From 7ced218bf565e2e54cb3840e635d06b5e2ca9591 Mon Sep 17 00:00:00 2001 From: mudkip Date: Sat, 20 Jul 2024 11:29:37 -0600 Subject: [PATCH 01/97] improve notification api (#2204) --- .../java/net/minestom/demo/PlayerInit.java | 8 +- .../demo/commands/NotificationCommand.java | 11 ++- .../server/advancements/Notification.java | 58 ++++++++++++++ .../notifications/Notification.java | 26 ------- .../notifications/NotificationCenter.java | 77 ------------------- .../audience/PacketGroupingAudience.java | 11 ++- .../net/minestom/server/entity/Player.java | 10 +++ 7 files changed, 86 insertions(+), 115 deletions(-) create mode 100644 src/main/java/net/minestom/server/advancements/Notification.java delete mode 100644 src/main/java/net/minestom/server/advancements/notifications/Notification.java delete mode 100644 src/main/java/net/minestom/server/advancements/notifications/NotificationCenter.java diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 6d89fcffd..f915a40db 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -5,8 +5,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.FeatureFlag; import net.minestom.server.MinecraftServer; import net.minestom.server.advancements.FrameType; -import net.minestom.server.advancements.notifications.Notification; -import net.minestom.server.advancements.notifications.NotificationCenter; +import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.coordinate.Pos; @@ -174,12 +173,11 @@ public class PlayerInit { if (event.isFirstSpawn()) { - Notification notification = new Notification( + event.getPlayer().sendNotification(new Notification( Component.text("Welcome!"), FrameType.TASK, Material.IRON_SWORD - ); - NotificationCenter.send(notification, event.getPlayer()); + )); player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); } diff --git a/demo/src/main/java/net/minestom/demo/commands/NotificationCommand.java b/demo/src/main/java/net/minestom/demo/commands/NotificationCommand.java index d5fc7453e..b5cc3f292 100644 --- a/demo/src/main/java/net/minestom/demo/commands/NotificationCommand.java +++ b/demo/src/main/java/net/minestom/demo/commands/NotificationCommand.java @@ -2,12 +2,10 @@ package net.minestom.demo.commands; import net.kyori.adventure.text.Component; import net.minestom.server.advancements.FrameType; -import net.minestom.server.advancements.notifications.Notification; -import net.minestom.server.advancements.notifications.NotificationCenter; +import net.minestom.server.advancements.Notification; import net.minestom.server.command.builder.Command; import net.minestom.server.entity.Player; import net.minestom.server.item.Material; -import org.jetbrains.annotations.NotNull; public class NotificationCommand extends Command { public NotificationCommand() { @@ -15,9 +13,10 @@ public class NotificationCommand extends Command { setDefaultExecutor((sender, context) -> { var player = (Player) sender; - - var notification = new Notification(Component.text("Hello World!"), FrameType.GOAL, Material.DIAMOND_AXE); - NotificationCenter.send(notification, player); + player.sendNotification(new Notification( + Component.text("Hello World!"), + FrameType.GOAL, + Material.DIAMOND_AXE)); }); } } diff --git a/src/main/java/net/minestom/server/advancements/Notification.java b/src/main/java/net/minestom/server/advancements/Notification.java new file mode 100644 index 000000000..0621fe399 --- /dev/null +++ b/src/main/java/net/minestom/server/advancements/Notification.java @@ -0,0 +1,58 @@ +package net.minestom.server.advancements; + +import net.kyori.adventure.text.Component; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.AdvancementsPacket; + +import java.util.List; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a toast which can be sent to the player using {@link net.minestom.server.entity.Player#sendNotification(Notification)}. + */ +public record Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull ItemStack icon) { + private static final String IDENTIFIER = "minestom:notification"; + + public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull Material icon) { + this(title, frameType, ItemStack.of(icon)); + } + + @ApiStatus.Internal + public @NotNull AdvancementsPacket buildAddPacket() { + // For an advancement to be shown, it must have all of its criteria achieved (progress 100%) + // Create a criteria that we can set to 100% achieved. + final var displayData = new AdvancementsPacket.DisplayData( + title, Component.text("Articdive was here. #Minestom"), + icon, frameType, + 0x6, null, 0f, 0f); + + final var criteria = new AdvancementsPacket.Criteria("minestom:some_criteria", + new AdvancementsPacket.CriterionProgress(System.currentTimeMillis())); + + final var advancement = new AdvancementsPacket.Advancement(null, displayData, + List.of(new AdvancementsPacket.Requirement(List.of(criteria.criterionIdentifier()))), + false); + + final var mapping = new AdvancementsPacket.AdvancementMapping(IDENTIFIER, advancement); + final var progressMapping = new AdvancementsPacket.ProgressMapping(IDENTIFIER, + new AdvancementsPacket.AdvancementProgress(List.of(criteria))); + + return new AdvancementsPacket( + false, + List.of(mapping), + List.of(), + List.of(progressMapping)); + } + + @ApiStatus.Internal + public @NotNull AdvancementsPacket buildRemovePacket() { + return new AdvancementsPacket( + false, + List.of(), + List.of(IDENTIFIER), + List.of()); + } +} diff --git a/src/main/java/net/minestom/server/advancements/notifications/Notification.java b/src/main/java/net/minestom/server/advancements/notifications/Notification.java deleted file mode 100644 index 90660466e..000000000 --- a/src/main/java/net/minestom/server/advancements/notifications/Notification.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.minestom.server.advancements.notifications; - -import net.kyori.adventure.text.Component; -import net.minestom.server.advancements.FrameType; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import org.jetbrains.annotations.NotNull; - -/** - * Represents a message which can be sent using the {@link NotificationCenter}. - */ -public record Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull ItemStack icon) { - public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull Material icon) { - this(title, frameType, ItemStack.of(icon)); - } - - @Deprecated - public @NotNull Component getTitle() { - return title; - } - - @Deprecated - public @NotNull FrameType getFrameType() { - return frameType; - } -} diff --git a/src/main/java/net/minestom/server/advancements/notifications/NotificationCenter.java b/src/main/java/net/minestom/server/advancements/notifications/NotificationCenter.java deleted file mode 100644 index 5c5326b3c..000000000 --- a/src/main/java/net/minestom/server/advancements/notifications/NotificationCenter.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.minestom.server.advancements.notifications; - -import net.kyori.adventure.text.Component; -import net.minestom.server.entity.Player; -import net.minestom.server.network.packet.server.play.AdvancementsPacket; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.List; - -/** - * Used to send one or multiples {@link Notification}. - *

- * Works by sending a completed advancement and remove it immediately. - *

- * You can simply create a {@link Notification} object and call {@link #send(Notification, Player)}. - */ -public final class NotificationCenter { - private static final String IDENTIFIER = "minestom:notification"; - private static final AdvancementsPacket REMOVE_PACKET = new AdvancementsPacket(false, List.of(), List.of(IDENTIFIER), List.of()); - - /** - * Can't create an instance, use the static methods instead. - */ - private NotificationCenter() { - } - - /** - * Send a {@link Notification} to one player. - * - * @param notification the {@link Notification} to send - * @param player the player to send the notification to - */ - public static void send(@NotNull Notification notification, @NotNull Player player) { - player.sendPacket(createPacket(notification)); - player.sendPacket(REMOVE_PACKET); - } - - /** - * Send a {@link Notification} to a collection of players. - * - * @param notification the {@link Notification} to send - * @param players the collection of players to send the notification to - */ - public static void send(@NotNull Notification notification, @NotNull Collection players) { - // Can't use PacketWriterUtils because we need the packets to come in the correct order - players.forEach(player -> send(notification, player)); - } - - /** - * Create the {@link AdvancementsPacket} responsible for showing the Toast to players - * - * @param notification the notification - * @return the packet used to show the Toast - */ - private static AdvancementsPacket createPacket(Notification notification) { - // For An advancement to be shown, it must have all of its criteria achieved (progress 100%) - // Create a Criteria that we can set to 100% achieved. - final var displayData = new AdvancementsPacket.DisplayData( - notification.title(), Component.text("Articdive was here. #Minestom"), - notification.icon(), notification.frameType(), - 0x6, null, 0f, 0f); - - final var criteria = new AdvancementsPacket.Criteria("minestom:some_criteria", - new AdvancementsPacket.CriterionProgress(System.currentTimeMillis())); - - final var advancement = new AdvancementsPacket.Advancement(null, displayData, - List.of(new AdvancementsPacket.Requirement(List.of(criteria.criterionIdentifier()))), - false); - - final var mapping = new AdvancementsPacket.AdvancementMapping(IDENTIFIER, advancement); - final var progressMapping = new AdvancementsPacket.ProgressMapping(IDENTIFIER, - new AdvancementsPacket.AdvancementProgress(List.of(criteria))); - - return new AdvancementsPacket(false, List.of(mapping), List.of(), List.of(progressMapping)); - } -} diff --git a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java index 3b512728f..f532a6be0 100644 --- a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java +++ b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java @@ -10,6 +10,7 @@ import net.kyori.adventure.sound.SoundStop; import net.kyori.adventure.text.Component; import net.kyori.adventure.title.TitlePart; import net.minestom.server.MinecraftServer; +import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; @@ -28,7 +29,6 @@ import java.util.Collection; * An audience implementation that sends grouped packets if possible. */ public interface PacketGroupingAudience extends ForwardingAudience { - /** * Creates a packet grouping audience that copies an iterable of players. The * underlying collection is not copied, so changes to the collection will be @@ -129,6 +129,15 @@ public interface PacketGroupingAudience extends ForwardingAudience { sendGroupedPacket(AdventurePacketConvertor.createSoundStopPacket(stop)); } + /** + * Send a {@link Notification} to the audience. + * @param notification the {@link Notification} to send + */ + default void sendNotification(@NotNull Notification notification) { + sendGroupedPacket(notification.buildAddPacket()); + sendGroupedPacket(notification.buildRemovePacket()); + } + @Override default @NotNull Iterable audiences() { return this.getPlayers(); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 6e7ea0b84..c08d1cae4 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -24,6 +24,7 @@ import net.kyori.adventure.title.TitlePart; import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; import net.minestom.server.advancements.AdvancementTab; +import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.Localizable; import net.minestom.server.adventure.audience.Audiences; @@ -2360,6 +2361,15 @@ public class Player extends LivingEntity implements CommandSender, Localizable, return super.teleport(position, chunks, flags); } + /** + * Send a {@link Notification} to the player. + * @param notification the {@link Notification} to send + */ + public void sendNotification(@NotNull Notification notification) { + sendPacket(notification.buildAddPacket()); + sendPacket(notification.buildRemovePacket()); + } + /** * Represents the main or off hand of the player. */ From 3a8157f2631c2e1848885411825ca2306efaf963 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 20 Jul 2024 19:53:46 +0200 Subject: [PATCH 02/97] move enums (#2282) --- .../java/net/minestom/demo/PlayerInit.java | 2 +- .../server/collision/BoundingBox.java | 4 +- .../net/minestom/server/entity/Entity.java | 36 +++-------- .../minestom/server/entity/EntityPose.java | 22 +++++++ .../minestom/server/entity/LivingEntity.java | 4 +- .../net/minestom/server/entity/Metadata.java | 2 +- .../minestom/server/entity/MetadataImpl.java | 2 +- .../net/minestom/server/entity/Player.java | 62 ++++++++----------- .../minestom/server/entity/PlayerHand.java | 9 +++ .../server/entity/metadata/EntityMeta.java | 7 ++- .../entity/metadata/LivingEntityMeta.java | 10 +-- .../event/item/ItemUpdateStateEvent.java | 7 ++- .../event/item/ItemUsageCompleteEvent.java | 7 ++- .../player/PlayerBlockInteractEvent.java | 7 ++- .../event/player/PlayerBlockPlaceEvent.java | 7 ++- .../server/event/player/PlayerEatEvent.java | 7 ++- .../player/PlayerEntityInteractEvent.java | 7 ++- .../player/PlayerHandAnimationEvent.java | 7 ++- .../player/PlayerItemAnimationEvent.java | 7 ++- .../event/player/PlayerPreEatEvent.java | 7 ++- .../event/player/PlayerUseItemEvent.java | 7 ++- .../player/PlayerUseItemOnBlockEvent.java | 7 ++- .../server/instance/block/BlockHandler.java | 13 ++-- .../server/inventory/EquipmentHandler.java | 6 +- .../server/listener/AnimationListener.java | 3 +- .../listener/BlockPlacementListener.java | 3 +- .../listener/PlayerDiggingListener.java | 5 +- .../server/listener/UseItemListener.java | 5 +- .../server/network/NetworkBuffer.java | 4 +- .../client/play/ClientAnimationPacket.java | 8 +-- .../play/ClientInteractEntityPacket.java | 15 +++-- .../ClientPlayerBlockPlacementPacket.java | 8 +-- .../client/play/ClientUseItemPacket.java | 8 +-- .../packet/server/play/OpenBookPacket.java | 8 +-- .../EntityBoundingBoxIntegrationTest.java | 18 +++--- .../entity/EntityMetaIntegrationTest.java | 4 +- .../PlayerBlockPlacementIntegrationTest.java | 4 +- .../instance/BlockPlaceIntegrationTest.java | 10 +-- .../TestUseItemListenerIntegration.java | 10 +-- 39 files changed, 194 insertions(+), 175 deletions(-) create mode 100644 src/main/java/net/minestom/server/entity/EntityPose.java create mode 100644 src/main/java/net/minestom/server/entity/PlayerHand.java diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index f915a40db..f012a5b72 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -190,7 +190,7 @@ public class PlayerInit { //System.out.println("in " + event.getPacket().getClass().getSimpleName()); }) .addListener(PlayerUseItemOnBlockEvent.class, event -> { - if (event.getHand() != Player.Hand.MAIN) return; + if (event.getHand() != PlayerHand.MAIN) return; var itemStack = event.getItemStack(); var block = event.getInstance().getBlock(event.getPosition()); diff --git a/src/main/java/net/minestom/server/collision/BoundingBox.java b/src/main/java/net/minestom/server/collision/BoundingBox.java index e6fbb8606..ab89455f1 100644 --- a/src/main/java/net/minestom/server/collision/BoundingBox.java +++ b/src/main/java/net/minestom/server/collision/BoundingBox.java @@ -3,7 +3,7 @@ package net.minestom.server.collision; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityPose; import net.minestom.server.instance.block.BlockFace; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -253,7 +253,7 @@ public record BoundingBox(Vec relativeStart, Vec relativeEnd) implements Shape { } } - public static @Nullable BoundingBox fromPose(@NotNull Entity.Pose pose) { + public static @Nullable BoundingBox fromPose(@NotNull EntityPose pose) { return switch (pose) { case FALL_FLYING, SWIMMING, SPIN_ATTACK -> SMALL; case SLEEPING, DYING -> SLEEPING; diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index e7bd1cac1..7ab9b06be 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -1122,7 +1122,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev * * @return the entity pose */ - public @NotNull Pose getPose() { + public @NotNull EntityPose getPose() { return this.entityMeta.getPose(); } @@ -1134,21 +1134,21 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev * * @param pose the new entity pose */ - public void setPose(@NotNull Pose pose) { + public void setPose(@NotNull EntityPose pose) { this.entityMeta.setPose(pose); } protected void updatePose() { if (entityMeta.isFlyingWithElytra()) { - setPose(Pose.FALL_FLYING); + setPose(EntityPose.FALL_FLYING); } else if (entityMeta.isSwimming()) { - setPose(Pose.SWIMMING); + setPose(EntityPose.SWIMMING); } else if (entityMeta instanceof LivingEntityMeta livingMeta && livingMeta.isInRiptideSpinAttack()) { - setPose(Pose.SPIN_ATTACK); + setPose(EntityPose.SPIN_ATTACK); } else if (entityMeta.isSneaking()) { - setPose(Pose.SNEAKING); + setPose(EntityPose.SNEAKING); } else { - setPose(Pose.STANDING); + setPose(EntityPose.STANDING); } } @@ -1350,7 +1350,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev * @return the entity eye height */ public double getEyeHeight() { - return getPose() == Pose.SLEEPING ? 0.2 : entityType.registry().eyeHeight(); + return getPose() == EntityPose.SLEEPING ? 0.2 : entityType.registry().eyeHeight(); } /** @@ -1768,24 +1768,4 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev return acquirable; } - public enum Pose { - STANDING, - FALL_FLYING, - SLEEPING, - SWIMMING, - SPIN_ATTACK, - SNEAKING, - LONG_JUMPING, - DYING, - CROAKING, - USING_TONGUE, - SITTING, - ROARING, - SNIFFING, - EMERGING, - DIGGING, - SLIDING, - SHOOTING, - INHALING; - } } diff --git a/src/main/java/net/minestom/server/entity/EntityPose.java b/src/main/java/net/minestom/server/entity/EntityPose.java new file mode 100644 index 000000000..6988e29ef --- /dev/null +++ b/src/main/java/net/minestom/server/entity/EntityPose.java @@ -0,0 +1,22 @@ +package net.minestom.server.entity; + +public enum EntityPose { + STANDING, + FALL_FLYING, + SLEEPING, + SWIMMING, + SPIN_ATTACK, + SNEAKING, + LONG_JUMPING, + DYING, + CROAKING, + USING_TONGUE, + SITTING, + ROARING, + SNIFFING, + EMERGING, + DIGGING, + SLIDING, + SHOOTING, + INHALING; +} diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index 95ae60eb0..e5f7c00df 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -261,7 +261,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { public void kill() { refreshIsDead(true); // So the entity isn't killed over and over again triggerStatus((byte) 3); // Start death animation status - setPose(Pose.DYING); + setPose(EntityPose.DYING); setHealth(0); // Reset velocity @@ -595,7 +595,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { if (meta != null) { meta.setNotifyAboutChanges(false); meta.setHandActive(isHandActive); - meta.setActiveHand(offHand ? Player.Hand.OFF : Player.Hand.MAIN); + meta.setActiveHand(offHand ? PlayerHand.OFF : PlayerHand.MAIN); meta.setInRiptideSpinAttack(riptideSpinAttack); meta.setNotifyAboutChanges(true); diff --git a/src/main/java/net/minestom/server/entity/Metadata.java b/src/main/java/net/minestom/server/entity/Metadata.java index 7dd983e6a..223f3e8a1 100644 --- a/src/main/java/net/minestom/server/entity/Metadata.java +++ b/src/main/java/net/minestom/server/entity/Metadata.java @@ -137,7 +137,7 @@ public final class Metadata { }); } - public static Entry Pose(Entity.@NotNull Pose value) { + public static Entry Pose(@NotNull EntityPose value) { return new MetadataImpl.EntryImpl<>(TYPE_POSE, value, NetworkBuffer.POSE); } diff --git a/src/main/java/net/minestom/server/entity/MetadataImpl.java b/src/main/java/net/minestom/server/entity/MetadataImpl.java index 239f870f6..56000a7b0 100644 --- a/src/main/java/net/minestom/server/entity/MetadataImpl.java +++ b/src/main/java/net/minestom/server/entity/MetadataImpl.java @@ -48,7 +48,7 @@ final class MetadataImpl { EMPTY_VALUES.set(TYPE_PARTICLE_LIST, ParticleList(List.of())); EMPTY_VALUES.set(TYPE_VILLAGERDATA, VillagerData(0, 0, 0)); EMPTY_VALUES.set(TYPE_OPT_VARINT, OptVarInt(null)); - EMPTY_VALUES.set(TYPE_POSE, Pose(Entity.Pose.STANDING)); + EMPTY_VALUES.set(TYPE_POSE, Pose(EntityPose.STANDING)); EMPTY_VALUES.set(TYPE_CAT_VARIANT, CatVariant(CatMeta.Variant.TABBY)); EMPTY_VALUES.set(TYPE_WOLF_VARIANT, WolfVariant(WolfMeta.Variant.PALE)); EMPTY_VALUES.set(TYPE_FROG_VARIANT, FrogVariant(FrogMeta.Variant.TEMPERATE)); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index c08d1cae4..bcf210c84 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -196,7 +196,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, private long startItemUseTime; private long itemUseTime; - private Hand itemUseHand; + private PlayerHand itemUseHand; // Game state (https://wiki.vg/Protocol#Change_Game_State) private boolean enableRespawnScreen; @@ -442,7 +442,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, ItemUpdateStateEvent itemUpdateStateEvent = callItemUpdateStateEvent(itemUseHand); // Refresh hand - final boolean isOffHand = itemUpdateStateEvent.getHand() == Player.Hand.OFF; + final boolean isOffHand = itemUpdateStateEvent.getHand() == PlayerHand.OFF; refreshActiveHand(false, isOffHand, false); final ItemStack item = itemUpdateStateEvent.getItemStack(); @@ -832,47 +832,47 @@ public class Player extends LivingEntity implements CommandSender, Localizable, @Override protected void updatePose() { - Pose oldPose = getPose(); - Pose newPose; + EntityPose oldPose = getPose(); + EntityPose newPose; // Figure out their expected state var meta = getEntityMeta(); if (meta.isFlyingWithElytra()) { - newPose = Pose.FALL_FLYING; + newPose = EntityPose.FALL_FLYING; } else if (false) { // When should they be sleeping? We don't have any in-bed state... - newPose = Pose.SLEEPING; + newPose = EntityPose.SLEEPING; } else if (meta.isSwimming()) { - newPose = Pose.SWIMMING; + newPose = EntityPose.SWIMMING; } else if (meta instanceof LivingEntityMeta livingMeta && livingMeta.isInRiptideSpinAttack()) { - newPose = Pose.SPIN_ATTACK; + newPose = EntityPose.SPIN_ATTACK; } else if (isSneaking() && !isFlying()) { - newPose = Pose.SNEAKING; + newPose = EntityPose.SNEAKING; } else { - newPose = Pose.STANDING; + newPose = EntityPose.STANDING; } // Try to put them in their expected state, or the closest if they don't fit. if (canFitWithBoundingBox(newPose)) { // Use expected state - } else if (canFitWithBoundingBox(Pose.SNEAKING)) { - newPose = Pose.SNEAKING; - } else if (canFitWithBoundingBox(Pose.SWIMMING)) { - newPose = Pose.SWIMMING; + } else if (canFitWithBoundingBox(EntityPose.SNEAKING)) { + newPose = EntityPose.SNEAKING; + } else if (canFitWithBoundingBox(EntityPose.SWIMMING)) { + newPose = EntityPose.SWIMMING; } else { // If they can't fit anywhere, just use standing - newPose = Pose.STANDING; + newPose = EntityPose.STANDING; } if (newPose != oldPose) setPose(newPose); } /** - * Returns true if the player can fit at the current position with the given {@link net.minestom.server.entity.Entity.Pose}, false otherwise. + * Returns true if the player can fit at the current position with the given {@link EntityPose}, false otherwise. * * @param pose The pose to check */ - private boolean canFitWithBoundingBox(@NotNull Pose pose) { - BoundingBox bb = pose == Pose.STANDING ? boundingBox : BoundingBox.fromPose(pose); + private boolean canFitWithBoundingBox(@NotNull EntityPose pose) { + BoundingBox bb = pose == EntityPose.STANDING ? boundingBox : BoundingBox.fromPose(pose); if (bb == null) return false; var position = getPosition(); @@ -1018,7 +1018,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Set book in offhand sendPacket(new SetSlotPacket((byte) 0, 0, (short) PlayerInventoryUtils.OFFHAND_SLOT, writtenBook)); // Open the book - sendPacket(new OpenBookPacket(Hand.OFF)); + sendPacket(new OpenBookPacket(PlayerHand.OFF)); // Restore the item in offhand sendPacket(new SetSlotPacket((byte) 0, 0, (short) PlayerInventoryUtils.OFFHAND_SLOT, getItemInOffHand())); } @@ -1136,7 +1136,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * * @return the item use hand, null if none */ - public @Nullable Hand getItemUseHand() { + public @Nullable PlayerHand getItemUseHand() { return itemUseHand; } @@ -2002,12 +2002,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void refreshFlying(boolean flying) { //When the player starts or stops flying, their pose needs to change if (this.flying != flying) { - Pose pose = getPose(); + EntityPose pose = getPose(); - if (this.isSneaking() && pose == Pose.STANDING) { - setPose(Pose.SNEAKING); - } else if (pose == Pose.SNEAKING) { - setPose(Pose.STANDING); + if (this.isSneaking() && pose == EntityPose.STANDING) { + setPose(EntityPose.SNEAKING); + } else if (pose == EntityPose.SNEAKING) { + setPose(EntityPose.STANDING); } } @@ -2188,7 +2188,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, updateEquipmentAttributes(inventory.getItemStack(oldHeldSlot), inventory.getItemStack(this.heldSlot), EquipmentSlot.MAIN_HAND); } - public void refreshItemUse(@Nullable Hand itemUseHand, long itemUseTimeTicks) { + public void refreshItemUse(@Nullable PlayerHand itemUseHand, long itemUseTimeTicks) { this.itemUseHand = itemUseHand; if (itemUseHand != null) { this.startItemUseTime = getAliveTicks(); @@ -2208,7 +2208,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * * @return the called {@link ItemUpdateStateEvent}, */ - public @NotNull ItemUpdateStateEvent callItemUpdateStateEvent(@NotNull Hand hand) { + public @NotNull ItemUpdateStateEvent callItemUpdateStateEvent(@NotNull PlayerHand hand) { ItemUpdateStateEvent itemUpdateStateEvent = new ItemUpdateStateEvent(this, hand, getItemInHand(hand)); EventDispatcher.call(itemUpdateStateEvent); @@ -2370,14 +2370,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable, sendPacket(notification.buildRemovePacket()); } - /** - * Represents the main or off hand of the player. - */ - public enum Hand { - MAIN, - OFF - } - public enum FacePoint { FEET, EYE diff --git a/src/main/java/net/minestom/server/entity/PlayerHand.java b/src/main/java/net/minestom/server/entity/PlayerHand.java new file mode 100644 index 000000000..21a251afd --- /dev/null +++ b/src/main/java/net/minestom/server/entity/PlayerHand.java @@ -0,0 +1,9 @@ +package net.minestom.server.entity; + +/** + * Represents the main or off hand of the player. + */ +public enum PlayerHand { + MAIN, + OFF +} diff --git a/src/main/java/net/minestom/server/entity/metadata/EntityMeta.java b/src/main/java/net/minestom/server/entity/metadata/EntityMeta.java index 90b1663da..07e500824 100644 --- a/src/main/java/net/minestom/server/entity/metadata/EntityMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/EntityMeta.java @@ -2,6 +2,7 @@ package net.minestom.server.entity.metadata; import net.kyori.adventure.text.Component; import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityPose; import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; @@ -143,11 +144,11 @@ public class EntityMeta { this.metadata.setIndex(OFFSET + 5, Metadata.Boolean(value)); } - public Entity.Pose getPose() { - return this.metadata.getIndex(OFFSET + 6, Entity.Pose.STANDING); + public EntityPose getPose() { + return this.metadata.getIndex(OFFSET + 6, EntityPose.STANDING); } - public void setPose(Entity.Pose value) { + public void setPose(EntityPose value) { this.metadata.setIndex(OFFSET + 6, Metadata.Pose(value)); } diff --git a/src/main/java/net/minestom/server/entity/metadata/LivingEntityMeta.java b/src/main/java/net/minestom/server/entity/metadata/LivingEntityMeta.java index d6b2ab277..33e76a968 100644 --- a/src/main/java/net/minestom/server/entity/metadata/LivingEntityMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/LivingEntityMeta.java @@ -4,7 +4,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.particle.Particle; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,12 +32,12 @@ public class LivingEntityMeta extends EntityMeta { } @NotNull - public Player.Hand getActiveHand() { - return getMaskBit(OFFSET, ACTIVE_HAND_BIT) ? Player.Hand.OFF : Player.Hand.MAIN; + public PlayerHand getActiveHand() { + return getMaskBit(OFFSET, ACTIVE_HAND_BIT) ? PlayerHand.OFF : PlayerHand.MAIN; } - public void setActiveHand(@NotNull Player.Hand hand) { - setMaskBit(OFFSET, ACTIVE_HAND_BIT, hand == Player.Hand.OFF); + public void setActiveHand(@NotNull PlayerHand hand) { + setMaskBit(OFFSET, ACTIVE_HAND_BIT, hand == PlayerHand.OFF); } public boolean isInRiptideSpinAttack() { diff --git a/src/main/java/net/minestom/server/event/item/ItemUpdateStateEvent.java b/src/main/java/net/minestom/server/event/item/ItemUpdateStateEvent.java index ecfd8baf2..0a974b3a3 100644 --- a/src/main/java/net/minestom/server/event/item/ItemUpdateStateEvent.java +++ b/src/main/java/net/minestom/server/event/item/ItemUpdateStateEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.item; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.ItemEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import net.minestom.server.item.ItemStack; @@ -12,20 +13,20 @@ import org.jetbrains.annotations.NotNull; public class ItemUpdateStateEvent implements PlayerInstanceEvent, ItemEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final ItemStack itemStack; private boolean handAnimation; private boolean riptideSpinAttack; - public ItemUpdateStateEvent(@NotNull Player player, @NotNull Player.Hand hand, @NotNull ItemStack itemStack) { + public ItemUpdateStateEvent(@NotNull Player player, @NotNull PlayerHand hand, @NotNull ItemStack itemStack) { this.player = player; this.hand = hand; this.itemStack = itemStack; } @NotNull - public Player.Hand getHand() { + public PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/item/ItemUsageCompleteEvent.java b/src/main/java/net/minestom/server/event/item/ItemUsageCompleteEvent.java index 0205451ab..e24f9974e 100644 --- a/src/main/java/net/minestom/server/event/item/ItemUsageCompleteEvent.java +++ b/src/main/java/net/minestom/server/event/item/ItemUsageCompleteEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.item; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.ItemEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import net.minestom.server.item.ItemStack; @@ -12,10 +13,10 @@ import org.jetbrains.annotations.NotNull; public class ItemUsageCompleteEvent implements PlayerInstanceEvent, ItemEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final ItemStack itemStack; - public ItemUsageCompleteEvent(@NotNull Player player, @NotNull Player.Hand hand, + public ItemUsageCompleteEvent(@NotNull Player player, @NotNull PlayerHand hand, @NotNull ItemStack itemStack) { this.player = player; this.hand = hand; @@ -23,7 +24,7 @@ public class ItemUsageCompleteEvent implements PlayerInstanceEvent, ItemEvent { } @NotNull - public Player.Hand getHand() { + public PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java b/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java index f43a96137..b1d636c20 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java @@ -3,6 +3,7 @@ package net.minestom.server.event.player; import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; @@ -17,7 +18,7 @@ import org.jetbrains.annotations.NotNull; public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent, CancellableEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final Block block; private final BlockVec blockPosition; private final Point cursorPosition; @@ -31,7 +32,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent private boolean cancelled; - public PlayerBlockInteractEvent(@NotNull Player player, @NotNull Player.Hand hand, + public PlayerBlockInteractEvent(@NotNull Player player, @NotNull PlayerHand hand, @NotNull Block block, @NotNull BlockVec blockPosition, @NotNull Point cursorPosition, @NotNull BlockFace blockFace) { this.player = player; @@ -86,7 +87,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent * * @return the hand used */ - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java b/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java index 07db5f41e..e88d38862 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java @@ -3,6 +3,7 @@ package net.minestom.server.event.player; import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; @@ -20,7 +21,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C private final BlockFace blockFace; private final BlockVec blockPosition; private final Point cursorPosition; - private final Player.Hand hand; + private final PlayerHand hand; private boolean consumeBlock; private boolean doBlockUpdates; @@ -29,7 +30,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block, @NotNull BlockFace blockFace, @NotNull BlockVec blockPosition, - @NotNull Point cursorPosition, @NotNull Player.Hand hand) { + @NotNull Point cursorPosition, @NotNull PlayerHand hand) { this.player = player; this.block = block; this.blockFace = blockFace; @@ -82,7 +83,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C * * @return the hand used */ - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerEatEvent.java b/src/main/java/net/minestom/server/event/player/PlayerEatEvent.java index b45665fb7..1d2c0ba8f 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerEatEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerEatEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.ItemEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import net.minestom.server.item.ItemStack; @@ -13,9 +14,9 @@ public class PlayerEatEvent implements ItemEvent, PlayerInstanceEvent { private final Player player; private final ItemStack foodItem; - private final Player.Hand hand; + private final PlayerHand hand; - public PlayerEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull Player.Hand hand) { + public PlayerEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull PlayerHand hand) { this.player = player; this.foodItem = foodItem; this.hand = hand; @@ -32,7 +33,7 @@ public class PlayerEatEvent implements ItemEvent, PlayerInstanceEvent { return foodItem; } - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerEntityInteractEvent.java b/src/main/java/net/minestom/server/event/player/PlayerEntityInteractEvent.java index e5901073f..b2c94259d 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerEntityInteractEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerEntityInteractEvent.java @@ -3,6 +3,7 @@ package net.minestom.server.event.player; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.PlayerInstanceEvent; import org.jetbrains.annotations.NotNull; @@ -13,10 +14,10 @@ public class PlayerEntityInteractEvent implements PlayerInstanceEvent { private final Player player; private final Entity entityTarget; - private final Player.Hand hand; + private final PlayerHand hand; private final Point interactPosition; - public PlayerEntityInteractEvent(@NotNull Player player, @NotNull Entity entityTarget, @NotNull Player.Hand hand, + public PlayerEntityInteractEvent(@NotNull Player player, @NotNull Entity entityTarget, @NotNull PlayerHand hand, @NotNull Point interactPosition) { this.player = player; this.entityTarget = entityTarget; @@ -45,7 +46,7 @@ public class PlayerEntityInteractEvent implements PlayerInstanceEvent { * @return the hand */ @NotNull - public Player.Hand getHand() { + public PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerHandAnimationEvent.java b/src/main/java/net/minestom/server/event/player/PlayerHandAnimationEvent.java index e89d3a674..8302236a1 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerHandAnimationEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerHandAnimationEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import org.jetbrains.annotations.NotNull; @@ -11,11 +12,11 @@ import org.jetbrains.annotations.NotNull; public class PlayerHandAnimationEvent implements PlayerInstanceEvent, CancellableEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private boolean cancelled; - public PlayerHandAnimationEvent(@NotNull Player player, @NotNull Player.Hand hand) { + public PlayerHandAnimationEvent(@NotNull Player player, @NotNull PlayerHand hand) { this.player = player; this.hand = hand; } @@ -26,7 +27,7 @@ public class PlayerHandAnimationEvent implements PlayerInstanceEvent, Cancellabl * @return the hand */ @NotNull - public Player.Hand getHand() { + public PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerItemAnimationEvent.java b/src/main/java/net/minestom/server/event/player/PlayerItemAnimationEvent.java index dcbda3ec2..3841b8ce0 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerItemAnimationEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerItemAnimationEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import org.jetbrains.annotations.NotNull; @@ -14,10 +15,10 @@ public class PlayerItemAnimationEvent implements PlayerInstanceEvent, Cancellabl private final Player player; private final ItemAnimationType itemAnimationType; - private final Player.Hand hand; + private final PlayerHand hand; private boolean cancelled; - public PlayerItemAnimationEvent(@NotNull Player player, @NotNull ItemAnimationType itemAnimationType, @NotNull Player.Hand hand) { + public PlayerItemAnimationEvent(@NotNull Player player, @NotNull ItemAnimationType itemAnimationType, @NotNull PlayerHand hand) { this.player = player; this.itemAnimationType = itemAnimationType; this.hand = hand; @@ -37,7 +38,7 @@ public class PlayerItemAnimationEvent implements PlayerInstanceEvent, Cancellabl * * @return the hand */ - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerPreEatEvent.java b/src/main/java/net/minestom/server/event/player/PlayerPreEatEvent.java index abf6b6336..43ade967a 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerPreEatEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerPreEatEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.ItemEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; @@ -16,12 +17,12 @@ public class PlayerPreEatEvent implements ItemEvent, PlayerInstanceEvent, Cancel private final Player player; private final ItemStack foodItem; - private final Player.Hand hand; + private final PlayerHand hand; private long eatingTime; private boolean cancelled; - public PlayerPreEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull Player.Hand hand, long eatingTime) { + public PlayerPreEatEvent(@NotNull Player player, @NotNull ItemStack foodItem, @NotNull PlayerHand hand, long eatingTime) { this.player = player; this.foodItem = foodItem; this.hand = hand; @@ -39,7 +40,7 @@ public class PlayerPreEatEvent implements ItemEvent, PlayerInstanceEvent, Cancel return foodItem; } - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerUseItemEvent.java b/src/main/java/net/minestom/server/event/player/PlayerUseItemEvent.java index 9f091dad5..eadd9f03c 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerUseItemEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerUseItemEvent.java @@ -1,6 +1,7 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.item.ItemUpdateStateEvent; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.ItemEvent; @@ -14,13 +15,13 @@ import org.jetbrains.annotations.NotNull; public class PlayerUseItemEvent implements PlayerInstanceEvent, ItemEvent, CancellableEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final ItemStack itemStack; private long itemUseTime; private boolean cancelled; - public PlayerUseItemEvent(@NotNull Player player, @NotNull Player.Hand hand, @NotNull ItemStack itemStack, long itemUseTime) { + public PlayerUseItemEvent(@NotNull Player player, @NotNull PlayerHand hand, @NotNull ItemStack itemStack, long itemUseTime) { this.player = player; this.hand = hand; this.itemStack = itemStack; @@ -32,7 +33,7 @@ public class PlayerUseItemEvent implements PlayerInstanceEvent, ItemEvent, Cance * * @return the hand used */ - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerUseItemOnBlockEvent.java b/src/main/java/net/minestom/server/event/player/PlayerUseItemOnBlockEvent.java index a2a3d0548..d0efd7378 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerUseItemOnBlockEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerUseItemOnBlockEvent.java @@ -2,6 +2,7 @@ package net.minestom.server.event.player; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.trait.ItemEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import net.minestom.server.instance.block.BlockFace; @@ -14,12 +15,12 @@ import org.jetbrains.annotations.NotNull; public class PlayerUseItemOnBlockEvent implements PlayerInstanceEvent, ItemEvent { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final ItemStack itemStack; private final Point position; private final BlockFace blockFace; - public PlayerUseItemOnBlockEvent(@NotNull Player player, @NotNull Player.Hand hand, + public PlayerUseItemOnBlockEvent(@NotNull Player player, @NotNull PlayerHand hand, @NotNull ItemStack itemStack, @NotNull Point position, @NotNull Point cursorPosition, @NotNull BlockFace blockFace) { @@ -53,7 +54,7 @@ public class PlayerUseItemOnBlockEvent implements PlayerInstanceEvent, ItemEvent * * @return the hand */ - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } diff --git a/src/main/java/net/minestom/server/instance/block/BlockHandler.java b/src/main/java/net/minestom/server/instance/block/BlockHandler.java index b5cf80e74..7ca4c4c51 100644 --- a/src/main/java/net/minestom/server/instance/block/BlockHandler.java +++ b/src/main/java/net/minestom/server/instance/block/BlockHandler.java @@ -3,6 +3,7 @@ package net.minestom.server.instance.block; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.instance.Instance; import net.minestom.server.tag.Tag; import net.minestom.server.utils.NamespaceID; @@ -116,13 +117,13 @@ public interface BlockHandler { final class PlayerPlacement extends Placement { private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; private final BlockFace blockFace; private final float cursorX, cursorY, cursorZ; @ApiStatus.Internal public PlayerPlacement(Block block, Instance instance, Point blockPosition, - Player player, Player.Hand hand, BlockFace blockFace, float cursorX, float cursorY, float cursorZ) { + Player player, PlayerHand hand, BlockFace blockFace, float cursorX, float cursorY, float cursorZ) { super(block, instance, blockPosition); this.player = player; this.hand = hand; @@ -136,7 +137,7 @@ public interface BlockHandler { return player; } - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } @@ -203,10 +204,10 @@ public interface BlockHandler { private final Point blockPosition; private final Point cursorPosition; private final Player player; - private final Player.Hand hand; + private final PlayerHand hand; @ApiStatus.Internal - public Interaction(Block block, Instance instance, BlockFace blockFace, Point blockPosition, Point cursorPosition, Player player, Player.Hand hand) { + public Interaction(Block block, Instance instance, BlockFace blockFace, Point blockPosition, Point cursorPosition, Player player, PlayerHand hand) { this.block = block; this.instance = instance; this.blockFace = blockFace; @@ -240,7 +241,7 @@ public interface BlockHandler { return player; } - public @NotNull Player.Hand getHand() { + public @NotNull PlayerHand getHand() { return hand; } } diff --git a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java index fc4431fef..8e4a93649 100644 --- a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java +++ b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java @@ -2,7 +2,7 @@ package net.minestom.server.inventory; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EquipmentSlot; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.utils.validate.Check; @@ -67,7 +67,7 @@ public interface EquipmentHandler { * @param hand the Hand to get the {@link ItemStack} from * @return the {@link ItemStack} in {@code hand} */ - default @NotNull ItemStack getItemInHand(@NotNull Player.Hand hand) { + default @NotNull ItemStack getItemInHand(@NotNull PlayerHand hand) { return switch (hand) { case MAIN -> getItemInMainHand(); case OFF -> getItemInOffHand(); @@ -80,7 +80,7 @@ public interface EquipmentHandler { * @param hand the hand to set the item to * @param stack the {@link ItemStack} to set */ - default void setItemInHand(@NotNull Player.Hand hand, @NotNull ItemStack stack) { + default void setItemInHand(@NotNull PlayerHand hand, @NotNull ItemStack stack) { switch (hand) { case MAIN -> setItemInMainHand(stack); case OFF -> setItemInOffHand(stack); diff --git a/src/main/java/net/minestom/server/listener/AnimationListener.java b/src/main/java/net/minestom/server/listener/AnimationListener.java index e8756e0f3..a84c682ba 100644 --- a/src/main/java/net/minestom/server/listener/AnimationListener.java +++ b/src/main/java/net/minestom/server/listener/AnimationListener.java @@ -1,6 +1,7 @@ package net.minestom.server.listener; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerHandAnimationEvent; import net.minestom.server.item.ItemStack; @@ -9,7 +10,7 @@ import net.minestom.server.network.packet.client.play.ClientAnimationPacket; public class AnimationListener { public static void animationListener(ClientAnimationPacket packet, Player player) { - final Player.Hand hand = packet.hand(); + final PlayerHand hand = packet.hand(); final ItemStack itemStack = player.getItemInHand(hand); //itemStack.onLeftClick(player, hand); PlayerHandAnimationEvent handAnimationEvent = new PlayerHandAnimationEvent(player, hand); diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index 561f562fe..75d813576 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -8,6 +8,7 @@ import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent; @@ -37,7 +38,7 @@ public class BlockPlacementListener { public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) { final PlayerInventory playerInventory = player.getInventory(); - final Player.Hand hand = packet.hand(); + final PlayerHand hand = packet.hand(); final BlockFace blockFace = packet.blockFace(); Point blockPosition = packet.blockPosition(); diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index 488966379..af840bcec 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -6,6 +6,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.entity.metadata.LivingEntityMeta; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.item.ItemUpdateStateEvent; @@ -147,14 +148,14 @@ public final class PlayerDiggingListener { private static void updateItemState(Player player) { LivingEntityMeta meta = player.getLivingEntityMeta(); if (meta == null || !meta.isHandActive()) return; - Player.Hand hand = meta.getActiveHand(); + PlayerHand hand = meta.getActiveHand(); ItemUpdateStateEvent itemUpdateStateEvent = player.callItemUpdateStateEvent(hand); player.clearItemUse(); player.triggerStatus((byte) 9); - final boolean isOffHand = itemUpdateStateEvent.getHand() == Player.Hand.OFF; + final boolean isOffHand = itemUpdateStateEvent.getHand() == PlayerHand.OFF; player.refreshActiveHand(itemUpdateStateEvent.hasHandAnimation(), isOffHand, itemUpdateStateEvent.isRiptideSpinAttack()); } diff --git a/src/main/java/net/minestom/server/listener/UseItemListener.java b/src/main/java/net/minestom/server/listener/UseItemListener.java index 683f151e0..65ba27b35 100644 --- a/src/main/java/net/minestom/server/listener/UseItemListener.java +++ b/src/main/java/net/minestom/server/listener/UseItemListener.java @@ -2,6 +2,7 @@ package net.minestom.server.listener; import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerItemAnimationEvent; import net.minestom.server.event.player.PlayerPreEatEvent; @@ -19,7 +20,7 @@ import org.jetbrains.annotations.NotNull; public class UseItemListener { public static void useItemListener(ClientUseItemPacket packet, Player player) { - final Player.Hand hand = packet.hand(); + final PlayerHand hand = packet.hand(); final ItemStack itemStack = player.getInventory().getItemInHand(hand); final Material material = itemStack.material(); @@ -75,7 +76,7 @@ public class UseItemListener { PlayerItemAnimationEvent playerItemAnimationEvent = new PlayerItemAnimationEvent(player, itemAnimationType, hand); EventDispatcher.callCancellable(playerItemAnimationEvent, () -> { - player.refreshActiveHand(true, hand == Player.Hand.OFF, false); + player.refreshActiveHand(true, hand == PlayerHand.OFF, false); player.sendPacketToViewers(player.getMetadataPacket()); }); } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index 3944320ec..570bc6782 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -4,7 +4,7 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityPose; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.registry.ProtocolObject; import net.minestom.server.registry.Registries; @@ -64,7 +64,7 @@ public final class NetworkBuffer { public static final Type<@Nullable UUID> OPT_UUID = Optional(UUID); public static final Type DIRECTION = new NetworkBufferTypeImpl.EnumType<>(Direction.class); - public static final Type POSE = new NetworkBufferTypeImpl.EnumType<>(Entity.Pose.class); + public static final Type POSE = new NetworkBufferTypeImpl.EnumType<>(EntityPose.class); // Combinators diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java index 03a255517..7bd6067a6 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java @@ -1,17 +1,17 @@ package net.minestom.server.network.packet.client.play; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -public record ClientAnimationPacket(@NotNull Player.Hand hand) implements ClientPacket { +public record ClientAnimationPacket(@NotNull PlayerHand hand) implements ClientPacket { public ClientAnimationPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Player.Hand.class)); + this(reader.readEnum(PlayerHand.class)); } @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java index e16fc7b06..75b66ac40 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java @@ -1,9 +1,8 @@ package net.minestom.server.network.packet.client.play; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.ClientPacket; -import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -31,14 +30,14 @@ public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boole int id(); } - public record Interact(Player.@NotNull Hand hand) implements Type { + public record Interact(@NotNull PlayerHand hand) implements Type { public Interact(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Player.Hand.class)); + this(reader.readEnum(PlayerHand.class)); } @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); } @Override @@ -60,10 +59,10 @@ public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boole } public record InteractAt(float targetX, float targetY, float targetZ, - Player.@NotNull Hand hand) implements Type { + @NotNull PlayerHand hand) implements Type { public InteractAt(@NotNull NetworkBuffer reader) { this(reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT), - reader.readEnum(Player.Hand.class)); + reader.readEnum(PlayerHand.class)); } @Override @@ -71,7 +70,7 @@ public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boole writer.write(FLOAT, targetX); writer.write(FLOAT, targetY); writer.write(FLOAT, targetZ); - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); } @Override diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java index 2f222f1c8..f2bcd3cbd 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java @@ -1,7 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.ClientPacket; @@ -9,12 +9,12 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; -public record ClientPlayerBlockPlacementPacket(@NotNull Player.Hand hand, @NotNull Point blockPosition, +public record ClientPlayerBlockPlacementPacket(@NotNull PlayerHand hand, @NotNull Point blockPosition, @NotNull BlockFace blockFace, float cursorPositionX, float cursorPositionY, float cursorPositionZ, boolean insideBlock, int sequence) implements ClientPacket { public ClientPlayerBlockPlacementPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Player.Hand.class), reader.read(BLOCK_POSITION), + this(reader.readEnum(PlayerHand.class), reader.read(BLOCK_POSITION), reader.readEnum(BlockFace.class), reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT), reader.read(BOOLEAN), reader.read(VAR_INT)); @@ -22,7 +22,7 @@ public record ClientPlayerBlockPlacementPacket(@NotNull Player.Hand hand, @NotNu @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); writer.write(BLOCK_POSITION, blockPosition); writer.writeEnum(BlockFace.class, blockFace); writer.write(FLOAT, cursorPositionX); diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java index 6d6fffdf7..c39e143d2 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java @@ -1,21 +1,21 @@ package net.minestom.server.network.packet.client.play; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record ClientUseItemPacket(@NotNull Player.Hand hand, int sequence, float yaw, float pitch) implements ClientPacket { +public record ClientUseItemPacket(@NotNull PlayerHand hand, int sequence, float yaw, float pitch) implements ClientPacket { public ClientUseItemPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Player.Hand.class), reader.read(VAR_INT), + this(reader.readEnum(PlayerHand.class), reader.read(VAR_INT), reader.read(NetworkBuffer.FLOAT), reader.read(NetworkBuffer.FLOAT)); } @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); writer.write(VAR_INT, sequence); writer.write(NetworkBuffer.FLOAT, yaw); writer.write(NetworkBuffer.FLOAT, pitch); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java index 5a63eb8b7..812cecec9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java @@ -1,19 +1,19 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -public record OpenBookPacket(@NotNull Player.Hand hand) implements ServerPacket.Play { +public record OpenBookPacket(@NotNull PlayerHand hand) implements ServerPacket.Play { public OpenBookPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Player.Hand.class)); + this(reader.readEnum(PlayerHand.class)); } @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Player.Hand.class, hand); + writer.writeEnum(PlayerHand.class, hand); } @Override diff --git a/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java index dc20cd87d..caaf72511 100644 --- a/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java @@ -1,13 +1,13 @@ package net.minestom.server.entity; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.collision.BoundingBox; import net.minestom.server.coordinate.Pos; import net.minestom.server.event.item.PickupItemEvent; import net.minestom.server.instance.Instance; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -22,16 +22,16 @@ public class EntityBoundingBoxIntegrationTest { // Bounding box should be from the registry assertEquals(player.getEntityType().registry().boundingBox(), player.getBoundingBox()); - player.setPose(Entity.Pose.STANDING); + player.setPose(EntityPose.STANDING); assertEquals(player.getEntityType().registry().boundingBox(), player.getBoundingBox()); - player.setPose(Entity.Pose.SLEEPING); + player.setPose(EntityPose.SLEEPING); assertEquals(new BoundingBox(0.2, 0.2, 0.2), player.getBoundingBox()); - player.setPose(Entity.Pose.SNEAKING); + player.setPose(EntityPose.SNEAKING); assertEquals(new BoundingBox(0.6, 1.5, 0.6), player.getBoundingBox()); - player.setPose(Entity.Pose.FALL_FLYING); + player.setPose(EntityPose.FALL_FLYING); assertEquals(new BoundingBox(0.6, 0.6, 0.6), player.getBoundingBox()); } @@ -43,13 +43,13 @@ public class EntityBoundingBoxIntegrationTest { assertEquals(1.62, player.getEyeHeight()); - player.setPose(Entity.Pose.SLEEPING); + player.setPose(EntityPose.SLEEPING); assertEquals(0.2, player.getEyeHeight()); - player.setPose(Entity.Pose.SNEAKING); + player.setPose(EntityPose.SNEAKING); assertEquals(1.27, player.getEyeHeight()); - player.setPose(Entity.Pose.FALL_FLYING); + player.setPose(EntityPose.FALL_FLYING); assertEquals(0.4, player.getEyeHeight()); } diff --git a/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java index fdd5a2554..bf3e916e2 100644 --- a/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java @@ -47,7 +47,7 @@ public class EntityMetaIntegrationTest { } else if (entry.type() == Metadata.TYPE_BOOLEAN) { assertTrue((boolean) content); } else if (entry.type() == Metadata.TYPE_POSE) { - assertEquals(Entity.Pose.SNEAKING, content); + assertEquals(EntityPose.SNEAKING, content); } else { Assertions.fail("Invalid MetaData entry"); } @@ -66,7 +66,7 @@ public class EntityMetaIntegrationTest { } else if (entry.type() == Metadata.TYPE_BOOLEAN) { assertFalse((boolean) content); } else if (entry.type() == Metadata.TYPE_POSE) { - assertEquals(Entity.Pose.STANDING, content); + assertEquals(EntityPose.STANDING, content); } else { Assertions.fail("Invalid MetaData entry"); } diff --git a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java index 60b296aaf..c6e0a8c33 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java @@ -2,7 +2,7 @@ package net.minestom.server.entity.player; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.GameMode; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.instance.block.predicate.BlockPredicate; @@ -39,7 +39,7 @@ public class PlayerBlockPlacementIntegrationTest { player.setItemInMainHand(ItemStack.builder(Material.WHITE_WOOL).set(ItemComponent.CAN_PLACE_ON, canPlaceOn).build()); var packet = new ClientPlayerBlockPlacementPacket( - Player.Hand.MAIN, new Pos(2, 41, 0), BlockFace.WEST, + PlayerHand.MAIN, new Pos(2, 41, 0), BlockFace.WEST, 1f, 1f, 1f, false, 0 ); diff --git a/src/test/java/net/minestom/server/instance/BlockPlaceIntegrationTest.java b/src/test/java/net/minestom/server/instance/BlockPlaceIntegrationTest.java index f353e4aa8..342bb5ed5 100644 --- a/src/test/java/net/minestom/server/instance/BlockPlaceIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/BlockPlaceIntegrationTest.java @@ -1,7 +1,7 @@ package net.minestom.server.instance; import net.minestom.server.coordinate.Pos; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.item.ItemStack; @@ -30,11 +30,11 @@ public class BlockPlaceIntegrationTest { Instance instance = env.createFlatInstance(); instance.setWorldBorder(WorldBorder.DEFAULT_BORDER.withDiameter(1)); var player = env.createPlayer(instance, new Pos(0, 40, 0)); - player.setItemInHand(Player.Hand.MAIN, ItemStack.of(Material.STONE, 5)); + player.setItemInHand(PlayerHand.MAIN, ItemStack.of(Material.STONE, 5)); // Should be air, then we place (this is outside the border) assertEquals(Block.AIR, instance.getBlock(3, 40, 0)); - var placePacket = new ClientPlayerBlockPlacementPacket(Player.Hand.MAIN, new Pos(3, 39, 0), BlockFace.TOP, 0.5f, 0.5f, 0.5f, false, 1); + var placePacket = new ClientPlayerBlockPlacementPacket(PlayerHand.MAIN, new Pos(3, 39, 0), BlockFace.TOP, 0.5f, 0.5f, 0.5f, false, 1); BlockPlacementListener.listener(placePacket, player); // Should still be air @@ -46,12 +46,12 @@ public class BlockPlaceIntegrationTest { void testPlacementAtMinus64(Env env) { Instance instance = env.createFlatInstance(); var player = env.createPlayer(instance, new Pos(0, -64, 0)); - player.setItemInHand(Player.Hand.MAIN, ItemStack.of(Material.STONE, 5)); + player.setItemInHand(PlayerHand.MAIN, ItemStack.of(Material.STONE, 5)); env.tick(); // World border tick to update distance // Should be air, then we place assertEquals(Block.AIR, instance.getBlock(3, -64, 0)); - var placePacket = new ClientPlayerBlockPlacementPacket(Player.Hand.MAIN, new Pos(3, -64, 0), BlockFace.TOP, 0.5f, 0.5f, 0.5f, false, 1); + var placePacket = new ClientPlayerBlockPlacementPacket(PlayerHand.MAIN, new Pos(3, -64, 0), BlockFace.TOP, 0.5f, 0.5f, 0.5f, false, 1); BlockPlacementListener.listener(placePacket, player); // Should be stone. diff --git a/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java b/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java index ade807db3..7fcd6f7d5 100644 --- a/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java +++ b/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java @@ -2,7 +2,7 @@ package net.minestom.server.listener; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.EquipmentSlot; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventFilter; import net.minestom.server.event.player.PlayerUseItemEvent; import net.minestom.server.item.ItemStack; @@ -27,10 +27,10 @@ public class TestUseItemListenerIntegration { var itemStack = ItemStack.of(Material.DIAMOND); player.setItemInMainHand(itemStack); - UseItemListener.useItemListener(new ClientUseItemPacket(Player.Hand.MAIN, 42, 0f, 0f), player); + UseItemListener.useItemListener(new ClientUseItemPacket(PlayerHand.MAIN, 42, 0f, 0f), player); useItemCollector.assertSingle(event -> { - assertEquals(Player.Hand.MAIN, event.getHand()); + assertEquals(PlayerHand.MAIN, event.getHand()); assertEquals(itemStack, event.getItemStack()); assertEquals(0, event.getItemUseTime()); }); @@ -43,7 +43,7 @@ public class TestUseItemListenerIntegration { var boots = ItemStack.of(Material.DIAMOND_BOOTS); player.setItemInMainHand(boots); - UseItemListener.useItemListener(new ClientUseItemPacket(Player.Hand.MAIN, 42, 0f, 0f), player); + UseItemListener.useItemListener(new ClientUseItemPacket(PlayerHand.MAIN, 42, 0f, 0f), player); assertEquals(ItemStack.AIR, player.getItemInMainHand()); assertEquals(boots, player.getEquipment(EquipmentSlot.BOOTS)); @@ -59,7 +59,7 @@ public class TestUseItemListenerIntegration { var boots = ItemStack.of(Material.DIAMOND_BOOTS); player.setItemInMainHand(boots); - UseItemListener.useItemListener(new ClientUseItemPacket(Player.Hand.MAIN, 42, 0f, 0f), player); + UseItemListener.useItemListener(new ClientUseItemPacket(PlayerHand.MAIN, 42, 0f, 0f), player); assertEquals(oldBoots, player.getItemInMainHand()); assertEquals(boots, player.getEquipment(EquipmentSlot.BOOTS)); From 9498b28fda1ab2dc459e791b713f3b32ce00c708 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 21 Jul 2024 18:09:28 +0200 Subject: [PATCH 03/97] Range rework (#2284) * Range rework * Range.Int --- .../arguments/minecraft/ArgumentEntity.java | 6 +- .../minecraft/ArgumentFloatRange.java | 8 +- .../arguments/minecraft/ArgumentIntRange.java | 8 +- .../arguments/minecraft/ArgumentRange.java | 2 +- .../java/net/minestom/server/utils/Range.java | 68 ++++++++++++++ .../server/utils/entity/EntityFinder.java | 18 ++-- .../minestom/server/utils/math/ByteRange.java | 20 ---- .../server/utils/math/DoubleRange.java | 20 ---- .../server/utils/math/FloatRange.java | 19 ---- .../minestom/server/utils/math/IntRange.java | 20 ---- .../minestom/server/utils/math/LongRange.java | 20 ---- .../net/minestom/server/utils/math/Range.java | 93 ------------------- .../server/utils/math/ShortRange.java | 18 ---- .../server/command/ArgumentTypeTest.java | 31 +++---- 14 files changed, 104 insertions(+), 247 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/Range.java delete mode 100644 src/main/java/net/minestom/server/utils/math/ByteRange.java delete mode 100644 src/main/java/net/minestom/server/utils/math/DoubleRange.java delete mode 100644 src/main/java/net/minestom/server/utils/math/FloatRange.java delete mode 100644 src/main/java/net/minestom/server/utils/math/IntRange.java delete mode 100644 src/main/java/net/minestom/server/utils/math/LongRange.java delete mode 100644 src/main/java/net/minestom/server/utils/math/Range.java delete mode 100644 src/main/java/net/minestom/server/utils/math/ShortRange.java diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java index 81156259f..33f3d0214 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java @@ -5,10 +5,10 @@ import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; +import net.minestom.server.utils.Range; import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.entity.EntityFinder; -import net.minestom.server.utils.math.IntRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -252,7 +252,7 @@ public class ArgumentEntity extends Argument { break; case "level": try { - final IntRange level = Argument.parse(sender, new ArgumentIntRange(value)); + final Range.Int level = Argument.parse(sender, new ArgumentIntRange(value)); entityFinder.setLevel(level); } catch (ArgumentSyntaxException e) { throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE); @@ -260,7 +260,7 @@ public class ArgumentEntity extends Argument { break; case "distance": try { - final IntRange distance = Argument.parse(sender, new ArgumentIntRange(value)); + final Range.Int distance = Argument.parse(sender, new ArgumentIntRange(value)); entityFinder.setDistance(distance); } catch (ArgumentSyntaxException e) { throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE); diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentFloatRange.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentFloatRange.java index 7f6ce258a..944492636 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentFloatRange.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentFloatRange.java @@ -1,16 +1,16 @@ package net.minestom.server.command.builder.arguments.minecraft; -import net.minestom.server.utils.math.FloatRange; +import net.minestom.server.utils.Range; /** - * Represents an argument which will give you an {@link FloatRange}. + * Represents an argument which will give you an {@link Range.Float}. *

* Example: ..3, 3.., 5..10, 15 */ -public class ArgumentFloatRange extends ArgumentRange { +public class ArgumentFloatRange extends ArgumentRange { public ArgumentFloatRange(String id) { - super(id, -Float.MAX_VALUE, Float.MAX_VALUE, Float::parseFloat, FloatRange::new); + super(id, -Float.MAX_VALUE, Float.MAX_VALUE, Float::parseFloat, Range.Float::new); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentIntRange.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentIntRange.java index 1ea44245e..c531926e2 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentIntRange.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentIntRange.java @@ -1,16 +1,16 @@ package net.minestom.server.command.builder.arguments.minecraft; -import net.minestom.server.utils.math.IntRange; +import net.minestom.server.utils.Range; /** - * Represents an argument which will give you an {@link IntRange}. + * Represents an argument which will give you an {@link Range.Int}. *

* Example: ..3, 3.., 5..10, 15 */ -public class ArgumentIntRange extends ArgumentRange { +public class ArgumentIntRange extends ArgumentRange { public ArgumentIntRange(String id) { - super(id, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer::parseInt, IntRange::new); + super(id, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer::parseInt, Range.Int::new); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentRange.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentRange.java index 5f53f6e81..7ca9fe4a4 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentRange.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentRange.java @@ -3,7 +3,7 @@ package net.minestom.server.command.builder.arguments.minecraft; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; -import net.minestom.server.utils.math.Range; +import net.minestom.server.utils.Range; import org.jetbrains.annotations.NotNull; import java.util.function.BiFunction; diff --git a/src/main/java/net/minestom/server/utils/Range.java b/src/main/java/net/minestom/server/utils/Range.java new file mode 100644 index 000000000..8c66eb2bc --- /dev/null +++ b/src/main/java/net/minestom/server/utils/Range.java @@ -0,0 +1,68 @@ +package net.minestom.server.utils; + +/** + * Represents the base for any data type that is numeric. + * + * @param The type numeric of the range object. + */ +public sealed interface Range { + record Byte(byte min, byte max) implements Range { + public Byte(byte value) { + this(value, value); + } + + public boolean inRange(byte value) { + return value >= min && value <= max; + } + } + + record Short(short min, short max) implements Range { + public Short(short value) { + this(value, value); + } + + public boolean inRange(short value) { + return value >= min && value <= max; + } + } + + record Int(int min, int max) implements Range { + public Int(int value) { + this(value, value); + } + + public boolean inRange(int value) { + return value >= min && value <= max; + } + } + + record Long(long min, long max) implements Range { + public Long(long value) { + this(value, value); + } + + public boolean inRange(long value) { + return value >= min && value <= max; + } + } + + record Float(float min, float max) implements Range { + public Float(float value) { + this(value, value); + } + + public boolean inRange(float value) { + return value >= min && value <= max; + } + } + + record Double(double min, double max) implements Range { + public Double(double value) { + this(value, value); + } + + public boolean inRange(double value) { + return value >= min && value <= max; + } + } +} diff --git a/src/main/java/net/minestom/server/utils/entity/EntityFinder.java b/src/main/java/net/minestom/server/utils/entity/EntityFinder.java index f319f8d88..82c1ea210 100644 --- a/src/main/java/net/minestom/server/utils/entity/EntityFinder.java +++ b/src/main/java/net/minestom/server/utils/entity/EntityFinder.java @@ -13,7 +13,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.instance.Instance; import net.minestom.server.network.ConnectionManager; import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.math.IntRange; +import net.minestom.server.utils.Range; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,7 +37,7 @@ public class EntityFinder { // Position private Point startPosition; private Float dx, dy, dz; - private IntRange distance; + private Range.Int distance; // By traits private Integer limit; @@ -50,7 +50,7 @@ public class EntityFinder { // Players specific private final ToggleableMap gameModes = new ToggleableMap<>(); - private IntRange level; + private Range.Int level; public EntityFinder setTargetSelector(@NotNull TargetSelector targetSelector) { this.targetSelector = targetSelector; @@ -67,7 +67,7 @@ public class EntityFinder { return this; } - public EntityFinder setDistance(@NotNull IntRange distance) { + public EntityFinder setDistance(@NotNull Range.Int distance) { this.distance = distance; return this; } @@ -77,7 +77,7 @@ public class EntityFinder { return this; } - public EntityFinder setLevel(@NotNull IntRange level) { + public EntityFinder setLevel(@NotNull Range.Int level) { this.level = level; return this; } @@ -148,8 +148,8 @@ public class EntityFinder { // Distance argument if (distance != null) { - final int minDistance = distance.getMinimum(); - final int maxDistance = distance.getMaximum(); + final int minDistance = distance.min(); + final int maxDistance = distance.max(); result = result.stream() .filter(entity -> MathUtils.isBetween(entity.getPosition().distanceSquared(pos), minDistance * minDistance, maxDistance * maxDistance)) .toList(); @@ -195,8 +195,8 @@ public class EntityFinder { // Level if (level != null) { - final int minLevel = level.getMinimum(); - final int maxLevel = level.getMaximum(); + final int minLevel = level.min(); + final int maxLevel = level.max(); result = result.stream() .filter(Player.class::isInstance) .filter(entity -> MathUtils.isBetween(((Player) entity).getLevel(), minLevel, maxLevel)) diff --git a/src/main/java/net/minestom/server/utils/math/ByteRange.java b/src/main/java/net/minestom/server/utils/math/ByteRange.java deleted file mode 100644 index 8509d4037..000000000 --- a/src/main/java/net/minestom/server/utils/math/ByteRange.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.utils.math; - -public class ByteRange extends Range { - - public ByteRange(Byte minimum, Byte maximum) { - super(minimum, maximum); - } - - public ByteRange(Byte value) { - super(value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isInRange(Byte value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - } -} diff --git a/src/main/java/net/minestom/server/utils/math/DoubleRange.java b/src/main/java/net/minestom/server/utils/math/DoubleRange.java deleted file mode 100644 index e117737ce..000000000 --- a/src/main/java/net/minestom/server/utils/math/DoubleRange.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.utils.math; - -public class DoubleRange extends Range { - - public DoubleRange(Double minimum, Double maximum) { - super(minimum, maximum); - } - - public DoubleRange(Double value) { - super(value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isInRange(Double value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - } -} diff --git a/src/main/java/net/minestom/server/utils/math/FloatRange.java b/src/main/java/net/minestom/server/utils/math/FloatRange.java deleted file mode 100644 index 47a1fa972..000000000 --- a/src/main/java/net/minestom/server/utils/math/FloatRange.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.minestom.server.utils.math; - -public class FloatRange extends Range { - - public FloatRange(Float minimum, Float maximum) { - super(minimum, maximum); - } - - public FloatRange(Float value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public boolean isInRange(Float value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - - } -} diff --git a/src/main/java/net/minestom/server/utils/math/IntRange.java b/src/main/java/net/minestom/server/utils/math/IntRange.java deleted file mode 100644 index b06414b7d..000000000 --- a/src/main/java/net/minestom/server/utils/math/IntRange.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.utils.math; - -public class IntRange extends Range { - - public IntRange(Integer minimum, Integer maximum) { - super(minimum, maximum); - } - - public IntRange(Integer value) { - super(value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isInRange(Integer value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - } -} diff --git a/src/main/java/net/minestom/server/utils/math/LongRange.java b/src/main/java/net/minestom/server/utils/math/LongRange.java deleted file mode 100644 index 459a24011..000000000 --- a/src/main/java/net/minestom/server/utils/math/LongRange.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.utils.math; - -public class LongRange extends Range { - - public LongRange(Long minimum, Long maximum) { - super(minimum, maximum); - } - - public LongRange(Long value) { - super(value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isInRange(Long value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - } -} diff --git a/src/main/java/net/minestom/server/utils/math/Range.java b/src/main/java/net/minestom/server/utils/math/Range.java deleted file mode 100644 index 3c27a998d..000000000 --- a/src/main/java/net/minestom/server/utils/math/Range.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.minestom.server.utils.math; - -import java.util.Objects; - -/** - * Represents the base for any data type that is numeric. - * - * @param The type numeric of the range object. - */ -public abstract class Range { - - private T minimum; - private T maximum; - - /** - * Constructs a new {@link Range} with a {@code minimum} and a {@code maximum} value. - * - * @param minimum The minimum of the range. - * @param maximum The maximum of the range. - */ - public Range(T minimum, T maximum) { - this.minimum = minimum; - this.maximum = maximum; - } - - /** - * Constructs a new {@link Range} with the {@code value}. - * - * @param value The value of the range. - */ - public Range(T value) { - this(value, value); - } - - /** - * Retrieves the minimum value of the range. - * - * @return The range's minimum value. - */ - public T getMinimum() { - return this.minimum; - } - - /** - * Changes the minimum value of the range. - * - * @param minimum The new minimum value. - */ - public void setMinimum(T minimum) { - this.minimum = minimum; - } - - /** - * Retrieves the maximum value of the range. - * - * @return The range's maximum value. - */ - public T getMaximum() { - return this.maximum; - } - - /** - * Changes the maximum value of the range. - * - * @param maximum The new maximum value. - */ - public void setMaximum(T maximum) { - this.maximum = maximum; - } - - /** - * Whether the given {@code value} is in range of the minimum and the maximum. - * - * @param value The value to be checked. - * @return {@code true} if the value in the range of {@code minimum} and {@code maximum}, - * otherwise {@code false}. - */ - public abstract boolean isInRange(T value); - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Range range = (Range) o; - return Objects.equals(minimum, range.minimum) && Objects.equals(maximum, range.maximum); - } - - @Override - public int hashCode() { - return Objects.hash(minimum, maximum); - } - -} diff --git a/src/main/java/net/minestom/server/utils/math/ShortRange.java b/src/main/java/net/minestom/server/utils/math/ShortRange.java deleted file mode 100644 index 725212894..000000000 --- a/src/main/java/net/minestom/server/utils/math/ShortRange.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.minestom.server.utils.math; - -public class ShortRange extends Range { - - public ShortRange(Short minimum, Short maximum) { - super(minimum, maximum); - } - - public ShortRange(Short value) { - super(value); - } - - /** {@inheritDoc} */ - @Override - public boolean isInRange(Short value) { - return value >= this.getMinimum() && value <= this.getMaximum(); - } -} diff --git a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java index 7bbdfa6b3..a41e60259 100644 --- a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java +++ b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java @@ -23,9 +23,8 @@ import net.minestom.server.item.Material; import net.minestom.server.item.component.CustomData; import net.minestom.server.particle.Particle; import net.minestom.server.tag.Tag; +import net.minestom.server.utils.Range; import net.minestom.server.utils.location.RelativeVec; -import net.minestom.server.utils.math.FloatRange; -import net.minestom.server.utils.math.IntRange; import net.minestom.server.utils.time.TimeUnit; import org.junit.jupiter.api.Test; @@ -129,14 +128,14 @@ public class ArgumentTypeTest { @Test public void testArgumentFloatRange() { var arg = ArgumentType.FloatRange("float_range"); - assertArg(arg, new FloatRange(0f, 50f), "0..50"); - assertArg(arg, new FloatRange(0f, 0f), "0..0"); - assertArg(arg, new FloatRange(-50f, 0f), "-50..0"); - assertArg(arg, new FloatRange(-Float.MAX_VALUE, 50f), "..50"); - assertArg(arg, new FloatRange(0f, Float.MAX_VALUE), "0.."); - assertArg(arg, new FloatRange(-Float.MAX_VALUE, Float.MAX_VALUE), "-3.4028235E38..3.4028235E38"); - assertArg(arg, new FloatRange(0.5f, 24f), "0.5..24"); - assertArg(arg, new FloatRange(12f, 45.6f), "12..45.6"); + assertArg(arg, new Range.Float(0f, 50f), "0..50"); + assertArg(arg, new Range.Float(0f, 0f), "0..0"); + assertArg(arg, new Range.Float(-50f, 0f), "-50..0"); + assertArg(arg, new Range.Float(-Float.MAX_VALUE, 50f), "..50"); + assertArg(arg, new Range.Float(0f, Float.MAX_VALUE), "0.."); + assertArg(arg, new Range.Float(-Float.MAX_VALUE, Float.MAX_VALUE), "-3.4028235E38..3.4028235E38"); + assertArg(arg, new Range.Float(0.5f, 24f), "0.5..24"); + assertArg(arg, new Range.Float(12f, 45.6f), "12..45.6"); assertInvalidArg(arg, ".."); assertInvalidArg(arg, "0..50.."); } @@ -145,12 +144,12 @@ public class ArgumentTypeTest { public void testArgumentIntRange() { var arg = ArgumentType.IntRange("int_range"); - assertArg(arg, new IntRange(0, 50), "0..50"); - assertArg(arg, new IntRange(0, 0), "0..0"); - assertArg(arg, new IntRange(-50, 0), "-50..0"); - assertArg(arg, new IntRange(Integer.MIN_VALUE, 50), "..50"); - assertArg(arg, new IntRange(0, Integer.MAX_VALUE), "0.."); - assertArg(arg, new IntRange(Integer.MIN_VALUE, Integer.MAX_VALUE), "-2147483648..2147483647"); + assertArg(arg, new Range.Int(0, 50), "0..50"); + assertArg(arg, new Range.Int(0, 0), "0..0"); + assertArg(arg, new Range.Int(-50, 0), "-50..0"); + assertArg(arg, new Range.Int(Integer.MIN_VALUE, 50), "..50"); + assertArg(arg, new Range.Int(0, Integer.MAX_VALUE), "0.."); + assertArg(arg, new Range.Int(Integer.MIN_VALUE, Integer.MAX_VALUE), "-2147483648..2147483647"); assertInvalidArg(arg, ".."); assertInvalidArg(arg, "-2147483649..2147483647"); From be6b723490416dbe1a85a77893840d8cea496d65 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 21 Jul 2024 18:19:49 +0200 Subject: [PATCH 04/97] Remove `MinecraftServer` + `Entity` from packets (#2287) * Remove `MinecraftServer` + `Entity` from packets * No need for static cached packet --- .../java/net/minestom/server/MinecraftServer.java | 2 +- .../java/net/minestom/server/entity/Entity.java | 5 +++-- .../java/net/minestom/server/entity/Player.java | 2 +- .../minestom/server/network/ConnectionManager.java | 13 +++++++++++-- .../packet/server/common/PluginMessagePacket.java | 4 +--- .../network/packet/server/common/TagsPacket.java | 6 ------ .../packet/server/play/AttachEntityPacket.java | 6 ------ .../network/packet/server/play/CameraPacket.java | 5 ----- 8 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 065ca0832..1ea099466 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -108,7 +108,7 @@ public final class MinecraftServer implements MinecraftConstants { */ public static void setBrandName(@NotNull String brandName) { MinecraftServer.brandName = brandName; - PacketUtils.broadcastPlayPacket(PluginMessagePacket.getBrandPacket()); + PacketUtils.broadcastPlayPacket(PluginMessagePacket.brandPacket(brandName)); } /** diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 7ab9b06be..c5f401d9c 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -482,7 +482,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev if (passenger != player) passenger.updateOldViewer(player); } } - leashedEntities.forEach(entity -> player.sendPacket(new AttachEntityPacket(entity, null))); + leashedEntities.forEach(entity -> player.sendPacket(new AttachEntityPacket(entity.getEntityId(), -1))); player.sendPacket(destroyPacketCache); } @@ -1014,7 +1014,8 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev } protected @NotNull AttachEntityPacket getAttachEntityPacket() { - return new AttachEntityPacket(this, leashHolder); + Entity leashHolder = this.leashHolder; + return new AttachEntityPacket(getEntityId(), leashHolder != null ? leashHolder.getEntityId() : -1); } /** diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index bcf210c84..8fe13be0c 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1404,7 +1404,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * @param entity the entity to spectate */ public void spectate(@NotNull Entity entity) { - sendPacket(new CameraPacket(entity)); + sendPacket(new CameraPacket(entity.getEntityId())); } /** diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 14a58b754..b71631171 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -44,6 +44,15 @@ import java.util.stream.Collectors; */ public final class ConnectionManager { private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED); + private CachedPacket defaultTags; + + private CachedPacket getDefaultTags() { + var defaultTags = this.defaultTags; + if (defaultTags == null) { + this.defaultTags = defaultTags = new CachedPacket(new TagsPacket(MinecraftServer.getTagManager().getTagMap())); + } + return defaultTags; + } // All players once their Player object has been instantiated. private final Map connectionPlayerMap = new ConcurrentHashMap<>(); @@ -270,7 +279,7 @@ public final class ConnectionManager { final PlayerConnection connection = player.getPlayerConnection(); connection.setConnectionState(ConnectionState.CONFIGURATION); - player.sendPacket(PluginMessagePacket.getBrandPacket()); + player.sendPacket(PluginMessagePacket.brandPacket(MinecraftServer.getBrandName())); // Request known packs immediately, but don't wait for the response until required (sending registry data). final var knownPacksFuture = connection.requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE)); @@ -313,7 +322,7 @@ public final class ConnectionManager { player.sendPacket(serverProcess.paintingVariant().registryDataPacket(excludeVanilla)); player.sendPacket(serverProcess.jukeboxSong().registryDataPacket(excludeVanilla)); - player.sendPacket(TagsPacket.DEFAULT_TAGS); + player.sendPacket(getDefaultTags()); } // Wait for pending resource packs if any diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java index ede91dd39..c4ad532e3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java @@ -1,6 +1,5 @@ package net.minestom.server.network.packet.server.common; -import net.minestom.server.MinecraftServer; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; @@ -38,8 +37,7 @@ public record PluginMessagePacket(String channel, * * @return the current brand name packet */ - public static @NotNull PluginMessagePacket getBrandPacket() { - final String brandName = MinecraftServer.getBrandName(); + public static @NotNull PluginMessagePacket brandPacket(String brandName) { final byte[] data = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(STRING, brandName)); return new PluginMessagePacket("minecraft:brand", data); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java index ec24448d0..d6682eef2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java @@ -1,12 +1,9 @@ package net.minestom.server.network.packet.server.common; -import net.minestom.server.MinecraftServer; import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; @@ -17,9 +14,6 @@ import static net.minestom.server.network.NetworkBuffer.*; public record TagsPacket( @NotNull Map> tagsMap) implements ServerPacket.Configuration, ServerPacket.Play { - @ApiStatus.Internal - public static final CachedPacket DEFAULT_TAGS = new CachedPacket(new TagsPacket(MinecraftServer.getTagManager().getTagMap())); - public TagsPacket { tagsMap = Map.copyOf(tagsMap); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java index 66878a864..ea9e199ae 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.entity.Entity; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.INT; public record AttachEntityPacket(int attachedEntityId, int holdingEntityId) implements ServerPacket.Play { - public AttachEntityPacket(@NotNull Entity attachedEntity, @Nullable Entity holdingEntity) { - this(attachedEntity.getEntityId(), holdingEntity != null ? holdingEntity.getEntityId() : -1); - } - public AttachEntityPacket(@NotNull NetworkBuffer reader) { this(reader.read(INT), reader.read(INT)); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java index a3656adf8..fae30a2b4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java @@ -1,6 +1,5 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.entity.Entity; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; @@ -13,10 +12,6 @@ public record CameraPacket(int cameraId) implements ServerPacket.Play { this(reader.read(VAR_INT)); } - public CameraPacket(@NotNull Entity camera) { - this(camera.getEntityId()); - } - @Override public void write(@NotNull NetworkBuffer writer) { writer.write(VAR_INT, cameraId); From 020c99fc4434f9e7d4a2787a245db95f5a20e9d5 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 21 Jul 2024 18:29:12 +0200 Subject: [PATCH 05/97] PacketParser (#2283) * PacketParser * Remove old ClientPacketsHandler.java * Use ClassValue, use packetparser subclass --- .../net/minestom/server/MinecraftServer.java | 6 +- .../net/minestom/server/ServerProcess.java | 6 +- .../minestom/server/ServerProcessImpl.java | 12 +- .../server/network/PacketProcessor.java | 64 ---- .../server/network/packet/PacketParser.java | 75 ++++ .../server/network/packet/PacketRegistry.java | 358 ++++++++++++++++++ .../packet/client/ClientPacketsHandler.java | 153 -------- .../server/play/StartConfigurationPacket.java | 4 +- .../player/PlayerSocketConnection.java | 18 +- .../server/network/socket/Server.java | 14 +- .../server/network/socket/Worker.java | 2 +- .../network/socket/ServerAddressTest.java | 11 +- 12 files changed, 476 insertions(+), 247 deletions(-) delete mode 100644 src/main/java/net/minestom/server/network/PacketProcessor.java create mode 100644 src/main/java/net/minestom/server/network/packet/PacketParser.java create mode 100644 src/main/java/net/minestom/server/network/packet/PacketRegistry.java delete mode 100644 src/main/java/net/minestom/server/network/packet/client/ClientPacketsHandler.java diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 1ea099466..9cc7c1870 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -21,7 +21,7 @@ import net.minestom.server.listener.manager.PacketListenerManager; import net.minestom.server.message.ChatType; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.packet.PacketParser; import net.minestom.server.network.packet.server.common.PluginMessagePacket; import net.minestom.server.network.packet.server.play.ServerDifficultyPacket; import net.minestom.server.network.socket.Server; @@ -188,8 +188,8 @@ public final class MinecraftServer implements MinecraftConstants { return serverProcess.bossBar(); } - public static @NotNull PacketProcessor getPacketProcessor() { - return serverProcess.packetProcessor(); + public static @NotNull PacketParser.Client getPacketParser() { + return serverProcess.packetParser(); } public static boolean isStarted() { diff --git a/src/main/java/net/minestom/server/ServerProcess.java b/src/main/java/net/minestom/server/ServerProcess.java index 9b058bab2..4b93d28f2 100644 --- a/src/main/java/net/minestom/server/ServerProcess.java +++ b/src/main/java/net/minestom/server/ServerProcess.java @@ -13,7 +13,7 @@ import net.minestom.server.instance.block.rule.BlockPlacementRule; import net.minestom.server.listener.manager.PacketListenerManager; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.packet.PacketParser; import net.minestom.server.network.socket.Server; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.registry.Registries; @@ -99,11 +99,11 @@ public interface ServerProcess extends Registries, Snapshotable { @NotNull PacketListenerManager packetListener(); /** - * Gets the object handling the client packets processing. + * Gets the object handling the client packets parsing. *

* Can be used if you want to convert a buffer to a client packet object. */ - @NotNull PacketProcessor packetProcessor(); + @NotNull PacketParser.Client packetParser(); /** * Exposed socket server. diff --git a/src/main/java/net/minestom/server/ServerProcessImpl.java b/src/main/java/net/minestom/server/ServerProcessImpl.java index 3d6aa9263..f44894dbd 100644 --- a/src/main/java/net/minestom/server/ServerProcessImpl.java +++ b/src/main/java/net/minestom/server/ServerProcessImpl.java @@ -27,7 +27,7 @@ import net.minestom.server.message.ChatType; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.packet.PacketParser; import net.minestom.server.network.socket.Server; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.registry.DynamicRegistry; @@ -77,7 +77,7 @@ final class ServerProcessImpl implements ServerProcess { private final ConnectionManager connection; private final PacketListenerManager packetListener; - private final PacketProcessor packetProcessor; + private final PacketParser.Client packetParser; private final InstanceManager instance; private final BlockManager block; private final CommandManager command; @@ -122,7 +122,7 @@ final class ServerProcessImpl implements ServerProcess { this.connection = new ConnectionManager(); this.packetListener = new PacketListenerManager(); - this.packetProcessor = new PacketProcessor(packetListener); + this.packetParser = new PacketParser.Client(); this.instance = new InstanceManager(this); this.block = new BlockManager(); this.command = new CommandManager(); @@ -135,7 +135,7 @@ final class ServerProcessImpl implements ServerProcess { this.bossBar = new BossBarManager(); this.tag = new TagManager(); - this.server = new Server(packetProcessor); + this.server = new Server(packetParser); this.dispatcher = ThreadDispatcher.of(ThreadProvider.counter(), ServerFlag.DISPATCHER_THREADS); this.ticker = new TickerImpl(); @@ -287,8 +287,8 @@ final class ServerProcessImpl implements ServerProcess { } @Override - public @NotNull PacketProcessor packetProcessor() { - return packetProcessor; + public @NotNull PacketParser.Client packetParser() { + return packetParser; } @Override diff --git a/src/main/java/net/minestom/server/network/PacketProcessor.java b/src/main/java/net/minestom/server/network/PacketProcessor.java deleted file mode 100644 index 7cadc5256..000000000 --- a/src/main/java/net/minestom/server/network/PacketProcessor.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.minestom.server.network; - -import net.minestom.server.entity.Player; -import net.minestom.server.listener.manager.PacketListenerManager; -import net.minestom.server.network.packet.client.ClientPacket; -import net.minestom.server.network.packet.client.ClientPacketsHandler; -import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; -import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.NotNull; - -import java.nio.ByteBuffer; - -/** - * Responsible for processing client packets. - *

- * You can retrieve the different packet handlers per state (status/login/play) - * from the {@link ClientPacketsHandler} classes. - */ -public class PacketProcessor { - private final ClientPacketsHandler statusHandler; - private final ClientPacketsHandler loginHandler; - private final ClientPacketsHandler configurationHandler; - private final ClientPacketsHandler playHandler; - - private final PacketListenerManager packetListenerManager; - - public PacketProcessor(@NotNull PacketListenerManager packetListenerManager) { - statusHandler = new ClientPacketsHandler.Status(); - loginHandler = new ClientPacketsHandler.Login(); - configurationHandler = new ClientPacketsHandler.Configuration(); - playHandler = new ClientPacketsHandler.Play(); - - this.packetListenerManager = packetListenerManager; - } - - public @NotNull ClientPacket create(@NotNull ConnectionState connectionState, int packetId, ByteBuffer body) { - NetworkBuffer buffer = new NetworkBuffer(body); - final ClientPacket clientPacket = switch (connectionState) { - case HANDSHAKE -> { - assert packetId == 0; - yield new ClientHandshakePacket(buffer); - } - case STATUS -> statusHandler.create(packetId, buffer); - case LOGIN -> loginHandler.create(packetId, buffer); - case CONFIGURATION -> configurationHandler.create(packetId, buffer); - case PLAY -> playHandler.create(packetId, buffer); - }; - body.position(buffer.readIndex()); - return clientPacket; - } - - public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) { - final ClientPacket packet = create(connection.getConnectionState(), packetId, body); - if (packet.processImmediately()) { - packetListenerManager.processClientPacket(packet, connection); - return packet; - } - - final Player player = connection.getPlayer(); - assert player != null; - player.addPacketToQueue(packet); - return packet; - } -} diff --git a/src/main/java/net/minestom/server/network/packet/PacketParser.java b/src/main/java/net/minestom/server/network/packet/PacketParser.java new file mode 100644 index 000000000..1387ae3f4 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/PacketParser.java @@ -0,0 +1,75 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +/** + * Responsible for parsing client & server packets. + *

+ * You can retrieve the different packets per state (status/login/play) + * from the {@link PacketRegistry} classes. + */ +public sealed interface PacketParser { + + @NotNull T parse(@NotNull ConnectionState connectionState, + int packetId, @NotNull NetworkBuffer buffer); + + record Client( + PacketRegistry.Client statusHandler, + PacketRegistry.Client loginHandler, + PacketRegistry.Client configurationHandler, + PacketRegistry.Client playHandler + ) implements PacketParser { + + public Client() { + this(new PacketRegistry.ClientStatus(), new PacketRegistry.ClientLogin(), + new PacketRegistry.ClientConfiguration(), new PacketRegistry.ClientPlay() + ); + } + + @Override + public @NotNull ClientPacket parse(@NotNull ConnectionState connectionState, + int packetId, @NotNull NetworkBuffer buffer) { + return switch (connectionState) { + case HANDSHAKE -> { + assert packetId == 0; + yield new ClientHandshakePacket(buffer); + } + case STATUS -> statusHandler.create(packetId, buffer); + case LOGIN -> loginHandler.create(packetId, buffer); + case CONFIGURATION -> configurationHandler.create(packetId, buffer); + case PLAY -> playHandler.create(packetId, buffer); + }; + } + } + + record Server( + PacketRegistry.Server statusHandler, + PacketRegistry.Server loginHandler, + PacketRegistry.Server configurationHandler, + PacketRegistry.Server playHandler + ) implements PacketParser { + + public Server() { + this(new PacketRegistry.ServerStatus(), new PacketRegistry.ServerLogin(), + new PacketRegistry.ServerConfiguration(), new PacketRegistry.ServerPlay() + ); + } + + @Override + public @NotNull ServerPacket parse(@NotNull ConnectionState connectionState, + int packetId, @NotNull NetworkBuffer buffer) { + return switch (connectionState) { + case HANDSHAKE -> throw new UnsupportedOperationException("No client-bound Handshake packet"); + case STATUS -> statusHandler.create(packetId, buffer); + case LOGIN -> loginHandler.create(packetId, buffer); + case CONFIGURATION -> configurationHandler.create(packetId, buffer); + case PLAY -> playHandler.create(packetId, buffer); + }; + } + } +} diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java new file mode 100644 index 000000000..c9eb3fd14 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -0,0 +1,358 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.client.common.*; +import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; +import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; +import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; +import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; +import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; +import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; +import net.minestom.server.network.packet.client.play.*; +import net.minestom.server.network.packet.client.status.StatusRequestPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.packet.server.common.*; +import net.minestom.server.network.packet.server.configuration.*; +import net.minestom.server.network.packet.server.login.*; +import net.minestom.server.network.packet.server.play.*; +import net.minestom.server.network.packet.server.status.ResponsePacket; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnknownNullability; + +public interface PacketRegistry { + @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader); + + int packetId(@NotNull Class packetClass); + + sealed class Client extends PacketRegistryTemplate { + @SafeVarargs + Client(Entry... suppliers) { + super(suppliers); + } + } + + final class ClientStatus extends Client { + public ClientStatus() { + super( + entry(StatusRequestPacket.class, StatusRequestPacket::new), + entry(ClientPingRequestPacket.class, ClientPingRequestPacket::new) + ); + } + } + + final class ClientLogin extends Client { + public ClientLogin() { + super( + entry(ClientLoginStartPacket.class, ClientLoginStartPacket::new), + entry(ClientEncryptionResponsePacket.class, ClientEncryptionResponsePacket::new), + entry(ClientLoginPluginResponsePacket.class, ClientLoginPluginResponsePacket::new), + entry(ClientLoginAcknowledgedPacket.class, ClientLoginAcknowledgedPacket::new), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new) + ); + } + } + + final class ClientConfiguration extends Client { + public ClientConfiguration() { + super( + entry(ClientSettingsPacket.class, ClientSettingsPacket::new), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new), + entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket::new), + entry(ClientFinishConfigurationPacket.class, ClientFinishConfigurationPacket::new), + entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket::new), + entry(ClientPongPacket.class, ClientPongPacket::new), + entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket::new), + entry(ClientSelectKnownPacksPacket.class, ClientSelectKnownPacksPacket::new) + ); + } + } + + final class ClientPlay extends Client { + public ClientPlay() { + super( + entry(ClientTeleportConfirmPacket.class, ClientTeleportConfirmPacket::new), + entry(ClientQueryBlockNbtPacket.class, ClientQueryBlockNbtPacket::new), + null, // difficulty packet + entry(ClientChatAckPacket.class, ClientChatAckPacket::new), + entry(ClientCommandChatPacket.class, ClientCommandChatPacket::new), + entry(ClientSignedCommandChatPacket.class, ClientSignedCommandChatPacket::new), + entry(ClientChatMessagePacket.class, ClientChatMessagePacket::new), + entry(ClientChatSessionUpdatePacket.class, ClientChatSessionUpdatePacket::new), + entry(ClientChunkBatchReceivedPacket.class, ClientChunkBatchReceivedPacket::new), + entry(ClientStatusPacket.class, ClientStatusPacket::new), + entry(ClientSettingsPacket.class, ClientSettingsPacket::new), + entry(ClientTabCompletePacket.class, ClientTabCompletePacket::new), + entry(ClientConfigurationAckPacket.class, ClientConfigurationAckPacket::new), + entry(ClientClickWindowButtonPacket.class, ClientClickWindowButtonPacket::new), + entry(ClientClickWindowPacket.class, ClientClickWindowPacket::new), + entry(ClientCloseWindowPacket.class, ClientCloseWindowPacket::new), + entry(ClientWindowSlotStatePacket.class, ClientWindowSlotStatePacket::new), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new), + entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket::new), + entry(ClientDebugSampleSubscriptionPacket.class, ClientDebugSampleSubscriptionPacket::new), + entry(ClientEditBookPacket.class, ClientEditBookPacket::new), + entry(ClientQueryEntityNbtPacket.class, ClientQueryEntityNbtPacket::new), + entry(ClientInteractEntityPacket.class, ClientInteractEntityPacket::new), + entry(ClientGenerateStructurePacket.class, ClientGenerateStructurePacket::new), + entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket::new), + null, // lock difficulty + entry(ClientPlayerPositionPacket.class, ClientPlayerPositionPacket::new), + entry(ClientPlayerPositionAndRotationPacket.class, ClientPlayerPositionAndRotationPacket::new), + entry(ClientPlayerRotationPacket.class, ClientPlayerRotationPacket::new), + entry(ClientPlayerPacket.class, ClientPlayerPacket::new), + entry(ClientVehicleMovePacket.class, ClientVehicleMovePacket::new), + entry(ClientSteerBoatPacket.class, ClientSteerBoatPacket::new), + entry(ClientPickItemPacket.class, ClientPickItemPacket::new), + entry(ClientPingRequestPacket.class, ClientPingRequestPacket::new), + entry(ClientCraftRecipeRequest.class, ClientCraftRecipeRequest::new), + entry(ClientPlayerAbilitiesPacket.class, ClientPlayerAbilitiesPacket::new), + entry(ClientPlayerDiggingPacket.class, ClientPlayerDiggingPacket::new), + entry(ClientEntityActionPacket.class, ClientEntityActionPacket::new), + entry(ClientSteerVehiclePacket.class, ClientSteerVehiclePacket::new), + entry(ClientPongPacket.class, ClientPongPacket::new), + entry(ClientSetRecipeBookStatePacket.class, ClientSetRecipeBookStatePacket::new), + entry(ClientSetDisplayedRecipePacket.class, ClientSetDisplayedRecipePacket::new), + entry(ClientNameItemPacket.class, ClientNameItemPacket::new), + entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket::new), + entry(ClientAdvancementTabPacket.class, ClientAdvancementTabPacket::new), + entry(ClientSelectTradePacket.class, ClientSelectTradePacket::new), + entry(ClientSetBeaconEffectPacket.class, ClientSetBeaconEffectPacket::new), + entry(ClientHeldItemChangePacket.class, ClientHeldItemChangePacket::new), + entry(ClientUpdateCommandBlockPacket.class, ClientUpdateCommandBlockPacket::new), + entry(ClientUpdateCommandBlockMinecartPacket.class, ClientUpdateCommandBlockMinecartPacket::new), + entry(ClientCreativeInventoryActionPacket.class, ClientCreativeInventoryActionPacket::new), + null, // Update Jigsaw Block + entry(ClientUpdateStructureBlockPacket.class, ClientUpdateStructureBlockPacket::new), + entry(ClientUpdateSignPacket.class, ClientUpdateSignPacket::new), + entry(ClientAnimationPacket.class, ClientAnimationPacket::new), + entry(ClientSpectatePacket.class, ClientSpectatePacket::new), + entry(ClientPlayerBlockPlacementPacket.class, ClientPlayerBlockPlacementPacket::new), + entry(ClientUseItemPacket.class, ClientUseItemPacket::new) + ); + } + } + + sealed class Server extends PacketRegistryTemplate { + @SafeVarargs + Server(Entry... suppliers) { + super(suppliers); + } + } + + final class ServerStatus extends Server { + public ServerStatus() { + super( + entry(ResponsePacket.class, ResponsePacket::new), + entry(PingResponsePacket.class, PingResponsePacket::new) + ); + } + } + + final class ServerLogin extends Server { + public ServerLogin() { + super( + entry(LoginDisconnectPacket.class, LoginDisconnectPacket::new), + entry(EncryptionRequestPacket.class, EncryptionRequestPacket::new), + entry(LoginSuccessPacket.class, LoginSuccessPacket::new), + entry(SetCompressionPacket.class, SetCompressionPacket::new), + entry(LoginPluginRequestPacket.class, LoginPluginRequestPacket::new), + entry(CookieRequestPacket.class, CookieRequestPacket::new) + ); + } + } + + final class ServerConfiguration extends Server { + public ServerConfiguration() { + super( + entry(CookieRequestPacket.class, CookieRequestPacket::new), + entry(PluginMessagePacket.class, PluginMessagePacket::new), + entry(DisconnectPacket.class, DisconnectPacket::new), + entry(FinishConfigurationPacket.class, FinishConfigurationPacket::new), + entry(KeepAlivePacket.class, KeepAlivePacket::new), + entry(PingPacket.class, PingPacket::new), + entry(ResetChatPacket.class, ResetChatPacket::new), + entry(RegistryDataPacket.class, RegistryDataPacket::new), + entry(ResourcePackPopPacket.class, ResourcePackPopPacket::new), + entry(ResourcePackPushPacket.class, ResourcePackPushPacket::new), + entry(CookieStorePacket.class, CookieStorePacket::new), + entry(TransferPacket.class, TransferPacket::new), + entry(UpdateEnabledFeaturesPacket.class, UpdateEnabledFeaturesPacket::new), + entry(TagsPacket.class, TagsPacket::new), + entry(SelectKnownPacksPacket.class, SelectKnownPacksPacket::new), + entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket::new), + entry(ServerLinksPacket.class, ServerLinksPacket::new) + ); + } + } + + final class ServerPlay extends Server { + public ServerPlay() { + super( + entry(BundlePacket.class, BundlePacket::new), + entry(SpawnEntityPacket.class, SpawnEntityPacket::new), + entry(SpawnExperienceOrbPacket.class, SpawnExperienceOrbPacket::new), + entry(EntityAnimationPacket.class, EntityAnimationPacket::new), + entry(StatisticsPacket.class, StatisticsPacket::new), + entry(AcknowledgeBlockChangePacket.class, AcknowledgeBlockChangePacket::new), + entry(BlockBreakAnimationPacket.class, BlockBreakAnimationPacket::new), + entry(BlockEntityDataPacket.class, BlockEntityDataPacket::new), + entry(BlockActionPacket.class, BlockActionPacket::new), + entry(BlockChangePacket.class, BlockChangePacket::new), + entry(BossBarPacket.class, BossBarPacket::new), + entry(ServerDifficultyPacket.class, ServerDifficultyPacket::new), + entry(ChunkBatchFinishedPacket.class, ChunkBatchFinishedPacket::new), + entry(ChunkBatchStartPacket.class, ChunkBatchStartPacket::new), + null, // CHUNK_BIOMES + entry(ClearTitlesPacket.class, ClearTitlesPacket::new), + entry(TabCompletePacket.class, TabCompletePacket::new), + entry(DeclareCommandsPacket.class, DeclareCommandsPacket::new), + entry(CloseWindowPacket.class, CloseWindowPacket::new), + entry(WindowItemsPacket.class, WindowItemsPacket::new), + entry(WindowPropertyPacket.class, WindowPropertyPacket::new), + entry(SetSlotPacket.class, SetSlotPacket::new), + entry(CookieRequestPacket.class, CookieRequestPacket::new), + entry(SetCooldownPacket.class, SetCooldownPacket::new), + entry(CustomChatCompletionPacket.class, CustomChatCompletionPacket::new), + entry(PluginMessagePacket.class, PluginMessagePacket::new), + entry(DamageEventPacket.class, DamageEventPacket::new), + entry(DebugSamplePacket.class, DebugSamplePacket::new), + entry(DeleteChatPacket.class, DeleteChatPacket::new), + entry(DisconnectPacket.class, DisconnectPacket::new), + null, // DISGUISED_CHAT + entry(EntityStatusPacket.class, EntityStatusPacket::new), + entry(ExplosionPacket.class, ExplosionPacket::new), + entry(UnloadChunkPacket.class, UnloadChunkPacket::new), + entry(ChangeGameStatePacket.class, ChangeGameStatePacket::new), + entry(OpenHorseWindowPacket.class, OpenHorseWindowPacket::new), + entry(HitAnimationPacket.class, HitAnimationPacket::new), + entry(InitializeWorldBorderPacket.class, InitializeWorldBorderPacket::new), + entry(KeepAlivePacket.class, KeepAlivePacket::new), + entry(ChunkDataPacket.class, ChunkDataPacket::new), + entry(EffectPacket.class, EffectPacket::new), + entry(ParticlePacket.class, ParticlePacket::new), + entry(UpdateLightPacket.class, UpdateLightPacket::new), + entry(JoinGamePacket.class, JoinGamePacket::new), + entry(MapDataPacket.class, MapDataPacket::new), + entry(TradeListPacket.class, TradeListPacket::new), + entry(EntityPositionPacket.class, EntityPositionPacket::new), + entry(EntityPositionAndRotationPacket.class, EntityPositionAndRotationPacket::new), + entry(EntityRotationPacket.class, EntityRotationPacket::new), + entry(VehicleMovePacket.class, VehicleMovePacket::new), + entry(OpenBookPacket.class, OpenBookPacket::new), + entry(OpenWindowPacket.class, OpenWindowPacket::new), + entry(OpenSignEditorPacket.class, OpenSignEditorPacket::new), + entry(PingPacket.class, PingPacket::new), + entry(PingResponsePacket.class, PingResponsePacket::new), + entry(CraftRecipeResponse.class, CraftRecipeResponse::new), + entry(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new), + entry(PlayerChatMessagePacket.class, PlayerChatMessagePacket::new), + entry(EndCombatEventPacket.class, EndCombatEventPacket::new), + entry(EnterCombatEventPacket.class, EnterCombatEventPacket::new), + entry(DeathCombatEventPacket.class, DeathCombatEventPacket::new), + entry(PlayerInfoRemovePacket.class, PlayerInfoRemovePacket::new), + entry(PlayerInfoUpdatePacket.class, PlayerInfoUpdatePacket::new), + entry(FacePlayerPacket.class, FacePlayerPacket::new), + entry(PlayerPositionAndLookPacket.class, PlayerPositionAndLookPacket::new), + entry(UnlockRecipesPacket.class, UnlockRecipesPacket::new), + entry(DestroyEntitiesPacket.class, DestroyEntitiesPacket::new), + entry(RemoveEntityEffectPacket.class, RemoveEntityEffectPacket::new), + entry(ResetScorePacket.class, ResetScorePacket::new), + entry(ResourcePackPopPacket.class, ResourcePackPopPacket::new), + entry(ResourcePackPushPacket.class, ResourcePackPushPacket::new), + entry(RespawnPacket.class, RespawnPacket::new), + entry(EntityHeadLookPacket.class, EntityHeadLookPacket::new), + entry(MultiBlockChangePacket.class, MultiBlockChangePacket::new), + entry(SelectAdvancementTabPacket.class, SelectAdvancementTabPacket::new), + entry(ServerDataPacket.class, ServerDataPacket::new), + entry(ActionBarPacket.class, ActionBarPacket::new), + entry(WorldBorderCenterPacket.class, WorldBorderCenterPacket::new), + entry(WorldBorderLerpSizePacket.class, WorldBorderLerpSizePacket::new), + entry(WorldBorderSizePacket.class, WorldBorderSizePacket::new), + entry(WorldBorderWarningDelayPacket.class, WorldBorderWarningDelayPacket::new), + entry(WorldBorderWarningReachPacket.class, WorldBorderWarningReachPacket::new), + entry(CameraPacket.class, CameraPacket::new), + entry(HeldItemChangePacket.class, HeldItemChangePacket::new), + entry(UpdateViewPositionPacket.class, UpdateViewPositionPacket::new), + entry(UpdateViewDistancePacket.class, UpdateViewDistancePacket::new), + entry(SpawnPositionPacket.class, SpawnPositionPacket::new), + entry(DisplayScoreboardPacket.class, DisplayScoreboardPacket::new), + entry(EntityMetaDataPacket.class, EntityMetaDataPacket::new), + entry(AttachEntityPacket.class, AttachEntityPacket::new), + entry(EntityVelocityPacket.class, EntityVelocityPacket::new), + entry(EntityEquipmentPacket.class, EntityEquipmentPacket::new), + entry(SetExperiencePacket.class, SetExperiencePacket::new), + entry(UpdateHealthPacket.class, UpdateHealthPacket::new), + entry(ScoreboardObjectivePacket.class, ScoreboardObjectivePacket::new), + entry(SetPassengersPacket.class, SetPassengersPacket::new), + entry(TeamsPacket.class, TeamsPacket::new), + entry(UpdateScorePacket.class, UpdateScorePacket::new), + entry(UpdateSimulationDistancePacket.class, UpdateSimulationDistancePacket::new), + entry(SetTitleSubTitlePacket.class, SetTitleSubTitlePacket::new), + entry(TimeUpdatePacket.class, TimeUpdatePacket::new), + entry(SetTitleTextPacket.class, SetTitleTextPacket::new), + entry(SetTitleTimePacket.class, SetTitleTimePacket::new), + entry(EntitySoundEffectPacket.class, EntitySoundEffectPacket::new), + entry(SoundEffectPacket.class, SoundEffectPacket::new), + entry(StartConfigurationPacket.class, StartConfigurationPacket::new), + entry(StopSoundPacket.class, StopSoundPacket::new), + entry(CookieStorePacket.class, CookieStorePacket::new), + entry(SystemChatPacket.class, SystemChatPacket::new), + entry(PlayerListHeaderAndFooterPacket.class, PlayerListHeaderAndFooterPacket::new), + entry(NbtQueryResponsePacket.class, NbtQueryResponsePacket::new), + entry(CollectItemPacket.class, CollectItemPacket::new), + entry(EntityTeleportPacket.class, EntityTeleportPacket::new), + entry(SetTickStatePacket.class, SetTickStatePacket::new), + entry(TickStepPacket.class, TickStepPacket::new), + entry(TransferPacket.class, TransferPacket::new), + entry(AdvancementsPacket.class, AdvancementsPacket::new), + entry(EntityAttributesPacket.class, EntityAttributesPacket::new), + entry(EntityEffectPacket.class, EntityEffectPacket::new), + entry(DeclareRecipesPacket.class, DeclareRecipesPacket::new), + entry(TagsPacket.class, TagsPacket::new), + entry(ProjectilePowerPacket.class, ProjectilePowerPacket::new), + entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket::new), + entry(ServerLinksPacket.class, ServerLinksPacket::new) + ); + } + } + + sealed class PacketRegistryTemplate implements PacketRegistry { + private final Entry[] suppliers; + private final ClassValue packetIds = new ClassValue<>() { + @Override + protected Integer computeValue(@NotNull Class type) { + for (int i = 0; i < suppliers.length; i++) { + if (suppliers[i].type == type) return i; + } + throw new IllegalStateException("Packet type " + type + " isn't registered!"); + } + }; + + @SafeVarargs + PacketRegistryTemplate(Entry... suppliers) { + this.suppliers = suppliers; + } + + public @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader) { + final Entry entry = suppliers[packetId]; + final NetworkBuffer.Reader supplier = entry.reader; + if (supplier == null) + throw new IllegalStateException("Packet id 0x" + Integer.toHexString(packetId) + " isn't registered!"); + return supplier.read(reader); + } + + @Override + public int packetId(@NotNull Class packetClass) { + return packetIds.get(packetClass); + } + + record Entry(Class type, NetworkBuffer.Reader reader) { + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static Entry entry(Class type, NetworkBuffer.Reader reader) { + return new Entry<>((Class) type, reader); + } + } +} diff --git a/src/main/java/net/minestom/server/network/packet/client/ClientPacketsHandler.java b/src/main/java/net/minestom/server/network/packet/client/ClientPacketsHandler.java deleted file mode 100644 index 91d739fa4..000000000 --- a/src/main/java/net/minestom/server/network/packet/client/ClientPacketsHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -package net.minestom.server.network.packet.client; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.client.common.*; -import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; -import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; -import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; -import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; -import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; -import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; -import net.minestom.server.network.packet.client.play.*; -import net.minestom.server.network.packet.client.status.StatusRequestPacket; -import net.minestom.server.utils.collection.ObjectArray; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.UnknownNullability; - -/** - * Contains registered packets and a way to instantiate them. - *

- * Packets are registered using {@link #register(int, NetworkBuffer.Reader)} and created using {@link #create(int, NetworkBuffer)}. - */ -public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, ClientPacketsHandler.Login, ClientPacketsHandler.Configuration, ClientPacketsHandler.Play { - private final ObjectArray> suppliers = ObjectArray.singleThread(0x10); - - private ClientPacketsHandler() { - } - - public void register(int id, @NotNull NetworkBuffer.Reader packetSupplier) { - this.suppliers.set(id, packetSupplier); - } - - public @UnknownNullability ClientPacket create(int packetId, @NotNull NetworkBuffer reader) { - final NetworkBuffer.Reader supplier = suppliers.get(packetId); - if (supplier == null) - throw new IllegalStateException("Packet id 0x" + Integer.toHexString(packetId) + " isn't registered!"); - return supplier.read(reader); - } - - public static final class Status extends ClientPacketsHandler { - private static int nextId = 0; - private static int nextId() { - return nextId++; - } - - public Status() { - register(nextId(), StatusRequestPacket::new); - register(nextId(), ClientPingRequestPacket::new); - } - } - - public static final class Login extends ClientPacketsHandler { - private static int nextId = 0; - private static int nextId() { - return nextId++; - } - - public Login() { - register(nextId(), ClientLoginStartPacket::new); - register(nextId(), ClientEncryptionResponsePacket::new); - register(nextId(), ClientLoginPluginResponsePacket::new); - register(nextId(), ClientLoginAcknowledgedPacket::new); - register(nextId(), ClientCookieResponsePacket::new); - } - } - - public static final class Configuration extends ClientPacketsHandler { - private static int nextId = 0; - private static int nextId() { - return nextId++; - } - - public Configuration() { - register(nextId(), ClientSettingsPacket::new); - register(nextId(), ClientCookieResponsePacket::new); - register(nextId(), ClientPluginMessagePacket::new); - register(nextId(), ClientFinishConfigurationPacket::new); - register(nextId(), ClientKeepAlivePacket::new); - register(nextId(), ClientPongPacket::new); - register(nextId(), ClientResourcePackStatusPacket::new); - register(nextId(), ClientSelectKnownPacksPacket::new); - } - - } - - public static final class Play extends ClientPacketsHandler { - private static int nextId = 0; - - private static int nextId() { - return nextId++; - } - - public Play() { - register(nextId(), ClientTeleportConfirmPacket::new); - register(nextId(), ClientQueryBlockNbtPacket::new); - nextId(); // difficulty packet - register(nextId(), ClientChatAckPacket::new); - register(nextId(), ClientCommandChatPacket::new); - register(nextId(), ClientSignedCommandChatPacket::new); - register(nextId(), ClientChatMessagePacket::new); - register(nextId(), ClientChatSessionUpdatePacket::new); - register(nextId(), ClientChunkBatchReceivedPacket::new); - register(nextId(), ClientStatusPacket::new); - register(nextId(), ClientSettingsPacket::new); - register(nextId(), ClientTabCompletePacket::new); - register(nextId(), ClientConfigurationAckPacket::new); - register(nextId(), ClientClickWindowButtonPacket::new); - register(nextId(), ClientClickWindowPacket::new); - register(nextId(), ClientCloseWindowPacket::new); - register(nextId(), ClientWindowSlotStatePacket::new); - register(nextId(), ClientCookieResponsePacket::new); - register(nextId(), ClientPluginMessagePacket::new); - register(nextId(), ClientDebugSampleSubscriptionPacket::new); - register(nextId(), ClientEditBookPacket::new); - register(nextId(), ClientQueryEntityNbtPacket::new); - register(nextId(), ClientInteractEntityPacket::new); - register(nextId(), ClientGenerateStructurePacket::new); - register(nextId(), ClientKeepAlivePacket::new); - nextId(); // lock difficulty - register(nextId(), ClientPlayerPositionPacket::new); - register(nextId(), ClientPlayerPositionAndRotationPacket::new); - register(nextId(), ClientPlayerRotationPacket::new); - register(nextId(), ClientPlayerPacket::new); - register(nextId(), ClientVehicleMovePacket::new); - register(nextId(), ClientSteerBoatPacket::new); - register(nextId(), ClientPickItemPacket::new); - register(nextId(), ClientPingRequestPacket::new); - register(nextId(), ClientCraftRecipeRequest::new); - register(nextId(), ClientPlayerAbilitiesPacket::new); - register(nextId(), ClientPlayerDiggingPacket::new); - register(nextId(), ClientEntityActionPacket::new); - register(nextId(), ClientSteerVehiclePacket::new); - register(nextId(), ClientPongPacket::new); - register(nextId(), ClientSetRecipeBookStatePacket::new); - register(nextId(), ClientSetDisplayedRecipePacket::new); - register(nextId(), ClientNameItemPacket::new); - register(nextId(), ClientResourcePackStatusPacket::new); - register(nextId(), ClientAdvancementTabPacket::new); - register(nextId(), ClientSelectTradePacket::new); - register(nextId(), ClientSetBeaconEffectPacket::new); - register(nextId(), ClientHeldItemChangePacket::new); - register(nextId(), ClientUpdateCommandBlockPacket::new); - register(nextId(), ClientUpdateCommandBlockMinecartPacket::new); - register(nextId(), ClientCreativeInventoryActionPacket::new); - nextId(); // Update Jigsaw Block - register(nextId(), ClientUpdateStructureBlockPacket::new); - register(nextId(), ClientUpdateSignPacket::new); - register(nextId(), ClientAnimationPacket::new); - register(nextId(), ClientSpectatePacket::new); - register(nextId(), ClientPlayerBlockPlacementPacket::new); - register(nextId(), ClientUseItemPacket::new); - } - } -} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java index 60c4928a1..d48551863 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java @@ -4,9 +4,11 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public record StartConfigurationPacket() implements ServerPacket.Play { + public StartConfigurationPacket(NetworkBuffer reader) { + this(); + } @Override public void write(@NotNull NetworkBuffer writer) { diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index fefbf9c00..2f2fe09f8 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -7,7 +7,8 @@ import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.ListenerHandle; import net.minestom.server.event.player.PlayerPacketOutEvent; import net.minestom.server.extras.mojangAuth.MojangCrypt; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketParser; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.server.*; @@ -78,7 +79,7 @@ public class PlayerSocketConnection extends PlayerConnection { this.remoteAddress = remoteAddress; } - public void processPackets(BinaryBuffer readBuffer, PacketProcessor packetProcessor) { + public void processPackets(BinaryBuffer readBuffer, PacketParser.Client packetParser) { // Decrypt data { final EncryptionContext encryptionContext = this.encryptionContext; @@ -100,7 +101,18 @@ public class PlayerSocketConnection extends PlayerConnection { return; // Prevent packet corruption ClientPacket packet = null; try { - packet = packetProcessor.process(this, id, payload); + NetworkBuffer networkBuffer = new NetworkBuffer(payload); + packet = packetParser.parse(getConnectionState(), id, networkBuffer); + payload.position(networkBuffer.readIndex()); + // Process the packet + if (packet.processImmediately()) { + MinecraftServer.getPacketListenerManager().processClientPacket(packet, this); + } else { + // To be processed during the next player tick + final Player player = getPlayer(); + assert player != null; + player.addPacketToQueue(packet); + } } catch (Exception e) { // Error while reading the packet MinecraftServer.getExceptionManager().handleException(e); diff --git a/src/main/java/net/minestom/server/network/socket/Server.java b/src/main/java/net/minestom/server/network/socket/Server.java index 38a556924..ee5f0224c 100644 --- a/src/main/java/net/minestom/server/network/socket/Server.java +++ b/src/main/java/net/minestom/server/network/socket/Server.java @@ -2,7 +2,7 @@ package net.minestom.server.network.socket; import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.packet.PacketParser; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -24,7 +24,7 @@ public final class Server { private volatile boolean stop; private final Selector selector = Selector.open(); - private final PacketProcessor packetProcessor; + private final PacketParser.Client packetParser; private final List workers; private int index; @@ -33,8 +33,8 @@ public final class Server { private String address; private int port; - public Server(PacketProcessor packetProcessor) throws IOException { - this.packetProcessor = packetProcessor; + public Server(PacketParser.Client packetParser) throws IOException { + this.packetParser = packetParser; Worker[] workers = new Worker[ServerFlag.WORKER_COUNT]; Arrays.setAll(workers, value -> new Worker(this)); this.workers = List.of(workers); @@ -103,7 +103,7 @@ public final class Server { public void stop() { this.stop = true; try { - if(serverSocket != null) { + if (serverSocket != null) { this.serverSocket.close(); } @@ -124,8 +124,8 @@ public final class Server { } @ApiStatus.Internal - public @NotNull PacketProcessor packetProcessor() { - return packetProcessor; + public @NotNull PacketParser.Client packetParser() { + return packetParser; } public SocketAddress socketAddress() { diff --git a/src/main/java/net/minestom/server/network/socket/Worker.java b/src/main/java/net/minestom/server/network/socket/Worker.java index 2050976f3..40b2c5097 100644 --- a/src/main/java/net/minestom/server/network/socket/Worker.java +++ b/src/main/java/net/minestom/server/network/socket/Worker.java @@ -100,7 +100,7 @@ public final class Worker extends MinestomThread { connection.consumeCache(readBuffer); // Read & process readBuffer.readChannel(channel); - connection.processPackets(readBuffer, server.packetProcessor()); + connection.processPackets(readBuffer, server.packetParser()); } } catch (IOException e) { // TODO print exception? (should ignore disconnection) diff --git a/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java b/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java index e3d5357e8..d38b84d04 100644 --- a/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java +++ b/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java @@ -1,7 +1,6 @@ package net.minestom.server.network.socket; -import net.minestom.server.listener.manager.PacketListenerManager; -import net.minestom.server.network.PacketProcessor; +import net.minestom.server.network.packet.PacketParser; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -20,7 +19,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); InetSocketAddress address = new InetSocketAddress("localhost", 25565); - var server = new Server(new PacketProcessor(new PacketListenerManager())); + var server = new Server(new PacketParser.Client()); server.init(address); assertSame(address, server.socketAddress()); assertEquals(address.getHostString(), server.getAddress()); @@ -36,7 +35,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); InetSocketAddress address = new InetSocketAddress("localhost", 0); - var server = new Server(new PacketProcessor(new PacketListenerManager())); + var server = new Server(new PacketParser.Client()); server.init(address); assertSame(address, server.socketAddress()); assertEquals(address.getHostString(), server.getAddress()); @@ -52,7 +51,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); UnixDomainSocketAddress address = UnixDomainSocketAddress.of("minestom.sock"); - var server = new Server(new PacketProcessor(new PacketListenerManager())); + var server = new Server(new PacketParser.Client()); server.init(address); assertTrue(Files.exists(address.getPath())); assertSame(address, server.socketAddress()); @@ -66,7 +65,7 @@ public class ServerAddressTest { @Test public void noAddressTest() throws IOException { - var server = new Server(new PacketProcessor(new PacketListenerManager())); + var server = new Server(new PacketParser.Client()); assertDoesNotThrow(server::stop); } } From 6a95c6576d361ed83997de2d587cc448a6c24df6 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 21 Jul 2024 18:49:19 +0200 Subject: [PATCH 06/97] Recipe rework (#2285) * Recipe rework * Remove unnecessary lists * Add remaining recipes * Fix `dataSerializer` * Fix DecoratedPot naming --- .../src/main/java/net/minestom/demo/Main.java | 55 ++-- .../net/minestom/server/entity/Player.java | 4 +- .../server/network/NetworkBufferTemplate.java | 240 ++++++++++++++ .../server/play/DeclareRecipesPacket.java | 300 +----------------- .../server/recipe/BlastingRecipe.java | 80 ----- .../server/recipe/CampfireCookingRecipe.java | 82 ----- .../net/minestom/server/recipe/Recipe.java | 143 ++++++++- .../server/recipe/RecipeConversion.java | 99 ------ .../minestom/server/recipe/RecipeManager.java | 54 ++-- .../server/recipe/RecipeSerializers.java | 260 +++++++++++++++ .../minestom/server/recipe/ShapedRecipe.java | 93 ------ .../server/recipe/ShapelessRecipe.java | 67 ---- .../server/recipe/SmeltingRecipe.java | 80 ----- .../recipe/SmithingTransformRecipe.java | 62 ---- .../server/recipe/SmithingTrimRecipe.java | 49 --- .../minestom/server/recipe/SmokingRecipe.java | 82 ----- .../server/recipe/StonecutterRecipe.java | 50 --- .../server/network/PacketWriteReadTest.java | 61 ++-- .../packet/DeclareRecipesPacketTest.java | 10 +- 19 files changed, 715 insertions(+), 1156 deletions(-) create mode 100644 src/main/java/net/minestom/server/network/NetworkBufferTemplate.java delete mode 100644 src/main/java/net/minestom/server/recipe/BlastingRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/CampfireCookingRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/RecipeConversion.java create mode 100644 src/main/java/net/minestom/server/recipe/RecipeSerializers.java delete mode 100644 src/main/java/net/minestom/server/recipe/ShapedRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/ShapelessRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/SmeltingRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/SmithingTransformRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/SmithingTrimRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/SmokingRecipe.java delete mode 100644 src/main/java/net/minestom/server/recipe/StonecutterRecipe.java diff --git a/demo/src/main/java/net/minestom/demo/Main.java b/demo/src/main/java/net/minestom/demo/Main.java index 087ca866b..e410ad8a3 100644 --- a/demo/src/main/java/net/minestom/demo/Main.java +++ b/demo/src/main/java/net/minestom/demo/Main.java @@ -10,7 +10,6 @@ import net.minestom.demo.block.placement.DripstonePlacementRule; import net.minestom.demo.commands.*; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; -import net.minestom.server.entity.Player; import net.minestom.server.event.server.ServerListPingEvent; import net.minestom.server.extras.MojangAuth; import net.minestom.server.extras.lan.OpenToLAN; @@ -19,14 +18,11 @@ import net.minestom.server.instance.block.BlockManager; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; import net.minestom.server.ping.ResponseData; +import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeCategory; -import net.minestom.server.recipe.ShapedRecipe; -import net.minestom.server.recipe.ShapelessRecipe; import net.minestom.server.utils.identity.NamedAndIdentified; import net.minestom.server.utils.time.TimeUnit; -import org.jetbrains.annotations.NotNull; import java.time.Duration; import java.util.List; @@ -122,36 +118,27 @@ public class Main { //responseData.setPlayersHidden(true); }); - var ironBlockRecipe = new ShapedRecipe( - "minestom:test", 2, 2, "", - RecipeCategory.Crafting.MISC, - List.of( - new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))) - ), ItemStack.of(Material.IRON_BLOCK), true) { - @Override - public boolean shouldShow(@NotNull Player player) { - return true; - } - }; + var ironBlockRecipe = new Recipe( + "minestom:test", + new Recipe.Shaped("", RecipeCategory.Crafting.MISC, 2, 2, + List.of( + new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), + new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), + new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), + new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)) + ), ItemStack.of(Material.IRON_BLOCK), true)); MinecraftServer.getRecipeManager().addRecipe(ironBlockRecipe); - var recipe = new ShapelessRecipe( - "minestom:test2", "abc", - RecipeCategory.Crafting.MISC, - List.of( - new DeclareRecipesPacket.Ingredient(List.of(ItemStack.of(Material.DIRT))) - ), - ItemStack.builder(Material.GOLD_BLOCK) - .set(ItemComponent.CUSTOM_NAME, Component.text("abc")) - .build() - ) { - @Override - public boolean shouldShow(@NotNull Player player) { - return true; - } - }; + var recipe = new Recipe( + "minestom:test2", + new Recipe.Shapeless("abc", + RecipeCategory.Crafting.MISC, + List.of( + new Recipe.Ingredient(ItemStack.of(Material.DIRT)) + ), + ItemStack.builder(Material.GOLD_BLOCK) + .set(ItemComponent.CUSTOM_NAME, Component.text("abc")) + .build()) + ); MinecraftServer.getRecipeManager().addRecipe(recipe); new PlayerInit().init(); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8fe13be0c..8d2b26c41 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -354,9 +354,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, sendPacket(recipeManager.getDeclareRecipesPacket()); List recipesIdentifier = new ArrayList<>(); - for (Recipe recipe : recipeManager.getRecipes()) { - if (!recipe.shouldShow(this)) - continue; + for (Recipe recipe : recipeManager.consumeRecipes(this)) { recipesIdentifier.add(recipe.id()); } if (!recipesIdentifier.isEmpty()) { diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java new file mode 100644 index 000000000..c5834b449 --- /dev/null +++ b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java @@ -0,0 +1,240 @@ +package net.minestom.server.network; + +import net.minestom.server.network.NetworkBuffer.Type; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; + +public final class NetworkBufferTemplate { + + @FunctionalInterface + public interface F1 { + R apply(P1 p1); + } + + @FunctionalInterface + public interface F2 { + R apply(P1 p1, P2 p2); + } + + @FunctionalInterface + public interface F3 { + R apply(P1 p1, P2 p2, P3 p3); + } + + @FunctionalInterface + public interface F4 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4); + } + + @FunctionalInterface + public interface F5 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + } + + @FunctionalInterface + public interface F6 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); + } + + @FunctionalInterface + public interface F7 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); + } + + @FunctionalInterface + public interface F8 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); + } + + public static Type template(Type p1, Function g1, F1 reader) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply(p1.read(buffer)); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + F2 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply(p1.read(buffer), p2.read(buffer)); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, F3 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply(p1.read(buffer), p2.read(buffer), p3.read(buffer)); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + F4 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, F5 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + F6 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, F7 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + F8 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer) + ); + } + }; + } +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java index 8a06a6600..f4bbae3dd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java @@ -1,322 +1,32 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; -import net.minestom.server.recipe.RecipeCategory; -import net.minestom.server.recipe.RecipeType; +import net.minestom.server.recipe.Recipe; +import net.minestom.server.recipe.RecipeSerializers; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -import static net.minestom.server.network.NetworkBuffer.*; - -public record DeclareRecipesPacket(@NotNull List recipes) implements ServerPacket.Play { +public record DeclareRecipesPacket(@NotNull List recipes) implements ServerPacket.Play { public static final int MAX_RECIPES = Short.MAX_VALUE; - public static final int MAX_INGREDIENTS = 128; public DeclareRecipesPacket { recipes = List.copyOf(recipes); } public DeclareRecipesPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(r -> { - final String recipeId = r.read(STRING); - final RecipeType type = r.read(RecipeType.NETWORK_TYPE); - return switch (type) { - case RecipeType.SHAPELESS -> new DeclaredShapelessCraftingRecipe(recipeId, reader); - case RecipeType.SHAPED -> new DeclaredShapedCraftingRecipe(recipeId, reader); - case RecipeType.SMELTING -> new DeclaredSmeltingRecipe(recipeId, reader); - case RecipeType.BLASTING -> new DeclaredBlastingRecipe(recipeId, reader); - case RecipeType.SMOKING -> new DeclaredSmokingRecipe(recipeId, reader); - case RecipeType.CAMPFIRE_COOKING -> new DeclaredCampfireCookingRecipe(recipeId, reader); - case RecipeType.STONECUTTING -> new DeclaredStonecutterRecipe(recipeId, reader); - case RecipeType.SMITHING_TRIM -> new DeclaredSmithingTrimRecipe(recipeId, reader); - case RecipeType.SMITHING_TRANSFORM -> new DeclaredSmithingTransformRecipe(recipeId, reader); - default -> throw new UnsupportedOperationException("Unrecognized type: " + type); - }; - }, MAX_RECIPES)); + this(reader.readCollection(RecipeSerializers.RECIPE, MAX_RECIPES)); } @Override public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(recipes, (bWriter, recipe) -> { - bWriter.write(STRING, recipe.recipeId()); - bWriter.write(RecipeType.NETWORK_TYPE, recipe.type()); - bWriter.write(recipe); - }); + writer.writeCollection(RecipeSerializers.RECIPE, recipes); } @Override public int playId() { return ServerPacketIdentifier.DECLARE_RECIPES; } - - public sealed interface DeclaredRecipe extends NetworkBuffer.Writer - permits DeclaredShapelessCraftingRecipe, DeclaredShapedCraftingRecipe, - DeclaredSmeltingRecipe, DeclaredBlastingRecipe, DeclaredSmokingRecipe, - DeclaredCampfireCookingRecipe, DeclaredStonecutterRecipe, - DeclaredSmithingTrimRecipe, DeclaredSmithingTransformRecipe { - @NotNull RecipeType type(); - - @NotNull String recipeId(); - } - - public record DeclaredShapelessCraftingRecipe(@NotNull String recipeId, @NotNull String group, - @NotNull RecipeCategory.Crafting crafting, - @NotNull List ingredients, - @NotNull ItemStack result) implements DeclaredRecipe { - private DeclaredShapelessCraftingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - reader.readEnum(RecipeCategory.Crafting.class), - reader.readCollection(Ingredient::new, MAX_INGREDIENTS), reader.read(ItemStack.STRICT_NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Crafting.class, crafting); - writer.writeCollection(ingredients); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SHAPELESS; - } - } - - public record DeclaredShapedCraftingRecipe(@NotNull String recipeId, - @NotNull String group, @NotNull RecipeCategory.Crafting category, - int width, int height, @NotNull List ingredients, - @NotNull ItemStack result, boolean showNotification) implements DeclaredRecipe { - public DeclaredShapedCraftingRecipe { - ingredients = List.copyOf(ingredients); - } - - private DeclaredShapedCraftingRecipe(DeclaredShapedCraftingRecipe packet) { - this(packet.recipeId, packet.group, packet.category, packet.width, packet.height, packet.ingredients, packet.result, packet.showNotification); - } - - public DeclaredShapedCraftingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(read(recipeId, reader)); - } - - private static DeclaredShapedCraftingRecipe read(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - String group = reader.read(STRING); - RecipeCategory.Crafting category = reader.readEnum(RecipeCategory.Crafting.class); - int width = reader.read(VAR_INT); - int height = reader.read(VAR_INT); - List ingredients = new ArrayList<>(); - for (int slot = 0; slot < width * height; slot++) { - ingredients.add(new Ingredient(reader)); - } - ItemStack result = reader.read(ItemStack.STRICT_NETWORK_TYPE); - boolean showNotification = reader.read(BOOLEAN); - return new DeclaredShapedCraftingRecipe(recipeId, group, category, width, height, ingredients, result, showNotification); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Crafting.class, category); - writer.write(VAR_INT, width); - writer.write(VAR_INT, height); - for (Ingredient ingredient : ingredients) { - ingredient.write(writer); - } - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - writer.write(BOOLEAN, showNotification); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SHAPED; - } - } - - public record DeclaredSmeltingRecipe(@NotNull String recipeId, @NotNull String group, - @NotNull RecipeCategory.Cooking category, @NotNull Ingredient ingredient, - @NotNull ItemStack result, float experience, - int cookingTime) implements DeclaredRecipe { - public DeclaredSmeltingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - reader.readEnum(RecipeCategory.Cooking.class), - new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE), - reader.read(FLOAT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Cooking.class, category); - writer.write(ingredient); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - writer.write(FLOAT, experience); - writer.write(VAR_INT, cookingTime); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SMELTING; - } - } - - public record DeclaredBlastingRecipe(@NotNull String recipeId, @NotNull String group, - @NotNull RecipeCategory.Cooking category, @NotNull Ingredient ingredient, - @NotNull ItemStack result, float experience, - int cookingTime) implements DeclaredRecipe { - public DeclaredBlastingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - reader.readEnum(RecipeCategory.Cooking.class), - new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE), - reader.read(FLOAT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Cooking.class, category); - writer.write(ingredient); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - writer.write(FLOAT, experience); - writer.write(VAR_INT, cookingTime); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.BLASTING; - } - } - - public record DeclaredSmokingRecipe(@NotNull String recipeId, @NotNull String group, - @NotNull RecipeCategory.Cooking category, @NotNull Ingredient ingredient, - @NotNull ItemStack result, float experience, - int cookingTime) implements DeclaredRecipe { - public DeclaredSmokingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - reader.readEnum(RecipeCategory.Cooking.class), - new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE), - reader.read(FLOAT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Cooking.class, category); - writer.write(ingredient); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - writer.write(FLOAT, experience); - writer.write(VAR_INT, cookingTime); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SMOKING; - } - } - - public record DeclaredCampfireCookingRecipe(@NotNull String recipeId, @NotNull String group, - @NotNull RecipeCategory.Cooking category, @NotNull Ingredient ingredient, - @NotNull ItemStack result, float experience, - int cookingTime) implements DeclaredRecipe { - public DeclaredCampfireCookingRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - reader.readEnum(RecipeCategory.Cooking.class), - new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE), - reader.read(FLOAT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.writeEnum(RecipeCategory.Cooking.class, category); - writer.write(ingredient); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - writer.write(FLOAT, experience); - writer.write(VAR_INT, cookingTime); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.CAMPFIRE_COOKING; - } - } - - public record DeclaredStonecutterRecipe(String recipeId, String group, - Ingredient ingredient, ItemStack result) implements DeclaredRecipe { - public DeclaredStonecutterRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, reader.read(STRING), - new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, group); - writer.write(ingredient); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.STONECUTTING; - } - } - - public record DeclaredSmithingTransformRecipe(String recipeId, Ingredient template, - Ingredient base, Ingredient addition, - ItemStack result) implements DeclaredRecipe { - public DeclaredSmithingTransformRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, new Ingredient(reader), new Ingredient(reader), new Ingredient(reader), reader.read(ItemStack.STRICT_NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(template); - writer.write(base); - writer.write(addition); - writer.write(ItemStack.STRICT_NETWORK_TYPE, result); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SMITHING_TRANSFORM; - } - } - - public record DeclaredSmithingTrimRecipe(String recipeId, Ingredient template, - Ingredient base, Ingredient addition) implements DeclaredRecipe { - public DeclaredSmithingTrimRecipe(@NotNull String recipeId, @NotNull NetworkBuffer reader) { - this(recipeId, new Ingredient(reader), new Ingredient(reader), new Ingredient(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(template); - writer.write(base); - writer.write(addition); - } - - @Override - public @NotNull RecipeType type() { - return RecipeType.SMITHING_TRIM; - } - } - - public record Ingredient(@Nullable List items) implements NetworkBuffer.Writer { - public Ingredient { - items = items == null ? null : List.copyOf(items); - } - - public Ingredient(@NotNull NetworkBuffer reader) { - this(reader.readCollection(ItemStack.STRICT_NETWORK_TYPE, MAX_INGREDIENTS)); - } - - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(ItemStack.STRICT_NETWORK_TYPE, items); - } - } } diff --git a/src/main/java/net/minestom/server/recipe/BlastingRecipe.java b/src/main/java/net/minestom/server/recipe/BlastingRecipe.java deleted file mode 100644 index 91148daf0..000000000 --- a/src/main/java/net/minestom/server/recipe/BlastingRecipe.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class BlastingRecipe extends Recipe { - private String group; - private RecipeCategory.Cooking category; - private DeclareRecipesPacket.Ingredient ingredient; - private ItemStack result; - private float experience; - private int cookingTime; - - protected BlastingRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull RecipeCategory.Cooking category, - @NotNull ItemStack result, - float experience, - int cookingTime - ) { - super(RecipeType.BLASTING, recipeId); - this.group = group; - this.category = category; - this.result = result; - this.experience = experience; - this.cookingTime = cookingTime; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - public @NotNull RecipeCategory.Cooking getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Cooking category) { - this.category = category; - } - - public @NotNull DeclareRecipesPacket.Ingredient getIngredient() { - return ingredient; - } - - public void setIngredient(@NotNull DeclareRecipesPacket.Ingredient ingredient) { - this.ingredient = ingredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } - - public float getExperience() { - return experience; - } - - public void setExperience(float experience) { - this.experience = experience; - } - - public int getCookingTime() { - return cookingTime; - } - - public void setCookingTime(int cookingTime) { - this.cookingTime = cookingTime; - } -} diff --git a/src/main/java/net/minestom/server/recipe/CampfireCookingRecipe.java b/src/main/java/net/minestom/server/recipe/CampfireCookingRecipe.java deleted file mode 100644 index 7a9a45b3d..000000000 --- a/src/main/java/net/minestom/server/recipe/CampfireCookingRecipe.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class CampfireCookingRecipe extends Recipe { - private String group; - private RecipeCategory.Cooking category; - private DeclareRecipesPacket.Ingredient ingredient; - private ItemStack result; - private float experience; - private int cookingTime; - - protected CampfireCookingRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull RecipeCategory.Cooking category, - @NotNull ItemStack result, - float experience, - int cookingTime - ) { - super(RecipeType.CAMPFIRE_COOKING, recipeId); - this.group = group; - this.category = category; - this.result = result; - this.experience = experience; - this.cookingTime = cookingTime; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - @NotNull - public RecipeCategory.Cooking getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Cooking category) { - this.category = category; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getIngredient() { - return ingredient; - } - - public void setIngredient(@NotNull DeclareRecipesPacket.Ingredient ingredient) { - this.ingredient = ingredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } - - public float getExperience() { - return experience; - } - - public void setExperience(float experience) { - this.experience = experience; - } - - public int getCookingTime() { - return cookingTime; - } - - public void setCookingTime(int cookingTime) { - this.cookingTime = cookingTime; - } -} diff --git a/src/main/java/net/minestom/server/recipe/Recipe.java b/src/main/java/net/minestom/server/recipe/Recipe.java index ad183a5d4..c751acf4a 100644 --- a/src/main/java/net/minestom/server/recipe/Recipe.java +++ b/src/main/java/net/minestom/server/recipe/Recipe.java @@ -1,25 +1,142 @@ package net.minestom.server.recipe; -import net.minestom.server.entity.Player; +import net.minestom.server.item.ItemStack; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; -public abstract class Recipe { - protected final RecipeType type; - protected final String id; +import java.util.List; - protected Recipe(@NotNull RecipeType type, @NotNull String id) { - this.type = type; - this.id = id; +public record Recipe(@NotNull String id, @NotNull Data data) { + public static final int MAX_INGREDIENTS = 128; + + sealed public interface Data { } - public abstract boolean shouldShow(@NotNull Player player); + public record Shaped(String group, RecipeCategory.Crafting category, + int width, int height, List ingredients, + ItemStack result, boolean showNotification) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SHAPED; - @NotNull - public RecipeType type() { - return type; + public Shaped { + if (ingredients.size() != width * height) + throw new IllegalArgumentException("Invalid shaped recipe, ingredients size must be equal to width * height"); + ingredients = List.copyOf(ingredients); + } } - public @NotNull String id() { - return id; + public record Shapeless(String group, RecipeCategory.Crafting category, + List ingredients, ItemStack result) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SHAPELESS; + + public Shapeless { + if (ingredients.size() > MAX_INGREDIENTS) + throw new IllegalArgumentException("Shapeless recipe has too many ingredients"); + ingredients = List.copyOf(ingredients); + } + } + + public record Smelting(String group, RecipeCategory.Cooking category, + Ingredient ingredient, ItemStack result, + float experience, int cookingTime) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SMELTING; + } + + public record Blasting(String group, RecipeCategory.Cooking category, + Ingredient ingredient, ItemStack result, + float experience, int cookingTime) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.BLASTING; + } + + public record Smoking(String group, RecipeCategory.Cooking category, + Ingredient ingredient, ItemStack result, + float experience, int cookingTime) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SMOKING; + } + + public record CampfireCooking(String group, RecipeCategory.Cooking category, + Ingredient ingredient, ItemStack result, + float experience, int cookingTime) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.CAMPFIRE_COOKING; + } + + public record Stonecutting(String group, Ingredient ingredient, + ItemStack result) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.STONECUTTING; + } + + public record SmithingTransform(Ingredient template, Ingredient base, + Ingredient addition, ItemStack result) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SMITHING_TRANSFORM; + } + + public record SmithingTrim(Ingredient template, + Ingredient base, Ingredient addition) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SMITHING_TRIM; + } + + public record Ingredient(@NotNull List<@NotNull ItemStack> items) { + public Ingredient { + items = List.copyOf(items); + } + + public Ingredient(@NotNull ItemStack @NotNull ... items) { + this(List.of(items)); + } + } + + public record SpecialArmorDye(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.ARMOR_DYE; + } + + public record SpecialBookCloning(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.BOOK_CLONING; + } + + public record SpecialMapCloning(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.MAP_CLONING; + } + + public record SpecialMapExtending(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.MAP_EXTENDING; + } + + public record SpecialFireworkRocket(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.FIREWORK_ROCKET; + } + + public record SpecialFireworkStar(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.FIREWORK_STAR; + } + + public record SpecialFireworkStarFade(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.FIREWORK_STAR_FADE; + } + + public record SpecialTippedArrow(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.TIPPED_ARROW; + } + + public record SpecialBannerDuplicate(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.BANNER_DUPLICATE; + } + + public record SpecialShieldDecoration(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SHIELD_DECORATION; + } + + public record SpecialShulkerBoxColoring(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SPECIAL_SHULKER_BOX_COLORING; + } + + public record SpecialSuspiciousStew(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SUSPICIOUS_STEW; + } + + public record SpecialRepairItem(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.REPAIR_ITEM; + } + + public record DecoratedPot(RecipeCategory.Crafting category) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.DECORATED_POT; } } diff --git a/src/main/java/net/minestom/server/recipe/RecipeConversion.java b/src/main/java/net/minestom/server/recipe/RecipeConversion.java deleted file mode 100644 index cbc904d8c..000000000 --- a/src/main/java/net/minestom/server/recipe/RecipeConversion.java +++ /dev/null @@ -1,99 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -final class RecipeConversion { - - static @NotNull DeclareRecipesPacket.DeclaredShapelessCraftingRecipe shapeless(@NotNull ShapelessRecipe shapelessRecipe) { - return new DeclareRecipesPacket.DeclaredShapelessCraftingRecipe(shapelessRecipe.id(), - shapelessRecipe.getGroup(), - shapelessRecipe.getCategory(), - shapelessRecipe.getIngredients(), - shapelessRecipe.getResult()); - } - - static @NotNull DeclareRecipesPacket.DeclaredShapedCraftingRecipe shaped(@NotNull ShapedRecipe shapedRecipe) { - return new DeclareRecipesPacket.DeclaredShapedCraftingRecipe(shapedRecipe.id(), - shapedRecipe.getGroup(), - shapedRecipe.getCategory(), - shapedRecipe.getWidth(), - shapedRecipe.getHeight(), - shapedRecipe.getIngredients(), - shapedRecipe.getResult(), - shapedRecipe.getShowNotification()); - } - - static @NotNull DeclareRecipesPacket.DeclaredSmeltingRecipe smelting(@NotNull SmeltingRecipe smeltingRecipe) { - return new DeclareRecipesPacket.DeclaredSmeltingRecipe( - smeltingRecipe.id(), - smeltingRecipe.getGroup(), - smeltingRecipe.getCategory(), - smeltingRecipe.getIngredient(), - smeltingRecipe.getResult(), - smeltingRecipe.getExperience(), - smeltingRecipe.getCookingTime()); - } - - static @NotNull DeclareRecipesPacket.DeclaredBlastingRecipe blasting(@NotNull BlastingRecipe blastingRecipe) { - return new DeclareRecipesPacket.DeclaredBlastingRecipe( - blastingRecipe.id(), - blastingRecipe.getGroup(), - blastingRecipe.getCategory(), - blastingRecipe.getIngredient(), - blastingRecipe.getResult(), - blastingRecipe.getExperience(), - blastingRecipe.getCookingTime()); - } - - static @NotNull DeclareRecipesPacket.DeclaredSmokingRecipe smoking(@NotNull SmokingRecipe smokingRecipe) { - return new DeclareRecipesPacket.DeclaredSmokingRecipe( - smokingRecipe.id(), - smokingRecipe.getGroup(), - smokingRecipe.getCategory(), - smokingRecipe.getIngredient(), - smokingRecipe.getResult(), - smokingRecipe.getExperience(), - smokingRecipe.getCookingTime()); - } - - static @NotNull DeclareRecipesPacket.DeclaredCampfireCookingRecipe campfire(@NotNull CampfireCookingRecipe campfireCookingRecipe) { - return new DeclareRecipesPacket.DeclaredCampfireCookingRecipe( - campfireCookingRecipe.id(), - campfireCookingRecipe.getGroup(), - campfireCookingRecipe.getCategory(), - campfireCookingRecipe.getIngredient(), - campfireCookingRecipe.getResult(), - campfireCookingRecipe.getExperience(), - campfireCookingRecipe.getCookingTime()); - } - - static @NotNull DeclareRecipesPacket.DeclaredStonecutterRecipe stonecutter(@NotNull StonecutterRecipe stonecuttingRecipe) { - return new DeclareRecipesPacket.DeclaredStonecutterRecipe( - stonecuttingRecipe.id(), - stonecuttingRecipe.getGroup(), - stonecuttingRecipe.getIngredient(), - stonecuttingRecipe.getResult()); - } - - static @NotNull DeclareRecipesPacket.DeclaredSmithingTransformRecipe smithingTransform(@NotNull SmithingTransformRecipe smithingTransformRecipe) { - return new DeclareRecipesPacket.DeclaredSmithingTransformRecipe( - smithingTransformRecipe.id(), - smithingTransformRecipe.getTemplate(), - smithingTransformRecipe.getBaseIngredient(), - smithingTransformRecipe.getAdditionIngredient(), - smithingTransformRecipe.getResult()); - } - - static @NotNull DeclareRecipesPacket.DeclaredSmithingTrimRecipe smithingTrim(@NotNull SmithingTrimRecipe smithingTrimRecipe) { - return new DeclareRecipesPacket.DeclaredSmithingTrimRecipe( - smithingTrimRecipe.id(), - smithingTrimRecipe.getTemplate(), - smithingTrimRecipe.getBaseIngredient(), - smithingTrimRecipe.getAdditionIngredient()); - } - - private RecipeConversion() { - - } -} diff --git a/src/main/java/net/minestom/server/recipe/RecipeManager.java b/src/main/java/net/minestom/server/recipe/RecipeManager.java index 38b8cc3fd..49faf063d 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeManager.java +++ b/src/main/java/net/minestom/server/recipe/RecipeManager.java @@ -1,64 +1,54 @@ package net.minestom.server.recipe; +import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; -public class RecipeManager { +public final class RecipeManager { private final CachedPacket declareRecipesPacket = new CachedPacket(this::createDeclareRecipesPacket); - private final Set recipes = new CopyOnWriteArraySet<>(); + private final Map> recipes = new ConcurrentHashMap<>(); - public void addRecipes(@NotNull Recipe... recipe) { - if (recipes.addAll(List.of(recipe))) { + public void addRecipe(@NotNull Recipe recipe, @NotNull Predicate predicate) { + var previous = recipes.put(recipe, predicate); + if (previous == null) { declareRecipesPacket.invalidate(); } } public void addRecipe(@NotNull Recipe recipe) { - if (this.recipes.add(recipe)) { - declareRecipesPacket.invalidate(); - } + addRecipe(recipe, player -> true); } public void removeRecipe(@NotNull Recipe recipe) { - if (this.recipes.remove(recipe)) { + if (this.recipes.remove(recipe) != null) { declareRecipesPacket.invalidate(); } } - @NotNull - public Set getRecipes() { - return recipes; + public List consumeRecipes(Player player) { + return recipes.entrySet().stream() + .filter(entry -> entry.getValue().test(player)) + .map(Map.Entry::getKey) + .toList(); } - @NotNull - public SendablePacket getDeclareRecipesPacket() { + public @NotNull Set getRecipes() { + return recipes.keySet(); + } + + public @NotNull SendablePacket getDeclareRecipesPacket() { return declareRecipesPacket; } private @NotNull DeclareRecipesPacket createDeclareRecipesPacket() { - var entries = new ArrayList(); - for (var recipe : recipes) { - entries.add(switch (recipe.type) { - case SHAPELESS -> RecipeConversion.shapeless((ShapelessRecipe) recipe); - case SHAPED -> RecipeConversion.shaped((ShapedRecipe) recipe); - case SMELTING -> RecipeConversion.smelting((SmeltingRecipe) recipe); - case BLASTING -> RecipeConversion.blasting((BlastingRecipe) recipe); - case SMOKING -> RecipeConversion.smoking((SmokingRecipe) recipe); - case CAMPFIRE_COOKING -> RecipeConversion.campfire((CampfireCookingRecipe) recipe); - case STONECUTTING -> RecipeConversion.stonecutter((StonecutterRecipe) recipe); - case SMITHING_TRANSFORM -> RecipeConversion.smithingTransform((SmithingTransformRecipe) recipe); - case SMITHING_TRIM -> RecipeConversion.smithingTrim((SmithingTrimRecipe) recipe); - default -> throw new IllegalStateException("Unhandled recipe type : " + recipe.type); - }); - } - return new DeclareRecipesPacket(entries); + return new DeclareRecipesPacket(List.copyOf(recipes.keySet())); } - } diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java new file mode 100644 index 000000000..c40b6c996 --- /dev/null +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -0,0 +1,260 @@ +package net.minestom.server.recipe; + +import net.minestom.server.item.ItemStack; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.recipe.Recipe.*; +import static net.minestom.server.recipe.RecipeCategory.Cooking; +import static net.minestom.server.recipe.RecipeCategory.Crafting; + +@ApiStatus.Internal +public final class RecipeSerializers { + public static final Type RECIPE = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer writer, Recipe shaped) { + writer.write(STRING, shaped.id()); + final RecipeType recipeType = recipeToType(shaped.data()); + writer.write(RecipeType.NETWORK_TYPE, recipeType); + var serializer = RecipeSerializers.dataSerializer(recipeType); + if (serializer == null) + throw new UnsupportedOperationException("Unrecognized type: " + recipeType); + serializer.write(writer, shaped.data()); + } + + @Override + public Recipe read(@NotNull NetworkBuffer reader) { + final String identifier = reader.read(STRING); + final RecipeType type = reader.read(RecipeType.NETWORK_TYPE); + var serializer = RecipeSerializers.dataSerializer(type); + if (serializer == null) throw new UnsupportedOperationException("Unrecognized type: " + type); + final Data data = serializer.read(reader); + return new Recipe(identifier, data); + } + }; + + public static final Type INGREDIENT = NetworkBufferTemplate.template( + ItemStack.STRICT_NETWORK_TYPE.list(MAX_INGREDIENTS), Ingredient::items, + Ingredient::new + ); + + public static final Type SHAPED = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer writer, Shaped shaped) { + writer.write(STRING, shaped.group()); + writer.writeEnum(Crafting.class, shaped.category()); + writer.write(VAR_INT, shaped.width()); + writer.write(VAR_INT, shaped.height()); + for (Ingredient ingredient : shaped.ingredients()) { + writer.write(INGREDIENT, ingredient); + } + writer.write(ItemStack.STRICT_NETWORK_TYPE, shaped.result()); + writer.write(BOOLEAN, shaped.showNotification()); + } + + @Override + public Shaped read(@NotNull NetworkBuffer reader) { + String group = reader.read(STRING); + Crafting category = reader.readEnum(Crafting.class); + int width = reader.read(VAR_INT); + int height = reader.read(VAR_INT); + List ingredients = new ArrayList<>(); + for (int slot = 0; slot < width * height; slot++) { + ingredients.add(reader.read(INGREDIENT)); + } + ItemStack result = reader.read(ItemStack.STRICT_NETWORK_TYPE); + boolean showNotification = reader.read(BOOLEAN); + return new Shaped(group, category, width, height, ingredients, result, showNotification); + } + }; + + public static final Type SHAPELESS = NetworkBufferTemplate.template( + STRING, Shapeless::group, + Enum(Crafting.class), Shapeless::category, + INGREDIENT.list(MAX_INGREDIENTS), Shapeless::ingredients, + ItemStack.STRICT_NETWORK_TYPE, Shapeless::result, + Shapeless::new + ); + + public static final Type SMELTING = NetworkBufferTemplate.template( + STRING, Smelting::group, + Enum(Cooking.class), Smelting::category, + INGREDIENT, Smelting::ingredient, + ItemStack.STRICT_NETWORK_TYPE, Smelting::result, + FLOAT, Smelting::experience, + VAR_INT, Smelting::cookingTime, + Smelting::new + ); + + public static final Type BLASTING = NetworkBufferTemplate.template( + STRING, Blasting::group, + Enum(Cooking.class), Blasting::category, + INGREDIENT, Blasting::ingredient, + ItemStack.STRICT_NETWORK_TYPE, Blasting::result, + FLOAT, Blasting::experience, + VAR_INT, Blasting::cookingTime, + Blasting::new + ); + + public static final Type SMOKING = NetworkBufferTemplate.template( + STRING, Smoking::group, + Enum(Cooking.class), Smoking::category, + INGREDIENT, Smoking::ingredient, + ItemStack.STRICT_NETWORK_TYPE, Smoking::result, + FLOAT, Smoking::experience, + VAR_INT, Smoking::cookingTime, + Smoking::new + ); + + public static final Type CAMPFIRE_COOKING = NetworkBufferTemplate.template( + STRING, CampfireCooking::group, + Enum(Cooking.class), CampfireCooking::category, + INGREDIENT, CampfireCooking::ingredient, + ItemStack.STRICT_NETWORK_TYPE, CampfireCooking::result, + FLOAT, CampfireCooking::experience, + VAR_INT, CampfireCooking::cookingTime, + CampfireCooking::new + ); + + public static final Type STONECUTTING = NetworkBufferTemplate.template( + STRING, Stonecutting::group, + INGREDIENT, Stonecutting::ingredient, + ItemStack.STRICT_NETWORK_TYPE, Stonecutting::result, + Stonecutting::new + ); + + public static final Type SMITHING_TRANSFORM = NetworkBufferTemplate.template( + INGREDIENT, SmithingTransform::template, + INGREDIENT, SmithingTransform::base, + INGREDIENT, SmithingTransform::addition, + ItemStack.STRICT_NETWORK_TYPE, SmithingTransform::result, + SmithingTransform::new + ); + + public static final Type SMITHING_TRIM = NetworkBufferTemplate.template( + INGREDIENT, SmithingTrim::template, + INGREDIENT, SmithingTrim::base, + INGREDIENT, SmithingTrim::addition, + SmithingTrim::new + ); + + public static final Type ARMOR_DYE = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialArmorDye::category, SpecialArmorDye::new + ); + + public static final Type BOOK_CLONING = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialBookCloning::category, SpecialBookCloning::new + ); + + public static final Type MAP_CLONING = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialMapCloning::category, SpecialMapCloning::new + ); + + public static final Type MAP_EXTENDING = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialMapExtending::category, SpecialMapExtending::new + ); + + public static final Type FIREWORK_ROCKET = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialFireworkRocket::category, SpecialFireworkRocket::new + ); + + public static final Type FIREWORK_STAR = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialFireworkStar::category, SpecialFireworkStar::new + ); + + public static final Type FIREWORK_STAR_FADE = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialFireworkStarFade::category, SpecialFireworkStarFade::new + ); + + public static final Type TIPPED_ARROW = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialTippedArrow::category, SpecialTippedArrow::new + ); + + public static final Type BANNER_DUPLICATE = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialBannerDuplicate::category, SpecialBannerDuplicate::new + ); + + public static final Type SHIELD_DECORATION = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialShieldDecoration::category, SpecialShieldDecoration::new + ); + + public static final Type SPECIAL_SHULKER_BOX_COLORING = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialShulkerBoxColoring::category, SpecialShulkerBoxColoring::new + ); + + public static final Type SUSPICIOUS_STEW = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialSuspiciousStew::category, SpecialSuspiciousStew::new + ); + + public static final Type REPAIR_ITEM = NetworkBufferTemplate.template( + Enum(Crafting.class), SpecialRepairItem::category, SpecialRepairItem::new + ); + + public static final Type DECORATED_POT = NetworkBufferTemplate.template( + Enum(Crafting.class), DecoratedPot::category, DecoratedPot::new + ); + + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static Type dataSerializer(RecipeType type) { + return (Type) switch (type) { + case SHAPED -> SHAPED; + case SHAPELESS -> SHAPELESS; + case SPECIAL_ARMORDYE -> ARMOR_DYE; + case SPECIAL_BOOKCLONING -> BOOK_CLONING; + case SPECIAL_MAPCLONING -> MAP_CLONING; + case SPECIAL_MAPEXTENDING -> MAP_EXTENDING; + case SPECIAL_FIREWORK_ROCKET -> FIREWORK_ROCKET; + case SPECIAL_FIREWORK_STAR -> FIREWORK_STAR; + case SPECIAL_FIREWORK_STAR_FADE -> FIREWORK_STAR_FADE; + case SPECIAL_TIPPEDARROW -> TIPPED_ARROW; + case SPECIAL_BANNERDUPLICATE -> BANNER_DUPLICATE; + case SPECIAL_SHIELDDECORATION -> SHIELD_DECORATION; + case SPECIAL_SHULKERBOXCOLORING -> SPECIAL_SHULKER_BOX_COLORING; + case SPECIAL_SUSPICIOUSSTEW -> SUSPICIOUS_STEW; + case SPECIAL_REPAIRITEM -> REPAIR_ITEM; + case SMELTING -> SMELTING; + case BLASTING -> BLASTING; + case SMOKING -> SMOKING; + case CAMPFIRE_COOKING -> CAMPFIRE_COOKING; + case STONECUTTING -> STONECUTTING; + case SMITHING_TRANSFORM -> SMITHING_TRANSFORM; + case SMITHING_TRIM -> SMITHING_TRIM; + case DECORATED_POT -> DECORATED_POT; + }; + } + + public static RecipeType recipeToType(Data data) { + return switch (data) { + case Shaped ignored -> RecipeType.SHAPED; + case Shapeless ignored -> RecipeType.SHAPELESS; + case Smelting ignored -> RecipeType.SMELTING; + case Blasting ignored -> RecipeType.BLASTING; + case Smoking ignored -> RecipeType.SMOKING; + case CampfireCooking ignored -> RecipeType.CAMPFIRE_COOKING; + case Stonecutting ignored -> RecipeType.STONECUTTING; + case SmithingTransform ignored -> RecipeType.SMITHING_TRANSFORM; + case SmithingTrim ignored -> RecipeType.SMITHING_TRIM; + case SpecialArmorDye ignored -> RecipeType.SPECIAL_ARMORDYE; + case SpecialBannerDuplicate ignored -> RecipeType.SPECIAL_BANNERDUPLICATE; + case SpecialBookCloning ignored -> RecipeType.SPECIAL_BOOKCLONING; + case DecoratedPot ignored -> RecipeType.DECORATED_POT; + case SpecialFireworkRocket ignored -> RecipeType.SPECIAL_FIREWORK_ROCKET; + case SpecialFireworkStar ignored -> RecipeType.SPECIAL_FIREWORK_STAR; + case SpecialFireworkStarFade ignored -> RecipeType.SPECIAL_FIREWORK_STAR_FADE; + case SpecialMapCloning ignored -> RecipeType.SPECIAL_MAPCLONING; + case SpecialMapExtending ignored -> RecipeType.SPECIAL_MAPEXTENDING; + case SpecialRepairItem ignored -> RecipeType.SPECIAL_REPAIRITEM; + case SpecialShieldDecoration ignored -> RecipeType.SPECIAL_SHIELDDECORATION; + case SpecialShulkerBoxColoring ignored -> RecipeType.SPECIAL_SHULKERBOXCOLORING; + case SpecialSuspiciousStew ignored -> RecipeType.SPECIAL_SUSPICIOUSSTEW; + case SpecialTippedArrow ignored -> RecipeType.SPECIAL_TIPPEDARROW; + }; + } +} diff --git a/src/main/java/net/minestom/server/recipe/ShapedRecipe.java b/src/main/java/net/minestom/server/recipe/ShapedRecipe.java deleted file mode 100644 index 7e195ffaa..000000000 --- a/src/main/java/net/minestom/server/recipe/ShapedRecipe.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; - -public abstract class ShapedRecipe extends Recipe { - private final int width; - private final int height; - private String group; - private RecipeCategory.Crafting category; - private final List ingredients; - private ItemStack result; - private boolean showNotification; - - protected ShapedRecipe(@NotNull String recipeId, - int width, - int height, - @NotNull String group, - @NotNull RecipeCategory.Crafting category, - @Nullable List ingredients, - @NotNull ItemStack result, boolean showNotification) { - super(RecipeType.SHAPED, recipeId); - this.width = width; - this.height = height; - this.group = group; - this.category = category; - this.ingredients = Objects.requireNonNullElseGet(ingredients, LinkedList::new); - this.result = result; - this.showNotification = showNotification; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - @NotNull - public RecipeCategory.Crafting getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Crafting category) { - this.category = category; - } - - public void addIngredient(DeclareRecipesPacket.Ingredient ingredient) { - if (ingredients.size() + 1 > width * height) { - throw new IndexOutOfBoundsException("You cannot add more ingredients than width*height"); - } - - ingredients.add(ingredient); - } - - @NotNull - public List getIngredients() { - return ingredients; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } - - public boolean getShowNotification() { - return showNotification; - } - - public void setShowNotification(boolean showNotification) { - this.showNotification = showNotification; - } -} diff --git a/src/main/java/net/minestom/server/recipe/ShapelessRecipe.java b/src/main/java/net/minestom/server/recipe/ShapelessRecipe.java deleted file mode 100644 index 391029344..000000000 --- a/src/main/java/net/minestom/server/recipe/ShapelessRecipe.java +++ /dev/null @@ -1,67 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; - -public abstract class ShapelessRecipe extends Recipe { - private String group; - private RecipeCategory.Crafting category; - private final List ingredients; - private ItemStack result; - - protected ShapelessRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull RecipeCategory.Crafting category, - @Nullable List ingredients, - @NotNull ItemStack result - ) { - super(RecipeType.SHAPELESS, recipeId); - this.group = group; - this.category = category; - this.ingredients = Objects.requireNonNullElseGet(ingredients, LinkedList::new); - this.result = result; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - @NotNull - public RecipeCategory.Crafting getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Crafting category) { - this.category = category; - } - - public void addIngredient(DeclareRecipesPacket.Ingredient ingredient) { - ingredients.add(ingredient); - } - - @NotNull - public List getIngredients() { - return ingredients; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } -} diff --git a/src/main/java/net/minestom/server/recipe/SmeltingRecipe.java b/src/main/java/net/minestom/server/recipe/SmeltingRecipe.java deleted file mode 100644 index 35a0a1061..000000000 --- a/src/main/java/net/minestom/server/recipe/SmeltingRecipe.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class SmeltingRecipe extends Recipe { - private String group; - private RecipeCategory.Cooking category; - private DeclareRecipesPacket.Ingredient ingredient; - private ItemStack result; - private float experience; - private int cookingTime; - - protected SmeltingRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull RecipeCategory.Cooking category, - @NotNull ItemStack result, - float experience, - int cookingTime - ) { - super(RecipeType.SMELTING, recipeId); - this.group = group; - this.category = category; - this.result = result; - this.experience = experience; - this.cookingTime = cookingTime; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - public @NotNull RecipeCategory.Cooking getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Cooking category) { - this.category = category; - } - - public @NotNull DeclareRecipesPacket.Ingredient getIngredient() { - return ingredient; - } - - public void setIngredient(@NotNull DeclareRecipesPacket.Ingredient ingredient) { - this.ingredient = ingredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } - - public float getExperience() { - return experience; - } - - public void setExperience(float experience) { - this.experience = experience; - } - - public int getCookingTime() { - return cookingTime; - } - - public void setCookingTime(int cookingTime) { - this.cookingTime = cookingTime; - } -} diff --git a/src/main/java/net/minestom/server/recipe/SmithingTransformRecipe.java b/src/main/java/net/minestom/server/recipe/SmithingTransformRecipe.java deleted file mode 100644 index b1ae9bdff..000000000 --- a/src/main/java/net/minestom/server/recipe/SmithingTransformRecipe.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class SmithingTransformRecipe extends Recipe { - private DeclareRecipesPacket.Ingredient template; - private DeclareRecipesPacket.Ingredient baseIngredient; - private DeclareRecipesPacket.Ingredient additionIngredient; - private ItemStack result; - - protected SmithingTransformRecipe( - @NotNull String recipeId, - @NotNull DeclareRecipesPacket.Ingredient template, - @NotNull DeclareRecipesPacket.Ingredient baseIngredient, - @NotNull DeclareRecipesPacket.Ingredient additionIngredient, - @NotNull ItemStack result - ) { - super(RecipeType.SMITHING_TRANSFORM, recipeId); - this.template = template; - this.baseIngredient = baseIngredient; - this.additionIngredient = additionIngredient; - this.result = result; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getTemplate() { - return template; - } - - public void setTemplate(@NotNull DeclareRecipesPacket.Ingredient template) { - this.template = template; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getBaseIngredient() { - return baseIngredient; - } - - public void setBaseIngredient(@NotNull DeclareRecipesPacket.Ingredient baseIngredient) { - this.baseIngredient = baseIngredient; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getAdditionIngredient() { - return additionIngredient; - } - - public void setAdditionIngredient(@NotNull DeclareRecipesPacket.Ingredient additionIngredient) { - this.additionIngredient = additionIngredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } -} diff --git a/src/main/java/net/minestom/server/recipe/SmithingTrimRecipe.java b/src/main/java/net/minestom/server/recipe/SmithingTrimRecipe.java deleted file mode 100644 index 1259392a7..000000000 --- a/src/main/java/net/minestom/server/recipe/SmithingTrimRecipe.java +++ /dev/null @@ -1,49 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class SmithingTrimRecipe extends Recipe { - private DeclareRecipesPacket.Ingredient template; - private DeclareRecipesPacket.Ingredient baseIngredient; - private DeclareRecipesPacket.Ingredient additionIngredient; - - protected SmithingTrimRecipe( - @NotNull String recipeId, - @NotNull DeclareRecipesPacket.Ingredient template, - @NotNull DeclareRecipesPacket.Ingredient baseIngredient, - @NotNull DeclareRecipesPacket.Ingredient additionIngredient - ) { - super(RecipeType.SMITHING_TRIM, recipeId); - this.template = template; - this.baseIngredient = baseIngredient; - this.additionIngredient = additionIngredient; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getTemplate() { - return template; - } - - public void setTemplate(@NotNull DeclareRecipesPacket.Ingredient template) { - this.template = template; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getBaseIngredient() { - return baseIngredient; - } - - public void setBaseIngredient(@NotNull DeclareRecipesPacket.Ingredient baseIngredient) { - this.baseIngredient = baseIngredient; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getAdditionIngredient() { - return additionIngredient; - } - - public void setAdditionIngredient(@NotNull DeclareRecipesPacket.Ingredient additionIngredient) { - this.additionIngredient = additionIngredient; - } -} diff --git a/src/main/java/net/minestom/server/recipe/SmokingRecipe.java b/src/main/java/net/minestom/server/recipe/SmokingRecipe.java deleted file mode 100644 index ef27f1a58..000000000 --- a/src/main/java/net/minestom/server/recipe/SmokingRecipe.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class SmokingRecipe extends Recipe { - private String group; - private RecipeCategory.Cooking category; - private DeclareRecipesPacket.Ingredient ingredient; - private ItemStack result; - private float experience; - private int cookingTime; - - protected SmokingRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull RecipeCategory.Cooking category, - @NotNull ItemStack result, - float experience, - int cookingTime - ) { - super(RecipeType.SMOKING, recipeId); - this.group = group; - this.category = category; - this.result = result; - this.experience = experience; - this.cookingTime = cookingTime; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - @NotNull - public RecipeCategory.Cooking getCategory() { - return category; - } - - public void setCategory(@NotNull RecipeCategory.Cooking category) { - this.category = category; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getIngredient() { - return ingredient; - } - - public void setIngredient(@NotNull DeclareRecipesPacket.Ingredient ingredient) { - this.ingredient = ingredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } - - public float getExperience() { - return experience; - } - - public void setExperience(float experience) { - this.experience = experience; - } - - public int getCookingTime() { - return cookingTime; - } - - public void setCookingTime(int cookingTime) { - this.cookingTime = cookingTime; - } -} diff --git a/src/main/java/net/minestom/server/recipe/StonecutterRecipe.java b/src/main/java/net/minestom/server/recipe/StonecutterRecipe.java deleted file mode 100644 index 78dc4db84..000000000 --- a/src/main/java/net/minestom/server/recipe/StonecutterRecipe.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import org.jetbrains.annotations.NotNull; - -public abstract class StonecutterRecipe extends Recipe { - private String group; - private DeclareRecipesPacket.Ingredient ingredient; - private ItemStack result; - - protected StonecutterRecipe( - @NotNull String recipeId, - @NotNull String group, - @NotNull DeclareRecipesPacket.Ingredient ingredient, - @NotNull ItemStack result - ) { - super(RecipeType.STONECUTTING, recipeId); - this.group = group; - this.ingredient = ingredient; - this.result = result; - } - - @NotNull - public String getGroup() { - return group; - } - - public void setGroup(@NotNull String group) { - this.group = group; - } - - @NotNull - public DeclareRecipesPacket.Ingredient getIngredient() { - return ingredient; - } - - public void setIngredient(@NotNull DeclareRecipesPacket.Ingredient ingredient) { - this.ingredient = ingredient; - } - - @NotNull - public ItemStack getResult() { - return result; - } - - public void setResult(@NotNull ItemStack result) { - this.result = result; - } -} diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index 19e86f0e2..8d6db2e23 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -20,8 +20,8 @@ import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.login.LoginSuccessPacket; import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.network.packet.server.play.*; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket.Ingredient; import net.minestom.server.network.packet.server.status.ResponsePacket; +import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeCategory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -81,45 +81,44 @@ public class PacketWriteReadTest { SERVER_PACKETS.add(new CraftRecipeResponse((byte) 2, "recipe")); SERVER_PACKETS.add(new DeathCombatEventPacket(5, COMPONENT)); SERVER_PACKETS.add(new DeclareRecipesPacket( - List.of(new DeclareRecipesPacket.DeclaredShapelessCraftingRecipe( + List.of(new Recipe( "minecraft:sticks", - "sticks", - RecipeCategory.Crafting.MISC, - List.of(new Ingredient(List.of(ItemStack.of(Material.OAK_PLANKS)))), - ItemStack.of(Material.STICK) + new Recipe.Shapeless("sticks", RecipeCategory.Crafting.MISC, + List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.OAK_PLANKS)))), + ItemStack.of(Material.STICK)) ), - new DeclareRecipesPacket.DeclaredShapedCraftingRecipe( + new Recipe( "minecraft:torch", - "", - RecipeCategory.Crafting.MISC, - 1, - 2, - List.of(new Ingredient(List.of(ItemStack.of(Material.COAL))), - new Ingredient(List.of(ItemStack.of(Material.STICK)))), - ItemStack.of(Material.TORCH), - true + new Recipe.Shaped("", + RecipeCategory.Crafting.MISC, + 1, + 2, + List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), + new Recipe.Ingredient(List.of(ItemStack.of(Material.STICK)))), + ItemStack.of(Material.TORCH), + true) ), - new DeclareRecipesPacket.DeclaredBlastingRecipe( + new Recipe( "minecraft:coal", - "forging", - RecipeCategory.Cooking.MISC, - new Ingredient(List.of(ItemStack.of(Material.COAL))), - ItemStack.of(Material.IRON_INGOT), - 5, - 5 + new Recipe.Blasting("forging", + RecipeCategory.Cooking.MISC, + new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), + ItemStack.of(Material.IRON_INGOT), + 5, + 5) ), - new DeclareRecipesPacket.DeclaredSmithingTransformRecipe( + new Recipe( "minecraft:iron_to_diamond", - new Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), - new Ingredient(List.of(ItemStack.of(Material.DIAMOND))), - new Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - ItemStack.of(Material.DIAMOND) + new Recipe.SmithingTransform(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), + new Recipe.Ingredient(List.of(ItemStack.of(Material.DIAMOND))), + new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), + ItemStack.of(Material.DIAMOND)) ), - new DeclareRecipesPacket.DeclaredSmithingTrimRecipe( + new Recipe( "minecraft:iron_to_coast", - new Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - new Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), - new Ingredient(List.of(ItemStack.of(Material.COAL))) + new Recipe.SmithingTrim(new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), + new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), + new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL)))) ) ))); diff --git a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java index 0f4363826..9e5df2c3d 100644 --- a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java +++ b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java @@ -4,6 +4,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; +import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeCategory; import org.junit.jupiter.api.Test; @@ -16,10 +17,11 @@ public class DeclareRecipesPacketTest { @Test public void cannotWriteAirIngredient() { var packet = new DeclareRecipesPacket(List.of( - new DeclareRecipesPacket.DeclaredShapelessCraftingRecipe( - "recipe1", "group1", RecipeCategory.Crafting.BUILDING, - List.of(new DeclareRecipesPacket.Ingredient(List.of(ItemStack.AIR))), - ItemStack.of(Material.DIAMOND) + new Recipe( + "recipe1", + new Recipe.Shapeless("group1", RecipeCategory.Crafting.BUILDING, + List.of(new Recipe.Ingredient(List.of(ItemStack.AIR))), + ItemStack.of(Material.DIAMOND)) ) )); From e1e26cbd35446b8f14021cd93701dd8a4d81948b Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 21 Jul 2024 22:25:48 +0200 Subject: [PATCH 07/97] Get packet id from packet registry (#2288) * Get packet id from packet registry * Fix test, cleanup packet parser/registry * Style --- .../server/network/packet/PacketParser.java | 91 ++++----- .../server/network/packet/PacketRegistry.java | 18 +- .../network/packet/server/ServerPacket.java | 35 ---- .../packet/server/ServerPacketIdentifier.java | 179 ------------------ .../server/common/CookieRequestPacket.java | 15 -- .../server/common/CookieStorePacket.java | 10 - .../common/CustomReportDetailsPacket.java | 10 - .../server/common/DisconnectPacket.java | 11 -- .../packet/server/common/KeepAlivePacket.java | 10 - .../packet/server/common/PingPacket.java | 10 - .../server/common/PingResponsePacket.java | 10 - .../server/common/PluginMessagePacket.java | 11 -- .../server/common/ResourcePackPopPacket.java | 10 - .../server/common/ResourcePackPushPacket.java | 11 -- .../server/common/ServerLinksPacket.java | 11 -- .../packet/server/common/TagsPacket.java | 11 -- .../packet/server/common/TransferPacket.java | 10 - .../FinishConfigurationPacket.java | 5 - .../configuration/RegistryDataPacket.java | 6 - .../server/configuration/ResetChatPacket.java | 5 - .../configuration/SelectKnownPacksPacket.java | 6 - .../UpdateEnabledFeaturesPacket.java | 5 - .../server/login/EncryptionRequestPacket.java | 5 - .../server/login/LoginDisconnectPacket.java | 6 - .../login/LoginPluginRequestPacket.java | 5 - .../server/login/LoginSuccessPacket.java | 5 - .../server/login/SetCompressionPacket.java | 5 - .../play/AcknowledgeBlockChangePacket.java | 5 - .../packet/server/play/ActionBarPacket.java | 6 - .../server/play/AdvancementsPacket.java | 6 - .../server/play/AttachEntityPacket.java | 5 - .../packet/server/play/BlockActionPacket.java | 5 - .../play/BlockBreakAnimationPacket.java | 5 - .../packet/server/play/BlockChangePacket.java | 5 - .../server/play/BlockEntityDataPacket.java | 5 - .../packet/server/play/BossBarPacket.java | 6 - .../packet/server/play/BundlePacket.java | 5 - .../packet/server/play/CameraPacket.java | 5 - .../server/play/ChangeGameStatePacket.java | 6 - .../server/play/ChunkBatchFinishedPacket.java | 5 - .../server/play/ChunkBatchStartPacket.java | 5 - .../packet/server/play/ChunkDataPacket.java | 5 - .../packet/server/play/ClearTitlesPacket.java | 5 - .../packet/server/play/CloseWindowPacket.java | 5 - .../packet/server/play/CollectItemPacket.java | 5 - .../server/play/CraftRecipeResponse.java | 5 - .../play/CustomChatCompletionPacket.java | 6 - .../packet/server/play/DamageEventPacket.java | 6 - .../server/play/DeathCombatEventPacket.java | 10 +- .../packet/server/play/DebugSamplePacket.java | 6 - .../server/play/DeclareCommandsPacket.java | 6 - .../server/play/DeclareRecipesPacket.java | 5 - .../packet/server/play/DeleteChatPacket.java | 5 - .../server/play/DestroyEntitiesPacket.java | 5 - .../server/play/DisplayScoreboardPacket.java | 5 - .../packet/server/play/EffectPacket.java | 5 - .../server/play/EndCombatEventPacket.java | 5 - .../server/play/EnterCombatEventPacket.java | 5 - .../server/play/EntityAnimationPacket.java | 6 - .../server/play/EntityEffectPacket.java | 5 - .../server/play/EntityEquipmentPacket.java | 6 - .../server/play/EntityHeadLookPacket.java | 5 - .../server/play/EntityMetaDataPacket.java | 6 - .../play/EntityPositionAndRotationPacket.java | 6 - .../server/play/EntityPositionPacket.java | 6 - .../server/play/EntityRotationPacket.java | 5 - .../server/play/EntitySoundEffectPacket.java | 5 - .../server/play/EntityStatusPacket.java | 5 - .../server/play/EntityTeleportPacket.java | 5 - .../server/play/EntityVelocityPacket.java | 5 - .../packet/server/play/ExplosionPacket.java | 6 - .../packet/server/play/FacePlayerPacket.java | 6 - .../server/play/HeldItemChangePacket.java | 5 - .../server/play/HitAnimationPacket.java | 5 - .../play/InitializeWorldBorderPacket.java | 5 - .../packet/server/play/JoinGamePacket.java | 6 - .../packet/server/play/MapDataPacket.java | 6 - .../server/play/MultiBlockChangePacket.java | 8 +- .../server/play/NbtQueryResponsePacket.java | 6 - .../packet/server/play/OpenBookPacket.java | 5 - .../server/play/OpenHorseWindowPacket.java | 5 - .../server/play/OpenSignEditorPacket.java | 5 - .../packet/server/play/OpenWindowPacket.java | 7 - .../packet/server/play/ParticlePacket.java | 5 - .../server/play/PlayerAbilitiesPacket.java | 5 - .../server/play/PlayerChatMessagePacket.java | 7 - .../server/play/PlayerInfoRemovePacket.java | 5 - .../server/play/PlayerInfoUpdatePacket.java | 6 - .../play/PlayerListHeaderAndFooterPacket.java | 6 - .../play/PlayerPositionAndLookPacket.java | 5 - .../server/play/ProjectilePowerPacket.java | 6 - .../server/play/RemoveEntityEffectPacket.java | 5 - .../packet/server/play/ResetScorePacket.java | 5 - .../packet/server/play/RespawnPacket.java | 5 - .../play/ScoreboardObjectivePacket.java | 7 - .../play/SelectAdvancementTabPacket.java | 5 - .../packet/server/play/ServerDataPacket.java | 5 - .../server/play/ServerDifficultyPacket.java | 5 - .../packet/server/play/SetCooldownPacket.java | 5 - .../server/play/SetExperiencePacket.java | 5 - .../server/play/SetPassengersPacket.java | 5 - .../packet/server/play/SetSlotPacket.java | 6 - .../server/play/SetTickStatePacket.java | 8 +- .../server/play/SetTitleSubTitlePacket.java | 7 - .../server/play/SetTitleTextPacket.java | 7 - .../server/play/SetTitleTimePacket.java | 5 - .../packet/server/play/SoundEffectPacket.java | 5 - .../packet/server/play/SpawnEntityPacket.java | 5 - .../server/play/SpawnExperienceOrbPacket.java | 5 - .../server/play/SpawnPositionPacket.java | 5 - .../server/play/StartConfigurationPacket.java | 6 - .../packet/server/play/StatisticsPacket.java | 6 - .../packet/server/play/StopSoundPacket.java | 5 - .../packet/server/play/SystemChatPacket.java | 7 - .../packet/server/play/TabCompletePacket.java | 7 - .../packet/server/play/TeamsPacket.java | 12 -- .../packet/server/play/TickStepPacket.java | 5 - .../packet/server/play/TimeUpdatePacket.java | 5 - .../packet/server/play/TradeListPacket.java | 6 - .../packet/server/play/UnloadChunkPacket.java | 6 - .../server/play/UnlockRecipesPacket.java | 5 - .../server/play/UpdateHealthPacket.java | 5 - .../packet/server/play/UpdateLightPacket.java | 5 - .../packet/server/play/UpdateScorePacket.java | 5 - .../play/UpdateSimulationDistancePacket.java | 5 - .../server/play/UpdateViewDistancePacket.java | 5 - .../server/play/UpdateViewPositionPacket.java | 5 - .../packet/server/play/VehicleMovePacket.java | 5 - .../packet/server/play/WindowItemsPacket.java | 6 - .../server/play/WindowPropertyPacket.java | 5 - .../server/play/WorldBorderCenterPacket.java | 5 - .../play/WorldBorderLerpSizePacket.java | 5 - .../server/play/WorldBorderSizePacket.java | 5 - .../play/WorldBorderWarningDelayPacket.java | 5 - .../play/WorldBorderWarningReachPacket.java | 5 - .../packet/server/status/ResponsePacket.java | 5 - .../minestom/server/utils/PacketUtils.java | 10 +- .../server/network/SocketWriteTest.java | 22 +-- 138 files changed, 85 insertions(+), 1067 deletions(-) delete mode 100644 src/main/java/net/minestom/server/network/packet/server/ServerPacketIdentifier.java diff --git a/src/main/java/net/minestom/server/network/packet/PacketParser.java b/src/main/java/net/minestom/server/network/packet/PacketParser.java index 1387ae3f4..522407170 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketParser.java +++ b/src/main/java/net/minestom/server/network/packet/PacketParser.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.ClientPacket; -import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -15,61 +14,65 @@ import org.jetbrains.annotations.NotNull; */ public sealed interface PacketParser { - @NotNull T parse(@NotNull ConnectionState connectionState, - int packetId, @NotNull NetworkBuffer buffer); + @NotNull PacketRegistry handshakeRegistry(); + + @NotNull PacketRegistry statusRegistry(); + + @NotNull PacketRegistry loginRegistry(); + + @NotNull PacketRegistry configurationRegistry(); + + @NotNull PacketRegistry playRegistry(); + + default @NotNull T parse(@NotNull ConnectionState connectionState, + int packetId, @NotNull NetworkBuffer buffer) { + final PacketRegistry registry = stateRegistry(connectionState); + return registry.create(packetId, buffer); + } + + default @NotNull PacketRegistry stateRegistry(@NotNull ConnectionState connectionState) { + return switch (connectionState) { + case HANDSHAKE -> handshakeRegistry(); + case STATUS -> statusRegistry(); + case LOGIN -> loginRegistry(); + case CONFIGURATION -> configurationRegistry(); + case PLAY -> playRegistry(); + }; + } record Client( - PacketRegistry.Client statusHandler, - PacketRegistry.Client loginHandler, - PacketRegistry.Client configurationHandler, - PacketRegistry.Client playHandler + PacketRegistry handshakeRegistry, + PacketRegistry statusRegistry, + PacketRegistry loginRegistry, + PacketRegistry configurationRegistry, + PacketRegistry playRegistry ) implements PacketParser { - public Client() { - this(new PacketRegistry.ClientStatus(), new PacketRegistry.ClientLogin(), - new PacketRegistry.ClientConfiguration(), new PacketRegistry.ClientPlay() + this( + new PacketRegistry.ClientHandshake(), + new PacketRegistry.ClientStatus(), + new PacketRegistry.ClientLogin(), + new PacketRegistry.ClientConfiguration(), + new PacketRegistry.ClientPlay() ); } - - @Override - public @NotNull ClientPacket parse(@NotNull ConnectionState connectionState, - int packetId, @NotNull NetworkBuffer buffer) { - return switch (connectionState) { - case HANDSHAKE -> { - assert packetId == 0; - yield new ClientHandshakePacket(buffer); - } - case STATUS -> statusHandler.create(packetId, buffer); - case LOGIN -> loginHandler.create(packetId, buffer); - case CONFIGURATION -> configurationHandler.create(packetId, buffer); - case PLAY -> playHandler.create(packetId, buffer); - }; - } } record Server( - PacketRegistry.Server statusHandler, - PacketRegistry.Server loginHandler, - PacketRegistry.Server configurationHandler, - PacketRegistry.Server playHandler + PacketRegistry handshakeRegistry, + PacketRegistry statusRegistry, + PacketRegistry loginRegistry, + PacketRegistry configurationRegistry, + PacketRegistry playRegistry ) implements PacketParser { - public Server() { - this(new PacketRegistry.ServerStatus(), new PacketRegistry.ServerLogin(), - new PacketRegistry.ServerConfiguration(), new PacketRegistry.ServerPlay() + this( + new PacketRegistry.ServerHandshake(), + new PacketRegistry.ServerStatus(), + new PacketRegistry.ServerLogin(), + new PacketRegistry.ServerConfiguration(), + new PacketRegistry.ServerPlay() ); } - - @Override - public @NotNull ServerPacket parse(@NotNull ConnectionState connectionState, - int packetId, @NotNull NetworkBuffer buffer) { - return switch (connectionState) { - case HANDSHAKE -> throw new UnsupportedOperationException("No client-bound Handshake packet"); - case STATUS -> statusHandler.create(packetId, buffer); - case LOGIN -> loginHandler.create(packetId, buffer); - case CONFIGURATION -> configurationHandler.create(packetId, buffer); - case PLAY -> playHandler.create(packetId, buffer); - }; - } } } diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index c9eb3fd14..b6dd6a302 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -5,6 +5,7 @@ import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.common.*; import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; +import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; @@ -32,6 +33,14 @@ public interface PacketRegistry { } } + final class ClientHandshake extends Client { + public ClientHandshake() { + super( + entry(ClientHandshakePacket.class, ClientHandshakePacket::new) + ); + } + } + final class ClientStatus extends Client { public ClientStatus() { super( @@ -140,6 +149,12 @@ public interface PacketRegistry { } } + final class ServerHandshake extends Server { + public ServerHandshake() { + super(); + } + } + final class ServerStatus extends Server { public ServerStatus() { super( @@ -323,7 +338,8 @@ public interface PacketRegistry { @Override protected Integer computeValue(@NotNull Class type) { for (int i = 0; i < suppliers.length; i++) { - if (suppliers[i].type == type) return i; + final Entry entry = suppliers[i]; + if (entry != null && entry.type == type) return i; } throw new IllegalStateException("Packet type " + type + " isn't registered!"); } 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 37384bc20..ab9668310 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,14 +1,8 @@ package net.minestom.server.network.packet.server; import net.minestom.server.adventure.ComponentHolder; -import net.minestom.server.network.ConnectionState; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.PacketUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; /** * Represents a packet which can be sent to a player using {@link PlayerConnection#sendPacket(SendablePacket)}. @@ -18,45 +12,16 @@ import java.util.List; public sealed interface ServerPacket extends NetworkBuffer.Writer, SendablePacket permits ServerPacket.Configuration, ServerPacket.Status, ServerPacket.Login, ServerPacket.Play { - /** - * Gets the id of this packet. - *

- * Written in the final buffer header so it needs to match the client id. - * - * @return the id of this packet - */ - default int getId(@NotNull ConnectionState state) { - final int id = switch (state) { - case HANDSHAKE -> -1; - case CONFIGURATION -> this instanceof Configuration configuration ? configuration.configurationId() : -1; - case STATUS -> this instanceof Status status ? status.statusId() : -1; - case LOGIN -> this instanceof Login login ? login.loginId() : -1; - case PLAY -> this instanceof Play play ? play.playId() : -1; - }; - if (id != -1) return id; - // Invalid state, generate error - List validStates = new ArrayList<>(); - if (this instanceof Configuration) validStates.add(ConnectionState.CONFIGURATION); - if (this instanceof Status) validStates.add(ConnectionState.STATUS); - if (this instanceof Login) validStates.add(ConnectionState.LOGIN); - if (this instanceof Play) validStates.add(ConnectionState.PLAY); - return PacketUtils.invalidPacketState(getClass(), state, validStates.toArray(ConnectionState[]::new)); - } - non-sealed interface Configuration extends ServerPacket { - int configurationId(); } non-sealed interface Status extends ServerPacket { - int statusId(); } non-sealed interface Login extends ServerPacket { - int loginId(); } non-sealed interface Play extends ServerPacket { - int playId(); } interface ComponentHolding extends ComponentHolder { diff --git a/src/main/java/net/minestom/server/network/packet/server/ServerPacketIdentifier.java b/src/main/java/net/minestom/server/network/packet/server/ServerPacketIdentifier.java deleted file mode 100644 index 0d48a9c3f..000000000 --- a/src/main/java/net/minestom/server/network/packet/server/ServerPacketIdentifier.java +++ /dev/null @@ -1,179 +0,0 @@ -package net.minestom.server.network.packet.server; - -import java.util.concurrent.atomic.AtomicInteger; - -public final class ServerPacketIdentifier { - private static final AtomicInteger STATUS_ID = new AtomicInteger(0); - private static final AtomicInteger LOGIN_ID = new AtomicInteger(0); - private static final AtomicInteger CONFIGURATION_ID = new AtomicInteger(0); - private static final AtomicInteger PLAY_ID = new AtomicInteger(0); - - public static final int STATUS_RESPONSE = nextStatusId(); - public static final int STATUS_PING_RESPONSE = nextStatusId(); - - public static final int LOGIN_DISCONNECT = nextLoginId(); - public static final int LOGIN_ENCRYPTION_REQUEST = nextLoginId(); - public static final int LOGIN_SUCCESS = nextLoginId(); - public static final int LOGIN_SET_COMPRESSION = nextLoginId(); - public static final int LOGIN_PLUGIN_REQUEST = nextLoginId(); - public static final int LOGIN_COOKIE_REQUEST = nextLoginId(); - - public static final int CONFIGURATION_COOKIE_REQUEST = nextConfigurationId(); - public static final int CONFIGURATION_PLUGIN_MESSAGE = nextConfigurationId(); - public static final int CONFIGURATION_DISCONNECT = nextConfigurationId(); - public static final int CONFIGURATION_FINISH_CONFIGURATION = nextConfigurationId(); - public static final int CONFIGURATION_KEEP_ALIVE = nextConfigurationId(); - public static final int CONFIGURATION_PING = nextConfigurationId(); - public static final int CONFIGURATION_RESET_CHAT = nextConfigurationId(); - public static final int CONFIGURATION_REGISTRY_DATA = nextConfigurationId(); - public static final int CONFIGURATION_RESOURCE_PACK_POP = nextConfigurationId(); - public static final int CONFIGURATION_RESOURCE_PACK_PUSH = nextConfigurationId(); - public static final int CONFIGURATION_COOKIE_STORE = nextConfigurationId(); - public static final int CONFIGURATION_TRANSFER = nextConfigurationId(); - public static final int CONFIGURATION_UPDATE_ENABLED_FEATURES = nextConfigurationId(); - public static final int CONFIGURATION_TAGS = nextConfigurationId(); - public static final int CONFIGURATION_SELECT_KNOWN_PACKS = nextConfigurationId(); - public static final int CONFIGURATION_CUSTOM_REPORT_DETAILS = nextConfigurationId(); - public static final int CONFIGURATION_SERVER_LINKS = nextConfigurationId(); - - public static final int BUNDLE = nextPlayId(); - public static final int SPAWN_ENTITY = nextPlayId(); - public static final int SPAWN_EXPERIENCE_ORB = nextPlayId(); - public static final int ENTITY_ANIMATION = nextPlayId(); - public static final int STATISTICS = nextPlayId(); - public static final int ACKNOWLEDGE_BLOCK_CHANGE = nextPlayId(); - public static final int BLOCK_BREAK_ANIMATION = nextPlayId(); - public static final int BLOCK_ENTITY_DATA = nextPlayId(); - public static final int BLOCK_ACTION = nextPlayId(); - public static final int BLOCK_CHANGE = nextPlayId(); - public static final int BOSS_BAR = nextPlayId(); - public static final int SERVER_DIFFICULTY = nextPlayId(); - public static final int CHUNK_BATCH_FINISHED = nextPlayId(); - public static final int CHUNK_BATCH_START = nextPlayId(); - public static final int CHUNK_BIOMES = nextPlayId(); - public static final int CLEAR_TITLES = nextPlayId(); - public static final int TAB_COMPLETE = nextPlayId(); - public static final int DECLARE_COMMANDS = nextPlayId(); - public static final int CLOSE_WINDOW = nextPlayId(); - public static final int WINDOW_ITEMS = nextPlayId(); - public static final int WINDOW_PROPERTY = nextPlayId(); - public static final int SET_SLOT = nextPlayId(); - public static final int COOKIE_REQUEST = nextPlayId(); - public static final int SET_COOLDOWN = nextPlayId(); - public static final int CUSTOM_CHAT_COMPLETIONS = nextPlayId(); - public static final int PLUGIN_MESSAGE = nextPlayId(); - public static final int DAMAGE_EVENT = nextPlayId(); - public static final int DEBUG_SAMPLE = nextPlayId(); - public static final int DELETE_CHAT_MESSAGE = nextPlayId(); - public static final int DISCONNECT = nextPlayId(); - public static final int DISGUISED_CHAT = nextPlayId(); - public static final int ENTITY_STATUS = nextPlayId(); - public static final int EXPLOSION = nextPlayId(); - public static final int UNLOAD_CHUNK = nextPlayId(); - public static final int CHANGE_GAME_STATE = nextPlayId(); - public static final int OPEN_HORSE_WINDOW = nextPlayId(); - public static final int HIT_ANIMATION = nextPlayId(); - public static final int INITIALIZE_WORLD_BORDER = nextPlayId(); - public static final int KEEP_ALIVE = nextPlayId(); - public static final int CHUNK_DATA = nextPlayId(); - public static final int EFFECT = nextPlayId(); - public static final int PARTICLE = nextPlayId(); - public static final int UPDATE_LIGHT = nextPlayId(); - public static final int JOIN_GAME = nextPlayId(); - public static final int MAP_DATA = nextPlayId(); - public static final int TRADE_LIST = nextPlayId(); - public static final int ENTITY_POSITION = nextPlayId(); - public static final int ENTITY_POSITION_AND_ROTATION = nextPlayId(); - public static final int ENTITY_ROTATION = nextPlayId(); - public static final int VEHICLE_MOVE = nextPlayId(); - public static final int OPEN_BOOK = nextPlayId(); - public static final int OPEN_WINDOW = nextPlayId(); - public static final int OPEN_SIGN_EDITOR = nextPlayId(); - public static final int PING = nextPlayId(); - public static final int PING_RESPONSE = nextPlayId(); - public static final int CRAFT_RECIPE_RESPONSE = nextPlayId(); - public static final int PLAYER_ABILITIES = nextPlayId(); - public static final int PLAYER_CHAT = nextPlayId(); - public static final int END_COMBAT_EVENT = nextPlayId(); - public static final int ENTER_COMBAT_EVENT = nextPlayId(); - public static final int DEATH_COMBAT_EVENT = nextPlayId(); - public static final int PLAYER_INFO_REMOVE = nextPlayId(); - public static final int PLAYER_INFO_UPDATE = nextPlayId(); - public static final int FACE_PLAYER = nextPlayId(); - public static final int PLAYER_POSITION_AND_LOOK = nextPlayId(); - public static final int UNLOCK_RECIPES = nextPlayId(); - public static final int DESTROY_ENTITIES = nextPlayId(); - public static final int REMOVE_ENTITY_EFFECT = nextPlayId(); - public static final int RESET_SCORE = nextPlayId(); - public static final int RESOURCE_PACK_POP = nextPlayId(); - public static final int RESOURCE_PACK_PUSH = nextPlayId(); - public static final int RESPAWN = nextPlayId(); - public static final int ENTITY_HEAD_LOOK = nextPlayId(); - public static final int MULTI_BLOCK_CHANGE = nextPlayId(); - public static final int SELECT_ADVANCEMENT_TAB = nextPlayId(); - public static final int SERVER_DATA = nextPlayId(); - public static final int ACTION_BAR = nextPlayId(); - public static final int WORLD_BORDER_CENTER = nextPlayId(); - public static final int WORLD_BORDER_LERP_SIZE = nextPlayId(); - public static final int WORLD_BORDER_SIZE = nextPlayId(); - public static final int WORLD_BORDER_WARNING_DELAY = nextPlayId(); - public static final int WORLD_BORDER_WARNING_REACH = nextPlayId(); - public static final int CAMERA = nextPlayId(); - public static final int HELD_ITEM_CHANGE = nextPlayId(); - public static final int UPDATE_VIEW_POSITION = nextPlayId(); - public static final int UPDATE_VIEW_DISTANCE = nextPlayId(); // Not used by the dedicated server - public static final int SPAWN_POSITION = nextPlayId(); - public static final int DISPLAY_SCOREBOARD = nextPlayId(); - public static final int ENTITY_METADATA = nextPlayId(); - public static final int ATTACH_ENTITY = nextPlayId(); - public static final int ENTITY_VELOCITY = nextPlayId(); - public static final int ENTITY_EQUIPMENT = nextPlayId(); - public static final int SET_EXPERIENCE = nextPlayId(); - public static final int UPDATE_HEALTH = nextPlayId(); - public static final int SCOREBOARD_OBJECTIVE = nextPlayId(); - public static final int SET_PASSENGERS = nextPlayId(); - public static final int TEAMS = nextPlayId(); - public static final int UPDATE_SCORE = nextPlayId(); - public static final int SET_SIMULATION_DISTANCE = nextPlayId(); - public static final int SET_TITLE_SUBTITLE = nextPlayId(); - public static final int TIME_UPDATE = nextPlayId(); - public static final int SET_TITLE_TEXT = nextPlayId(); - public static final int SET_TITLE_TIME = nextPlayId(); - public static final int ENTITY_SOUND_EFFECT = nextPlayId(); - public static final int SOUND_EFFECT = nextPlayId(); - public static final int START_CONFIGURATION_PACKET = nextPlayId(); - public static final int STOP_SOUND = nextPlayId(); - public static final int COOKIE_STORE = nextPlayId(); - public static final int SYSTEM_CHAT = nextPlayId(); - public static final int PLAYER_LIST_HEADER_AND_FOOTER = nextPlayId(); - public static final int NBT_QUERY_RESPONSE = nextPlayId(); - public static final int COLLECT_ITEM = nextPlayId(); - public static final int ENTITY_TELEPORT = nextPlayId(); - public static final int TICK_STATE = nextPlayId(); - public static final int TICK_STEP = nextPlayId(); - public static final int TRANSFER = nextPlayId(); - public static final int ADVANCEMENTS = nextPlayId(); - public static final int ENTITY_ATTRIBUTES = nextPlayId(); - public static final int ENTITY_EFFECT = nextPlayId(); - public static final int DECLARE_RECIPES = nextPlayId(); - public static final int TAGS = nextPlayId(); - public static final int PROJECTILE_POWER = nextPlayId(); - public static final int CUSTOM_REPORT_DETAILS = nextPlayId(); - public static final int SERVER_LINKS = nextPlayId(); - - private static int nextStatusId() { - return STATUS_ID.getAndIncrement(); - } - - private static int nextLoginId() { - return LOGIN_ID.getAndIncrement(); - } - - private static int nextConfigurationId() { - return CONFIGURATION_ID.getAndIncrement(); - } - - private static int nextPlayId() { - return PLAY_ID.getAndIncrement(); - } -} diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java index 853c11b39..8bd739e3e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record CookieRequestPacket(@NotNull String key) implements @@ -17,18 +16,4 @@ public record CookieRequestPacket(@NotNull String key) implements writer.write(NetworkBuffer.STRING, key); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_COOKIE_REQUEST; - } - - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_COOKIE_REQUEST; - } - - @Override - public int playId() { - return ServerPacketIdentifier.COOKIE_REQUEST; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java index 42775547f..ca9279477 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -42,13 +41,4 @@ public record CookieStorePacket( writer.write(NetworkBuffer.BYTE_ARRAY, value); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_COOKIE_STORE; - } - - @Override - public int playId() { - return ServerPacketIdentifier.COOKIE_STORE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java index 548637286..2adf6638e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -25,13 +24,4 @@ public record CustomReportDetailsPacket( writer.writeMap(NetworkBuffer.STRING, NetworkBuffer.STRING, details); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_CUSTOM_REPORT_DETAILS; - } - - @Override - public int playId() { - return ServerPacketIdentifier.CUSTOM_REPORT_DETAILS; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java index 494a463f2..d25fdf3c1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.common; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -23,16 +22,6 @@ public record DisconnectPacket(@NotNull Component message) implements ServerPack writer.write(COMPONENT, message); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_DISCONNECT; - } - - @Override - public int playId() { - return ServerPacketIdentifier.DISCONNECT; - } - @Override public @NotNull Collection components() { return List.of(message); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java index fd70b8cb1..b3db14494 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; @@ -17,13 +16,4 @@ public record KeepAlivePacket(long id) implements ServerPacket.Configuration, Se writer.write(LONG, id); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_KEEP_ALIVE; - } - - @Override - public int playId() { - return ServerPacketIdentifier.KEEP_ALIVE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java index 085355e90..2a796c6d6 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; @@ -17,13 +16,4 @@ public record PingPacket(int id) implements ServerPacket.Configuration, ServerPa writer.write(INT, id); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_PING; - } - - @Override - public int playId() { - return ServerPacketIdentifier.PING; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java index ad8a2c20a..01637df61 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; @@ -17,13 +16,4 @@ public record PingResponsePacket(long number) implements ServerPacket.Status, Se writer.write(LONG, number); } - @Override - public int statusId() { - return ServerPacketIdentifier.STATUS_PING_RESPONSE; - } - - @Override - public int playId() { - return ServerPacketIdentifier.PING_RESPONSE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java index c4ad532e3..f35a390d1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.RAW_BYTES; @@ -20,16 +19,6 @@ public record PluginMessagePacket(String channel, writer.write(RAW_BYTES, data); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_PLUGIN_MESSAGE; - } - - @Override - public int playId() { - return ServerPacketIdentifier.PLUGIN_MESSAGE; - } - /** * Gets the current server brand name packet. *

diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java index 82adfd113..cfc6d3143 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,13 +17,4 @@ public record ResourcePackPopPacket(@Nullable UUID id) implements ServerPacket.C writer.writeOptional(NetworkBuffer.UUID, id); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_RESOURCE_PACK_POP; - } - - @Override - public int playId() { - return ServerPacketIdentifier.RESOURCE_PACK_POP; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java index b585c2152..5c1803f21 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java @@ -4,7 +4,6 @@ import net.kyori.adventure.resource.ResourcePackInfo; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,16 +39,6 @@ public record ResourcePackPushPacket( writer.writeOptional(COMPONENT, prompt); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_RESOURCE_PACK_PUSH; - } - - @Override - public int playId() { - return ServerPacketIdentifier.RESOURCE_PACK_PUSH; - } - @Override public @NotNull Collection components() { return List.of(this.prompt); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java index 3c98bc06d..10b5ab9d7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.common; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,16 +29,6 @@ public record ServerLinksPacket(@NotNull List entries) implements ServerP writer.write(Entry.LIST_NETWORK_TYPE, entries); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_SERVER_LINKS; - } - - @Override - public int playId() { - return ServerPacketIdentifier.SERVER_LINKS; - } - public record Entry(@Nullable KnownLinkType knownType, @Nullable Component customType, @NotNull String link) { public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java index d6682eef2..7f0002e85 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; @@ -45,16 +44,6 @@ public record TagsPacket( } } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_TAGS; - } - - @Override - public int playId() { - return ServerPacketIdentifier.TAGS; - } - private static Map> readTagsMap(@NotNull NetworkBuffer reader) { Map> tagsMap = new EnumMap<>(Tag.BasicType.class); // Read amount of tag types diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java index 968e6b725..17cab834b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record TransferPacket( @@ -20,13 +19,4 @@ public record TransferPacket( writer.write(NetworkBuffer.VAR_INT, port); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_TRANSFER; - } - - @Override - public int playId() { - return ServerPacketIdentifier.TRANSFER; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java index cecb189ff..51386647e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record FinishConfigurationPacket() implements ServerPacket.Configuration { @@ -14,8 +13,4 @@ public record FinishConfigurationPacket() implements ServerPacket.Configuration public void write(@NotNull NetworkBuffer writer) { } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_FINISH_CONFIGURATION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java index cf0fc3eac..7b7275911 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.configuration; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,11 +26,6 @@ public record RegistryDataPacket( writer.writeCollection(entries); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_REGISTRY_DATA; - } - public record Entry( @NotNull String id, @Nullable CompoundBinaryTag data diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java index f460192f0..dec8daa25 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record ResetChatPacket() implements ServerPacket.Configuration { @@ -16,8 +15,4 @@ public record ResetChatPacket() implements ServerPacket.Configuration { // No fields } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_RESET_CHAT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java index 4f07a5f32..e13deff54 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.MinecraftServer; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -30,11 +29,6 @@ public record SelectKnownPacksPacket( writer.writeCollection(entries); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_SELECT_KNOWN_PACKS; - } - public record Entry( @NotNull String namespace, @NotNull String id, diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java index 7bba65a9b..3df4450e1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; @@ -22,8 +21,4 @@ public record UpdateEnabledFeaturesPacket(@NotNull Set features) im writer.writeCollection(features, (b, feature) -> b.write(STRING, feature.asString())); } - @Override - public int configurationId() { - return ServerPacketIdentifier.CONFIGURATION_UPDATE_ENABLED_FEATURES; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java index 99d0dd22f..181d92d7d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -29,8 +28,4 @@ public record EncryptionRequestPacket( writer.write(BOOLEAN, shouldAuthenticate); } - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_ENCRYPTION_REQUEST; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java index 87ad70bef..8b6f5926a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.login; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -23,11 +22,6 @@ public record LoginDisconnectPacket(@NotNull Component kickMessage) implements S writer.write(JSON_COMPONENT, kickMessage); } - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_DISCONNECT; - } - @Override public @NotNull Collection components() { return List.of(this.kickMessage); diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java index 2228a80e4..9daf69e9e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -24,8 +23,4 @@ public record LoginPluginRequestPacket(int messageId, @NotNull String channel, } } - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_PLUGIN_REQUEST; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java index 6b645b830..1549818e9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -23,8 +22,4 @@ public record LoginSuccessPacket(@NotNull UUID uuid, @NotNull String username, writer.write(BOOLEAN, strictErrorHandling); } - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_SUCCESS; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java index 11ac1eb0d..4d09af3f4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record SetCompressionPacket(int threshold) implements ServerPacket.Login writer.write(VAR_INT, threshold); } - @Override - public int loginId() { - return ServerPacketIdentifier.LOGIN_SET_COMPRESSION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java index 66c226b8e..f317d29c4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record AcknowledgeBlockChangePacket(int sequence) implements ServerPacket writer.write(VAR_INT, sequence); } - @Override - public int playId() { - return ServerPacketIdentifier.ACKNOWLEDGE_BLOCK_CHANGE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java index 72923a0ae..262ba5f13 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -22,11 +21,6 @@ public record ActionBarPacket(@NotNull Component text) implements ServerPacket.P writer.write(COMPONENT, text); } - @Override - public int playId() { - return ServerPacketIdentifier.ACTION_BAR; - } - @Override public @NotNull Collection components() { return List.of(this.text); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java index 1461344f4..e102063fe 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java @@ -6,7 +6,6 @@ import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,11 +42,6 @@ public record AdvancementsPacket(boolean reset, @NotNull List components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java index ea9e199ae..b8264ad29 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; @@ -18,8 +17,4 @@ public record AttachEntityPacket(int attachedEntityId, int holdingEntityId) impl writer.write(INT, holdingEntityId); } - @Override - public int playId() { - return ServerPacketIdentifier.ATTACH_ENTITY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java index 947709d75..7252b296a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java @@ -4,7 +4,6 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -28,8 +27,4 @@ public record BlockActionPacket(@NotNull Point blockPosition, byte actionId, writer.write(VAR_INT, blockId); } - @Override - public int playId() { - return ServerPacketIdentifier.BLOCK_ACTION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java index a1adbc383..698efd752 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -21,8 +20,4 @@ public record BlockBreakAnimationPacket(int entityId, @NotNull Point blockPositi writer.write(BYTE, destroyStage); } - @Override - public int playId() { - return ServerPacketIdentifier.BLOCK_BREAK_ANIMATION; - } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java index 40ff8820b..d613263ae 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java @@ -4,7 +4,6 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; @@ -25,8 +24,4 @@ public record BlockChangePacket(@NotNull Point blockPosition, int blockStateId) writer.write(VAR_INT, blockStateId); } - @Override - public int playId() { - return ServerPacketIdentifier.BLOCK_CHANGE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java index e990226a7..a648e8cda 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java @@ -4,7 +4,6 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,8 +27,4 @@ public record BlockEntityDataPacket(@NotNull Point blockPosition, int action, } } - @Override - public int playId() { - return ServerPacketIdentifier.BLOCK_ENTITY_DATA; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java index cd2fc9f11..14d9ed884 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java @@ -5,9 +5,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -198,8 +196,4 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen } } - @Override - public int playId() { - return ServerPacketIdentifier.BOSS_BAR; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java index 2d0cdc08f..610db7755 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record BundlePacket() implements ServerPacket.Play { @@ -14,8 +13,4 @@ public record BundlePacket() implements ServerPacket.Play { public void write(@NotNull NetworkBuffer writer) { } - @Override - public int playId() { - return ServerPacketIdentifier.BUNDLE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java index fae30a2b4..1d220e236 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record CameraPacket(int cameraId) implements ServerPacket.Play { writer.write(VAR_INT, cameraId); } - @Override - public int playId() { - return ServerPacketIdentifier.CAMERA; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java index 3f7e29886..11be16242 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,11 +18,6 @@ public record ChangeGameStatePacket(@NotNull Reason reason, float value) impleme writer.write(FLOAT, value); } - @Override - public int playId() { - return ServerPacketIdentifier.CHANGE_GAME_STATE; - } - public enum Reason { NO_RESPAWN_BLOCK, END_RAINING, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java index e6399e600..d5db4070b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record ChunkBatchFinishedPacket(int batchSize) implements ServerPacket.Pl writer.write(VAR_INT, batchSize); } - @Override - public int playId() { - return ServerPacketIdentifier.CHUNK_BATCH_FINISHED; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java index b77ef15b6..d93e4a758 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record ChunkBatchStartPacket() implements ServerPacket.Play { @@ -14,8 +13,4 @@ public record ChunkBatchStartPacket() implements ServerPacket.Play { public void write(@NotNull NetworkBuffer writer) { } - @Override - public int playId() { - return ServerPacketIdentifier.CHUNK_BATCH_START; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index 30a2f1e91..2fcbf77bd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.play.data.ChunkData; import net.minestom.server.network.packet.server.play.data.LightData; import org.jetbrains.annotations.NotNull; @@ -26,8 +25,4 @@ public record ChunkDataPacket(int chunkX, int chunkZ, writer.write(lightData); } - @Override - public int playId() { - return ServerPacketIdentifier.CHUNK_DATA; - } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java index 36e3f15a7..366418444 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; @@ -17,8 +16,4 @@ public record ClearTitlesPacket(boolean reset) implements ServerPacket.Play { writer.write(BOOLEAN, reset); } - @Override - public int playId() { - return ServerPacketIdentifier.CLEAR_TITLES; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java index b7b458181..ee3a858c6 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -17,8 +16,4 @@ public record CloseWindowPacket(byte windowId) implements ServerPacket.Play { writer.write(BYTE, windowId); } - @Override - public int playId() { - return ServerPacketIdentifier.CLOSE_WINDOW; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java index 67213c8f8..acec0725b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -20,8 +19,4 @@ public record CollectItemPacket(int collectedEntityId, int collectorEntityId, in writer.write(VAR_INT, pickupItemCount); } - @Override - public int playId() { - return ServerPacketIdentifier.COLLECT_ITEM; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java b/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java index a65cb3749..24c7fbd5a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,8 +18,4 @@ public record CraftRecipeResponse(byte windowId, String recipe) implements Serve writer.write(STRING, recipe); } - @Override - public int playId() { - return ServerPacketIdentifier.CRAFT_RECIPE_RESPONSE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java index 9f6504ece..df748a0cf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -27,11 +26,6 @@ public record CustomChatCompletionPacket(@NotNull Action action, writer.writeCollection(STRING, entries); } - @Override - public int playId() { - return ServerPacketIdentifier.CUSTOM_CHAT_COMPLETIONS; - } - public enum Action { ADD, REMOVE, SET } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java index da5bace3d..e1a01b6ed 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,11 +25,6 @@ public record DamageEventPacket(int targetEntityId, int damageTypeId, int source this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readOptional(VECTOR3D)); } - @Override - public int playId() { - return ServerPacketIdentifier.DAMAGE_EVENT; - } - @Override public void write(@NotNull NetworkBuffer writer) { writer.write(VAR_INT, targetEntityId); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java index 18fc906c5..0b9cbda06 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java @@ -2,16 +2,15 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; import java.util.function.UnaryOperator; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.COMPONENT; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record DeathCombatEventPacket(int playerId, @NotNull Component message) implements ServerPacket.Play, ServerPacket.ComponentHolding { public DeathCombatEventPacket(@NotNull NetworkBuffer reader) { @@ -24,11 +23,6 @@ public record DeathCombatEventPacket(int playerId, @NotNull Component message) i writer.write(COMPONENT, message); } - @Override - public int playId() { - return ServerPacketIdentifier.DEATH_COMBAT_EVENT; - } - @Override public @NotNull Collection components() { return List.of(this.message); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java index 4d70d0185..d361b9191 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record DebugSamplePacket(long @NotNull [] sample, @NotNull Type type) implements ServerPacket.Play { @@ -17,11 +16,6 @@ public record DebugSamplePacket(long @NotNull [] sample, @NotNull Type type) imp writer.writeEnum(Type.class, type); } - @Override - public int playId() { - return ServerPacketIdentifier.DEBUG_SAMPLE; - } - public enum Type { TICK_TIME } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java index 6ded2f005..f7d78e4b2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.registry.StaticProtocolObject; import org.jetbrains.annotations.NotNull; @@ -34,11 +33,6 @@ public record DeclareCommandsPacket(@NotNull List nodes, writer.write(VAR_INT, rootIndex); } - @Override - public int playId() { - return ServerPacketIdentifier.DECLARE_COMMANDS; - } - public static final class Node implements NetworkBuffer.Writer { public byte flags; public int[] children = new int[0]; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java index f4bbae3dd..557237d02 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeSerializers; import org.jetbrains.annotations.NotNull; @@ -25,8 +24,4 @@ public record DeclareRecipesPacket(@NotNull List recipes) implements Ser writer.writeCollection(RecipeSerializers.RECIPE, recipes); } - @Override - public int playId() { - return ServerPacketIdentifier.DECLARE_RECIPES; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java index 692420de1..0edaf70b1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.crypto.MessageSignature; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record DeleteChatPacket(@NotNull MessageSignature signature) implements ServerPacket.Play { @@ -16,8 +15,4 @@ public record DeleteChatPacket(@NotNull MessageSignature signature) implements S writer.write(signature); } - @Override - public int playId() { - return ServerPacketIdentifier.DELETE_CHAT_MESSAGE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java index 322b88704..66914fe90 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -29,8 +28,4 @@ public record DestroyEntitiesPacket(@NotNull List entityIds) implements writer.writeCollection(VAR_INT, entityIds); } - @Override - public int playId() { - return ServerPacketIdentifier.DESTROY_ENTITIES; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java index e90c8f5fa..dc73fbddd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,8 +18,4 @@ public record DisplayScoreboardPacket(byte position, String scoreName) implement writer.write(STRING, scoreName); } - @Override - public int playId() { - return ServerPacketIdentifier.DISPLAY_SCOREBOARD; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java index c4c912912..7cd747ead 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -22,8 +21,4 @@ public record EffectPacket(int effectId, Point position, int data, writer.write(BOOLEAN, disableRelativeVolume); } - @Override - public int playId() { - return ServerPacketIdentifier.EFFECT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java index b56dd5a59..b24b08679 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record EndCombatEventPacket(int duration) implements ServerPacket.Play { writer.write(VAR_INT, duration); } - @Override - public int playId() { - return ServerPacketIdentifier.END_COMBAT_EVENT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java index 652247fcc..d4b66b046 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record EnterCombatEventPacket() implements ServerPacket.Play { @@ -15,8 +14,4 @@ public record EnterCombatEventPacket() implements ServerPacket.Play { // Empty } - @Override - public int playId() { - return ServerPacketIdentifier.ENTER_COMBAT_EVENT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java index 7949fa04b..50cf1f5bd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,11 +18,6 @@ public record EntityAnimationPacket(int entityId, @NotNull Animation animation) writer.write(BYTE, (byte) animation.ordinal()); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_ANIMATION; - } - public enum Animation { SWING_MAIN_ARM, TAKE_DAMAGE, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java index 3024a943e..51846fe8e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.potion.Potion; import org.jetbrains.annotations.NotNull; @@ -19,8 +18,4 @@ public record EntityEffectPacket(int entityId, @NotNull Potion potion) implement writer.write(potion); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_EFFECT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java index a46d13d77..c2eb5170c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java @@ -6,7 +6,6 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -44,11 +43,6 @@ public record EntityEquipmentPacket(int entityId, } } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_EQUIPMENT; - } - @Override public @NotNull Collection components() { return this.equipments.values() diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java index 6e0ec3f52..d7fb70afc 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,8 +18,4 @@ public record EntityHeadLookPacket(int entityId, float yaw) implements ServerPac writer.write(BYTE, (byte) (this.yaw * 256 / 360)); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_HEAD_LOOK; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java index 6dbc825a0..b258bddfe 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java @@ -4,7 +4,6 @@ import net.kyori.adventure.text.Component; import net.minestom.server.entity.Metadata; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -48,11 +47,6 @@ public record EntityMetaDataPacket(int entityId, return entries; } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_METADATA; - } - @Override public @NotNull Collection components() { return this.entries.values() diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java index 87858321e..461235e7f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -26,11 +25,6 @@ public record EntityPositionAndRotationPacket(int entityId, short deltaX, short writer.write(BOOLEAN, onGround); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_POSITION_AND_ROTATION; - } - public static EntityPositionAndRotationPacket getPacket(int entityId, @NotNull Pos newPosition, @NotNull Pos oldPosition, boolean onGround) { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java index ff3e63003..6dbb6fd9b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -24,11 +23,6 @@ public record EntityPositionPacket(int entityId, short deltaX, short deltaY, sho writer.write(BOOLEAN, onGround); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_POSITION; - } - @NotNull public static EntityPositionPacket getPacket(int entityId, @NotNull Pos newPosition, @NotNull Pos oldPosition, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java index c4cb98a1f..4893818ba 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -20,8 +19,4 @@ public record EntityRotationPacket(int entityId, float yaw, float pitch, boolean writer.write(BOOLEAN, onGround); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_ROTATION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java index ed384771a..a936c757c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java @@ -4,7 +4,6 @@ import net.kyori.adventure.sound.Sound; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; @@ -38,8 +37,4 @@ public record EntitySoundEffectPacket( writer.write(LONG, seed); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_SOUND_EFFECT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java index f1ea56491..a976ba7c4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -19,8 +18,4 @@ public record EntityStatusPacket(int entityId, byte status) implements ServerPac writer.write(BYTE, status); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_STATUS; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java index c22e323f6..9b3b2b40b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -26,8 +25,4 @@ public record EntityTeleportPacket(int entityId, Pos position, boolean onGround) writer.write(BOOLEAN, onGround); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_TELEPORT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java index 1590d1046..2415b3286 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.MathUtils; import org.jetbrains.annotations.NotNull; @@ -33,8 +32,4 @@ public record EntityVelocityPacket(int entityId, short velocityX, short velocity writer.write(SHORT, velocityZ); } - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_VELOCITY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java index 4b5dbb42d..405c7a83c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.particle.Particle; import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.binary.BinaryWriter; @@ -103,11 +102,6 @@ public record ExplosionPacket(double x, double y, double z, float radius, writer.write(SoundEvent.NETWORK_TYPE, sound); } - @Override - public int playId() { - return ServerPacketIdentifier.EXPLOSION; - } - public enum BlockInteraction { KEEP, DESTROY, DESTROY_WITH_DECAY, TRIGGER_BLOCK } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java index edc478175..80e040d02 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java @@ -4,7 +4,6 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -32,11 +31,6 @@ public record FacePlayerPacket(FacePosition facePosition, } } - @Override - public int playId() { - return ServerPacketIdentifier.FACE_PLAYER; - } - public enum FacePosition { FEET, EYES } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java index 39217b309..26d237583 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -17,8 +16,4 @@ public record HeldItemChangePacket(byte slot) implements ServerPacket.Play { writer.write(BYTE, slot); } - @Override - public int playId() { - return ServerPacketIdentifier.HELD_ITEM_CHANGE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java index bb1bcd92c..1d8d21a9f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; @@ -20,8 +19,4 @@ public record HitAnimationPacket(int entityId, float yaw) implements ServerPacke writer.write(FLOAT, yaw); } - @Override - public int playId() { - return ServerPacketIdentifier.HIT_ANIMATION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java index 51754412b..78e801537 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -29,8 +28,4 @@ public record InitializeWorldBorderPacket(double x, double z, writer.write(VAR_INT, warningBlocks); } - @Override - public int playId() { - return ServerPacketIdentifier.INITIALIZE_WORLD_BORDER; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java index b9811bab4..3295888a0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.play.data.WorldPos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,11 +76,6 @@ public record JoinGamePacket( writer.write(BOOLEAN, enforcesSecureChat); } - @Override - public int playId() { - return ServerPacketIdentifier.JOIN_GAME; - } - /** * This method exists in lieu of a NetworkBufferType since -1 is only a * valid value in this packet and changing behaviour of GameMode.fromId() diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java index 1cc52751e..483aa01eb 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,11 +61,6 @@ public record MapDataPacket(int mapId, byte scale, boolean locked, } } - @Override - public int playId() { - return ServerPacketIdentifier.MAP_DATA; - } - public record Icon(int type, byte x, byte z, byte direction, @Nullable Component displayName) implements NetworkBuffer.Writer { public Icon(@NotNull NetworkBuffer reader) { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java index 5e3d4f327..c05dbdac7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java @@ -2,10 +2,10 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.LONG; +import static net.minestom.server.network.NetworkBuffer.VAR_LONG_ARRAY; public record MultiBlockChangePacket(long chunkSectionPosition, long[] blocks) implements ServerPacket.Play { public MultiBlockChangePacket(int chunkX, int section, int chunkZ, @@ -23,8 +23,4 @@ public record MultiBlockChangePacket(long chunkSectionPosition, long[] blocks) i writer.write(VAR_LONG_ARRAY, blocks); } - @Override - public int playId() { - return ServerPacketIdentifier.MULTI_BLOCK_CHANGE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java index d48187ec2..ffb12682c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java @@ -1,10 +1,8 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.minestom.server.network.ConnectionState; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -25,8 +23,4 @@ public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) } } - @Override - public int playId() { - return ServerPacketIdentifier.NBT_QUERY_RESPONSE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java index 812cecec9..386d9a9ea 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record OpenBookPacket(@NotNull PlayerHand hand) implements ServerPacket.Play { @@ -16,8 +15,4 @@ public record OpenBookPacket(@NotNull PlayerHand hand) implements ServerPacket.P writer.writeEnum(PlayerHand.class, hand); } - @Override - public int playId() { - return ServerPacketIdentifier.OPEN_BOOK; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java index 2b524a991..6a7ea5536 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -19,8 +18,4 @@ public record OpenHorseWindowPacket(byte windowId, int slotCount, int entityId) writer.write(INT, entityId); } - @Override - public int playId() { - return ServerPacketIdentifier.OPEN_HORSE_WINDOW; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java index 7fdd341d0..c35971125 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; @@ -20,8 +19,4 @@ public record OpenSignEditorPacket(@NotNull Point position, boolean isFrontText) writer.write(BOOLEAN, isFrontText); } - @Override - public int playId() { - return ServerPacketIdentifier.OPEN_SIGN_EDITOR; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java index dcada15dd..0a3419b3c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -27,11 +25,6 @@ public record OpenWindowPacket(int windowId, int windowType, writer.write(COMPONENT, title); } - @Override - public int playId() { - return ServerPacketIdentifier.OPEN_WINDOW; - } - @Override public @NotNull Collection components() { return List.of(this.title); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java index efb2a8442..bc5a048e2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.particle.Particle; import org.jetbrains.annotations.NotNull; @@ -64,8 +63,4 @@ public record ParticlePacket(@NotNull Particle particle, boolean longDistance, d particle.writeData(writer); } - @Override - public int playId() { - return ServerPacketIdentifier.PARTICLE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java index 6ec615185..2669abc5d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -25,8 +24,4 @@ public record PlayerAbilitiesPacket(byte flags, float flyingSpeed, float walking writer.write(FLOAT, walkingSpeed); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_ABILITIES; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java index d193e4db4..138149192 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java @@ -4,9 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.crypto.FilterMask; import net.minestom.server.crypto.SignedMessageBody; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,11 +45,6 @@ public record PlayerChatMessagePacket(UUID sender, int index, byte @Nullable [] writer.writeOptional(COMPONENT, msgTypeTarget); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_CHAT; - } - @Override public @NotNull Collection components() { final ArrayList list = new ArrayList<>(); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java index 61a7246d8..02368bfcf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -28,8 +27,4 @@ public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) impleme writer.writeCollection(NetworkBuffer.UUID, uuids); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_INFO_REMOVE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java index 7b8132a96..47d5043ba 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java @@ -5,7 +5,6 @@ import net.minestom.server.crypto.ChatSession; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.player.GameProfile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -72,11 +71,6 @@ public final class PlayerInfoUpdatePacket implements ServerPacket.Play { }); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_INFO_UPDATE; - } - public @NotNull EnumSet actions() { return actions; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java index 298ace319..2ab94be03 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -35,8 +33,4 @@ public record PlayerListHeaderAndFooterPacket(@NotNull Component header, return new PlayerListHeaderAndFooterPacket(operator.apply(header), operator.apply(footer)); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_LIST_HEADER_AND_FOOTER; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java index 616ccf927..e38abe05c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -27,8 +26,4 @@ public record PlayerPositionAndLookPacket(Pos position, byte flags, int teleport writer.write(VAR_INT, teleportId); } - @Override - public int playId() { - return ServerPacketIdentifier.PLAYER_POSITION_AND_LOOK; - } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java index 262a8d7de..a1ba5e331 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record ProjectilePowerPacket( @@ -19,9 +18,4 @@ public record ProjectilePowerPacket( writer.write(NetworkBuffer.DOUBLE, accelerationPower); } - @Override - public int playId() { - return ServerPacketIdentifier.PROJECTILE_POWER; - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java index f95257b28..275e3ced5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.potion.PotionEffect; import org.jetbrains.annotations.NotNull; @@ -21,8 +20,4 @@ public record RemoveEntityEffectPacket(int entityId, @NotNull PotionEffect potio writer.write(VAR_INT, potionEffect.id()); } - @Override - public int playId() { - return ServerPacketIdentifier.REMOVE_ENTITY_EFFECT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java index 718930042..a7719cfa9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,8 +19,4 @@ public record ResetScorePacket(@NotNull String owner, @Nullable String objective writer.writeOptional(STRING, objective); } - @Override - public int playId() { - return ServerPacketIdentifier.RESET_SCORE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java index 2c96d1c3c..58faef789 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.play.data.WorldPos; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,8 +43,4 @@ public record RespawnPacket( writer.write(BYTE, (byte) copyData); } - @Override - public int playId() { - return ServerPacketIdentifier.RESPAWN; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java index 18e8289b1..24746f5bd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.scoreboard.Sidebar; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,11 +52,6 @@ public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode } } - @Override - public int playId() { - return ServerPacketIdentifier.SCOREBOARD_OBJECTIVE; - } - @Override public @NotNull Collection components() { return mode == 0 || mode == 2 ? List.of(objectiveValue) : diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java index 747c792b8..f84f6a55e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,8 +17,4 @@ public record SelectAdvancementTabPacket(@Nullable String identifier) implements writer.writeOptional(STRING, identifier); } - @Override - public int playId() { - return ServerPacketIdentifier.SELECT_ADVANCEMENT_TAB; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java index 3f9db24ca..22097b1ef 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,8 +22,4 @@ public record ServerDataPacket(@Nullable Component motd, byte @Nullable [] iconB writer.write(BOOLEAN, enforcesSecureChat); } - @Override - public int playId() { - return ServerPacketIdentifier.SERVER_DATA; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java index 194995b63..a2465b0be 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.world.Difficulty; import org.jetbrains.annotations.NotNull; @@ -19,8 +18,4 @@ public record ServerDifficultyPacket(@NotNull Difficulty difficulty, boolean loc writer.write(BOOLEAN, locked); } - @Override - public int playId() { - return ServerPacketIdentifier.SERVER_DIFFICULTY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java index ca88551cf..b42cfb52c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -18,8 +17,4 @@ public record SetCooldownPacket(int itemId, int cooldownTicks) implements Server writer.write(VAR_INT, cooldownTicks); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_COOLDOWN; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java index 8cd7c3dd2..74e35c7e0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; @@ -20,8 +19,4 @@ public record SetExperiencePacket(float percentage, int level, int totalExperien writer.write(VAR_INT, totalExperience); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_EXPERIENCE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java index f95a973bd..940fad25d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -27,8 +26,4 @@ public record SetPassengersPacket(int vehicleEntityId, writer.writeCollection(VAR_INT, passengersId); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_PASSENGERS; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java index bf200a91a..583cce95e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java @@ -5,7 +5,6 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -30,11 +29,6 @@ public record SetSlotPacket(byte windowId, int stateId, short slot, writer.write(ItemStack.NETWORK_TYPE, itemStack); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_SLOT; - } - @Override public @NotNull Collection components() { final var components = new ArrayList<>(this.itemStack.get(ItemComponent.LORE, List.of())); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java index b080b61c4..c68d7765d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java @@ -2,10 +2,10 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.FLOAT; public record SetTickStatePacket(float tickRate, boolean isFrozen) implements ServerPacket.Play { @@ -19,8 +19,4 @@ public record SetTickStatePacket(float tickRate, boolean isFrozen) implements Se writer.write(BOOLEAN, isFrozen); } - @Override - public int playId() { - return ServerPacketIdentifier.TICK_STATE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java index 5657f37e0..5907c6170 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -23,11 +21,6 @@ public record SetTitleSubTitlePacket(@NotNull Component subtitle) implements Ser writer.write(COMPONENT, subtitle); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_TITLE_SUBTITLE; - } - @Override public @NotNull Collection components() { return List.of(this.subtitle); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java index fcd312794..d244d7dbb 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -23,11 +21,6 @@ public record SetTitleTextPacket(@NotNull Component title) implements ServerPack writer.write(COMPONENT, title); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_TITLE_TEXT; - } - @Override public @NotNull Collection components() { return List.of(this.title); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java index c9eacdd00..400bd2dd8 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; @@ -19,8 +18,4 @@ public record SetTitleTimePacket(int fadeIn, int stay, int fadeOut) implements S writer.write(INT, fadeOut); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_TITLE_TIME; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java index 488872888..e11765852 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java @@ -5,7 +5,6 @@ import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; @@ -50,8 +49,4 @@ public record SoundEffectPacket( writer.write(LONG, seed); } - @Override - public int playId() { - return ServerPacketIdentifier.SOUND_EFFECT; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java index ac70d9d48..af5e738ef 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -41,8 +40,4 @@ public record SpawnEntityPacket(int entityId, @NotNull UUID uuid, int type, writer.write(SHORT, velocityZ); } - @Override - public int playId() { - return ServerPacketIdentifier.SPAWN_ENTITY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java index 764b12a5e..bbbee7f1f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -24,8 +23,4 @@ public record SpawnExperienceOrbPacket(int entityId, writer.write(SHORT, expCount); } - @Override - public int playId() { - return ServerPacketIdentifier.SPAWN_EXPERIENCE_ORB; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java index 119463f59..c3a0e06ff 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; @@ -20,8 +19,4 @@ public record SpawnPositionPacket(@NotNull Point position, float angle) implemen writer.write(FLOAT, angle); } - @Override - public int playId() { - return ServerPacketIdentifier.SPAWN_POSITION; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java index d48551863..2418edf2f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; public record StartConfigurationPacket() implements ServerPacket.Play { @@ -14,9 +13,4 @@ public record StartConfigurationPacket() implements ServerPacket.Play { public void write(@NotNull NetworkBuffer writer) { } - @Override - public int playId() { - return ServerPacketIdentifier.START_CONFIGURATION_PACKET; - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java index 1a34e326a..76d7098dd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.statistic.StatisticCategory; import org.jetbrains.annotations.NotNull; @@ -26,11 +25,6 @@ public record StatisticsPacket(@NotNull List statistics) implements S writer.writeCollection(statistics); } - @Override - public int playId() { - return ServerPacketIdentifier.STATISTICS; - } - public record Statistic(@NotNull StatisticCategory category, int statisticId, int value) implements NetworkBuffer.Writer { public Statistic(@NotNull NetworkBuffer reader) { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java index b4c219645..5467a3fc5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java @@ -4,7 +4,6 @@ import net.kyori.adventure.sound.Sound; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,8 +39,4 @@ public record StopSoundPacket(byte flags, @Nullable Sound.Source source, } } - @Override - public int playId() { - return ServerPacketIdentifier.STOP_SOUND; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java index 6a86a3f9a..69f214d2e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java @@ -2,9 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -25,11 +23,6 @@ public record SystemChatPacket(@NotNull Component message, boolean overlay) impl writer.write(BOOLEAN, overlay); } - @Override - public int playId() { - return ServerPacketIdentifier.SYSTEM_CHAT; - } - @Override public @NotNull Collection components() { return List.of(message); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java index 39b2e1569..a74814039 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java @@ -3,9 +3,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,11 +34,6 @@ public record TabCompletePacket(int transactionId, int start, int length, writer.writeCollection(matches); } - @Override - public int playId() { - return ServerPacketIdentifier.TAB_COMPLETE; - } - @Override public @NotNull Collection components() { if (matches.isEmpty()) return List.of(); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java index 005655261..b1b47451e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java @@ -5,9 +5,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket.ComponentHolding; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -212,16 +210,6 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke } } - /** - * Gets the identifier of the packet - * - * @return the identifier - */ - @Override - public int playId() { - return ServerPacketIdentifier.TEAMS; - } - /** * An enumeration which representing all visibility states for the name tags */ diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java index 7c654aebb..25d2979b5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -18,8 +17,4 @@ public record TickStepPacket(int steps) implements ServerPacket.Play { writer.write(VAR_INT, steps); } - @Override - public int playId() { - return ServerPacketIdentifier.TICK_STEP; - } } 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 5a77d69f7..f42f85680 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; @@ -18,8 +17,4 @@ public record TimeUpdatePacket(long worldAge, long timeOfDay) implements ServerP writer.write(LONG, timeOfDay); } - @Override - public int playId() { - return ServerPacketIdentifier.TIME_UPDATE; - } } 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 c21acc41b..3334a36a7 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,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -35,11 +34,6 @@ public record TradeListPacket(int windowId, @NotNull List trades, writer.write(BOOLEAN, canRestock); } - @Override - public int playId() { - return ServerPacketIdentifier.TRADE_LIST; - } - public record Trade(ItemStack inputItem1, ItemStack result, ItemStack inputItem2, boolean tradeDisabled, int tradeUsesNumber, int maxTradeUsesNumber, int exp, 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 aa7aa2f3c..e11aeb4e1 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; @@ -23,11 +22,6 @@ public record UnloadChunkPacket(int chunkX, int chunkZ) implements ServerPacket. writer.write(INT, chunkX); } - @Override - public int playId() { - return ServerPacketIdentifier.UNLOAD_CHUNK; - } - private static UnloadChunkPacket read(@NotNull NetworkBuffer reader) { int z = reader.read(INT); int x = reader.read(INT); 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 9a567a2cc..81164fb05 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; @@ -75,8 +74,4 @@ public record UnlockRecipesPacket(int mode, } } - @Override - public int playId() { - 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 cc994074e..4512d1aca 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; @@ -20,8 +19,4 @@ public record UpdateHealthPacket(float health, int food, float foodSaturation) i writer.write(FLOAT, foodSaturation); } - @Override - public int playId() { - 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 3fe41b57e..58074c41d 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.play.data.LightData; import org.jetbrains.annotations.NotNull; @@ -21,8 +20,4 @@ public record UpdateLightPacket(int chunkX, int chunkZ, writer.write(lightData); } - @Override - public int playId() { - 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 00e9f4ea3..2a13400b8 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 @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.scoreboard.Sidebar; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,8 +34,4 @@ public record UpdateScorePacket( writer.writeOptional(numberFormat); } - @Override - public int playId() { - return ServerPacketIdentifier.UPDATE_SCORE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java index 1bfe3408d..92ad62edf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record UpdateSimulationDistancePacket(int simulationDistance) implements writer.write(VAR_INT, simulationDistance); } - @Override - public int playId() { - return ServerPacketIdentifier.SET_SIMULATION_DISTANCE; - } } 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 08f4f7104..a958334cc 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record UpdateViewDistancePacket(int viewDistance) implements ServerPacket writer.write(VAR_INT, viewDistance); } - @Override - public int playId() { - 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 3c3d5f7fc..b060776d6 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -18,8 +17,4 @@ public record UpdateViewPositionPacket(int chunkX, int chunkZ) implements Server writer.write(VAR_INT, chunkZ); } - @Override - public int playId() { - 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 1d7b80dbf..e9b713d7d 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 @@ -3,7 +3,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; @@ -24,8 +23,4 @@ public record VehicleMovePacket(@NotNull Pos position) implements ServerPacket.P writer.write(FLOAT, position.pitch()); } - @Override - public int playId() { - return ServerPacketIdentifier.VEHICLE_MOVE; - } } 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 6c712c510..b3ac10fd0 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 @@ -5,7 +5,6 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -37,11 +36,6 @@ public record WindowItemsPacket(byte windowId, int stateId, @NotNull List components() { final var list = new ArrayList<>(this.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 604c06350..e79640516 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,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; @@ -20,8 +19,4 @@ public record WindowPropertyPacket(byte windowId, short property, short value) i writer.write(SHORT, value); } - @Override - public int playId() { - return ServerPacketIdentifier.WINDOW_PROPERTY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java index 29a197ae1..14562fc25 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; @@ -18,8 +17,4 @@ public record WorldBorderCenterPacket(double x, double z) implements ServerPacke writer.write(DOUBLE, z); } - @Override - public int playId() { - return ServerPacketIdentifier.WORLD_BORDER_CENTER; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java index 776d08ea4..a690e2eac 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; @@ -20,8 +19,4 @@ public record WorldBorderLerpSizePacket(double oldDiameter, double newDiameter, writer.write(VAR_LONG, speed); } - @Override - public int playId() { - return ServerPacketIdentifier.WORLD_BORDER_LERP_SIZE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java index 56a12d34a..3ce678090 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; @@ -17,8 +16,4 @@ public record WorldBorderSizePacket(double diameter) implements ServerPacket.Pla writer.write(DOUBLE, diameter); } - @Override - public int playId() { - return ServerPacketIdentifier.WORLD_BORDER_SIZE; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java index ba2f5cd7f..f1f3c031a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record WorldBorderWarningDelayPacket(int warningTime) implements ServerPa writer.write(VAR_INT, warningTime); } - @Override - public int playId() { - return ServerPacketIdentifier.WORLD_BORDER_WARNING_DELAY; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java index 242d8ef4a..5169986a4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -17,8 +16,4 @@ public record WorldBorderWarningReachPacket(int warningBlocks) implements Server writer.write(VAR_INT, warningBlocks); } - @Override - public int playId() { - return ServerPacketIdentifier.WORLD_BORDER_WARNING_REACH; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java index 93b2a3e82..0be655ba0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.status; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.STRING; @@ -17,8 +16,4 @@ public record ResponsePacket(@NotNull String jsonResponse) implements ServerPack writer.write(STRING, jsonResponse); } - @Override - public int statusId() { - return ServerPacketIdentifier.STATUS_RESPONSE; - } } diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java index 49565b009..0935eb2d7 100644 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketUtils.java @@ -20,6 +20,8 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.PacketRegistry; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.FramedPacket; import net.minestom.server.network.packet.server.SendablePacket; @@ -52,6 +54,9 @@ import java.util.zip.Inflater; public final class PacketUtils { private static final ThreadLocal LOCAL_DEFLATER = ThreadLocal.withInitial(Deflater::new); + + private static final PacketParser.Server SERVER_PACKET_PARSER = new PacketParser.Server(); + // Viewable packets private static final Cache VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); @@ -248,8 +253,9 @@ public final class PacketUtils { @NotNull ByteBuffer buffer, @NotNull ServerPacket packet, boolean compression) { - writeFramedPacket(buffer, packet.getId(state), packet, - compression ? MinecraftServer.getCompressionThreshold() : 0); + PacketRegistry registry = SERVER_PACKET_PARSER.stateRegistry(state); + final int id = registry.packetId(packet.getClass()); + writeFramedPacket(buffer, id, packet, compression ? MinecraftServer.getCompressionThreshold() : 0); } public static void writeFramedPacket(@NotNull ByteBuffer buffer, diff --git a/src/test/java/net/minestom/server/network/SocketWriteTest.java b/src/test/java/net/minestom/server/network/SocketWriteTest.java index bcaadeade..3e8e01dc1 100644 --- a/src/test/java/net/minestom/server/network/SocketWriteTest.java +++ b/src/test/java/net/minestom/server/network/SocketWriteTest.java @@ -22,10 +22,6 @@ public class SocketWriteTest { writer.write(INT, value); } - @Override - public int playId() { - return 1; - } } record CompressiblePacket(String value) implements ServerPacket.Play { @@ -34,10 +30,6 @@ public class SocketWriteTest { writer.write(STRING, value); } - @Override - public int playId() { - return 1; - } } @Test @@ -45,7 +37,7 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false); + PacketUtils.writeFramedPacket(buffer, 1, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -57,8 +49,8 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, false); + PacketUtils.writeFramedPacket(buffer, 1, packet, -1); + PacketUtils.writeFramedPacket(buffer, 1, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -74,7 +66,7 @@ public class SocketWriteTest { var packet = new CompressiblePacket(string); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true); + PacketUtils.writeFramedPacket(buffer, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + payload // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -86,7 +78,7 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true); + PacketUtils.writeFramedPacket(buffer, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -98,8 +90,8 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true); - PacketUtils.writeFramedPacket(ConnectionState.PLAY, buffer, packet, true); + PacketUtils.writeFramedPacket(buffer, 1, packet, 256); + PacketUtils.writeFramedPacket(buffer, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future From 00ca682d0521b6e5c0ba3b26fa10a2e25d308994 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 24 Jul 2024 19:20:55 +0200 Subject: [PATCH 08/97] Compress packet serializers (#2289) * WIP packet template serializers * More packets * More packets * More packets * No more packets * rename to buffer * less generic mess * review stuff * Fix ClientResourcePackStatusPacket enum * Update UpdateEnabledFeaturesPacket --- .../net/minestom/server/entity/GameMode.java | 15 + .../net/minestom/server/entity/Player.java | 6 +- .../server/network/NetworkBuffer.java | 7 + .../server/network/NetworkBufferTemplate.java | 94 ++++ .../server/network/NetworkBufferTypeImpl.java | 40 +- .../server/network/packet/PacketRegistry.java | 481 +++++++++--------- .../network/packet/client/ClientPacket.java | 4 +- .../common/ClientCookieResponsePacket.java | 24 +- .../client/common/ClientKeepAlivePacket.java | 12 +- .../common/ClientPingRequestPacket.java | 12 +- .../common/ClientPluginMessagePacket.java | 16 +- .../client/common/ClientPongPacket.java | 12 +- .../ClientResourcePackStatusPacket.java | 32 +- .../client/common/ClientSettingsPacket.java | 31 +- .../ClientFinishConfigurationPacket.java | 12 +- .../ClientSelectKnownPacksPacket.java | 15 +- .../handshake/ClientHandshakePacket.java | 42 +- .../login/ClientEncryptionResponsePacket.java | 16 +- .../login/ClientLoginAcknowledgedPacket.java | 12 +- .../ClientLoginPluginResponsePacket.java | 20 +- .../client/login/ClientLoginStartPacket.java | 19 +- .../play/ClientAdvancementTabPacket.java | 44 +- .../client/play/ClientAnimationPacket.java | 12 +- .../client/play/ClientChatAckPacket.java | 13 +- .../client/play/ClientChatMessagePacket.java | 32 +- .../play/ClientChatSessionUpdatePacket.java | 17 +- .../play/ClientChunkBatchReceivedPacket.java | 16 +- .../play/ClientClickWindowButtonPacket.java | 15 +- .../client/play/ClientClickWindowPacket.java | 43 +- .../client/play/ClientCloseWindowPacket.java | 13 +- .../client/play/ClientCommandChatPacket.java | 14 +- .../play/ClientConfigurationAckPacket.java | 10 +- .../client/play/ClientCraftRecipeRequest.java | 18 +- .../ClientCreativeInventoryActionPacket.java | 14 +- .../ClientDebugSampleSubscriptionPacket.java | 13 +- .../client/play/ClientEditBookPacket.java | 19 +- .../client/play/ClientEntityActionPacket.java | 18 +- .../play/ClientGenerateStructurePacket.java | 16 +- .../play/ClientHeldItemChangePacket.java | 13 +- .../play/ClientInteractEntityPacket.java | 34 +- .../client/play/ClientNameItemPacket.java | 14 +- .../client/play/ClientPickItemPacket.java | 13 +- .../play/ClientPlayerAbilitiesPacket.java | 13 +- .../ClientPlayerBlockPlacementPacket.java | 29 +- .../play/ClientPlayerDiggingPacket.java | 26 +- .../client/play/ClientPlayerPacket.java | 13 +- ...ClientPlayerPositionAndRotationPacket.java | 22 +- .../play/ClientPlayerPositionPacket.java | 20 +- .../play/ClientPlayerRotationPacket.java | 17 +- .../play/ClientQueryBlockNbtPacket.java | 14 +- .../play/ClientQueryEntityNbtPacket.java | 15 +- .../client/play/ClientSelectTradePacket.java | 13 +- .../play/ClientSetBeaconEffectPacket.java | 25 +- .../play/ClientSetDisplayedRecipePacket.java | 16 +- .../play/ClientSetRecipeBookStatePacket.java | 16 +- .../play/ClientSignedCommandChatPacket.java | 33 +- .../client/play/ClientSpectatePacket.java | 14 +- .../client/play/ClientStatusPacket.java | 12 +- .../client/play/ClientSteerBoatPacket.java | 15 +- .../client/play/ClientSteerVehiclePacket.java | 17 +- .../client/play/ClientTabCompletePacket.java | 14 +- .../play/ClientTeleportConfirmPacket.java | 13 +- ...lientUpdateCommandBlockMinecartPacket.java | 16 +- .../play/ClientUpdateCommandBlockPacket.java | 19 +- .../client/play/ClientUpdateSignPacket.java | 27 +- .../ClientUpdateStructureBlockPacket.java | 59 ++- .../client/play/ClientUseItemPacket.java | 24 +- .../client/play/ClientVehicleMovePacket.java | 20 +- .../play/ClientWindowSlotStatePacket.java | 18 +- .../status/LegacyServerListPingPacket.java | 13 +- .../client/status/StatusRequestPacket.java | 11 +- .../network/packet/server/ServerPacket.java | 3 +- .../server/common/CookieRequestPacket.java | 16 +- .../server/common/CookieStorePacket.java | 29 +- .../common/CustomReportDetailsPacket.java | 22 +- .../server/common/DisconnectPacket.java | 11 +- .../packet/server/common/KeepAlivePacket.java | 13 +- .../packet/server/common/PingPacket.java | 13 +- .../server/common/PingResponsePacket.java | 14 +- .../server/common/PluginMessagePacket.java | 14 +- .../server/common/ResourcePackPopPacket.java | 14 +- .../server/common/ResourcePackPushPacket.java | 23 +- .../server/common/ServerLinksPacket.java | 14 +- .../packet/server/common/TagsPacket.java | 49 +- .../packet/server/common/TransferPacket.java | 16 +- .../FinishConfigurationPacket.java | 11 +- .../configuration/RegistryDataPacket.java | 33 +- .../server/configuration/ResetChatPacket.java | 13 +- .../configuration/SelectKnownPacksPacket.java | 34 +- .../UpdateEnabledFeaturesPacket.java | 21 +- .../server/login/EncryptionRequestPacket.java | 23 +- .../server/login/LoginDisconnectPacket.java | 12 +- .../login/LoginPluginRequestPacket.java | 23 +- .../server/login/LoginSuccessPacket.java | 19 +- .../server/login/SetCompressionPacket.java | 14 +- .../play/AcknowledgeBlockChangePacket.java | 14 +- .../packet/server/play/ActionBarPacket.java | 12 +- .../server/play/AdvancementsPacket.java | 34 +- .../server/play/AttachEntityPacket.java | 16 +- .../packet/server/play/BlockActionPacket.java | 22 +- .../play/BlockBreakAnimationPacket.java | 17 +- .../packet/server/play/BlockChangePacket.java | 17 +- .../server/play/BlockEntityDataPacket.java | 30 +- .../packet/server/play/BossBarPacket.java | 40 +- .../packet/server/play/BundlePacket.java | 11 +- .../packet/server/play/CameraPacket.java | 14 +- .../server/play/ChangeGameStatePacket.java | 19 +- .../server/play/ChunkBatchFinishedPacket.java | 14 +- .../server/play/ChunkBatchStartPacket.java | 11 +- .../packet/server/play/ChunkDataPacket.java | 28 +- .../packet/server/play/ClearTitlesPacket.java | 14 +- .../packet/server/play/CloseWindowPacket.java | 14 +- .../packet/server/play/CollectItemPacket.java | 18 +- .../server/play/CraftRecipeResponse.java | 16 +- .../play/CustomChatCompletionPacket.java | 16 +- .../packet/server/play/DamageEventPacket.java | 22 +- .../server/play/DeathCombatEventPacket.java | 17 +- .../packet/server/play/DebugSamplePacket.java | 19 +- .../server/play/DeclareCommandsPacket.java | 27 +- .../server/play/DeclareRecipesPacket.java | 15 +- .../packet/server/play/DeleteChatPacket.java | 18 +- .../server/play/DestroyEntitiesPacket.java | 15 +- .../server/play/DisplayScoreboardPacket.java | 16 +- .../packet/server/play/EffectPacket.java | 20 +- .../server/play/EndCombatEventPacket.java | 14 +- .../server/play/EnterCombatEventPacket.java | 12 +- .../server/play/EntityAnimationPacket.java | 19 +- .../server/play/EntityAttributesPacket.java | 23 +- .../server/play/EntityEffectPacket.java | 20 +- .../server/play/EntityEquipmentPacket.java | 33 +- .../server/play/EntityHeadLookPacket.java | 20 +- .../server/play/EntityMetaDataPacket.java | 27 +- .../play/EntityPositionAndRotationPacket.java | 33 +- .../server/play/EntityPositionPacket.java | 21 +- .../server/play/EntityRotationPacket.java | 29 +- .../server/play/EntitySoundEffectPacket.java | 39 +- .../server/play/EntityStatusPacket.java | 16 +- .../server/play/EntityTeleportPacket.java | 34 +- .../server/play/EntityVelocityPacket.java | 20 +- .../packet/server/play/ExplosionPacket.java | 100 ++-- .../packet/server/play/FacePlayerPacket.java | 43 +- .../server/play/HeldItemChangePacket.java | 14 +- .../server/play/HitAnimationPacket.java | 17 +- .../play/InitializeWorldBorderPacket.java | 30 +- .../packet/server/play/JoinGamePacket.java | 102 ++-- .../packet/server/play/MapDataPacket.java | 117 ++--- .../server/play/MultiBlockChangePacket.java | 18 +- .../server/play/NbtQueryResponsePacket.java | 28 +- .../packet/server/play/OpenBookPacket.java | 13 +- .../server/play/OpenHorseWindowPacket.java | 18 +- .../server/play/OpenSignEditorPacket.java | 15 +- .../packet/server/play/OpenWindowPacket.java | 16 +- .../packet/server/play/ParticlePacket.java | 74 ++- .../server/play/PlayerAbilitiesPacket.java | 18 +- .../server/play/PlayerChatMessagePacket.java | 42 +- .../server/play/PlayerInfoRemovePacket.java | 15 +- .../server/play/PlayerInfoUpdatePacket.java | 149 +++--- .../play/PlayerListHeaderAndFooterPacket.java | 15 +- .../play/PlayerPositionAndLookPacket.java | 25 +- .../server/play/ProjectilePowerPacket.java | 20 +- .../server/play/RemoveEntityEffectPacket.java | 20 +- .../packet/server/play/ResetScorePacket.java | 16 +- .../packet/server/play/RespawnPacket.java | 38 +- .../play/ScoreboardObjectivePacket.java | 57 +-- .../play/SelectAdvancementTabPacket.java | 14 +- .../packet/server/play/ServerDataPacket.java | 20 +- .../server/play/ServerDifficultyPacket.java | 16 +- .../packet/server/play/SetCooldownPacket.java | 16 +- .../server/play/SetExperiencePacket.java | 18 +- .../server/play/SetPassengersPacket.java | 17 +- .../packet/server/play/SetSlotPacket.java | 19 +- .../server/play/SetTickStatePacket.java | 17 +- .../server/play/SetTitleSubTitlePacket.java | 15 +- .../server/play/SetTitleTextPacket.java | 12 +- .../server/play/SetTitleTimePacket.java | 18 +- .../packet/server/play/SoundEffectPacket.java | 50 +- .../packet/server/play/SpawnEntityPacket.java | 48 +- .../server/play/SpawnExperienceOrbPacket.java | 24 +- .../server/play/SpawnPositionPacket.java | 15 +- .../server/play/StartConfigurationPacket.java | 11 +- .../packet/server/play/StatisticsPacket.java | 33 +- .../packet/server/play/StopSoundPacket.java | 46 +- .../packet/server/play/SystemChatPacket.java | 17 +- .../packet/server/play/TabCompletePacket.java | 35 +- .../packet/server/play/TeamsPacket.java | 35 +- .../packet/server/play/TickStepPacket.java | 15 +- .../packet/server/play/TimeUpdatePacket.java | 16 +- .../packet/server/play/TradeListPacket.java | 60 +-- .../packet/server/play/UnloadChunkPacket.java | 33 +- .../server/play/UnlockRecipesPacket.java | 85 ++-- .../server/play/UpdateHealthPacket.java | 18 +- .../packet/server/play/UpdateLightPacket.java | 22 +- .../packet/server/play/UpdateScorePacket.java | 28 +- .../play/UpdateSimulationDistancePacket.java | 14 +- .../server/play/UpdateViewDistancePacket.java | 14 +- .../server/play/UpdateViewPositionPacket.java | 16 +- .../packet/server/play/VehicleMovePacket.java | 20 +- .../packet/server/play/WindowItemsPacket.java | 27 +- .../server/play/WindowPropertyPacket.java | 18 +- .../server/play/WorldBorderCenterPacket.java | 16 +- .../play/WorldBorderLerpSizePacket.java | 21 +- .../server/play/WorldBorderSizePacket.java | 14 +- .../play/WorldBorderWarningDelayPacket.java | 14 +- .../play/WorldBorderWarningReachPacket.java | 14 +- .../packet/server/status/ResponsePacket.java | 13 +- .../server/recipe/RecipeSerializers.java | 48 +- .../minestom/server/utils/PacketUtils.java | 15 +- 207 files changed, 2295 insertions(+), 3009 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/GameMode.java b/src/main/java/net/minestom/server/entity/GameMode.java index f85c599a1..983ec78cf 100644 --- a/src/main/java/net/minestom/server/entity/GameMode.java +++ b/src/main/java/net/minestom/server/entity/GameMode.java @@ -1,7 +1,10 @@ package net.minestom.server.entity; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; +import static net.minestom.server.network.NetworkBuffer.BYTE; + /** * Represents the game mode of a player. *

@@ -29,6 +32,18 @@ public enum GameMode { return canTakeDamage; } + public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, GameMode value) { + buffer.write(BYTE, value.id()); + } + + @Override + public GameMode read(@NotNull NetworkBuffer buffer) { + return GameMode.fromId(buffer.read(BYTE)); + } + }; + public static @NotNull GameMode fromId(int id) { return switch (id) { case 0 -> SURVIVAL; diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 8d2b26c41..e1f34666d 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -525,7 +525,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, refreshHealth(); sendPacket(new RespawnPacket(dimensionTypeId, instance.getDimensionName(), 0, gameMode, gameMode, - false, levelFlat, deathLocation, portalCooldown, RespawnPacket.COPY_ALL)); + false, levelFlat, deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL)); refreshClientStateAfterRespawn(); PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this); @@ -1208,7 +1208,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, final PlayerInfoUpdatePacket addPlayerPacket = getAddPlayerToList(); RespawnPacket respawnPacket = new RespawnPacket(dimensionTypeId, instance.getDimensionName(), - 0, gameMode, gameMode, false, levelFlat, deathLocation, portalCooldown, RespawnPacket.COPY_ALL); + 0, gameMode, gameMode, false, levelFlat, deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL); sendPacket(removePlayerPacket); sendPacket(destroyEntitiesPacket); @@ -1658,7 +1658,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, this.dimensionTypeId = DIMENSION_TYPE_REGISTRY.getId(dimensionType); sendPacket(new RespawnPacket(dimensionTypeId, dimensionName, 0, gameMode, gameMode, false, levelFlat, - deathLocation, portalCooldown, RespawnPacket.COPY_ALL)); + deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL)); refreshClientStateAfterRespawn(); } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index 570bc6782..fe0202930 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.EntityPose; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.registry.ProtocolObject; @@ -43,6 +44,7 @@ public final class NetworkBuffer { public static final Type COMPONENT = new ComponentNetworkBufferTypeImpl(); public static final Type JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); public static final Type UUID = new NetworkBufferTypeImpl.UUIDType(); + public static final Type POS = new NetworkBufferTypeImpl.PosType(); public static final Type BYTE_ARRAY = new NetworkBufferTypeImpl.ByteArrayType(); public static final Type LONG_ARRAY = new NetworkBufferTypeImpl.LongArrayType(); @@ -320,6 +322,7 @@ public final class NetworkBuffer { public interface Type { void write(@NotNull NetworkBuffer buffer, T value); + T read(@NotNull NetworkBuffer buffer); default @NotNull Type map(@NotNull Function to, @NotNull Function from) { @@ -329,6 +332,10 @@ public final class NetworkBuffer { default @NotNull Type> list(int maxSize) { return new NetworkBufferTypeImpl.ListType<>(this, maxSize); } + + default @NotNull Type optional() { + return new NetworkBufferTypeImpl.OptionalTypeImpl<>(this); + } } @FunctionalInterface diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java index c5834b449..d6de109a8 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java @@ -4,6 +4,7 @@ import net.minestom.server.network.NetworkBuffer.Type; import org.jetbrains.annotations.NotNull; import java.util.function.Function; +import java.util.function.Supplier; public final class NetworkBufferTemplate { @@ -47,6 +48,29 @@ public final class NetworkBufferTemplate { R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); } + @FunctionalInterface + public interface F9 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9); + } + + @FunctionalInterface + public interface F10 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); + } + + public static Type template(Supplier supplier) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return supplier.get(); + } + }; + } + public static Type template(Type p1, Function g1, F1 reader) { return new NetworkBufferTypeImpl<>() { @Override @@ -237,4 +261,74 @@ public final class NetworkBufferTemplate { } }; } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, F9 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + F10 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer) + ); + } + }; + } } diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java index c8b2ab9ed..66294d8c1 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java @@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.network.packet.server.play.data.WorldPos; import net.minestom.server.registry.DynamicRegistry; @@ -393,6 +394,27 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } + record PosType() implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, Pos value) { + buffer.write(DOUBLE, value.x()); + buffer.write(DOUBLE, value.y()); + buffer.write(DOUBLE, value.z()); + buffer.write(FLOAT, value.yaw()); + buffer.write(FLOAT, value.pitch()); + } + + @Override + public Pos read(@NotNull NetworkBuffer buffer) { + final double x = buffer.read(DOUBLE); + final double y = buffer.read(DOUBLE); + final double z = buffer.read(DOUBLE); + final float yaw = buffer.read(FLOAT); + final float pitch = buffer.read(FLOAT); + return new Pos(x, y, z, yaw, pitch); + } + } + record ByteArrayType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, byte[] value) { @@ -602,7 +624,8 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } - record MappedType(@NotNull Type parent, @NotNull Function to, @NotNull Function from) implements NetworkBufferTypeImpl { + record MappedType(@NotNull Type parent, @NotNull Function to, + @NotNull Function from) implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, S value) { parent.write(buffer, from.apply(value)); @@ -626,7 +649,20 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } - record RegistryTypeType(@NotNull Function> selector) implements NetworkBufferTypeImpl> { + record OptionalTypeImpl(@NotNull Type parent) implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, T value) { + buffer.writeOptional(parent, value); + } + + @Override + public T read(@NotNull NetworkBuffer buffer) { + return buffer.readOptional(parent); + } + } + + record RegistryTypeType( + @NotNull Function> selector) implements NetworkBufferTypeImpl> { @Override public void write(@NotNull NetworkBuffer buffer, DynamicRegistry.Key value) { Check.stateCondition(buffer.registries == null, "Buffer does not have registries"); diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index b6dd6a302..7d265e3c4 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -22,13 +22,17 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; public interface PacketRegistry { - @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader); + @UnknownNullability + T create(int packetId, @NotNull NetworkBuffer reader); - int packetId(@NotNull Class packetClass); + PacketInfo packetInfo(Class packetClass); + + record PacketInfo(Class packetClass, int id, NetworkBuffer.Type serializer) { + } sealed class Client extends PacketRegistryTemplate { @SafeVarargs - Client(Entry... suppliers) { + Client(Entry... suppliers) { super(suppliers); } } @@ -36,7 +40,7 @@ public interface PacketRegistry { final class ClientHandshake extends Client { public ClientHandshake() { super( - entry(ClientHandshakePacket.class, ClientHandshakePacket::new) + entry(ClientHandshakePacket.class, ClientHandshakePacket.SERIALIZER) ); } } @@ -44,8 +48,8 @@ public interface PacketRegistry { final class ClientStatus extends Client { public ClientStatus() { super( - entry(StatusRequestPacket.class, StatusRequestPacket::new), - entry(ClientPingRequestPacket.class, ClientPingRequestPacket::new) + entry(StatusRequestPacket.class, StatusRequestPacket.SERIALIZER), + entry(ClientPingRequestPacket.class, ClientPingRequestPacket.SERIALIZER) ); } } @@ -53,11 +57,11 @@ public interface PacketRegistry { final class ClientLogin extends Client { public ClientLogin() { super( - entry(ClientLoginStartPacket.class, ClientLoginStartPacket::new), - entry(ClientEncryptionResponsePacket.class, ClientEncryptionResponsePacket::new), - entry(ClientLoginPluginResponsePacket.class, ClientLoginPluginResponsePacket::new), - entry(ClientLoginAcknowledgedPacket.class, ClientLoginAcknowledgedPacket::new), - entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new) + entry(ClientLoginStartPacket.class, ClientLoginStartPacket.SERIALIZER), + entry(ClientEncryptionResponsePacket.class, ClientEncryptionResponsePacket.SERIALIZER), + entry(ClientLoginPluginResponsePacket.class, ClientLoginPluginResponsePacket.SERIALIZER), + entry(ClientLoginAcknowledgedPacket.class, ClientLoginAcknowledgedPacket.SERIALIZER), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket.SERIALIZER) ); } } @@ -65,14 +69,14 @@ public interface PacketRegistry { final class ClientConfiguration extends Client { public ClientConfiguration() { super( - entry(ClientSettingsPacket.class, ClientSettingsPacket::new), - entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new), - entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket::new), - entry(ClientFinishConfigurationPacket.class, ClientFinishConfigurationPacket::new), - entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket::new), - entry(ClientPongPacket.class, ClientPongPacket::new), - entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket::new), - entry(ClientSelectKnownPacksPacket.class, ClientSelectKnownPacksPacket::new) + entry(ClientSettingsPacket.class, ClientSettingsPacket.SERIALIZER), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket.SERIALIZER), + entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket.SERIALIZER), + entry(ClientFinishConfigurationPacket.class, ClientFinishConfigurationPacket.SERIALIZER), + entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket.SERIALIZER), + entry(ClientPongPacket.class, ClientPongPacket.SERIALIZER), + entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket.SERIALIZER), + entry(ClientSelectKnownPacksPacket.class, ClientSelectKnownPacksPacket.SERIALIZER) ); } } @@ -80,71 +84,71 @@ public interface PacketRegistry { final class ClientPlay extends Client { public ClientPlay() { super( - entry(ClientTeleportConfirmPacket.class, ClientTeleportConfirmPacket::new), - entry(ClientQueryBlockNbtPacket.class, ClientQueryBlockNbtPacket::new), + entry(ClientTeleportConfirmPacket.class, ClientTeleportConfirmPacket.SERIALIZER), + entry(ClientQueryBlockNbtPacket.class, ClientQueryBlockNbtPacket.SERIALIZER), null, // difficulty packet - entry(ClientChatAckPacket.class, ClientChatAckPacket::new), - entry(ClientCommandChatPacket.class, ClientCommandChatPacket::new), - entry(ClientSignedCommandChatPacket.class, ClientSignedCommandChatPacket::new), - entry(ClientChatMessagePacket.class, ClientChatMessagePacket::new), - entry(ClientChatSessionUpdatePacket.class, ClientChatSessionUpdatePacket::new), - entry(ClientChunkBatchReceivedPacket.class, ClientChunkBatchReceivedPacket::new), - entry(ClientStatusPacket.class, ClientStatusPacket::new), - entry(ClientSettingsPacket.class, ClientSettingsPacket::new), - entry(ClientTabCompletePacket.class, ClientTabCompletePacket::new), - entry(ClientConfigurationAckPacket.class, ClientConfigurationAckPacket::new), - entry(ClientClickWindowButtonPacket.class, ClientClickWindowButtonPacket::new), - entry(ClientClickWindowPacket.class, ClientClickWindowPacket::new), - entry(ClientCloseWindowPacket.class, ClientCloseWindowPacket::new), - entry(ClientWindowSlotStatePacket.class, ClientWindowSlotStatePacket::new), - entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket::new), - entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket::new), - entry(ClientDebugSampleSubscriptionPacket.class, ClientDebugSampleSubscriptionPacket::new), - entry(ClientEditBookPacket.class, ClientEditBookPacket::new), - entry(ClientQueryEntityNbtPacket.class, ClientQueryEntityNbtPacket::new), - entry(ClientInteractEntityPacket.class, ClientInteractEntityPacket::new), - entry(ClientGenerateStructurePacket.class, ClientGenerateStructurePacket::new), - entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket::new), + entry(ClientChatAckPacket.class, ClientChatAckPacket.SERIALIZER), + entry(ClientCommandChatPacket.class, ClientCommandChatPacket.SERIALIZER), + entry(ClientSignedCommandChatPacket.class, ClientSignedCommandChatPacket.SERIALIZER), + entry(ClientChatMessagePacket.class, ClientChatMessagePacket.SERIALIZER), + entry(ClientChatSessionUpdatePacket.class, ClientChatSessionUpdatePacket.SERIALIZER), + entry(ClientChunkBatchReceivedPacket.class, ClientChunkBatchReceivedPacket.SERIALIZER), + entry(ClientStatusPacket.class, ClientStatusPacket.SERIALIZER), + entry(ClientSettingsPacket.class, ClientSettingsPacket.SERIALIZER), + entry(ClientTabCompletePacket.class, ClientTabCompletePacket.SERIALIZER), + entry(ClientConfigurationAckPacket.class, ClientConfigurationAckPacket.SERIALIZER), + entry(ClientClickWindowButtonPacket.class, ClientClickWindowButtonPacket.SERIALIZER), + entry(ClientClickWindowPacket.class, ClientClickWindowPacket.SERIALIZER), + entry(ClientCloseWindowPacket.class, ClientCloseWindowPacket.SERIALIZER), + entry(ClientWindowSlotStatePacket.class, ClientWindowSlotStatePacket.SERIALIZER), + entry(ClientCookieResponsePacket.class, ClientCookieResponsePacket.SERIALIZER), + entry(ClientPluginMessagePacket.class, ClientPluginMessagePacket.SERIALIZER), + entry(ClientDebugSampleSubscriptionPacket.class, ClientDebugSampleSubscriptionPacket.SERIALIZER), + entry(ClientEditBookPacket.class, ClientEditBookPacket.SERIALIZER), + entry(ClientQueryEntityNbtPacket.class, ClientQueryEntityNbtPacket.SERIALIZER), + entry(ClientInteractEntityPacket.class, ClientInteractEntityPacket.SERIALIZER), + entry(ClientGenerateStructurePacket.class, ClientGenerateStructurePacket.SERIALIZER), + entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket.SERIALIZER), null, // lock difficulty - entry(ClientPlayerPositionPacket.class, ClientPlayerPositionPacket::new), - entry(ClientPlayerPositionAndRotationPacket.class, ClientPlayerPositionAndRotationPacket::new), - entry(ClientPlayerRotationPacket.class, ClientPlayerRotationPacket::new), - entry(ClientPlayerPacket.class, ClientPlayerPacket::new), - entry(ClientVehicleMovePacket.class, ClientVehicleMovePacket::new), - entry(ClientSteerBoatPacket.class, ClientSteerBoatPacket::new), - entry(ClientPickItemPacket.class, ClientPickItemPacket::new), - entry(ClientPingRequestPacket.class, ClientPingRequestPacket::new), - entry(ClientCraftRecipeRequest.class, ClientCraftRecipeRequest::new), - entry(ClientPlayerAbilitiesPacket.class, ClientPlayerAbilitiesPacket::new), - entry(ClientPlayerDiggingPacket.class, ClientPlayerDiggingPacket::new), - entry(ClientEntityActionPacket.class, ClientEntityActionPacket::new), - entry(ClientSteerVehiclePacket.class, ClientSteerVehiclePacket::new), - entry(ClientPongPacket.class, ClientPongPacket::new), - entry(ClientSetRecipeBookStatePacket.class, ClientSetRecipeBookStatePacket::new), - entry(ClientSetDisplayedRecipePacket.class, ClientSetDisplayedRecipePacket::new), - entry(ClientNameItemPacket.class, ClientNameItemPacket::new), - entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket::new), - entry(ClientAdvancementTabPacket.class, ClientAdvancementTabPacket::new), - entry(ClientSelectTradePacket.class, ClientSelectTradePacket::new), - entry(ClientSetBeaconEffectPacket.class, ClientSetBeaconEffectPacket::new), - entry(ClientHeldItemChangePacket.class, ClientHeldItemChangePacket::new), - entry(ClientUpdateCommandBlockPacket.class, ClientUpdateCommandBlockPacket::new), - entry(ClientUpdateCommandBlockMinecartPacket.class, ClientUpdateCommandBlockMinecartPacket::new), - entry(ClientCreativeInventoryActionPacket.class, ClientCreativeInventoryActionPacket::new), + entry(ClientPlayerPositionPacket.class, ClientPlayerPositionPacket.SERIALIZER), + entry(ClientPlayerPositionAndRotationPacket.class, ClientPlayerPositionAndRotationPacket.SERIALIZER), + entry(ClientPlayerRotationPacket.class, ClientPlayerRotationPacket.SERIALIZER), + entry(ClientPlayerPacket.class, ClientPlayerPacket.SERIALIZER), + entry(ClientVehicleMovePacket.class, ClientVehicleMovePacket.SERIALIZER), + entry(ClientSteerBoatPacket.class, ClientSteerBoatPacket.SERIALIZER), + entry(ClientPickItemPacket.class, ClientPickItemPacket.SERIALIZER), + entry(ClientPingRequestPacket.class, ClientPingRequestPacket.SERIALIZER), + entry(ClientCraftRecipeRequest.class, ClientCraftRecipeRequest.SERIALIZER), + entry(ClientPlayerAbilitiesPacket.class, ClientPlayerAbilitiesPacket.SERIALIZER), + entry(ClientPlayerDiggingPacket.class, ClientPlayerDiggingPacket.SERIALIZER), + entry(ClientEntityActionPacket.class, ClientEntityActionPacket.SERIALIZER), + entry(ClientSteerVehiclePacket.class, ClientSteerVehiclePacket.SERIALIZER), + entry(ClientPongPacket.class, ClientPongPacket.SERIALIZER), + entry(ClientSetRecipeBookStatePacket.class, ClientSetRecipeBookStatePacket.SERIALIZER), + entry(ClientSetDisplayedRecipePacket.class, ClientSetDisplayedRecipePacket.SERIALIZER), + entry(ClientNameItemPacket.class, ClientNameItemPacket.SERIALIZER), + entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket.SERIALIZER), + entry(ClientAdvancementTabPacket.class, ClientAdvancementTabPacket.SERIALIZER), + entry(ClientSelectTradePacket.class, ClientSelectTradePacket.SERIALIZER), + entry(ClientSetBeaconEffectPacket.class, ClientSetBeaconEffectPacket.SERIALIZER), + entry(ClientHeldItemChangePacket.class, ClientHeldItemChangePacket.SERIALIZER), + entry(ClientUpdateCommandBlockPacket.class, ClientUpdateCommandBlockPacket.SERIALIZER), + entry(ClientUpdateCommandBlockMinecartPacket.class, ClientUpdateCommandBlockMinecartPacket.SERIALIZER), + entry(ClientCreativeInventoryActionPacket.class, ClientCreativeInventoryActionPacket.SERIALIZER), null, // Update Jigsaw Block - entry(ClientUpdateStructureBlockPacket.class, ClientUpdateStructureBlockPacket::new), - entry(ClientUpdateSignPacket.class, ClientUpdateSignPacket::new), - entry(ClientAnimationPacket.class, ClientAnimationPacket::new), - entry(ClientSpectatePacket.class, ClientSpectatePacket::new), - entry(ClientPlayerBlockPlacementPacket.class, ClientPlayerBlockPlacementPacket::new), - entry(ClientUseItemPacket.class, ClientUseItemPacket::new) + entry(ClientUpdateStructureBlockPacket.class, ClientUpdateStructureBlockPacket.SERIALIZER), + entry(ClientUpdateSignPacket.class, ClientUpdateSignPacket.SERIALIZER), + entry(ClientAnimationPacket.class, ClientAnimationPacket.SERIALIZER), + entry(ClientSpectatePacket.class, ClientSpectatePacket.SERIALIZER), + entry(ClientPlayerBlockPlacementPacket.class, ClientPlayerBlockPlacementPacket.SERIALIZER), + entry(ClientUseItemPacket.class, ClientUseItemPacket.SERIALIZER) ); } } sealed class Server extends PacketRegistryTemplate { @SafeVarargs - Server(Entry... suppliers) { + Server(Entry... suppliers) { super(suppliers); } } @@ -158,8 +162,8 @@ public interface PacketRegistry { final class ServerStatus extends Server { public ServerStatus() { super( - entry(ResponsePacket.class, ResponsePacket::new), - entry(PingResponsePacket.class, PingResponsePacket::new) + entry(ResponsePacket.class, ResponsePacket.SERIALIZER), + entry(PingResponsePacket.class, PingResponsePacket.SERIALIZER) ); } } @@ -167,12 +171,12 @@ public interface PacketRegistry { final class ServerLogin extends Server { public ServerLogin() { super( - entry(LoginDisconnectPacket.class, LoginDisconnectPacket::new), - entry(EncryptionRequestPacket.class, EncryptionRequestPacket::new), - entry(LoginSuccessPacket.class, LoginSuccessPacket::new), - entry(SetCompressionPacket.class, SetCompressionPacket::new), - entry(LoginPluginRequestPacket.class, LoginPluginRequestPacket::new), - entry(CookieRequestPacket.class, CookieRequestPacket::new) + entry(LoginDisconnectPacket.class, LoginDisconnectPacket.SERIALIZER), + entry(EncryptionRequestPacket.class, EncryptionRequestPacket.SERIALIZER), + entry(LoginSuccessPacket.class, LoginSuccessPacket.SERIALIZER), + entry(SetCompressionPacket.class, SetCompressionPacket.SERIALIZER), + entry(LoginPluginRequestPacket.class, LoginPluginRequestPacket.SERIALIZER), + entry(CookieRequestPacket.class, CookieRequestPacket.SERIALIZER) ); } } @@ -180,23 +184,23 @@ public interface PacketRegistry { final class ServerConfiguration extends Server { public ServerConfiguration() { super( - entry(CookieRequestPacket.class, CookieRequestPacket::new), - entry(PluginMessagePacket.class, PluginMessagePacket::new), - entry(DisconnectPacket.class, DisconnectPacket::new), - entry(FinishConfigurationPacket.class, FinishConfigurationPacket::new), - entry(KeepAlivePacket.class, KeepAlivePacket::new), - entry(PingPacket.class, PingPacket::new), - entry(ResetChatPacket.class, ResetChatPacket::new), - entry(RegistryDataPacket.class, RegistryDataPacket::new), - entry(ResourcePackPopPacket.class, ResourcePackPopPacket::new), - entry(ResourcePackPushPacket.class, ResourcePackPushPacket::new), - entry(CookieStorePacket.class, CookieStorePacket::new), - entry(TransferPacket.class, TransferPacket::new), - entry(UpdateEnabledFeaturesPacket.class, UpdateEnabledFeaturesPacket::new), - entry(TagsPacket.class, TagsPacket::new), - entry(SelectKnownPacksPacket.class, SelectKnownPacksPacket::new), - entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket::new), - entry(ServerLinksPacket.class, ServerLinksPacket::new) + entry(CookieRequestPacket.class, CookieRequestPacket.SERIALIZER), + entry(PluginMessagePacket.class, PluginMessagePacket.SERIALIZER), + entry(DisconnectPacket.class, DisconnectPacket.SERIALIZER), + entry(FinishConfigurationPacket.class, FinishConfigurationPacket.SERIALIZER), + entry(KeepAlivePacket.class, KeepAlivePacket.SERIALIZER), + entry(PingPacket.class, PingPacket.SERIALIZER), + entry(ResetChatPacket.class, ResetChatPacket.SERIALIZER), + entry(RegistryDataPacket.class, RegistryDataPacket.SERIALIZER), + entry(ResourcePackPopPacket.class, ResourcePackPopPacket.SERIALIZER), + entry(ResourcePackPushPacket.class, ResourcePackPushPacket.SERIALIZER), + entry(CookieStorePacket.class, CookieStorePacket.SERIALIZER), + entry(TransferPacket.class, TransferPacket.SERIALIZER), + entry(UpdateEnabledFeaturesPacket.class, UpdateEnabledFeaturesPacket.SERIALIZER), + entry(TagsPacket.class, TagsPacket.SERIALIZER), + entry(SelectKnownPacksPacket.class, SelectKnownPacksPacket.SERIALIZER), + entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket.SERIALIZER), + entry(ServerLinksPacket.class, ServerLinksPacket.SERIALIZER) ); } } @@ -204,170 +208,177 @@ public interface PacketRegistry { final class ServerPlay extends Server { public ServerPlay() { super( - entry(BundlePacket.class, BundlePacket::new), - entry(SpawnEntityPacket.class, SpawnEntityPacket::new), - entry(SpawnExperienceOrbPacket.class, SpawnExperienceOrbPacket::new), - entry(EntityAnimationPacket.class, EntityAnimationPacket::new), - entry(StatisticsPacket.class, StatisticsPacket::new), - entry(AcknowledgeBlockChangePacket.class, AcknowledgeBlockChangePacket::new), - entry(BlockBreakAnimationPacket.class, BlockBreakAnimationPacket::new), - entry(BlockEntityDataPacket.class, BlockEntityDataPacket::new), - entry(BlockActionPacket.class, BlockActionPacket::new), - entry(BlockChangePacket.class, BlockChangePacket::new), - entry(BossBarPacket.class, BossBarPacket::new), - entry(ServerDifficultyPacket.class, ServerDifficultyPacket::new), - entry(ChunkBatchFinishedPacket.class, ChunkBatchFinishedPacket::new), - entry(ChunkBatchStartPacket.class, ChunkBatchStartPacket::new), + entry(BundlePacket.class, BundlePacket.SERIALIZER), + entry(SpawnEntityPacket.class, SpawnEntityPacket.SERIALIZER), + entry(SpawnExperienceOrbPacket.class, SpawnExperienceOrbPacket.SERIALIZER), + entry(EntityAnimationPacket.class, EntityAnimationPacket.SERIALIZER), + entry(StatisticsPacket.class, StatisticsPacket.SERIALIZER), + entry(AcknowledgeBlockChangePacket.class, AcknowledgeBlockChangePacket.SERIALIZER), + entry(BlockBreakAnimationPacket.class, BlockBreakAnimationPacket.SERIALIZER), + entry(BlockEntityDataPacket.class, BlockEntityDataPacket.SERIALIZER), + entry(BlockActionPacket.class, BlockActionPacket.SERIALIZER), + entry(BlockChangePacket.class, BlockChangePacket.SERIALIZER), + entry(BossBarPacket.class, BossBarPacket.SERIALIZER), + entry(ServerDifficultyPacket.class, ServerDifficultyPacket.SERIALIZER), + entry(ChunkBatchFinishedPacket.class, ChunkBatchFinishedPacket.SERIALIZER), + entry(ChunkBatchStartPacket.class, ChunkBatchStartPacket.SERIALIZER), null, // CHUNK_BIOMES - entry(ClearTitlesPacket.class, ClearTitlesPacket::new), - entry(TabCompletePacket.class, TabCompletePacket::new), - entry(DeclareCommandsPacket.class, DeclareCommandsPacket::new), - entry(CloseWindowPacket.class, CloseWindowPacket::new), - entry(WindowItemsPacket.class, WindowItemsPacket::new), - entry(WindowPropertyPacket.class, WindowPropertyPacket::new), - entry(SetSlotPacket.class, SetSlotPacket::new), - entry(CookieRequestPacket.class, CookieRequestPacket::new), - entry(SetCooldownPacket.class, SetCooldownPacket::new), - entry(CustomChatCompletionPacket.class, CustomChatCompletionPacket::new), - entry(PluginMessagePacket.class, PluginMessagePacket::new), - entry(DamageEventPacket.class, DamageEventPacket::new), - entry(DebugSamplePacket.class, DebugSamplePacket::new), - entry(DeleteChatPacket.class, DeleteChatPacket::new), - entry(DisconnectPacket.class, DisconnectPacket::new), + entry(ClearTitlesPacket.class, ClearTitlesPacket.SERIALIZER), + entry(TabCompletePacket.class, TabCompletePacket.SERIALIZER), + entry(DeclareCommandsPacket.class, DeclareCommandsPacket.SERIALIZER), + entry(CloseWindowPacket.class, CloseWindowPacket.SERIALIZER), + entry(WindowItemsPacket.class, WindowItemsPacket.SERIALIZER), + entry(WindowPropertyPacket.class, WindowPropertyPacket.SERIALIZER), + entry(SetSlotPacket.class, SetSlotPacket.SERIALIZER), + entry(CookieRequestPacket.class, CookieRequestPacket.SERIALIZER), + entry(SetCooldownPacket.class, SetCooldownPacket.SERIALIZER), + entry(CustomChatCompletionPacket.class, CustomChatCompletionPacket.SERIALIZER), + entry(PluginMessagePacket.class, PluginMessagePacket.SERIALIZER), + entry(DamageEventPacket.class, DamageEventPacket.SERIALIZER), + entry(DebugSamplePacket.class, DebugSamplePacket.SERIALIZER), + entry(DeleteChatPacket.class, DeleteChatPacket.SERIALIZER), + entry(DisconnectPacket.class, DisconnectPacket.SERIALIZER), null, // DISGUISED_CHAT - entry(EntityStatusPacket.class, EntityStatusPacket::new), - entry(ExplosionPacket.class, ExplosionPacket::new), - entry(UnloadChunkPacket.class, UnloadChunkPacket::new), - entry(ChangeGameStatePacket.class, ChangeGameStatePacket::new), - entry(OpenHorseWindowPacket.class, OpenHorseWindowPacket::new), - entry(HitAnimationPacket.class, HitAnimationPacket::new), - entry(InitializeWorldBorderPacket.class, InitializeWorldBorderPacket::new), - entry(KeepAlivePacket.class, KeepAlivePacket::new), - entry(ChunkDataPacket.class, ChunkDataPacket::new), - entry(EffectPacket.class, EffectPacket::new), - entry(ParticlePacket.class, ParticlePacket::new), - entry(UpdateLightPacket.class, UpdateLightPacket::new), - entry(JoinGamePacket.class, JoinGamePacket::new), - entry(MapDataPacket.class, MapDataPacket::new), - entry(TradeListPacket.class, TradeListPacket::new), - entry(EntityPositionPacket.class, EntityPositionPacket::new), - entry(EntityPositionAndRotationPacket.class, EntityPositionAndRotationPacket::new), - entry(EntityRotationPacket.class, EntityRotationPacket::new), - entry(VehicleMovePacket.class, VehicleMovePacket::new), - entry(OpenBookPacket.class, OpenBookPacket::new), - entry(OpenWindowPacket.class, OpenWindowPacket::new), - entry(OpenSignEditorPacket.class, OpenSignEditorPacket::new), - entry(PingPacket.class, PingPacket::new), - entry(PingResponsePacket.class, PingResponsePacket::new), - entry(CraftRecipeResponse.class, CraftRecipeResponse::new), - entry(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new), - entry(PlayerChatMessagePacket.class, PlayerChatMessagePacket::new), - entry(EndCombatEventPacket.class, EndCombatEventPacket::new), - entry(EnterCombatEventPacket.class, EnterCombatEventPacket::new), - entry(DeathCombatEventPacket.class, DeathCombatEventPacket::new), - entry(PlayerInfoRemovePacket.class, PlayerInfoRemovePacket::new), - entry(PlayerInfoUpdatePacket.class, PlayerInfoUpdatePacket::new), - entry(FacePlayerPacket.class, FacePlayerPacket::new), - entry(PlayerPositionAndLookPacket.class, PlayerPositionAndLookPacket::new), - entry(UnlockRecipesPacket.class, UnlockRecipesPacket::new), - entry(DestroyEntitiesPacket.class, DestroyEntitiesPacket::new), - entry(RemoveEntityEffectPacket.class, RemoveEntityEffectPacket::new), - entry(ResetScorePacket.class, ResetScorePacket::new), - entry(ResourcePackPopPacket.class, ResourcePackPopPacket::new), - entry(ResourcePackPushPacket.class, ResourcePackPushPacket::new), - entry(RespawnPacket.class, RespawnPacket::new), - entry(EntityHeadLookPacket.class, EntityHeadLookPacket::new), - entry(MultiBlockChangePacket.class, MultiBlockChangePacket::new), - entry(SelectAdvancementTabPacket.class, SelectAdvancementTabPacket::new), - entry(ServerDataPacket.class, ServerDataPacket::new), - entry(ActionBarPacket.class, ActionBarPacket::new), - entry(WorldBorderCenterPacket.class, WorldBorderCenterPacket::new), - entry(WorldBorderLerpSizePacket.class, WorldBorderLerpSizePacket::new), - entry(WorldBorderSizePacket.class, WorldBorderSizePacket::new), - entry(WorldBorderWarningDelayPacket.class, WorldBorderWarningDelayPacket::new), - entry(WorldBorderWarningReachPacket.class, WorldBorderWarningReachPacket::new), - entry(CameraPacket.class, CameraPacket::new), - entry(HeldItemChangePacket.class, HeldItemChangePacket::new), - entry(UpdateViewPositionPacket.class, UpdateViewPositionPacket::new), - entry(UpdateViewDistancePacket.class, UpdateViewDistancePacket::new), - entry(SpawnPositionPacket.class, SpawnPositionPacket::new), - entry(DisplayScoreboardPacket.class, DisplayScoreboardPacket::new), - entry(EntityMetaDataPacket.class, EntityMetaDataPacket::new), - entry(AttachEntityPacket.class, AttachEntityPacket::new), - entry(EntityVelocityPacket.class, EntityVelocityPacket::new), - entry(EntityEquipmentPacket.class, EntityEquipmentPacket::new), - entry(SetExperiencePacket.class, SetExperiencePacket::new), - entry(UpdateHealthPacket.class, UpdateHealthPacket::new), - entry(ScoreboardObjectivePacket.class, ScoreboardObjectivePacket::new), - entry(SetPassengersPacket.class, SetPassengersPacket::new), - entry(TeamsPacket.class, TeamsPacket::new), - entry(UpdateScorePacket.class, UpdateScorePacket::new), - entry(UpdateSimulationDistancePacket.class, UpdateSimulationDistancePacket::new), - entry(SetTitleSubTitlePacket.class, SetTitleSubTitlePacket::new), - entry(TimeUpdatePacket.class, TimeUpdatePacket::new), - entry(SetTitleTextPacket.class, SetTitleTextPacket::new), - entry(SetTitleTimePacket.class, SetTitleTimePacket::new), - entry(EntitySoundEffectPacket.class, EntitySoundEffectPacket::new), - entry(SoundEffectPacket.class, SoundEffectPacket::new), - entry(StartConfigurationPacket.class, StartConfigurationPacket::new), - entry(StopSoundPacket.class, StopSoundPacket::new), - entry(CookieStorePacket.class, CookieStorePacket::new), - entry(SystemChatPacket.class, SystemChatPacket::new), - entry(PlayerListHeaderAndFooterPacket.class, PlayerListHeaderAndFooterPacket::new), - entry(NbtQueryResponsePacket.class, NbtQueryResponsePacket::new), - entry(CollectItemPacket.class, CollectItemPacket::new), - entry(EntityTeleportPacket.class, EntityTeleportPacket::new), - entry(SetTickStatePacket.class, SetTickStatePacket::new), - entry(TickStepPacket.class, TickStepPacket::new), - entry(TransferPacket.class, TransferPacket::new), - entry(AdvancementsPacket.class, AdvancementsPacket::new), - entry(EntityAttributesPacket.class, EntityAttributesPacket::new), - entry(EntityEffectPacket.class, EntityEffectPacket::new), - entry(DeclareRecipesPacket.class, DeclareRecipesPacket::new), - entry(TagsPacket.class, TagsPacket::new), - entry(ProjectilePowerPacket.class, ProjectilePowerPacket::new), - entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket::new), - entry(ServerLinksPacket.class, ServerLinksPacket::new) + entry(EntityStatusPacket.class, EntityStatusPacket.SERIALIZER), + entry(ExplosionPacket.class, ExplosionPacket.SERIALIZER), + entry(UnloadChunkPacket.class, UnloadChunkPacket.SERIALIZER), + entry(ChangeGameStatePacket.class, ChangeGameStatePacket.SERIALIZER), + entry(OpenHorseWindowPacket.class, OpenHorseWindowPacket.SERIALIZER), + entry(HitAnimationPacket.class, HitAnimationPacket.SERIALIZER), + entry(InitializeWorldBorderPacket.class, InitializeWorldBorderPacket.SERIALIZER), + entry(KeepAlivePacket.class, KeepAlivePacket.SERIALIZER), + entry(ChunkDataPacket.class, ChunkDataPacket.SERIALIZER), + entry(EffectPacket.class, EffectPacket.SERIALIZER), + entry(ParticlePacket.class, ParticlePacket.SERIALIZER), + entry(UpdateLightPacket.class, UpdateLightPacket.SERIALIZER), + entry(JoinGamePacket.class, JoinGamePacket.SERIALIZER), + entry(MapDataPacket.class, MapDataPacket.SERIALIZER), + entry(TradeListPacket.class, TradeListPacket.SERIALIZER), + entry(EntityPositionPacket.class, EntityPositionPacket.SERIALIZER), + entry(EntityPositionAndRotationPacket.class, EntityPositionAndRotationPacket.SERIALIZER), + entry(EntityRotationPacket.class, EntityRotationPacket.SERIALIZER), + entry(VehicleMovePacket.class, VehicleMovePacket.SERIALIZER), + entry(OpenBookPacket.class, OpenBookPacket.SERIALIZER), + entry(OpenWindowPacket.class, OpenWindowPacket.SERIALIZER), + entry(OpenSignEditorPacket.class, OpenSignEditorPacket.SERIALIZER), + entry(PingPacket.class, PingPacket.SERIALIZER), + entry(PingResponsePacket.class, PingResponsePacket.SERIALIZER), + entry(CraftRecipeResponse.class, CraftRecipeResponse.SERIALIZER), + entry(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket.SERIALIZER), + entry(PlayerChatMessagePacket.class, PlayerChatMessagePacket.SERIALIZER), + entry(EndCombatEventPacket.class, EndCombatEventPacket.SERIALIZER), + entry(EnterCombatEventPacket.class, EnterCombatEventPacket.SERIALIZER), + entry(DeathCombatEventPacket.class, DeathCombatEventPacket.SERIALIZER), + entry(PlayerInfoRemovePacket.class, PlayerInfoRemovePacket.SERIALIZER), + entry(PlayerInfoUpdatePacket.class, PlayerInfoUpdatePacket.SERIALIZER), + entry(FacePlayerPacket.class, FacePlayerPacket.SERIALIZER), + entry(PlayerPositionAndLookPacket.class, PlayerPositionAndLookPacket.SERIALIZER), + entry(UnlockRecipesPacket.class, UnlockRecipesPacket.SERIALIZER), + entry(DestroyEntitiesPacket.class, DestroyEntitiesPacket.SERIALIZER), + entry(RemoveEntityEffectPacket.class, RemoveEntityEffectPacket.SERIALIZER), + entry(ResetScorePacket.class, ResetScorePacket.SERIALIZER), + entry(ResourcePackPopPacket.class, ResourcePackPopPacket.SERIALIZER), + entry(ResourcePackPushPacket.class, ResourcePackPushPacket.SERIALIZER), + entry(RespawnPacket.class, RespawnPacket.SERIALIZER), + entry(EntityHeadLookPacket.class, EntityHeadLookPacket.SERIALIZER), + entry(MultiBlockChangePacket.class, MultiBlockChangePacket.SERIALIZER), + entry(SelectAdvancementTabPacket.class, SelectAdvancementTabPacket.SERIALIZER), + entry(ServerDataPacket.class, ServerDataPacket.SERIALIZER), + entry(ActionBarPacket.class, ActionBarPacket.SERIALIZER), + entry(WorldBorderCenterPacket.class, WorldBorderCenterPacket.SERIALIZER), + entry(WorldBorderLerpSizePacket.class, WorldBorderLerpSizePacket.SERIALIZER), + entry(WorldBorderSizePacket.class, WorldBorderSizePacket.SERIALIZER), + entry(WorldBorderWarningDelayPacket.class, WorldBorderWarningDelayPacket.SERIALIZER), + entry(WorldBorderWarningReachPacket.class, WorldBorderWarningReachPacket.SERIALIZER), + entry(CameraPacket.class, CameraPacket.SERIALIZER), + entry(HeldItemChangePacket.class, HeldItemChangePacket.SERIALIZER), + entry(UpdateViewPositionPacket.class, UpdateViewPositionPacket.SERIALIZER), + entry(UpdateViewDistancePacket.class, UpdateViewDistancePacket.SERIALIZER), + entry(SpawnPositionPacket.class, SpawnPositionPacket.SERIALIZER), + entry(DisplayScoreboardPacket.class, DisplayScoreboardPacket.SERIALIZER), + entry(EntityMetaDataPacket.class, EntityMetaDataPacket.SERIALIZER), + entry(AttachEntityPacket.class, AttachEntityPacket.SERIALIZER), + entry(EntityVelocityPacket.class, EntityVelocityPacket.SERIALIZER), + entry(EntityEquipmentPacket.class, EntityEquipmentPacket.SERIALIZER), + entry(SetExperiencePacket.class, SetExperiencePacket.SERIALIZER), + entry(UpdateHealthPacket.class, UpdateHealthPacket.SERIALIZER), + entry(ScoreboardObjectivePacket.class, ScoreboardObjectivePacket.SERIALIZER), + entry(SetPassengersPacket.class, SetPassengersPacket.SERIALIZER), + entry(TeamsPacket.class, TeamsPacket.SERIALIZER), + entry(UpdateScorePacket.class, UpdateScorePacket.SERIALIZER), + entry(UpdateSimulationDistancePacket.class, UpdateSimulationDistancePacket.SERIALIZER), + entry(SetTitleSubTitlePacket.class, SetTitleSubTitlePacket.SERIALIZER), + entry(TimeUpdatePacket.class, TimeUpdatePacket.SERIALIZER), + entry(SetTitleTextPacket.class, SetTitleTextPacket.SERIALIZER), + entry(SetTitleTimePacket.class, SetTitleTimePacket.SERIALIZER), + entry(EntitySoundEffectPacket.class, EntitySoundEffectPacket.SERIALIZER), + entry(SoundEffectPacket.class, SoundEffectPacket.SERIALIZER), + entry(StartConfigurationPacket.class, StartConfigurationPacket.SERIALIZER), + entry(StopSoundPacket.class, StopSoundPacket.SERIALIZER), + entry(CookieStorePacket.class, CookieStorePacket.SERIALIZER), + entry(SystemChatPacket.class, SystemChatPacket.SERIALIZER), + entry(PlayerListHeaderAndFooterPacket.class, PlayerListHeaderAndFooterPacket.SERIALIZER), + entry(NbtQueryResponsePacket.class, NbtQueryResponsePacket.SERIALIZER), + entry(CollectItemPacket.class, CollectItemPacket.SERIALIZER), + entry(EntityTeleportPacket.class, EntityTeleportPacket.SERIALIZER), + entry(SetTickStatePacket.class, SetTickStatePacket.SERIALIZER), + entry(TickStepPacket.class, TickStepPacket.SERIALIZER), + entry(TransferPacket.class, TransferPacket.SERIALIZER), + entry(AdvancementsPacket.class, AdvancementsPacket.SERIALIZER), + entry(EntityAttributesPacket.class, EntityAttributesPacket.SERIALIZER), + entry(EntityEffectPacket.class, EntityEffectPacket.SERIALIZER), + entry(DeclareRecipesPacket.class, DeclareRecipesPacket.SERIALIZER), + entry(TagsPacket.class, TagsPacket.SERIALIZER), + entry(ProjectilePowerPacket.class, ProjectilePowerPacket.SERIALIZER), + entry(CustomReportDetailsPacket.class, CustomReportDetailsPacket.SERIALIZER), + entry(ServerLinksPacket.class, ServerLinksPacket.SERIALIZER) ); } } sealed class PacketRegistryTemplate implements PacketRegistry { - private final Entry[] suppliers; - private final ClassValue packetIds = new ClassValue<>() { + private final Entry[] suppliers; + private final ClassValue> packetIds = new ClassValue<>() { @Override - protected Integer computeValue(@NotNull Class type) { + protected PacketInfo computeValue(@NotNull Class type) { for (int i = 0; i < suppliers.length; i++) { - final Entry entry = suppliers[i]; - if (entry != null && entry.type == type) return i; + final Entry entry = suppliers[i]; + if (entry != null && entry.type == type) { + //noinspection unchecked + return new PacketInfo(entry.type, i, (NetworkBuffer.Type) entry.reader); + } } throw new IllegalStateException("Packet type " + type + " isn't registered!"); } }; @SafeVarargs - PacketRegistryTemplate(Entry... suppliers) { + PacketRegistryTemplate(Entry... suppliers) { this.suppliers = suppliers; } public @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader) { - final Entry entry = suppliers[packetId]; - final NetworkBuffer.Reader supplier = entry.reader; - if (supplier == null) + final Entry entry = suppliers[packetId]; + if (entry == null) throw new IllegalStateException("Packet id 0x" + Integer.toHexString(packetId) + " isn't registered!"); - return supplier.read(reader); + final NetworkBuffer.Type supplier = entry.reader; + final T packet = supplier.read(reader); + if (packet == null) { + throw new IllegalStateException("Packet " + entry.type + " failed to read!"); + } + return packet; } @Override - public int packetId(@NotNull Class packetClass) { + public PacketInfo packetInfo(Class packetClass) { return packetIds.get(packetClass); } - record Entry(Class type, NetworkBuffer.Reader reader) { + record Entry(Class type, NetworkBuffer.Type reader) { } @SuppressWarnings({"unchecked", "rawtypes"}) - static Entry entry(Class type, NetworkBuffer.Reader reader) { + static Entry entry(Class type, NetworkBuffer.Type reader) { return new Entry<>((Class) type, reader); } } 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 cd22192c8..dc7da3ce3 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,6 +1,5 @@ package net.minestom.server.network.packet.client; -import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.ApiStatus; /** @@ -8,10 +7,11 @@ import org.jetbrains.annotations.ApiStatus; *

* Packets are value-based, and should therefore not be reliant on identity. */ -public interface ClientPacket extends NetworkBuffer.Writer { +public interface ClientPacket { /** * Determines whether this packet should be processed immediately * or wait until the next server tick. + * * @return true if this packet should process immediately */ @ApiStatus.Internal diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java index de07946ac..a8ea92cec 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java @@ -1,40 +1,32 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.common.CookieStorePacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY; +import static net.minestom.server.network.NetworkBuffer.STRING; + public record ClientCookieResponsePacket( @NotNull String key, byte @Nullable [] value ) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientCookieResponsePacket::key, + BYTE_ARRAY.optional(), ClientCookieResponsePacket::value, + ClientCookieResponsePacket::new); public ClientCookieResponsePacket { Check.argCondition(value != null && value.length > CookieStorePacket.MAX_VALUE_LENGTH, "Value is too long: {0} > {1}", value != null ? value.length : 0, CookieStorePacket.MAX_VALUE_LENGTH); } - public ClientCookieResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.STRING), reader.readOptional(buffer -> { - int valueLength = buffer.read(NetworkBuffer.VAR_INT); - Check.argCondition(valueLength > CookieStorePacket.MAX_VALUE_LENGTH, - "Value is too long: {0} > {1}", valueLength, CookieStorePacket.MAX_VALUE_LENGTH); - return buffer.readBytes(valueLength); - })); - } - @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, key); - writer.writeOptional(NetworkBuffer.BYTE_ARRAY, value); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java index 15a2dabc5..5094d30b2 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java @@ -1,23 +1,17 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; public record ClientKeepAlivePacket(long id) implements ClientPacket { - public ClientKeepAlivePacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, ClientKeepAlivePacket::id, ClientKeepAlivePacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, id); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java index ce27af105..cac7205b4 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java @@ -1,23 +1,17 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; public record ClientPingRequestPacket(long number) implements ClientPacket { - public ClientPingRequestPacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, ClientPingRequestPacket::number, ClientPingRequestPacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, number); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java index d67034c32..e60c0cba0 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -8,18 +9,13 @@ import static net.minestom.server.network.NetworkBuffer.RAW_BYTES; import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientPluginMessagePacket(@NotNull String channel, byte[] data) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientPluginMessagePacket::channel, + RAW_BYTES, ClientPluginMessagePacket::data, + ClientPluginMessagePacket::new); + public ClientPluginMessagePacket { if (channel.length() > 256) throw new IllegalArgumentException("Channel cannot be more than 256 characters long"); } - - public ClientPluginMessagePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(RAW_BYTES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, channel); - writer.write(RAW_BYTES, data); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientPongPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientPongPacket.java index a7ab7dac6..4ce81059e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientPongPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientPongPacket.java @@ -1,18 +1,12 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; public record ClientPongPacket(int id) implements ClientPacket { - public ClientPongPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, id); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, ClientPongPacket::id, ClientPongPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java index 5caa2cb86..5b5660595 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java @@ -11,15 +11,18 @@ public record ClientResourcePackStatusPacket( @NotNull UUID id, @NotNull ResourcePackStatus status ) implements ClientPacket { - public ClientResourcePackStatusPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID), readStatus(reader)); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientResourcePackStatusPacket value) { + buffer.write(NetworkBuffer.UUID, value.id); + buffer.write(NetworkBuffer.VAR_INT, statusId(value.status)); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, id); - writer.writeEnum(ResourcePackStatus.class, status); - } + @Override + public ClientResourcePackStatusPacket read(@NotNull NetworkBuffer buffer) { + return new ClientResourcePackStatusPacket(buffer.read(NetworkBuffer.UUID), readStatus(buffer)); + } + }; private static @NotNull ResourcePackStatus readStatus(@NotNull NetworkBuffer reader) { var ordinal = reader.read(NetworkBuffer.VAR_INT); @@ -35,4 +38,17 @@ public record ClientResourcePackStatusPacket( default -> throw new IllegalStateException("Unexpected resource pack status: " + ordinal); }; } + + private static int statusId(@NotNull ResourcePackStatus status) { + return switch (status) { + case SUCCESSFULLY_LOADED -> 0; + case DECLINED -> 1; + case FAILED_DOWNLOAD -> 2; + case ACCEPTED -> 3; + case DOWNLOADED -> 4; + case INVALID_URL -> 5; + case FAILED_RELOAD -> 6; + case DISCARDED -> 7; + }; + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java index b139cac78..0cb96bdaf 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.common; import net.minestom.server.entity.Player; import net.minestom.server.message.ChatMessageType; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -12,27 +13,19 @@ public record ClientSettingsPacket(@NotNull String locale, byte viewDistance, @NotNull ChatMessageType chatMessageType, boolean chatColors, byte displayedSkinParts, @NotNull Player.MainHand mainHand, boolean enableTextFiltering, boolean allowsListing) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientSettingsPacket::locale, + BYTE, ClientSettingsPacket::viewDistance, + Enum(ChatMessageType.class), ClientSettingsPacket::chatMessageType, + BOOLEAN, ClientSettingsPacket::chatColors, + BYTE, ClientSettingsPacket::displayedSkinParts, + Enum(Player.MainHand.class), ClientSettingsPacket::mainHand, + BOOLEAN, ClientSettingsPacket::enableTextFiltering, + BOOLEAN, ClientSettingsPacket::allowsListing, + ClientSettingsPacket::new); + public ClientSettingsPacket { if (locale.length() > 128) throw new IllegalArgumentException("Locale cannot be longer than 128 characters."); } - - public ClientSettingsPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(BYTE), - ChatMessageType.fromPacketID(reader.read(VAR_INT)), reader.read(BOOLEAN), - reader.read(BYTE), reader.readEnum(Player.MainHand.class), - reader.read(BOOLEAN), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, locale); - writer.write(BYTE, viewDistance); - writer.write(VAR_INT, chatMessageType.getPacketID()); - writer.write(BOOLEAN, chatColors); - writer.write(BYTE, displayedSkinParts); - writer.write(VAR_INT, mainHand.ordinal()); - writer.write(BOOLEAN, enableTextFiltering); - writer.write(BOOLEAN, allowsListing); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/configuration/ClientFinishConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/client/configuration/ClientFinishConfigurationPacket.java index d500b844a..aa270b0ac 100644 --- a/src/main/java/net/minestom/server/network/packet/client/configuration/ClientFinishConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/configuration/ClientFinishConfigurationPacket.java @@ -1,17 +1,9 @@ package net.minestom.server.network.packet.client.configuration; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; public record ClientFinishConfigurationPacket() implements ClientPacket { - - public ClientFinishConfigurationPacket(@NotNull NetworkBuffer buffer) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ClientFinishConfigurationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/configuration/ClientSelectKnownPacksPacket.java b/src/main/java/net/minestom/server/network/packet/client/configuration/ClientSelectKnownPacksPacket.java index 6be68623a..effc73ce7 100644 --- a/src/main/java/net/minestom/server/network/packet/client/configuration/ClientSelectKnownPacksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/configuration/ClientSelectKnownPacksPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.configuration; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.configuration.SelectKnownPacksPacket; import net.minestom.server.utils.validate.Check; @@ -13,18 +14,12 @@ public record ClientSelectKnownPacksPacket( ) implements ClientPacket { private static final int MAX_ENTRIES = 64; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + SelectKnownPacksPacket.Entry.SERIALIZER.list(MAX_ENTRIES), ClientSelectKnownPacksPacket::entries, + ClientSelectKnownPacksPacket::new); + public ClientSelectKnownPacksPacket { Check.argCondition(entries.size() > MAX_ENTRIES, "Too many known packs: {0} > {1}", entries.size(), MAX_ENTRIES); entries = List.copyOf(entries); } - - public ClientSelectKnownPacksPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(SelectKnownPacksPacket.Entry::new, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(entries); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java b/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java index f25e01d98..a71705e88 100644 --- a/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java @@ -16,31 +16,34 @@ public record ClientHandshakePacket(int protocolVersion, @NotNull String serverA } } - public ClientHandshakePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(STRING), - reader.read(UNSIGNED_SHORT), - // Not a readEnum call because the indices are not 0-based - Intent.fromId(reader.read(VAR_INT))); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientHandshakePacket value) { + buffer.write(VAR_INT, value.protocolVersion); + int maxLength = getMaxHandshakeLength(); + if (value.serverAddress.length() > maxLength) { + throw new IllegalArgumentException("serverAddress is " + value.serverAddress.length() + " characters long, maximum allowed is " + maxLength); + } + buffer.write(STRING, value.serverAddress); + buffer.write(UNSIGNED_SHORT, value.serverPort); + // Not a writeEnum call because the indices are not 0-based + buffer.write(VAR_INT, value.intent.id()); + } + + @Override + public @NotNull ClientHandshakePacket read(@NotNull NetworkBuffer buffer) { + return new ClientHandshakePacket(buffer.read(VAR_INT), buffer.read(STRING), + buffer.read(UNSIGNED_SHORT), + // Not a readEnum call because the indices are not 0-based + Intent.fromId(buffer.read(VAR_INT))); + } + }; @Override public boolean processImmediately() { return true; } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, protocolVersion); - int maxLength = getMaxHandshakeLength(); - if (serverAddress.length() > maxLength) { - throw new IllegalArgumentException("serverAddress is " + serverAddress.length() + " characters long, maximum allowed is " + maxLength); - } - writer.write(STRING, serverAddress); - writer.write(UNSIGNED_SHORT, serverPort); - // Not a writeEnum call because the indices are not 0-based - writer.write(VAR_INT, intent.id()); - } - private static int getMaxHandshakeLength() { // BungeeGuard limits handshake length to 2500 characters, while vanilla limits it to 255 return BungeeCordProxy.isEnabled() ? (BungeeCordProxy.isBungeeGuardEnabled() ? 2500 : Short.MAX_VALUE) : 255; @@ -64,5 +67,4 @@ public record ClientHandshakePacket(int protocolVersion, @NotNull String serverA return ordinal() + 1; } } - } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java index 4ea7c7479..3985a7a26 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java @@ -1,26 +1,20 @@ package net.minestom.server.network.packet.client.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY; public record ClientEncryptionResponsePacket(byte[] sharedSecret, byte[] encryptedVerifyToken) implements ClientPacket { - - public ClientEncryptionResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE_ARRAY), reader.read(BYTE_ARRAY)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE_ARRAY, ClientEncryptionResponsePacket::sharedSecret, + BYTE_ARRAY, ClientEncryptionResponsePacket::encryptedVerifyToken, + ClientEncryptionResponsePacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE_ARRAY, sharedSecret); - writer.write(BYTE_ARRAY, encryptedVerifyToken); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java index 9830a10a5..ae0161c8a 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java @@ -1,22 +1,14 @@ package net.minestom.server.network.packet.client.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; public record ClientLoginAcknowledgedPacket() implements ClientPacket { - - public ClientLoginAcknowledgedPacket(@NotNull NetworkBuffer buffer) { - this(); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ClientLoginAcknowledgedPacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java index b11b62930..16f933422 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java @@ -1,27 +1,21 @@ package net.minestom.server.network.packet.client.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.RAW_BYTES; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientLoginPluginResponsePacket(int messageId, byte @Nullable [] data) implements ClientPacket { - - public ClientLoginPluginResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readOptional(RAW_BYTES)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientLoginPluginResponsePacket::messageId, + RAW_BYTES, ClientLoginPluginResponsePacket::data, + ClientLoginPluginResponsePacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, messageId); - writer.writeOptional(RAW_BYTES, data); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java index b4ba4adc5..9a4dbf2f0 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java @@ -1,9 +1,9 @@ package net.minestom.server.network.packet.client.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.UUID; @@ -12,21 +12,18 @@ import static net.minestom.server.network.NetworkBuffer.UUID; public record ClientLoginStartPacket(@NotNull String username, @NotNull UUID profileId) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientLoginStartPacket::username, + UUID, ClientLoginStartPacket::profileId, + ClientLoginStartPacket::new); - public ClientLoginStartPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(UUID)); + public ClientLoginStartPacket { + if (username.length() > 16) + throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters"); } @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - if (username.length() > 16) - throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters"); - writer.write(STRING, username); - writer.write(UUID, profileId); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java index fec3c5c7f..05140065e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java @@ -10,35 +10,27 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientAdvancementTabPacket(@NotNull AdvancementAction action, @Nullable String tabIdentifier) implements ClientPacket { + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientAdvancementTabPacket value) { + buffer.writeEnum(AdvancementAction.class, value.action); + if (value.action == AdvancementAction.OPENED_TAB) { + assert value.tabIdentifier != null; + buffer.write(STRING, value.tabIdentifier); + } + } + + @Override + public ClientAdvancementTabPacket read(@NotNull NetworkBuffer buffer) { + var action = buffer.readEnum(AdvancementAction.class); + var tabIdentifier = action == AdvancementAction.OPENED_TAB ? buffer.read(STRING) : null; + return new ClientAdvancementTabPacket(action, tabIdentifier); + } + }; + public ClientAdvancementTabPacket { if (tabIdentifier != null && tabIdentifier.length() > 256) { throw new IllegalArgumentException("Tab identifier too long: " + tabIdentifier.length()); } } - - public ClientAdvancementTabPacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } - - private ClientAdvancementTabPacket(ClientAdvancementTabPacket packet) { - this(packet.action, packet.tabIdentifier); - } - - private static ClientAdvancementTabPacket read(@NotNull NetworkBuffer reader) { - var action = reader.readEnum(AdvancementAction.class); - var tabIdentifier = action == AdvancementAction.OPENED_TAB ? reader.read(STRING) : null; - return new ClientAdvancementTabPacket(action, tabIdentifier); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(AdvancementAction.class, action); - if (action == AdvancementAction.OPENED_TAB) { - assert tabIdentifier != null; - if (tabIdentifier.length() > 256) { - throw new IllegalArgumentException("Tab identifier cannot be longer than 256 characters."); - } - writer.write(STRING, tabIdentifier); - } - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java index 7bd6067a6..00b34fcd5 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientAnimationPacket.java @@ -2,16 +2,12 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; public record ClientAnimationPacket(@NotNull PlayerHand hand) implements ClientPacket { - public ClientAnimationPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(PlayerHand.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(PlayerHand.class, hand); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(PlayerHand.class), ClientAnimationPacket::hand, + ClientAnimationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatAckPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatAckPacket.java index 9f448d037..6e185e068 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatAckPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatAckPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientChatAckPacket(int offset) implements ClientPacket { - public ClientChatAckPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, offset); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientChatAckPacket::offset, + ClientChatAckPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java index 3da9f83f4..7f194fa1e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java @@ -13,20 +13,22 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientChatMessagePacket(String message, long timestamp, long salt, byte @Nullable [] signature, int ackOffset, BitSet ackList) implements ClientPacket { + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientChatMessagePacket value) { + buffer.write(STRING, value.message); + buffer.write(LONG, value.timestamp); + buffer.write(LONG, value.salt); + buffer.writeOptional(BYTE_ARRAY, value.signature); + buffer.write(VAR_INT, value.ackOffset); + buffer.write(RAW_BYTES, Arrays.copyOf(value.ackList.toByteArray(), 3)); + } - public ClientChatMessagePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(LONG), - reader.read(LONG), reader.readOptional(r -> r.readBytes(256)), - reader.read(VAR_INT), BitSet.valueOf(reader.readBytes(3))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, message); - writer.write(LONG, timestamp); - writer.write(LONG, salt); - writer.writeOptional(BYTE_ARRAY, signature); - writer.write(VAR_INT, ackOffset); - writer.write(RAW_BYTES, Arrays.copyOf(ackList.toByteArray(), 3)); - } + @Override + public ClientChatMessagePacket read(@NotNull NetworkBuffer buffer) { + return new ClientChatMessagePacket(buffer.read(STRING), buffer.read(LONG), + buffer.read(LONG), buffer.readOptional(r -> r.readBytes(256)), + buffer.read(VAR_INT), BitSet.valueOf(buffer.readBytes(3))); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java index a18b33e9a..7226def8e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java @@ -6,12 +6,15 @@ import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; public record ClientChatSessionUpdatePacket(@NotNull ChatSession chatSession) implements ClientPacket { - public ClientChatSessionUpdatePacket(@NotNull NetworkBuffer reader) { - this(new ChatSession(reader)); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientChatSessionUpdatePacket value) { + buffer.write(value.chatSession); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(chatSession); - } + @Override + public ClientChatSessionUpdatePacket read(@NotNull NetworkBuffer buffer) { + return new ClientChatSessionUpdatePacket(new ChatSession(buffer)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChunkBatchReceivedPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChunkBatchReceivedPacket.java index c678c2bb1..ad48da2a2 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChunkBatchReceivedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChunkBatchReceivedPacket.java @@ -1,17 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.FLOAT; public record ClientChunkBatchReceivedPacket(float targetChunksPerTick) implements ClientPacket { - - public ClientChunkBatchReceivedPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.FLOAT, targetChunksPerTick); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, ClientChunkBatchReceivedPacket::targetChunksPerTick, + ClientChunkBatchReceivedPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java index 610625d13..b97a5d880 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java @@ -1,19 +1,14 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record ClientClickWindowButtonPacket(byte windowId, byte buttonId) implements ClientPacket { - public ClientClickWindowButtonPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(BYTE, buttonId); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientClickWindowButtonPacket::windowId, + BYTE, ClientClickWindowButtonPacket::buttonId, + ClientClickWindowButtonPacket::new); } 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 595bfc27e..fdd11a776 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 @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -15,37 +16,25 @@ public record ClientClickWindowPacket(byte windowId, int stateId, @NotNull ItemStack clickedItem) implements ClientPacket { public static final int MAX_CHANGED_SLOTS = 128; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientClickWindowPacket::windowId, + VAR_INT, ClientClickWindowPacket::stateId, + SHORT, ClientClickWindowPacket::slot, + BYTE, ClientClickWindowPacket::button, + Enum(ClickType.class), ClientClickWindowPacket::clickType, + ChangedSlot.SERIALIZER.list(MAX_CHANGED_SLOTS), ClientClickWindowPacket::changedSlots, + ItemStack.NETWORK_TYPE, ClientClickWindowPacket::clickedItem, + ClientClickWindowPacket::new); + public ClientClickWindowPacket { changedSlots = List.copyOf(changedSlots); } - public ClientClickWindowPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(VAR_INT), - reader.read(SHORT), reader.read(BYTE), reader.readEnum(ClickType.class), - reader.readCollection(ChangedSlot::new, MAX_CHANGED_SLOTS), reader.read(ItemStack.NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(VAR_INT, stateId); - writer.write(SHORT, slot); - writer.write(BYTE, button); - writer.write(VAR_INT, clickType.ordinal()); - writer.writeCollection(changedSlots); - writer.write(ItemStack.NETWORK_TYPE, clickedItem); - } - - public record ChangedSlot(short slot, @NotNull ItemStack item) implements NetworkBuffer.Writer { - public ChangedSlot(@NotNull NetworkBuffer reader) { - this(reader.read(SHORT), reader.read(ItemStack.NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SHORT, slot); - writer.write(ItemStack.NETWORK_TYPE, item); - } + public record ChangedSlot(short slot, @NotNull ItemStack item) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + SHORT, ChangedSlot::slot, + ItemStack.NETWORK_TYPE, ChangedSlot::item, + ChangedSlot::new); } public enum ClickType { diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java index fe00a8a8f..49ce2b32c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record ClientCloseWindowPacket(byte windowId) implements ClientPacket { - public ClientCloseWindowPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientCloseWindowPacket::windowId, + ClientCloseWindowPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCommandChatPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCommandChatPacket.java index 66b302b3e..5a0d996a0 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCommandChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCommandChatPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -8,16 +9,11 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientCommandChatPacket(@NotNull String message) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientCommandChatPacket::message, + ClientCommandChatPacket::new); + public ClientCommandChatPacket { Check.argCondition(message.length() > 256, "Message length cannot be greater than 256"); } - - public ClientCommandChatPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, message); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientConfigurationAckPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientConfigurationAckPacket.java index 853593402..7b5859aa5 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientConfigurationAckPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientConfigurationAckPacket.java @@ -1,15 +1,9 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; public record ClientConfigurationAckPacket() implements ClientPacket { - public ClientConfigurationAckPacket(@NotNull NetworkBuffer buffer) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ClientConfigurationAckPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java index 5897c2928..3920ca3e4 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java @@ -1,26 +1,20 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record ClientCraftRecipeRequest(byte windowId, String recipe, boolean makeAll) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientCraftRecipeRequest::windowId, + STRING, ClientCraftRecipeRequest::recipe, + BOOLEAN, ClientCraftRecipeRequest::makeAll, + ClientCraftRecipeRequest::new); public ClientCraftRecipeRequest { if (recipe.length() > 256) { throw new IllegalArgumentException("'recipe' cannot be longer than 256 characters."); } } - - public ClientCraftRecipeRequest(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(STRING), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(STRING, recipe); - writer.write(BOOLEAN, makeAll); - } } 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 794029111..222c4a999 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 @@ -2,19 +2,15 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.SHORT; public record ClientCreativeInventoryActionPacket(short slot, @NotNull ItemStack item) implements ClientPacket { - public ClientCreativeInventoryActionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(SHORT), reader.read(ItemStack.NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SHORT, slot); - writer.write(ItemStack.NETWORK_TYPE, item); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + SHORT, ClientCreativeInventoryActionPacket::slot, + ItemStack.NETWORK_TYPE, ClientCreativeInventoryActionPacket::item, + ClientCreativeInventoryActionPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientDebugSampleSubscriptionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientDebugSampleSubscriptionPacket.java index 2fd208907..f19bd00f3 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientDebugSampleSubscriptionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientDebugSampleSubscriptionPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.play.DebugSamplePacket; import org.jetbrains.annotations.NotNull; public record ClientDebugSampleSubscriptionPacket(@NotNull DebugSamplePacket.Type type) implements ClientPacket { - - public ClientDebugSampleSubscriptionPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(DebugSamplePacket.Type.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(DebugSamplePacket.Type.class, type); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(DebugSamplePacket.Type.class), ClientDebugSampleSubscriptionPacket::type, + ClientDebugSampleSubscriptionPacket::new); } 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 ef8996b47..e0b089167 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 @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,22 +15,16 @@ public record ClientEditBookPacket(int slot, @NotNull List pages, @Nullable String title) implements ClientPacket { public static final int MAX_PAGES = 200; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientEditBookPacket::slot, + STRING.list(MAX_PAGES), ClientEditBookPacket::pages, + STRING.optional(), ClientEditBookPacket::title, + ClientEditBookPacket::new); + public ClientEditBookPacket { pages = List.copyOf(pages); if (title != null && title.length() > 128) { throw new IllegalArgumentException("Title length cannot be greater than 128"); } } - - public ClientEditBookPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readCollection(STRING, MAX_PAGES), - reader.readOptional(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, slot); - writer.writeCollection(STRING, pages); - writer.writeOptional(STRING, title); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientEntityActionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientEntityActionPacket.java index 80cbac342..121667f30 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientEntityActionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientEntityActionPacket.java @@ -1,24 +1,20 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; +import static net.minestom.server.network.NetworkBuffer.Enum; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientEntityActionPacket(int playerId, @NotNull Action action, int horseJumpBoost) implements ClientPacket { - public ClientEntityActionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readEnum(Action.class), - reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, playerId); - writer.writeEnum(Action.class, action); - writer.write(VAR_INT, horseJumpBoost); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientEntityActionPacket::playerId, + Enum(Action.class), ClientEntityActionPacket::action, + VAR_INT, ClientEntityActionPacket::horseJumpBoost, + ClientEntityActionPacket::new); public enum Action { START_SNEAKING, diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientGenerateStructurePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientGenerateStructurePacket.java index 471bc2a74..2b7167dde 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientGenerateStructurePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientGenerateStructurePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -9,14 +10,9 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientGenerateStructurePacket(@NotNull Point blockPosition, int level, boolean keepJigsaws) implements ClientPacket { - public ClientGenerateStructurePacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(VAR_INT, level); - writer.write(BOOLEAN, keepJigsaws); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, ClientGenerateStructurePacket::blockPosition, + VAR_INT, ClientGenerateStructurePacket::level, + BOOLEAN, ClientGenerateStructurePacket::keepJigsaws, + ClientGenerateStructurePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientHeldItemChangePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientHeldItemChangePacket.java index bdac77c69..12702e150 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientHeldItemChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientHeldItemChangePacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.SHORT; public record ClientHeldItemChangePacket(short slot) implements ClientPacket { - public ClientHeldItemChangePacket(@NotNull NetworkBuffer reader) { - this(reader.read(SHORT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SHORT, slot); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + SHORT, ClientHeldItemChangePacket::slot, + ClientHeldItemChangePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java index 75b66ac40..1912ebc99 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java @@ -8,22 +8,26 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boolean sneaking) implements ClientPacket { - public ClientInteractEntityPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), switch (reader.read(VAR_INT)) { - case 0 -> new Interact(reader); - case 1 -> new Attack(); - case 2 -> new InteractAt(reader); - default -> throw new RuntimeException("Unknown action id"); - }, reader.read(BOOLEAN)); - } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, targetId); - writer.write(VAR_INT, type.id()); - writer.write(type); - writer.write(BOOLEAN, sneaking); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientInteractEntityPacket value) { + buffer.write(VAR_INT, value.targetId); + buffer.write(VAR_INT, value.type.id()); + buffer.write(value.type); + buffer.write(BOOLEAN, value.sneaking); + } + + @Override + public ClientInteractEntityPacket read(@NotNull NetworkBuffer buffer) { + return new ClientInteractEntityPacket(buffer.read(VAR_INT), switch (buffer.read(VAR_INT)) { + case 0 -> new Interact(buffer); + case 1 -> new Attack(); + case 2 -> new InteractAt(buffer); + default -> throw new RuntimeException("Unknown action id"); + }, buffer.read(BOOLEAN)); + } + }; public sealed interface Type extends Writer permits Interact, Attack, InteractAt { diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java index 01ccaefc9..e693813a1 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java @@ -1,24 +1,20 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientNameItemPacket(@NotNull String itemName) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientNameItemPacket::itemName, + ClientNameItemPacket::new); + public ClientNameItemPacket { if (itemName.length() > Short.MAX_VALUE) { throw new IllegalArgumentException("ItemStack name cannot be longer than Short.MAX_VALUE characters!"); } } - - public ClientNameItemPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, itemName); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPickItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPickItemPacket.java index 42cae8485..53003a599 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPickItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPickItemPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientPickItemPacket(int slot) implements ClientPacket { - public ClientPickItemPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, slot); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientPickItemPacket::slot, + ClientPickItemPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerAbilitiesPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerAbilitiesPacket.java index 9c40a6b49..69f3aec96 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerAbilitiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerAbilitiesPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record ClientPlayerAbilitiesPacket(byte flags) implements ClientPacket { - public ClientPlayerAbilitiesPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientPlayerAbilitiesPacket::flags, + ClientPlayerAbilitiesPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java index f2bcd3cbd..370afc626 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java @@ -4,6 +4,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.entity.PlayerHand; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -13,22 +14,14 @@ public record ClientPlayerBlockPlacementPacket(@NotNull PlayerHand hand, @NotNul @NotNull BlockFace blockFace, float cursorPositionX, float cursorPositionY, float cursorPositionZ, boolean insideBlock, int sequence) implements ClientPacket { - public ClientPlayerBlockPlacementPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(PlayerHand.class), reader.read(BLOCK_POSITION), - reader.readEnum(BlockFace.class), - reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT), - reader.read(BOOLEAN), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(PlayerHand.class, hand); - writer.write(BLOCK_POSITION, blockPosition); - writer.writeEnum(BlockFace.class, blockFace); - writer.write(FLOAT, cursorPositionX); - writer.write(FLOAT, cursorPositionY); - writer.write(FLOAT, cursorPositionZ); - writer.write(BOOLEAN, insideBlock); - writer.write(VAR_INT, sequence); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Enum(PlayerHand.class), ClientPlayerBlockPlacementPacket::hand, + BLOCK_POSITION, ClientPlayerBlockPlacementPacket::blockPosition, + Enum(BlockFace.class), ClientPlayerBlockPlacementPacket::blockFace, + FLOAT, ClientPlayerBlockPlacementPacket::cursorPositionX, + FLOAT, ClientPlayerBlockPlacementPacket::cursorPositionY, + FLOAT, ClientPlayerBlockPlacementPacket::cursorPositionZ, + BOOLEAN, ClientPlayerBlockPlacementPacket::insideBlock, + INT, ClientPlayerBlockPlacementPacket::sequence, + ClientPlayerBlockPlacementPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java index c6c8c08b1..1baf77fe6 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java @@ -10,18 +10,22 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientPlayerDiggingPacket(@NotNull Status status, @NotNull Point blockPosition, @NotNull BlockFace blockFace, int sequence) implements ClientPacket { - public ClientPlayerDiggingPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Status.class), reader.read(BLOCK_POSITION), - BlockFace.values()[reader.read(BYTE)], reader.read(VAR_INT)); - } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Status.class, status); - writer.write(BLOCK_POSITION, blockPosition); - writer.write(BYTE, (byte) blockFace.ordinal()); - writer.write(VAR_INT, sequence); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientPlayerDiggingPacket value) { + buffer.writeEnum(Status.class, value.status); + buffer.write(BLOCK_POSITION, value.blockPosition); + buffer.write(BYTE, (byte) value.blockFace.ordinal()); + buffer.write(VAR_INT, value.sequence); + } + + @Override + public ClientPlayerDiggingPacket read(@NotNull NetworkBuffer buffer) { + return new ClientPlayerDiggingPacket(buffer.readEnum(Status.class), buffer.read(BLOCK_POSITION), + BlockFace.values()[buffer.read(BYTE)], buffer.read(VAR_INT)); + } + }; public enum Status { STARTED_DIGGING, diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java index 88b607d6d..0c500e88b 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; public record ClientPlayerPacket(boolean onGround) implements ClientPacket { - public ClientPlayerPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BOOLEAN, ClientPlayerPacket::onGround, + ClientPlayerPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java index 5543dc82c..9605e931b 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java @@ -2,25 +2,17 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.POS; public record ClientPlayerPositionAndRotationPacket(@NotNull Pos position, boolean onGround) implements ClientPacket { - public ClientPlayerPositionAndRotationPacket(@NotNull NetworkBuffer reader) { - this(new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(FLOAT), reader.read(FLOAT)), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(FLOAT, position.yaw()); - writer.write(FLOAT, position.pitch()); - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + POS, ClientPlayerPositionAndRotationPacket::position, + BOOLEAN, ClientPlayerPositionAndRotationPacket::onGround, + ClientPlayerPositionAndRotationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java index a258ab5f7..643d4af2a 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java @@ -1,26 +1,18 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; -import static net.minestom.server.network.NetworkBuffer.DOUBLE; +import static net.minestom.server.network.NetworkBuffer.VECTOR3D; public record ClientPlayerPositionPacket(@NotNull Point position, boolean onGround) implements ClientPacket { - public ClientPlayerPositionPacket(@NotNull NetworkBuffer reader) { - this(new Vec(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE)), - reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VECTOR3D, ClientPlayerPositionPacket::position, + BOOLEAN, ClientPlayerPositionPacket::onGround, + ClientPlayerPositionPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java index 23e8e46b3..1e36449c1 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java @@ -1,21 +1,16 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.FLOAT; public record ClientPlayerRotationPacket(float yaw, float pitch, boolean onGround) implements ClientPacket { - public ClientPlayerRotationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(FLOAT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, yaw); - writer.write(FLOAT, pitch); - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, ClientPlayerRotationPacket::yaw, + FLOAT, ClientPlayerRotationPacket::pitch, + BOOLEAN, ClientPlayerRotationPacket::onGround, + ClientPlayerRotationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryBlockNbtPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryBlockNbtPacket.java index 24a815183..cf1326202 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryBlockNbtPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryBlockNbtPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -9,13 +10,8 @@ import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientQueryBlockNbtPacket(int transactionId, @NotNull Point blockPosition) implements ClientPacket { - public ClientQueryBlockNbtPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(BLOCK_POSITION)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, transactionId); - writer.write(BLOCK_POSITION, blockPosition); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientQueryBlockNbtPacket::transactionId, + BLOCK_POSITION, ClientQueryBlockNbtPacket::blockPosition, + ClientQueryBlockNbtPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryEntityNbtPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryEntityNbtPacket.java index 007dd64c1..a12e5ce61 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryEntityNbtPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientQueryEntityNbtPacket.java @@ -1,19 +1,14 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientQueryEntityNbtPacket(int transactionId, int entityId) implements ClientPacket { - public ClientQueryEntityNbtPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, transactionId); - writer.write(VAR_INT, entityId); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientQueryEntityNbtPacket::transactionId, + VAR_INT, ClientQueryEntityNbtPacket::entityId, + ClientQueryEntityNbtPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectTradePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectTradePacket.java index 20cba35cf..9a8b33f08 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectTradePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectTradePacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientSelectTradePacket(int selectedSlot) implements ClientPacket { - public ClientSelectTradePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, selectedSlot); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientSelectTradePacket::selectedSlot, + ClientSelectTradePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java index e9676740a..99a218440 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java @@ -11,16 +11,19 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientSetBeaconEffectPacket(@Nullable PotionType primaryEffect, @Nullable PotionType secondaryEffect) implements ClientPacket { - public ClientSetBeaconEffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BOOLEAN) ? PotionType.fromId(reader.read(VAR_INT)) : null, - reader.read(BOOLEAN) ? PotionType.fromId(reader.read(VAR_INT)) : null); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientSetBeaconEffectPacket value) { + buffer.write(BOOLEAN, value.primaryEffect != null); + if (value.primaryEffect != null) buffer.write(VAR_INT, value.primaryEffect.id()); + buffer.write(BOOLEAN, value.secondaryEffect != null); + if (value.secondaryEffect != null) buffer.write(VAR_INT, value.secondaryEffect.id()); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, primaryEffect != null); - if (primaryEffect != null) writer.write(VAR_INT, primaryEffect.id()); - writer.write(BOOLEAN, secondaryEffect != null); - if (secondaryEffect != null) writer.write(VAR_INT, secondaryEffect.id()); - } + @Override + public ClientSetBeaconEffectPacket read(@NotNull NetworkBuffer buffer) { + return new ClientSetBeaconEffectPacket(buffer.read(BOOLEAN) ? PotionType.fromId(buffer.read(VAR_INT)) : null, + buffer.read(BOOLEAN) ? PotionType.fromId(buffer.read(VAR_INT)) : null); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java index f534f9c62..38f6b1c48 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java @@ -1,24 +1,20 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientSetDisplayedRecipePacket(@NotNull String recipeId) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientSetDisplayedRecipePacket::recipeId, + ClientSetDisplayedRecipePacket::new); + public ClientSetDisplayedRecipePacket { if (recipeId.length() > 256) { throw new IllegalArgumentException("'recipeId' cannot be longer than 256 characters."); } } - - public ClientSetDisplayedRecipePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, recipeId); - } -} \ No newline at end of file +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetRecipeBookStatePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetRecipeBookStatePacket.java index f9109124a..21d93b0af 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetRecipeBookStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetRecipeBookStatePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -8,16 +9,11 @@ import static net.minestom.server.network.NetworkBuffer.BOOLEAN; public record ClientSetRecipeBookStatePacket(@NotNull BookType bookType, boolean bookOpen, boolean filterActive) implements ClientPacket { - public ClientSetRecipeBookStatePacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(BookType.class), reader.read(BOOLEAN), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(BookType.class, bookType); - writer.write(BOOLEAN, bookOpen); - writer.write(BOOLEAN, filterActive); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(BookType.class), ClientSetRecipeBookStatePacket::bookType, + BOOLEAN, ClientSetRecipeBookStatePacket::bookOpen, + BOOLEAN, ClientSetRecipeBookStatePacket::filterActive, + ClientSetRecipeBookStatePacket::new); public enum BookType { CRAFTING, FURNACE, BLAST_FURNACE, SMOKER diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java index 3693b80e8..2f5d9dd87 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java @@ -13,22 +13,25 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientSignedCommandChatPacket(@NotNull String message, long timestamp, long salt, @NotNull ArgumentSignatures signatures, LastSeenMessages.@NotNull Update lastSeenMessages) implements ClientPacket { + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientSignedCommandChatPacket value) { + buffer.write(STRING, value.message); + buffer.write(LONG, value.timestamp); + buffer.write(LONG, value.salt); + buffer.write(value.signatures); + buffer.write(value.lastSeenMessages); + } + + @Override + public ClientSignedCommandChatPacket read(@NotNull NetworkBuffer buffer) { + return new ClientSignedCommandChatPacket(buffer.read(STRING), buffer.read(LONG), + buffer.read(LONG), new ArgumentSignatures(buffer), + new LastSeenMessages.Update(buffer)); + } + }; + public ClientSignedCommandChatPacket { Check.argCondition(message.length() > 256, "Message length cannot be greater than 256"); } - - public ClientSignedCommandChatPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(LONG), - reader.read(LONG), new ArgumentSignatures(reader), - new LastSeenMessages.Update(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, message); - writer.write(LONG, timestamp); - writer.write(LONG, salt); - writer.write(signatures); - writer.write(lastSeenMessages); - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSpectatePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSpectatePacket.java index cfdc5dbb8..abeb2e091 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSpectatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSpectatePacket.java @@ -1,23 +1,19 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import java.util.UUID; /** - * The ClientSpectatePacket is sent when the client interacts with their hotbar to switch between entities. + * The ClientSpectatePacket is sent when the client interacts with their hot-bar to switch between entities. * Contrary to its name, it is actually used to teleport the player to the entity they are switching to, * rather than spectating them. */ public record ClientSpectatePacket(@NotNull UUID target) implements ClientPacket { - public ClientSpectatePacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, target); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.UUID, ClientSpectatePacket::target, + ClientSpectatePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientStatusPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientStatusPacket.java index 079aeb3f1..75f4102c4 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientStatusPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientStatusPacket.java @@ -1,18 +1,14 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; public record ClientStatusPacket(@NotNull Action action) implements ClientPacket { - public ClientStatusPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Action.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Action.class, action); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(Action.class), ClientStatusPacket::action, + ClientStatusPacket::new); public enum Action { PERFORM_RESPAWN, diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerBoatPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerBoatPacket.java index 05ed9b36d..21914b20c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerBoatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerBoatPacket.java @@ -1,19 +1,14 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; public record ClientSteerBoatPacket(boolean leftPaddleTurning, boolean rightPaddleTurning) implements ClientPacket { - public ClientSteerBoatPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BOOLEAN), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, leftPaddleTurning); - writer.write(BOOLEAN, rightPaddleTurning); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BOOLEAN, ClientSteerBoatPacket::leftPaddleTurning, + BOOLEAN, ClientSteerBoatPacket::rightPaddleTurning, + ClientSteerBoatPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java index 95cb55f81..f5279496b 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java @@ -1,22 +1,17 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.FLOAT; public record ClientSteerVehiclePacket(float sideways, float forward, byte flags) implements ClientPacket { - public ClientSteerVehiclePacket(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(FLOAT), reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, sideways); - writer.write(FLOAT, forward); - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, ClientSteerVehiclePacket::sideways, + FLOAT, ClientSteerVehiclePacket::forward, + BYTE, ClientSteerVehiclePacket::flags, + ClientSteerVehiclePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientTabCompletePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientTabCompletePacket.java index 857d7b370..a8e6c3656 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientTabCompletePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientTabCompletePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -8,13 +9,8 @@ import static net.minestom.server.network.NetworkBuffer.STRING; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientTabCompletePacket(int transactionId, @NotNull String text) implements ClientPacket { - public ClientTabCompletePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, transactionId); - writer.write(STRING, text); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientTabCompletePacket::transactionId, + STRING, ClientTabCompletePacket::text, + ClientTabCompletePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientTeleportConfirmPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientTeleportConfirmPacket.java index 374f8853d..cc7158991 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientTeleportConfirmPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientTeleportConfirmPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientTeleportConfirmPacket(int teleportId) implements ClientPacket { - public ClientTeleportConfirmPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, teleportId); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientTeleportConfirmPacket::teleportId, + ClientTeleportConfirmPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockMinecartPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockMinecartPacket.java index 0a87117b9..83d92af01 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockMinecartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockMinecartPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -8,14 +9,9 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientUpdateCommandBlockMinecartPacket(int entityId, @NotNull String command, boolean trackOutput) implements ClientPacket { - public ClientUpdateCommandBlockMinecartPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(STRING), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(STRING, command); - writer.write(BOOLEAN, trackOutput); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientUpdateCommandBlockMinecartPacket::entityId, + STRING, ClientUpdateCommandBlockMinecartPacket::command, + BOOLEAN, ClientUpdateCommandBlockMinecartPacket::trackOutput, + ClientUpdateCommandBlockMinecartPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockPacket.java index 5c8890f27..7ad67f9b6 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateCommandBlockPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -9,18 +10,12 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientUpdateCommandBlockPacket(@NotNull Point blockPosition, @NotNull String command, @NotNull Mode mode, byte flags) implements ClientPacket { - public ClientUpdateCommandBlockPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(STRING), - Mode.values()[reader.read(VAR_INT)], reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(STRING, command); - writer.write(VAR_INT, mode.ordinal()); - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, ClientUpdateCommandBlockPacket::blockPosition, + STRING, ClientUpdateCommandBlockPacket::command, + Enum(Mode.class), ClientUpdateCommandBlockPacket::mode, + BYTE, ClientUpdateCommandBlockPacket::flags, + ClientUpdateCommandBlockPacket::new); public enum Mode { SEQUENCE, AUTO, REDSTONE diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateSignPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateSignPacket.java index 19d1a24b1..fc4ea942c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateSignPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateSignPacket.java @@ -26,19 +26,22 @@ public record ClientUpdateSignPacket( } } - public ClientUpdateSignPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(BOOLEAN), readLines(reader)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull ClientUpdateSignPacket value) { + buffer.write(BLOCK_POSITION, value.blockPosition); + buffer.write(BOOLEAN, value.isFrontText); + buffer.write(STRING, value.lines.get(0)); + buffer.write(STRING, value.lines.get(1)); + buffer.write(STRING, value.lines.get(2)); + buffer.write(STRING, value.lines.get(3)); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(BOOLEAN, isFrontText); - writer.write(STRING, lines.get(0)); - writer.write(STRING, lines.get(1)); - writer.write(STRING, lines.get(2)); - writer.write(STRING, lines.get(3)); - } + @Override + public @NotNull ClientUpdateSignPacket read(@NotNull NetworkBuffer buffer) { + return new ClientUpdateSignPacket(buffer.read(BLOCK_POSITION), buffer.read(BOOLEAN), readLines(buffer)); + } + }; private static List readLines(@NotNull NetworkBuffer reader) { return List.of(reader.read(STRING), reader.read(STRING), diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java index aa4daa072..6e2705ba0 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java @@ -15,14 +15,37 @@ public record ClientUpdateStructureBlockPacket(Point location, Action action, Mirror mirror, Rotation rotation, String metadata, float integrity, long seed, byte flags) implements ClientPacket { - public ClientUpdateStructureBlockPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.readEnum(Action.class), - reader.readEnum(Mode.class), reader.read(STRING), - new Vec(reader.read(BYTE), reader.read(BYTE), reader.read(BYTE)), new Vec(reader.read(BYTE), reader.read(BYTE), reader.read(BYTE)), - Mirror.values()[reader.read(VAR_INT)], fromRestrictedRotation(reader.read(VAR_INT)), - reader.read(STRING), reader.read(FLOAT), - reader.read(VAR_LONG), reader.read(BYTE)); - } + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ClientUpdateStructureBlockPacket value) { + buffer.write(BLOCK_POSITION, value.location); + buffer.writeEnum(Action.class, value.action); + buffer.writeEnum(Mode.class, value.mode); + buffer.write(STRING, value.name); + buffer.write(BYTE, (byte) value.offset.x()); + buffer.write(BYTE, (byte) value.offset.y()); + buffer.write(BYTE, (byte) value.offset.z()); + buffer.write(BYTE, (byte) value.size.x()); + buffer.write(BYTE, (byte) value.size.y()); + buffer.write(BYTE, (byte) value.size.z()); + buffer.write(VAR_INT, value.mirror.ordinal()); + buffer.write(VAR_INT, toRestrictedRotation(value.rotation)); + buffer.write(STRING, value.metadata); + buffer.write(FLOAT, value.integrity); + buffer.write(VAR_LONG, value.seed); + buffer.write(BYTE, value.flags); + } + + @Override + public ClientUpdateStructureBlockPacket read(@NotNull NetworkBuffer buffer) { + return new ClientUpdateStructureBlockPacket(buffer.read(BLOCK_POSITION), buffer.readEnum(Action.class), + buffer.readEnum(Mode.class), buffer.read(STRING), + new Vec(buffer.read(BYTE), buffer.read(BYTE), buffer.read(BYTE)), new Vec(buffer.read(BYTE), buffer.read(BYTE), buffer.read(BYTE)), + Mirror.values()[buffer.read(VAR_INT)], fromRestrictedRotation(buffer.read(VAR_INT)), + buffer.read(STRING), buffer.read(FLOAT), + buffer.read(VAR_LONG), buffer.read(BYTE)); + } + }; // Flag values public static final byte IGNORE_ENTITIES = 0x1; @@ -32,26 +55,6 @@ public record ClientUpdateStructureBlockPacket(Point location, Action action, */ public static final byte SHOW_BOUNDING_BOX = 0x4; - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, location); - writer.writeEnum(Action.class, action); - writer.writeEnum(Mode.class, mode); - writer.write(STRING, name); - writer.write(BYTE, (byte) offset.x()); - writer.write(BYTE, (byte) offset.y()); - writer.write(BYTE, (byte) offset.z()); - writer.write(BYTE, (byte) size.x()); - writer.write(BYTE, (byte) size.y()); - writer.write(BYTE, (byte) size.z()); - writer.write(VAR_INT, mirror.ordinal()); - writer.write(VAR_INT, toRestrictedRotation(rotation)); - writer.write(STRING, metadata); - writer.write(FLOAT, integrity); - writer.write(VAR_LONG, seed); - writer.write(BYTE, flags); - } - /** * Update action, UPDATE_DATA indicates nothing special. */ diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java index c39e143d2..6ca7d8037 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUseItemPacket.java @@ -2,22 +2,18 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.VAR_INT; +import static net.minestom.server.network.NetworkBuffer.*; -public record ClientUseItemPacket(@NotNull PlayerHand hand, int sequence, float yaw, float pitch) implements ClientPacket { - public ClientUseItemPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(PlayerHand.class), reader.read(VAR_INT), - reader.read(NetworkBuffer.FLOAT), reader.read(NetworkBuffer.FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(PlayerHand.class, hand); - writer.write(VAR_INT, sequence); - writer.write(NetworkBuffer.FLOAT, yaw); - writer.write(NetworkBuffer.FLOAT, pitch); - } +public record ClientUseItemPacket(@NotNull PlayerHand hand, int sequence, float yaw, + float pitch) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Enum(PlayerHand.class), ClientUseItemPacket::hand, + VAR_INT, ClientUseItemPacket::sequence, + FLOAT, ClientUseItemPacket::yaw, + FLOAT, ClientUseItemPacket::pitch, + ClientUseItemPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientVehicleMovePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientVehicleMovePacket.java index ffbba4177..f72a18d96 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientVehicleMovePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientVehicleMovePacket.java @@ -2,24 +2,14 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.DOUBLE; -import static net.minestom.server.network.NetworkBuffer.FLOAT; +import static net.minestom.server.network.NetworkBuffer.POS; public record ClientVehicleMovePacket(@NotNull Pos position) implements ClientPacket { - public ClientVehicleMovePacket(@NotNull NetworkBuffer reader) { - this(new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(FLOAT), reader.read(FLOAT))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(FLOAT, position.yaw()); - writer.write(FLOAT, position.pitch()); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + POS, ClientVehicleMovePacket::position, + ClientVehicleMovePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientWindowSlotStatePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientWindowSlotStatePacket.java index fd0cb5e3d..2894b7c6f 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientWindowSlotStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientWindowSlotStatePacket.java @@ -1,23 +1,17 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.VAR_INT; // This is the packet sent when you toggle a slot in a crafter UI public record ClientWindowSlotStatePacket(int slot, int windowId, boolean newState) implements ClientPacket { - - public ClientWindowSlotStatePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, slot); - writer.write(VAR_INT, windowId); - writer.write(BOOLEAN, newState); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientWindowSlotStatePacket::slot, + VAR_INT, ClientWindowSlotStatePacket::windowId, + BOOLEAN, ClientWindowSlotStatePacket::newState, + ClientWindowSlotStatePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/status/LegacyServerListPingPacket.java b/src/main/java/net/minestom/server/network/packet/client/status/LegacyServerListPingPacket.java index 8e3e31af1..d85cb628a 100644 --- a/src/main/java/net/minestom/server/network/packet/client/status/LegacyServerListPingPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/status/LegacyServerListPingPacket.java @@ -1,18 +1,13 @@ package net.minestom.server.network.packet.client.status; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record LegacyServerListPingPacket(byte payload) implements ClientPacket { - public LegacyServerListPingPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, payload); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, LegacyServerListPingPacket::payload, + LegacyServerListPingPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java b/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java index ed3809876..27c9932da 100644 --- a/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java @@ -1,21 +1,14 @@ package net.minestom.server.network.packet.client.status; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; public record StatusRequestPacket() implements ClientPacket { - public StatusRequestPacket(@NotNull NetworkBuffer reader) { - this(); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(StatusRequestPacket::new); @Override public boolean processImmediately() { return true; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - // Empty - } } 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 ab9668310..b41ee4f42 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,7 +1,6 @@ package net.minestom.server.network.packet.server; import net.minestom.server.adventure.ComponentHolder; -import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.player.PlayerConnection; /** @@ -9,7 +8,7 @@ import net.minestom.server.network.player.PlayerConnection; *

* Packets are value-based, and should therefore not be reliant on identity. */ -public sealed interface ServerPacket extends NetworkBuffer.Writer, SendablePacket permits +public sealed interface ServerPacket extends SendablePacket permits ServerPacket.Configuration, ServerPacket.Status, ServerPacket.Login, ServerPacket.Play { non-sealed interface Configuration extends ServerPacket { diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java index 8bd739e3e..8018d5ebd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CookieRequestPacket.java @@ -1,19 +1,15 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; +import static net.minestom.server.network.NetworkBuffer.STRING; + public record CookieRequestPacket(@NotNull String key) implements ServerPacket.Login, ServerPacket.Configuration, ServerPacket.Play { - - public CookieRequestPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, key); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, CookieRequestPacket::key, + CookieRequestPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java index ca9279477..1cff9e501 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CookieStorePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.validate.Check; @@ -11,6 +12,11 @@ public record CookieStorePacket( ) implements ServerPacket.Configuration, ServerPacket.Play { public static final int MAX_VALUE_LENGTH = 5120; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.STRING, CookieStorePacket::key, + NetworkBuffer.BYTE_ARRAY, CookieStorePacket::value, + CookieStorePacket::new); + public CookieStorePacket { Check.argCondition(value.length > MAX_VALUE_LENGTH, "Cookie value length too long: {0} > {1}", value.length, MAX_VALUE_LENGTH); } @@ -18,27 +24,4 @@ public record CookieStorePacket( public CookieStorePacket(@NotNull NamespaceID key, byte[] value) { this(key.asString(), value); } - - public CookieStorePacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } - - private CookieStorePacket(@NotNull CookieStorePacket other) { - this(other.key, other.value); - } - - private static @NotNull CookieStorePacket read(@NotNull NetworkBuffer reader) { - String key = reader.read(NetworkBuffer.STRING); - int valueLength = reader.read(NetworkBuffer.VAR_INT); - Check.argCondition(valueLength > MAX_VALUE_LENGTH, "Cookie value length too long: {0} > {1}", valueLength, MAX_VALUE_LENGTH); - byte[] value = reader.readBytes(valueLength); - return new CookieStorePacket(key, value); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, key); - writer.write(NetworkBuffer.BYTE_ARRAY, value); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java index 2adf6638e..962f3a072 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java @@ -11,17 +11,19 @@ public record CustomReportDetailsPacket( ) implements ServerPacket.Configuration, ServerPacket.Play { private static final int MAX_DETAILS = 32; + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, CustomReportDetailsPacket packet) { + buffer.writeMap(NetworkBuffer.STRING, NetworkBuffer.STRING, packet.details); + } + + @Override + public CustomReportDetailsPacket read(@NotNull NetworkBuffer buffer) { + return new CustomReportDetailsPacket(buffer.readMap(NetworkBuffer.STRING, NetworkBuffer.STRING, MAX_DETAILS)); + } + }; + public CustomReportDetailsPacket { details = Map.copyOf(details); } - - public CustomReportDetailsPacket(@NotNull NetworkBuffer reader) { - this(reader.readMap(NetworkBuffer.STRING, NetworkBuffer.STRING, MAX_DETAILS)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeMap(NetworkBuffer.STRING, NetworkBuffer.STRING, details); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java index d25fdf3c1..5090071b5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/DisconnectPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.common; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -13,14 +14,8 @@ import static net.minestom.server.network.NetworkBuffer.COMPONENT; public record DisconnectPacket(@NotNull Component message) implements ServerPacket.Configuration, ServerPacket.Play, ServerPacket.ComponentHolding { - public DisconnectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, message); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, DisconnectPacket::message, DisconnectPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java index b3db14494..4a06d0ec4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/KeepAlivePacket.java @@ -1,19 +1,12 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; public record KeepAlivePacket(long id) implements ServerPacket.Configuration, ServerPacket.Play { - public KeepAlivePacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, id); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, KeepAlivePacket::id, KeepAlivePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java index 2a796c6d6..19085a573 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PingPacket.java @@ -1,19 +1,12 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; public record PingPacket(int id) implements ServerPacket.Configuration, ServerPacket.Play { - public PingPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, id); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, PingPacket::id, PingPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java index 01637df61..791a04205 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PingResponsePacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; public record PingResponsePacket(long number) implements ServerPacket.Status, ServerPacket.Play { - public PingResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, number); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, PingResponsePacket::number, + PingResponsePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java index f35a390d1..05203ce84 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -9,15 +10,10 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public record PluginMessagePacket(String channel, byte[] data) implements ServerPacket.Configuration, ServerPacket.Play { - public PluginMessagePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(RAW_BYTES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, channel); - writer.write(RAW_BYTES, data); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, PluginMessagePacket::channel, + RAW_BYTES, PluginMessagePacket::data, + PluginMessagePacket::new); /** * Gets the current server brand name packet. diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java index cfc6d3143..7a4b30aa1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPopPacket.java @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; public record ResourcePackPopPacket(@Nullable UUID id) implements ServerPacket.Configuration, ServerPacket.Play { - public ResourcePackPopPacket(@NotNull NetworkBuffer reader) { - this(reader.readOptional(NetworkBuffer.UUID)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeOptional(NetworkBuffer.UUID, id); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.UUID.optional(), ResourcePackPopPacket::id, + ResourcePackPopPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java index 5c1803f21..81f0b47c0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ResourcePackPushPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.common; import net.kyori.adventure.resource.ResourcePackInfo; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +13,7 @@ import java.util.List; import java.util.UUID; import java.util.function.UnaryOperator; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.COMPONENT; public record ResourcePackPushPacket( @NotNull UUID id, @@ -21,24 +22,18 @@ public record ResourcePackPushPacket( boolean forced, @Nullable Component prompt ) implements ServerPacket.Configuration, ServerPacket.Play, ServerPacket.ComponentHolding { - public ResourcePackPushPacket(@NotNull NetworkBuffer reader) { - this(reader.read(UUID), reader.read(STRING), reader.read(STRING), - reader.read(BOOLEAN), reader.readOptional(COMPONENT)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.UUID, ResourcePackPushPacket::id, + NetworkBuffer.STRING, ResourcePackPushPacket::url, + NetworkBuffer.STRING, ResourcePackPushPacket::hash, + NetworkBuffer.BOOLEAN, ResourcePackPushPacket::forced, + COMPONENT.optional(), ResourcePackPushPacket::prompt, + ResourcePackPushPacket::new); public ResourcePackPushPacket(@NotNull ResourcePackInfo resourcePackInfo, boolean required, @Nullable Component prompt) { this(resourcePackInfo.id(), resourcePackInfo.uri().toString(), resourcePackInfo.hash(), required, prompt); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(UUID, id); - writer.write(STRING, url); - writer.write(STRING, hash); - writer.write(BOOLEAN, forced); - writer.writeOptional(COMPONENT, prompt); - } - @Override public @NotNull Collection components() { return List.of(this.prompt); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java index 10b5ab9d7..88a33110a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.common; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -12,6 +13,10 @@ import java.util.List; public record ServerLinksPacket(@NotNull List entries) implements ServerPacket.Configuration, ServerPacket.Play { private static final int MAX_ENTRIES = 100; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Entry.NETWORK_TYPE.list(MAX_ENTRIES), ServerLinksPacket::entries, + ServerLinksPacket::new); + public ServerLinksPacket { entries = List.copyOf(entries); } @@ -20,15 +25,6 @@ public record ServerLinksPacket(@NotNull List entries) implements ServerP this(List.of(entries)); } - public ServerLinksPacket(@NotNull NetworkBuffer reader) { - this(reader.read(Entry.LIST_NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(Entry.LIST_NETWORK_TYPE, entries); - } - public record Entry(@Nullable KnownLinkType knownType, @Nullable Component customType, @NotNull String link) { public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java index 7f0002e85..d1270c54d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java @@ -17,32 +17,35 @@ public record TagsPacket( tagsMap = Map.copyOf(tagsMap); } - public TagsPacket(@NotNull NetworkBuffer reader) { - this(readTagsMap(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, tagsMap.size()); - for (var entry : tagsMap.entrySet()) { - final var type = entry.getKey(); - final var tags = entry.getValue(); - writer.write(STRING, type.getIdentifier()); - if (type.getFunction() == null) { - writer.write(VAR_INT, 0); - continue; - } - writer.write(VAR_INT, tags.size()); - for (var tag : tags) { - writer.write(STRING, tag.name()); - final var values = tag.getValues(); - writer.write(VAR_INT, values.size()); - for (var name : values) { - writer.write(VAR_INT, type.getFunction().apply(name.asString())); + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, TagsPacket packet) { + buffer.write(VAR_INT, packet.tagsMap.size()); + for (var entry : packet.tagsMap.entrySet()) { + final var type = entry.getKey(); + final var tags = entry.getValue(); + buffer.write(STRING, type.getIdentifier()); + if (type.getFunction() == null) { + buffer.write(VAR_INT, 0); + continue; + } + buffer.write(VAR_INT, tags.size()); + for (var tag : tags) { + buffer.write(STRING, tag.name()); + final var values = tag.getValues(); + buffer.write(VAR_INT, values.size()); + for (var name : values) { + buffer.write(VAR_INT, type.getFunction().apply(name.asString())); + } } } } - } + + @Override + public TagsPacket read(@NotNull NetworkBuffer buffer) { + return new TagsPacket(readTagsMap(buffer)); + } + }; private static Map> readTagsMap(@NotNull NetworkBuffer reader) { Map> tagsMap = new EnumMap<>(Tag.BasicType.class); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java index 17cab834b..47d0c996e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TransferPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -8,15 +9,8 @@ public record TransferPacket( @NotNull String host, int port ) implements ServerPacket.Configuration, ServerPacket.Play { - - public TransferPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.STRING), reader.read(NetworkBuffer.VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, host); - writer.write(NetworkBuffer.VAR_INT, port); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.STRING, TransferPacket::host, + NetworkBuffer.VAR_INT, TransferPacket::port, + TransferPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java index 51386647e..97ad08d35 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/FinishConfigurationPacket.java @@ -1,16 +1,9 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record FinishConfigurationPacket() implements ServerPacket.Configuration { - public FinishConfigurationPacket(@NotNull NetworkBuffer buffer) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(FinishConfigurationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java index 7b7275911..6d9ac4c07 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/RegistryDataPacket.java @@ -1,7 +1,8 @@ package net.minestom.server.network.packet.server.configuration; -import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.BinaryTag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,30 +16,16 @@ public record RegistryDataPacket( @NotNull String registryId, @NotNull List entries ) implements ServerPacket.Configuration { - - public RegistryDataPacket(@NotNull NetworkBuffer buffer) { - this(buffer.read(STRING), buffer.readCollection(Entry::new, Integer.MAX_VALUE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, registryId); - writer.writeCollection(entries); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, RegistryDataPacket::registryId, + Entry.SERIALIZER.list(Integer.MAX_VALUE), RegistryDataPacket::entries, + RegistryDataPacket::new); public record Entry( @NotNull String id, - @Nullable CompoundBinaryTag data - ) implements NetworkBuffer.Writer { - - public Entry(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), (CompoundBinaryTag) reader.readOptional(NBT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, id); - writer.writeOptional(NBT, data); - } + @Nullable BinaryTag data + ) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Entry::id, NBT.optional(), Entry::data, Entry::new); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java index dec8daa25..2765604c4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/ResetChatPacket.java @@ -1,18 +1,9 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record ResetChatPacket() implements ServerPacket.Configuration { - - public ResetChatPacket(@NotNull NetworkBuffer reader) { - this(); // No fields - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - // No fields - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ResetChatPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java index e13deff54..678bf01b3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/SelectKnownPacksPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.MinecraftServer; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -12,39 +13,26 @@ public record SelectKnownPacksPacket( @NotNull List entries ) implements ServerPacket.Configuration { private static final int MAX_ENTRIES = 64; - public static final Entry MINECRAFT_CORE = new Entry("minecraft", "core", MinecraftServer.VERSION_NAME); + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Entry.SERIALIZER.list(MAX_ENTRIES), SelectKnownPacksPacket::entries, + SelectKnownPacksPacket::new); + public SelectKnownPacksPacket { Check.argCondition(entries.size() > MAX_ENTRIES, "Too many known packs: {0} > {1}", entries.size(), MAX_ENTRIES); entries = List.copyOf(entries); } - public SelectKnownPacksPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(Entry::new, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(entries); - } - public record Entry( @NotNull String namespace, @NotNull String id, @NotNull String version - ) implements NetworkBuffer.Writer { - public Entry(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.STRING), - reader.read(NetworkBuffer.STRING), - reader.read(NetworkBuffer.STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, namespace); - writer.write(NetworkBuffer.STRING, id); - writer.write(NetworkBuffer.STRING, version); - } + ) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.STRING, Entry::namespace, + NetworkBuffer.STRING, Entry::id, + NetworkBuffer.STRING, Entry::version, + Entry::new); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java index 3df4450e1..d386867c6 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java @@ -1,24 +1,25 @@ package net.minestom.server.network.packet.server.configuration; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; -import java.util.Set; +import java.util.List; import static net.minestom.server.network.NetworkBuffer.STRING; -public record UpdateEnabledFeaturesPacket(@NotNull Set features) implements ServerPacket.Configuration { +public record UpdateEnabledFeaturesPacket(@NotNull List features) implements ServerPacket.Configuration { public static final int MAX_FEATURES = 1024; - public UpdateEnabledFeaturesPacket(@NotNull NetworkBuffer buffer) { - this(Set.copyOf(buffer.readCollection((b) -> NamespaceID.from(b.read(STRING)), MAX_FEATURES))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(features, (b, feature) -> b.write(STRING, feature.asString())); + public UpdateEnabledFeaturesPacket { + if (features.size() > MAX_FEATURES) + throw new IllegalArgumentException("Too many features"); + features = List.copyOf(features); } + public static NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.list(MAX_FEATURES), UpdateEnabledFeaturesPacket::features, + UpdateEnabledFeaturesPacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java index 181d92d7d..3da6290f9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/EncryptionRequestPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,20 +13,10 @@ public record EncryptionRequestPacket( byte @NotNull [] verifyToken, boolean shouldAuthenticate ) implements ServerPacket.Login { - - public EncryptionRequestPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), - reader.read(BYTE_ARRAY), - reader.read(BYTE_ARRAY), - reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, serverId); - writer.write(BYTE_ARRAY, publicKey); - writer.write(BYTE_ARRAY, verifyToken); - writer.write(BOOLEAN, shouldAuthenticate); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, EncryptionRequestPacket::serverId, + BYTE_ARRAY, EncryptionRequestPacket::publicKey, + BYTE_ARRAY, EncryptionRequestPacket::verifyToken, + BOOLEAN, EncryptionRequestPacket::shouldAuthenticate, + EncryptionRequestPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java index 8b6f5926a..2649d0ecd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginDisconnectPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.login; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -13,14 +14,9 @@ import static net.minestom.server.network.NetworkBuffer.JSON_COMPONENT; public record LoginDisconnectPacket(@NotNull Component kickMessage) implements ServerPacket.Login, ServerPacket.ComponentHolding { - public LoginDisconnectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(JSON_COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(JSON_COMPONENT, kickMessage); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + JSON_COMPONENT, LoginDisconnectPacket::kickMessage, + LoginDisconnectPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java index 9daf69e9e..8783ddaa0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginPluginRequestPacket.java @@ -1,26 +1,17 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.*; public record LoginPluginRequestPacket(int messageId, @NotNull String channel, - byte @Nullable [] data) implements ServerPacket.Login { - public LoginPluginRequestPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(STRING), - reader.read(RAW_BYTES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, messageId); - writer.write(STRING, channel); - if (data != null && data.length > 0) { - writer.write(RAW_BYTES, data); - } - } - + byte[] data) implements ServerPacket.Login { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, LoginPluginRequestPacket::messageId, + STRING, LoginPluginRequestPacket::channel, + RAW_BYTES, LoginPluginRequestPacket::data, + LoginPluginRequestPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java index 1549818e9..e2d0a147d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -10,16 +11,10 @@ import static net.minestom.server.network.NetworkBuffer.*; public record LoginSuccessPacket(@NotNull UUID uuid, @NotNull String username, int properties, boolean strictErrorHandling) implements ServerPacket.Login { - public LoginSuccessPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.read(VAR_INT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, uuid); - writer.write(STRING, username); - writer.write(VAR_INT, properties); - writer.write(BOOLEAN, strictErrorHandling); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + UUID, LoginSuccessPacket::uuid, + STRING, LoginSuccessPacket::username, + VAR_INT, LoginSuccessPacket::properties, + BOOLEAN, LoginSuccessPacket::strictErrorHandling, + LoginSuccessPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java index 4d09af3f4..749757ac9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/SetCompressionPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record SetCompressionPacket(int threshold) implements ServerPacket.Login { - public SetCompressionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, threshold); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, SetCompressionPacket::threshold, + SetCompressionPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java index f317d29c4..55775c0bf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AcknowledgeBlockChangePacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record AcknowledgeBlockChangePacket(int sequence) implements ServerPacket.Play { - public AcknowledgeBlockChangePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, sequence); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, AcknowledgeBlockChangePacket::sequence, + AcknowledgeBlockChangePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java index 262ba5f13..53ed40d67 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ActionBarPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,14 +13,9 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.COMPONENT; public record ActionBarPacket(@NotNull Component text) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public ActionBarPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, text); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, ActionBarPacket::text, + ActionBarPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java index e102063fe..27eac906e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java @@ -22,26 +22,32 @@ public record AdvancementsPacket(boolean reset, @NotNull List progressMappings) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final int MAX_ADVANCEMENTS = Short.MAX_VALUE; + public static NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, AdvancementsPacket value) { + buffer.write(BOOLEAN, value.reset); + buffer.writeCollection(value.advancementMappings); + buffer.writeCollection(STRING, value.identifiersToRemove); + buffer.writeCollection(value.progressMappings); + } + + @Override + public AdvancementsPacket read(@NotNull NetworkBuffer buffer) { + return new AdvancementsPacket( + buffer.read(BOOLEAN), + buffer.readCollection(AdvancementMapping::new, MAX_ADVANCEMENTS), + buffer.readCollection(STRING, MAX_ADVANCEMENTS), + buffer.readCollection(ProgressMapping::new, MAX_ADVANCEMENTS) + ); + } + }; + public AdvancementsPacket { advancementMappings = List.copyOf(advancementMappings); identifiersToRemove = List.copyOf(identifiersToRemove); progressMappings = List.copyOf(progressMappings); } - public AdvancementsPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BOOLEAN), reader.readCollection(AdvancementMapping::new, MAX_ADVANCEMENTS), - reader.readCollection(STRING, MAX_ADVANCEMENTS), - reader.readCollection(ProgressMapping::new, MAX_ADVANCEMENTS)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, reset); - writer.writeCollection(advancementMappings); - writer.writeCollection(STRING, identifiersToRemove); - writer.writeCollection(progressMappings); - } - // TODO is the display-item needed to be updated? @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java index b8264ad29..62f18811f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AttachEntityPacket.java @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; public record AttachEntityPacket(int attachedEntityId, int holdingEntityId) implements ServerPacket.Play { - public AttachEntityPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT), reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, attachedEntityId); - writer.write(INT, holdingEntityId); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, AttachEntityPacket::attachedEntityId, + INT, AttachEntityPacket::holdingEntityId, + AttachEntityPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java index 7252b296a..3b55e8773 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockActionPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -10,21 +11,14 @@ import static net.minestom.server.network.NetworkBuffer.*; public record BlockActionPacket(@NotNull Point blockPosition, byte actionId, byte actionParam, int blockId) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, BlockActionPacket::blockPosition, + BYTE, BlockActionPacket::actionId, + BYTE, BlockActionPacket::actionParam, + VAR_INT, BlockActionPacket::blockId, + BlockActionPacket::new); + public BlockActionPacket(Point blockPosition, byte actionId, byte actionParam, Block block) { this(blockPosition, actionId, actionParam, block.id()); } - - public BlockActionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(BYTE), - reader.read(BYTE), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(BYTE, actionId); - writer.write(BYTE, actionParam); - writer.write(VAR_INT, blockId); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java index 698efd752..281af1ae5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockBreakAnimationPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -9,15 +10,9 @@ import static net.minestom.server.network.NetworkBuffer.*; public record BlockBreakAnimationPacket(int entityId, @NotNull Point blockPosition, byte destroyStage) implements ServerPacket.Play { - public BlockBreakAnimationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(BLOCK_POSITION), reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(BLOCK_POSITION, blockPosition); - writer.write(BYTE, destroyStage); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, BlockBreakAnimationPacket::entityId, + BLOCK_POSITION, BlockBreakAnimationPacket::blockPosition, + BYTE, BlockBreakAnimationPacket::destroyStage, + BlockBreakAnimationPacket::new); } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java index d613263ae..23b70d8ca 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockChangePacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -10,18 +11,12 @@ import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record BlockChangePacket(@NotNull Point blockPosition, int blockStateId) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, BlockChangePacket::blockPosition, + VAR_INT, BlockChangePacket::blockStateId, + BlockChangePacket::new); + public BlockChangePacket(@NotNull Point blockPosition, @NotNull Block block) { this(blockPosition, block.stateId()); } - - public BlockChangePacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(VAR_INT, blockStateId); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java index a648e8cda..fceecd900 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java @@ -11,20 +11,22 @@ import static net.minestom.server.network.NetworkBuffer.*; public record BlockEntityDataPacket(@NotNull Point blockPosition, int action, @Nullable CompoundBinaryTag data) implements ServerPacket.Play { - public BlockEntityDataPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, blockPosition); - writer.write(VAR_INT, action); - if (data != null) { - writer.write(NBT, data); - } else { - // TAG_End - writer.write(BYTE, (byte) 0x00); + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, BlockEntityDataPacket value) { + buffer.write(BLOCK_POSITION, value.blockPosition); + buffer.write(VAR_INT, value.action); + if (value.data != null) { + buffer.write(NBT, value.data); + } else { + // TAG_End + buffer.write(BYTE, (byte) 0x00); + } } - } + @Override + public BlockEntityDataPacket read(@NotNull NetworkBuffer buffer) { + return new BlockEntityDataPacket(buffer.read(BLOCK_POSITION), buffer.read(VAR_INT), (CompoundBinaryTag) buffer.read(NBT)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java index 14d9ed884..4ea9b2410 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java @@ -15,25 +15,29 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.*; -public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public BossBarPacket(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID), switch (reader.read(VAR_INT)) { - case 0 -> new AddAction(reader); - case 1 -> new RemoveAction(); - case 2 -> new UpdateHealthAction(reader); - case 3 -> new UpdateTitleAction(reader); - case 4 -> new UpdateStyleAction(reader); - case 5 -> new UpdateFlagsAction(reader); - default -> throw new RuntimeException("Unknown action id"); - }); - } +public record BossBarPacket(@NotNull UUID uuid, + @NotNull Action action) implements ServerPacket.Play, ServerPacket.ComponentHolding { + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, BossBarPacket value) { + buffer.write(NetworkBuffer.UUID, value.uuid); + buffer.write(VAR_INT, value.action.id()); + buffer.write(value.action); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, uuid); - writer.write(VAR_INT, action.id()); - writer.write(action); - } + @Override + public BossBarPacket read(@NotNull NetworkBuffer buffer) { + return new BossBarPacket(buffer.read(NetworkBuffer.UUID), switch (buffer.read(VAR_INT)) { + case 0 -> new AddAction(buffer); + case 1 -> new RemoveAction(); + case 2 -> new UpdateHealthAction(buffer); + case 3 -> new UpdateTitleAction(buffer); + case 4 -> new UpdateStyleAction(buffer); + case 5 -> new UpdateFlagsAction(buffer); + default -> throw new RuntimeException("Unknown action id"); + }); + } + }; @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java index 610db7755..9a011cbe3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BundlePacket.java @@ -1,16 +1,9 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record BundlePacket() implements ServerPacket.Play { - public BundlePacket(@NotNull NetworkBuffer reader) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(BundlePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java index 1d220e236..6493d3a07 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CameraPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record CameraPacket(int cameraId) implements ServerPacket.Play { - public CameraPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, cameraId); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, CameraPacket::cameraId, + CameraPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java index 11be16242..5f2ca7e81 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChangeGameStatePacket.java @@ -8,15 +8,18 @@ import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.FLOAT; public record ChangeGameStatePacket(@NotNull Reason reason, float value) implements ServerPacket.Play { - public ChangeGameStatePacket(@NotNull NetworkBuffer reader) { - this(Reason.values()[reader.read(BYTE)], reader.read(FLOAT)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ChangeGameStatePacket value) { + buffer.write(BYTE, (byte) value.reason.ordinal()); + buffer.write(FLOAT, value.value); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, (byte) reason.ordinal()); - writer.write(FLOAT, value); - } + @Override + public ChangeGameStatePacket read(@NotNull NetworkBuffer buffer) { + return new ChangeGameStatePacket(Reason.values()[buffer.read(BYTE)], buffer.read(FLOAT)); + } + }; public enum Reason { NO_RESPAWN_BLOCK, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java index d5db4070b..439e1bf7e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchFinishedPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ChunkBatchFinishedPacket(int batchSize) implements ServerPacket.Play { - public ChunkBatchFinishedPacket(@NotNull NetworkBuffer buffer) { - this(buffer.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, batchSize); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ChunkBatchFinishedPacket::batchSize, + ChunkBatchFinishedPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java index d93e4a758..a56121cf2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBatchStartPacket.java @@ -1,16 +1,9 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record ChunkBatchStartPacket() implements ServerPacket.Play { - public ChunkBatchStartPacket(@NotNull NetworkBuffer buffer) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ChunkBatchStartPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index 2fcbf77bd..4751b6060 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -11,18 +11,20 @@ import static net.minestom.server.network.NetworkBuffer.INT; public record ChunkDataPacket(int chunkX, int chunkZ, @NotNull ChunkData chunkData, @NotNull LightData lightData) implements ServerPacket.Play { - public ChunkDataPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT), reader.read(INT), - new ChunkData(reader), - new LightData(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, chunkX); - writer.write(INT, chunkZ); - writer.write(chunkData); - writer.write(lightData); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ChunkDataPacket value) { + buffer.write(INT, value.chunkX); + buffer.write(INT, value.chunkZ); + buffer.write(value.chunkData); + buffer.write(value.lightData); + } + @Override + public ChunkDataPacket read(@NotNull NetworkBuffer buffer) { + return new ChunkDataPacket(buffer.read(INT), buffer.read(INT), + new ChunkData(buffer), + new LightData(buffer)); + } + }; } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java index 366418444..b50c9221c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ClearTitlesPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; public record ClearTitlesPacket(boolean reset) implements ServerPacket.Play { - public ClearTitlesPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, reset); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BOOLEAN, ClearTitlesPacket::reset, + ClearTitlesPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java index ee3a858c6..d2623524c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record CloseWindowPacket(byte windowId) implements ServerPacket.Play { - public CloseWindowPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, CloseWindowPacket::windowId, + CloseWindowPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java index acec0725b..94003f06b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CollectItemPacket.java @@ -1,22 +1,16 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record CollectItemPacket(int collectedEntityId, int collectorEntityId, int pickupItemCount) implements ServerPacket.Play { - public CollectItemPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, collectedEntityId); - writer.write(VAR_INT, collectorEntityId); - writer.write(VAR_INT, pickupItemCount); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, CollectItemPacket::collectedEntityId, + VAR_INT, CollectItemPacket::collectorEntityId, + VAR_INT, CollectItemPacket::pickupItemCount, + CollectItemPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java b/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java index 24c7fbd5a..400cf1baf 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java @@ -1,21 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.STRING; public record CraftRecipeResponse(byte windowId, String recipe) implements ServerPacket.Play { - public CraftRecipeResponse(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(STRING, recipe); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, CraftRecipeResponse::windowId, + STRING, CraftRecipeResponse::recipe, + CraftRecipeResponse::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java index df748a0cf..5efca2484 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CustomChatCompletionPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,20 +13,15 @@ public record CustomChatCompletionPacket(@NotNull Action action, @NotNull List<@NotNull String> entries) implements ServerPacket.Play { public static final int MAX_ENTRIES = Short.MAX_VALUE; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(Action.class), CustomChatCompletionPacket::action, + STRING.list(MAX_ENTRIES), CustomChatCompletionPacket::entries, + CustomChatCompletionPacket::new); + public CustomChatCompletionPacket { entries = List.copyOf(entries); } - public CustomChatCompletionPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Action.class), reader.readCollection(STRING, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Action.class, action); - writer.writeCollection(STRING, entries); - } - public enum Action { ADD, REMOVE, SET } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java index e1a01b6ed..c898372b0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DamageEventPacket.java @@ -2,8 +2,8 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -20,17 +20,11 @@ import static net.minestom.server.network.NetworkBuffer.VECTOR3D; */ public record DamageEventPacket(int targetEntityId, int damageTypeId, int sourceEntityId, int sourceDirectId, @Nullable Point sourcePos) implements ServerPacket.Play { - - public DamageEventPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readOptional(VECTOR3D)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, targetEntityId); - writer.write(VAR_INT, damageTypeId); - writer.write(VAR_INT, sourceEntityId); - writer.write(VAR_INT, sourceDirectId); - writer.writeOptional(VECTOR3D, sourcePos); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, DamageEventPacket::targetEntityId, + VAR_INT, DamageEventPacket::damageTypeId, + VAR_INT, DamageEventPacket::sourceEntityId, + VAR_INT, DamageEventPacket::sourceDirectId, + VECTOR3D.optional(), DamageEventPacket::sourcePos, + DamageEventPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java index 0b9cbda06..93a9fc12e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeathCombatEventPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,16 +13,12 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.COMPONENT; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record DeathCombatEventPacket(int playerId, @NotNull Component message) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public DeathCombatEventPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, playerId); - writer.write(COMPONENT, message); - } +public record DeathCombatEventPacket(int playerId, + @NotNull Component message) implements ServerPacket.Play, ServerPacket.ComponentHolding { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, DeathCombatEventPacket::playerId, + COMPONENT, DeathCombatEventPacket::message, + DeathCombatEventPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java index d361b9191..b7381b723 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DebugSamplePacket.java @@ -1,23 +1,20 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; +import static net.minestom.server.network.NetworkBuffer.Enum; +import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY; + public record DebugSamplePacket(long @NotNull [] sample, @NotNull Type type) implements ServerPacket.Play { - - public DebugSamplePacket(@NotNull NetworkBuffer buffer) { - this(buffer.read(NetworkBuffer.LONG_ARRAY), buffer.readEnum(Type.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.LONG_ARRAY, sample); - writer.writeEnum(Type.class, type); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG_ARRAY, DebugSamplePacket::sample, + Enum(Type.class), DebugSamplePacket::type, + DebugSamplePacket::new); public enum Type { TICK_TIME } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java index f7d78e4b2..920c6fcf2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java @@ -19,19 +19,22 @@ public record DeclareCommandsPacket(@NotNull List nodes, nodes = List.copyOf(nodes); } - public DeclareCommandsPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(r -> { - Node node = new Node(); - node.read(r); - return node; - }, MAX_NODES), reader.read(VAR_INT)); - } + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, DeclareCommandsPacket value) { + buffer.writeCollection(value.nodes); + buffer.write(VAR_INT, value.rootIndex); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(nodes); - writer.write(VAR_INT, rootIndex); - } + @Override + public DeclareCommandsPacket read(@NotNull NetworkBuffer buffer) { + return new DeclareCommandsPacket(buffer.readCollection(r -> { + Node node = new Node(); + node.read(r); + return node; + }, MAX_NODES), buffer.read(VAR_INT)); + } + }; public static final class Node implements NetworkBuffer.Writer { public byte flags; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java index 557237d02..260b48bd2 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeSerializers; @@ -11,17 +12,11 @@ import java.util.List; public record DeclareRecipesPacket(@NotNull List recipes) implements ServerPacket.Play { public static final int MAX_RECIPES = Short.MAX_VALUE; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + RecipeSerializers.RECIPE.list(MAX_RECIPES), DeclareRecipesPacket::recipes, + DeclareRecipesPacket::new); + public DeclareRecipesPacket { recipes = List.copyOf(recipes); } - - public DeclareRecipesPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(RecipeSerializers.RECIPE, MAX_RECIPES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(RecipeSerializers.RECIPE, recipes); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java index 0edaf70b1..cfe2b3846 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java @@ -6,13 +6,15 @@ import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; public record DeleteChatPacket(@NotNull MessageSignature signature) implements ServerPacket.Play { - public DeleteChatPacket(@NotNull NetworkBuffer reader) { - this(new MessageSignature(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(signature); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, DeleteChatPacket value) { + buffer.write(value.signature); + } + @Override + public DeleteChatPacket read(@NotNull NetworkBuffer buffer) { + return new DeleteChatPacket(new MessageSignature(buffer)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java index 66914fe90..e9b7a98f1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DestroyEntitiesPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,10 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record DestroyEntitiesPacket(@NotNull List entityIds) implements ServerPacket.Play { public static final int MAX_ENTRIES = Short.MAX_VALUE; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT.list(Short.MAX_VALUE), DestroyEntitiesPacket::entityIds, + DestroyEntitiesPacket::new); + public DestroyEntitiesPacket { entityIds = List.copyOf(entityIds); } @@ -18,14 +23,4 @@ public record DestroyEntitiesPacket(@NotNull List entityIds) implements public DestroyEntitiesPacket(int entityId) { this(List.of(entityId)); } - - public DestroyEntitiesPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(VAR_INT, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(VAR_INT, entityIds); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java index dc73fbddd..c69330132 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DisplayScoreboardPacket.java @@ -1,21 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.STRING; public record DisplayScoreboardPacket(byte position, String scoreName) implements ServerPacket.Play { - public DisplayScoreboardPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, position); - writer.write(STRING, scoreName); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, DisplayScoreboardPacket::position, + STRING, DisplayScoreboardPacket::scoreName, + DisplayScoreboardPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java index 7cd747ead..ca96c9df6 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EffectPacket.java @@ -2,23 +2,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record EffectPacket(int effectId, Point position, int data, boolean disableRelativeVolume) implements ServerPacket.Play { - public EffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT), reader.read(BLOCK_POSITION), reader.read(INT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, effectId); - writer.write(BLOCK_POSITION, position); - writer.write(INT, data); - writer.write(BOOLEAN, disableRelativeVolume); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, EffectPacket::effectId, + BLOCK_POSITION, EffectPacket::position, + INT, EffectPacket::data, + BOOLEAN, EffectPacket::disableRelativeVolume, + EffectPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java index b24b08679..a3d99958a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EndCombatEventPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EndCombatEventPacket(int duration) implements ServerPacket.Play { - public EndCombatEventPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, duration); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EndCombatEventPacket::duration, + EndCombatEventPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java index d4b66b046..8d91da9cc 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EnterCombatEventPacket.java @@ -1,17 +1,9 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record EnterCombatEventPacket() implements ServerPacket.Play { - public EnterCombatEventPacket(@NotNull NetworkBuffer reader) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - // Empty - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(EnterCombatEventPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java index 50cf1f5bd..fe1818074 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityAnimationPacket.java @@ -8,15 +8,18 @@ import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityAnimationPacket(int entityId, @NotNull Animation animation) implements ServerPacket.Play { - public EntityAnimationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), Animation.values()[reader.read(BYTE)]); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityAnimationPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(BYTE, (byte) value.animation.ordinal()); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(BYTE, (byte) animation.ordinal()); - } + @Override + public EntityAnimationPacket read(@NotNull NetworkBuffer buffer) { + return new EntityAnimationPacket(buffer.read(VAR_INT), Animation.values()[buffer.read(BYTE)]); + } + }; public enum Animation { SWING_MAIN_ARM, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java index f08afb3e9..ef645a47b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java @@ -3,8 +3,8 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.attribute.AttributeModifier; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.ServerPacketIdentifier; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -16,26 +16,15 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityAttributesPacket(int entityId, List properties) implements ServerPacket.Play { public static final int MAX_ENTRIES = 1024; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EntityAttributesPacket::entityId, + Property.NETWORK_TYPE.list(MAX_ENTRIES), EntityAttributesPacket::properties, + EntityAttributesPacket::new); + public EntityAttributesPacket { properties = List.copyOf(properties); } - public EntityAttributesPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readCollection(Property.NETWORK_TYPE, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.writeCollection(Property.NETWORK_TYPE, properties); - } - - @Override - public int playId() { - return ServerPacketIdentifier.ENTITY_ATTRIBUTES; - } - - public record Property(Attribute attribute, double value, Collection modifiers) { public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java index 51846fe8e..54aa967e5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java @@ -8,14 +8,16 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityEffectPacket(int entityId, @NotNull Potion potion) implements ServerPacket.Play { - public EntityEffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), new Potion(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(potion); - } + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityEffectPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(value.potion); + } + @Override + public EntityEffectPacket read(@NotNull NetworkBuffer buffer) { + return new EntityEffectPacket(buffer.read(VAR_INT), new Potion(buffer)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java index c2eb5170c..8641bd28e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java @@ -26,22 +26,25 @@ public record EntityEquipmentPacket(int entityId, throw new IllegalArgumentException("Equipments cannot be empty"); } - public EntityEquipmentPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), readEquipments(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - int index = 0; - for (var entry : equipments.entrySet()) { - final boolean last = index++ == equipments.size() - 1; - byte slotEnum = (byte) entry.getKey().ordinal(); - if (!last) slotEnum |= 0x80; - writer.write(BYTE, slotEnum); - writer.write(ItemStack.NETWORK_TYPE, entry.getValue()); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityEquipmentPacket value) { + buffer.write(VAR_INT, value.entityId); + int index = 0; + for (var entry : value.equipments.entrySet()) { + final boolean last = index++ == value.equipments.size() - 1; + byte slotEnum = (byte) entry.getKey().ordinal(); + if (!last) slotEnum |= 0x80; + buffer.write(BYTE, slotEnum); + buffer.write(ItemStack.NETWORK_TYPE, entry.getValue()); + } } - } + + @Override + public EntityEquipmentPacket read(@NotNull NetworkBuffer buffer) { + return new EntityEquipmentPacket(buffer.read(VAR_INT), readEquipments(buffer)); + } + }; @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java index d7fb70afc..3050c36b5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityHeadLookPacket.java @@ -8,14 +8,16 @@ import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityHeadLookPacket(int entityId, float yaw) implements ServerPacket.Play { - public EntityHeadLookPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), (reader.read(BYTE) * 360f) / 256f); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(BYTE, (byte) (this.yaw * 256 / 360)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityHeadLookPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(BYTE, (byte) (value.yaw * 256 / 360)); + } + @Override + public EntityHeadLookPacket read(@NotNull NetworkBuffer buffer) { + return new EntityHeadLookPacket(buffer.read(VAR_INT), (buffer.read(BYTE) * 360f) / 256f); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java index b258bddfe..08478ce46 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java @@ -20,19 +20,22 @@ public record EntityMetaDataPacket(int entityId, entries = Map.copyOf(entries); } - public EntityMetaDataPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), readEntries(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - for (var entry : entries.entrySet()) { - writer.write(BYTE, entry.getKey().byteValue()); - writer.write(entry.getValue()); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityMetaDataPacket value) { + buffer.write(VAR_INT, value.entityId); + for (var entry : value.entries.entrySet()) { + buffer.write(BYTE, entry.getKey().byteValue()); + buffer.write(entry.getValue()); + } + buffer.write(BYTE, (byte) 0xFF); // End } - writer.write(BYTE, (byte) 0xFF); // End - } + + @Override + public EntityMetaDataPacket read(@NotNull NetworkBuffer buffer) { + return new EntityMetaDataPacket(buffer.read(VAR_INT), readEntries(buffer)); + } + }; private static Map> readEntries(@NotNull NetworkBuffer reader) { Map> entries = new HashMap<>(); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java index 461235e7f..8a6eb2d4c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionAndRotationPacket.java @@ -9,21 +9,26 @@ import static net.minestom.server.network.NetworkBuffer.*; public record EntityPositionAndRotationPacket(int entityId, short deltaX, short deltaY, short deltaZ, float yaw, float pitch, boolean onGround) implements ServerPacket.Play { - public EntityPositionAndRotationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(SHORT), reader.read(SHORT), reader.read(SHORT), - reader.read(BYTE) * 360f / 256f, reader.read(BYTE) * 360f / 256f, reader.read(BOOLEAN)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityPositionAndRotationPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(SHORT, value.deltaX); + buffer.write(SHORT, value.deltaY); + buffer.write(SHORT, value.deltaZ); + buffer.write(BYTE, (byte) (value.yaw * 256 / 360)); + buffer.write(BYTE, (byte) (value.pitch * 256 / 360)); + buffer.write(BOOLEAN, value.onGround); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(SHORT, deltaX); - writer.write(SHORT, deltaY); - writer.write(SHORT, deltaZ); - writer.write(BYTE, (byte) (yaw * 256 / 360)); - writer.write(BYTE, (byte) (pitch * 256 / 360)); - writer.write(BOOLEAN, onGround); - } + @Override + public EntityPositionAndRotationPacket read(@NotNull NetworkBuffer buffer) { + return new EntityPositionAndRotationPacket(buffer.read(VAR_INT), + buffer.read(SHORT), buffer.read(SHORT), buffer.read(SHORT), + buffer.read(BYTE) * 360f / 256f, buffer.read(BYTE) * 360f / 256f, + buffer.read(BOOLEAN)); + } + }; public static EntityPositionAndRotationPacket getPacket(int entityId, @NotNull Pos newPosition, @NotNull Pos oldPosition, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java index 6dbb6fd9b..6bfcedf0b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -9,19 +10,13 @@ import static net.minestom.server.network.NetworkBuffer.*; public record EntityPositionPacket(int entityId, short deltaX, short deltaY, short deltaZ, boolean onGround) implements ServerPacket.Play { - - public EntityPositionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(SHORT), reader.read(SHORT), reader.read(SHORT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(SHORT, deltaX); - writer.write(SHORT, deltaY); - writer.write(SHORT, deltaZ); - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EntityPositionPacket::entityId, + SHORT, EntityPositionPacket::deltaX, + SHORT, EntityPositionPacket::deltaY, + SHORT, EntityPositionPacket::deltaZ, + BOOLEAN, EntityPositionPacket::onGround, + EntityPositionPacket::new); @NotNull public static EntityPositionPacket getPacket(int entityId, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java index 4893818ba..2c803219e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityRotationPacket.java @@ -6,17 +6,22 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; -public record EntityRotationPacket(int entityId, float yaw, float pitch, boolean onGround) implements ServerPacket.Play { - public EntityRotationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(BYTE) * 360f / 256f, reader.read(BYTE) * 360f / 256f, reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(BYTE, (byte) (yaw * 256 / 360)); - writer.write(BYTE, (byte) (pitch * 256 / 360)); - writer.write(BOOLEAN, onGround); - } +public record EntityRotationPacket(int entityId, float yaw, float pitch, + boolean onGround) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntityRotationPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(BYTE, (byte) (value.yaw * 256 / 360)); + buffer.write(BYTE, (byte) (value.pitch * 256 / 360)); + buffer.write(BOOLEAN, value.onGround); + } + @Override + public EntityRotationPacket read(@NotNull NetworkBuffer buffer) { + return new EntityRotationPacket(buffer.read(VAR_INT), + buffer.read(BYTE) * 360f / 256f, buffer.read(BYTE) * 360f / 256f, + buffer.read(BOOLEAN)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java index a936c757c..cf7c50a5b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java @@ -17,24 +17,25 @@ public record EntitySoundEffectPacket( float pitch, long seed ) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntitySoundEffectPacket value) { + buffer.write(SoundEvent.NETWORK_TYPE, value.soundEvent); + buffer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(value.source)); + buffer.write(VAR_INT, value.entityId); + buffer.write(FLOAT, value.volume); + buffer.write(FLOAT, value.pitch); + buffer.write(LONG, value.seed); + } - public EntitySoundEffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(SoundEvent.NETWORK_TYPE), - reader.readEnum(Sound.Source.class), - reader.read(VAR_INT), - reader.read(FLOAT), - reader.read(FLOAT), - reader.read(LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SoundEvent.NETWORK_TYPE, soundEvent); - writer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(source)); - writer.write(VAR_INT, entityId); - writer.write(FLOAT, volume); - writer.write(FLOAT, pitch); - writer.write(LONG, seed); - } - + @Override + public EntitySoundEffectPacket read(@NotNull NetworkBuffer buffer) { + return new EntitySoundEffectPacket(buffer.read(SoundEvent.NETWORK_TYPE), + buffer.readEnum(Sound.Source.class), + buffer.read(VAR_INT), + buffer.read(FLOAT), + buffer.read(FLOAT), + buffer.read(LONG)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java index a976ba7c4..9df8c4d3f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityStatusPacket.java @@ -1,21 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.INT; public record EntityStatusPacket(int entityId, byte status) implements ServerPacket.Play { - public EntityStatusPacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT), reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, entityId); - writer.write(BYTE, status); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, EntityStatusPacket::entityId, + BYTE, EntityStatusPacket::status, + EntityStatusPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java index 9b3b2b40b..9e707e646 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java @@ -8,21 +8,23 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record EntityTeleportPacket(int entityId, Pos position, boolean onGround) implements ServerPacket.Play { - public EntityTeleportPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(BYTE) * 360f / 256f, reader.read(BYTE) * 360f / 256f), - reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(BYTE, (byte) (position.yaw() * 256f / 360f)); - writer.write(BYTE, (byte) (position.pitch() * 256f / 360f)); - writer.write(BOOLEAN, onGround); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull EntityTeleportPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(DOUBLE, value.position.x()); + buffer.write(DOUBLE, value.position.y()); + buffer.write(DOUBLE, value.position.z()); + buffer.write(BYTE, (byte) (value.position.yaw() * 256f / 360f)); + buffer.write(BYTE, (byte) (value.position.pitch() * 256f / 360f)); + buffer.write(BOOLEAN, value.onGround); + } + @Override + public @NotNull EntityTeleportPacket read(@NotNull NetworkBuffer buffer) { + return new EntityTeleportPacket(buffer.read(VAR_INT), new Pos(buffer.read(DOUBLE), buffer.read(DOUBLE), buffer.read(DOUBLE), + buffer.read(BYTE) * 360f / 256f, buffer.read(BYTE) * 360f / 256f), + buffer.read(BOOLEAN)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java index 2415b3286..6004343a0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityVelocityPacket.java @@ -2,18 +2,21 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.MathUtils; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.SHORT; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityVelocityPacket(int entityId, short velocityX, short velocityY, short velocityZ) implements ServerPacket.Play { - public EntityVelocityPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(SHORT), reader.read(SHORT), reader.read(SHORT)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EntityVelocityPacket::entityId, + SHORT, EntityVelocityPacket::velocityX, + SHORT, EntityVelocityPacket::velocityY, + SHORT, EntityVelocityPacket::velocityZ, + EntityVelocityPacket::new); public EntityVelocityPacket(int entityId, Point velocity) { this( @@ -23,13 +26,4 @@ public record EntityVelocityPacket(int entityId, short velocityX, short velocity (short) MathUtils.clamp(velocity.z(), Short.MIN_VALUE, Short.MAX_VALUE) ); } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(SHORT, velocityX); - writer.write(SHORT, velocityY); - writer.write(SHORT, velocityZ); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java index 405c7a83c..cb9feabb4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java @@ -19,89 +19,77 @@ public record ExplosionPacket(double x, double y, double z, float radius, @NotNull SoundEvent sound) implements ServerPacket.Play { public static final SoundEvent DEFAULT_SOUND = SoundEvent.ENTITY_GENERIC_EXPLODE; - private static @NotNull ExplosionPacket fromReader(@NotNull NetworkBuffer reader) { - double x = reader.read(DOUBLE), y = reader.read(DOUBLE), z = reader.read(DOUBLE); - float radius = reader.read(FLOAT); - byte[] records = reader.readBytes(reader.read(VAR_INT) * 3); - float playerMotionX = reader.read(FLOAT), playerMotionY = reader.read(FLOAT), playerMotionZ = reader.read(FLOAT); - BlockInteraction blockInteraction = reader.readEnum(BlockInteraction.class); - int smallParticleId = reader.read(VAR_INT); - byte[] smallParticleData = readParticleData(reader, Particle.fromId(smallParticleId)); - int largeParticleId = reader.read(VAR_INT); - byte[] largeParticleData = readParticleData(reader, Particle.fromId(largeParticleId)); - SoundEvent sound = reader.read(SoundEvent.NETWORK_TYPE); - return new ExplosionPacket(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ, - blockInteraction, smallParticleId, smallParticleData, largeParticleId, largeParticleData, - sound); - } + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ExplosionPacket value) { + buffer.write(DOUBLE, value.x); + buffer.write(DOUBLE, value.y); + buffer.write(DOUBLE, value.z); + buffer.write(FLOAT, value.radius); + buffer.write(VAR_INT, value.records.length / 3); // each record is 3 bytes long + buffer.write(RAW_BYTES, value.records); + buffer.write(FLOAT, value.playerMotionX); + buffer.write(FLOAT, value.playerMotionY); + buffer.write(FLOAT, value.playerMotionZ); + buffer.write(VAR_INT, value.blockInteraction.ordinal()); + buffer.write(VAR_INT, value.smallParticleId); + buffer.write(RAW_BYTES, value.smallParticleData); + buffer.write(VAR_INT, value.largeParticleId); + buffer.write(RAW_BYTES, value.largeParticleData); + buffer.write(SoundEvent.NETWORK_TYPE, value.sound); + } + + @Override + public ExplosionPacket read(@NotNull NetworkBuffer buffer) { + double x = buffer.read(DOUBLE), y = buffer.read(DOUBLE), z = buffer.read(DOUBLE); + float radius = buffer.read(FLOAT); + byte[] records = buffer.readBytes(buffer.read(VAR_INT) * 3); + float playerMotionX = buffer.read(FLOAT), playerMotionY = buffer.read(FLOAT), playerMotionZ = buffer.read(FLOAT); + BlockInteraction blockInteraction = buffer.readEnum(BlockInteraction.class); + int smallParticleId = buffer.read(VAR_INT); + byte[] smallParticleData = readParticleData(buffer, Particle.fromId(smallParticleId)); + int largeParticleId = buffer.read(VAR_INT); + byte[] largeParticleData = readParticleData(buffer, Particle.fromId(largeParticleId)); + SoundEvent sound = buffer.read(SoundEvent.NETWORK_TYPE); + return new ExplosionPacket(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ, + blockInteraction, smallParticleId, smallParticleData, largeParticleId, largeParticleData, + sound); + } + }; private static byte @NotNull [] readParticleData(@NotNull NetworkBuffer reader, Particle particle) { //Need to do this because particle data isn't at the end of the packet BinaryWriter writer = new BinaryWriter(); if (particle.equals(Particle.BLOCK) || particle.equals(Particle.BLOCK_MARKER) || particle.equals(Particle.FALLING_DUST) || particle.equals(Particle.SHRIEK)) { writer.writeVarInt(reader.read(VAR_INT)); - } - else if (particle.equals(Particle.VIBRATION)) { + } else if (particle.equals(Particle.VIBRATION)) { writer.writeVarInt(reader.read(VAR_INT)); writer.writeBlockPosition(reader.read(BLOCK_POSITION)); writer.writeVarInt(reader.read(VAR_INT)); writer.writeFloat(reader.read(FLOAT)); writer.writeVarInt(reader.read(VAR_INT)); - } - else if (particle.equals(Particle.SCULK_CHARGE)) { + } else if (particle.equals(Particle.SCULK_CHARGE)) { writer.writeFloat(reader.read(FLOAT)); return writer.toByteArray(); - } - else if (particle.equals(Particle.ITEM)) { + } else if (particle.equals(Particle.ITEM)) { writer.writeItemStack(reader.read(ItemStack.NETWORK_TYPE)); - } - else if (particle.equals(Particle.DUST_COLOR_TRANSITION)) { + } else if (particle.equals(Particle.DUST_COLOR_TRANSITION)) { for (int i = 0; i < 7; i++) writer.writeFloat(reader.read(FLOAT)); - } - else if (particle.equals(Particle.DUST)) { + } else if (particle.equals(Particle.DUST)) { for (int i = 0; i < 4; i++) writer.writeFloat(reader.read(FLOAT)); } return writer.toByteArray(); } - public ExplosionPacket(@NotNull NetworkBuffer reader) { - this(fromReader(reader)); - } - public ExplosionPacket(double x, double y, double z, float radius, byte @NotNull [] records, float playerMotionX, float playerMotionY, float playerMotionZ) { this(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ, - BlockInteraction.DESTROY, Particle.EXPLOSION.id(), new byte[] {}, - Particle.EXPLOSION_EMITTER.id(), new byte[] {}, + BlockInteraction.DESTROY, Particle.EXPLOSION.id(), new byte[]{}, + Particle.EXPLOSION_EMITTER.id(), new byte[]{}, DEFAULT_SOUND); } - private ExplosionPacket(@NotNull ExplosionPacket packet) { - this(packet.x, packet.y, packet.z, packet.radius, packet.records, packet.playerMotionX, packet.playerMotionY, packet.playerMotionZ, - packet.blockInteraction, packet.smallParticleId, packet.smallParticleData, packet.largeParticleId, packet.largeParticleData, - packet.sound); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, x); - writer.write(DOUBLE, y); - writer.write(DOUBLE, z); - writer.write(FLOAT, radius); - writer.write(VAR_INT, records.length / 3); // each record is 3 bytes long - writer.write(RAW_BYTES, records); - writer.write(FLOAT, playerMotionX); - writer.write(FLOAT, playerMotionY); - writer.write(FLOAT, playerMotionZ); - writer.write(VAR_INT, blockInteraction.ordinal()); - writer.write(VAR_INT, smallParticleId); - writer.write(RAW_BYTES, smallParticleData); - writer.write(VAR_INT, largeParticleId); - writer.write(RAW_BYTES, largeParticleData); - writer.write(SoundEvent.NETWORK_TYPE, sound); - } - public enum BlockInteraction { KEEP, DESTROY, DESTROY_WITH_DECAY, TRIGGER_BLOCK } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java index 80e040d02..7b0185711 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java @@ -9,27 +9,32 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record FacePlayerPacket(FacePosition facePosition, - Point target, int entityId, FacePosition entityFacePosition) implements ServerPacket.Play { - public FacePlayerPacket(@NotNull NetworkBuffer reader) { - this(FacePosition.values()[reader.read(VAR_INT)], - new Vec(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE)), - reader.read(BOOLEAN) ? reader.read(VAR_INT) : 0, - reader.readableBytes() > 0 ? reader.readEnum(FacePosition.class) : null); - } + Point target, int entityId, + FacePosition entityFacePosition) implements ServerPacket.Play { - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, facePosition.ordinal()); - writer.write(DOUBLE, target.x()); - writer.write(DOUBLE, target.y()); - writer.write(DOUBLE, target.z()); - final boolean isEntity = entityId > 0; - writer.write(BOOLEAN, isEntity); - if (isEntity) { - writer.write(VAR_INT, entityId); - writer.writeEnum(FacePosition.class, entityFacePosition); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull FacePlayerPacket value) { + buffer.write(VAR_INT, value.facePosition.ordinal()); + buffer.write(DOUBLE, value.target.x()); + buffer.write(DOUBLE, value.target.y()); + buffer.write(DOUBLE, value.target.z()); + final boolean isEntity = value.entityId > 0; + buffer.write(BOOLEAN, isEntity); + if (isEntity) { + buffer.write(VAR_INT, value.entityId); + buffer.writeEnum(FacePosition.class, value.entityFacePosition); + } } - } + + @Override + public @NotNull FacePlayerPacket read(@NotNull NetworkBuffer buffer) { + return new FacePlayerPacket(FacePosition.values()[buffer.read(VAR_INT)], + new Vec(buffer.read(DOUBLE), buffer.read(DOUBLE), buffer.read(DOUBLE)), + buffer.read(BOOLEAN) ? buffer.read(VAR_INT) : 0, + buffer.readableBytes() > 0 ? buffer.readEnum(FacePosition.class) : null); + } + }; public enum FacePosition { FEET, EYES diff --git a/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java index 26d237583..7d3de2d28 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/HeldItemChangePacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; public record HeldItemChangePacket(byte slot) implements ServerPacket.Play { - public HeldItemChangePacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, slot); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, HeldItemChangePacket::slot, + HeldItemChangePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java index 1d8d21a9f..1b95e0fd0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/HitAnimationPacket.java @@ -1,22 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record HitAnimationPacket(int entityId, float yaw) implements ServerPacket.Play { - - public HitAnimationPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(FLOAT, yaw); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, HitAnimationPacket::entityId, + FLOAT, HitAnimationPacket::yaw, + HitAnimationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java index 78e801537..dcaa6e242 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/InitializeWorldBorderPacket.java @@ -1,8 +1,8 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -10,22 +10,14 @@ public record InitializeWorldBorderPacket(double x, double z, double oldDiameter, double newDiameter, long speed, int portalTeleportBoundary, int warningTime, int warningBlocks) implements ServerPacket.Play { - public InitializeWorldBorderPacket(@NotNull NetworkBuffer reader) { - this(reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(VAR_LONG), reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, x); - writer.write(DOUBLE, z); - writer.write(DOUBLE, oldDiameter); - writer.write(DOUBLE, newDiameter); - writer.write(VAR_LONG, speed); - writer.write(VAR_INT, portalTeleportBoundary); - writer.write(VAR_INT, warningTime); - writer.write(VAR_INT, warningBlocks); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + DOUBLE, InitializeWorldBorderPacket::x, + DOUBLE, InitializeWorldBorderPacket::z, + DOUBLE, InitializeWorldBorderPacket::oldDiameter, + DOUBLE, InitializeWorldBorderPacket::newDiameter, + VAR_LONG, InitializeWorldBorderPacket::speed, + VAR_INT, InitializeWorldBorderPacket::portalTeleportBoundary, + VAR_INT, InitializeWorldBorderPacket::warningTime, + VAR_INT, InitializeWorldBorderPacket::warningBlocks, + InitializeWorldBorderPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java index 3295888a0..6214c7517 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java @@ -25,56 +25,59 @@ public record JoinGamePacket( worlds = List.copyOf(worlds); } - public JoinGamePacket(@NotNull NetworkBuffer reader) { - this( - reader.read(INT), - reader.read(BOOLEAN), - reader.readCollection(STRING, MAX_WORLDS), - reader.read(VAR_INT), - reader.read(VAR_INT), - reader.read(VAR_INT), - reader.read(BOOLEAN), - reader.read(BOOLEAN), - reader.read(BOOLEAN), - reader.read(VAR_INT), - reader.read(STRING), - reader.read(LONG), - GameMode.fromId(reader.read(BYTE)), - getNullableGameMode(reader.read(BYTE)), - reader.read(BOOLEAN), - reader.read(BOOLEAN), - reader.readOptional(WorldPos.NETWORK_TYPE), - reader.read(VAR_INT), - reader.read(BOOLEAN) - ); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, entityId); - writer.write(BOOLEAN, isHardcore); - writer.writeCollection(STRING, worlds); - writer.write(VAR_INT, maxPlayers); - writer.write(VAR_INT, viewDistance); - writer.write(VAR_INT, simulationDistance); - writer.write(BOOLEAN, reducedDebugInfo); - writer.write(BOOLEAN, enableRespawnScreen); - writer.write(BOOLEAN, doLimitedCrafting); - writer.write(VAR_INT, dimensionType); - writer.write(STRING, world); - writer.write(LONG, hashedSeed); - writer.write(BYTE, gameMode.id()); - if (previousGameMode != null) { - writer.write(BYTE, previousGameMode.id()); - } else { - writer.write(BYTE, (byte) -1); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, JoinGamePacket value) { + buffer.write(INT, value.entityId); + buffer.write(BOOLEAN, value.isHardcore); + buffer.writeCollection(STRING, value.worlds); + buffer.write(VAR_INT, value.maxPlayers); + buffer.write(VAR_INT, value.viewDistance); + buffer.write(VAR_INT, value.simulationDistance); + buffer.write(BOOLEAN, value.reducedDebugInfo); + buffer.write(BOOLEAN, value.enableRespawnScreen); + buffer.write(BOOLEAN, value.doLimitedCrafting); + buffer.write(VAR_INT, value.dimensionType); + buffer.write(STRING, value.world); + buffer.write(LONG, value.hashedSeed); + buffer.write(BYTE, value.gameMode.id()); + if (value.previousGameMode != null) { + buffer.write(BYTE, value.previousGameMode.id()); + } else { + buffer.write(BYTE, (byte) -1); + } + buffer.write(BOOLEAN, value.isDebug); + buffer.write(BOOLEAN, value.isFlat); + buffer.writeOptional(WorldPos.NETWORK_TYPE, value.deathLocation); + buffer.write(VAR_INT, value.portalCooldown); + buffer.write(BOOLEAN, value.enforcesSecureChat); } - writer.write(BOOLEAN, isDebug); - writer.write(BOOLEAN, isFlat); - writer.writeOptional(WorldPos.NETWORK_TYPE, deathLocation); - writer.write(VAR_INT, portalCooldown); - writer.write(BOOLEAN, enforcesSecureChat); - } + + @Override + public JoinGamePacket read(@NotNull NetworkBuffer buffer) { + return new JoinGamePacket( + buffer.read(INT), + buffer.read(BOOLEAN), + buffer.readCollection(STRING, MAX_WORLDS), + buffer.read(VAR_INT), + buffer.read(VAR_INT), + buffer.read(VAR_INT), + buffer.read(BOOLEAN), + buffer.read(BOOLEAN), + buffer.read(BOOLEAN), + buffer.read(VAR_INT), + buffer.read(STRING), + buffer.read(LONG), + GameMode.fromId(buffer.read(BYTE)), + getNullableGameMode(buffer.read(BYTE)), + buffer.read(BOOLEAN), + buffer.read(BOOLEAN), + buffer.readOptional(WorldPos.NETWORK_TYPE), + buffer.read(VAR_INT), + buffer.read(BOOLEAN) + ); + } + }; /** * This method exists in lieu of a NetworkBufferType since -1 is only a @@ -85,5 +88,4 @@ public record JoinGamePacket( private static @Nullable GameMode getNullableGameMode(final byte id) { return id == (byte) -1 ? null : GameMode.fromId(id); } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java index 483aa01eb..af1699c68 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,78 +20,60 @@ public record MapDataPacket(int mapId, byte scale, boolean locked, icons = List.copyOf(icons); } - public MapDataPacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } - - private MapDataPacket(MapDataPacket packet) { - this(packet.mapId, packet.scale, packet.locked, - packet.trackingPosition, packet.icons, - packet.colorContent); - } - - private static MapDataPacket read(@NotNull NetworkBuffer reader) { - var mapId = reader.read(VAR_INT); - var scale = reader.read(BYTE); - var locked = reader.read(BOOLEAN); - var trackingPosition = reader.read(BOOLEAN); - List icons = trackingPosition ? reader.readCollection(Icon::new, MAX_ICONS) : List.of(); - - var columns = reader.read(BYTE); - if (columns <= 0) return new MapDataPacket(mapId, scale, locked, trackingPosition, icons, null); - byte rows = reader.read(BYTE); - byte x = reader.read(BYTE); - byte z = reader.read(BYTE); - byte[] data = reader.read(BYTE_ARRAY); - return new MapDataPacket(mapId, scale, locked, - trackingPosition, icons, new ColorContent(columns, rows, x, z, - data)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, mapId); - writer.write(BYTE, scale); - writer.write(BOOLEAN, locked); - writer.write(BOOLEAN, trackingPosition); - if (trackingPosition) writer.writeCollection(icons); - if (colorContent != null) { - writer.write(colorContent); - } else { - writer.write(BYTE, (byte) 0); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, MapDataPacket value) { + buffer.write(VAR_INT, value.mapId); + buffer.write(BYTE, value.scale); + buffer.write(BOOLEAN, value.locked); + buffer.write(BOOLEAN, value.trackingPosition); + if (value.trackingPosition) buffer.writeCollection(Icon.SERIALIZER, value.icons); + if (value.colorContent != null) { + buffer.write(ColorContent.SERIALIZER, value.colorContent); + } else { + buffer.write(BYTE, (byte) 0); + } } - } + + @Override + public MapDataPacket read(@NotNull NetworkBuffer buffer) { + var mapId = buffer.read(VAR_INT); + var scale = buffer.read(BYTE); + var locked = buffer.read(BOOLEAN); + var trackingPosition = buffer.read(BOOLEAN); + List icons = trackingPosition ? buffer.readCollection(Icon.SERIALIZER, MAX_ICONS) : List.of(); + + var columns = buffer.read(BYTE); + if (columns <= 0) return new MapDataPacket(mapId, scale, locked, trackingPosition, icons, null); + byte rows = buffer.read(BYTE); + byte x = buffer.read(BYTE); + byte z = buffer.read(BYTE); + byte[] data = buffer.read(BYTE_ARRAY); + return new MapDataPacket(mapId, scale, locked, + trackingPosition, icons, new ColorContent(columns, rows, x, z, + data)); + } + }; public record Icon(int type, byte x, byte z, byte direction, - @Nullable Component displayName) implements NetworkBuffer.Writer { - public Icon(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(BYTE), reader.read(BYTE), reader.read(BYTE), - reader.read(BOOLEAN) ? reader.read(COMPONENT) : null); - } - - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, type); - writer.write(BYTE, x); - writer.write(BYTE, z); - writer.write(BYTE, direction); - writer.write(BOOLEAN, displayName != null); - if (displayName != null) writer.write(COMPONENT, displayName); - } + @Nullable Component displayName) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, Icon::type, + BYTE, Icon::x, + BYTE, Icon::z, + BYTE, Icon::direction, + COMPONENT.optional(), Icon::displayName, + Icon::new); } public record ColorContent(byte columns, byte rows, byte x, byte z, - byte @NotNull [] data) implements NetworkBuffer.Writer { - public ColorContent(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(BYTE), reader.read(BYTE), reader.read(BYTE), - reader.read(BYTE_ARRAY)); - } - - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, columns); - writer.write(BYTE, rows); - writer.write(BYTE, x); - writer.write(BYTE, z); - writer.write(BYTE_ARRAY, data); - } + byte @NotNull [] data) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ColorContent::columns, + BYTE, ColorContent::rows, + BYTE, ColorContent::x, + BYTE, ColorContent::z, + BYTE_ARRAY, ColorContent::data, + ColorContent::new); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java index c05dbdac7..a0fd49f27 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/MultiBlockChangePacket.java @@ -1,26 +1,20 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; import static net.minestom.server.network.NetworkBuffer.VAR_LONG_ARRAY; public record MultiBlockChangePacket(long chunkSectionPosition, long[] blocks) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, MultiBlockChangePacket::chunkSectionPosition, + VAR_LONG_ARRAY.optional(), MultiBlockChangePacket::blocks, + MultiBlockChangePacket::new); + public MultiBlockChangePacket(int chunkX, int section, int chunkZ, long[] blocks) { this(((long) (chunkX & 0x3FFFFF) << 42) | (section & 0xFFFFF) | ((long) (chunkZ & 0x3FFFFF) << 20), blocks); } - - public MultiBlockChangePacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG), reader.read(VAR_LONG_ARRAY)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, chunkSectionPosition); - writer.write(VAR_LONG_ARRAY, blocks); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java index ffb12682c..727576756 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java @@ -8,19 +8,21 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) implements ServerPacket.Play { - public NbtQueryResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, transactionId); - if (data != null) { - writer.write(NBT, data); - } else { - // TAG_End - writer.write(BYTE, (byte) 0x00); + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, NbtQueryResponsePacket value) { + buffer.write(VAR_INT, value.transactionId); + if (value.data != null) { + buffer.write(NBT, value.data); + } else { + // TAG_End + buffer.write(BYTE, (byte) 0x00); + } } - } + @Override + public NbtQueryResponsePacket read(@NotNull NetworkBuffer buffer) { + return new NbtQueryResponsePacket(buffer.read(VAR_INT), (CompoundBinaryTag) buffer.read(NBT)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java index 386d9a9ea..e7f78eb4f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenBookPacket.java @@ -2,17 +2,12 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; public record OpenBookPacket(@NotNull PlayerHand hand) implements ServerPacket.Play { - public OpenBookPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(PlayerHand.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(PlayerHand.class, hand); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(PlayerHand.class), OpenBookPacket::hand, + OpenBookPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java index 6a7ea5536..96a0ea381 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java @@ -1,21 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record OpenHorseWindowPacket(byte windowId, int slotCount, int entityId) implements ServerPacket.Play { - public OpenHorseWindowPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(VAR_INT), reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(VAR_INT, slotCount); - writer.write(INT, entityId); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, OpenHorseWindowPacket::windowId, + VAR_INT, OpenHorseWindowPacket::slotCount, + INT, OpenHorseWindowPacket::entityId, + OpenHorseWindowPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java index c35971125..011d84d3e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenSignEditorPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -9,14 +10,8 @@ import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; public record OpenSignEditorPacket(@NotNull Point position, boolean isFrontText) implements ServerPacket.Play { - public OpenSignEditorPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, position); - writer.write(BOOLEAN, isFrontText); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, OpenSignEditorPacket::position, + BOOLEAN, OpenSignEditorPacket::isFrontText, + OpenSignEditorPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java index 0a3419b3c..c408ba487 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -14,16 +15,11 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record OpenWindowPacket(int windowId, int windowType, @NotNull Component title) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public OpenWindowPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, windowId); - writer.write(VAR_INT, windowType); - writer.write(COMPONENT, title); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, OpenWindowPacket::windowId, + VAR_INT, OpenWindowPacket::windowType, + COMPONENT, OpenWindowPacket::title, + OpenWindowPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java index bc5a048e2..01328ba49 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ParticlePacket.java @@ -10,57 +10,53 @@ import java.util.Objects; import static net.minestom.server.network.NetworkBuffer.*; -public record ParticlePacket(@NotNull Particle particle, boolean longDistance, double x, double y, double z, float offsetX, float offsetY, float offsetZ, float maxSpeed, int particleCount) implements ServerPacket.Play { - private ParticlePacket(ParticlePacket copy) { - this(copy.particle, copy.longDistance, copy.x, copy.y, copy.z, copy.offsetX, copy.offsetY, copy.offsetZ, copy.maxSpeed, copy.particleCount); - } - - public ParticlePacket(@NotNull NetworkBuffer reader) { - this(readPacket(reader)); - } - +public record ParticlePacket(@NotNull Particle particle, boolean longDistance, double x, double y, double z, + float offsetX, float offsetY, float offsetZ, float maxSpeed, + int particleCount) implements ServerPacket.Play { public ParticlePacket(@NotNull Particle particle, double x, double y, double z, float offsetX, float offsetY, float offsetZ, float maxSpeed, int particleCount) { this(particle, false, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount); } public ParticlePacket(@NotNull Particle particle, boolean longDistance, @NotNull Point position, @NotNull Point offset, float maxSpeed, int particleCount) { - this(particle, longDistance, position.x(), position.y(), position.z(), (float)offset.x(), (float)offset.y(), (float)offset.z(), maxSpeed, particleCount); + this(particle, longDistance, position.x(), position.y(), position.z(), (float) offset.x(), (float) offset.y(), (float) offset.z(), maxSpeed, particleCount); } public ParticlePacket(@NotNull Particle particle, @NotNull Point position, @NotNull Point offset, float maxSpeed, int particleCount) { this(particle, false, position, offset, maxSpeed, particleCount); } - private static ParticlePacket readPacket(NetworkBuffer reader) { - Boolean longDistance = reader.read(BOOLEAN); - Double x = reader.read(DOUBLE); - Double y = reader.read(DOUBLE); - Double z = reader.read(DOUBLE); - Float offsetX = reader.read(FLOAT); - Float offsetY = reader.read(FLOAT); - Float offsetZ = reader.read(FLOAT); - Float maxSpeed = reader.read(FLOAT); - Integer particleCount = reader.read(INT); + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ParticlePacket value) { + buffer.write(BOOLEAN, value.longDistance); + buffer.write(DOUBLE, value.x); + buffer.write(DOUBLE, value.y); + buffer.write(DOUBLE, value.z); + buffer.write(FLOAT, value.offsetX); + buffer.write(FLOAT, value.offsetY); + buffer.write(FLOAT, value.offsetZ); + buffer.write(FLOAT, value.maxSpeed); + buffer.write(INT, value.particleCount); + buffer.write(VAR_INT, value.particle.id()); + value.particle.writeData(buffer); + } - Particle particle = Particle.fromId(reader.read(VAR_INT)); - Objects.requireNonNull(particle); + @Override + public ParticlePacket read(@NotNull NetworkBuffer buffer) { + Boolean longDistance = buffer.read(BOOLEAN); + Double x = buffer.read(DOUBLE); + Double y = buffer.read(DOUBLE); + Double z = buffer.read(DOUBLE); + Float offsetX = buffer.read(FLOAT); + Float offsetY = buffer.read(FLOAT); + Float offsetZ = buffer.read(FLOAT); + Float maxSpeed = buffer.read(FLOAT); + Integer particleCount = buffer.read(INT); - return new ParticlePacket(particle.readData(reader), longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BOOLEAN, longDistance); - writer.write(DOUBLE, x); - writer.write(DOUBLE, y); - writer.write(DOUBLE, z); - writer.write(FLOAT, offsetX); - writer.write(FLOAT, offsetY); - writer.write(FLOAT, offsetZ); - writer.write(FLOAT, maxSpeed); - writer.write(INT, particleCount); - writer.write(VAR_INT, particle.id()); - particle.writeData(writer); - } + Particle particle = Particle.fromId(buffer.read(VAR_INT)); + Objects.requireNonNull(particle); + return new ParticlePacket(particle.readData(buffer), longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java index 2669abc5d..ab33ced8c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerAbilitiesPacket.java @@ -1,8 +1,8 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.FLOAT; @@ -13,15 +13,9 @@ public record PlayerAbilitiesPacket(byte flags, float flyingSpeed, float walking public static final byte FLAG_ALLOW_FLYING = 0x04; public static final byte FLAG_INSTANT_BREAK = 0x08; - public PlayerAbilitiesPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(FLOAT), reader.read(FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, flags); - writer.write(FLOAT, flyingSpeed); - writer.write(FLOAT, walkingSpeed); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, PlayerAbilitiesPacket::flags, + FLOAT, PlayerAbilitiesPacket::flyingSpeed, + FLOAT, PlayerAbilitiesPacket::walkingSpeed, + PlayerAbilitiesPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java index 138149192..dc8fc6ba8 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java @@ -24,26 +24,30 @@ public record PlayerChatMessagePacket(UUID sender, int index, byte @Nullable [] @Nullable Component unsignedContent, FilterMask filterMask, int msgTypeId, Component msgTypeName, @Nullable Component msgTypeTarget) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public PlayerChatMessagePacket(@NotNull NetworkBuffer reader) { - this(reader.read(UUID), reader.read(VAR_INT), reader.readOptional(r -> r.readBytes(256)), - new SignedMessageBody.Packed(reader), - reader.readOptional(COMPONENT), new FilterMask(reader), - reader.read(VAR_INT), reader.read(COMPONENT), - reader.readOptional(COMPONENT)); - } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(UUID, sender); - writer.write(VAR_INT, index); - writer.writeOptional(RAW_BYTES, signature); - writer.write(messageBody); - writer.writeOptional(COMPONENT, unsignedContent); - writer.write(filterMask); - writer.write(VAR_INT, msgTypeId); - writer.write(COMPONENT, msgTypeName); - writer.writeOptional(COMPONENT, msgTypeTarget); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull PlayerChatMessagePacket value) { + buffer.write(UUID, value.sender); + buffer.write(VAR_INT, value.index); + buffer.writeOptional(RAW_BYTES, value.signature); + buffer.write(value.messageBody); + buffer.writeOptional(COMPONENT, value.unsignedContent); + buffer.write(value.filterMask); + buffer.write(VAR_INT, value.msgTypeId); + buffer.write(COMPONENT, value.msgTypeName); + buffer.writeOptional(COMPONENT, value.msgTypeTarget); + } + + @Override + public @NotNull PlayerChatMessagePacket read(@NotNull NetworkBuffer buffer) { + return new PlayerChatMessagePacket(buffer.read(UUID), buffer.read(VAR_INT), buffer.readOptional(r -> r.readBytes(256)), + new SignedMessageBody.Packed(buffer), + buffer.readOptional(COMPONENT), new FilterMask(buffer), + buffer.read(VAR_INT), buffer.read(COMPONENT), + buffer.readOptional(COMPONENT)); + } + }; @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java index 02368bfcf..6c5de563e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoRemovePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -10,6 +11,10 @@ import java.util.UUID; public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) implements ServerPacket.Play { public static final int MAX_ENTRIES = 1024; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.UUID.list(MAX_ENTRIES), PlayerInfoRemovePacket::uuids, + PlayerInfoRemovePacket::new); + public PlayerInfoRemovePacket(@NotNull UUID uuid) { this(List.of(uuid)); } @@ -17,14 +22,4 @@ public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) impleme public PlayerInfoRemovePacket { uuids = List.copyOf(uuids); } - - public PlayerInfoRemovePacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(NetworkBuffer.UUID, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(NetworkBuffer.UUID, uuids); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java index 47d5043ba..4f3c62a68 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.crypto.ChatSession; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.player.GameProfile; import org.jetbrains.annotations.NotNull; @@ -11,94 +12,67 @@ import org.jetbrains.annotations.Nullable; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.UUID; import static net.minestom.server.network.NetworkBuffer.*; -public final class PlayerInfoUpdatePacket implements ServerPacket.Play { +public record PlayerInfoUpdatePacket( + @NotNull EnumSet<@NotNull Action> actions, + @NotNull List<@NotNull Entry> entries +) implements ServerPacket.Play { public static final int MAX_ENTRIES = 1024; - private final @NotNull EnumSet<@NotNull Action> actions; - private final @NotNull List<@NotNull Entry> entries; - - public PlayerInfoUpdatePacket(@NotNull EnumSet<@NotNull Action> actions, @NotNull List<@NotNull Entry> entries) { - this.actions = EnumSet.copyOf(actions); - this.entries = List.copyOf(entries); - } - public PlayerInfoUpdatePacket(@NotNull Action action, @NotNull Entry entry) { - this.actions = EnumSet.of(action); - this.entries = List.of(entry); + this(EnumSet.of(action), List.of(entry)); } - public PlayerInfoUpdatePacket(@NotNull NetworkBuffer reader) { - this.actions = reader.readEnumSet(Action.class); - this.entries = reader.readCollection(buffer -> { - UUID uuid = buffer.read(NetworkBuffer.UUID); - String username = ""; - List properties = List.of(); - boolean listed = false; - int latency = 0; - GameMode gameMode = GameMode.SURVIVAL; - Component displayName = null; - ChatSession chatSession = null; - for (Action action : actions) { - switch (action) { - case ADD_PLAYER -> { - username = reader.read(STRING); - properties = reader.readCollection(Property::new, GameProfile.MAX_PROPERTIES); - } - case INITIALIZE_CHAT -> chatSession = new ChatSession(reader); - case UPDATE_GAME_MODE -> gameMode = reader.readEnum(GameMode.class); - case UPDATE_LISTED -> listed = reader.read(BOOLEAN); - case UPDATE_LATENCY -> latency = reader.read(VAR_INT); - case UPDATE_DISPLAY_NAME -> displayName = reader.readOptional(COMPONENT); + public PlayerInfoUpdatePacket { + actions = EnumSet.copyOf(actions); + entries = List.copyOf(entries); + } + + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer writer, PlayerInfoUpdatePacket value) { + writer.writeEnumSet(value.actions, Action.class); + writer.writeCollection(value.entries, (buffer, entry) -> { + buffer.write(NetworkBuffer.UUID, entry.uuid); + for (Action action : value.actions) { + action.writer.write(buffer, entry); } - } - return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession); - }, MAX_ENTRIES); - } + }); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnumSet(actions, Action.class); - writer.writeCollection(entries, (buffer, entry) -> { - buffer.write(NetworkBuffer.UUID, entry.uuid); - for (Action action : actions) { - action.writer.write(buffer, entry); - } - }); - } - - public @NotNull EnumSet actions() { - return actions; - } - - public @NotNull List entries() { - return entries; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - PlayerInfoUpdatePacket that = (PlayerInfoUpdatePacket) o; - return actions.equals(that.actions) && entries.equals(that.entries); - } - - @Override - public int hashCode() { - return Objects.hash(actions, entries); - } - - @Override - public String toString() { - return "PlayerInfoUpdatePacket{" + - "actions=" + actions + - ", entries=" + entries + - '}'; - } + @Override + public PlayerInfoUpdatePacket read(@NotNull NetworkBuffer reader) { + var actions = reader.readEnumSet(Action.class); + var entries = reader.readCollection(buffer -> { + UUID uuid = buffer.read(NetworkBuffer.UUID); + String username = ""; + List properties = List.of(); + boolean listed = false; + int latency = 0; + GameMode gameMode = GameMode.SURVIVAL; + Component displayName = null; + ChatSession chatSession = null; + for (Action action : actions) { + switch (action) { + case ADD_PLAYER -> { + username = reader.read(STRING); + properties = reader.readCollection(Property.SERIALIZER, GameProfile.MAX_PROPERTIES); + } + case INITIALIZE_CHAT -> chatSession = new ChatSession(reader); + case UPDATE_GAME_MODE -> gameMode = reader.readEnum(GameMode.class); + case UPDATE_LISTED -> listed = reader.read(BOOLEAN); + case UPDATE_LATENCY -> latency = reader.read(VAR_INT); + case UPDATE_DISPLAY_NAME -> displayName = reader.readOptional(COMPONENT); + } + } + return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession); + }, MAX_ENTRIES); + return new PlayerInfoUpdatePacket(actions, entries); + } + }; public record Entry(UUID uuid, String username, List properties, boolean listed, int latency, GameMode gameMode, @@ -108,29 +82,22 @@ public final class PlayerInfoUpdatePacket implements ServerPacket.Play { } } - public record Property(@NotNull String name, @NotNull String value, - @Nullable String signature) implements NetworkBuffer.Writer { + public record Property(@NotNull String name, @NotNull String value, @Nullable String signature) { public Property(@NotNull String name, @NotNull String value) { this(name, value, null); } - public Property(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(STRING), - reader.readOptional(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, name); - writer.write(STRING, value); - writer.writeOptional(STRING, signature); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Property::name, + STRING, Property::value, + STRING.optional(), Property::signature, + Property::new); } public enum Action { ADD_PLAYER((writer, entry) -> { writer.write(STRING, entry.username); - writer.writeCollection(entry.properties); + writer.writeCollection(Property.SERIALIZER, entry.properties); }), INITIALIZE_CHAT((writer, entry) -> writer.writeOptional(entry.chatSession)), UPDATE_GAME_MODE((writer, entry) -> writer.write(VAR_INT, entry.gameMode.ordinal())), diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java index 2ab94be03..796c0e7e3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerListHeaderAndFooterPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -13,15 +14,10 @@ import static net.minestom.server.network.NetworkBuffer.COMPONENT; public record PlayerListHeaderAndFooterPacket(@NotNull Component header, @NotNull Component footer) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public PlayerListHeaderAndFooterPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, header); - writer.write(COMPONENT, footer); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, PlayerListHeaderAndFooterPacket::header, + COMPONENT, PlayerListHeaderAndFooterPacket::footer, + PlayerListHeaderAndFooterPacket::new); @Override public @NotNull Collection components() { @@ -32,5 +28,4 @@ public record PlayerListHeaderAndFooterPacket(@NotNull Component header, public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator operator) { return new PlayerListHeaderAndFooterPacket(operator.apply(header), operator.apply(footer)); } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java index e38abe05c..50e548651 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java @@ -2,28 +2,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record PlayerPositionAndLookPacket(Pos position, byte flags, int teleportId) implements ServerPacket.Play { - public PlayerPositionAndLookPacket(@NotNull NetworkBuffer reader) { - this(new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), reader.read(FLOAT), reader.read(FLOAT)), - reader.read(BYTE), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - - writer.write(FLOAT, position.yaw()); - writer.write(FLOAT, position.pitch()); - - writer.write(BYTE, flags); - writer.write(VAR_INT, teleportId); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + POS, PlayerPositionAndLookPacket::position, + BYTE, PlayerPositionAndLookPacket::flags, + VAR_INT, PlayerPositionAndLookPacket::teleportId, + PlayerPositionAndLookPacket::new); } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java index a1ba5e331..8fb0d7209 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ProjectilePowerPacket.java @@ -1,21 +1,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.DOUBLE; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ProjectilePowerPacket( int entityId, double accelerationPower ) implements ServerPacket.Play { - - public ProjectilePowerPacket(@NotNull NetworkBuffer buffer) { - this(buffer.read(NetworkBuffer.VAR_INT), buffer.read(NetworkBuffer.DOUBLE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.VAR_INT, entityId); - writer.write(NetworkBuffer.DOUBLE, accelerationPower); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ProjectilePowerPacket::entityId, + DOUBLE, ProjectilePowerPacket::accelerationPower, + ProjectilePowerPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java index 275e3ced5..562774928 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java @@ -10,14 +10,16 @@ import java.util.Objects; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record RemoveEntityEffectPacket(int entityId, @NotNull PotionEffect potionEffect) implements ServerPacket.Play { - public RemoveEntityEffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), Objects.requireNonNull(PotionEffect.fromId(reader.read(VAR_INT)))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(VAR_INT, potionEffect.id()); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, RemoveEntityEffectPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(VAR_INT, value.potionEffect.id()); + } + @Override + public RemoveEntityEffectPacket read(@NotNull NetworkBuffer buffer) { + return new RemoveEntityEffectPacket(buffer.read(VAR_INT), Objects.requireNonNull(PotionEffect.fromId(buffer.read(VAR_INT)))); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java index a7719cfa9..16534f101 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ResetScorePacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -8,15 +9,8 @@ import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.STRING; public record ResetScorePacket(@NotNull String owner, @Nullable String objective) implements ServerPacket.Play { - - public ResetScorePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.readOptional(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, owner); - writer.writeOptional(STRING, objective); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ResetScorePacket::owner, + STRING.optional(), ResetScorePacket::objective, + ResetScorePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java index 58faef789..4dcb8ee70 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.data.WorldPos; import org.jetbrains.annotations.NotNull; @@ -13,34 +14,23 @@ public record RespawnPacket( int dimensionType, @NotNull String worldName, long hashedSeed, @NotNull GameMode gameMode, @NotNull GameMode previousGameMode, boolean isDebug, boolean isFlat, @Nullable WorldPos deathLocation, - int portalCooldown, int copyData + int portalCooldown, byte copyData ) implements ServerPacket.Play { public static final int COPY_NONE = 0x0; public static final int COPY_ATTRIBUTES = 0x1; public static final int COPY_METADATA = 0x2; public static final int COPY_ALL = COPY_ATTRIBUTES | COPY_METADATA; - public RespawnPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(STRING), - reader.read(LONG), GameMode.fromId(reader.read(BYTE)), - GameMode.fromId(reader.read(BYTE)), - reader.read(BOOLEAN), reader.read(BOOLEAN), - reader.readOptional(WorldPos.NETWORK_TYPE), - reader.read(VAR_INT), reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, dimensionType); - writer.write(STRING, worldName); - writer.write(LONG, hashedSeed); - writer.write(BYTE, gameMode.id()); - writer.write(BYTE, previousGameMode.id()); - writer.write(BOOLEAN, isDebug); - writer.write(BOOLEAN, isFlat); - writer.writeOptional(WorldPos.NETWORK_TYPE, deathLocation); - writer.write(VAR_INT, portalCooldown); - writer.write(BYTE, (byte) copyData); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, RespawnPacket::dimensionType, + STRING, RespawnPacket::worldName, + LONG, RespawnPacket::hashedSeed, + GameMode.NETWORK_TYPE, RespawnPacket::gameMode, + GameMode.NETWORK_TYPE, RespawnPacket::previousGameMode, + BOOLEAN, RespawnPacket::isDebug, + BOOLEAN, RespawnPacket::isFlat, + WorldPos.NETWORK_TYPE.optional(), RespawnPacket::deathLocation, + VAR_INT, RespawnPacket::portalCooldown, + BYTE, RespawnPacket::copyData, + RespawnPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java index 24746f5bd..0765abad7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java @@ -17,40 +17,35 @@ public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode @Nullable Component objectiveValue, @Nullable Type type, @Nullable Sidebar.NumberFormat numberFormat) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public ScoreboardObjectivePacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } - - private ScoreboardObjectivePacket(ScoreboardObjectivePacket packet) { - this(packet.objectiveName, packet.mode, packet.objectiveValue, packet.type, packet.numberFormat); - } - - private static ScoreboardObjectivePacket read(@NotNull NetworkBuffer reader) { - String objectiveName = reader.read(STRING); - byte mode = reader.read(BYTE); - Component objectiveValue = null; - Type type = null; - Sidebar.NumberFormat numberFormat = null; - if (mode == 0 || mode == 2) { - objectiveValue = reader.read(COMPONENT); - type = Type.values()[reader.read(VAR_INT)]; - numberFormat = reader.readOptional(Sidebar.NumberFormat::new); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ScoreboardObjectivePacket value) { + buffer.write(STRING, value.objectiveName); + buffer.write(BYTE, value.mode); + if (value.mode == 0 || value.mode == 2) { + assert value.objectiveValue != null; + buffer.write(COMPONENT, value.objectiveValue); + assert value.type != null; + buffer.write(VAR_INT, value.type.ordinal()); + buffer.writeOptional(value.numberFormat); + } } - return new ScoreboardObjectivePacket(objectiveName, mode, objectiveValue, type, numberFormat); - } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, objectiveName); - writer.write(BYTE, mode); - if (mode == 0 || mode == 2) { - assert objectiveValue != null; - writer.write(COMPONENT, objectiveValue); - assert type != null; - writer.write(VAR_INT, type.ordinal()); - writer.writeOptional(numberFormat); + @Override + public ScoreboardObjectivePacket read(@NotNull NetworkBuffer buffer) { + String objectiveName = buffer.read(STRING); + byte mode = buffer.read(BYTE); + Component objectiveValue = null; + Type type = null; + Sidebar.NumberFormat numberFormat = null; + if (mode == 0 || mode == 2) { + objectiveValue = buffer.read(COMPONENT); + type = Type.values()[buffer.read(VAR_INT)]; + numberFormat = buffer.readOptional(Sidebar.NumberFormat::new); + } + return new ScoreboardObjectivePacket(objectiveName, mode, objectiveValue, type, numberFormat); } - } + }; @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java index f84f6a55e..f482aaf31 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SelectAdvancementTabPacket.java @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.STRING; public record SelectAdvancementTabPacket(@Nullable String identifier) implements ServerPacket.Play { - public SelectAdvancementTabPacket(@NotNull NetworkBuffer reader) { - this(reader.readOptional(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeOptional(STRING, identifier); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.optional(), SelectAdvancementTabPacket::identifier, + SelectAdvancementTabPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java index 22097b1ef..b5c46370d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ServerDataPacket.java @@ -2,24 +2,18 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.*; -public record ServerDataPacket(@Nullable Component motd, byte @Nullable [] iconBase64, +public record ServerDataPacket(@NotNull Component motd, byte @Nullable [] iconBase64, boolean enforcesSecureChat) implements ServerPacket.Play { - public ServerDataPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.readOptional(BYTE_ARRAY), - reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, this.motd); - writer.writeOptional(BYTE_ARRAY, this.iconBase64); - writer.write(BOOLEAN, enforcesSecureChat); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, ServerDataPacket::motd, + BYTE_ARRAY.optional(), ServerDataPacket::iconBase64, + BOOLEAN, ServerDataPacket::enforcesSecureChat, + ServerDataPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java index a2465b0be..429c99c20 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ServerDifficultyPacket.java @@ -1,21 +1,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.world.Difficulty; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.Enum; public record ServerDifficultyPacket(@NotNull Difficulty difficulty, boolean locked) implements ServerPacket.Play { - public ServerDifficultyPacket(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Difficulty.class), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Difficulty.class, difficulty); - writer.write(BOOLEAN, locked); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Enum(Difficulty.class), ServerDifficultyPacket::difficulty, + BOOLEAN, ServerDifficultyPacket::locked, + ServerDifficultyPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java index b42cfb52c..a35cd5c93 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record SetCooldownPacket(int itemId, int cooldownTicks) implements ServerPacket.Play { - public SetCooldownPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, itemId); - writer.write(VAR_INT, cooldownTicks); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, SetCooldownPacket::itemId, + VAR_INT, SetCooldownPacket::cooldownTicks, + SetCooldownPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java index 74e35c7e0..137a8a7a3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetExperiencePacket.java @@ -1,22 +1,16 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record SetExperiencePacket(float percentage, int level, int totalExperience) implements ServerPacket.Play { - public SetExperiencePacket(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, percentage); - writer.write(VAR_INT, level); - writer.write(VAR_INT, totalExperience); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, SetExperiencePacket::percentage, + VAR_INT, SetExperiencePacket::level, + VAR_INT, SetExperiencePacket::totalExperience, + SetExperiencePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java index 940fad25d..31b421fc3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetPassengersPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,18 +13,12 @@ public record SetPassengersPacket(int vehicleEntityId, @NotNull List passengersId) implements ServerPacket.Play { public static final int MAX_PASSENGERS = 16384; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, SetPassengersPacket::vehicleEntityId, + VAR_INT.list(MAX_PASSENGERS), SetPassengersPacket::passengersId, + SetPassengersPacket::new); + public SetPassengersPacket { passengersId = List.copyOf(passengersId); } - - public SetPassengersPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readCollection(VAR_INT, MAX_PASSENGERS)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, vehicleEntityId); - writer.writeCollection(VAR_INT, passengersId); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java index 583cce95e..6bfd23af4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -16,18 +17,12 @@ import static net.minestom.server.network.NetworkBuffer.*; public record SetSlotPacket(byte windowId, int stateId, short slot, @NotNull ItemStack itemStack) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public SetSlotPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(VAR_INT), reader.read(SHORT), - reader.read(ItemStack.NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(VAR_INT, stateId); - writer.write(SHORT, slot); - writer.write(ItemStack.NETWORK_TYPE, itemStack); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, SetSlotPacket::windowId, + VAR_INT, SetSlotPacket::stateId, + SHORT, SetSlotPacket::slot, + ItemStack.NETWORK_TYPE, SetSlotPacket::itemStack, + SetSlotPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java index c68d7765d..9b3d5e898 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTickStatePacket.java @@ -1,22 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.FLOAT; public record SetTickStatePacket(float tickRate, boolean isFrozen) implements ServerPacket.Play { - - public SetTickStatePacket(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, tickRate); - writer.write(BOOLEAN, isFrozen); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, SetTickStatePacket::tickRate, + BOOLEAN, SetTickStatePacket::isFrozen, + SetTickStatePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java index 5907c6170..df4e1fa11 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleSubTitlePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -11,15 +12,11 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.COMPONENT; -public record SetTitleSubTitlePacket(@NotNull Component subtitle) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public SetTitleSubTitlePacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, subtitle); - } +public record SetTitleSubTitlePacket( + @NotNull Component subtitle) implements ServerPacket.Play, ServerPacket.ComponentHolding { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, SetTitleSubTitlePacket::subtitle, + SetTitleSubTitlePacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java index d244d7dbb..3bfafac9b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTextPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,14 +13,9 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.COMPONENT; public record SetTitleTextPacket(@NotNull Component title) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public SetTitleTextPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, title); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, SetTitleTextPacket::title, + SetTitleTextPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java index 400bd2dd8..b799c97fe 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetTitleTimePacket.java @@ -1,21 +1,15 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; public record SetTitleTimePacket(int fadeIn, int stay, int fadeOut) implements ServerPacket.Play { - public SetTitleTimePacket(@NotNull NetworkBuffer reader) { - this(reader.read(INT), reader.read(INT), reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, fadeIn); - writer.write(INT, stay); - writer.write(INT, fadeOut); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, SetTitleTimePacket::fadeIn, + INT, SetTitleTimePacket::stay, + INT, SetTitleTimePacket::fadeOut, + SetTitleTimePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java index e11765852..6404a983a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java @@ -20,33 +20,33 @@ public record SoundEffectPacket( float pitch, long seed ) implements ServerPacket.Play { + public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, SoundEffectPacket value) { + buffer.write(SoundEvent.NETWORK_TYPE, value.soundEvent()); + buffer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(value.source())); + buffer.write(INT, value.x() * 8); + buffer.write(INT, value.y() * 8); + buffer.write(INT, value.z() * 8); + buffer.write(FLOAT, value.volume()); + buffer.write(FLOAT, value.pitch()); + buffer.write(LONG, value.seed()); + } + + @Override + public SoundEffectPacket read(@NotNull NetworkBuffer buffer) { + return new SoundEffectPacket(buffer.read(SoundEvent.NETWORK_TYPE), + buffer.readEnum(Source.class), + buffer.read(INT) * 8, + buffer.read(INT) * 8, + buffer.read(INT) * 8, + buffer.read(FLOAT), + buffer.read(FLOAT), + buffer.read(LONG)); + } + }; public SoundEffectPacket(@NotNull SoundEvent soundEvent, @NotNull Source source, @NotNull Point position, float volume, float pitch, long seed) { this(soundEvent, source, position.blockX(), position.blockY(), position.blockZ(), volume, pitch, seed); } - - public SoundEffectPacket(@NotNull NetworkBuffer reader) { - this(reader.read(SoundEvent.NETWORK_TYPE), - reader.readEnum(Source.class), - reader.read(INT) * 8, - reader.read(INT) * 8, - reader.read(INT) * 8, - reader.read(FLOAT), - reader.read(FLOAT), - reader.read(LONG)); - } - - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SoundEvent.NETWORK_TYPE, soundEvent); - writer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(source)); - writer.write(INT, x * 8); - writer.write(INT, y * 8); - writer.write(INT, z * 8); - writer.write(FLOAT, volume); - writer.write(FLOAT, pitch); - writer.write(LONG, seed); - } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java index af5e738ef..711b55e37 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnEntityPacket.java @@ -12,32 +12,34 @@ import static net.minestom.server.network.NetworkBuffer.*; public record SpawnEntityPacket(int entityId, @NotNull UUID uuid, int type, @NotNull Pos position, float headRot, int data, short velocityX, short velocityY, short velocityZ) implements ServerPacket.Play { - public SpawnEntityPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(UUID), reader.read(VAR_INT), - new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(BYTE) * 360f / 256f, reader.read(BYTE) * 360f / 256f), reader.read(BYTE) * 360f / 256f, - reader.read(VAR_INT), reader.read(SHORT), reader.read(SHORT), reader.read(SHORT)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull SpawnEntityPacket value) { + buffer.write(VAR_INT, value.entityId); + buffer.write(UUID, value.uuid); + buffer.write(VAR_INT, value.type); - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(UUID, uuid); - writer.write(VAR_INT, type); + buffer.write(DOUBLE, value.position.x()); + buffer.write(DOUBLE, value.position.y()); + buffer.write(DOUBLE, value.position.z()); - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); + buffer.write(BYTE, (byte) (value.position.pitch() * 256 / 360)); + buffer.write(BYTE, (byte) (value.position.yaw() * 256 / 360)); + buffer.write(BYTE, (byte) (value.headRot * 256 / 360)); - writer.write(BYTE, (byte) (position.pitch() * 256 / 360)); - writer.write(BYTE, (byte) (position.yaw() * 256 / 360)); - writer.write(BYTE, (byte) (headRot * 256 / 360)); + buffer.write(VAR_INT, value.data); - writer.write(VAR_INT, data); - - writer.write(SHORT, velocityX); - writer.write(SHORT, velocityY); - writer.write(SHORT, velocityZ); - } + buffer.write(SHORT, value.velocityX); + buffer.write(SHORT, value.velocityY); + buffer.write(SHORT, value.velocityZ); + } + @Override + public @NotNull SpawnEntityPacket read(@NotNull NetworkBuffer buffer) { + return new SpawnEntityPacket(buffer.read(VAR_INT), buffer.read(UUID), buffer.read(VAR_INT), + new Pos(buffer.read(DOUBLE), buffer.read(DOUBLE), buffer.read(DOUBLE), + buffer.read(BYTE) * 360f / 256f, buffer.read(BYTE) * 360f / 256f), buffer.read(BYTE) * 360f / 256f, + buffer.read(VAR_INT), buffer.read(SHORT), buffer.read(SHORT), buffer.read(SHORT)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java index bbbee7f1f..7bb8c7a84 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnExperienceOrbPacket.java @@ -1,26 +1,18 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record SpawnExperienceOrbPacket(int entityId, - @NotNull Pos position, short expCount) implements ServerPacket.Play { - public SpawnExperienceOrbPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), - new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE)), reader.read(SHORT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, entityId); - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(SHORT, expCount); - } - + @NotNull Point position, short expCount) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, SpawnExperienceOrbPacket::entityId, + VECTOR3D, SpawnExperienceOrbPacket::position, + SHORT, SpawnExperienceOrbPacket::expCount, + SpawnExperienceOrbPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java index c3a0e06ff..3b361eac9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SpawnPositionPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -9,14 +10,8 @@ import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; import static net.minestom.server.network.NetworkBuffer.FLOAT; public record SpawnPositionPacket(@NotNull Point position, float angle) implements ServerPacket.Play { - public SpawnPositionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BLOCK_POSITION), reader.read(FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BLOCK_POSITION, position); - writer.write(FLOAT, angle); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, SpawnPositionPacket::position, + FLOAT, SpawnPositionPacket::angle, + SpawnPositionPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java index 2418edf2f..6518c9dae 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StartConfigurationPacket.java @@ -1,16 +1,9 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; public record StartConfigurationPacket() implements ServerPacket.Play { - public StartConfigurationPacket(NetworkBuffer reader) { - this(); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(StartConfigurationPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java index 76d7098dd..7248d1952 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StatisticsPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.statistic.StatisticCategory; import org.jetbrains.annotations.NotNull; @@ -12,31 +13,19 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record StatisticsPacket(@NotNull List statistics) implements ServerPacket.Play { public static final int MAX_ENTRIES = 16384; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Statistic.SERIALIZER.list(MAX_ENTRIES), StatisticsPacket::statistics, + StatisticsPacket::new); + public StatisticsPacket { statistics = List.copyOf(statistics); } - public StatisticsPacket(@NotNull NetworkBuffer reader) { - this(reader.readCollection(Statistic::new, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(statistics); - } - - public record Statistic(@NotNull StatisticCategory category, - int statisticId, int value) implements NetworkBuffer.Writer { - public Statistic(@NotNull NetworkBuffer reader) { - this(reader.readEnum(StatisticCategory.class), - reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, category.ordinal()); - writer.write(VAR_INT, statisticId); - writer.write(VAR_INT, value); - } + public record Statistic(@NotNull StatisticCategory category, int statisticId, int value) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(StatisticCategory.class), Statistic::category, + VAR_INT, Statistic::statisticId, + VAR_INT, Statistic::value, + Statistic::new); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java index 5467a3fc5..f87494d59 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java @@ -11,32 +11,26 @@ import static net.minestom.server.network.NetworkBuffer.*; public record StopSoundPacket(byte flags, @Nullable Sound.Source source, @Nullable String sound) implements ServerPacket.Play { - public StopSoundPacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } - - private StopSoundPacket(StopSoundPacket packet) { - this(packet.flags, packet.source, packet.sound); - } - - private static StopSoundPacket read(@NotNull NetworkBuffer reader) { - byte flags = reader.read(BYTE); - var source = flags == 3 || flags == 1 ? reader.readEnum(Sound.Source.class) : null; - var sound = flags == 2 || flags == 3 ? reader.read(STRING) : null; - return new StopSoundPacket(flags, source, sound); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, flags); - if (flags == 3 || flags == 1) { - assert source != null; - writer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(source)); + public static NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, StopSoundPacket value) { + buffer.write(BYTE, value.flags()); + if (value.flags == 3 || value.flags == 1) { + assert value.source != null; + buffer.write(VAR_INT, AdventurePacketConvertor.getSoundSourceValue(value.source)); + } + if (value.flags == 2 || value.flags == 3) { + assert value.sound != null; + buffer.write(STRING, value.sound); + } } - if (flags == 2 || flags == 3) { - assert sound != null; - writer.write(STRING, sound); - } - } + @Override + public StopSoundPacket read(@NotNull NetworkBuffer buffer) { + byte flags = buffer.read(BYTE); + var source = flags == 3 || flags == 1 ? buffer.readEnum(Sound.Source.class) : null; + var sound = flags == 2 || flags == 3 ? buffer.read(STRING) : null; + return new StopSoundPacket(flags, source, sound); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java index 69f214d2e..4867f3f45 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SystemChatPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -12,16 +13,12 @@ import java.util.function.UnaryOperator; import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.COMPONENT; -public record SystemChatPacket(@NotNull Component message, boolean overlay) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public SystemChatPacket(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, message); - writer.write(BOOLEAN, overlay); - } +public record SystemChatPacket(@NotNull Component message, + boolean overlay) implements ServerPacket.Play, ServerPacket.ComponentHolding { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, SystemChatPacket::message, + BOOLEAN, SystemChatPacket::overlay, + SystemChatPacket::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java index a74814039..527317622 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,22 +19,17 @@ public record TabCompletePacket(int transactionId, int start, int length, @NotNull List matches) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final int MAX_ENTRIES = Short.MAX_VALUE; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, TabCompletePacket::transactionId, + VAR_INT, TabCompletePacket::start, + VAR_INT, TabCompletePacket::length, + Match.SERIALIZER.list(MAX_ENTRIES), TabCompletePacket::matches, + TabCompletePacket::new); + public TabCompletePacket { matches = List.copyOf(matches); } - public TabCompletePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readCollection(Match::new, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, transactionId); - writer.write(VAR_INT, start); - writer.write(VAR_INT, length); - writer.writeCollection(matches); - } - @Override public @NotNull Collection components() { if (matches.isEmpty()) return List.of(); @@ -55,16 +51,11 @@ public record TabCompletePacket(int transactionId, int start, int length, } public record Match(@NotNull String match, - @Nullable Component tooltip) implements NetworkBuffer.Writer, ComponentHolder { - public Match(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(BOOLEAN) ? reader.read(COMPONENT) : null); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, match); - writer.writeOptional(COMPONENT, tooltip); - } + @Nullable Component tooltip) implements ComponentHolder { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Match::match, + COMPONENT.optional(), Match::tooltip, + Match::new); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java index b1b47451e..b1d284f7b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java @@ -21,23 +21,26 @@ import static net.minestom.server.network.NetworkBuffer.*; public record TeamsPacket(String teamName, Action action) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final int MAX_MEMBERS = 16384; - public TeamsPacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), switch (reader.read(BYTE)) { - case 0 -> new CreateTeamAction(reader); - case 1 -> new RemoveTeamAction(); - case 2 -> new UpdateTeamAction(reader); - case 3 -> new AddEntitiesToTeamAction(reader); - case 4 -> new RemoveEntitiesToTeamAction(reader); - default -> throw new RuntimeException("Unknown action id"); - }); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, TeamsPacket value) { + buffer.write(STRING, value.teamName); + buffer.write(BYTE, (byte) value.action.id()); + buffer.write(value.action); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, teamName); - writer.write(BYTE, (byte) action.id()); - writer.write(action); - } + @Override + public @NotNull TeamsPacket read(@NotNull NetworkBuffer buffer) { + return new TeamsPacket(buffer.read(STRING), switch (buffer.read(BYTE)) { + case 0 -> new CreateTeamAction(buffer); + case 1 -> new RemoveTeamAction(); + case 2 -> new UpdateTeamAction(buffer); + case 3 -> new AddEntitiesToTeamAction(buffer); + case 4 -> new RemoveEntitiesToTeamAction(buffer); + default -> throw new RuntimeException("Unknown action id"); + }); + } + }; @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java index 25d2979b5..27bafd7a5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TickStepPacket.java @@ -1,20 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record TickStepPacket(int steps) implements ServerPacket.Play { - - public TickStepPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, steps); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, TickStepPacket::steps, + TickStepPacket::new); } 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 f42f85680..da23b5009 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 @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.LONG; public record TimeUpdatePacket(long worldAge, long timeOfDay) implements ServerPacket.Play { - public TimeUpdatePacket(@NotNull NetworkBuffer reader) { - this(reader.read(LONG), reader.read(LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, worldAge); - writer.write(LONG, timeOfDay); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG, TimeUpdatePacket::worldAge, + LONG, TimeUpdatePacket::timeOfDay, + TimeUpdatePacket::new); } 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 3334a36a7..89569264d 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 @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -14,49 +15,34 @@ public record TradeListPacket(int windowId, @NotNull List trades, boolean regularVillager, boolean canRestock) implements ServerPacket.Play { public static final int MAX_TRADES = Short.MAX_VALUE; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, TradeListPacket::windowId, + Trade.SERIALIZER.list(MAX_TRADES), TradeListPacket::trades, + VAR_INT, TradeListPacket::villagerLevel, + VAR_INT, TradeListPacket::experience, + BOOLEAN, TradeListPacket::regularVillager, + BOOLEAN, TradeListPacket::canRestock, + TradeListPacket::new); + public TradeListPacket { trades = List.copyOf(trades); } - public TradeListPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readCollection(Trade::new, MAX_TRADES), - reader.read(VAR_INT), reader.read(VAR_INT), - reader.read(BOOLEAN), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, windowId); - writer.writeCollection(trades); - writer.write(VAR_INT, villagerLevel); - writer.write(VAR_INT, experience); - writer.write(BOOLEAN, regularVillager); - writer.write(BOOLEAN, canRestock); - } - public record Trade(ItemStack inputItem1, ItemStack result, ItemStack inputItem2, boolean tradeDisabled, int tradeUsesNumber, int maxTradeUsesNumber, int exp, - int specialPrice, float priceMultiplier, int demand) implements NetworkBuffer.Writer { - public Trade(@NotNull NetworkBuffer reader) { - this(reader.read(ItemStack.NETWORK_TYPE), reader.read(ItemStack.NETWORK_TYPE), - reader.readOptional(ItemStack.NETWORK_TYPE), reader.read(BOOLEAN), - reader.read(INT), reader.read(INT), reader.read(INT), - reader.read(INT), reader.read(FLOAT), reader.read(INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(ItemStack.NETWORK_TYPE, inputItem1); - writer.write(ItemStack.NETWORK_TYPE, result); - writer.writeOptional(ItemStack.NETWORK_TYPE, inputItem2); - writer.write(BOOLEAN, tradeDisabled); - writer.write(INT, tradeUsesNumber); - writer.write(INT, maxTradeUsesNumber); - writer.write(INT, exp); - writer.write(INT, specialPrice); - writer.write(FLOAT, priceMultiplier); - writer.write(INT, demand); - } + int specialPrice, float priceMultiplier, int demand) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + ItemStack.NETWORK_TYPE, Trade::inputItem1, + ItemStack.NETWORK_TYPE, Trade::result, + ItemStack.NETWORK_TYPE.optional(), Trade::inputItem2, + BOOLEAN, Trade::tradeDisabled, + INT, Trade::tradeUsesNumber, + INT, Trade::maxTradeUsesNumber, + INT, Trade::exp, + INT, Trade::specialPrice, + FLOAT, Trade::priceMultiplier, + INT, Trade::demand, + Trade::new); } } 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 e11aeb4e1..33759df6f 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 @@ -7,24 +7,19 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.INT; public record UnloadChunkPacket(int chunkX, int chunkZ) implements ServerPacket.Play { - public UnloadChunkPacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, UnloadChunkPacket value) { + // Client reads this as a single long in big endian, so we have to write it backwards + buffer.write(INT, value.chunkZ); + buffer.write(INT, value.chunkX); + } - private UnloadChunkPacket(@NotNull UnloadChunkPacket other) { - this(other.chunkX(), other.chunkZ()); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - // Client reads this as a single long in big endian, so we have to write it backwards - writer.write(INT, chunkZ); - writer.write(INT, chunkX); - } - - private static UnloadChunkPacket read(@NotNull NetworkBuffer reader) { - int z = reader.read(INT); - int x = reader.read(INT); - return new UnloadChunkPacket(x, z); - } + @Override + public UnloadChunkPacket read(@NotNull NetworkBuffer buffer) { + int z = buffer.read(INT); + int x = buffer.read(INT); + return new UnloadChunkPacket(x, z); + } + }; } 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 81164fb05..a0da0be28 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 @@ -23,55 +23,44 @@ public record UnlockRecipesPacket(int mode, } } - public UnlockRecipesPacket(@NotNull NetworkBuffer reader) { - this(read(reader)); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, UnlockRecipesPacket value) { + buffer.write(VAR_INT, value.mode); + buffer.write(BOOLEAN, value.craftingRecipeBookOpen); + buffer.write(BOOLEAN, value.craftingRecipeBookFilterActive); + buffer.write(BOOLEAN, value.smeltingRecipeBookOpen); + buffer.write(BOOLEAN, value.smeltingRecipeBookFilterActive); + buffer.write(BOOLEAN, value.blastFurnaceRecipeBookOpen); + buffer.write(BOOLEAN, value.blastFurnaceRecipeBookFilterActive); + buffer.write(BOOLEAN, value.smokerRecipeBookOpen); + buffer.write(BOOLEAN, value.smokerRecipeBookFilterActive); - private UnlockRecipesPacket(UnlockRecipesPacket packet) { - this(packet.mode, - packet.craftingRecipeBookOpen, packet.craftingRecipeBookFilterActive, - packet.smeltingRecipeBookOpen, packet.smeltingRecipeBookFilterActive, - packet.blastFurnaceRecipeBookOpen, packet.blastFurnaceRecipeBookFilterActive, - packet.smokerRecipeBookOpen, packet.smokerRecipeBookFilterActive, - packet.recipeIds, packet.initRecipeIds); - } - - private static UnlockRecipesPacket read(@NotNull NetworkBuffer reader) { - var mode = reader.read(VAR_INT); - var craftingRecipeBookOpen = reader.read(BOOLEAN); - var craftingRecipeBookFilterActive = reader.read(BOOLEAN); - var smeltingRecipeBookOpen = reader.read(BOOLEAN); - var smeltingRecipeBookFilterActive = reader.read(BOOLEAN); - var blastFurnaceRecipeBookOpen = reader.read(BOOLEAN); - var blastFurnaceRecipeBookFilterActive = reader.read(BOOLEAN); - var smokerRecipeBookOpen = reader.read(BOOLEAN); - var smokerRecipeBookFilterActive = reader.read(BOOLEAN); - var recipeIds = reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES); - var initRecipeIds = mode == 0 ? reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES) : null; - return new UnlockRecipesPacket(mode, - craftingRecipeBookOpen, craftingRecipeBookFilterActive, - smeltingRecipeBookOpen, smeltingRecipeBookFilterActive, - blastFurnaceRecipeBookOpen, blastFurnaceRecipeBookFilterActive, - smokerRecipeBookOpen, smokerRecipeBookFilterActive, - recipeIds, initRecipeIds); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, mode); - writer.write(BOOLEAN, craftingRecipeBookOpen); - writer.write(BOOLEAN, craftingRecipeBookFilterActive); - writer.write(BOOLEAN, smeltingRecipeBookOpen); - writer.write(BOOLEAN, smeltingRecipeBookFilterActive); - writer.write(BOOLEAN, blastFurnaceRecipeBookOpen); - writer.write(BOOLEAN, blastFurnaceRecipeBookFilterActive); - writer.write(BOOLEAN, smokerRecipeBookOpen); - writer.write(BOOLEAN, smokerRecipeBookFilterActive); - - writer.writeCollection(STRING, recipeIds); - if (mode == 0) { - writer.writeCollection(STRING, initRecipeIds); + buffer.writeCollection(STRING, value.recipeIds); + if (value.mode == 0) { + buffer.writeCollection(STRING, value.initRecipeIds); + } } - } + @Override + public UnlockRecipesPacket read(@NotNull NetworkBuffer buffer) { + var mode = buffer.read(VAR_INT); + var craftingRecipeBookOpen = buffer.read(BOOLEAN); + var craftingRecipeBookFilterActive = buffer.read(BOOLEAN); + var smeltingRecipeBookOpen = buffer.read(BOOLEAN); + var smeltingRecipeBookFilterActive = buffer.read(BOOLEAN); + var blastFurnaceRecipeBookOpen = buffer.read(BOOLEAN); + var blastFurnaceRecipeBookFilterActive = buffer.read(BOOLEAN); + var smokerRecipeBookOpen = buffer.read(BOOLEAN); + var smokerRecipeBookFilterActive = buffer.read(BOOLEAN); + var recipeIds = buffer.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES); + var initRecipeIds = mode == 0 ? buffer.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES) : null; + return new UnlockRecipesPacket(mode, + craftingRecipeBookOpen, craftingRecipeBookFilterActive, + smeltingRecipeBookOpen, smeltingRecipeBookFilterActive, + blastFurnaceRecipeBookOpen, blastFurnaceRecipeBookFilterActive, + smokerRecipeBookOpen, smokerRecipeBookFilterActive, + recipeIds, initRecipeIds); + } + }; } 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 4512d1aca..a34b43cf5 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 @@ -1,22 +1,16 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.FLOAT; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateHealthPacket(float health, int food, float foodSaturation) implements ServerPacket.Play { - public UpdateHealthPacket(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(VAR_INT), reader.read(FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, health); - writer.write(VAR_INT, food); - writer.write(FLOAT, foodSaturation); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, UpdateHealthPacket::health, + VAR_INT, UpdateHealthPacket::food, + FLOAT, UpdateHealthPacket::foodSaturation, + UpdateHealthPacket::new); } 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 58074c41d..c06c54007 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 @@ -9,15 +9,17 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateLightPacket(int chunkX, int chunkZ, @NotNull LightData lightData) implements ServerPacket.Play { - public UpdateLightPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT), new LightData(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, chunkX); - writer.write(VAR_INT, chunkZ); - writer.write(lightData); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, UpdateLightPacket value) { + buffer.write(VAR_INT, value.chunkX); + buffer.write(VAR_INT, value.chunkZ); + buffer.write(value.lightData); + } + @Override + public UpdateLightPacket read(@NotNull NetworkBuffer buffer) { + return new UpdateLightPacket(buffer.read(VAR_INT), buffer.read(VAR_INT), new LightData(buffer)); + } + }; } 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 2a13400b8..688c9080f 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 @@ -20,18 +20,20 @@ public record UpdateScorePacket( @Nullable Component displayName, @Nullable Sidebar.NumberFormat numberFormat ) implements ServerPacket.Play { - public UpdateScorePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(STRING), reader.read(VAR_INT), - reader.readOptional(COMPONENT), reader.readOptional(Sidebar.NumberFormat::new)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, entityName); - writer.write(STRING, objectiveName); - writer.write(VAR_INT, score); - writer.writeOptional(COMPONENT, displayName); - writer.writeOptional(numberFormat); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, @NotNull UpdateScorePacket value) { + buffer.write(STRING, value.entityName); + buffer.write(STRING, value.objectiveName); + buffer.write(VAR_INT, value.score); + buffer.writeOptional(COMPONENT, value.displayName); + buffer.writeOptional(value.numberFormat); + } + @Override + public @NotNull UpdateScorePacket read(@NotNull NetworkBuffer buffer) { + return new UpdateScorePacket(buffer.read(STRING), buffer.read(STRING), buffer.read(VAR_INT), + buffer.readOptional(COMPONENT), buffer.readOptional(Sidebar.NumberFormat::new)); + } + }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java index 92ad62edf..6e6631436 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/UpdateSimulationDistancePacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateSimulationDistancePacket(int simulationDistance) implements ServerPacket.Play { - public UpdateSimulationDistancePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, simulationDistance); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, UpdateSimulationDistancePacket::simulationDistance, + UpdateSimulationDistancePacket::new); } 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 a958334cc..7ce100bd8 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 @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateViewDistancePacket(int viewDistance) implements ServerPacket.Play { - public UpdateViewDistancePacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, viewDistance); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, UpdateViewDistancePacket::viewDistance, + UpdateViewDistancePacket::new); } 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 b060776d6..ec87a90e7 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 @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateViewPositionPacket(int chunkX, int chunkZ) implements ServerPacket.Play { - public UpdateViewPositionPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, chunkX); - writer.write(VAR_INT, chunkZ); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, UpdateViewPositionPacket::chunkX, + VAR_INT, UpdateViewPositionPacket::chunkZ, + UpdateViewPositionPacket::new); } 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 e9b713d7d..d24f4f200 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,25 +2,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.DOUBLE; -import static net.minestom.server.network.NetworkBuffer.FLOAT; +import static net.minestom.server.network.NetworkBuffer.POS; public record VehicleMovePacket(@NotNull Pos position) implements ServerPacket.Play { - public VehicleMovePacket(@NotNull NetworkBuffer reader) { - this(new Pos(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(DOUBLE), - reader.read(FLOAT), reader.read(FLOAT))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, position.x()); - writer.write(DOUBLE, position.y()); - writer.write(DOUBLE, position.z()); - writer.write(FLOAT, position.yaw()); - writer.write(FLOAT, position.pitch()); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + POS, VehicleMovePacket::position, VehicleMovePacket::new); } 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 b3ac10fd0..fcc73c8f0 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 @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -19,23 +20,17 @@ public record WindowItemsPacket(byte windowId, int stateId, @NotNull List SERIALIZER = NetworkBufferTemplate.template( + BYTE, WindowItemsPacket::windowId, + VAR_INT, WindowItemsPacket::stateId, + ItemStack.NETWORK_TYPE.list(MAX_ENTRIES), WindowItemsPacket::items, + ItemStack.NETWORK_TYPE, WindowItemsPacket::carriedItem, + WindowItemsPacket::new); + public WindowItemsPacket { items = List.copyOf(items); } - public WindowItemsPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(VAR_INT), reader.readCollection(ItemStack.NETWORK_TYPE, MAX_ENTRIES), - reader.read(ItemStack.NETWORK_TYPE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(VAR_INT, stateId); - writer.writeCollection(ItemStack.NETWORK_TYPE, items); - writer.write(ItemStack.NETWORK_TYPE, carriedItem); - } - @Override public @NotNull Collection components() { final var list = new ArrayList<>(this.items); @@ -71,9 +66,9 @@ public record WindowItemsPacket(byte windowId, int stateId, @NotNull List stack - .with(ItemComponent.ITEM_NAME, operator) - .with(ItemComponent.CUSTOM_NAME, operator) - .with(ItemComponent.LORE, loreOperator)) + .with(ItemComponent.ITEM_NAME, operator) + .with(ItemComponent.CUSTOM_NAME, operator) + .with(ItemComponent.LORE, loreOperator)) .toList(), this.carriedItem .with(ItemComponent.ITEM_NAME, operator) 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 e79640516..f00485901 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 @@ -1,22 +1,16 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.SHORT; public record WindowPropertyPacket(byte windowId, short property, short value) implements ServerPacket.Play { - public WindowPropertyPacket(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE), reader.read(SHORT), reader.read(SHORT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, windowId); - writer.write(SHORT, property); - writer.write(SHORT, value); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, WindowPropertyPacket::windowId, + SHORT, WindowPropertyPacket::property, + SHORT, WindowPropertyPacket::value, + WindowPropertyPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java index 14562fc25..0e9793bf5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderCenterPacket.java @@ -1,20 +1,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; public record WorldBorderCenterPacket(double x, double z) implements ServerPacket.Play { - public WorldBorderCenterPacket(@NotNull NetworkBuffer reader) { - this(reader.read(DOUBLE), reader.read(DOUBLE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, x); - writer.write(DOUBLE, z); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + DOUBLE, WorldBorderCenterPacket::x, + DOUBLE, WorldBorderCenterPacket::z, + WorldBorderCenterPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java index a690e2eac..523a3a1e3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderLerpSizePacket.java @@ -1,22 +1,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; import static net.minestom.server.network.NetworkBuffer.VAR_LONG; -public record WorldBorderLerpSizePacket(double oldDiameter, double newDiameter, long speed) implements ServerPacket.Play { - public WorldBorderLerpSizePacket(@NotNull NetworkBuffer reader) { - this(reader.read(DOUBLE), reader.read(DOUBLE), reader.read(VAR_LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, oldDiameter); - writer.write(DOUBLE, newDiameter); - writer.write(VAR_LONG, speed); - } - +public record WorldBorderLerpSizePacket(double oldDiameter, double newDiameter, + long speed) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + DOUBLE, WorldBorderLerpSizePacket::oldDiameter, + DOUBLE, WorldBorderLerpSizePacket::newDiameter, + VAR_LONG, WorldBorderLerpSizePacket::speed, + WorldBorderLerpSizePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java index 3ce678090..f115d4d4e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderSizePacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.DOUBLE; public record WorldBorderSizePacket(double diameter) implements ServerPacket.Play { - public WorldBorderSizePacket(@NotNull NetworkBuffer reader) { - this(reader.read(DOUBLE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(DOUBLE, diameter); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + DOUBLE, WorldBorderSizePacket::diameter, + WorldBorderSizePacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java index f1f3c031a..35fc9274c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningDelayPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record WorldBorderWarningDelayPacket(int warningTime) implements ServerPacket.Play { - public WorldBorderWarningDelayPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, warningTime); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, WorldBorderWarningDelayPacket::warningTime, + WorldBorderWarningDelayPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java index 5169986a4..fcc6cf742 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/WorldBorderWarningReachPacket.java @@ -1,19 +1,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record WorldBorderWarningReachPacket(int warningBlocks) implements ServerPacket.Play { - public WorldBorderWarningReachPacket(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, warningBlocks); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, WorldBorderWarningReachPacket::warningBlocks, + WorldBorderWarningReachPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java index 0be655ba0..c89b25836 100644 --- a/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/status/ResponsePacket.java @@ -1,19 +1,14 @@ package net.minestom.server.network.packet.server.status; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.STRING; public record ResponsePacket(@NotNull String jsonResponse) implements ServerPacket.Status { - public ResponsePacket(@NotNull NetworkBuffer reader) { - this(reader.read(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, jsonResponse); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ResponsePacket::jsonResponse, + ResponsePacket::new); } diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java index c40b6c996..ca46d2fd1 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -18,23 +18,23 @@ import static net.minestom.server.recipe.RecipeCategory.Crafting; public final class RecipeSerializers { public static final Type RECIPE = new Type<>() { @Override - public void write(@NotNull NetworkBuffer writer, Recipe shaped) { - writer.write(STRING, shaped.id()); + public void write(@NotNull NetworkBuffer buffer, Recipe shaped) { + buffer.write(STRING, shaped.id()); final RecipeType recipeType = recipeToType(shaped.data()); - writer.write(RecipeType.NETWORK_TYPE, recipeType); + buffer.write(RecipeType.NETWORK_TYPE, recipeType); var serializer = RecipeSerializers.dataSerializer(recipeType); if (serializer == null) throw new UnsupportedOperationException("Unrecognized type: " + recipeType); - serializer.write(writer, shaped.data()); + serializer.write(buffer, shaped.data()); } @Override - public Recipe read(@NotNull NetworkBuffer reader) { - final String identifier = reader.read(STRING); - final RecipeType type = reader.read(RecipeType.NETWORK_TYPE); + public Recipe read(@NotNull NetworkBuffer buffer) { + final String identifier = buffer.read(STRING); + final RecipeType type = buffer.read(RecipeType.NETWORK_TYPE); var serializer = RecipeSerializers.dataSerializer(type); if (serializer == null) throw new UnsupportedOperationException("Unrecognized type: " + type); - final Data data = serializer.read(reader); + final Data data = serializer.read(buffer); return new Recipe(identifier, data); } }; @@ -46,30 +46,30 @@ public final class RecipeSerializers { public static final Type SHAPED = new Type<>() { @Override - public void write(@NotNull NetworkBuffer writer, Shaped shaped) { - writer.write(STRING, shaped.group()); - writer.writeEnum(Crafting.class, shaped.category()); - writer.write(VAR_INT, shaped.width()); - writer.write(VAR_INT, shaped.height()); + public void write(@NotNull NetworkBuffer buffer, Shaped shaped) { + buffer.write(STRING, shaped.group()); + buffer.writeEnum(Crafting.class, shaped.category()); + buffer.write(VAR_INT, shaped.width()); + buffer.write(VAR_INT, shaped.height()); for (Ingredient ingredient : shaped.ingredients()) { - writer.write(INGREDIENT, ingredient); + buffer.write(INGREDIENT, ingredient); } - writer.write(ItemStack.STRICT_NETWORK_TYPE, shaped.result()); - writer.write(BOOLEAN, shaped.showNotification()); + buffer.write(ItemStack.STRICT_NETWORK_TYPE, shaped.result()); + buffer.write(BOOLEAN, shaped.showNotification()); } @Override - public Shaped read(@NotNull NetworkBuffer reader) { - String group = reader.read(STRING); - Crafting category = reader.readEnum(Crafting.class); - int width = reader.read(VAR_INT); - int height = reader.read(VAR_INT); + public Shaped read(@NotNull NetworkBuffer buffer) { + String group = buffer.read(STRING); + Crafting category = buffer.readEnum(Crafting.class); + int width = buffer.read(VAR_INT); + int height = buffer.read(VAR_INT); List ingredients = new ArrayList<>(); for (int slot = 0; slot < width * height; slot++) { - ingredients.add(reader.read(INGREDIENT)); + ingredients.add(buffer.read(INGREDIENT)); } - ItemStack result = reader.read(ItemStack.STRICT_NETWORK_TYPE); - boolean showNotification = reader.read(BOOLEAN); + ItemStack result = buffer.read(ItemStack.STRICT_NETWORK_TYPE); + boolean showNotification = buffer.read(BOOLEAN); return new Shaped(group, category, width, height, ingredients, result, showNotification); } }; diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java index 0935eb2d7..7e8ddcf89 100644 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketUtils.java @@ -253,21 +253,24 @@ public final class PacketUtils { @NotNull ByteBuffer buffer, @NotNull ServerPacket packet, boolean compression) { - PacketRegistry registry = SERVER_PACKET_PARSER.stateRegistry(state); - final int id = registry.packetId(packet.getClass()); - writeFramedPacket(buffer, id, packet, compression ? MinecraftServer.getCompressionThreshold() : 0); + final PacketRegistry registry = SERVER_PACKET_PARSER.stateRegistry(state); + final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet.getClass()); + final int id = packetInfo.id(); + final NetworkBuffer.Type serializer = packetInfo.serializer(); + writeFramedPacket(buffer, id, serializer, packet, compression ? MinecraftServer.getCompressionThreshold() : 0); } public static void writeFramedPacket(@NotNull ByteBuffer buffer, int id, - @NotNull NetworkBuffer.Writer writer, + @NotNull NetworkBuffer.Type type, + @NotNull ServerPacket packet, int compressionThreshold) { NetworkBuffer networkBuffer = new NetworkBuffer(buffer, false); if (compressionThreshold <= 0) { // Uncompressed format https://wiki.vg/Protocol#Without_compression final int lengthIndex = networkBuffer.skipWrite(3); networkBuffer.write(NetworkBuffer.VAR_INT, id); - networkBuffer.write(writer); + type.write(networkBuffer, packet); final int finalSize = networkBuffer.writeIndex() - (lengthIndex + 3); Utils.writeVarIntHeader(buffer, lengthIndex, finalSize); buffer.position(networkBuffer.writeIndex()); @@ -279,7 +282,7 @@ public final class PacketUtils { final int contentStart = networkBuffer.writeIndex(); networkBuffer.write(NetworkBuffer.VAR_INT, id); - networkBuffer.write(writer); + type.write(networkBuffer, packet); final int packetSize = networkBuffer.writeIndex() - contentStart; final boolean compressed = packetSize >= compressionThreshold; if (compressed) { From b5a53f8b6b79b523032dc4c3b26a32f963b01a66 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 24 Jul 2024 21:49:52 +0200 Subject: [PATCH 09/97] Remove BinaryReader/Writer (#2291) * Remove BinaryReader/Writer * Fix UpdateEnabledFeaturesPacket --- .../builder/arguments/ArgumentString.java | 6 +- .../arguments/ArgumentStringArray.java | 6 +- .../builder/arguments/ArgumentWord.java | 6 +- .../arguments/minecraft/ArgumentEntity.java | 6 +- .../arguments/minecraft/ArgumentResource.java | 6 +- .../minecraft/ArgumentResourceOrTag.java | 6 +- .../arguments/minecraft/ArgumentTime.java | 6 +- .../arguments/number/ArgumentDouble.java | 5 +- .../arguments/number/ArgumentFloat.java | 5 +- .../arguments/number/ArgumentInteger.java | 5 +- .../arguments/number/ArgumentLong.java | 5 +- .../arguments/number/ArgumentNumber.java | 17 +- .../minestom/server/extras/query/Query.java | 32 +- .../server/extras/query/event/QueryEvent.java | 4 +- .../query/response/BasicQueryResponse.java | 22 +- .../query/response/FullQueryResponse.java | 26 +- .../server/network/ConnectionManager.java | 3 +- .../server/network/NetworkBuffer.java | 1 + .../server/network/NetworkBufferTypeImpl.java | 22 ++ .../packet/server/play/ExplosionPacket.java | 43 ++- .../server/utils/binary/BinaryReader.java | 286 ------------------ .../server/utils/binary/BinaryWriter.java | 258 ---------------- .../server/utils/binary/Readable.java | 17 -- .../server/utils/binary/Writeable.java | 17 -- 24 files changed, 119 insertions(+), 691 deletions(-) delete mode 100644 src/main/java/net/minestom/server/utils/binary/BinaryReader.java delete mode 100644 src/main/java/net/minestom/server/utils/binary/BinaryWriter.java delete mode 100644 src/main/java/net/minestom/server/utils/binary/Readable.java delete mode 100644 src/main/java/net/minestom/server/utils/binary/Writeable.java diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java index 6c6f78039..1a19db780 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java @@ -2,8 +2,8 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,8 +37,8 @@ public class ArgumentString extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { - packetWriter.writeVarInt(1); // Quotable phrase + return NetworkBuffer.makeArray(buffer -> { + buffer.write(NetworkBuffer.VAR_INT, 1); // Quotable phrase }); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java index 3e41f18d7..52dee3837 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java @@ -1,8 +1,8 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.command.CommandSender; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,8 +32,8 @@ public class ArgumentStringArray extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { - packetWriter.writeVarInt(2); // Greedy phrase + return NetworkBuffer.makeArray(buffer -> { + buffer.write(NetworkBuffer.VAR_INT, 2); // Greedy phrase }); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java index 8dcbc8933..0a47a1ec5 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java @@ -2,8 +2,8 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -75,8 +75,8 @@ public class ArgumentWord extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { - packetWriter.writeVarInt(0); // Single word + return NetworkBuffer.makeArray(buffer -> { + buffer.write(NetworkBuffer.VAR_INT, 0); // Single word }); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java index 33f3d0214..04b4d6558 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentEntity.java @@ -5,9 +5,9 @@ import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.Range; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.entity.EntityFinder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -78,7 +78,7 @@ public class ArgumentEntity extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { + return NetworkBuffer.makeArray(buffer -> { byte mask = 0; if (this.isOnlySingleEntity()) { mask |= 0x01; @@ -86,7 +86,7 @@ public class ArgumentEntity extends Argument { if (this.isOnlyPlayers()) { mask |= 0x02; } - packetWriter.writeByte(mask); + buffer.write(NetworkBuffer.BYTE, mask); }); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java index 7042d24a4..d1a666c3d 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java @@ -3,8 +3,8 @@ package net.minestom.server.command.builder.arguments.minecraft; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,8 +39,6 @@ public class ArgumentResource extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> - packetWriter.writeSizedString(this.identifier) - ); + return NetworkBuffer.makeArray(buffer -> buffer.write(NetworkBuffer.STRING, identifier)); } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java index b54c63c61..5d48a7f18 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java @@ -3,8 +3,8 @@ package net.minestom.server.command.builder.arguments.minecraft; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,8 +39,8 @@ public class ArgumentResourceOrTag extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> - packetWriter.writeSizedString(this.identifier) + return NetworkBuffer.makeArray(buffer -> + buffer.write(NetworkBuffer.STRING, this.identifier) ); } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java index b7f5e4ee8..779f104c2 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java @@ -5,7 +5,7 @@ import it.unimi.dsi.fastutil.chars.CharList; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.time.TimeUnit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -70,9 +70,7 @@ public class ArgumentTime extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { - packetWriter.writeInt(min); - }); + return NetworkBuffer.makeArray(buffer -> buffer.write(NetworkBuffer.INT, min)); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentDouble.java b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentDouble.java index 49548fdae..74ae4aff5 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentDouble.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentDouble.java @@ -1,11 +1,12 @@ package net.minestom.server.command.builder.arguments.number; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; public class ArgumentDouble extends ArgumentNumber { public ArgumentDouble(String id) { - super(id, "brigadier:double", Double::parseDouble, ((s, radix) -> (double) Long.parseLong(s, radix)), BinaryWriter::writeDouble, Double::compare); + super(id, "brigadier:double", Double::parseDouble, ((s, radix) -> (double) Long.parseLong(s, radix)), + NetworkBuffer.DOUBLE, Double::compare); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentFloat.java b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentFloat.java index 93094da62..50d233d60 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentFloat.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentFloat.java @@ -1,11 +1,12 @@ package net.minestom.server.command.builder.arguments.number; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; public class ArgumentFloat extends ArgumentNumber { public ArgumentFloat(String id) { - super(id, "brigadier:float", Float::parseFloat, (s, radix) -> (float) Integer.parseInt(s, radix), BinaryWriter::writeFloat, Float::compare); + super(id, "brigadier:float", Float::parseFloat, (s, radix) -> (float) Integer.parseInt(s, radix), + NetworkBuffer.FLOAT, Float::compare); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentInteger.java b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentInteger.java index 0baf8fc10..d637675a4 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentInteger.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentInteger.java @@ -1,11 +1,12 @@ package net.minestom.server.command.builder.arguments.number; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; public class ArgumentInteger extends ArgumentNumber { public ArgumentInteger(String id) { - super(id, "brigadier:integer", Integer::parseInt, Integer::parseInt, BinaryWriter::writeInt, Integer::compare); + super(id, "brigadier:integer", Integer::parseInt, Integer::parseInt, + NetworkBuffer.INT, Integer::compare); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentLong.java b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentLong.java index cc2984db7..30745a8fa 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentLong.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentLong.java @@ -1,11 +1,12 @@ package net.minestom.server.command.builder.arguments.number; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; public class ArgumentLong extends ArgumentNumber { public ArgumentLong(String id) { - super(id, "brigadier:long", Long::parseLong, Long::parseLong, BinaryWriter::writeLong, Long::compare); + super(id, "brigadier:long", Long::parseLong, Long::parseLong, + NetworkBuffer.LONG, Long::compare); } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentNumber.java b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentNumber.java index d1977c906..0cb12a41b 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentNumber.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/number/ArgumentNumber.java @@ -3,13 +3,12 @@ package net.minestom.server.command.builder.arguments.number; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; -import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; import java.util.Comparator; -import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import java.util.regex.Pattern; @@ -26,17 +25,17 @@ public class ArgumentNumber extends Argument { protected final String parserName; protected final BiFunction radixParser; protected final Function parser; - protected final BiConsumer propertiesWriter; + protected final NetworkBuffer.Type networkType; protected final Comparator comparator; ArgumentNumber(@NotNull String id, String parserName, Function parser, - BiFunction radixParser, BiConsumer propertiesWriter, + BiFunction radixParser, NetworkBuffer.Type networkType, Comparator comparator) { super(id); this.parserName = parserName; this.radixParser = radixParser; this.parser = parser; - this.propertiesWriter = propertiesWriter; + this.networkType = networkType; this.comparator = comparator; } @@ -72,12 +71,12 @@ public class ArgumentNumber extends Argument { @Override public byte @Nullable [] nodeProperties() { - return BinaryWriter.makeArray(packetWriter -> { - packetWriter.writeByte(getNumberProperties()); + return NetworkBuffer.makeArray(buffer -> { + buffer.write(NetworkBuffer.BYTE, getNumberProperties()); if (this.hasMin()) - propertiesWriter.accept(packetWriter, getMin()); + networkType.write(buffer, getMin()); if (this.hasMax()) - propertiesWriter.accept(packetWriter, getMax()); + networkType.write(buffer, getMax()); }); } diff --git a/src/main/java/net/minestom/server/extras/query/Query.java b/src/main/java/net/minestom/server/extras/query/Query.java index 34087ced1..e60a610a4 100644 --- a/src/main/java/net/minestom/server/extras/query/Query.java +++ b/src/main/java/net/minestom/server/extras/query/Query.java @@ -7,9 +7,8 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.event.EventDispatcher; import net.minestom.server.extras.query.event.BasicQueryEvent; import net.minestom.server.extras.query.event.FullQueryEvent; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.timer.Task; -import net.minestom.server.utils.binary.BinaryWriter; -import net.minestom.server.utils.binary.Writeable; import net.minestom.server.utils.time.TimeUnit; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -158,13 +157,13 @@ public class Query { CHALLENGE_TOKENS.put(challengeToken, packet.getSocketAddress()); // send the response - BinaryWriter response = new BinaryWriter(32); - response.writeByte((byte) 9); - response.writeInt(sessionID); - response.writeNullTerminatedString(String.valueOf(challengeToken), CHARSET); + final byte[] responseData = NetworkBuffer.makeArray(response -> { + response.write(NetworkBuffer.BYTE, (byte) 9); + response.write(NetworkBuffer.INT, sessionID); + response.write(NetworkBuffer.STRING_TERMINATED, String.valueOf(challengeToken)); + }); try { - byte[] responseData = response.toByteArray(); socket.send(new DatagramPacket(responseData, responseData.length, packet.getSocketAddress())); } catch (IOException e) { if (!started) { @@ -195,17 +194,14 @@ public class Query { } } - private static void sendResponse(@NotNull Writeable queryResponse, int sessionID, @NotNull SocketAddress sender) { - // header - BinaryWriter response = new BinaryWriter(); - response.writeByte((byte) 0); - response.writeInt(sessionID); - - // payload - queryResponse.write(response); - - // send! - byte[] responseData = response.toByteArray(); + private static void sendResponse(@NotNull NetworkBuffer.Writer queryResponse, int sessionID, @NotNull SocketAddress sender) { + final byte[] responseData = NetworkBuffer.makeArray(buffer -> { + // header + buffer.write(NetworkBuffer.BYTE, (byte) 0); + buffer.write(NetworkBuffer.INT, sessionID); + // payload + buffer.write(queryResponse); + }); try { socket.send(new DatagramPacket(responseData, responseData.length, sender)); } catch (IOException e) { diff --git a/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java b/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java index 6db13d118..976def4b4 100644 --- a/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java +++ b/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java @@ -1,7 +1,7 @@ package net.minestom.server.extras.query.event; import net.minestom.server.event.trait.CancellableEvent; -import net.minestom.server.utils.binary.Writeable; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import java.net.SocketAddress; @@ -12,7 +12,7 @@ import java.util.Objects; * * @param the type of the response */ -public abstract class QueryEvent implements CancellableEvent { +public abstract class QueryEvent implements CancellableEvent { private final SocketAddress sender; private final int sessionID; diff --git a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java index f18780397..4a4875255 100644 --- a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java @@ -1,9 +1,7 @@ package net.minestom.server.extras.query.response; import net.minestom.server.MinecraftServer; -import net.minestom.server.extras.query.Query; -import net.minestom.server.utils.binary.BinaryWriter; -import net.minestom.server.utils.binary.Writeable; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -11,7 +9,7 @@ import java.util.Objects; /** * A basic query response containing a fixed set of responses. */ -public class BasicQueryResponse implements Writeable { +public class BasicQueryResponse implements NetworkBuffer.Writer { private String motd, gametype, map, numPlayers, maxPlayers; /** @@ -136,13 +134,13 @@ public class BasicQueryResponse implements Writeable { } @Override - public void write(@NotNull BinaryWriter writer) { - writer.writeNullTerminatedString(this.motd, Query.CHARSET); - writer.writeNullTerminatedString(this.gametype, Query.CHARSET); - writer.writeNullTerminatedString(this.map, Query.CHARSET); - writer.writeNullTerminatedString(this.numPlayers, Query.CHARSET); - writer.writeNullTerminatedString(this.maxPlayers, Query.CHARSET); - writer.writeShort((short) MinecraftServer.getServer().getPort()); // TODO little endian? - writer.writeNullTerminatedString(Objects.requireNonNullElse(MinecraftServer.getServer().getAddress(), ""), Query.CHARSET); + public void write(@NotNull NetworkBuffer writer) { + writer.write(NetworkBuffer.STRING_TERMINATED, this.motd); + writer.write(NetworkBuffer.STRING_TERMINATED, this.gametype); + writer.write(NetworkBuffer.STRING_TERMINATED, this.map); + writer.write(NetworkBuffer.STRING_TERMINATED, this.numPlayers); + writer.write(NetworkBuffer.STRING_TERMINATED, this.maxPlayers); + writer.write(NetworkBuffer.SHORT, (short) MinecraftServer.getServer().getPort()); // TODO little endian? + writer.write(NetworkBuffer.STRING_TERMINATED, Objects.requireNonNullElse(MinecraftServer.getServer().getAddress(), "")); } } diff --git a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java index 2bb07697f..891269a26 100644 --- a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java @@ -2,9 +2,7 @@ package net.minestom.server.extras.query.response; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.minestom.server.MinecraftServer; -import net.minestom.server.extras.query.Query; -import net.minestom.server.utils.binary.BinaryWriter; -import net.minestom.server.utils.binary.Writeable; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -12,7 +10,7 @@ import java.util.*; /** * A full query response containing a dynamic set of responses. */ -public class FullQueryResponse implements Writeable { +public class FullQueryResponse implements NetworkBuffer.Writer { private static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.plainText(); private static final byte[] PADDING_10 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, PADDING_11 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -126,23 +124,19 @@ public class FullQueryResponse implements Writeable { } @Override - public void write(@NotNull BinaryWriter writer) { - writer.writeBytes(PADDING_11); - + public void write(@NotNull NetworkBuffer writer) { + writer.write(NetworkBuffer.RAW_BYTES, PADDING_11); // key-values for (var entry : this.kv.entrySet()) { - writer.writeNullTerminatedString(entry.getKey(), Query.CHARSET); - writer.writeNullTerminatedString(entry.getValue(), Query.CHARSET); + writer.write(NetworkBuffer.STRING_TERMINATED, entry.getKey()); + writer.write(NetworkBuffer.STRING_TERMINATED, entry.getValue()); } - - writer.writeNullTerminatedString("", Query.CHARSET); - writer.writeBytes(PADDING_10); - + writer.write(NetworkBuffer.STRING_TERMINATED, ""); + writer.write(NetworkBuffer.RAW_BYTES, PADDING_10); // players for (String player : this.players) { - writer.writeNullTerminatedString(player, Query.CHARSET); + writer.write(NetworkBuffer.STRING_TERMINATED, player); } - - writer.writeNullTerminatedString("", Query.CHARSET); + writer.write(NetworkBuffer.STRING_TERMINATED, ""); } } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index b71631171..af7dbac84 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -37,7 +37,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.*; import java.util.function.Function; -import java.util.stream.Collectors; /** * Manages the connected clients. @@ -288,7 +287,7 @@ public final class ConnectionManager { EventDispatcher.call(event); if (!player.isOnline()) return; // Player was kicked during config. - player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags().stream().map(StaticProtocolObject::namespace).collect(Collectors.toSet()))); // send player features that were enabled or disabled during async config event + player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags().stream().map(StaticProtocolObject::name).toList())); // send player features that were enabled or disabled during async config event final Instance spawningInstance = event.getSpawningInstance(); Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index fe0202930..a5bd4c341 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -39,6 +39,7 @@ public final class NetworkBuffer { public static final Type VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); public static final Type RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(); public static final Type STRING = new NetworkBufferTypeImpl.StringType(); + public static final Type STRING_TERMINATED = new NetworkBufferTypeImpl.StringTerminatedType(); public static final Type NBT = new NetworkBufferTypeImpl.NbtType(); public static final Type BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); public static final Type COMPONENT = new ComponentNetworkBufferTypeImpl(); diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java index 66294d8c1..81e487af4 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java @@ -1,5 +1,6 @@ package net.minestom.server.network; +import it.unimi.dsi.fastutil.bytes.ByteArrayList; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -298,6 +299,27 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } + record StringTerminatedType() implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, String value) { + final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + byte[] terminated = new byte[bytes.length + 1]; + System.arraycopy(bytes, 0, terminated, 0, bytes.length); + terminated[terminated.length - 1] = 0; + buffer.write(RAW_BYTES, terminated); + } + + @Override + public String read(@NotNull NetworkBuffer buffer) { + ByteArrayList bytes = new ByteArrayList(); + byte b; + while ((b = buffer.read(BYTE)) != 0) { + bytes.add(b); + } + return new String(bytes.elements(), StandardCharsets.UTF_8); + } + } + record NbtType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, BinaryTag value) { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java index cb9feabb4..a8168f249 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java @@ -5,7 +5,6 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.particle.Particle; import net.minestom.server.sound.SoundEvent; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -58,28 +57,26 @@ public record ExplosionPacket(double x, double y, double z, float radius, }; private static byte @NotNull [] readParticleData(@NotNull NetworkBuffer reader, Particle particle) { - //Need to do this because particle data isn't at the end of the packet - BinaryWriter writer = new BinaryWriter(); - if (particle.equals(Particle.BLOCK) || particle.equals(Particle.BLOCK_MARKER) || particle.equals(Particle.FALLING_DUST) || particle.equals(Particle.SHRIEK)) { - writer.writeVarInt(reader.read(VAR_INT)); - } else if (particle.equals(Particle.VIBRATION)) { - writer.writeVarInt(reader.read(VAR_INT)); - writer.writeBlockPosition(reader.read(BLOCK_POSITION)); - writer.writeVarInt(reader.read(VAR_INT)); - writer.writeFloat(reader.read(FLOAT)); - writer.writeVarInt(reader.read(VAR_INT)); - } else if (particle.equals(Particle.SCULK_CHARGE)) { - writer.writeFloat(reader.read(FLOAT)); - return writer.toByteArray(); - } else if (particle.equals(Particle.ITEM)) { - writer.writeItemStack(reader.read(ItemStack.NETWORK_TYPE)); - } else if (particle.equals(Particle.DUST_COLOR_TRANSITION)) { - for (int i = 0; i < 7; i++) writer.writeFloat(reader.read(FLOAT)); - } else if (particle.equals(Particle.DUST)) { - for (int i = 0; i < 4; i++) writer.writeFloat(reader.read(FLOAT)); - } - - return writer.toByteArray(); + return NetworkBuffer.makeArray(buffer -> { + //Need to do this because particle data isn't at the end of the packet + if (particle.equals(Particle.BLOCK) || particle.equals(Particle.BLOCK_MARKER) || particle.equals(Particle.FALLING_DUST) || particle.equals(Particle.SHRIEK)) { + buffer.write(VAR_INT, reader.read(VAR_INT)); + } else if (particle.equals(Particle.VIBRATION)) { + buffer.write(VAR_INT, reader.read(VAR_INT)); + buffer.write(BLOCK_POSITION, reader.read(BLOCK_POSITION)); + buffer.write(VAR_INT, reader.read(VAR_INT)); + buffer.write(FLOAT, reader.read(FLOAT)); + buffer.write(VAR_INT, reader.read(VAR_INT)); + } else if (particle.equals(Particle.SCULK_CHARGE)) { + buffer.write(FLOAT, reader.read(FLOAT)); + } else if (particle.equals(Particle.ITEM)) { + buffer.write(ItemStack.NETWORK_TYPE, reader.read(ItemStack.NETWORK_TYPE)); + } else if (particle.equals(Particle.DUST_COLOR_TRANSITION)) { + for (int i = 0; i < 7; i++) buffer.write(FLOAT, reader.read(FLOAT)); + } else if (particle.equals(Particle.DUST)) { + for (int i = 0; i < 4; i++) buffer.write(FLOAT, reader.read(FLOAT)); + } + }); } public ExplosionPacket(double x, double y, double z, float radius, byte @NotNull [] records, diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java deleted file mode 100644 index dc85307a1..000000000 --- a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java +++ /dev/null @@ -1,286 +0,0 @@ -package net.minestom.server.utils.binary; - -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minestom.server.coordinate.Point; -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.utils.Either; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; - -import java.io.InputStream; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.function.Function; -import java.util.function.Supplier; - -import static net.minestom.server.network.NetworkBuffer.*; - -/** - * Class used to read from a byte array. - *

- * WARNING: not thread-safe. - */ -public class BinaryReader extends InputStream { - private final NetworkBuffer buffer; - - public BinaryReader(@NotNull NetworkBuffer buffer) { - this.buffer = buffer; - } - - public BinaryReader(@NotNull ByteBuffer buffer) { - this.buffer = new NetworkBuffer(buffer); - } - - public BinaryReader(byte[] bytes) { - this(ByteBuffer.wrap(bytes)); - } - - public int readVarInt() { - return buffer.read(VAR_INT); - } - - public long readVarLong() { - return buffer.read(VAR_LONG); - } - - public boolean readBoolean() { - return buffer.read(BOOLEAN); - } - - public byte readByte() { - return buffer.read(BYTE); - } - - public short readShort() { - return buffer.read(SHORT); - } - - public int readUnsignedShort() { - return buffer.read(SHORT) & 0xFFFF; - } - - /** - * Same as readInt - */ - public int readInteger() { - return buffer.read(INT); - } - - /** - * Same as readInteger, created for parity with BinaryWriter - */ - public int readInt() { - return buffer.read(INT); - } - - public long readLong() { - return buffer.read(LONG); - } - - public float readFloat() { - return buffer.read(FLOAT); - } - - public double readDouble() { - return buffer.read(DOUBLE); - } - - /** - * Reads a string size by a var-int. - *

- * If the string length is higher than {@code maxLength}, - * the code throws an exception and the string bytes are not read. - * - * @param maxLength the max length of the string - * @return the string - * @throws IllegalStateException if the string length is invalid or higher than {@code maxLength} - */ - public String readSizedString(int maxLength) { - final int length = readVarInt(); - byte[] bytes = new byte[length]; - try { - for (int i = 0; i < length; i++) { - bytes[i] = readByte(); - } - } catch (BufferUnderflowException e) { - throw new RuntimeException("Could not read " + length + ", " + buffer.readableBytes() + " remaining."); - } - final String str = new String(bytes, StandardCharsets.UTF_8); - Check.stateCondition(str.length() > maxLength, - "String length ({0}) was higher than the max length of {1}", length, maxLength); - return str; - } - - public String readSizedString() { - return buffer.read(STRING); - } - - public byte[] readBytes(int length) { - byte[] bytes = new byte[length]; - for (int i = 0; i < length; i++) { - bytes[i] = readByte(); - } - return bytes; - } - - public byte[] readByteArray() { - return readBytes(readVarInt()); - } - - public String[] readSizedStringArray(int maxLength) { - final int size = readVarInt(); - String[] strings = new String[size]; - for (int i = 0; i < size; i++) { - strings[i] = readSizedString(maxLength); - } - return strings; - } - - public String[] readSizedStringArray() { - return readSizedStringArray(Integer.MAX_VALUE); - } - - public int[] readVarIntArray() { - final int size = readVarInt(); - int[] array = new int[size]; - for (int i = 0; i < size; i++) { - array[i] = readVarInt(); - } - return array; - } - - public long[] readVarLongArray() { - final int size = readVarInt(); - long[] array = new long[size]; - for (int i = 0; i < size; i++) { - array[i] = readVarLong(); - } - return array; - } - - public long[] readLongArray() { - final int size = readVarInt(); - long[] array = new long[size]; - for (int i = 0; i < size; i++) { - array[i] = readLong(); - } - return array; - } - - public byte[] readRemainingBytes() { - return buffer.read(RAW_BYTES); - } - - public Point readBlockPosition() { - return buffer.read(BLOCK_POSITION); - } - - public UUID readUuid() { - return buffer.read(UUID); - } - - public ItemStack readItemStack() { - return buffer.read(ItemStack.NETWORK_TYPE); - } - - public Component readComponent(int maxLength) { - final String jsonObject = readSizedString(maxLength); - return GsonComponentSerializer.gson().deserialize(jsonObject); - } - - public Component readComponent() { - return buffer.read(COMPONENT); - } - - /** - * Creates a new object from the given supplier and calls its {@link Readable#read(BinaryReader)} method with this reader. - * - * @param supplier supplier to create new instances of your object - * @param the readable object type - * @return the read object - */ - public T read(@NotNull Supplier<@NotNull T> supplier) { - T result = supplier.get(); - result.read(this); - return result; - } - - /** - * Reads the length of the array to read as a varint, creates the array to contain the readable objects and call - * their respective {@link Readable#read(BinaryReader)} methods. - * - * @param supplier supplier to create new instances of your object - * @param the readable object type - * @return the read objects - */ - public @NotNull T[] readArray(@NotNull Supplier<@NotNull T> supplier) { - Readable[] result = new Readable[readVarInt()]; - for (int i = 0; i < result.length; i++) { - result[i] = supplier.get(); - result[i].read(this); - } - return (T[]) result; - } - - public List readVarIntList(@NotNull Function supplier) { - return readList(readVarInt(), supplier); - } - - public List readByteList(@NotNull Function supplier) { - return readList(readByte(), supplier); - } - - public Either readEither(Function leftReader, Function rightReader) { - if (readBoolean()) { - return Either.left(leftReader.apply(this)); - } else { - return Either.right(rightReader.apply(this)); - } - } - - private List readList(int length, @NotNull Function supplier) { - List list = new ArrayList<>(length); - for (int i = 0; i < length; i++) { - list.add(supplier.apply(this)); - } - return list; - } - - @Override - public int read() { - return readByte() & 0xFF; - } - - @Override - public int available() { - return buffer.readableBytes(); - } - - public BinaryTag readTag() { - return buffer.read(NBT); - } - - /** - * Records the current position, runs the given Runnable, and then returns the bytes between the position before - * running the runnable and the position after. - * Can be used to extract a subsection of this reader's buffer with complex data - * - * @param extractor the extraction code, simply call the reader's read* methods here. - */ - public byte[] extractBytes(Runnable extractor) { - int startingPosition = buffer.readIndex(); - extractor.run(); - int endingPosition = buffer.readIndex(); - byte[] output = new byte[endingPosition - startingPosition]; - buffer.copyTo(buffer.readIndex(), output, 0, output.length); - //buffer.get(startingPosition, output); - return output; - } -} diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java deleted file mode 100644 index 037c12fd4..000000000 --- a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java +++ /dev/null @@ -1,258 +0,0 @@ -package net.minestom.server.utils.binary; - -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.text.Component; -import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.utils.Either; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Collection; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import static net.minestom.server.network.NetworkBuffer.*; - -/** - * Class used to write to a byte array. - * WARNING: not thread-safe. - */ -public class BinaryWriter extends OutputStream { - private final NetworkBuffer buffer; - - public BinaryWriter(@NotNull NetworkBuffer buffer) { - this.buffer = buffer; - } - - private BinaryWriter(ByteBuffer buffer, boolean resizable) { - this.buffer = new NetworkBuffer(buffer, resizable); - } - - public BinaryWriter(@NotNull ByteBuffer buffer) { - this.buffer = new NetworkBuffer(buffer); - } - - public BinaryWriter(int initialCapacity) { - this(ByteBuffer.allocate(initialCapacity)); - } - - public BinaryWriter() { - this(255); - } - - @ApiStatus.Experimental - public static BinaryWriter view(ByteBuffer buffer) { - return new BinaryWriter(buffer, false); - } - - public void writeComponent(@NotNull Component component) { - this.buffer.write(COMPONENT, component); - } - - public void writeByte(byte b) { - this.buffer.write(BYTE, b); - } - - public void writeBoolean(boolean b) { - this.buffer.write(BOOLEAN, b); - } - - public void writeShort(short s) { - this.buffer.write(SHORT, s); - } - - public void writeInt(int i) { - this.buffer.write(INT, i); - } - - public void writeLong(long l) { - this.buffer.write(LONG, l); - } - - public void writeFloat(float f) { - this.buffer.write(FLOAT, f); - } - - public void writeDouble(double d) { - this.buffer.write(DOUBLE, d); - } - - public void writeVarInt(int i) { - this.buffer.write(VAR_INT, i); - } - - public void writeVarLong(long l) { - this.buffer.write(VAR_LONG, l); - } - - public void writeSizedString(@NotNull String string) { - this.buffer.write(STRING, string); - } - - public void writeNullTerminatedString(@NotNull String string, @NotNull Charset charset) { - final var bytes = (string + '\0').getBytes(charset); - writeBytes(bytes); - } - - public void writeVarIntArray(int[] array) { - if (array == null) { - writeVarInt(0); - return; - } - writeVarInt(array.length); - for (int element : array) { - writeVarInt(element); - } - } - - public void writeVarLongArray(long[] array) { - if (array == null) { - writeVarInt(0); - return; - } - writeVarInt(array.length); - for (long element : array) { - writeVarLong(element); - } - } - - public void writeLongArray(long[] array) { - if (array == null) { - writeVarInt(0); - return; - } - writeVarInt(array.length); - for (long element : array) { - writeLong(element); - } - } - - public void writeByteArray(byte[] array) { - if (array == null) { - writeVarInt(0); - return; - } - writeVarInt(array.length); - writeBytes(array); - } - - public void writeBytes(byte @NotNull [] bytes) { - this.buffer.write(RAW_BYTES, bytes); - } - - public void writeStringArray(@NotNull String[] array) { - this.buffer.writeCollection(STRING, array); - } - - public void writeUuid(@NotNull UUID uuid) { - this.buffer.write(UUID, uuid); - } - - public void writeBlockPosition(@NotNull Point point) { - writeBlockPosition(point.blockX(), point.blockY(), point.blockZ()); - } - - public void writeBlockPosition(int x, int y, int z) { - this.buffer.write(BLOCK_POSITION, new Vec(x, y, z)); - } - - public void writeItemStack(@NotNull ItemStack itemStack) { - this.buffer.write(ItemStack.NETWORK_TYPE, itemStack); - } - - public void writeNBT(@NotNull String name, @NotNull BinaryTag tag) { - this.buffer.write(NBT, tag); - } - - public void writeEither(Either either, BiConsumer leftWriter, BiConsumer rightWriter) { - if (either.isLeft()) { - writeBoolean(true); - leftWriter.accept(this, either.left()); - } else { - writeBoolean(false); - rightWriter.accept(this, either.right()); - } - } - - /** - * Writes the given writeable object into this writer. - * - * @param writeable the object to write - */ - public void write(@NotNull Writeable writeable) { - writeable.write(this); - } - - public void write(@NotNull ByteBuffer buffer) { - byte[] remaining = new byte[buffer.remaining()]; - buffer.get(remaining); - writeBytes(remaining); - } - - public void write(@NotNull BinaryWriter writer) { - writeBytes(writer.toByteArray()); - } - - /** - * Writes an array of writeable objects to this writer. Will prepend the binary stream with a var int to denote the - * length of the array. - * - * @param writeables the array of writeables to write - */ - public void writeArray(@NotNull Writeable[] writeables) { - writeVarInt(writeables.length); - for (Writeable w : writeables) { - write(w); - } - } - - public void writeVarIntList(Collection list, @NotNull BiConsumer consumer) { - writeVarInt(list.size()); - writeList(list, consumer); - } - - public void writeByteList(Collection list, @NotNull BiConsumer consumer) { - writeByte((byte) list.size()); - writeList(list, consumer); - } - - private void writeList(Collection list, @NotNull BiConsumer consumer) { - for (T t : list) consumer.accept(this, t); - } - - /** - * Converts the internal buffer to a byte array. - * - * @return the byte array containing all the {@link BinaryWriter} data - */ - public byte[] toByteArray() { - byte[] bytes = new byte[buffer.writeIndex()]; - this.buffer.copyTo(0, bytes, 0, bytes.length); - return bytes; - } - - @Override - public void write(int b) { - writeByte((byte) b); - } - - public void writeUnsignedShort(int yourShort) { - this.buffer.write(SHORT, (short) (yourShort & 0xFFFF)); - } - - /** - * Returns a byte[] with the contents written via BinaryWriter - */ - public static byte[] makeArray(@NotNull Consumer<@NotNull BinaryWriter> writing) { - BinaryWriter writer = new BinaryWriter(); - writing.accept(writer); - return writer.toByteArray(); - } -} diff --git a/src/main/java/net/minestom/server/utils/binary/Readable.java b/src/main/java/net/minestom/server/utils/binary/Readable.java deleted file mode 100644 index 48fa33012..000000000 --- a/src/main/java/net/minestom/server/utils/binary/Readable.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.minestom.server.utils.binary; - -import org.jetbrains.annotations.NotNull; - -/** - * Represents an element which can read from a {@link BinaryReader}. - */ -public interface Readable { - - /** - * Reads from a {@link BinaryReader}. - * - * @param reader the reader to read from - */ - void read(@NotNull BinaryReader reader); - -} diff --git a/src/main/java/net/minestom/server/utils/binary/Writeable.java b/src/main/java/net/minestom/server/utils/binary/Writeable.java deleted file mode 100644 index 1099b84a2..000000000 --- a/src/main/java/net/minestom/server/utils/binary/Writeable.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.minestom.server.utils.binary; - -import org.jetbrains.annotations.NotNull; - -/** - * Represents an element which can write to a {@link BinaryWriter}. - */ -public interface Writeable { - - /** - * Writes into a {@link BinaryWriter}. - * - * @param writer the writer to write to - */ - void write(@NotNull BinaryWriter writer); - -} From a561cd0a3e71d0f86825535132de151071e9b81b Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 25 Jul 2024 13:12:23 +0200 Subject: [PATCH 10/97] Fix packet tests --- .../minestom/server/utils/PacketUtils.java | 6 +-- .../server/network/PacketWriteReadTest.java | 47 ++++++++----------- .../server/network/SocketReadTest.java | 18 +++---- .../server/network/SocketWriteTest.java | 31 +++++------- .../packet/DeclareRecipesPacketTest.java | 3 +- .../server/particle/ParticleDataTest.java | 10 ++-- 6 files changed, 52 insertions(+), 63 deletions(-) diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java index 7e8ddcf89..8aaec93a7 100644 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketUtils.java @@ -260,10 +260,10 @@ public final class PacketUtils { writeFramedPacket(buffer, id, serializer, packet, compression ? MinecraftServer.getCompressionThreshold() : 0); } - public static void writeFramedPacket(@NotNull ByteBuffer buffer, + public static void writeFramedPacket(@NotNull ByteBuffer buffer, int id, - @NotNull NetworkBuffer.Type type, - @NotNull ServerPacket packet, + @NotNull NetworkBuffer.Type type, + @NotNull T packet, int compressionThreshold) { NetworkBuffer networkBuffer = new NetworkBuffer(buffer, false); if (compressionThreshold <= 0) { diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index 8d6db2e23..86bb04e57 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -26,15 +26,12 @@ import net.minestom.server.recipe.RecipeCategory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ThreadLocalRandom; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; /** * Ensures that packet can be written and read correctly. @@ -160,32 +157,28 @@ public class PacketWriteReadTest { } @Test - public void serverTest() { - SERVER_PACKETS.forEach(PacketWriteReadTest::testPacket); - } - - @Test - public void clientTest() { - CLIENT_PACKETS.forEach(PacketWriteReadTest::testPacket); - } - - private static void testPacket(NetworkBuffer.Writer writeable) { - try { - byte[] bytes = NetworkBuffer.makeArray(buffer -> buffer.write(writeable)); - var readerConstructor = writeable.getClass().getConstructor(NetworkBuffer.class); - NetworkBuffer reader = new NetworkBuffer(); - reader.write(NetworkBuffer.RAW_BYTES, bytes); - var createdPacket = readerConstructor.newInstance(reader); - assertEquals(writeable, createdPacket); - } catch (NoSuchMethodException | InvocationTargetException | InstantiationException - | IllegalAccessException e) { - fail(writeable.toString(), e); + public void serverTest() throws NoSuchFieldException, IllegalAccessException { + for (var packet : SERVER_PACKETS) { + var packetClass = packet.getClass(); + NetworkBuffer.Type serializer = (NetworkBuffer.Type) packetClass.getField("SERIALIZER").get(packetClass); + testPacket(serializer, packet); } } - private static byte[] generateByteArray(int size) { - byte[] array = new byte[size]; - ThreadLocalRandom.current().nextBytes(array); - return array; + @Test + public void clientTest() throws NoSuchFieldException, IllegalAccessException { + for (var packet : CLIENT_PACKETS) { + var packetClass = packet.getClass(); + NetworkBuffer.Type serializer = (NetworkBuffer.Type) packetClass.getField("SERIALIZER").get(packetClass); + testPacket(serializer, packet); + } + } + + private static void testPacket(NetworkBuffer.Type networkType, T packet) { + byte[] bytes = NetworkBuffer.makeArray(buffer -> networkType.write(buffer, packet)); + NetworkBuffer reader = new NetworkBuffer(); + reader.write(NetworkBuffer.RAW_BYTES, bytes); + var createdPacket = networkType.read(reader); + assertEquals(packet, createdPacket); } } diff --git a/src/test/java/net/minestom/server/network/SocketReadTest.java b/src/test/java/net/minestom/server/network/SocketReadTest.java index 4c8db0970..d2e607061 100644 --- a/src/test/java/net/minestom/server/network/SocketReadTest.java +++ b/src/test/java/net/minestom/server/network/SocketReadTest.java @@ -24,7 +24,7 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, packet, compressed ? 256 : 0); + PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); var wrapper = BinaryBuffer.wrap(buffer); wrapper.reset(0, buffer.position()); @@ -37,7 +37,7 @@ public class SocketReadTest { assertEquals(1, packets.size()); var rawPacket = packets.get(0); assertEquals(0x0A, rawPacket.left()); - var readPacket = new ClientPluginMessagePacket(new NetworkBuffer(rawPacket.right())); + var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); assertEquals("channel", readPacket.channel()); assertEquals(2000, readPacket.data().length); } @@ -48,8 +48,8 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, packet, compressed ? 256 : 0); - PacketUtils.writeFramedPacket(buffer, 0x0A, packet, compressed ? 256 : 0); + PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); + PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); var wrapper = BinaryBuffer.wrap(buffer); wrapper.reset(0, buffer.position()); @@ -62,7 +62,7 @@ public class SocketReadTest { assertEquals(2, packets.size()); for (var rawPacket : packets) { assertEquals(0x0A, rawPacket.left()); - var readPacket = new ClientPluginMessagePacket(new NetworkBuffer(rawPacket.right())); + var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); assertEquals("channel", readPacket.channel()); assertEquals(2000, readPacket.data().length); } @@ -76,7 +76,7 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, packet, compressed ? 256 : 0); + PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); Utils.writeVarInt(buffer, 200); // incomplete 200 bytes packet var wrapper = BinaryBuffer.wrap(buffer); @@ -91,7 +91,7 @@ public class SocketReadTest { assertEquals(1, packets.size()); var rawPacket = packets.get(0); assertEquals(0x0A, rawPacket.left()); - var readPacket = new ClientPluginMessagePacket(new NetworkBuffer(rawPacket.right())); + var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); assertEquals("channel", readPacket.channel()); assertEquals(2000, readPacket.data().length); } @@ -104,7 +104,7 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, packet, compressed ? 256 : 0); + PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); buffer.put((byte) -85); // incomplete var-int length var wrapper = BinaryBuffer.wrap(buffer); @@ -119,7 +119,7 @@ public class SocketReadTest { assertEquals(1, packets.size()); var rawPacket = packets.get(0); assertEquals(0x0A, rawPacket.left()); - var readPacket = new ClientPluginMessagePacket(new NetworkBuffer(rawPacket.right())); + var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); assertEquals("channel", readPacket.channel()); assertEquals(2000, readPacket.data().length); } diff --git a/src/test/java/net/minestom/server/network/SocketWriteTest.java b/src/test/java/net/minestom/server/network/SocketWriteTest.java index 3e8e01dc1..d1450cb01 100644 --- a/src/test/java/net/minestom/server/network/SocketWriteTest.java +++ b/src/test/java/net/minestom/server/network/SocketWriteTest.java @@ -4,7 +4,6 @@ import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.ObjectPool; import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.Utils; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; @@ -17,19 +16,15 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; public class SocketWriteTest { record IntPacket(int value) implements ServerPacket.Play { - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(INT, value); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, IntPacket::value, + IntPacket::new); } record CompressiblePacket(String value) implements ServerPacket.Play { - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, value); - } - + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, CompressiblePacket::value, + CompressiblePacket::new); } @Test @@ -37,7 +32,7 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, packet, -1); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -49,8 +44,8 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, packet, -1); - PacketUtils.writeFramedPacket(buffer, 1, packet, -1); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -66,7 +61,7 @@ public class SocketWriteTest { var packet = new CompressiblePacket(string); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, packet, 256); + PacketUtils.writeFramedPacket(buffer, 1, CompressiblePacket.SERIALIZER, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + payload // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -78,7 +73,7 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, packet, 256); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future @@ -90,8 +85,8 @@ public class SocketWriteTest { var packet = new IntPacket(5); var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, packet, 256); - PacketUtils.writeFramedPacket(buffer, 1, packet, 256); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); + PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future diff --git a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java index 9e5df2c3d..dd5c72fec 100644 --- a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java +++ b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java @@ -25,6 +25,7 @@ public class DeclareRecipesPacketTest { ) )); - assertThrows(IllegalArgumentException.class, () -> NetworkBuffer.makeArray(packet::write)); + assertThrows(IllegalArgumentException.class, () -> NetworkBuffer.makeArray(networkBuffer -> + DeclareRecipesPacket.SERIALIZER.write(networkBuffer, packet))); } } diff --git a/src/test/java/net/minestom/server/particle/ParticleDataTest.java b/src/test/java/net/minestom/server/particle/ParticleDataTest.java index 43ef509f3..f7aa234f7 100644 --- a/src/test/java/net/minestom/server/particle/ParticleDataTest.java +++ b/src/test/java/net/minestom/server/particle/ParticleDataTest.java @@ -13,34 +13,34 @@ public class ParticleDataTest { public void testDustParticleDefault() { Particle particle = Particle.DUST; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> packet.write(new NetworkBuffer())); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); } @Test public void testDustParticleInvalid() { var particle = Particle.DUST.withProperties(null, 1); ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertThrows(NullPointerException.class, () -> packet.write(new NetworkBuffer())); + assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); } @Test public void testParticleValid() { var particle = Particle.ENTITY_EFFECT; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> packet.write(new NetworkBuffer())); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); } @Test public void testParticleData() { var particle = Particle.ENTITY_EFFECT; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> packet.write(new NetworkBuffer())); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); } @Test public void invalidBlock() { var particle = Particle.BLOCK.withBlock(null); ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertThrows(NullPointerException.class, () -> packet.write(new NetworkBuffer())); + assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); } } From 000483dcdedfe142ff0333e95220f827fa9ed3e8 Mon Sep 17 00:00:00 2001 From: Eaterminer <58890567+Eaterminer@users.noreply.github.com> Date: Fri, 2 Aug 2024 04:11:36 +1200 Subject: [PATCH 11/97] fix: grammatical mistake in PlayerChatEvent.java (#2313) --- .../java/net/minestom/server/event/player/PlayerChatEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java b/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java index 87789ecbe..040a84cd5 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java @@ -13,7 +13,7 @@ import java.util.function.Function; import java.util.function.Supplier; /** - * Called every time a {@link Player} write and send something in the chat. + * Called every time a {@link Player} writes and sends something in the chat. * The event can be cancelled to do not send anything, and the format can be changed. */ public class PlayerChatEvent implements PlayerInstanceEvent, CancellableEvent { From 561470c82ac31eb27269b5afb71008175ca6ca81 Mon Sep 17 00:00:00 2001 From: mudkip Date: Tue, 20 Aug 2024 08:45:15 -0600 Subject: [PATCH 12/97] Improve chat API (#2329) * improve chat api * fix typoes * remove click event * make requested changes --- .../server/event/player/PlayerChatEvent.java | 66 +++++++++---------- .../server/listener/ChatMessageListener.java | 32 +++------ 2 files changed, 38 insertions(+), 60 deletions(-) diff --git a/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java b/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java index 040a84cd5..7e70111cb 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerChatEvent.java @@ -1,85 +1,70 @@ package net.minestom.server.event.player; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.CancellableEvent; import net.minestom.server.event.trait.PlayerInstanceEvent; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; -import java.util.function.Function; -import java.util.function.Supplier; /** * Called every time a {@link Player} writes and sends something in the chat. - * The event can be cancelled to do not send anything, and the format can be changed. + * The event can be cancelled to not send anything, and the final message can be changed. */ public class PlayerChatEvent implements PlayerInstanceEvent, CancellableEvent { - private final Player player; private final Collection recipients; - private String message; - private Function chatFormat; - + private final String rawMessage; + private Component formattedMessage; private boolean cancelled; public PlayerChatEvent(@NotNull Player player, @NotNull Collection recipients, - @NotNull Function defaultChatFormat, - @NotNull String message) { + @NotNull String rawMessage) { this.player = player; this.recipients = new ArrayList<>(recipients); - this.chatFormat = defaultChatFormat; - this.message = message; + this.rawMessage = rawMessage; + formattedMessage = buildDefaultChatMessage(); } /** - * Changes the chat format. - * - * @param chatFormat the custom chat format - */ - public void setChatFormat(@NotNull Function chatFormat) { - this.chatFormat = chatFormat; - } - - /** - * Those are the players who will receive the message. + * Returns the players who will receive the message. *

- * It can be modified to add or remove recipient. + * It can be modified to add and remove recipients. * - * @return a modifiable list of message targets + * @return a modifiable list of the message's targets */ public @NotNull Collection getRecipients() { return recipients; } /** - * Gets the message sent. + * Gets the original message content sent by the player. * * @return the sender's message */ - public @NotNull String getMessage() { - return message; + public @NotNull String getRawMessage() { + return rawMessage; } /** - * Used to change the message. + * Gets the final message component that will be sent. * - * @param message the new message + * @return the chat message component */ - public void setMessage(@NotNull String message) { - this.message = message; + public Component getFormattedMessage() { + return formattedMessage; } /** - * Used to retrieve the chat format for this message. - *

+ * Used to change the final message component. * - * @return the chat format which will be used + * @param message the new message component */ - public @NotNull Function<@NotNull PlayerChatEvent, @NotNull Component> getChatFormatFunction() { - return chatFormat; + public void setFormattedMessage(@NotNull Component message) { + formattedMessage = message; } @Override @@ -96,4 +81,13 @@ public class PlayerChatEvent implements PlayerInstanceEvent, CancellableEvent { public @NotNull Player getPlayer() { return player; } + + private Component buildDefaultChatMessage() { + return Component.translatable("chat.type.text") + .arguments( + Component.text(player.getUsername()) + .insertion(player.getUsername()) + .hoverEvent(player), + Component.text(rawMessage)); + } } diff --git a/src/main/java/net/minestom/server/listener/ChatMessageListener.java b/src/main/java/net/minestom/server/listener/ChatMessageListener.java index b3bbabfc1..4058d8a18 100644 --- a/src/main/java/net/minestom/server/listener/ChatMessageListener.java +++ b/src/main/java/net/minestom/server/listener/ChatMessageListener.java @@ -1,7 +1,5 @@ package net.minestom.server.listener; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.ClickEvent; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; import net.minestom.server.entity.Player; @@ -10,16 +8,12 @@ import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.message.ChatPosition; import net.minestom.server.message.Messenger; import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.play.ClientChatMessagePacket; import net.minestom.server.network.packet.client.play.ClientCommandChatPacket; -import org.jetbrains.annotations.NotNull; import java.util.Collection; -import java.util.function.Function; public class ChatMessageListener { - private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager(); private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); @@ -40,30 +34,20 @@ public class ChatMessageListener { } final Collection players = CONNECTION_MANAGER.getOnlinePlayers(); - PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, players, (e) -> buildDefaultChatMessage(e.getPlayer(), e.getMessage()), message); + PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, players, message); // Call the event EventDispatcher.callCancellable(playerChatEvent, () -> { - final Function formatFunction = playerChatEvent.getChatFormatFunction(); - Component textObject = formatFunction.apply(playerChatEvent); - final Collection recipients = playerChatEvent.getRecipients(); + if (!recipients.isEmpty()) { // delegate to the messenger to avoid sending messages we shouldn't be - Messenger.sendMessage(recipients, textObject, ChatPosition.CHAT, player.getUuid()); + Messenger.sendMessage( + recipients, + playerChatEvent.getFormattedMessage(), + ChatPosition.CHAT, + player.getUuid()); } }); } - - private static @NotNull Component buildDefaultChatMessage(@NotNull Player player, @NotNull String message) { - final String username = player.getUsername(); - return Component.translatable("chat.type.text") - .args(Component.text(username) - .insertion(username) - .clickEvent(ClickEvent.suggestCommand("/msg " + username + " ")) - .hoverEvent(player), - Component.text(message) - ); - } - -} \ No newline at end of file +} From 3f079d252e9ca1c1a106648c10a0b0538148a0e1 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 28 Aug 2024 20:50:21 +0200 Subject: [PATCH 13/97] Network improvements (#2324) --- .../minestom/server/utils/ObjectPoolTest.java | 5 +- .../net/minestom/server/MinecraftServer.java | 19 +- .../java/net/minestom/server/ServerFlag.java | 15 +- .../net/minestom/server/ServerProcess.java | 3 +- .../minestom/server/ServerProcessImpl.java | 17 +- .../java/net/minestom/server/Viewable.java | 4 +- .../audience/PacketGroupingAudience.java | 4 +- .../adventure/bossbar/BossBarListener.java | 13 +- .../adventure/bossbar/BossBarManager.java | 8 +- .../net/minestom/server/color/AlphaColor.java | 12 +- .../java/net/minestom/server/color/Color.java | 15 +- .../builder/arguments/ArgumentString.java | 4 +- .../arguments/ArgumentStringArray.java | 4 +- .../builder/arguments/ArgumentWord.java | 4 +- .../arguments/minecraft/ArgumentResource.java | 2 +- .../minecraft/ArgumentResourceOrTag.java | 4 +- .../arguments/minecraft/ArgumentTime.java | 2 +- .../server/crypto/ArgumentSignatures.java | 31 +- .../minestom/server/crypto/ChatSession.java | 17 +- .../minestom/server/crypto/FilterMask.java | 29 +- .../server/crypto/LastSeenMessages.java | 45 +- .../server/crypto/MessageSignature.java | 44 +- .../server/crypto/PlayerPublicKey.java | 36 +- .../server/crypto/SaltSignaturePair.java | 21 +- .../server/crypto/SignedMessageBody.java | 22 +- .../server/crypto/SignedMessageHeader.java | 18 +- .../net/minestom/server/entity/Entity.java | 19 +- .../net/minestom/server/entity/GameMode.java | 9 +- .../net/minestom/server/entity/Metadata.java | 15 +- .../minestom/server/entity/MetadataImpl.java | 29 +- .../net/minestom/server/entity/Player.java | 19 +- .../server/entity/attribute/Attribute.java | 2 +- .../entity/attribute/AttributeInstance.java | 4 +- .../player/AsyncPlayerPreLoginEvent.java | 4 +- .../minestom/server/extras/query/Query.java | 10 +- .../server/extras/query/event/QueryEvent.java | 3 +- .../query/response/BasicQueryResponse.java | 156 +---- .../query/response/FullQueryResponse.java | 37 +- .../server/extras/velocity/VelocityProxy.java | 4 +- .../server/gamedata/tags/TagManager.java | 20 +- .../server/instance/DynamicChunk.java | 8 +- .../minestom/server/instance/Explosion.java | 4 +- .../minestom/server/instance/Instance.java | 6 +- .../server/instance/InstanceContainer.java | 4 +- .../net/minestom/server/instance/Section.java | 11 +- .../server/instance/anvil/AnvilLoader.java | 10 +- .../minestom/server/instance/block/Block.java | 2 +- .../block/predicate/BlockPredicate.java | 30 +- .../block/predicate/PropertiesPredicate.java | 46 +- .../instance/palette/AdaptivePalette.java | 38 +- .../server/instance/palette/Palette.java | 58 +- ...xiblePalette.java => PaletteIndirect.java} | 103 ++-- ...{FilledPalette.java => PaletteSingle.java} | 13 +- .../server/instance/palette/Palettes.java | 98 +++ .../net/minestom/server/item/ItemStack.java | 2 +- .../net/minestom/server/item/Material.java | 2 +- .../server/item/book/FilteredText.java | 4 +- .../server/item/component/ArmorTrim.java | 26 +- .../server/item/component/AttributeList.java | 45 +- .../server/item/component/BannerPatterns.java | 20 +- .../minestom/server/item/component/Bee.java | 22 +- .../server/item/component/DyedItemColor.java | 18 +- .../item/component/EnchantmentList.java | 31 +- .../item/component/FireworkExplosion.java | 32 +- .../server/item/component/FireworkList.java | 19 +- .../minestom/server/item/component/Food.java | 55 +- .../server/item/component/HeadProfile.java | 43 +- .../server/item/component/ItemBlockState.java | 25 +- .../item/component/LodestoneTracker.java | 21 +- .../item/component/MapPostProcessing.java | 14 +- .../server/item/component/PotDecorations.java | 2 +- .../server/item/component/PotionContents.java | 12 +- .../item/component/SuspiciousStewEffects.java | 20 +- .../minestom/server/item/component/Tool.java | 24 +- .../server/item/component/Unbreakable.java | 18 +- .../item/component/WritableBookContent.java | 16 +- .../item/component/WrittenBookContent.java | 44 +- .../manager/PacketListenerManager.java | 2 +- .../listener/preplay/LoginListener.java | 14 +- .../minestom/server/message/Messenger.java | 4 +- .../server/network/ConnectionManager.java | 3 +- .../server/network/ConnectionState.java | 24 +- .../server/network/NetworkBuffer.java | 503 +++++++-------- .../server/network/NetworkBufferImpl.java | 575 ++++++++++++++++++ .../server/network/NetworkBufferTemplate.java | 146 +++++ .../server/network/NetworkBufferTypeImpl.java | 371 ++++++----- .../server/network/NetworkBufferUnsafe.java | 48 ++ .../server/network/packet/PacketParser.java | 40 +- .../server/network/packet/PacketReading.java | 224 +++++++ .../server/network/packet/PacketRegistry.java | 52 +- .../server/network/packet/PacketVanilla.java | 58 ++ .../server/network/packet/PacketWriting.java | 163 +++++ .../network/packet/client/ClientPacket.java | 12 - .../common/ClientCookieResponsePacket.java | 5 - .../client/common/ClientKeepAlivePacket.java | 5 - .../common/ClientPingRequestPacket.java | 5 - .../common/ClientPluginMessagePacket.java | 16 + .../ClientResourcePackStatusPacket.java | 28 +- .../handshake/ClientHandshakePacket.java | 38 +- .../login/ClientEncryptionResponsePacket.java | 5 - .../login/ClientLoginAcknowledgedPacket.java | 5 - .../ClientLoginPluginResponsePacket.java | 7 +- .../client/login/ClientLoginStartPacket.java | 5 - .../play/ClientAdvancementTabPacket.java | 6 +- .../client/play/ClientChatMessagePacket.java | 30 +- .../play/ClientChatSessionUpdatePacket.java | 16 +- .../play/ClientInteractEntityPacket.java | 64 +- .../ClientPlayerBlockPlacementPacket.java | 2 +- .../play/ClientPlayerDiggingPacket.java | 23 +- .../play/ClientSetBeaconEffectPacket.java | 25 +- .../play/ClientSignedCommandChatPacket.java | 26 +- .../ClientUpdateStructureBlockPacket.java | 48 +- .../client/status/StatusRequestPacket.java | 5 - .../network/packet/server/BufferedPacket.java | 18 + .../network/packet/server/CachedPacket.java | 24 +- .../network/packet/server/FramedPacket.java | 10 +- .../network/packet/server/SendablePacket.java | 26 +- .../common/CustomReportDetailsPacket.java | 16 +- .../server/common/PluginMessagePacket.java | 2 +- .../server/common/ServerLinksPacket.java | 1 - .../packet/server/common/TagsPacket.java | 79 +-- .../UpdateEnabledFeaturesPacket.java | 2 +- .../server/play/AdvancementsPacket.java | 215 +++---- .../server/play/BlockEntityDataPacket.java | 4 +- .../packet/server/play/BossBarPacket.java | 111 ++-- .../packet/server/play/ChunkDataPacket.java | 24 +- .../server/play/DeclareCommandsPacket.java | 111 ++-- .../packet/server/play/DeleteChatPacket.java | 16 +- .../server/play/EntityEffectPacket.java | 18 +- .../server/play/EntityMetaDataPacket.java | 8 +- .../server/play/EntitySoundEffectPacket.java | 2 +- .../packet/server/play/ExplosionPacket.java | 4 +- .../packet/server/play/FacePlayerPacket.java | 16 +- .../packet/server/play/JoinGamePacket.java | 87 +-- .../packet/server/play/MapDataPacket.java | 4 +- .../server/play/NbtQueryResponsePacket.java | 4 +- .../server/play/PlayerChatMessagePacket.java | 36 +- .../server/play/PlayerInfoUpdatePacket.java | 78 +-- .../server/play/RemoveEntityEffectPacket.java | 20 +- .../packet/server/play/RespawnPacket.java | 2 +- .../play/ScoreboardObjectivePacket.java | 4 +- .../packet/server/play/SoundEffectPacket.java | 4 +- .../packet/server/play/StopSoundPacket.java | 4 +- .../packet/server/play/TabCompletePacket.java | 4 +- .../packet/server/play/TeamsPacket.java | 136 +++-- .../server/play/UnlockRecipesPacket.java | 8 +- .../packet/server/play/UpdateLightPacket.java | 20 +- .../packet/server/play/UpdateScorePacket.java | 29 +- .../packet/server/play/data/ChunkData.java | 57 +- .../packet/server/play/data/LightData.java | 33 +- .../packet/server/play/data/WorldPos.java | 33 +- .../server/network/player/GameProfile.java | 38 +- .../player/PlayerSocketConnection.java | 426 +++++++------ .../server/network/plugin/LoginPlugin.java | 27 + .../plugin/LoginPluginMessageProcessor.java | 28 +- .../network/plugin/LoginPluginRequest.java | 28 - .../network/plugin/LoginPluginResponse.java | 30 - .../server/network/socket/Server.java | 143 +++-- .../server/network/socket/Worker.java | 149 ----- .../minestom/server/particle/Particle.java | 4 +- .../server/potion/CustomPotionEffect.java | 52 +- .../net/minestom/server/potion/Potion.java | 25 +- .../minestom/server/potion/PotionEffect.java | 2 +- .../minestom/server/potion/PotionType.java | 3 + .../server/recipe/RecipeSerializers.java | 4 +- .../minestom/server/scoreboard/Sidebar.java | 51 +- .../net/minestom/server/scoreboard/Team.java | 10 +- .../server/scoreboard/TeamManager.java | 6 +- .../net/minestom/server/sound/SoundEvent.java | 9 +- .../net/minestom/server/utils/ArrayUtils.java | 47 -- .../net/minestom/server/utils/Either.java | 20 - .../minestom/server/utils/InterfaceUtils.java | 13 - .../net/minestom/server/utils/ObjectPool.java | 33 +- .../server/utils/PacketSendingUtils.java | 122 ++++ .../minestom/server/utils/PacketUtils.java | 409 ------------- .../server/utils/PacketViewableUtils.java | 120 ++++ .../java/net/minestom/server/utils/Utils.java | 59 -- .../server/utils/binary/BinaryBuffer.java | 185 ------ .../server/command/ArgumentTypeTest.java | 2 +- .../anvil/AnvilLoaderIntegrationTest.java | 14 +- .../palette/PaletteOptimizationTest.java | 4 +- .../component/AbstractItemComponentTest.java | 9 +- .../server/network/NetworkBufferTest.java | 227 ++++++- .../server/network/PacketWriteReadTest.java | 6 +- .../server/network/SendablePacketTest.java | 29 +- .../server/network/SocketReadTest.java | 166 ++--- .../server/network/SocketWriteTest.java | 49 +- .../packet/DeclareRecipesPacketTest.java | 4 +- .../network/socket/ServerAddressTest.java | 11 +- .../server/particle/ParticleDataTest.java | 10 +- .../minestom/server/utils/ObjectPoolTest.java | 12 +- .../utils/TranslationIntegrationTest.java | 10 +- 192 files changed, 4235 insertions(+), 3909 deletions(-) rename src/main/java/net/minestom/server/instance/palette/{FlexiblePalette.java => PaletteIndirect.java} (73%) rename src/main/java/net/minestom/server/instance/palette/{FilledPalette.java => PaletteSingle.java} (70%) create mode 100644 src/main/java/net/minestom/server/instance/palette/Palettes.java create mode 100644 src/main/java/net/minestom/server/network/NetworkBufferImpl.java create mode 100644 src/main/java/net/minestom/server/network/NetworkBufferUnsafe.java create mode 100644 src/main/java/net/minestom/server/network/packet/PacketReading.java create mode 100644 src/main/java/net/minestom/server/network/packet/PacketVanilla.java create mode 100644 src/main/java/net/minestom/server/network/packet/PacketWriting.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/BufferedPacket.java create mode 100644 src/main/java/net/minestom/server/network/plugin/LoginPlugin.java delete mode 100644 src/main/java/net/minestom/server/network/plugin/LoginPluginRequest.java delete mode 100644 src/main/java/net/minestom/server/network/plugin/LoginPluginResponse.java delete mode 100644 src/main/java/net/minestom/server/network/socket/Worker.java delete mode 100644 src/main/java/net/minestom/server/utils/Either.java delete mode 100644 src/main/java/net/minestom/server/utils/InterfaceUtils.java create mode 100644 src/main/java/net/minestom/server/utils/PacketSendingUtils.java delete mode 100644 src/main/java/net/minestom/server/utils/PacketUtils.java create mode 100644 src/main/java/net/minestom/server/utils/PacketViewableUtils.java delete mode 100644 src/main/java/net/minestom/server/utils/Utils.java delete mode 100644 src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java diff --git a/jcstress-tests/src/jcstress/java/net/minestom/server/utils/ObjectPoolTest.java b/jcstress-tests/src/jcstress/java/net/minestom/server/utils/ObjectPoolTest.java index 92e0fdeec..98a4523d0 100644 --- a/jcstress-tests/src/jcstress/java/net/minestom/server/utils/ObjectPoolTest.java +++ b/jcstress-tests/src/jcstress/java/net/minestom/server/utils/ObjectPoolTest.java @@ -1,6 +1,7 @@ package net.minestom.server.utils; -import net.minestom.server.utils.binary.BinaryBuffer; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketVanilla; import org.openjdk.jcstress.annotations.*; import org.openjdk.jcstress.infra.results.L_Result; @@ -11,7 +12,7 @@ import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; @Outcome(id = "2", expect = ACCEPTABLE) @State public class ObjectPoolTest { - private final ObjectPool pool = ObjectPool.BUFFER_POOL; + private final ObjectPool pool = PacketVanilla.PACKET_POOL; @Actor public void actor1() { diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 9cc7c1870..3eca63b50 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -22,6 +22,7 @@ import net.minestom.server.message.ChatType; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.common.PluginMessagePacket; import net.minestom.server.network.packet.server.play.ServerDifficultyPacket; import net.minestom.server.network.socket.Server; @@ -30,7 +31,7 @@ import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.scoreboard.TeamManager; import net.minestom.server.thread.TickSchedulerThread; import net.minestom.server.timer.SchedulerManager; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.nbt.BinaryTagSerializer; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.Difficulty; @@ -40,7 +41,6 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -80,13 +80,8 @@ public final class MinecraftServer implements MinecraftConstants { @ApiStatus.Internal public static ServerProcess updateProcess() { - ServerProcess process; - try { - process = new ServerProcessImpl(); - serverProcess = process; - } catch (IOException e) { - throw new RuntimeException(e); - } + ServerProcess process = new ServerProcessImpl(); + serverProcess = process; return process; } @@ -108,7 +103,7 @@ public final class MinecraftServer implements MinecraftConstants { */ public static void setBrandName(@NotNull String brandName) { MinecraftServer.brandName = brandName; - PacketUtils.broadcastPlayPacket(PluginMessagePacket.brandPacket(brandName)); + PacketSendingUtils.broadcastPlayPacket(PluginMessagePacket.brandPacket(brandName)); } /** @@ -128,7 +123,7 @@ public final class MinecraftServer implements MinecraftConstants { */ public static void setDifficulty(@NotNull Difficulty difficulty) { MinecraftServer.difficulty = difficulty; - PacketUtils.broadcastPlayPacket(new ServerDifficultyPacket(difficulty, true)); + PacketSendingUtils.broadcastPlayPacket(new ServerDifficultyPacket(difficulty, true)); } public static @UnknownNullability ServerProcess process() { @@ -188,7 +183,7 @@ public final class MinecraftServer implements MinecraftConstants { return serverProcess.bossBar(); } - public static @NotNull PacketParser.Client getPacketParser() { + public static @NotNull PacketParser getPacketParser() { return serverProcess.packetParser(); } diff --git a/src/main/java/net/minestom/server/ServerFlag.java b/src/main/java/net/minestom/server/ServerFlag.java index afd04ba8a..5caed768e 100644 --- a/src/main/java/net/minestom/server/ServerFlag.java +++ b/src/main/java/net/minestom/server/ServerFlag.java @@ -18,13 +18,7 @@ public final class ServerFlag { public static final int CHUNK_VIEW_DISTANCE = intProperty("minestom.chunk-view-distance", 8); public static final int ENTITY_VIEW_DISTANCE = intProperty("minestom.entity-view-distance", 5); public static final int ENTITY_SYNCHRONIZATION_TICKS = intProperty("minestom.entity-synchronization-ticks", 20); - public static final int WORKER_COUNT = intProperty("minestom.workers", Runtime.getRuntime().availableProcessors()); public static final int DISPATCHER_THREADS = intProperty("minestom.dispatcher-threads", 1); - public static final int MAX_PACKET_SIZE = intProperty("minestom.max-packet-size", 2_097_151); // 3 bytes var-int - public static final int SOCKET_SEND_BUFFER_SIZE = intProperty("minestom.send-buffer-size", 262_143); - public static final int SOCKET_RECEIVE_BUFFER_SIZE = intProperty("minestom.receive-buffer-size", 32_767); - public static final boolean SOCKET_NO_DELAY = booleanProperty("minestom.tcp-no-delay", true); - public static final int POOLED_BUFFER_SIZE = intProperty("minestom.pooled-buffer-size", 262_143); public static final int SEND_LIGHT_AFTER_BLOCK_PLACEMENT_DELAY = intProperty("minestom.send-light-after-block-placement-delay", 100); public static final long LOGIN_PLUGIN_MESSAGE_TIMEOUT = longProperty("minestom.login-plugin-message-timeout", 5_000); @@ -34,6 +28,15 @@ public final class ServerFlag { public static final long KEEP_ALIVE_DELAY = longProperty("minestom.keep-alive-delay", 10_000); public static final long KEEP_ALIVE_KICK = longProperty("minestom.keep-alive-kick", 15_000); + // Network buffers + public static final int MAX_PACKET_SIZE = intProperty("minestom.max-packet-size", 2_097_151); // 3 bytes var-int + public static final int MAX_PACKET_SIZE_PRE_AUTH = intProperty("minestom.max-packet-size-pre-auth", 8_192); + public static final int SOCKET_SEND_BUFFER_SIZE = intProperty("minestom.send-buffer-size", 262_143); + public static final int SOCKET_RECEIVE_BUFFER_SIZE = intProperty("minestom.receive-buffer-size", 32_767); + public static final boolean SOCKET_NO_DELAY = booleanProperty("minestom.tcp-no-delay", true); + public static final int SOCKET_TIMEOUT = intProperty("minestom.socket-timeout", 15_000); + public static final int POOLED_BUFFER_SIZE = intProperty("minestom.pooled-buffer-size", 16_383); + // Chunk update public static final float MIN_CHUNKS_PER_TICK = floatProperty("minestom.chunk-queue.min-per-tick", 0.01f); public static final float MAX_CHUNKS_PER_TICK = floatProperty("minestom.chunk-queue.max-per-tick", 64.0f); diff --git a/src/main/java/net/minestom/server/ServerProcess.java b/src/main/java/net/minestom/server/ServerProcess.java index 4b93d28f2..c231249ec 100644 --- a/src/main/java/net/minestom/server/ServerProcess.java +++ b/src/main/java/net/minestom/server/ServerProcess.java @@ -14,6 +14,7 @@ import net.minestom.server.listener.manager.PacketListenerManager; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.socket.Server; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.registry.Registries; @@ -103,7 +104,7 @@ public interface ServerProcess extends Registries, Snapshotable { *

* Can be used if you want to convert a buffer to a client packet object. */ - @NotNull PacketParser.Client packetParser(); + @NotNull PacketParser packetParser(); /** * Exposed socket server. diff --git a/src/main/java/net/minestom/server/ServerProcessImpl.java b/src/main/java/net/minestom/server/ServerProcessImpl.java index f44894dbd..375c0813d 100644 --- a/src/main/java/net/minestom/server/ServerProcessImpl.java +++ b/src/main/java/net/minestom/server/ServerProcessImpl.java @@ -28,6 +28,8 @@ import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.PacketVanilla; +import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.socket.Server; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.registry.DynamicRegistry; @@ -37,7 +39,7 @@ import net.minestom.server.thread.Acquirable; import net.minestom.server.thread.ThreadDispatcher; import net.minestom.server.thread.ThreadProvider; import net.minestom.server.timer.SchedulerManager; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketViewableUtils; import net.minestom.server.utils.collection.MappedCollection; import net.minestom.server.utils.nbt.BinaryTagSerializer; import net.minestom.server.world.DimensionType; @@ -77,7 +79,7 @@ final class ServerProcessImpl implements ServerProcess { private final ConnectionManager connection; private final PacketListenerManager packetListener; - private final PacketParser.Client packetParser; + private final PacketParser packetParser; private final InstanceManager instance; private final BlockManager block; private final CommandManager command; @@ -98,7 +100,7 @@ final class ServerProcessImpl implements ServerProcess { private final AtomicBoolean started = new AtomicBoolean(); private final AtomicBoolean stopped = new AtomicBoolean(); - public ServerProcessImpl() throws IOException { + public ServerProcessImpl() { this.exception = new ExceptionManager(); // The order of initialization here is relevant, we must load the enchantment util registries before the vanilla data is loaded. @@ -122,7 +124,7 @@ final class ServerProcessImpl implements ServerProcess { this.connection = new ConnectionManager(); this.packetListener = new PacketListenerManager(); - this.packetParser = new PacketParser.Client(); + this.packetParser = PacketVanilla.CLIENT_PACKET_PARSER; this.instance = new InstanceManager(this); this.block = new BlockManager(); this.command = new CommandManager(); @@ -287,7 +289,7 @@ final class ServerProcessImpl implements ServerProcess { } @Override - public @NotNull PacketParser.Client packetParser() { + public @NotNull PacketParser packetParser() { return packetParser; } @@ -379,10 +381,7 @@ final class ServerProcessImpl implements ServerProcess { scheduler().processTickEnd(); // Flush all waiting packets - PacketUtils.flush(); - - // Server connection tick - server().tick(); + PacketViewableUtils.flush(); // Monitoring { diff --git a/src/main/java/net/minestom/server/Viewable.java b/src/main/java/net/minestom/server/Viewable.java index 6cf1c0b59..14f66763b 100644 --- a/src/main/java/net/minestom/server/Viewable.java +++ b/src/main/java/net/minestom/server/Viewable.java @@ -5,7 +5,7 @@ import net.minestom.server.adventure.audience.PacketGroupingAudience; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -60,7 +60,7 @@ public interface Viewable { */ default void sendPacketToViewers(@NotNull SendablePacket packet) { if (packet instanceof ServerPacket serverPacket) { - PacketUtils.sendGroupedPacket(getViewers(), serverPacket); + PacketSendingUtils.sendGroupedPacket(getViewers(), serverPacket); } else { getViewers().forEach(player -> player.sendPacket(packet)); } diff --git a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java index f532a6be0..6ce60a2b4 100644 --- a/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java +++ b/src/main/java/net/minestom/server/adventure/audience/PacketGroupingAudience.java @@ -20,7 +20,7 @@ import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.ActionBarPacket; import net.minestom.server.network.packet.server.play.ClearTitlesPacket; import net.minestom.server.network.packet.server.play.PlayerListHeaderAndFooterPacket; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -54,7 +54,7 @@ public interface PacketGroupingAudience extends ForwardingAudience { * @param packet the packet to broadcast */ default void sendGroupedPacket(@NotNull ServerPacket packet) { - PacketUtils.sendGroupedPacket(getPlayers(), packet); + PacketSendingUtils.sendGroupedPacket(getPlayers(), packet); } @Deprecated diff --git a/src/main/java/net/minestom/server/adventure/bossbar/BossBarListener.java b/src/main/java/net/minestom/server/adventure/bossbar/BossBarListener.java index 8d36ec6fd..d05c2514e 100644 --- a/src/main/java/net/minestom/server/adventure/bossbar/BossBarListener.java +++ b/src/main/java/net/minestom/server/adventure/bossbar/BossBarListener.java @@ -3,7 +3,7 @@ package net.minestom.server.adventure.bossbar; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.Set; @@ -29,33 +29,32 @@ class BossBarListener implements BossBar.Listener { @Override public void bossBarNameChanged(@NotNull BossBar bar, @NotNull Component oldName, @NotNull Component newName) { - this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createTitleUpdate(newName))); + this.doIfRegistered(bar, holder -> PacketSendingUtils.sendGroupedPacket(holder.players, holder.createTitleUpdate(newName))); } @Override public void bossBarProgressChanged(@NotNull BossBar bar, float oldProgress, float newProgress) { - this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createPercentUpdate(newProgress))); + this.doIfRegistered(bar, holder -> PacketSendingUtils.sendGroupedPacket(holder.players, holder.createPercentUpdate(newProgress))); } @Override public void bossBarColorChanged(@NotNull BossBar bar, @NotNull BossBar.Color oldColor, @NotNull BossBar.Color newColor) { - this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createColorUpdate(newColor))); + this.doIfRegistered(bar, holder -> PacketSendingUtils.sendGroupedPacket(holder.players, holder.createColorUpdate(newColor))); } @Override public void bossBarOverlayChanged(@NotNull BossBar bar, BossBar.@NotNull Overlay oldOverlay, BossBar.@NotNull Overlay newOverlay) { - this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createOverlayUpdate(newOverlay))); + this.doIfRegistered(bar, holder -> PacketSendingUtils.sendGroupedPacket(holder.players, holder.createOverlayUpdate(newOverlay))); } @Override public void bossBarFlagsChanged(@NotNull BossBar bar, @NotNull Set flagsAdded, @NotNull Set flagsRemoved) { - this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createFlagsUpdate())); + this.doIfRegistered(bar, holder -> PacketSendingUtils.sendGroupedPacket(holder.players, holder.createFlagsUpdate())); } private void doIfRegistered(@NotNull BossBar bar, @NotNull Consumer consumer) { BossBarHolder holder = this.manager.bars.get(bar); - if (holder != null) { consumer.accept(holder); } diff --git a/src/main/java/net/minestom/server/adventure/bossbar/BossBarManager.java b/src/main/java/net/minestom/server/adventure/bossbar/BossBarManager.java index b1a9fc4b7..7e03508ef 100644 --- a/src/main/java/net/minestom/server/adventure/bossbar/BossBarManager.java +++ b/src/main/java/net/minestom/server/adventure/bossbar/BossBarManager.java @@ -4,7 +4,7 @@ import net.kyori.adventure.audience.Audience; import net.kyori.adventure.bossbar.BossBar; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -75,7 +75,7 @@ public class BossBarManager { BossBarHolder holder = this.getOrCreateHandler(bar); Collection addedPlayers = players.stream().filter(holder::addViewer).toList(); if (!addedPlayers.isEmpty()) { - PacketUtils.sendGroupedPacket(addedPlayers, holder.createAddPacket()); + PacketSendingUtils.sendGroupedPacket(addedPlayers, holder.createAddPacket()); } } @@ -90,7 +90,7 @@ public class BossBarManager { if (holder != null) { Collection removedPlayers = players.stream().filter(holder::removeViewer).toList(); if (!removedPlayers.isEmpty()) { - PacketUtils.sendGroupedPacket(removedPlayers, holder.createRemovePacket()); + PacketSendingUtils.sendGroupedPacket(removedPlayers, holder.createRemovePacket()); } } } @@ -103,7 +103,7 @@ public class BossBarManager { public void destroyBossBar(@NotNull BossBar bossBar) { BossBarHolder holder = this.bars.remove(bossBar); if (holder != null) { - PacketUtils.sendGroupedPacket(holder.players, holder.createRemovePacket()); + PacketSendingUtils.sendGroupedPacket(holder.players, holder.createRemovePacket()); for (Player player : holder.players) { this.removePlayer(player, holder); } diff --git a/src/main/java/net/minestom/server/color/AlphaColor.java b/src/main/java/net/minestom/server/color/AlphaColor.java index 10138425a..e61a4684c 100644 --- a/src/main/java/net/minestom/server/color/AlphaColor.java +++ b/src/main/java/net/minestom/server/color/AlphaColor.java @@ -16,17 +16,7 @@ import java.util.Objects; public final class AlphaColor extends Color { private static final int BIT_MASK = 0xff; - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, AlphaColor value) { - buffer.write(NetworkBuffer.INT, value.asARGB()); - } - - @Override - public AlphaColor read(@NotNull NetworkBuffer buffer) { - return new AlphaColor(buffer.read(NetworkBuffer.INT)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.INT.transform(AlphaColor::new, AlphaColor::asARGB); private final int alpha; public AlphaColor(int alpha, int red, int green, int blue) { diff --git a/src/main/java/net/minestom/server/color/Color.java b/src/main/java/net/minestom/server/color/Color.java index a825be1ae..7f62c67c8 100644 --- a/src/main/java/net/minestom/server/color/Color.java +++ b/src/main/java/net/minestom/server/color/Color.java @@ -17,17 +17,10 @@ import java.util.Objects; public class Color implements RGBLike { private static final int BIT_MASK = 0xff; - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, RGBLike value) { - buffer.write(NetworkBuffer.INT, Color.fromRGBLike(value).asRGB()); - } - - @Override - public RGBLike read(@NotNull NetworkBuffer buffer) { - return new Color(buffer.read(NetworkBuffer.INT)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.INT.transform( + Color::new, + color -> Color.fromRGBLike(color).asRGB() + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.INT .map(Color::new, color -> Color.fromRGBLike(color).asRGB()); private final int red; diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java index 1a19db780..d9b6b6aa9 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java @@ -37,9 +37,7 @@ public class ArgumentString extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> { - buffer.write(NetworkBuffer.VAR_INT, 1); // Quotable phrase - }); + return NetworkBuffer.makeArray(NetworkBuffer.VAR_INT, 1); // Quotable phrase } /** diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java index 52dee3837..f9e164b19 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java @@ -32,9 +32,7 @@ public class ArgumentStringArray extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> { - buffer.write(NetworkBuffer.VAR_INT, 2); // Greedy phrase - }); + return NetworkBuffer.makeArray(NetworkBuffer.VAR_INT, 2); // Greedy phrase } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java index 0a47a1ec5..59acab818 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java @@ -75,9 +75,7 @@ public class ArgumentWord extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> { - buffer.write(NetworkBuffer.VAR_INT, 0); // Single word - }); + return NetworkBuffer.makeArray(NetworkBuffer.VAR_INT, 0); // Single word } /** diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java index d1a666c3d..b36980e42 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResource.java @@ -39,6 +39,6 @@ public class ArgumentResource extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> buffer.write(NetworkBuffer.STRING, identifier)); + return NetworkBuffer.makeArray(NetworkBuffer.STRING, identifier); } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java index 5d48a7f18..47b84819c 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentResourceOrTag.java @@ -39,8 +39,6 @@ public class ArgumentResourceOrTag extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> - buffer.write(NetworkBuffer.STRING, this.identifier) - ); + return NetworkBuffer.makeArray(NetworkBuffer.STRING, identifier); } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java index 779f104c2..ca6d59ce8 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentTime.java @@ -70,7 +70,7 @@ public class ArgumentTime extends Argument { @Override public byte @Nullable [] nodeProperties() { - return NetworkBuffer.makeArray(buffer -> buffer.write(NetworkBuffer.INT, min)); + return NetworkBuffer.makeArray(NetworkBuffer.INT, min); } @Override diff --git a/src/main/java/net/minestom/server/crypto/ArgumentSignatures.java b/src/main/java/net/minestom/server/crypto/ArgumentSignatures.java index 4f793b445..bbafdb989 100644 --- a/src/main/java/net/minestom/server/crypto/ArgumentSignatures.java +++ b/src/main/java/net/minestom/server/crypto/ArgumentSignatures.java @@ -1,37 +1,30 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import java.util.List; import static net.minestom.server.network.NetworkBuffer.STRING; -public record ArgumentSignatures(@NotNull List<@NotNull Entry> entries) implements NetworkBuffer.Writer { +public record ArgumentSignatures(@NotNull List<@NotNull Entry> entries) { public static final int MAX_ENTRIES = 8; public ArgumentSignatures { entries = List.copyOf(entries); } - public ArgumentSignatures(@NotNull NetworkBuffer reader) { - this(reader.readCollection(Entry::new, MAX_ENTRIES)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Entry.SERIALIZER.list(MAX_ENTRIES), ArgumentSignatures::entries, + ArgumentSignatures::new + ); - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(entries); - } - - public record Entry(@NotNull String name, @NotNull MessageSignature signature) implements NetworkBuffer.Writer { - public Entry(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), new MessageSignature(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, name); - writer.write(signature); - } + public record Entry(@NotNull String name, @NotNull MessageSignature signature) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Entry::name, + MessageSignature.SERIALIZER, Entry::signature, + Entry::new + ); } } diff --git a/src/main/java/net/minestom/server/crypto/ChatSession.java b/src/main/java/net/minestom/server/crypto/ChatSession.java index 1cdcd253b..30d5fd8ec 100644 --- a/src/main/java/net/minestom/server/crypto/ChatSession.java +++ b/src/main/java/net/minestom/server/crypto/ChatSession.java @@ -1,18 +1,17 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import java.util.UUID; -public record ChatSession(@NotNull UUID sessionId, @NotNull PlayerPublicKey publicKey) implements NetworkBuffer.Writer { - public ChatSession(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID), new PlayerPublicKey(reader)); - } +import static net.minestom.server.network.NetworkBuffer.UUID; - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, sessionId); - writer.write(publicKey); - } +public record ChatSession(@NotNull UUID sessionId, @NotNull PlayerPublicKey publicKey) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + UUID, ChatSession::sessionId, + PlayerPublicKey.SERIALIZER, ChatSession::publicKey, + ChatSession::new + ); } diff --git a/src/main/java/net/minestom/server/crypto/FilterMask.java b/src/main/java/net/minestom/server/crypto/FilterMask.java index 2ffe575d4..d99d1e0e6 100644 --- a/src/main/java/net/minestom/server/crypto/FilterMask.java +++ b/src/main/java/net/minestom/server/crypto/FilterMask.java @@ -5,20 +5,25 @@ import org.jetbrains.annotations.NotNull; import java.util.BitSet; -import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY; +import static net.minestom.server.network.NetworkBuffer.BITSET; -public record FilterMask(@NotNull Type type, @NotNull BitSet mask) implements NetworkBuffer.Writer { - public FilterMask(@NotNull NetworkBuffer reader) { - this(reader.readEnum(Type.class), BitSet.valueOf(reader.read(LONG_ARRAY))); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(Type.class, type); - if (type == Type.PARTIALLY_FILTERED) { - writer.write(LONG_ARRAY, mask.toLongArray()); +public record FilterMask(@NotNull Type type, @NotNull BitSet mask) { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, FilterMask value) { + buffer.write(NetworkBuffer.Enum(Type.class), value.type); + if (value.type == Type.PARTIALLY_FILTERED) { + buffer.write(BITSET, value.mask); + } } - } + + @Override + public FilterMask read(@NotNull NetworkBuffer buffer) { + Type type = buffer.read(NetworkBuffer.Enum(Type.class)); + BitSet mask = type == Type.PARTIALLY_FILTERED ? buffer.read(BITSET) : new BitSet(); + return new FilterMask(type, mask); + } + }; public enum Type { PASS_THROUGH, diff --git a/src/main/java/net/minestom/server/crypto/LastSeenMessages.java b/src/main/java/net/minestom/server/crypto/LastSeenMessages.java index 76f3efd70..9e004f4a9 100644 --- a/src/main/java/net/minestom/server/crypto/LastSeenMessages.java +++ b/src/main/java/net/minestom/server/crypto/LastSeenMessages.java @@ -1,50 +1,41 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import java.util.BitSet; import java.util.List; +import static net.minestom.server.network.NetworkBuffer.FixedBitSet; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries) implements NetworkBuffer.Writer { +public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries) { public static final int MAX_ENTRIES = 20; public LastSeenMessages { entries = List.copyOf(entries); } - public LastSeenMessages(@NotNull NetworkBuffer reader) { - this(reader.readCollection(MessageSignature::new, MAX_ENTRIES)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + MessageSignature.SERIALIZER.list(MAX_ENTRIES), LastSeenMessages::entries, + LastSeenMessages::new + ); - @Override - public void write(@NotNull NetworkBuffer writer) { - } - - public record Packed(@NotNull List entries) implements NetworkBuffer.Writer { + public record Packed(@NotNull List entries) { public static final Packed EMPTY = new Packed(List.of()); - public Packed(@NotNull NetworkBuffer reader) { - this(reader.readCollection(MessageSignature.Packed::new, MAX_ENTRIES)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(entries); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + MessageSignature.Packed.SERIALIZER.list(MAX_ENTRIES), Packed::entries, + Packed::new + ); } - public record Update(int offset, @NotNull BitSet acknowledged) implements NetworkBuffer.Writer { - public Update(@NotNull NetworkBuffer reader) { - this(reader.read(VAR_INT), reader.readFixedBitSet(20)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, offset); - writer.writeFixedBitSet(acknowledged, 20); - } + public record Update(int offset, @NotNull BitSet acknowledged) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, Update::offset, + FixedBitSet(20), Update::acknowledged, + Update::new + ); } } diff --git a/src/main/java/net/minestom/server/crypto/MessageSignature.java b/src/main/java/net/minestom/server/crypto/MessageSignature.java index c6cf3e836..fe16e7e11 100644 --- a/src/main/java/net/minestom/server/crypto/MessageSignature.java +++ b/src/main/java/net/minestom/server/crypto/MessageSignature.java @@ -1,14 +1,13 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import static net.minestom.server.network.NetworkBuffer.RAW_BYTES; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record MessageSignature(byte @NotNull [] signature) implements NetworkBuffer.Writer { - +public record MessageSignature(byte @NotNull [] signature) { static final int SIGNATURE_BYTE_LENGTH = 256; public MessageSignature { @@ -17,33 +16,28 @@ public record MessageSignature(byte @NotNull [] signature) implements NetworkBuf } } - public MessageSignature(@NotNull NetworkBuffer reader) { - this(reader.readBytes(SIGNATURE_BYTE_LENGTH)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(RAW_BYTES, signature); - } - - public record Packed(int id, @UnknownNullability MessageSignature fullSignature) implements NetworkBuffer.Writer { - public Packed(@NotNull NetworkBuffer reader) { - this(read(reader)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.RAW_BYTES, MessageSignature::signature, + MessageSignature::new + ); + public record Packed(int id, @UnknownNullability MessageSignature fullSignature) { private Packed(@NotNull Packed packed) { this(packed.id, packed.fullSignature); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, id + 1); - if (id == 0) writer.write(fullSignature); - } + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, Packed value) { + buffer.write(VAR_INT, value.id + 1); + if (value.id == 0) buffer.write(MessageSignature.SERIALIZER, value.fullSignature); + } - private static Packed read(NetworkBuffer reader) { - final int id = reader.read(VAR_INT) - 1; - return new Packed(id, id == -1 ? new MessageSignature(reader) : null); - } + @Override + public Packed read(@NotNull NetworkBuffer buffer) { + final int id = buffer.read(VAR_INT) - 1; + return new Packed(id, id == -1 ? buffer.read(MessageSignature.SERIALIZER) : null); + } + }; } } diff --git a/src/main/java/net/minestom/server/crypto/PlayerPublicKey.java b/src/main/java/net/minestom/server/crypto/PlayerPublicKey.java index d052badfb..f27622dc6 100644 --- a/src/main/java/net/minestom/server/crypto/PlayerPublicKey.java +++ b/src/main/java/net/minestom/server/crypto/PlayerPublicKey.java @@ -1,39 +1,21 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.utils.crypto.KeyUtils; -import org.jetbrains.annotations.NotNull; +import net.minestom.server.network.NetworkBufferTemplate; import java.security.PublicKey; import java.time.Instant; -import java.util.Arrays; -import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY; -import static net.minestom.server.network.NetworkBuffer.LONG; +import static net.minestom.server.network.NetworkBuffer.*; /** * Player's public key used to sign chat messages */ -public record PlayerPublicKey(Instant expiresAt, PublicKey publicKey, - byte[] signature) implements NetworkBuffer.Writer { - public PlayerPublicKey(@NotNull NetworkBuffer reader) { - this(Instant.ofEpochMilli(reader.read(LONG)), - KeyUtils.publicRSAKeyFrom(reader.read(BYTE_ARRAY)), reader.read(BYTE_ARRAY)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, expiresAt().toEpochMilli()); - writer.write(BYTE_ARRAY, publicKey.getEncoded()); - writer.write(BYTE_ARRAY, signature()); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PlayerPublicKey ppk) { - return expiresAt.equals(ppk.expiresAt) && publicKey.equals(ppk.publicKey) && Arrays.equals(signature, ppk.signature); - } else { - return false; - } - } +public record PlayerPublicKey(Instant expiresAt, PublicKey publicKey, byte[] signature) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INSTANT_MS, PlayerPublicKey::expiresAt, + PUBLIC_KEY, PlayerPublicKey::publicKey, + BYTE_ARRAY, PlayerPublicKey::signature, + PlayerPublicKey::new + ); } diff --git a/src/main/java/net/minestom/server/crypto/SaltSignaturePair.java b/src/main/java/net/minestom/server/crypto/SaltSignaturePair.java index 132df950a..6ee4dda97 100644 --- a/src/main/java/net/minestom/server/crypto/SaltSignaturePair.java +++ b/src/main/java/net/minestom/server/crypto/SaltSignaturePair.java @@ -1,19 +1,12 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; -import org.jetbrains.annotations.NotNull; +import net.minestom.server.network.NetworkBufferTemplate; -import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY; -import static net.minestom.server.network.NetworkBuffer.LONG; - -public record SaltSignaturePair(long salt, byte[] signature) implements NetworkBuffer.Writer { - public SaltSignaturePair(@NotNull NetworkBuffer reader) { - this(reader.read(LONG), reader.read(BYTE_ARRAY)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG, salt); - writer.write(BYTE_ARRAY, signature); - } +public record SaltSignaturePair(long salt, byte[] signature) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.LONG, SaltSignaturePair::salt, + NetworkBuffer.BYTE_ARRAY, SaltSignaturePair::signature, + SaltSignaturePair::new + ); } diff --git a/src/main/java/net/minestom/server/crypto/SignedMessageBody.java b/src/main/java/net/minestom/server/crypto/SignedMessageBody.java index 49b60f6e1..c48225386 100644 --- a/src/main/java/net/minestom/server/crypto/SignedMessageBody.java +++ b/src/main/java/net/minestom/server/crypto/SignedMessageBody.java @@ -1,6 +1,7 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import java.time.Instant; @@ -8,24 +9,19 @@ import java.time.Instant; public final class SignedMessageBody { public record Packed(@NotNull String content, @NotNull Instant timeStamp, long salt, - LastSeenMessages.@NotNull Packed lastSeen) implements NetworkBuffer.Writer { + LastSeenMessages.@NotNull Packed lastSeen) { public Packed { if (content.length() > MessageSignature.SIGNATURE_BYTE_LENGTH) { throw new IllegalArgumentException("Message content too long"); } } - public Packed(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.STRING), Instant.ofEpochMilli(reader.read(NetworkBuffer.LONG)), - reader.read(NetworkBuffer.LONG), new LastSeenMessages.Packed(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING, content); - writer.write(NetworkBuffer.LONG, timeStamp.toEpochMilli()); - writer.write(NetworkBuffer.LONG, salt); - writer.write(lastSeen); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.STRING, Packed::content, + NetworkBuffer.INSTANT_MS, Packed::timeStamp, + NetworkBuffer.LONG, Packed::salt, + LastSeenMessages.Packed.SERIALIZER, Packed::lastSeen, + Packed::new + ); } } diff --git a/src/main/java/net/minestom/server/crypto/SignedMessageHeader.java b/src/main/java/net/minestom/server/crypto/SignedMessageHeader.java index 5aa6734cc..b15e68f12 100644 --- a/src/main/java/net/minestom/server/crypto/SignedMessageHeader.java +++ b/src/main/java/net/minestom/server/crypto/SignedMessageHeader.java @@ -1,20 +1,16 @@ package net.minestom.server.crypto; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; -public record SignedMessageHeader(@Nullable MessageSignature previousSignature, - @NotNull UUID sender) implements NetworkBuffer.Writer { - public SignedMessageHeader(@NotNull NetworkBuffer reader) { - this(reader.readOptional(MessageSignature::new), reader.read(NetworkBuffer.UUID)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeOptional(previousSignature); - writer.write(NetworkBuffer.UUID, sender); - } +public record SignedMessageHeader(@Nullable MessageSignature previousSignature, @NotNull UUID sender) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + MessageSignature.SERIALIZER.optional(), SignedMessageHeader::previousSignature, + NetworkBuffer.UUID, SignedMessageHeader::sender, + SignedMessageHeader::new + ); } diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index c5f401d9c..690a2d284 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -47,7 +47,7 @@ import net.minestom.server.timer.Schedulable; import net.minestom.server.timer.Scheduler; import net.minestom.server.timer.TaskSchedule; import net.minestom.server.utils.ArrayUtils; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketViewableUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.block.BlockIterator; import net.minestom.server.utils.chunk.ChunkCache; @@ -1244,22 +1244,21 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev final Chunk chunk = getChunk(); assert chunk != null; if (distanceX > 8 || distanceY > 8 || distanceZ > 8) { - PacketUtils.prepareViewablePacket(chunk, new EntityTeleportPacket(getEntityId(), position, isOnGround()), this); + PacketViewableUtils.prepareViewablePacket(chunk, new EntityTeleportPacket(getEntityId(), position, isOnGround()), this); nextSynchronizationTick = synchronizationTicks + 1; } else if (positionChange && viewChange) { -// PacketUtils.prepareViewablePacket(chunk, new EntityVelocityPacket(getEntityId(), new Vec(distanceX, distanceY, distanceZ).div(20 * 8000))); - PacketUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, + PacketViewableUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, lastSyncedPosition, isOnGround()), this); // Fix head rotation - PacketUtils.prepareViewablePacket(chunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); + PacketViewableUtils.prepareViewablePacket(chunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); } else if (positionChange) { // This is a confusing fix for a confusing issue. If rotation is only sent when the entity actually changes, then spawning an entity // on the ground causes the entity not to update its rotation correctly. It works fine if the entity is spawned in the air. Very weird. - PacketUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, + PacketViewableUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, lastSyncedPosition, onGround), this); } else if (viewChange) { - PacketUtils.prepareViewablePacket(chunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); - PacketUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, + PacketViewableUtils.prepareViewablePacket(chunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); + PacketViewableUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, lastSyncedPosition, isOnGround()), this); } this.lastSyncedPosition = position; @@ -1535,9 +1534,9 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev @ApiStatus.Internal protected void synchronizePosition() { final Pos posCache = this.position; - PacketUtils.prepareViewablePacket(currentChunk, new EntityTeleportPacket(getEntityId(), posCache, isOnGround()), this); + PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityTeleportPacket(getEntityId(), posCache, isOnGround()), this); if (posCache.yaw() != lastSyncedPosition.yaw()) { - PacketUtils.prepareViewablePacket(currentChunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); + PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); } nextSynchronizationTick = ticks + synchronizationTicks; this.lastSyncedPosition = posCache; diff --git a/src/main/java/net/minestom/server/entity/GameMode.java b/src/main/java/net/minestom/server/entity/GameMode.java index 983ec78cf..c72cd4a55 100644 --- a/src/main/java/net/minestom/server/entity/GameMode.java +++ b/src/main/java/net/minestom/server/entity/GameMode.java @@ -32,15 +32,18 @@ public enum GameMode { return canTakeDamage; } - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { + public static final NetworkBuffer.Type NETWORK_TYPE = BYTE.transform(GameMode::fromId, gameMode -> gameMode.id); + + public static final NetworkBuffer.Type OPT_NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, GameMode value) { - buffer.write(BYTE, value.id()); + buffer.write(BYTE, value != null ? value.id() : -1); } @Override public GameMode read(@NotNull NetworkBuffer buffer) { - return GameMode.fromId(buffer.read(BYTE)); + final byte id = buffer.read(BYTE); + return id != -1 ? GameMode.fromId(id) : null; } }; diff --git a/src/main/java/net/minestom/server/entity/Metadata.java b/src/main/java/net/minestom/server/entity/Metadata.java index 223f3e8a1..168fcc46a 100644 --- a/src/main/java/net/minestom/server/entity/Metadata.java +++ b/src/main/java/net/minestom/server/entity/Metadata.java @@ -16,7 +16,6 @@ import net.minestom.server.particle.Particle; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.Direction; import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnknownNullability; @@ -213,15 +212,13 @@ public final class Metadata { return (byte) NEXT_ID.getAndIncrement(); } - public sealed interface Entry extends NetworkBuffer.Writer - permits MetadataImpl.EntryImpl { + public sealed interface Entry permits MetadataImpl.EntryImpl { + @SuppressWarnings({"unchecked", "rawtypes"}) + NetworkBuffer.Type> SERIALIZER = (NetworkBuffer.Type) MetadataImpl.EntryImpl.SERIALIZER; + int type(); - @UnknownNullability T value(); - - @ApiStatus.Internal - static @NotNull Entry read(int type, @NotNull NetworkBuffer reader) { - return MetadataImpl.EntryImpl.read(type, reader); - } + @UnknownNullability + T value(); } } diff --git a/src/main/java/net/minestom/server/entity/MetadataImpl.java b/src/main/java/net/minestom/server/entity/MetadataImpl.java index 56000a7b0..ef168e7c1 100644 --- a/src/main/java/net/minestom/server/entity/MetadataImpl.java +++ b/src/main/java/net/minestom/server/entity/MetadataImpl.java @@ -61,22 +61,23 @@ final class MetadataImpl { EMPTY_VALUES.trim(); } + @SuppressWarnings({"rawtypes", "unchecked"}) record EntryImpl(int type, @UnknownNullability T value, @NotNull NetworkBuffer.Type serializer) implements Metadata.Entry { - static Entry read(int type, @NotNull NetworkBuffer reader) { - final EntryImpl value = (EntryImpl) EMPTY_VALUES.get(type); - if (value == null) throw new UnsupportedOperationException("Unknown value type: " + type); - return value.withValue(reader); - } + static final NetworkBuffer.Type> SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, EntryImpl value) { + buffer.write(VAR_INT, value.type); + buffer.write(value.serializer, value.value); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, type); - writer.write(serializer, value); - } - - private EntryImpl withValue(@NotNull NetworkBuffer reader) { - return new EntryImpl<>(type, reader.read(serializer), serializer); - } + @Override + public EntryImpl read(@NotNull NetworkBuffer buffer) { + final int type = buffer.read(VAR_INT); + final EntryImpl value = (EntryImpl) EMPTY_VALUES.get(type); + if (value == null) throw new UnsupportedOperationException("Unknown value type: " + type); + return new EntryImpl(type, value.serializer.read(buffer), value.serializer); + } + }; } } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index e1f34666d..5f7aa22ee 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -87,7 +87,7 @@ import net.minestom.server.statistic.PlayerStatistic; import net.minestom.server.thread.Acquirable; import net.minestom.server.timer.Scheduler; import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.chunk.ChunkUpdateLimitChecker; import net.minestom.server.utils.chunk.ChunkUtils; @@ -328,7 +328,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, EventDispatcher.call(skinInitEvent); this.skin = skinInitEvent.getSkin(); // FIXME: when using Geyser, this line remove the skin of the client - PacketUtils.broadcastPlayPacket(getAddPlayerToList()); + PacketSendingUtils.broadcastPlayPacket(getAddPlayerToList()); var connectionManager = MinecraftServer.getConnectionManager(); for (var player : connectionManager.getOnlinePlayers()) { @@ -604,7 +604,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Clear all viewable chunks ChunkUtils.forChunksInRange(chunkX, chunkZ, settings.getEffectiveViewDistance(), chunkRemover); // Remove from the tab-list - PacketUtils.broadcastPlayPacket(getRemovePlayerToList()); + PacketSendingUtils.broadcastPlayPacket(getRemovePlayerToList()); // Prevent the player from being stuck in loading screen, or just unable to interact with the server // This should be considered as a bug, since the player will ultimately time out anyway. @@ -1010,7 +1010,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, String title = PlainTextComponentSerializer.plainText().serialize(book.title()); String author = PlainTextComponentSerializer.plainText().serialize(book.author()); final ItemStack writtenBook = ItemStack.builder(Material.WRITTEN_BOOK) - .set(ItemComponent.WRITTEN_BOOK_CONTENT, new WrittenBookContent(book.pages(), title, author, 0, false)) + .set(ItemComponent.WRITTEN_BOOK_CONTENT, new WrittenBookContent(title, author, 0, book.pages(), false)) .build(); // Set book in offhand @@ -1176,7 +1176,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, */ public void setDisplayName(@Nullable Component displayName) { this.displayName = displayName; - PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, infoEntry())); + PacketSendingUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, infoEntry())); } /** @@ -1218,11 +1218,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable, { // Remove player - PacketUtils.broadcastPlayPacket(removePlayerPacket); + PacketSendingUtils.broadcastPlayPacket(removePlayerPacket); sendPacketToViewers(destroyEntitiesPacket); // Show player again - PacketUtils.broadcastPlayPacket(addPlayerPacket); + PacketSendingUtils.broadcastPlayPacket(addPlayerPacket); getViewers().forEach(player -> showPlayer(player.getPlayerConnection())); } @@ -1606,7 +1606,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Condition to prevent sending the packets before spawning the player if (isActive()) { sendPacket(new ChangeGameStatePacket(ChangeGameStatePacket.Reason.CHANGE_GAMEMODE, gameMode.id())); - PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, infoEntry())); + PacketSendingUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, infoEntry())); } // The client updates their abilities based on the GameMode as follows @@ -2138,7 +2138,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void refreshLatency(int latency) { this.latency = latency; if (getPlayerConnection().getConnectionState() == ConnectionState.PLAY) { - PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry())); + PacketSendingUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry())); } } @@ -2361,6 +2361,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, /** * Send a {@link Notification} to the player. + * * @param notification the {@link Notification} to send */ public void sendNotification(@NotNull Notification notification) { diff --git a/src/main/java/net/minestom/server/entity/attribute/Attribute.java b/src/main/java/net/minestom/server/entity/attribute/Attribute.java index de52d5156..ebfeb429c 100644 --- a/src/main/java/net/minestom/server/entity/attribute/Attribute.java +++ b/src/main/java/net/minestom/server/entity/attribute/Attribute.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; public sealed interface Attribute extends StaticProtocolObject, Attributes permits AttributeImpl { - @NotNull NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.map(AttributeImpl::getId, Attribute::id); + @NotNull NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(AttributeImpl::getId, Attribute::id); @NotNull BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.STRING.map(AttributeImpl::get, Attribute::name); @Contract(pure = true) diff --git a/src/main/java/net/minestom/server/entity/attribute/AttributeInstance.java b/src/main/java/net/minestom/server/entity/attribute/AttributeInstance.java index c55f0ff53..7685b55b6 100644 --- a/src/main/java/net/minestom/server/entity/attribute/AttributeInstance.java +++ b/src/main/java/net/minestom/server/entity/attribute/AttributeInstance.java @@ -22,13 +22,13 @@ public final class AttributeInstance { public void write(@NotNull NetworkBuffer buffer, AttributeInstance value) { buffer.write(Attribute.NETWORK_TYPE, value.attribute()); buffer.write(NetworkBuffer.DOUBLE, value.getBaseValue()); - buffer.writeCollection(AttributeModifier.NETWORK_TYPE, value.modifiers()); + buffer.write(AttributeModifier.NETWORK_TYPE.list(Short.MAX_VALUE), List.copyOf(value.modifiers())); } @Override public AttributeInstance read(@NotNull NetworkBuffer buffer) { return new AttributeInstance(buffer.read(Attribute.NETWORK_TYPE), buffer.read(NetworkBuffer.DOUBLE), - buffer.readCollection(AttributeModifier.NETWORK_TYPE, Short.MAX_VALUE), null); + buffer.read(AttributeModifier.NETWORK_TYPE.list(Short.MAX_VALUE)), null); } }; diff --git a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java index 13eea96a3..cfe3a4eaa 100644 --- a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java +++ b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java @@ -2,8 +2,8 @@ package net.minestom.server.event.player; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.PlayerEvent; +import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; -import net.minestom.server.network.plugin.LoginPluginResponse; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -64,7 +64,7 @@ public class AsyncPlayerPreLoginEvent implements PlayerEvent { * * @return a CompletableFuture for the response. The thread on which it completes is asynchronous. */ - public @NotNull CompletableFuture sendPluginRequest(String channel, byte[] requestPayload) { + public @NotNull CompletableFuture sendPluginRequest(String channel, byte[] requestPayload) { return pluginMessageProcessor.request(channel, requestPayload); } diff --git a/src/main/java/net/minestom/server/extras/query/Query.java b/src/main/java/net/minestom/server/extras/query/Query.java index e60a610a4..504432e08 100644 --- a/src/main/java/net/minestom/server/extras/query/Query.java +++ b/src/main/java/net/minestom/server/extras/query/Query.java @@ -7,6 +7,8 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.event.EventDispatcher; import net.minestom.server.extras.query.event.BasicQueryEvent; import net.minestom.server.extras.query.event.FullQueryEvent; +import net.minestom.server.extras.query.response.BasicQueryResponse; +import net.minestom.server.extras.query.response.FullQueryResponse; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.timer.Task; import net.minestom.server.utils.time.TimeUnit; @@ -183,24 +185,24 @@ public class Query { if (remaining == 0) { // basic BasicQueryEvent event = new BasicQueryEvent(sender, sessionID); EventDispatcher.callCancellable(event, () -> - sendResponse(event.getQueryResponse(), sessionID, sender)); + sendResponse(BasicQueryResponse.SERIALIZER, event.getQueryResponse(), sessionID, sender)); } else if (remaining == 5) { // full FullQueryEvent event = new FullQueryEvent(sender, sessionID); EventDispatcher.callCancellable(event, () -> - sendResponse(event.getQueryResponse(), sessionID, sender)); + sendResponse(FullQueryResponse.SERIALIZER, event.getQueryResponse(), sessionID, sender)); } } } } } - private static void sendResponse(@NotNull NetworkBuffer.Writer queryResponse, int sessionID, @NotNull SocketAddress sender) { + private static void sendResponse(NetworkBuffer.Type type, @NotNull T queryResponse, int sessionID, @NotNull SocketAddress sender) { final byte[] responseData = NetworkBuffer.makeArray(buffer -> { // header buffer.write(NetworkBuffer.BYTE, (byte) 0); buffer.write(NetworkBuffer.INT, sessionID); // payload - buffer.write(queryResponse); + buffer.write(type, queryResponse); }); try { socket.send(new DatagramPacket(responseData, responseData.length, sender)); diff --git a/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java b/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java index 976def4b4..c8ec510ad 100644 --- a/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java +++ b/src/main/java/net/minestom/server/extras/query/event/QueryEvent.java @@ -1,7 +1,6 @@ package net.minestom.server.extras.query.event; import net.minestom.server.event.trait.CancellableEvent; -import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import java.net.SocketAddress; @@ -12,7 +11,7 @@ import java.util.Objects; * * @param the type of the response */ -public abstract class QueryEvent implements CancellableEvent { +public abstract class QueryEvent implements CancellableEvent { private final SocketAddress sender; private final int sessionID; diff --git a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java index 4a4875255..7e43a263b 100644 --- a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java @@ -2,145 +2,43 @@ package net.minestom.server.extras.query.response; import net.minestom.server.MinecraftServer; import net.minestom.server.network.NetworkBuffer; -import org.jetbrains.annotations.NotNull; +import net.minestom.server.network.NetworkBufferTemplate; import java.util.Objects; +import static net.minestom.server.network.NetworkBuffer.SHORT; +import static net.minestom.server.network.NetworkBuffer.STRING_TERMINATED; + /** * A basic query response containing a fixed set of responses. */ -public class BasicQueryResponse implements NetworkBuffer.Writer { - private String motd, gametype, map, numPlayers, maxPlayers; - +public record BasicQueryResponse(String motd, String gameType, + String map, + String numPlayers, String maxPlayers, + short port, String address) { /** * Creates a new basic query response with pre-filled default values. */ public BasicQueryResponse() { - this.motd = "A Minestom Server"; - this.gametype = "SMP"; - this.map = "world"; - this.numPlayers = String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayerCount()); - this.maxPlayers = String.valueOf(Integer.parseInt(this.numPlayers) + 1); + this( + "A Minestom Server", + "SMP", + "world", + String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayerCount()), + "9999", + (short) MinecraftServer.getServer().getPort(), + Objects.requireNonNullElse(MinecraftServer.getServer().getAddress(), "") + ); } - /** - * Gets the MoTD. - * - * @return the motd - */ - public @NotNull String getMotd() { - return this.motd; - } - - /** - * Sets the MoTD. - * - * @param motd the motd - */ - public void setMotd(@NotNull String motd) { - this.motd = Objects.requireNonNull(motd, "motd"); - } - - /** - * Gets the gametype. - * - * @return the gametype - */ - public @NotNull String getGametype() { - return this.gametype; - } - - /** - * Sets the gametype. - * - * @param gametype the gametype - */ - public void setGametype(@NotNull String gametype) { - this.gametype = Objects.requireNonNull(gametype, "gametype"); - } - - /** - * Gets the map. - * - * @return the map - */ - public @NotNull String getMap() { - return this.map; - } - - /** - * Sets the map. - * - * @param map the map - */ - public void setMap(@NotNull String map) { - this.map = Objects.requireNonNull(map, "map"); - } - - /** - * Gets the number of players. - * - * @return the number of players - */ - public @NotNull String getNumPlayers() { - return this.numPlayers; - } - - /** - * Sets the number of players. - * - * @param numPlayers the number of players - */ - public void setNumPlayers(@NotNull String numPlayers) { - this.numPlayers = Objects.requireNonNull(numPlayers, "numPlayers"); - } - - /** - * Sets the number of players. - * This method is just an overload for {@link #setNumPlayers(String)}. - * - * @param numPlayers the number of players - */ - public void setNumPlayers(int numPlayers) { - this.setNumPlayers(String.valueOf(numPlayers)); - } - - /** - * Gets the max number of players. - * - * @return the max number of players - */ - public @NotNull String getMaxPlayers() { - return this.maxPlayers; - } - - /** - * Sets the max number of players. - * - * @param maxPlayers the max number of players - */ - public void setMaxPlayers(@NotNull String maxPlayers) { - this.maxPlayers = Objects.requireNonNull(maxPlayers, "maxPlayers"); - } - - /** - * Sets the max number of players. - * This method is just an overload for {@link #setMaxPlayers(String)} - * - * @param maxPlayers the max number of players - */ - public void setMaxPlayers(int maxPlayers) { - this.setMaxPlayers(String.valueOf(maxPlayers)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.STRING_TERMINATED, this.motd); - writer.write(NetworkBuffer.STRING_TERMINATED, this.gametype); - writer.write(NetworkBuffer.STRING_TERMINATED, this.map); - writer.write(NetworkBuffer.STRING_TERMINATED, this.numPlayers); - writer.write(NetworkBuffer.STRING_TERMINATED, this.maxPlayers); - writer.write(NetworkBuffer.SHORT, (short) MinecraftServer.getServer().getPort()); // TODO little endian? - writer.write(NetworkBuffer.STRING_TERMINATED, Objects.requireNonNullElse(MinecraftServer.getServer().getAddress(), "")); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING_TERMINATED, BasicQueryResponse::motd, + STRING_TERMINATED, BasicQueryResponse::gameType, + STRING_TERMINATED, BasicQueryResponse::map, + STRING_TERMINATED, BasicQueryResponse::numPlayers, + STRING_TERMINATED, BasicQueryResponse::maxPlayers, + SHORT, BasicQueryResponse::port, // TODO little endian? + STRING_TERMINATED, BasicQueryResponse::address, + BasicQueryResponse::new + ); } diff --git a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java index 891269a26..dee7d14cf 100644 --- a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java @@ -10,7 +10,7 @@ import java.util.*; /** * A full query response containing a dynamic set of responses. */ -public class FullQueryResponse implements NetworkBuffer.Writer { +public class FullQueryResponse { private static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.plainText(); private static final byte[] PADDING_10 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, PADDING_11 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -123,20 +123,27 @@ public class FullQueryResponse implements NetworkBuffer.Writer { return builder.toString(); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.RAW_BYTES, PADDING_11); - // key-values - for (var entry : this.kv.entrySet()) { - writer.write(NetworkBuffer.STRING_TERMINATED, entry.getKey()); - writer.write(NetworkBuffer.STRING_TERMINATED, entry.getValue()); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, FullQueryResponse value) { + buffer.write(NetworkBuffer.RAW_BYTES, PADDING_11); + // key-values + for (var entry : value.kv.entrySet()) { + buffer.write(NetworkBuffer.STRING_TERMINATED, entry.getKey()); + buffer.write(NetworkBuffer.STRING_TERMINATED, entry.getValue()); + } + buffer.write(NetworkBuffer.STRING_TERMINATED, ""); + buffer.write(NetworkBuffer.RAW_BYTES, PADDING_10); + // players + for (String player : value.players) { + buffer.write(NetworkBuffer.STRING_TERMINATED, player); + } + buffer.write(NetworkBuffer.STRING_TERMINATED, ""); } - writer.write(NetworkBuffer.STRING_TERMINATED, ""); - writer.write(NetworkBuffer.RAW_BYTES, PADDING_10); - // players - for (String player : this.players) { - writer.write(NetworkBuffer.STRING_TERMINATED, player); + + @Override + public FullQueryResponse read(@NotNull NetworkBuffer buffer) { + throw new UnsupportedOperationException("FullQueryResponse is write-only"); } - writer.write(NetworkBuffer.STRING_TERMINATED, ""); - } + }; } diff --git a/src/main/java/net/minestom/server/extras/velocity/VelocityProxy.java b/src/main/java/net/minestom/server/extras/velocity/VelocityProxy.java index 10e47b03d..6d6442493 100644 --- a/src/main/java/net/minestom/server/extras/velocity/VelocityProxy.java +++ b/src/main/java/net/minestom/server/extras/velocity/VelocityProxy.java @@ -55,7 +55,7 @@ public final class VelocityProxy { for (int i = 0; i < signature.length; i++) { signature[i] = buffer.read(BYTE); } - final int index = buffer.readIndex(); + final long index = buffer.readIndex(); final byte[] data = buffer.read(RAW_BYTES); buffer.readIndex(index); try { @@ -66,7 +66,7 @@ public final class VelocityProxy { return false; } } catch (NoSuchAlgorithmException | InvalidKeyException e) { - e.printStackTrace(); + throw new RuntimeException(e); } final int version = buffer.read(VAR_INT); return version == SUPPORTED_FORWARDING_VERSION; diff --git a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java index e0deb7f37..6bfde77fb 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/TagManager.java +++ b/src/main/java/net/minestom/server/gamedata/tags/TagManager.java @@ -1,6 +1,6 @@ package net.minestom.server.gamedata.tags; -import net.minestom.server.registry.Registry; +import net.minestom.server.network.packet.server.common.TagsPacket; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.Nullable; @@ -18,7 +18,7 @@ public final class TagManager { // Load required tags from files for (var type : Tag.BasicType.values()) { if (type.getResource() == null || type.getFunction() == null) continue; - final var json = Registry.load(type.getResource()); + final var json = net.minestom.server.registry.Registry.load(type.getResource()); final var tagIdentifierMap = tagMap.computeIfAbsent(type, s -> new CopyOnWriteArrayList<>()); json.keySet().forEach(tagName -> { final var tag = new Tag(NamespaceID.from(tagName), getValues(json, tagName)); @@ -40,6 +40,22 @@ public final class TagManager { return Collections.unmodifiableMap(tagMap); } + public TagsPacket packet() { + List registries = new ArrayList<>(); + for (Map.Entry> entry : tagMap.entrySet()) { + final Tag.BasicType type = entry.getKey(); + final String registry = type.getIdentifier(); + List tags = new ArrayList<>(); + for (Tag tag : entry.getValue()) { + final String identifier = tag.getName().asString(); + final int[] values = tag.getValues().stream().mapToInt(value -> type.getFunction().apply(value.asString())).toArray(); + tags.add(new TagsPacket.Tag(identifier, values)); + } + registries.add(new TagsPacket.Registry(registry, tags)); + } + return new TagsPacket(registries); + } + private Set getValues(Map> main, String value) { Map tagObject = main.get(value); final List tagValues = (List) tagObject.get("values"); diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index b72cdca05..50ef4c9d2 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -12,6 +12,7 @@ import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.heightmap.Heightmap; import net.minestom.server.instance.heightmap.MotionBlockingHeightmap; import net.minestom.server.instance.heightmap.WorldSurfaceHeightmap; +import net.minestom.server.instance.palette.Palette; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.SendablePacket; @@ -35,6 +36,7 @@ import org.slf4j.LoggerFactory; import java.util.*; +import static net.minestom.server.network.NetworkBuffer.SHORT; import static net.minestom.server.utils.chunk.ChunkUtils.toSectionRelativeCoordinate; /** @@ -260,7 +262,11 @@ public class DynamicChunk extends Chunk { heightmapsNBT = getHeightmapNBT(); data = NetworkBuffer.makeArray(networkBuffer -> { - for (Section section : sections) networkBuffer.write(section); + for (Section section : sections) { + networkBuffer.write(SHORT, (short) section.blockPalette().count()); + networkBuffer.write(Palette.BLOCK_SERIALIZER, section.blockPalette()); + networkBuffer.write(Palette.BIOME_SERIALIZER, section.biomePalette()); + } }); } diff --git a/src/main/java/net/minestom/server/instance/Explosion.java b/src/main/java/net/minestom/server/instance/Explosion.java index 186be7a1d..20dc8abd7 100644 --- a/src/main/java/net/minestom/server/instance/Explosion.java +++ b/src/main/java/net/minestom/server/instance/Explosion.java @@ -3,7 +3,7 @@ package net.minestom.server.instance; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.packet.server.play.ExplosionPacket; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -73,7 +73,7 @@ public abstract class Explosion { ExplosionPacket packet = new ExplosionPacket(centerX, centerY, centerZ, strength, records, 0, 0, 0); postExplosion(instance, blocks, packet); - PacketUtils.sendGroupedPacket(instance.getPlayers(), packet); + PacketSendingUtils.sendGroupedPacket(instance.getPlayers(), packet); postSend(instance, blocks); } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index bccaada7e..b5b28d3cc 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -41,7 +41,7 @@ import net.minestom.server.timer.Schedulable; import net.minestom.server.timer.Scheduler; import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.NamespaceID; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.chunk.ChunkCache; import net.minestom.server.utils.chunk.ChunkSupplier; import net.minestom.server.utils.chunk.ChunkUtils; @@ -472,7 +472,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, */ public void setTime(long time) { this.time = time; - PacketUtils.sendGroupedPacket(getPlayers(), createTimePacket()); + PacketSendingUtils.sendGroupedPacket(getPlayers(), createTimePacket()); } /** @@ -774,7 +774,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, this.time += timeRate; // time needs to be sent to players if (timeSynchronizationTicks > 0 && this.worldAge % timeSynchronizationTicks == 0) { - PacketUtils.sendGroupedPacket(getPlayers(), createTimePacket()); + PacketSendingUtils.sendGroupedPacket(getPlayers(), createTimePacket()); } } diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index ea28b8b2a..cac12b2b2 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -26,7 +26,7 @@ import net.minestom.server.network.packet.server.play.EffectPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.NamespaceID; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.chunk.ChunkCache; @@ -240,7 +240,7 @@ public class InstanceContainer extends Instance { UNSAFE_setBlock(chunk, x, y, z, resultBlock, null, new BlockHandler.PlayerDestroy(block, this, blockPosition, player), doBlockUpdates, 0); // Send the block break effect packet - PacketUtils.sendGroupedPacket(chunk.getViewers(), + PacketSendingUtils.sendGroupedPacket(chunk.getViewers(), new EffectPacket(2001 /*Block break + block break sound*/, blockPosition, block.stateId(), false), // Prevent the block breaker to play the particles and sound two times (viewer) -> !viewer.equals(player)); diff --git a/src/main/java/net/minestom/server/instance/Section.java b/src/main/java/net/minestom/server/instance/Section.java index da48e9eb1..70d70d5b5 100644 --- a/src/main/java/net/minestom/server/instance/Section.java +++ b/src/main/java/net/minestom/server/instance/Section.java @@ -2,16 +2,14 @@ package net.minestom.server.instance; import net.minestom.server.instance.light.Light; import net.minestom.server.instance.palette.Palette; -import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import static net.minestom.server.instance.light.LightCompute.CONTENT_FULLY_LIT; import static net.minestom.server.instance.light.LightCompute.EMPTY_CONTENT; -import static net.minestom.server.network.NetworkBuffer.SHORT; -public final class Section implements NetworkBuffer.Writer { +public final class Section { private final Palette blockPalette; private final Palette biomePalette; private final Light skyLight; @@ -56,13 +54,6 @@ public final class Section implements NetworkBuffer.Writer { return new Section(this.blockPalette.clone(), this.biomePalette.clone(), skyLight, blockLight); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(SHORT, (short) blockPalette.count()); - writer.write(blockPalette); - writer.write(biomePalette); - } - public void setSkyLight(byte[] copyArray) { if (copyArray == null || copyArray.length == 0) this.skyLight.set(EMPTY_CONTENT); else if (Arrays.equals(copyArray, EMPTY_CONTENT)) this.skyLight.set(EMPTY_CONTENT); diff --git a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java index 44990bce2..c4790e64e 100644 --- a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java +++ b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java @@ -9,8 +9,8 @@ import net.minestom.server.instance.Instance; import net.minestom.server.instance.Section; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockHandler; +import net.minestom.server.instance.palette.Palettes; import net.minestom.server.registry.DynamicRegistry; -import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.async.AsyncUtils; @@ -196,7 +196,7 @@ public class AnvilLoader implements IChunkLoader { int bitsPerEntry = packedIndices.length * 64 / biomeIndices.length; if (bitsPerEntry > 3) bitsPerEntry = MathUtils.bitsToRepresent(convertedBiomePalette.length); - ArrayUtils.unpack(biomeIndices, packedIndices, bitsPerEntry); + Palettes.unpack(biomeIndices, packedIndices, bitsPerEntry); section.biomePalette().setAll((x, y, z) -> { final int index = x + z * 4 + y * 16; @@ -216,7 +216,7 @@ public class AnvilLoader implements IChunkLoader { final long[] packedStates = blockStatesTag.getLongArray("data"); Check.stateCondition(packedStates.length == 0, "Missing packed states data"); int[] blockStateIndices = new int[Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE]; - ArrayUtils.unpack(blockStateIndices, packedStates, packedStates.length * 64 / blockStateIndices.length); + Palettes.unpack(blockStateIndices, packedStates, packedStates.length * 64 / blockStateIndices.length); for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) { @@ -465,7 +465,7 @@ public class AnvilLoader implements IChunkLoader { if (blockPaletteEntries.size() > 1) { // If there is only one entry we do not need to write the packed indices var bitsPerEntry = (int) Math.max(4, Math.ceil(Math.log(blockPaletteEntries.size()) / Math.log(2))); - blockStates.putLongArray("data", ArrayUtils.pack(blockIndices, bitsPerEntry)); + blockStates.putLongArray("data", Palettes.pack(blockIndices, bitsPerEntry)); } sectionData.put("block_states", blockStates.build()); @@ -474,7 +474,7 @@ public class AnvilLoader implements IChunkLoader { if (biomePalette.size() > 1) { // If there is only one entry we do not need to write the packed indices var bitsPerEntry = (int) Math.max(1, Math.ceil(Math.log(biomePalette.size()) / Math.log(2))); - biomes.putLongArray("data", ArrayUtils.pack(biomeIndices, bitsPerEntry)); + biomes.putLongArray("data", Palettes.pack(biomeIndices, bitsPerEntry)); } sectionData.put("biomes", biomes.build()); diff --git a/src/main/java/net/minestom/server/instance/block/Block.java b/src/main/java/net/minestom/server/instance/block/Block.java index 5fe94a823..e6096189e 100644 --- a/src/main/java/net/minestom/server/instance/block/Block.java +++ b/src/main/java/net/minestom/server/instance/block/Block.java @@ -27,7 +27,7 @@ import java.util.function.BiPredicate; public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks permits BlockImpl { @NotNull - NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.map(Block::fromStateId, Block::stateId); + NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(Block::fromStateId, Block::stateId); /** * Creates a new block with the the property {@code property} sets to {@code value}. diff --git a/src/main/java/net/minestom/server/instance/block/predicate/BlockPredicate.java b/src/main/java/net/minestom/server/instance/block/predicate/BlockPredicate.java index 850e53cb3..cfe1cf65a 100644 --- a/src/main/java/net/minestom/server/instance/block/predicate/BlockPredicate.java +++ b/src/main/java/net/minestom/server/instance/block/predicate/BlockPredicate.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -14,6 +15,8 @@ import java.util.Map; import java.util.Objects; import java.util.function.Predicate; +import static net.minestom.server.network.NetworkBuffer.NBT_COMPOUND; + /** *

A predicate to filter blocks based on their name, properties, and/or nbt.

* @@ -25,8 +28,8 @@ import java.util.function.Predicate; * is used for matching adventure mode blocks and must line up with client prediction.

* * @param blocks The block names/tags to match. - * @param state The block properties to match. - * @param nbt The block nbt to match. + * @param state The block properties to match. + * @param nbt The block nbt to match. */ public record BlockPredicate( @Nullable BlockTypeFilter blocks, @@ -44,23 +47,13 @@ public record BlockPredicate( */ public static final BlockPredicate NONE = new BlockPredicate(null, new PropertiesPredicate(Map.of("no_such_property", new PropertiesPredicate.ValuePredicate.Exact("never"))), null); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, BlockPredicate value) { - buffer.writeOptional(BlockTypeFilter.NETWORK_TYPE, value.blocks); - buffer.writeOptional(PropertiesPredicate.NETWORK_TYPE, value.state); - buffer.writeOptional(NetworkBuffer.NBT, value.nbt); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + BlockTypeFilter.NETWORK_TYPE.optional(), BlockPredicate::blocks, + PropertiesPredicate.NETWORK_TYPE.optional(), BlockPredicate::state, + NBT_COMPOUND.optional(), BlockPredicate::nbt, + BlockPredicate::new + ); - @Override - public BlockPredicate read(@NotNull NetworkBuffer buffer) { - return new BlockPredicate( - buffer.readOptional(BlockTypeFilter.NETWORK_TYPE), - buffer.readOptional(PropertiesPredicate.NETWORK_TYPE), - (CompoundBinaryTag) buffer.readOptional(NetworkBuffer.NBT) - ); - } - }; public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override public @NotNull BinaryTag write(@NotNull BlockPredicate value) { @@ -116,5 +109,4 @@ public record BlockPredicate( return false; return nbt == null || Objects.equals(nbt, BlockUtils.extractClientNbt(block)); } - } diff --git a/src/main/java/net/minestom/server/instance/block/predicate/PropertiesPredicate.java b/src/main/java/net/minestom/server/instance/block/predicate/PropertiesPredicate.java index 32210ef76..7eba17e7d 100644 --- a/src/main/java/net/minestom/server/instance/block/predicate/PropertiesPredicate.java +++ b/src/main/java/net/minestom/server/instance/block/predicate/PropertiesPredicate.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.StringBinaryTag; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -13,28 +14,14 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; +import static net.minestom.server.network.NetworkBuffer.STRING; + public record PropertiesPredicate(@NotNull Map properties) implements Predicate { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, PropertiesPredicate value) { - buffer.write(NetworkBuffer.VAR_INT, value.properties.size()); - for (Map.Entry entry : value.properties.entrySet()) { - buffer.write(NetworkBuffer.STRING, entry.getKey()); - buffer.write(ValuePredicate.NETWORK_TYPE, entry.getValue()); - } - } - - @Override - public PropertiesPredicate read(@NotNull NetworkBuffer buffer) { - int size = buffer.read(NetworkBuffer.VAR_INT); - Map properties = new HashMap<>(size); - for (int i = 0; i < size; i++) { - properties.put(buffer.read(NetworkBuffer.STRING), buffer.read(ValuePredicate.NETWORK_TYPE)); - } - return new PropertiesPredicate(properties); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.STRING.mapValue(ValuePredicate.NETWORK_TYPE), PropertiesPredicate::properties, + PropertiesPredicate::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> { Map properties = new HashMap<>(); @@ -74,7 +61,7 @@ public record PropertiesPredicate(@NotNull Map propertie record Exact(@Nullable String value) implements ValuePredicate { - public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.STRING.map(Exact::new, Exact::value); + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.STRING.transform(Exact::new, Exact::value); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.STRING.map(Exact::new, Exact::value); @Override @@ -94,19 +81,12 @@ public record PropertiesPredicate(@NotNull Map propertie * @param max The max value to match, exclusive */ record Range(@Nullable String min, @Nullable String max) implements ValuePredicate { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + STRING.optional(), Range::min, + STRING.optional(), Range::max, + Range::new + ); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Range value) { - buffer.writeOptional(NetworkBuffer.STRING, value.min); - buffer.writeOptional(NetworkBuffer.STRING, value.max); - } - - @Override - public Range read(@NotNull NetworkBuffer buffer) { - return new Range(buffer.readOptional(NetworkBuffer.STRING), buffer.readOptional(NetworkBuffer.STRING)); - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Range( tag.get("min") instanceof StringBinaryTag string ? string.value() : null, diff --git a/src/main/java/net/minestom/server/instance/palette/AdaptivePalette.java b/src/main/java/net/minestom/server/instance/palette/AdaptivePalette.java index d64930f9a..9d07b5ae9 100644 --- a/src/main/java/net/minestom/server/instance/palette/AdaptivePalette.java +++ b/src/main/java/net/minestom/server/instance/palette/AdaptivePalette.java @@ -2,7 +2,6 @@ package net.minestom.server.instance.palette; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.MathUtils; import org.jetbrains.annotations.NotNull; @@ -20,7 +19,7 @@ final class AdaptivePalette implements Palette, Cloneable { this.dimension = dimension; this.maxBitsPerEntry = maxBitsPerEntry; this.defaultBitsPerEntry = bitsPerEntry; - this.palette = new FilledPalette(dimension, 0); + this.palette = new PaletteSingle(dimension, 0); } @Override @@ -51,12 +50,12 @@ final class AdaptivePalette implements Palette, Cloneable { @Override public void fill(int value) { - this.palette = new FilledPalette(dimension, value); + this.palette = new PaletteSingle(dimension, value); } @Override public void setAll(@NotNull EntrySupplier supplier) { - SpecializedPalette newPalette = new FlexiblePalette(this); + SpecializedPalette newPalette = new PaletteIndirect(this); newPalette.setAll(supplier); this.palette = newPalette; } @@ -105,31 +104,24 @@ final class AdaptivePalette implements Palette, Cloneable { } } - @Override - public void write(@NotNull NetworkBuffer writer) { - final SpecializedPalette optimized = optimizedPalette(); - this.palette = optimized; - optimized.write(writer); - } - SpecializedPalette optimizedPalette() { var currentPalette = this.palette; - if (currentPalette instanceof FlexiblePalette flexiblePalette) { - final int count = flexiblePalette.count(); + if (currentPalette instanceof PaletteIndirect paletteIndirect) { + final int count = paletteIndirect.count(); if (count == 0) { - return new FilledPalette(dimension, 0); + return new PaletteSingle(dimension, 0); } else { // Find all entries and compress the palette - IntSet entries = new IntOpenHashSet(flexiblePalette.paletteToValueList.size()); - flexiblePalette.getAll((x, y, z, value) -> entries.add(value)); - final int currentBitsPerEntry = flexiblePalette.bitsPerEntry(); + IntSet entries = new IntOpenHashSet(paletteIndirect.paletteToValueList.size()); + paletteIndirect.getAll((x, y, z, value) -> entries.add(value)); + final int currentBitsPerEntry = paletteIndirect.bitsPerEntry(); final int bitsPerEntry; if (entries.size() == 1) { - return new FilledPalette(dimension, entries.iterator().nextInt()); + return new PaletteSingle(dimension, entries.iterator().nextInt()); } else if (currentBitsPerEntry > defaultBitsPerEntry && (bitsPerEntry = MathUtils.bitsToRepresent(entries.size() - 1)) < currentBitsPerEntry) { - flexiblePalette.resize((byte) bitsPerEntry); - return flexiblePalette; + paletteIndirect.resize((byte) bitsPerEntry); + return paletteIndirect; } } } @@ -138,9 +130,9 @@ final class AdaptivePalette implements Palette, Cloneable { Palette flexiblePalette() { SpecializedPalette currentPalette = this.palette; - if (currentPalette instanceof FilledPalette filledPalette) { - currentPalette = new FlexiblePalette(this); - currentPalette.fill(filledPalette.value()); + if (currentPalette instanceof PaletteSingle paletteSingle) { + currentPalette = new PaletteIndirect(this); + currentPalette.fill(paletteSingle.value()); this.palette = currentPalette; } return currentPalette; diff --git a/src/main/java/net/minestom/server/instance/palette/Palette.java b/src/main/java/net/minestom/server/instance/palette/Palette.java index 93a14b9b3..755d8c309 100644 --- a/src/main/java/net/minestom/server/instance/palette/Palette.java +++ b/src/main/java/net/minestom/server/instance/palette/Palette.java @@ -5,12 +5,14 @@ import org.jetbrains.annotations.NotNull; import java.util.function.IntUnaryOperator; +import static net.minestom.server.network.NetworkBuffer.*; + /** * Represents a palette used to store blocks and biomes. *

* 0 is the default value. */ -public interface Palette extends NetworkBuffer.Writer { +public interface Palette { static Palette blocks() { return newPalette(16, 8, 4); } @@ -77,4 +79,58 @@ public interface Palette extends NetworkBuffer.Writer { interface EntryFunction { int apply(int x, int y, int z, int value); } + + NetworkBuffer.Type BLOCK_SERIALIZER = serializer(16, 4, 8); + NetworkBuffer.Type BIOME_SERIALIZER = serializer(4, 1, 3); + + static NetworkBuffer.Type serializer(int dimension, int minIndirect, int maxIndirect) { + return new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, Palette value) { + switch (value) { + case AdaptivePalette adaptive -> { + final SpecializedPalette optimized = adaptive.optimizedPalette(); + adaptive.palette = optimized; + BLOCK_SERIALIZER.write(buffer, optimized); + } + case PaletteSingle single -> { + buffer.write(BYTE, (byte) 0); + buffer.write(VAR_INT, single.value()); + buffer.write(VAR_INT, 0); + } + case PaletteIndirect indirect -> { + buffer.write(BYTE, (byte) value.bitsPerEntry()); + if (indirect.bitsPerEntry() <= indirect.maxBitsPerEntry()) { // Palette index + buffer.write(VAR_INT.list(), indirect.paletteToValueList); + } + buffer.write(LONG_ARRAY, indirect.values); + } + default -> throw new UnsupportedOperationException("Unsupported palette type: " + value.getClass()); + } + } + + @Override + public Palette read(@NotNull NetworkBuffer buffer) { + final byte bitsPerEntry = buffer.read(BYTE); + if (bitsPerEntry == 0) { + // Single valued 0-0 + final int value = buffer.read(VAR_INT); + return new PaletteSingle((byte) dimension, value); + } else if (bitsPerEntry >= minIndirect && bitsPerEntry <= maxIndirect) { + // Indirect palette + final int[] palette = buffer.read(VAR_INT_ARRAY); + final long[] data = buffer.read(LONG_ARRAY); + return new PaletteIndirect(dimension, maxIndirect, bitsPerEntry, + Palettes.count(bitsPerEntry, data), + palette, data); + } else { + // Direct palette + final long[] data = buffer.read(LONG_ARRAY); + return new PaletteIndirect(dimension, maxIndirect, bitsPerEntry, + Palettes.count(bitsPerEntry, data), + new int[0], data); + } + } + }; + } } diff --git a/src/main/java/net/minestom/server/instance/palette/FlexiblePalette.java b/src/main/java/net/minestom/server/instance/palette/PaletteIndirect.java similarity index 73% rename from src/main/java/net/minestom/server/instance/palette/FlexiblePalette.java rename to src/main/java/net/minestom/server/instance/palette/PaletteIndirect.java index 89e07e9f0..3cd3aa2e2 100644 --- a/src/main/java/net/minestom/server/instance/palette/FlexiblePalette.java +++ b/src/main/java/net/minestom/server/instance/palette/PaletteIndirect.java @@ -3,7 +3,6 @@ package net.minestom.server.instance.palette; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import net.minestom.server.MinecraftServer; -import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.MathUtils; import org.jetbrains.annotations.NotNull; @@ -11,52 +10,64 @@ import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntUnaryOperator; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.instance.palette.Palettes.arrayLength; +import static net.minestom.server.instance.palette.Palettes.read; /** * Palette able to take any value anywhere. May consume more memory than required. */ -final class FlexiblePalette implements SpecializedPalette, Cloneable { +final class PaletteIndirect implements SpecializedPalette, Cloneable { private static final ThreadLocal WRITE_CACHE = ThreadLocal.withInitial(() -> new int[4096]); // Specific to this palette type - private final AdaptivePalette adaptivePalette; + private final int dimension; + private final int maxBitsPerEntry; + private byte bitsPerEntry; private int count; - private long[] values; + long[] values; // palette index = value IntArrayList paletteToValueList; // value = palette index private Int2IntOpenHashMap valueToPaletteMap; - FlexiblePalette(AdaptivePalette adaptivePalette, byte bitsPerEntry) { - this.adaptivePalette = adaptivePalette; - + PaletteIndirect(int dimension, int maxBitsPerEntry, byte bitsPerEntry, + int count, int[] palette, long[] values) { + this.dimension = dimension; + this.maxBitsPerEntry = maxBitsPerEntry; this.bitsPerEntry = bitsPerEntry; - this.paletteToValueList = new IntArrayList(1); - this.paletteToValueList.add(0); - this.valueToPaletteMap = new Int2IntOpenHashMap(1); - this.valueToPaletteMap.put(0, 0); + this.count = count; + this.values = values; + + this.paletteToValueList = new IntArrayList(palette.length); + this.valueToPaletteMap = new Int2IntOpenHashMap(palette.length); this.valueToPaletteMap.defaultReturnValue(-1); - final int valuesPerLong = 64 / bitsPerEntry; - this.values = new long[(maxSize() + valuesPerLong - 1) / valuesPerLong]; + for (int i = 0; i < palette.length; i++) { + this.paletteToValueList.add(palette[i]); + this.valueToPaletteMap.put(palette[i], i); + } + + this.values = new long[arrayLength(dimension(), bitsPerEntry)]; } - FlexiblePalette(AdaptivePalette adaptivePalette) { - this(adaptivePalette, adaptivePalette.defaultBitsPerEntry); + PaletteIndirect(int dimension, int maxBitsPerEntry, byte bitsPerEntry) { + this(dimension, maxBitsPerEntry, bitsPerEntry, + 0, + new int[]{0}, + new long[arrayLength(dimension, bitsPerEntry)] + ); + } + + PaletteIndirect(AdaptivePalette palette) { + this(palette.dimension, palette.maxBitsPerEntry, palette.defaultBitsPerEntry); } @Override public int get(int x, int y, int z) { - final int bitsPerEntry = this.bitsPerEntry; - final int sectionIndex = getSectionIndex(dimension(), x, y, z); - final int valuesPerLong = 64 / bitsPerEntry; - final int index = sectionIndex / valuesPerLong; - final int bitIndex = (sectionIndex - index * valuesPerLong) * bitsPerEntry; - final int value = (int) (values[index] >> bitIndex) & ((1 << bitsPerEntry) - 1); + final int value = read(dimension(), bitsPerEntry, values, x, y, z); // Change to palette value and return return hasPalette() ? paletteToValueList.getInt(value) : value; } @@ -74,20 +85,9 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { @Override public void set(int x, int y, int z, int value) { value = getPaletteIndex(value); - final int bitsPerEntry = this.bitsPerEntry; - final long[] values = this.values; - // Change to palette value - final int valuesPerLong = 64 / bitsPerEntry; - final int sectionIndex = getSectionIndex(dimension(), x, y, z); - final int index = sectionIndex / valuesPerLong; - final int bitIndex = (sectionIndex - index * valuesPerLong) * bitsPerEntry; - - final long block = values[index]; - final long clear = (1L << bitsPerEntry) - 1L; - final long oldBlock = block >> bitIndex & clear; - values[index] = block & ~(clear << bitIndex) | ((long) value << bitIndex); + final int oldValue = Palettes.write(dimension(), bitsPerEntry, values, x, y, z, value); // Check if block count needs to be updated - final boolean currentAir = oldBlock == 0; + final boolean currentAir = oldValue == 0; if (currentAir != (value == 0)) this.count += currentAir ? 1 : -1; } @@ -99,13 +99,7 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { return; } value = getPaletteIndex(value); - final int bitsPerEntry = this.bitsPerEntry; - final int valuesPerLong = 64 / bitsPerEntry; - final long[] values = this.values; - long block = 0; - for (int i = 0; i < valuesPerLong; i++) - block |= (long) value << i * bitsPerEntry; - Arrays.fill(values, block); + Palettes.fill(bitsPerEntry, values, value); this.count = maxSize(); } @@ -185,18 +179,18 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { @Override public int maxBitsPerEntry() { - return adaptivePalette.maxBitsPerEntry(); + return maxBitsPerEntry; } @Override public int dimension() { - return adaptivePalette.dimension(); + return dimension; } @Override public @NotNull SpecializedPalette clone() { try { - FlexiblePalette palette = (FlexiblePalette) super.clone(); + PaletteIndirect palette = (PaletteIndirect) super.clone(); palette.values = values != null ? values.clone() : null; palette.paletteToValueList = paletteToValueList.clone(); palette.valueToPaletteMap = valueToPaletteMap.clone(); @@ -208,15 +202,6 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { } } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, bitsPerEntry); - if (bitsPerEntry <= maxBitsPerEntry()) { // Palette index - writer.writeCollection(VAR_INT, paletteToValueList); - } - writer.write(LONG_ARRAY, values); - } - private void retrieveAll(@NotNull EntryConsumer consumer, boolean consumeEmpty) { if (!consumeEmpty && count == 0) return; final long[] values = this.values; @@ -268,7 +253,7 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { void resize(byte newBitsPerEntry) { newBitsPerEntry = newBitsPerEntry > maxBitsPerEntry() ? 15 : newBitsPerEntry; - FlexiblePalette palette = new FlexiblePalette(adaptivePalette, newBitsPerEntry); + PaletteIndirect palette = new PaletteIndirect(dimension, maxBitsPerEntry, newBitsPerEntry); palette.paletteToValueList = paletteToValueList; palette.valueToPaletteMap = valueToPaletteMap; getAll(palette::set); @@ -297,14 +282,6 @@ final class FlexiblePalette implements SpecializedPalette, Cloneable { return bitsPerEntry <= maxBitsPerEntry(); } - static int getSectionIndex(int dimension, int x, int y, int z) { - final int dimensionMask = dimension - 1; - final int dimensionBitCount = MathUtils.bitsToRepresent(dimensionMask); - return (y & dimensionMask) << (dimensionBitCount << 1) | - (z & dimensionMask) << dimensionBitCount | - (x & dimensionMask); - } - static int maxPaletteSize(int bitsPerEntry) { return 1 << bitsPerEntry; } diff --git a/src/main/java/net/minestom/server/instance/palette/FilledPalette.java b/src/main/java/net/minestom/server/instance/palette/PaletteSingle.java similarity index 70% rename from src/main/java/net/minestom/server/instance/palette/FilledPalette.java rename to src/main/java/net/minestom/server/instance/palette/PaletteSingle.java index 669d098f6..83fb1ab35 100644 --- a/src/main/java/net/minestom/server/instance/palette/FilledPalette.java +++ b/src/main/java/net/minestom/server/instance/palette/PaletteSingle.java @@ -1,15 +1,11 @@ package net.minestom.server.instance.palette; -import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.BYTE; -import static net.minestom.server.network.NetworkBuffer.VAR_INT; - /** * Palette containing a single value. Useful for both empty and full palettes. */ -record FilledPalette(byte dim, int value) implements SpecializedPalette.Immutable { +record PaletteSingle(byte dim, int value) implements SpecializedPalette.Immutable { @Override public int get(int x, int y, int z) { return value; @@ -44,11 +40,4 @@ record FilledPalette(byte dim, int value) implements SpecializedPalette.Immutabl public @NotNull SpecializedPalette clone() { return this; } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, (byte) 0); - writer.write(VAR_INT, value); - writer.write(VAR_INT, 0); - } } diff --git a/src/main/java/net/minestom/server/instance/palette/Palettes.java b/src/main/java/net/minestom/server/instance/palette/Palettes.java new file mode 100644 index 000000000..7adb5317b --- /dev/null +++ b/src/main/java/net/minestom/server/instance/palette/Palettes.java @@ -0,0 +1,98 @@ +package net.minestom.server.instance.palette; + +import net.minestom.server.utils.MathUtils; + +import java.util.Arrays; + +public final class Palettes { + private Palettes() { + } + + public static long[] pack(int[] ints, int bitsPerEntry) { + final int intsPerLong = (int) Math.floor(64d / bitsPerEntry); + long[] longs = new long[(int) Math.ceil(ints.length / (double) intsPerLong)]; + + final long mask = (1L << bitsPerEntry) - 1L; + for (int i = 0; i < longs.length; i++) { + for (int intIndex = 0; intIndex < intsPerLong; intIndex++) { + final int bitIndex = intIndex * bitsPerEntry; + final int intActualIndex = intIndex + i * intsPerLong; + if (intActualIndex < ints.length) { + longs[i] |= (ints[intActualIndex] & mask) << bitIndex; + } + } + } + + return longs; + } + + public static void unpack(int[] out, long[] in, int bitsPerEntry) { + assert in.length != 0 : "unpack input array is zero"; + + final double intsPerLong = Math.floor(64d / bitsPerEntry); + final int intsPerLongCeil = (int) Math.ceil(intsPerLong); + + long mask = (1L << bitsPerEntry) - 1L; + for (int i = 0; i < out.length; i++) { + final int longIndex = i / intsPerLongCeil; + final int subIndex = i % intsPerLongCeil; + + out[i] = (int) ((in[longIndex] >>> (bitsPerEntry * subIndex)) & mask); + } + } + + public static int arrayLength(int dimension, int bitsPerEntry) { + final int elementCount = dimension * dimension * dimension; + final int valuesPerLong = 64 / bitsPerEntry; + return (elementCount + valuesPerLong - 1) / valuesPerLong; + } + + public static int read(int dimension, int bitsPerEntry, long[] values, + int x, int y, int z) { + final int sectionIndex = sectionIndex(dimension, x, y, z); + final int valuesPerLong = 64 / bitsPerEntry; + final int index = sectionIndex / valuesPerLong; + final int bitIndex = (sectionIndex - index * valuesPerLong) * bitsPerEntry; + return (int) (values[index] >> bitIndex) & ((1 << bitsPerEntry) - 1); + } + + public static int write(int dimension, int bitsPerEntry, long[] values, + int x, int y, int z, int value) { + final int valuesPerLong = 64 / bitsPerEntry; + final int sectionIndex = sectionIndex(dimension, x, y, z); + final int index = sectionIndex / valuesPerLong; + final int bitIndex = (sectionIndex - index * valuesPerLong) * bitsPerEntry; + + final long block = values[index]; + final long clear = (1L << bitsPerEntry) - 1L; + final long oldBlock = block >> bitIndex & clear; + values[index] = block & ~(clear << bitIndex) | ((long) value << bitIndex); + return (int) oldBlock; + } + + public static void fill(int bitsPerEntry, long[] values, int value) { + final int valuesPerLong = 64 / bitsPerEntry; + long block = 0; + for (int i = 0; i < valuesPerLong; i++) block |= (long) value << i * bitsPerEntry; + Arrays.fill(values, block); + } + + public static int count(int bitsPerEntry, long[] values) { + final int valuesPerLong = 64 / bitsPerEntry; + int count = 0; + for (long block : values) { + for (int i = 0; i < valuesPerLong; i++) { + count += (block >>> i * bitsPerEntry) & ((1 << bitsPerEntry) - 1); + } + } + return count; + } + + public static int sectionIndex(int dimension, int x, int y, int z) { + final int dimensionMask = dimension - 1; + final int dimensionBitCount = MathUtils.bitsToRepresent(dimensionMask); + return (y & dimensionMask) << (dimensionBitCount << 1) | + (z & dimensionMask) << dimensionBitCount | + (x & dimensionMask); + } +} diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 9a6a61ac2..cef26be3e 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -58,7 +58,7 @@ public sealed interface ItemStack extends TagReadable, DataComponent.Holder, Hov return ItemStackImpl.create(material, amount, components); } }; - @NotNull NetworkBuffer.Type STRICT_NETWORK_TYPE = NETWORK_TYPE.map(itemStack -> { + @NotNull NetworkBuffer.Type STRICT_NETWORK_TYPE = NETWORK_TYPE.transform(itemStack -> { Check.argCondition(itemStack.amount() == 0 || itemStack.isAir(), "ItemStack cannot be empty"); return itemStack; }, itemStack -> { diff --git a/src/main/java/net/minestom/server/item/Material.java b/src/main/java/net/minestom/server/item/Material.java index 98fe2c878..8ff861086 100644 --- a/src/main/java/net/minestom/server/item/Material.java +++ b/src/main/java/net/minestom/server/item/Material.java @@ -16,7 +16,7 @@ import java.util.Collection; public sealed interface Material extends StaticProtocolObject, Materials permits MaterialImpl { - NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.map(MaterialImpl::getId, Material::id); + NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(MaterialImpl::getId, Material::id); BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.STRING.map(MaterialImpl::getSafe, Material::name); /** diff --git a/src/main/java/net/minestom/server/item/book/FilteredText.java b/src/main/java/net/minestom/server/item/book/FilteredText.java index 38c0ad757..384872c2f 100644 --- a/src/main/java/net/minestom/server/item/book/FilteredText.java +++ b/src/main/java/net/minestom/server/item/book/FilteredText.java @@ -21,12 +21,12 @@ public record FilteredText(@NotNull T text, @Nullable T filtered) { @Override public void write(@NotNull NetworkBuffer buffer, FilteredText value) { buffer.write(inner, value.text); - buffer.writeOptional(inner, value.filtered); + buffer.write(inner.optional(), value.filtered); } @Override public FilteredText read(@NotNull NetworkBuffer buffer) { - return new FilteredText<>(buffer.read(inner), buffer.readOptional(inner)); + return new FilteredText<>(buffer.read(inner), buffer.read(inner.optional())); } }; } diff --git a/src/main/java/net/minestom/server/item/component/ArmorTrim.java b/src/main/java/net/minestom/server/item/component/ArmorTrim.java index 2c67444e2..6bbd3697c 100644 --- a/src/main/java/net/minestom/server/item/component/ArmorTrim.java +++ b/src/main/java/net/minestom/server/item/component/ArmorTrim.java @@ -4,27 +4,20 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.item.armor.TrimMaterial; import net.minestom.server.item.armor.TrimPattern; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; -public record ArmorTrim(@NotNull DynamicRegistry.Key material, @NotNull DynamicRegistry.Key pattern, boolean showInTooltip) { +public record ArmorTrim(@NotNull DynamicRegistry.Key material, + @NotNull DynamicRegistry.Key pattern, boolean showInTooltip) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ArmorTrim value) { - buffer.write(TrimMaterial.NETWORK_TYPE, value.material); - buffer.write(TrimPattern.NETWORK_TYPE, value.pattern); - buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip); - } - - @Override - public ArmorTrim read(@NotNull NetworkBuffer buffer) { - return new ArmorTrim(buffer.read(TrimMaterial.NETWORK_TYPE), - buffer.read(TrimPattern.NETWORK_TYPE), - buffer.read(NetworkBuffer.BOOLEAN)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + TrimMaterial.NETWORK_TYPE, ArmorTrim::material, + TrimPattern.NETWORK_TYPE, ArmorTrim::pattern, + NetworkBuffer.BOOLEAN, ArmorTrim::showInTooltip, + ArmorTrim::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> { @@ -43,5 +36,4 @@ public record ArmorTrim(@NotNull DynamicRegistry.Key material, @No public @NotNull ArmorTrim withTooltip(boolean showInTooltip) { return new ArmorTrim(material, pattern, showInTooltip); } - } diff --git a/src/main/java/net/minestom/server/item/component/AttributeList.java b/src/main/java/net/minestom/server/item/component/AttributeList.java index 7af57caec..c2dae4386 100644 --- a/src/main/java/net/minestom/server/item/component/AttributeList.java +++ b/src/main/java/net/minestom/server/item/component/AttributeList.java @@ -8,28 +8,23 @@ import net.minestom.server.entity.EquipmentSlotGroup; import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.attribute.AttributeModifier; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; + public record AttributeList(@NotNull List modifiers, boolean showInTooltip) { public static final AttributeList EMPTY = new AttributeList(List.of(), true); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, AttributeList value) { - buffer.writeCollection(Modifier.NETWORK_TYPE, value.modifiers); - buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip); - } - - @Override - public AttributeList read(@NotNull NetworkBuffer buffer) { - return new AttributeList(buffer.readCollection(Modifier.NETWORK_TYPE, Short.MAX_VALUE), - buffer.read(NetworkBuffer.BOOLEAN)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Modifier.NETWORK_TYPE.list(Short.MAX_VALUE), AttributeList::modifiers, + BOOLEAN, AttributeList::showInTooltip, + AttributeList::new + ); public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override @@ -57,22 +52,14 @@ public record AttributeList(@NotNull List modifiers, boolean showInToo } }; - public record Modifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier, @NotNull EquipmentSlotGroup slot) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Modifier value) { - buffer.write(Attribute.NETWORK_TYPE, value.attribute); - buffer.write(AttributeModifier.NETWORK_TYPE, value.modifier); - buffer.writeEnum(EquipmentSlotGroup.class, value.slot); - } - - @Override - public Modifier read(@NotNull NetworkBuffer buffer) { - return new Modifier(buffer.read(Attribute.NETWORK_TYPE), - buffer.read(AttributeModifier.NETWORK_TYPE), - buffer.readEnum(EquipmentSlotGroup.class)); - } - }; + public record Modifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier, + @NotNull EquipmentSlotGroup slot) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Attribute.NETWORK_TYPE, Modifier::attribute, + AttributeModifier.NETWORK_TYPE, Modifier::modifier, + NetworkBuffer.Enum(EquipmentSlotGroup.class), Modifier::slot, + Modifier::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Modifier( Attribute.NBT_TYPE.read(tag.get("type")), diff --git a/src/main/java/net/minestom/server/item/component/BannerPatterns.java b/src/main/java/net/minestom/server/item/component/BannerPatterns.java index d18ebc00f..1a1231572 100644 --- a/src/main/java/net/minestom/server/item/component/BannerPatterns.java +++ b/src/main/java/net/minestom/server/item/component/BannerPatterns.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.color.DyeColor; import net.minestom.server.instance.block.banner.BannerPattern; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -15,22 +16,15 @@ import java.util.List; public record BannerPatterns(@NotNull List layers) { public static final int MAX_LAYERS = 1024; - public static final NetworkBuffer.Type NETWORK_TYPE = Layer.NETWORK_TYPE.list(MAX_LAYERS).map(BannerPatterns::new, BannerPatterns::layers); + public static final NetworkBuffer.Type NETWORK_TYPE = Layer.NETWORK_TYPE.list(MAX_LAYERS).transform(BannerPatterns::new, BannerPatterns::layers); public static final BinaryTagSerializer NBT_TYPE = Layer.NBT_TYPE.list().map(BannerPatterns::new, BannerPatterns::layers); public record Layer(@NotNull DynamicRegistry.Key pattern, @NotNull DyeColor color) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Layer value) { - buffer.write(BannerPattern.NETWORK_TYPE, value.pattern); - buffer.write(DyeColor.NETWORK_TYPE, value.color); - } - - @Override - public Layer read(@NotNull NetworkBuffer buffer) { - return new Layer(buffer.read(BannerPattern.NETWORK_TYPE), buffer.read(DyeColor.NETWORK_TYPE)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + BannerPattern.NETWORK_TYPE, Layer::pattern, + DyeColor.NETWORK_TYPE, Layer::color, + Layer::new + ); public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer() { @Override public @NotNull BinaryTag write(@NotNull Context context, @NotNull Layer value) { diff --git a/src/main/java/net/minestom/server/item/component/Bee.java b/src/main/java/net/minestom/server/item/component/Bee.java index 944cc8bc9..c61680261 100644 --- a/src/main/java/net/minestom/server/item/component/Bee.java +++ b/src/main/java/net/minestom/server/item/component/Bee.java @@ -2,26 +2,18 @@ package net.minestom.server.item.component; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; public record Bee(@NotNull CustomData entityData, int ticksInHive, int minTicksInHive) { - public static @NotNull NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, Bee value) { - buffer.write(CustomData.NETWORK_TYPE, value.entityData); - buffer.write(NetworkBuffer.VAR_INT, value.ticksInHive); - buffer.write(NetworkBuffer.VAR_INT, value.minTicksInHive); - } - - @Override - public Bee read(@NotNull NetworkBuffer buffer) { - return new Bee(buffer.read(CustomData.NETWORK_TYPE), - buffer.read(NetworkBuffer.VAR_INT), - buffer.read(NetworkBuffer.VAR_INT)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + CustomData.NETWORK_TYPE, Bee::entityData, + NetworkBuffer.VAR_INT, Bee::ticksInHive, + NetworkBuffer.VAR_INT, Bee::minTicksInHive, + Bee::new + ); public static @NotNull BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Bee(CustomData.NBT_TYPE.read(tag.getCompound("entity_data")), tag.getInt("ticks_in_hive"), diff --git a/src/main/java/net/minestom/server/item/component/DyedItemColor.java b/src/main/java/net/minestom/server/item/component/DyedItemColor.java index 76b18771c..39d297516 100644 --- a/src/main/java/net/minestom/server/item/component/DyedItemColor.java +++ b/src/main/java/net/minestom/server/item/component/DyedItemColor.java @@ -6,24 +6,18 @@ import net.kyori.adventure.nbt.IntBinaryTag; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.Color; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; public record DyedItemColor(@NotNull RGBLike color, boolean showInTooltip) { public static DyedItemColor LEATHER = new DyedItemColor(new Color(-6265536), true); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, DyedItemColor value) { - buffer.write(Color.NETWORK_TYPE, value.color); - buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip); - } - - @Override - public DyedItemColor read(@NotNull NetworkBuffer buffer) { - return new DyedItemColor(buffer.read(Color.NETWORK_TYPE), buffer.read(NetworkBuffer.BOOLEAN)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Color.NETWORK_TYPE, DyedItemColor::color, + NetworkBuffer.BOOLEAN, DyedItemColor::showInTooltip, + DyedItemColor::new + ); public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override diff --git a/src/main/java/net/minestom/server/item/component/EnchantmentList.java b/src/main/java/net/minestom/server/item/component/EnchantmentList.java index 643d88bba..01c515940 100644 --- a/src/main/java/net/minestom/server/item/component/EnchantmentList.java +++ b/src/main/java/net/minestom/server/item/component/EnchantmentList.java @@ -4,9 +4,9 @@ import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.nbt.BinaryTagSerializer; -import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -18,30 +18,11 @@ public record EnchantmentList(@NotNull Map, Int boolean showInTooltip) { public static final EnchantmentList EMPTY = new EnchantmentList(Map.of(), true); - public static NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, @NotNull EnchantmentList value) { - buffer.write(NetworkBuffer.VAR_INT, value.enchantments.size()); - for (Map.Entry, Integer> entry : value.enchantments.entrySet()) { - buffer.write(Enchantment.NETWORK_TYPE, entry.getKey()); - buffer.write(NetworkBuffer.VAR_INT, entry.getValue()); - } - buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip); - } - - @Override - public @NotNull EnchantmentList read(@NotNull NetworkBuffer buffer) { - int size = buffer.read(NetworkBuffer.VAR_INT); - Check.argCondition(size < 0 || size > Short.MAX_VALUE, "Invalid enchantment list size: {0}", size); - Map, Integer> enchantments = new HashMap<>(size); - for (int i = 0; i < size; i++) { - DynamicRegistry.Key enchantment = buffer.read(Enchantment.NETWORK_TYPE); - enchantments.put(enchantment, buffer.read(NetworkBuffer.VAR_INT)); - } - boolean showInTooltip = buffer.read(NetworkBuffer.BOOLEAN); - return new EnchantmentList(enchantments, showInTooltip); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Enchantment.NETWORK_TYPE.mapValue(NetworkBuffer.VAR_INT, Short.MAX_VALUE), EnchantmentList::enchantments, + NetworkBuffer.BOOLEAN, EnchantmentList::showInTooltip, + EnchantmentList::new + ); public static BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override public @NotNull BinaryTag write(@NotNull Context context, @NotNull EnchantmentList value) { diff --git a/src/main/java/net/minestom/server/item/component/FireworkExplosion.java b/src/main/java/net/minestom/server/item/component/FireworkExplosion.java index 50c0131d7..81810a9c0 100644 --- a/src/main/java/net/minestom/server/item/component/FireworkExplosion.java +++ b/src/main/java/net/minestom/server/item/component/FireworkExplosion.java @@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.Color; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; + public record FireworkExplosion( @NotNull Shape shape, @NotNull List colors, @@ -27,27 +30,14 @@ public record FireworkExplosion( BURST } - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, FireworkExplosion value) { - buffer.writeEnum(Shape.class, value.shape); - buffer.writeCollection(Color.NETWORK_TYPE, value.colors); - buffer.writeCollection(Color.NETWORK_TYPE, value.fadeColors); - buffer.write(NetworkBuffer.BOOLEAN, value.hasTrail); - buffer.write(NetworkBuffer.BOOLEAN, value.hasTwinkle); - } - - @Override - public FireworkExplosion read(@NotNull NetworkBuffer buffer) { - return new FireworkExplosion( - buffer.readEnum(Shape.class), - buffer.readCollection(Color.NETWORK_TYPE, Short.MAX_VALUE), - buffer.readCollection(Color.NETWORK_TYPE, Short.MAX_VALUE), - buffer.read(NetworkBuffer.BOOLEAN), - buffer.read(NetworkBuffer.BOOLEAN) - ); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.Enum(Shape.class), FireworkExplosion::shape, + Color.NETWORK_TYPE.list(Short.MAX_VALUE), FireworkExplosion::colors, + Color.NETWORK_TYPE.list(Short.MAX_VALUE), FireworkExplosion::fadeColors, + BOOLEAN, FireworkExplosion::hasTrail, + BOOLEAN, FireworkExplosion::hasTwinkle, + FireworkExplosion::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> { diff --git a/src/main/java/net/minestom/server/item/component/FireworkList.java b/src/main/java/net/minestom/server/item/component/FireworkList.java index b0ecc0ace..12ddb6790 100644 --- a/src/main/java/net/minestom/server/item/component/FireworkList.java +++ b/src/main/java/net/minestom/server/item/component/FireworkList.java @@ -2,6 +2,7 @@ package net.minestom.server.item.component; import net.kyori.adventure.nbt.*; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -11,19 +12,11 @@ import java.util.List; public record FireworkList(int flightDuration, @NotNull List explosions) { public static final FireworkList EMPTY = new FireworkList(0, List.of()); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, FireworkList value) { - buffer.write(NetworkBuffer.VAR_INT, value.flightDuration); - buffer.writeCollection(FireworkExplosion.NETWORK_TYPE, value.explosions); - } - - @Override - public FireworkList read(@NotNull NetworkBuffer buffer) { - return new FireworkList(buffer.read(NetworkBuffer.VAR_INT), - buffer.readCollection(FireworkExplosion.NETWORK_TYPE, 256)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.VAR_INT, FireworkList::flightDuration, + FireworkExplosion.NETWORK_TYPE.list(256), FireworkList::explosions, + FireworkList::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> { diff --git a/src/main/java/net/minestom/server/item/component/Food.java b/src/main/java/net/minestom/server/item/component/Food.java index e737f6289..076828444 100644 --- a/src/main/java/net/minestom/server/item/component/Food.java +++ b/src/main/java/net/minestom/server/item/component/Food.java @@ -6,43 +6,33 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.ServerFlag; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.potion.CustomPotionEffect; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import java.util.List; +import static net.minestom.server.network.NetworkBuffer.*; + public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, @NotNull ItemStack usingConvertsTo, @NotNull List effects) { public static final float DEFAULT_EAT_SECONDS = 1.6f; - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Food value) { - buffer.write(NetworkBuffer.VAR_INT, value.nutrition); - buffer.write(NetworkBuffer.FLOAT, value.saturationModifier); - buffer.write(NetworkBuffer.BOOLEAN, value.canAlwaysEat); - buffer.write(NetworkBuffer.FLOAT, value.eatSeconds); - buffer.write(ItemStack.NETWORK_TYPE, value.usingConvertsTo); - buffer.writeCollection(EffectChance.NETWORK_TYPE, value.effects); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + VAR_INT, Food::nutrition, + FLOAT, Food::saturationModifier, + BOOLEAN, Food::canAlwaysEat, + FLOAT, Food::eatSeconds, + ItemStack.NETWORK_TYPE, Food::usingConvertsTo, + EffectChance.NETWORK_TYPE.list(Short.MAX_VALUE), Food::effects, + Food::new + ); - @Override - public Food read(@NotNull NetworkBuffer buffer) { - return new Food( - buffer.read(NetworkBuffer.VAR_INT), - buffer.read(NetworkBuffer.FLOAT), - buffer.read(NetworkBuffer.BOOLEAN), - buffer.read(NetworkBuffer.FLOAT), - buffer.read(ItemStack.NETWORK_TYPE), - buffer.readCollection(EffectChance.NETWORK_TYPE, Short.MAX_VALUE) - ); - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Food( tag.getInt("nutrition"), - tag.getFloat("saturation"), + tag.getFloat("saturation_modifier"), tag.getBoolean("can_always_eat"), tag.getFloat("eat_seconds", DEFAULT_EAT_SECONDS), tag.get("using_converts_to") instanceof BinaryTag usingConvertsTo @@ -51,7 +41,7 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat value -> { CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() .putInt("nutrition", value.nutrition) - .putFloat("saturation", value.saturationModifier) + .putFloat("saturation_odifier", value.saturationModifier) .putBoolean("can_always_eat", value.canAlwaysEat) .putFloat("eat_seconds", value.eatSeconds) .put("effects", EffectChance.NBT_LIST_TYPE.write(value.effects)); @@ -71,18 +61,12 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat } public record EffectChance(@NotNull CustomPotionEffect effect, float probability) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, EffectChance value) { - CustomPotionEffect.NETWORK_TYPE.write(buffer, value.effect); - buffer.write(NetworkBuffer.FLOAT, value.probability); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + CustomPotionEffect.NETWORK_TYPE, EffectChance::effect, + FLOAT, EffectChance::probability, + EffectChance::new + ); - @Override - public EffectChance read(@NotNull NetworkBuffer buffer) { - return null; - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new EffectChance( CustomPotionEffect.NBT_TYPE.read(tag.getCompound("effect")), @@ -94,5 +78,4 @@ public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat ); public static final BinaryTagSerializer> NBT_LIST_TYPE = NBT_TYPE.list(); } - } diff --git a/src/main/java/net/minestom/server/item/component/HeadProfile.java b/src/main/java/net/minestom/server/item/component/HeadProfile.java index 9e8afcae1..588e5a6da 100644 --- a/src/main/java/net/minestom/server/item/component/HeadProfile.java +++ b/src/main/java/net/minestom/server/item/component/HeadProfile.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.IntArrayBinaryTag; import net.kyori.adventure.nbt.StringBinaryTag; import net.minestom.server.entity.PlayerSkin; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,22 +13,19 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.UUID; +import static net.minestom.server.network.NetworkBuffer.STRING; +import static net.minestom.server.network.NetworkBuffer.UUID; + public record HeadProfile(@Nullable String name, @Nullable UUID uuid, @NotNull List properties) { public static final HeadProfile EMPTY = new HeadProfile(null, null, List.of()); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, HeadProfile value) { - buffer.writeOptional(NetworkBuffer.STRING, value.name); - buffer.writeOptional(NetworkBuffer.UUID, value.uuid); - buffer.writeCollection(Property.NETWORK_TYPE, value.properties); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + STRING.optional(), HeadProfile::name, + UUID.optional(), HeadProfile::uuid, + Property.NETWORK_TYPE.list(Short.MAX_VALUE), HeadProfile::properties, + HeadProfile::new + ); - @Override - public HeadProfile read(@NotNull NetworkBuffer buffer) { - return new HeadProfile(buffer.readOptional(NetworkBuffer.STRING), buffer.readOptional(NetworkBuffer.UUID), buffer.readCollection(Property.NETWORK_TYPE, Short.MAX_VALUE)); - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new HeadProfile( tag.get("name") instanceof StringBinaryTag string ? string.value() : null, @@ -38,7 +36,8 @@ public record HeadProfile(@Nullable String name, @Nullable UUID uuid, @NotNull L CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); if (profile.name != null) builder.putString("name", profile.name); if (profile.uuid != null) builder.put("uuid", BinaryTagSerializer.UUID.write(profile.uuid)); - if (!profile.properties.isEmpty()) builder.put("properties", Property.NBT_LIST_TYPE.write(profile.properties)); + if (!profile.properties.isEmpty()) + builder.put("properties", Property.NBT_LIST_TYPE.write(profile.properties)); return builder.build(); } ); @@ -57,19 +56,13 @@ public record HeadProfile(@Nullable String name, @Nullable UUID uuid, @NotNull L } public record Property(@NotNull String name, @NotNull String value, @Nullable String signature) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, Property value) { - buffer.write(NetworkBuffer.STRING, value.name); - buffer.write(NetworkBuffer.STRING, value.value); - buffer.writeOptional(NetworkBuffer.STRING, value.signature); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + STRING, Property::name, + STRING, Property::value, + STRING.optional(), Property::signature, + Property::new + ); - @Override - public Property read(@NotNull NetworkBuffer buffer) { - return new Property(buffer.read(NetworkBuffer.STRING), buffer.read(NetworkBuffer.STRING), buffer.readOptional(NetworkBuffer.STRING)); - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Property(tag.getString("name"), tag.getString("value"), tag.get("signature") instanceof StringBinaryTag signature ? signature.value() : null), diff --git a/src/main/java/net/minestom/server/item/component/ItemBlockState.java b/src/main/java/net/minestom/server/item/component/ItemBlockState.java index ae403be3a..c8f5b6bb5 100644 --- a/src/main/java/net/minestom/server/item/component/ItemBlockState.java +++ b/src/main/java/net/minestom/server/item/component/ItemBlockState.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.StringBinaryTag; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -14,26 +15,10 @@ import java.util.Map; public record ItemBlockState(@NotNull Map properties) { public static final ItemBlockState EMPTY = new ItemBlockState(Map.of()); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ItemBlockState value) { - buffer.write(NetworkBuffer.VAR_INT, value.properties.size()); - for (Map.Entry entry : value.properties.entrySet()) { - buffer.write(NetworkBuffer.STRING, entry.getKey()); - buffer.write(NetworkBuffer.STRING, entry.getValue()); - } - } - - @Override - public ItemBlockState read(@NotNull NetworkBuffer buffer) { - int size = buffer.read(NetworkBuffer.VAR_INT); - Map properties = new HashMap<>(size); - for (int i = 0; i < size; i++) { - properties.put(buffer.read(NetworkBuffer.STRING), buffer.read(NetworkBuffer.STRING)); - } - return new ItemBlockState(properties); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.STRING.mapValue(NetworkBuffer.STRING), ItemBlockState::properties, + ItemBlockState::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> { diff --git a/src/main/java/net/minestom/server/item/component/LodestoneTracker.java b/src/main/java/net/minestom/server/item/component/LodestoneTracker.java index befd8f6a5..53d43dedb 100644 --- a/src/main/java/net/minestom/server/item/component/LodestoneTracker.java +++ b/src/main/java/net/minestom/server/item/component/LodestoneTracker.java @@ -3,6 +3,7 @@ package net.minestom.server.item.component; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.play.data.WorldPos; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -10,21 +11,11 @@ import org.jetbrains.annotations.Nullable; public record LodestoneTracker(@Nullable WorldPos target, boolean tracked) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, @NotNull LodestoneTracker value) { - buffer.writeOptional(WorldPos.NETWORK_TYPE, value.target); - buffer.write(NetworkBuffer.BOOLEAN, value.tracked); - } - - @Override - public @NotNull LodestoneTracker read(@NotNull NetworkBuffer buffer) { - return new LodestoneTracker( - buffer.readOptional(WorldPos.NETWORK_TYPE), - buffer.read(NetworkBuffer.BOOLEAN) - ); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + WorldPos.NETWORK_TYPE.optional(), LodestoneTracker::target, + NetworkBuffer.BOOLEAN, LodestoneTracker::tracked, + LodestoneTracker::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new LodestoneTracker( diff --git a/src/main/java/net/minestom/server/item/component/MapPostProcessing.java b/src/main/java/net/minestom/server/item/component/MapPostProcessing.java index a73723b31..1c24ad834 100644 --- a/src/main/java/net/minestom/server/item/component/MapPostProcessing.java +++ b/src/main/java/net/minestom/server/item/component/MapPostProcessing.java @@ -1,22 +1,10 @@ package net.minestom.server.item.component; import net.minestom.server.network.NetworkBuffer; -import org.jetbrains.annotations.NotNull; public enum MapPostProcessing { LOCK, SCALE; - private static final MapPostProcessing[] VALUES = values(); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, MapPostProcessing value) { - buffer.write(NetworkBuffer.VAR_INT, value.ordinal()); - } - - @Override - public MapPostProcessing read(@NotNull NetworkBuffer buffer) { - return VALUES[buffer.read(NetworkBuffer.VAR_INT)]; - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(MapPostProcessing.class); } diff --git a/src/main/java/net/minestom/server/item/component/PotDecorations.java b/src/main/java/net/minestom/server/item/component/PotDecorations.java index a0de6724e..30e77229b 100644 --- a/src/main/java/net/minestom/server/item/component/PotDecorations.java +++ b/src/main/java/net/minestom/server/item/component/PotDecorations.java @@ -16,7 +16,7 @@ public record PotDecorations( public static final @NotNull Material DEFAULT_ITEM = Material.BRICK; public static final PotDecorations EMPTY = new PotDecorations(DEFAULT_ITEM, DEFAULT_ITEM, DEFAULT_ITEM, DEFAULT_ITEM); - public static NetworkBuffer.Type NETWORK_TYPE = Material.NETWORK_TYPE.list(4).map(PotDecorations::new, PotDecorations::asList); + public static final NetworkBuffer.Type NETWORK_TYPE = Material.NETWORK_TYPE.list(4).transform(PotDecorations::new, PotDecorations::asList); public static BinaryTagSerializer NBT_TYPE = Material.NBT_TYPE.list().map(PotDecorations::new, PotDecorations::asList); public PotDecorations(@NotNull List list) { diff --git a/src/main/java/net/minestom/server/item/component/PotionContents.java b/src/main/java/net/minestom/server/item/component/PotionContents.java index fa3993381..27679ef77 100644 --- a/src/main/java/net/minestom/server/item/component/PotionContents.java +++ b/src/main/java/net/minestom/server/item/component/PotionContents.java @@ -25,18 +25,18 @@ public record PotionContents( @Override public void write(@NotNull NetworkBuffer buffer, PotionContents value) { Integer typeId = value.potion == null ? null : value.potion.id(); - buffer.writeOptional(NetworkBuffer.VAR_INT, typeId); - buffer.writeOptional(Color.NETWORK_TYPE, value.customColor); - buffer.writeCollection(CustomPotionEffect.NETWORK_TYPE, value.customEffects); + buffer.write(NetworkBuffer.VAR_INT.optional(), typeId); + buffer.write(Color.NETWORK_TYPE.optional(), value.customColor); + buffer.write(CustomPotionEffect.NETWORK_TYPE.list(), value.customEffects); } @Override public PotionContents read(@NotNull NetworkBuffer buffer) { - Integer typeId = buffer.readOptional(NetworkBuffer.VAR_INT); + Integer typeId = buffer.read(NetworkBuffer.VAR_INT.optional()); return new PotionContents( typeId == null ? null : PotionType.fromId(typeId), - buffer.readOptional(Color.NETWORK_TYPE), - buffer.readCollection(CustomPotionEffect.NETWORK_TYPE, Short.MAX_VALUE) + buffer.read(Color.NETWORK_TYPE.optional()), + buffer.read(CustomPotionEffect.NETWORK_TYPE.list(Short.MAX_VALUE)) ); } }; diff --git a/src/main/java/net/minestom/server/item/component/SuspiciousStewEffects.java b/src/main/java/net/minestom/server/item/component/SuspiciousStewEffects.java index 681adcde6..8279e4f57 100644 --- a/src/main/java/net/minestom/server/item/component/SuspiciousStewEffects.java +++ b/src/main/java/net/minestom/server/item/component/SuspiciousStewEffects.java @@ -2,6 +2,7 @@ package net.minestom.server.item.component; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.potion.PotionEffect; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -13,7 +14,7 @@ public record SuspiciousStewEffects(@NotNull List effects) { public static final int DEFAULT_DURATION = 160; public static final SuspiciousStewEffects EMPTY = new SuspiciousStewEffects(List.of()); - public static final NetworkBuffer.Type NETWORK_TYPE = Effect.NETWORK_TYPE.list(Short.MAX_VALUE).map(SuspiciousStewEffects::new, SuspiciousStewEffects::effects); + public static final NetworkBuffer.Type NETWORK_TYPE = Effect.NETWORK_TYPE.list(Short.MAX_VALUE).transform(SuspiciousStewEffects::new, SuspiciousStewEffects::effects); public static final BinaryTagSerializer NBT_TYPE = Effect.NBT_TYPE.list().map(SuspiciousStewEffects::new, SuspiciousStewEffects::effects); public SuspiciousStewEffects { @@ -32,18 +33,11 @@ public record SuspiciousStewEffects(@NotNull List effects) { public record Effect(@NotNull PotionEffect id, int durationTicks) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Effect value) { - buffer.write(PotionEffect.NETWORK_TYPE, value.id); - buffer.write(NetworkBuffer.VAR_INT, value.durationTicks); - } - - @Override - public Effect read(@NotNull NetworkBuffer buffer) { - return new Effect(buffer.read(PotionEffect.NETWORK_TYPE), buffer.read(NetworkBuffer.VAR_INT)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + PotionEffect.NETWORK_TYPE, Effect::id, + NetworkBuffer.VAR_INT, Effect::durationTicks, + Effect::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Effect(PotionEffect.fromNamespaceId(tag.getString("id")), diff --git a/src/main/java/net/minestom/server/item/component/Tool.java b/src/main/java/net/minestom/server/item/component/Tool.java index 68e93053a..32379f8e0 100644 --- a/src/main/java/net/minestom/server/item/component/Tool.java +++ b/src/main/java/net/minestom/server/item/component/Tool.java @@ -6,6 +6,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.FloatBinaryTag; import net.minestom.server.instance.block.predicate.BlockTypeFilter; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,23 +63,12 @@ public record Tool(@NotNull List rules, float defaultMiningSpeed, int dama public record Rule(@NotNull BlockTypeFilter blocks, @Nullable Float speed, @Nullable Boolean correctForDrops) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Rule value) { - buffer.write(BlockTypeFilter.NETWORK_TYPE, value.blocks()); - buffer.writeOptional(NetworkBuffer.FLOAT, value.speed()); - buffer.writeOptional(NetworkBuffer.BOOLEAN, value.correctForDrops()); - } - - @Override - public Rule read(@NotNull NetworkBuffer buffer) { - return new Rule( - buffer.read(BlockTypeFilter.NETWORK_TYPE), - buffer.readOptional(NetworkBuffer.FLOAT), - buffer.readOptional(NetworkBuffer.BOOLEAN) - ); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + BlockTypeFilter.NETWORK_TYPE, Rule::blocks, + NetworkBuffer.FLOAT, Rule::speed, + NetworkBuffer.BOOLEAN.optional(), Rule::correctForDrops, + Rule::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Rule( BlockTypeFilter.NBT_TYPE.read(Objects.requireNonNull(tag.get("blocks"))), diff --git a/src/main/java/net/minestom/server/item/component/Unbreakable.java b/src/main/java/net/minestom/server/item/component/Unbreakable.java index 087dc71c1..69d3be4aa 100644 --- a/src/main/java/net/minestom/server/item/component/Unbreakable.java +++ b/src/main/java/net/minestom/server/item/component/Unbreakable.java @@ -2,23 +2,16 @@ package net.minestom.server.item.component; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; -import org.jetbrains.annotations.NotNull; public record Unbreakable(boolean showInTooltip) { public static final Unbreakable DEFAULT = new Unbreakable(); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, Unbreakable value) { - buffer.write(NetworkBuffer.BOOLEAN, value.showInTooltip()); - } - - @Override - public Unbreakable read(@NotNull NetworkBuffer buffer) { - return new Unbreakable(buffer.read(NetworkBuffer.BOOLEAN)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.BOOLEAN, Unbreakable::showInTooltip, + Unbreakable::new + ); public Unbreakable() { this(true); @@ -28,5 +21,4 @@ public record Unbreakable(boolean showInTooltip) { tag -> new Unbreakable(tag.getBoolean("showInTooltip", true)), unbreakable -> CompoundBinaryTag.builder().putBoolean("showInTooltip", unbreakable.showInTooltip()).build() ); - } diff --git a/src/main/java/net/minestom/server/item/component/WritableBookContent.java b/src/main/java/net/minestom/server/item/component/WritableBookContent.java index b416f20cc..8fab0af5f 100644 --- a/src/main/java/net/minestom/server/item/component/WritableBookContent.java +++ b/src/main/java/net/minestom/server/item/component/WritableBookContent.java @@ -5,6 +5,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.ListBinaryTag; import net.minestom.server.item.book.FilteredText; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; @@ -14,17 +15,10 @@ import java.util.List; public record WritableBookContent(@NotNull List> pages) { public static final WritableBookContent EMPTY = new WritableBookContent(List.of()); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, WritableBookContent value) { - buffer.writeCollection(FilteredText.STRING_NETWORK_TYPE, value.pages); - } - - @Override - public WritableBookContent read(@NotNull NetworkBuffer buffer) { - return new WritableBookContent(buffer.readCollection(FilteredText.STRING_NETWORK_TYPE, 100)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + FilteredText.STRING_NETWORK_TYPE.list(100), WritableBookContent::pages, + WritableBookContent::new + ); public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override diff --git a/src/main/java/net/minestom/server/item/component/WrittenBookContent.java b/src/main/java/net/minestom/server/item/component/WrittenBookContent.java index ce4d55bd2..92e1b933d 100644 --- a/src/main/java/net/minestom/server/item/component/WrittenBookContent.java +++ b/src/main/java/net/minestom/server/item/component/WrittenBookContent.java @@ -6,34 +6,26 @@ import net.kyori.adventure.nbt.ListBinaryTag; import net.kyori.adventure.text.Component; import net.minestom.server.item.book.FilteredText; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import java.util.List; -public record WrittenBookContent(@NotNull List> pages, @NotNull FilteredText title, @NotNull String author, int generation, boolean resolved) { - public static final WrittenBookContent EMPTY = new WrittenBookContent(List.of(), new FilteredText<>("", null), "", 0, true); +import static net.minestom.server.network.NetworkBuffer.*; - public static final @NotNull NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, WrittenBookContent value) { - buffer.write(FilteredText.STRING_NETWORK_TYPE, value.title); - buffer.write(NetworkBuffer.STRING, value.author); - buffer.write(NetworkBuffer.VAR_INT, value.generation); - buffer.writeCollection(FilteredText.COMPONENT_NETWORK_TYPE, value.pages); - buffer.write(NetworkBuffer.BOOLEAN, value.resolved); - } +public record WrittenBookContent(@NotNull FilteredText title, @NotNull String author, int generation, + @NotNull List> pages, boolean resolved) { + public static final WrittenBookContent EMPTY = new WrittenBookContent(new FilteredText<>("", null), "", 0, List.of(), true); - @Override - public WrittenBookContent read(@NotNull NetworkBuffer buffer) { - FilteredText title = buffer.read(FilteredText.STRING_NETWORK_TYPE); - String author = buffer.read(NetworkBuffer.STRING); - int generation = buffer.read(NetworkBuffer.VAR_INT); - List> pages = buffer.readCollection(FilteredText.COMPONENT_NETWORK_TYPE, 100); - boolean resolved = buffer.read(NetworkBuffer.BOOLEAN); - return new WrittenBookContent(pages, title, author, generation, resolved); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + FilteredText.STRING_NETWORK_TYPE, WrittenBookContent::title, + STRING, WrittenBookContent::author, + VAR_INT, WrittenBookContent::generation, + FilteredText.COMPONENT_NETWORK_TYPE.list(100), WrittenBookContent::pages, + BOOLEAN, WrittenBookContent::resolved, + WrittenBookContent::new + ); public static final @NotNull BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( compound -> { @@ -45,7 +37,7 @@ public record WrittenBookContent(@NotNull List> pages, @ String author = compound.getString("author"); int generation = compound.getInt("generation"); boolean resolved = compound.getBoolean("resolved"); - return new WrittenBookContent(pages, title, author, generation, resolved); + return new WrittenBookContent(title, author, generation, pages, resolved); }, value -> { ListBinaryTag.Builder pagesTag = ListBinaryTag.builder(); @@ -66,11 +58,11 @@ public record WrittenBookContent(@NotNull List> pages, @ pages = List.copyOf(pages); } - public WrittenBookContent(@NotNull List pages, @NotNull String title, @NotNull String author) { - this(pages, title, author, 0, true); + public WrittenBookContent(@NotNull String title, @NotNull String author, @NotNull List pages) { + this(title, author, 0, pages, true); } - public WrittenBookContent(@NotNull List pages, @NotNull String title, @NotNull String author, int generation, boolean resolved) { - this(pages.stream().map(page -> new FilteredText<>(page, null)).toList(), new FilteredText<>(title, null), author, generation, resolved); + public WrittenBookContent(@NotNull String title, @NotNull String author, int generation, @NotNull List pages, boolean resolved) { + this(new FilteredText<>(title, null), author, generation, pages.stream().map(page -> new FilteredText<>(page, null)).toList(), resolved); } } diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 07ae247ed..9896cd696 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -114,7 +114,7 @@ public final class PacketListenerManager { // Listener can be null if none has been set before, call PacketConsumer anyway if (packetListenerConsumer == null) { - LOGGER.warn("Packet " + clazz + " does not have any default listener! (The issue comes from Minestom)"); + LOGGER.warn("Packet {}:{} does not have any default listener! (The issue likely comes from Minestom)", clazz, state); return; } diff --git a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java index ab9bf1a89..e0295ba8d 100644 --- a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java @@ -22,8 +22,8 @@ import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; +import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; -import net.minestom.server.network.plugin.LoginPluginResponse; import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.NotNull; @@ -33,7 +33,6 @@ import java.net.*; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -56,7 +55,7 @@ public final class LoginListener { socketConnection.UNSAFE_setLoginUsername(packet.username()); // Velocity support if (VelocityProxy.isEnabled()) { - connection.loginPluginMessageProcessor().request(VelocityProxy.PLAYER_INFO_CHANNEL, null) + connection.loginPluginMessageProcessor().request(VelocityProxy.PLAYER_INFO_CHANNEL, new byte[0]) .thenAccept(response -> handleVelocityProxyResponse(socketConnection, response)); return; } @@ -171,14 +170,13 @@ public final class LoginListener { return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret); } - private static void handleVelocityProxyResponse(PlayerSocketConnection socketConnection, LoginPluginResponse response) { - byte[] data = response.getPayload(); - + private static void handleVelocityProxyResponse(PlayerSocketConnection socketConnection, LoginPlugin.Response response) { + final byte[] data = response.payload(); SocketAddress socketAddress = null; GameProfile gameProfile = null; boolean success = false; if (data != null && data.length > 0) { - NetworkBuffer buffer = new NetworkBuffer(ByteBuffer.wrap(data)); + NetworkBuffer buffer = NetworkBuffer.wrap(data, 0, data.length); success = VelocityProxy.checkIntegrity(buffer); if (success) { // Get the real connection address @@ -191,7 +189,7 @@ public final class LoginListener { } final int port = ((java.net.InetSocketAddress) socketConnection.getRemoteAddress()).getPort(); socketAddress = new InetSocketAddress(address, port); - gameProfile = new GameProfile(buffer); + gameProfile = GameProfile.SERIALIZER.read(buffer); } } diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java index 3c508c6e1..50d779f75 100644 --- a/src/main/java/net/minestom/server/message/Messenger.java +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.play.SystemChatPacket; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,7 +50,7 @@ public final class Messenger { */ public static void sendMessage(@NotNull Collection players, @NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) { - PacketUtils.sendGroupedPacket(players, new SystemChatPacket(message, false), + PacketSendingUtils.sendGroupedPacket(players, new SystemChatPacket(message, false), player -> getChatMessageType(player).accepts(position)); } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index af7dbac84..5154906ba 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -48,7 +48,8 @@ public final class ConnectionManager { private CachedPacket getDefaultTags() { var defaultTags = this.defaultTags; if (defaultTags == null) { - this.defaultTags = defaultTags = new CachedPacket(new TagsPacket(MinecraftServer.getTagManager().getTagMap())); + final TagsPacket packet = MinecraftServer.getTagManager().packet(); + this.defaultTags = defaultTags = new CachedPacket(packet); } return defaultTags; } diff --git a/src/main/java/net/minestom/server/network/ConnectionState.java b/src/main/java/net/minestom/server/network/ConnectionState.java index b93837ec6..81e06d80a 100644 --- a/src/main/java/net/minestom/server/network/ConnectionState.java +++ b/src/main/java/net/minestom/server/network/ConnectionState.java @@ -1,8 +1,28 @@ package net.minestom.server.network; /** - * Represents the current connection state of a {@link net.minestom.server.network.player.PlayerConnection}. + * Represents the connection state of a client. */ public enum ConnectionState { - HANDSHAKE, STATUS, LOGIN, CONFIGURATION, PLAY + /** + * Default state before any packet is received. + */ + HANDSHAKE, + /** + * Client declares `Status` intent during handshake. + */ + STATUS, + /** + * Client declares `Login` intent during handshake. + */ + LOGIN, + /** + * Client acknowledged login and is now configuring the game. + * Can also go back to configuration from play. + */ + CONFIGURATION, + /** + * Client (re-)finished configuration. + */ + PLAY } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index a5bd4c341..bef9d2929 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -1,8 +1,8 @@ package net.minestom.server.network; import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; -import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.EntityPose; @@ -11,349 +11,278 @@ import net.minestom.server.registry.ProtocolObject; import net.minestom.server.registry.Registries; import net.minestom.server.utils.Direction; import net.minestom.server.utils.Unit; -import net.minestom.server.utils.nbt.BinaryTagReader; -import net.minestom.server.utils.nbt.BinaryTagWriter; -import net.minestom.server.utils.validate.Check; +import net.minestom.server.utils.crypto.KeyUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; +import javax.crypto.Cipher; +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SocketChannel; +import java.security.PublicKey; +import java.time.Instant; import java.util.*; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.zip.DataFormatException; -public final class NetworkBuffer { - public static final Type UNIT = new NetworkBufferTypeImpl.UnitType(); - public static final Type BOOLEAN = new NetworkBufferTypeImpl.BooleanType(); - public static final Type BYTE = new NetworkBufferTypeImpl.ByteType(); - public static final Type SHORT = new NetworkBufferTypeImpl.ShortType(); - public static final Type UNSIGNED_SHORT = new NetworkBufferTypeImpl.UnsignedShortType(); - public static final Type INT = new NetworkBufferTypeImpl.IntType(); - public static final Type LONG = new NetworkBufferTypeImpl.LongType(); - public static final Type FLOAT = new NetworkBufferTypeImpl.FloatType(); - public static final Type DOUBLE = new NetworkBufferTypeImpl.DoubleType(); - public static final Type VAR_INT = new NetworkBufferTypeImpl.VarIntType(); - public static final Type VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); - public static final Type RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(); - public static final Type STRING = new NetworkBufferTypeImpl.StringType(); - public static final Type STRING_TERMINATED = new NetworkBufferTypeImpl.StringTerminatedType(); - public static final Type NBT = new NetworkBufferTypeImpl.NbtType(); - public static final Type BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); - public static final Type COMPONENT = new ComponentNetworkBufferTypeImpl(); - public static final Type JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); - public static final Type UUID = new NetworkBufferTypeImpl.UUIDType(); - public static final Type POS = new NetworkBufferTypeImpl.PosType(); +public sealed interface NetworkBuffer permits NetworkBufferImpl { + Type UNIT = new NetworkBufferTypeImpl.UnitType(); + Type BOOLEAN = new NetworkBufferTypeImpl.BooleanType(); + Type BYTE = new NetworkBufferTypeImpl.ByteType(); + Type SHORT = new NetworkBufferTypeImpl.ShortType(); + Type UNSIGNED_SHORT = new NetworkBufferTypeImpl.UnsignedShortType(); + Type INT = new NetworkBufferTypeImpl.IntType(); + Type LONG = new NetworkBufferTypeImpl.LongType(); + Type FLOAT = new NetworkBufferTypeImpl.FloatType(); + Type DOUBLE = new NetworkBufferTypeImpl.DoubleType(); + Type VAR_INT = new NetworkBufferTypeImpl.VarIntType(); + Type VAR_INT_3 = new NetworkBufferTypeImpl.VarInt3Type(); + Type VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); + Type RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(-1); + Type STRING = new NetworkBufferTypeImpl.StringType(); + Type STRING_TERMINATED = new NetworkBufferTypeImpl.StringTerminatedType(); + Type NBT = new NetworkBufferTypeImpl.NbtType(); + @SuppressWarnings({"unchecked", "rawtypes"}) + Type NBT_COMPOUND = (Type) new NetworkBufferTypeImpl.NbtType(); + Type BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); + Type COMPONENT = new NetworkBufferTypeImpl.ComponentType(); + Type JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); + Type UUID = new NetworkBufferTypeImpl.UUIDType(); + Type POS = new NetworkBufferTypeImpl.PosType(); - public static final Type BYTE_ARRAY = new NetworkBufferTypeImpl.ByteArrayType(); - public static final Type LONG_ARRAY = new NetworkBufferTypeImpl.LongArrayType(); - public static final Type VAR_INT_ARRAY = new NetworkBufferTypeImpl.VarIntArrayType(); - public static final Type VAR_LONG_ARRAY = new NetworkBufferTypeImpl.VarLongArrayType(); + Type BYTE_ARRAY = new NetworkBufferTypeImpl.ByteArrayType(); + Type LONG_ARRAY = new NetworkBufferTypeImpl.LongArrayType(); + Type VAR_INT_ARRAY = new NetworkBufferTypeImpl.VarIntArrayType(); + Type VAR_LONG_ARRAY = new NetworkBufferTypeImpl.VarLongArrayType(); - public static @NotNull Type> RegistryKey(@NotNull Function> selector) { + Type BITSET = LONG_ARRAY.transform(BitSet::valueOf, BitSet::toLongArray); + Type INSTANT_MS = LONG.transform(Instant::ofEpochMilli, Instant::toEpochMilli); + Type PUBLIC_KEY = BYTE_ARRAY.transform(KeyUtils::publicRSAKeyFrom, PublicKey::getEncoded); + + static @NotNull Type> RegistryKey(@NotNull Function> selector) { return new NetworkBufferTypeImpl.RegistryTypeType<>(selector); } // METADATA - public static final Type VILLAGER_DATA = new NetworkBufferTypeImpl.VillagerDataType(); - public static final Type VECTOR3 = new NetworkBufferTypeImpl.Vector3Type(); - public static final Type VECTOR3D = new NetworkBufferTypeImpl.Vector3DType(); - public static final Type QUATERNION = new NetworkBufferTypeImpl.QuaternionType(); + Type VILLAGER_DATA = new NetworkBufferTypeImpl.VillagerDataType(); + Type VECTOR3 = new NetworkBufferTypeImpl.Vector3Type(); + Type VECTOR3D = new NetworkBufferTypeImpl.Vector3DType(); + Type VECTOR3B = new NetworkBufferTypeImpl.Vector3BType(); + Type QUATERNION = new NetworkBufferTypeImpl.QuaternionType(); - public static final Type<@Nullable Component> OPT_CHAT = Optional(COMPONENT); - public static final Type<@Nullable Point> OPT_BLOCK_POSITION = Optional(BLOCK_POSITION); - public static final Type<@Nullable UUID> OPT_UUID = Optional(UUID); + Type<@Nullable Component> OPT_CHAT = COMPONENT.optional(); + Type<@Nullable Point> OPT_BLOCK_POSITION = BLOCK_POSITION.optional(); + Type<@Nullable UUID> OPT_UUID = UUID.optional(); - public static final Type DIRECTION = new NetworkBufferTypeImpl.EnumType<>(Direction.class); - public static final Type POSE = new NetworkBufferTypeImpl.EnumType<>(EntityPose.class); + Type DIRECTION = Enum(Direction.class); + Type POSE = Enum(EntityPose.class); // Combinators - public static @NotNull Type<@Nullable T> Optional(@NotNull Type type) { - return new NetworkBufferTypeImpl.OptionalType<>(type); + static > @NotNull Type Enum(@NotNull Class enumClass) { + final E[] values = enumClass.getEnumConstants(); + return VAR_INT.transform(integer -> values[integer], Enum::ordinal); } - public static > @NotNull Type Enum(@NotNull Class enumClass) { - return new NetworkBufferTypeImpl.EnumType<>(enumClass); + static > @NotNull Type> EnumSet(@NotNull Class enumClass) { + return new NetworkBufferTypeImpl.EnumSetType<>(enumClass, enumClass.getEnumConstants()); } - public static @NotNull Type Lazy(@NotNull Supplier> supplier) { + static @NotNull Type FixedBitSet(int length) { + return new NetworkBufferTypeImpl.FixedBitSetType(length); + } + + static @NotNull Type FixedRawBytes(int length) { + return new NetworkBufferTypeImpl.RawBytesType(length); + } + + static @NotNull Type Lazy(@NotNull Supplier<@NotNull Type> supplier) { return new NetworkBufferTypeImpl.LazyType<>(supplier); } + void write(@NotNull Type type, @UnknownNullability T value); - ByteBuffer nioBuffer; - final boolean resizable; - int writeIndex; - int readIndex; + @UnknownNullability T read(@NotNull Type type); - BinaryTagWriter nbtWriter; - BinaryTagReader nbtReader; + void writeAt(long index, @NotNull Type type, @UnknownNullability T value); - // In the future, this should be passed as a parameter. - final Registries registries = MinecraftServer.process(); + @UnknownNullability T readAt(long index, @NotNull Type type); - public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) { - this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN); - this.resizable = resizable; + void copyTo(long srcOffset, byte @NotNull [] dest, long destOffset, long length); - this.writeIndex = buffer.position(); - this.readIndex = buffer.position(); + byte @NotNull [] extractBytes(@NotNull Consumer<@NotNull NetworkBuffer> extractor); + + @NotNull NetworkBuffer clear(); + + long writeIndex(); + + long readIndex(); + + @NotNull NetworkBuffer writeIndex(long writeIndex); + + @NotNull NetworkBuffer readIndex(long readIndex); + + @NotNull NetworkBuffer index(long readIndex, long writeIndex); + + long advanceWrite(long length); + + long advanceRead(long length); + + long readableBytes(); + + long writableBytes(); + + long capacity(); + + void readOnly(); + + boolean isReadOnly(); + + void resize(long newSize); + + void ensureWritable(long length); + + void compact(); + + NetworkBuffer slice(long index, long length, long readIndex, long writeIndex); + + NetworkBuffer copy(long index, long length, long readIndex, long writeIndex); + + default NetworkBuffer copy(long index, long length) { + return copy(index, length, readIndex(), writeIndex()); } - public NetworkBuffer(@NotNull ByteBuffer buffer) { - this(buffer, true); - } + int readChannel(ReadableByteChannel channel) throws IOException; - public NetworkBuffer(int initialCapacity) { - this(ByteBuffer.allocateDirect(initialCapacity), true); - } + boolean writeChannel(SocketChannel channel) throws IOException; - public NetworkBuffer() { - this(1024); - } + void cipher(Cipher cipher, long start, long length); - public void write(@NotNull Type type, @NotNull T value) { - type.write(this, value); - } + long compress(long start, long length, NetworkBuffer output); - public void write(@NotNull Writer writer) { - writer.write(this); - } + long decompress(long start, long length, NetworkBuffer output) throws DataFormatException; - public @NotNull T read(@NotNull Type type) { - return type.read(this); - } + @Nullable Registries registries(); - public void writeOptional(@NotNull Type type, @Nullable T value) { - write(BOOLEAN, value != null); - if (value != null) write(type, value); - } - - public void writeOptional(@Nullable Writer writer) { - write(BOOLEAN, writer != null); - if (writer != null) write(writer); - } - - public @Nullable T readOptional(@NotNull Type type) { - return read(BOOLEAN) ? read(type) : null; - } - - public @Nullable T readOptional(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function) { - return read(BOOLEAN) ? function.apply(this) : null; - } - - public void writeCollection(@NotNull Type type, @Nullable Collection<@NotNull T> values) { - if (values == null) { - write(BYTE, (byte) 0); - return; - } - write(VAR_INT, values.size()); - for (T value : values) write(type, value); - } - - @SafeVarargs - public final void writeCollection(@NotNull Type type, @NotNull T @Nullable ... values) { - writeCollection(type, values == null ? null : List.of(values)); - } - - public void writeCollection(@Nullable Collection<@NotNull T> values) { - if (values == null) { - write(BYTE, (byte) 0); - return; - } - write(VAR_INT, values.size()); - for (T value : values) write(value); - } - - public void writeCollection(@Nullable Collection<@NotNull T> values, - @NotNull BiConsumer<@NotNull NetworkBuffer, @NotNull T> consumer) { - if (values == null) { - write(BYTE, (byte) 0); - return; - } - write(VAR_INT, values.size()); - for (T value : values) consumer.accept(this, value); - } - - public @NotNull List<@NotNull T> readCollection(@NotNull Type type, int maxSize) { - final int size = read(VAR_INT); - Check.argCondition(size > maxSize, "Collection size ({0}) is higher than the maximum allowed size ({1})", size, maxSize); - final List values = new java.util.ArrayList<>(size); - for (int i = 0; i < size; i++) values.add(read(type)); - return values; - } - - public @NotNull List<@NotNull T> readCollection(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function, int maxSize) { - final int size = read(VAR_INT); - Check.argCondition(size > maxSize, "Collection size ({0}) is higher than the maximum allowed size ({1})", size, maxSize); - final List values = new java.util.ArrayList<>(size); - for (int i = 0; i < size; i++) values.add(function.apply(this)); - return values; - } - - public @NotNull Map writeMap(@NotNull NetworkBuffer.Type keyType, @NotNull NetworkBuffer.Type valueType, @NotNull Map map) { - write(VAR_INT, map.size()); - for (Map.Entry entry : map.entrySet()) { - write(keyType, entry.getKey()); - write(valueType, entry.getValue()); - } - return map; - } - - public @NotNull Map readMap(@NotNull NetworkBuffer.Type keyType, @NotNull NetworkBuffer.Type valueType, int maxSize) { - final int size = read(VAR_INT); - Check.argCondition(size > maxSize, "Map size ({0}) is higher than the maximum allowed size ({1})", size, maxSize); - final Map map = new HashMap<>(size); - for (int i = 0; i < size; i++) { - map.put(read(keyType), read(valueType)); - } - return map; - } - - public > void writeEnum(@NotNull Class enumClass, @NotNull E value) { - write(VAR_INT, value.ordinal()); - } - - public > @NotNull E readEnum(@NotNull Class<@NotNull E> enumClass) { - return enumClass.getEnumConstants()[read(VAR_INT)]; - } - - public > void writeEnumSet(EnumSet enumSet, Class enumType) { - final E[] values = enumType.getEnumConstants(); - BitSet bitSet = new BitSet(values.length); - for (int i = 0; i < values.length; ++i) { - bitSet.set(i, enumSet.contains(values[i])); - } - writeFixedBitSet(bitSet, values.length); - } - - public > @NotNull EnumSet readEnumSet(Class enumType) { - final E[] values = enumType.getEnumConstants(); - BitSet bitSet = readFixedBitSet(values.length); - EnumSet enumSet = EnumSet.noneOf(enumType); - for (int i = 0; i < values.length; ++i) { - if (bitSet.get(i)) { - enumSet.add(values[i]); - } - } - return enumSet; - } - - public void writeFixedBitSet(BitSet set, int length) { - final int setLength = set.length(); - if (setLength > length) { - throw new IllegalArgumentException("BitSet is larger than expected size (" + setLength + ">" + length + ")"); - } else { - final byte[] array = set.toByteArray(); - write(RAW_BYTES, array); - } - } - - @NotNull - public BitSet readFixedBitSet(int length) { - final byte[] array = readBytes((length + 7) / 8); - return BitSet.valueOf(array); - } - - public byte[] readBytes(int length) { - byte[] bytes = new byte[length]; - nioBuffer.get(readIndex, bytes, 0, length); - readIndex += length; - return bytes; - } - - public void copyTo(int srcOffset, byte @NotNull [] dest, int destOffset, int length) { - this.nioBuffer.get(srcOffset, dest, destOffset, length); - } - - public byte @NotNull [] extractBytes(@NotNull Consumer<@NotNull NetworkBuffer> extractor) { - final int startingPosition = readIndex(); - extractor.accept(this); - final int endingPosition = readIndex(); - byte[] output = new byte[endingPosition - startingPosition]; - copyTo(startingPosition, output, 0, output.length); - return output; - } - - public void clear() { - this.writeIndex = 0; - this.readIndex = 0; - } - - public int writeIndex() { - return writeIndex; - } - - public int readIndex() { - return readIndex; - } - - public void writeIndex(int writeIndex) { - this.writeIndex = writeIndex; - } - - public void readIndex(int readIndex) { - this.readIndex = readIndex; - } - - public int skipWrite(int length) { - final int oldWriteIndex = writeIndex; - writeIndex += length; - return oldWriteIndex; - } - - public int readableBytes() { - return writeIndex - readIndex; - } - - void ensureSize(int length) { - if (!resizable) return; - if (nioBuffer.capacity() < writeIndex + length) { - final int newCapacity = Math.max(nioBuffer.capacity() * 2, writeIndex + length); - ByteBuffer newBuffer = ByteBuffer.allocateDirect(newCapacity); - nioBuffer.position(0); - newBuffer.put(nioBuffer); - nioBuffer = newBuffer.clear(); - } - } - - - public interface Type { + interface Type { void write(@NotNull NetworkBuffer buffer, T value); T read(@NotNull NetworkBuffer buffer); - default @NotNull Type map(@NotNull Function to, @NotNull Function from) { - return new NetworkBufferTypeImpl.MappedType<>(this, to, from); + default long sizeOf(@NotNull T value, @Nullable Registries registries) { + return NetworkBufferTypeImpl.sizeOf(this, value, registries); + } + + default long sizeOf(@NotNull T value) { + return sizeOf(value, null); + } + + default @NotNull Type transform(@NotNull Function to, @NotNull Function from) { + return new NetworkBufferTypeImpl.TransformType<>(this, to, from); + } + + default @NotNull Type> mapValue(@NotNull Type valueType, int maxSize) { + return new NetworkBufferTypeImpl.MapType<>(this, valueType, maxSize); + } + + default @NotNull Type> mapValue(@NotNull Type valueType) { + return mapValue(valueType, Integer.MAX_VALUE); } default @NotNull Type> list(int maxSize) { return new NetworkBufferTypeImpl.ListType<>(this, maxSize); } + default @NotNull Type> list() { + return list(Integer.MAX_VALUE); + } + default @NotNull Type optional() { - return new NetworkBufferTypeImpl.OptionalTypeImpl<>(this); + return new NetworkBufferTypeImpl.OptionalType<>(this); } } - @FunctionalInterface - public interface Writer { - void write(@NotNull NetworkBuffer writer); + static @NotNull Builder builder(long size) { + return new NetworkBufferImpl.Builder(size); + } + + static @NotNull NetworkBuffer staticBuffer(long size, Registries registries) { + return builder(size).registry(registries).build(); + } + + static @NotNull NetworkBuffer staticBuffer(long size) { + return staticBuffer(size, null); + } + + static @NotNull NetworkBuffer resizableBuffer(long initialSize, Registries registries) { + return builder(initialSize) + .autoResize(AutoResize.DOUBLE) + .registry(registries) + .build(); + } + + static @NotNull NetworkBuffer resizableBuffer(int initialSize) { + return resizableBuffer(initialSize, null); + } + + static @NotNull NetworkBuffer resizableBuffer(Registries registries) { + return resizableBuffer(256, registries); + } + + static @NotNull NetworkBuffer resizableBuffer() { + return resizableBuffer(null); + } + + static @NotNull NetworkBuffer wrap(byte @NotNull [] bytes, int readIndex, int writeIndex, @Nullable Registries registries) { + return NetworkBufferImpl.wrap(bytes, readIndex, writeIndex, registries); + } + + static @NotNull NetworkBuffer wrap(byte @NotNull [] bytes, int readIndex, int writeIndex) { + return wrap(bytes, readIndex, writeIndex, null); + } + + sealed interface Builder permits NetworkBufferImpl.Builder { + @NotNull Builder autoResize(@Nullable AutoResize autoResize); + + @NotNull Builder registry(@Nullable Registries registries); + + @NotNull NetworkBuffer build(); } @FunctionalInterface - public interface Reader { - @NotNull T read(@NotNull NetworkBuffer reader); + interface AutoResize { + AutoResize DOUBLE = (capacity, targetSize) -> Math.max(capacity * 2, targetSize); + + long resize(long capacity, long targetSize); } - public static byte[] makeArray(@NotNull Consumer<@NotNull NetworkBuffer> writing) { - NetworkBuffer writer = new NetworkBuffer(); - writing.accept(writer); - byte[] bytes = new byte[writer.writeIndex]; - writer.copyTo(0, bytes, 0, bytes.length); - return bytes; + static byte[] makeArray(@NotNull Consumer<@NotNull NetworkBuffer> writing, @Nullable Registries registries) { + NetworkBuffer buffer = resizableBuffer(256, registries); + writing.accept(buffer); + return buffer.read(RAW_BYTES); + } + + static byte[] makeArray(@NotNull Consumer<@NotNull NetworkBuffer> writing) { + return makeArray(writing, null); + } + + static byte[] makeArray(@NotNull Type type, @NotNull T value, @Nullable Registries registries) { + return makeArray(buffer -> buffer.write(type, value), registries); + } + + static byte[] makeArray(@NotNull Type type, @NotNull T value) { + return makeArray(type, value, null); + } + + static void copy(NetworkBuffer srcBuffer, long srcOffset, + NetworkBuffer dstBuffer, long dstOffset, long length) { + NetworkBufferImpl.copy(srcBuffer, srcOffset, dstBuffer, dstOffset, length); + } + + static boolean equals(NetworkBuffer buffer1, NetworkBuffer buffer2) { + return NetworkBufferImpl.equals(buffer1, buffer2); } } diff --git a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java new file mode 100644 index 000000000..2617349d2 --- /dev/null +++ b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java @@ -0,0 +1,575 @@ +package net.minestom.server.network; + +import net.minestom.server.registry.Registries; +import net.minestom.server.utils.ObjectPool; +import net.minestom.server.utils.nbt.BinaryTagReader; +import net.minestom.server.utils.nbt.BinaryTagWriter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import javax.crypto.Cipher; +import javax.crypto.ShortBufferException; +import java.io.EOFException; +import java.io.IOException; +import java.lang.ref.Cleaner; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SocketChannel; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import static net.minestom.server.network.NetworkBufferUnsafe.*; + +final class NetworkBufferImpl implements NetworkBuffer { + private static final Cleaner CLEANER = Cleaner.create(); + private static final long DUMMY_ADDRESS = -1; + + private final NetworkBufferImpl parent; // Used for slices so we can control GC over the parent buffer + private final BufferCleaner state; + // Address may be -1 if the buffer is a dummy buffer + // Dummy buffers are used for size calculations and do not have memory allocated + private long address, capacity; + private long readIndex, writeIndex; + boolean readOnly; + + BinaryTagWriter nbtWriter; + BinaryTagReader nbtReader; + + final @Nullable AutoResize autoResize; + final @Nullable Registries registries; + + NetworkBufferImpl(NetworkBufferImpl parent, + long address, long capacity, + long readIndex, long writeIndex, + @Nullable AutoResize autoResize, + @Nullable Registries registries) { + this.parent = parent; + this.address = address; + this.capacity = capacity; + this.readIndex = readIndex; + this.writeIndex = writeIndex; + this.autoResize = autoResize; + this.registries = registries; + + this.state = new BufferCleaner(new AtomicLong(address)); + if (this.parent == null && address != DUMMY_ADDRESS) CLEANER.register(this, state); + } + + private record BufferCleaner(AtomicLong address) implements Runnable { + @Override + public void run() { + UNSAFE.freeMemory(address.get()); + } + } + + @Override + public void write(@NotNull Type type, @UnknownNullability T value) { + assertReadOnly(); + type.write(this, value); + } + + @Override + public @UnknownNullability T read(@NotNull Type type) { + assertDummy(); + return type.read(this); + } + + @Override + public void writeAt(long index, @NotNull Type type, @UnknownNullability T value) { + assertReadOnly(); + final long oldWriteIndex = writeIndex; + writeIndex = index; + try { + write(type, value); + } finally { + writeIndex = oldWriteIndex; + } + } + + @Override + public @UnknownNullability T readAt(long index, @NotNull Type type) { + assertDummy(); + final long oldReadIndex = readIndex; + readIndex = index; + try { + return read(type); + } finally { + readIndex = oldReadIndex; + } + } + + @Override + public void copyTo(long srcOffset, byte @NotNull [] dest, long destOffset, long length) { + assertDummy(); + assertOverflow(srcOffset + length); + assertOverflow(destOffset + length); + if (length == 0) return; + if (dest.length < destOffset + length) { + throw new IndexOutOfBoundsException("Destination array is too small: " + dest.length + " < " + (destOffset + length)); + } + UNSAFE.copyMemory(null, address + srcOffset, dest, BYTE_ARRAY_OFFSET + destOffset, length); + } + + public byte @NotNull [] extractBytes(@NotNull Consumer<@NotNull NetworkBuffer> extractor) { + assertDummy(); + final long startingPosition = readIndex(); + extractor.accept(this); + final long endingPosition = readIndex(); + final long length = endingPosition - startingPosition; + assertOverflow(length); + byte[] output = new byte[(int) length]; + copyTo(startingPosition, output, 0, output.length); + return output; + } + + public @NotNull NetworkBuffer clear() { + return index(0, 0); + } + + public long writeIndex() { + return writeIndex; + } + + public long readIndex() { + return readIndex; + } + + public @NotNull NetworkBuffer writeIndex(long writeIndex) { + this.writeIndex = writeIndex; + return this; + } + + public @NotNull NetworkBuffer readIndex(long readIndex) { + this.readIndex = readIndex; + return this; + } + + @Override + public @NotNull NetworkBuffer index(long readIndex, long writeIndex) { + this.readIndex = readIndex; + this.writeIndex = writeIndex; + return this; + } + + public long advanceWrite(long length) { + final long oldWriteIndex = writeIndex; + writeIndex += length; + return oldWriteIndex; + } + + @Override + public long advanceRead(long length) { + final long oldReadIndex = readIndex; + readIndex += length; + return oldReadIndex; + } + + @Override + public long readableBytes() { + return writeIndex - readIndex; + } + + @Override + public long writableBytes() { + return capacity() - writeIndex; + } + + @Override + public long capacity() { + return capacity; + } + + @Override + public void readOnly() { + this.readOnly = true; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public void resize(long newSize) { + assertDummy(); + assertReadOnly(); + if (newSize < capacity) throw new IllegalArgumentException("New size is smaller than the current size"); + if (newSize == capacity) throw new IllegalArgumentException("New size is the same as the current size"); + final long newAddress = UNSAFE.reallocateMemory(address, newSize); + this.address = newAddress; + this.capacity = newSize; + this.state.address.set(newAddress); + } + + @Override + public void ensureWritable(long length) { + assertReadOnly(); + if (writableBytes() >= length) return; + final long newCapacity = newCapacity(length, capacity()); + resize(newCapacity); + } + + private long newCapacity(long length, long capacity) { + final long targetSize = writeIndex + length; + final AutoResize strategy = this.autoResize; + if (strategy == null) + throw new IndexOutOfBoundsException("Buffer is full and cannot be resized: " + capacity + " -> " + targetSize); + final long newCapacity = strategy.resize(capacity, targetSize); + if (newCapacity == capacity) + throw new IndexOutOfBoundsException("Buffer is full has been resized to the same capacity: " + capacity + " -> " + targetSize); + return newCapacity; + } + + @Override + public void compact() { + assertDummy(); + assertReadOnly(); + ByteBuffer nioBuffer = bufferSlice((int) readIndex, (int) readableBytes()); + nioBuffer.compact(); + writeIndex -= readIndex; + readIndex = 0; + } + + @Override + public NetworkBuffer slice(long index, long length, long readIndex, long writeIndex) { + assertDummy(); + Objects.checkFromIndexSize(index, length, capacity); + NetworkBufferImpl slice = new NetworkBufferImpl(this, + address + index, length, + readIndex, writeIndex, + autoResize, registries); + slice.readOnly = readOnly; + return slice; + } + + @Override + public NetworkBuffer copy(long index, long length, long readIndex, long writeIndex) { + assertDummy(); + Objects.checkFromIndexSize(index, length, capacity); + final long newAddress = UNSAFE.allocateMemory(length); + if (newAddress == 0) { + throw new OutOfMemoryError("Failed to allocate memory"); + } + UNSAFE.copyMemory(address + index, newAddress, length); + return new NetworkBufferImpl(null, + newAddress, length, + readIndex, writeIndex, + autoResize, registries); + } + + @Override + public int readChannel(ReadableByteChannel channel) throws IOException { + assertDummy(); + assertReadOnly(); + assertOverflow(writeIndex + writableBytes()); + var buffer = bufferSlice((int) writeIndex, (int) writableBytes()); + final int count = channel.read(buffer); + if (count == -1) throw new EOFException("Disconnected"); + advanceWrite(count); + return count; + } + + @Override + public boolean writeChannel(SocketChannel channel) throws IOException { + assertDummy(); + final long readableBytes = readableBytes(); + if (readableBytes == 0) return true; // Nothing to write + assertOverflow(readIndex + readableBytes); + var buffer = bufferSlice((int) readIndex, (int) readableBytes); + if (!buffer.hasRemaining()) + return true; // Nothing to write + final int count = channel.write(buffer); + if (count == -1) throw new EOFException("Disconnected"); + advanceRead(count); + return !buffer.hasRemaining(); + } + + @Override + public void cipher(Cipher cipher, long start, long length) { + assertDummy(); + assertOverflow(start + length); + ByteBuffer input = bufferSlice((int) start, (int) length); + try { + cipher.update(input, input.duplicate()); + } catch (ShortBufferException e) { + throw new RuntimeException(e); + } + } + + private static final ObjectPool DEFLATER_POOL = ObjectPool.pool(Deflater::new); + private static final ObjectPool INFLATER_POOL = ObjectPool.pool(Inflater::new); + + @Override + public long compress(long start, long length, NetworkBuffer output) { + assertDummy(); + impl(output).assertReadOnly(); + assertOverflow(start + length); + + ByteBuffer input = bufferSlice((int) start, (int) length); + ByteBuffer outputBuffer = impl(output).bufferSlice((int) output.writeIndex(), (int) output.writableBytes()); + + Deflater deflater = DEFLATER_POOL.get(); + try { + deflater.setInput(input); + deflater.finish(); + final int bytes = deflater.deflate(outputBuffer); + deflater.reset(); + output.advanceWrite(bytes); + return bytes; + } finally { + DEFLATER_POOL.add(deflater); + } + } + + @Override + public long decompress(long start, long length, NetworkBuffer output) throws DataFormatException { + assertDummy(); + impl(output).assertReadOnly(); + assertOverflow(start + length); + + ByteBuffer input = bufferSlice((int) start, (int) length); + ByteBuffer outputBuffer = impl(output).bufferSlice((int) output.writeIndex(), (int) output.writableBytes()); + + Inflater inflater = INFLATER_POOL.get(); + try { + inflater.setInput(input); + final int bytes = inflater.inflate(outputBuffer); + inflater.reset(); + output.advanceWrite(bytes); + return bytes; + } finally { + INFLATER_POOL.add(inflater); + } + } + + @Override + public @Nullable Registries registries() { + return registries; + } + + private ByteBuffer bufferSlice(int position, int length) { + ByteBuffer buffer = ByteBuffer.allocateDirect(0).order(ByteOrder.BIG_ENDIAN); + updateAddress(buffer, address); + updateCapacity(buffer, (int) capacity); + buffer.limit(position + length).position(position); + return buffer; + } + + @Override + public String toString() { + return String.format("NetworkBuffer{r%d|w%d->%d, registries=%s, autoResize=%s, readOnly=%s}", + readIndex, writeIndex, capacity, registries != null, autoResize != null, readOnly); + } + + private static final boolean ENDIAN_CONVERSION = ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN; + + private boolean isDummy() { + return address == DUMMY_ADDRESS; + } + + // Internal writing methods + void _putBytes(long index, byte[] value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, value.length, capacity); + UNSAFE.copyMemory(value, BYTE_ARRAY_OFFSET, null, address + index, value.length); + } + + void _getBytes(long index, byte[] value) { + assertDummy(); + Objects.checkFromIndexSize(index, value.length, capacity); + UNSAFE.copyMemory(null, address + index, value, BYTE_ARRAY_OFFSET, value.length); + } + + void _putByte(long index, byte value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Byte.BYTES, capacity); + UNSAFE.putByte(address + index, value); + } + + byte _getByte(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Byte.BYTES, capacity); + return UNSAFE.getByte(address + index); + } + + void _putShort(long index, short value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Short.BYTES, capacity); + if (ENDIAN_CONVERSION) value = Short.reverseBytes(value); + UNSAFE.putShort(address + index, value); + } + + short _getShort(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Short.BYTES, capacity); + final short value = UNSAFE.getShort(address + index); + return ENDIAN_CONVERSION ? Short.reverseBytes(value) : value; + } + + void _putInt(long index, int value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Integer.BYTES, capacity); + if (ENDIAN_CONVERSION) value = Integer.reverseBytes(value); + UNSAFE.putInt(address + index, value); + } + + int _getInt(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Integer.BYTES, capacity); + final int value = UNSAFE.getInt(address + index); + return ENDIAN_CONVERSION ? Integer.reverseBytes(value) : value; + } + + void _putLong(long index, long value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Long.BYTES, capacity); + if (ENDIAN_CONVERSION) value = Long.reverseBytes(value); + UNSAFE.putLong(address + index, value); + } + + long _getLong(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Long.BYTES, capacity); + final long value = UNSAFE.getLong(address + index); + return ENDIAN_CONVERSION ? Long.reverseBytes(value) : value; + } + + void _putFloat(long index, float value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Float.BYTES, capacity); + int intValue = Float.floatToIntBits(value); + if (ENDIAN_CONVERSION) intValue = Integer.reverseBytes(intValue); + UNSAFE.putInt(address + index, intValue); + } + + float _getFloat(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Float.BYTES, capacity); + int intValue = UNSAFE.getInt(address + index); + if (ENDIAN_CONVERSION) intValue = Integer.reverseBytes(intValue); + return Float.intBitsToFloat(intValue); + } + + void _putDouble(long index, double value) { + if (isDummy()) return; + assertReadOnly(); + Objects.checkFromIndexSize(index, Double.BYTES, capacity); + long longValue = Double.doubleToLongBits(value); + if (ENDIAN_CONVERSION) longValue = Long.reverseBytes(longValue); + UNSAFE.putLong(address + index, longValue); + } + + double _getDouble(long index) { + assertDummy(); + Objects.checkFromIndexSize(index, Double.BYTES, capacity); + long longValue = UNSAFE.getLong(address + index); + if (ENDIAN_CONVERSION) longValue = Long.reverseBytes(longValue); + return Double.longBitsToDouble(longValue); + } + + static NetworkBuffer wrap(byte @NotNull [] bytes, long readIndex, long writeIndex, @Nullable Registries registries) { + var buffer = new Builder(bytes.length).registry(registries).build(); + buffer.writeAt(0, NetworkBuffer.RAW_BYTES, bytes); + buffer.index(readIndex, writeIndex); + return buffer; + } + + static void copy(NetworkBuffer srcBuffer, long srcOffset, + NetworkBuffer dstBuffer, long dstOffset, long length) { + var src = impl(srcBuffer); + var dst = impl(dstBuffer); + dst.assertReadOnly(); + Objects.checkFromIndexSize(srcOffset, length, src.capacity); + Objects.checkFromIndexSize(dstOffset, length, dst.capacity); + final long srcAddress = src.address + srcOffset; + final long dstAddress = dst.address + dstOffset; + UNSAFE.copyMemory(srcAddress, dstAddress, length); + } + + public static boolean equals(NetworkBuffer buffer1, NetworkBuffer buffer2) { + var impl1 = impl(buffer1); + var impl2 = impl(buffer2); + final int capacity = (int) impl1.capacity; + if (capacity != impl2.capacity) return false; + final long address1 = impl1.address; + final long address2 = impl2.address; + for (long i = 0; i < capacity; i++) { + if (UNSAFE.getByte(address1 + i) != UNSAFE.getByte(address2 + i)) { + return false; + } + } + return true; + } + + void assertReadOnly() { + if (readOnly) throw new UnsupportedOperationException("Buffer is read-only"); + } + + void assertDummy() { + if (isDummy()) throw new UnsupportedOperationException("Buffer is a dummy buffer"); + } + + static final class Builder implements NetworkBuffer.Builder { + private final long initialSize; + private AutoResize autoResize; + private Registries registries; + + public Builder(long initialSize) { + this.initialSize = initialSize; + } + + @Override + public NetworkBuffer.@NotNull Builder autoResize(@Nullable AutoResize autoResize) { + this.autoResize = autoResize; + return this; + } + + @Override + public NetworkBuffer.@NotNull Builder registry(Registries registries) { + this.registries = registries; + return this; + } + + @Override + public @NotNull NetworkBuffer build() { + final long address = UNSAFE.allocateMemory(initialSize); + return new NetworkBufferImpl(null, + address, initialSize, + 0, 0, + autoResize, registries); + } + } + + static NetworkBufferImpl dummy(Registries registries) { + // Dummy buffer with no memory allocated + // Useful for size calculations + return new NetworkBufferImpl(null, + DUMMY_ADDRESS, Long.MAX_VALUE, + 0, 0, + null, registries); + } + + static NetworkBufferImpl impl(NetworkBuffer buffer) { + return (NetworkBufferImpl) buffer; + } + + private static void assertOverflow(long value) { + try { + Math.toIntExact(value); // Check if long is within the bounds of an int + } catch (ArithmeticException e) { + throw new RuntimeException("Method does not support long values: " + value); + } + } +} diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java index d6de109a8..9dc142577 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java @@ -58,6 +58,21 @@ public final class NetworkBufferTemplate { R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); } + @FunctionalInterface + public interface F11 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11); + } + + @FunctionalInterface + public interface F12 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12); + } + + @FunctionalInterface + public interface F19 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19); + } + public static Type template(Supplier supplier) { return new NetworkBufferTypeImpl<>() { @Override @@ -331,4 +346,135 @@ public final class NetworkBufferTemplate { } }; } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, F11 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, F12 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, Type p16, Function g16, + Type p17, Function g17, Type p18, Function g18, + Type p19, Function g19, F19 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + p16.write(buffer, g16.apply(value)); + p17.write(buffer, g17.apply(value)); + p18.write(buffer, g18.apply(value)); + p19.write(buffer, g19.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer), p16.read(buffer), + p17.read(buffer), p18.read(buffer), + p19.read(buffer) + ); + } + }; + } } diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java index 81e487af4..b911b5c47 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java @@ -1,13 +1,13 @@ package net.minestom.server.network; import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; -import net.minestom.server.network.packet.server.play.data.WorldPos; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.registry.ProtocolObject; import net.minestom.server.registry.Registries; @@ -20,12 +20,12 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBufferImpl.impl; interface NetworkBufferTypeImpl extends NetworkBuffer.Type { int SEGMENT_BITS = 0x7F; @@ -45,15 +45,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record BooleanType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Boolean value) { - buffer.ensureSize(1); - buffer.nioBuffer.put(buffer.writeIndex(), value ? (byte) 1 : (byte) 0); - buffer.writeIndex += 1; + buffer.ensureWritable(1); + impl(buffer)._putByte(buffer.writeIndex(), value ? (byte) 1 : (byte) 0); + buffer.advanceWrite(1); } @Override public Boolean read(@NotNull NetworkBuffer buffer) { - final byte value = buffer.nioBuffer.get(buffer.readIndex()); - buffer.readIndex += 1; + final byte value = impl(buffer)._getByte(buffer.readIndex()); + buffer.advanceRead(1); return value == 1; } } @@ -61,15 +61,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record ByteType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Byte value) { - buffer.ensureSize(1); - buffer.nioBuffer.put(buffer.writeIndex(), value); - buffer.writeIndex += 1; + buffer.ensureWritable(1); + impl(buffer)._putByte(buffer.writeIndex(), value); + buffer.advanceWrite(1); } @Override public Byte read(@NotNull NetworkBuffer buffer) { - final byte value = buffer.nioBuffer.get(buffer.readIndex()); - buffer.readIndex += 1; + final byte value = impl(buffer)._getByte(buffer.readIndex()); + buffer.advanceRead(1); return value; } } @@ -77,15 +77,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record ShortType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Short value) { - buffer.ensureSize(2); - buffer.nioBuffer.putShort(buffer.writeIndex(), value); - buffer.writeIndex += 2; + buffer.ensureWritable(2); + impl(buffer)._putShort(buffer.writeIndex(), value); + buffer.advanceWrite(2); } @Override public Short read(@NotNull NetworkBuffer buffer) { - final short value = buffer.nioBuffer.getShort(buffer.readIndex()); - buffer.readIndex += 2; + final short value = impl(buffer)._getShort(buffer.readIndex()); + buffer.advanceRead(2); return value; } } @@ -93,15 +93,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record UnsignedShortType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Integer value) { - buffer.ensureSize(2); - buffer.nioBuffer.putShort(buffer.writeIndex(), (short) (value & 0xFFFF)); - buffer.writeIndex += 2; + buffer.ensureWritable(2); + impl(buffer)._putShort(buffer.writeIndex(), (short) (value & 0xFFFF)); + buffer.advanceWrite(2); } @Override public Integer read(@NotNull NetworkBuffer buffer) { - final short value = buffer.nioBuffer.getShort(buffer.readIndex()); - buffer.readIndex += 2; + final short value = impl(buffer)._getShort(buffer.readIndex()); + buffer.advanceRead(2); return value & 0xFFFF; } } @@ -109,15 +109,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record IntType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Integer value) { - buffer.ensureSize(4); - buffer.nioBuffer.putInt(buffer.writeIndex(), value); - buffer.writeIndex += 4; + buffer.ensureWritable(4); + impl(buffer)._putInt(buffer.writeIndex(), value); + buffer.advanceWrite(4); } @Override public Integer read(@NotNull NetworkBuffer buffer) { - final int value = buffer.nioBuffer.getInt(buffer.readIndex()); - buffer.readIndex += 4; + final int value = impl(buffer)._getInt(buffer.readIndex()); + buffer.advanceRead(4); return value; } } @@ -125,15 +125,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record LongType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Long value) { - buffer.ensureSize(8); - buffer.nioBuffer.putLong(buffer.writeIndex(), value); - buffer.writeIndex += 8; + buffer.ensureWritable(8); + impl(buffer)._putLong(buffer.writeIndex(), value); + buffer.advanceWrite(8); } @Override public Long read(@NotNull NetworkBuffer buffer) { - final long value = buffer.nioBuffer.getLong(buffer.readIndex()); - buffer.readIndex += 8; + final long value = impl(buffer)._getLong(buffer.readIndex()); + buffer.advanceRead(8); return value; } } @@ -141,15 +141,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record FloatType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Float value) { - buffer.ensureSize(4); - buffer.nioBuffer.putFloat(buffer.writeIndex(), value); - buffer.writeIndex += 4; + buffer.ensureWritable(4); + impl(buffer)._putFloat(buffer.writeIndex(), value); + buffer.advanceWrite(4); } @Override public Float read(@NotNull NetworkBuffer buffer) { - final float value = buffer.nioBuffer.getFloat(buffer.readIndex()); - buffer.readIndex += 4; + final float value = impl(buffer)._getFloat(buffer.readIndex()); + buffer.advanceRead(4); return value; } } @@ -157,15 +157,15 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record DoubleType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Double value) { - buffer.ensureSize(8); - buffer.nioBuffer.putDouble(buffer.writeIndex(), value); - buffer.writeIndex += 8; + buffer.ensureWritable(8); + impl(buffer)._putDouble(buffer.writeIndex(), value); + buffer.advanceWrite(8); } @Override public Double read(@NotNull NetworkBuffer buffer) { - final double value = buffer.nioBuffer.getDouble(buffer.readIndex()); - buffer.readIndex += 8; + final double value = impl(buffer)._getDouble(buffer.readIndex()); + buffer.advanceRead(8); return value; } } @@ -173,67 +173,73 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record VarIntType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Integer boxed) { - final int value = boxed; - final int index = buffer.writeIndex(); - if ((value & (0xFFFFFFFF << 7)) == 0) { - buffer.ensureSize(1); - buffer.nioBuffer.put(index, (byte) value); - buffer.writeIndex += 1; - } else if ((value & (0xFFFFFFFF << 14)) == 0) { - buffer.ensureSize(2); - buffer.nioBuffer.putShort(index, (short) ((value & 0x7F | 0x80) << 8 | (value >>> 7))); - buffer.writeIndex += 2; - } else if ((value & (0xFFFFFFFF << 21)) == 0) { - buffer.ensureSize(3); - var nio = buffer.nioBuffer; - nio.put(index, (byte) (value & 0x7F | 0x80)); - nio.put(index + 1, (byte) ((value >>> 7) & 0x7F | 0x80)); - nio.put(index + 2, (byte) (value >>> 14)); - buffer.writeIndex += 3; - } else if ((value & (0xFFFFFFFF << 28)) == 0) { - buffer.ensureSize(4); - var nio = buffer.nioBuffer; - nio.putInt(index, (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21)); - buffer.writeIndex += 4; - } else { - buffer.ensureSize(5); - var nio = buffer.nioBuffer; - nio.putInt(index, (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80)); - nio.put(index + 4, (byte) (value >>> 28)); - buffer.writeIndex += 5; + buffer.ensureWritable(5); + long index = buffer.writeIndex(); + int value = boxed; + var nio = impl(buffer); + while (true) { + if ((value & ~SEGMENT_BITS) == 0) { + nio._putByte(index++, (byte) value); + buffer.advanceWrite(index - buffer.writeIndex()); + return; + } + nio._putByte(index++, (byte) ((byte) (value & SEGMENT_BITS) | CONTINUE_BIT)); + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; } } @Override public Integer read(@NotNull NetworkBuffer buffer) { - int index = buffer.readIndex(); + long index = buffer.readIndex(); // https://github.com/jvm-profiling-tools/async-profiler/blob/a38a375dc62b31a8109f3af97366a307abb0fe6f/src/converter/one/jfr/JfrReader.java#L393 int result = 0; for (int shift = 0; ; shift += 7) { - byte b = buffer.nioBuffer.get(index++); + byte b = impl(buffer)._getByte(index++); result |= (b & 0x7f) << shift; if (b >= 0) { - buffer.readIndex += index - buffer.readIndex(); + buffer.advanceRead(index - buffer.readIndex()); return result; } } } } + record VarInt3Type() implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, Integer boxed) { + final int value = boxed; + // Value must be between 0 and 2^21 + Check.argCondition(value < 0 || value >= (1 << 21), "VarInt3 out of bounds: {0}", value); + buffer.ensureWritable(3); + final long startIndex = buffer.writeIndex(); + var impl = impl(buffer); + impl._putByte(startIndex, (byte) (value & 0x7F | 0x80)); + impl._putByte(startIndex + 1, (byte) ((value >>> 7) & 0x7F | 0x80)); + impl._putByte(startIndex + 2, (byte) (value >>> 14)); + buffer.advanceWrite(3); + } + + @Override + public Integer read(@NotNull NetworkBuffer buffer) { + // Ensure that the buffer can read other var-int sizes + // The optimization is mostly relevant for writing + return buffer.read(VAR_INT); + } + } + record VarLongType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Long value) { - buffer.ensureSize(10); + buffer.ensureWritable(10); int size = 0; while (true) { if ((value & ~((long) SEGMENT_BITS)) == 0) { - buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) value.intValue()); - buffer.writeIndex += size + 1; + impl(buffer)._putByte(buffer.writeIndex() + size, (byte) value.intValue()); + buffer.advanceWrite(size + 1); return; } - buffer.nioBuffer.put(buffer.writeIndex() + size, (byte) (value & SEGMENT_BITS | CONTINUE_BIT)); + impl(buffer)._putByte(buffer.writeIndex() + size, (byte) (value & SEGMENT_BITS | CONTINUE_BIT)); size++; // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone value >>>= 7; @@ -247,34 +253,44 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { int position = 0; byte currentByte; while (true) { - currentByte = buffer.nioBuffer.get(buffer.readIndex() + length); + currentByte = impl(buffer)._getByte(buffer.readIndex() + length); length++; value |= (long) (currentByte & SEGMENT_BITS) << position; if ((currentByte & CONTINUE_BIT) == 0) break; position += 7; if (position >= 64) throw new RuntimeException("VarLong is too big"); } - buffer.readIndex += length; + buffer.advanceRead(length); return value; } } - record RawBytesType() implements NetworkBufferTypeImpl { + record RawBytesType(int length) implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, byte[] value) { - buffer.ensureSize(value.length); - buffer.nioBuffer.put(buffer.writeIndex(), value); - buffer.writeIndex += value.length; + if (length != -1 && value.length != length) { + throw new IllegalArgumentException("Invalid length: " + value.length + " != " + length); + } + final int length = value.length; + if (length == 0) return; + buffer.ensureWritable(length); + impl(buffer)._putBytes(buffer.writeIndex(), value); + buffer.advanceWrite(length); } @Override public byte[] read(@NotNull NetworkBuffer buffer) { - final int limit = buffer.nioBuffer.limit(); - final int length = limit - buffer.readIndex(); - assert length >= 0 : "Invalid remaining: " + length; - final byte[] bytes = new byte[length]; - buffer.nioBuffer.get(buffer.readIndex(), bytes); - buffer.readIndex += length; + long length = buffer.readableBytes(); + if (this.length != -1) { + length = Math.min(length, this.length); + } + if (length == 0) return new byte[0]; + assert length > 0 : "Invalid remaining: " + length; + + final int arrayLength = Math.toIntExact(length); + final byte[] bytes = new byte[arrayLength]; + impl(buffer)._getBytes(buffer.readIndex(), bytes); + buffer.advanceRead(arrayLength); return bytes; } } @@ -283,18 +299,12 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { @Override public void write(@NotNull NetworkBuffer buffer, String value) { final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - buffer.write(VAR_INT, bytes.length); - buffer.write(RAW_BYTES, bytes); + buffer.write(BYTE_ARRAY, bytes); } @Override public String read(@NotNull NetworkBuffer buffer) { - final int length = buffer.read(VAR_INT); - final int remaining = buffer.nioBuffer.limit() - buffer.readIndex(); - Check.argCondition(length > remaining, "String is too long (length: {0}, readable: {1})", length, remaining); - byte[] bytes = new byte[length]; - buffer.nioBuffer.get(buffer.readIndex(), bytes); - buffer.readIndex += length; + final byte[] bytes = buffer.read(BYTE_ARRAY); return new String(bytes, StandardCharsets.UTF_8); } } @@ -323,7 +333,7 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { record NbtType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, BinaryTag value) { - BinaryTagWriter nbtWriter = buffer.nbtWriter; + BinaryTagWriter nbtWriter = impl(buffer).nbtWriter; if (nbtWriter == null) { nbtWriter = new BinaryTagWriter(new DataOutputStream(new OutputStream() { @Override @@ -331,7 +341,7 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { buffer.write(BYTE, (byte) b); } })); - buffer.nbtWriter = nbtWriter; + impl(buffer).nbtWriter = nbtWriter; } try { nbtWriter.writeNameless(value); @@ -342,7 +352,7 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { @Override public BinaryTag read(@NotNull NetworkBuffer buffer) { - BinaryTagReader nbtReader = buffer.nbtReader; + BinaryTagReader nbtReader = impl(buffer).nbtReader; if (nbtReader == null) { nbtReader = new BinaryTagReader(new DataInputStream(new InputStream() { @Override @@ -352,10 +362,10 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { @Override public int available() { - return buffer.readableBytes(); + return (int) buffer.readableBytes(); } })); - buffer.nbtReader = nbtReader; + impl(buffer).nbtReader = nbtReader; } try { return nbtReader.readNameless(); @@ -447,10 +457,10 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { @Override public byte[] read(@NotNull NetworkBuffer buffer) { final int length = buffer.read(VAR_INT); - final byte[] bytes = new byte[length]; - buffer.nioBuffer.get(buffer.readIndex(), bytes); - buffer.readIndex += length; - return bytes; + if (length == 0) return new byte[0]; + final long remaining = buffer.readableBytes(); + Check.argCondition(length > remaining, "String is too long (length: {0}, readable: {1})", length, remaining); + return buffer.read(FixedRawBytes(length)); } } @@ -534,18 +544,6 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } - record DeathLocationType() implements NetworkBufferTypeImpl { - @Override - public void write(@NotNull NetworkBuffer buffer, WorldPos value) { - buffer.writeOptional(value); - } - - @Override - public WorldPos read(@NotNull NetworkBuffer buffer) { - return buffer.readOptional(WorldPos::new); - } - } - record Vector3Type() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Point value) { @@ -580,6 +578,23 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } + record Vector3BType() implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, Point value) { + buffer.write(BYTE, (byte) value.x()); + buffer.write(BYTE, (byte) value.y()); + buffer.write(BYTE, (byte) value.z()); + } + + @Override + public Point read(@NotNull NetworkBuffer buffer) { + final byte x = buffer.read(BYTE); + final byte y = buffer.read(BYTE); + final byte z = buffer.read(BYTE); + return new Vec(x, y, z); + } + } + record QuaternionType() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, float[] value) { @@ -601,27 +616,61 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { // Combinators - record EnumType>(@NotNull Class enumClass) implements NetworkBufferTypeImpl { + record EnumSetType>(@NotNull Class enumType, + E[] values) implements NetworkBufferTypeImpl> { @Override - public void write(@NotNull NetworkBuffer buffer, E value) { - buffer.writeEnum(enumClass, value); + public void write(@NotNull NetworkBuffer buffer, EnumSet value) { + BitSet bitSet = new BitSet(values.length); + for (int i = 0; i < values.length; ++i) { + bitSet.set(i, value.contains(values[i])); + } + final byte[] array = bitSet.toByteArray(); + buffer.write(RAW_BYTES, array); } @Override - public E read(@NotNull NetworkBuffer buffer) { - return buffer.readEnum(enumClass); + public EnumSet read(@NotNull NetworkBuffer buffer) { + final byte[] array = buffer.read(FixedRawBytes((values.length + 7) / 8)); + BitSet bitSet = BitSet.valueOf(array); + EnumSet enumSet = EnumSet.noneOf(enumType); + for (int i = 0; i < values.length; ++i) { + if (bitSet.get(i)) { + enumSet.add(values[i]); + } + } + return enumSet; + } + } + + record FixedBitSetType(int length) implements NetworkBufferTypeImpl { + @Override + public void write(@NotNull NetworkBuffer buffer, BitSet value) { + final int setLength = value.length(); + if (setLength > length) { + throw new IllegalArgumentException("BitSet is larger than expected size (" + setLength + ">" + length + ")"); + } else { + final byte[] array = value.toByteArray(); + buffer.write(RAW_BYTES, array); + } + } + + @Override + public BitSet read(@NotNull NetworkBuffer buffer) { + final byte[] array = buffer.read(FixedRawBytes((length + 7) / 8)); + return BitSet.valueOf(array); } } record OptionalType(@NotNull Type parent) implements NetworkBufferTypeImpl<@Nullable T> { @Override public void write(@NotNull NetworkBuffer buffer, T value) { - buffer.writeOptional(parent, value); + buffer.write(BOOLEAN, value != null); + if (value != null) buffer.write(parent, value); } @Override public T read(@NotNull NetworkBuffer buffer) { - return buffer.readOptional(parent); + return buffer.read(BOOLEAN) ? buffer.read(parent) : null; } } @@ -646,8 +695,8 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } - record MappedType(@NotNull Type parent, @NotNull Function to, - @NotNull Function from) implements NetworkBufferTypeImpl { + record TransformType(@NotNull Type parent, @NotNull Function to, + @NotNull Function from) implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, S value) { parent.write(buffer, from.apply(value)); @@ -659,27 +708,51 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } - record ListType(@NotNull Type parent, int maxSize) implements NetworkBufferTypeImpl> { + record MapType(@NotNull Type parent, @NotNull NetworkBuffer.Type valueType, + int maxSize) implements NetworkBufferTypeImpl> { @Override - public void write(@NotNull NetworkBuffer buffer, List value) { - buffer.writeCollection(parent, value); + public void write(@NotNull NetworkBuffer buffer, Map map) { + buffer.write(VAR_INT, map.size()); + for (Map.Entry entry : map.entrySet()) { + buffer.write(parent, entry.getKey()); + buffer.write(valueType, entry.getValue()); + } } + @SuppressWarnings("unchecked") @Override - public List read(@NotNull NetworkBuffer buffer) { - return buffer.readCollection(parent, maxSize); + public Map read(@NotNull NetworkBuffer buffer) { + final int size = buffer.read(VAR_INT); + Check.argCondition(size > maxSize, "Map size ({0}) is higher than the maximum allowed size ({1})", size, maxSize); + K[] keys = (K[]) new Object[size]; + V[] values = (V[]) new Object[size]; + for (int i = 0; i < size; i++) { + keys[i] = buffer.read(parent); + values[i] = buffer.read(valueType); + } + return Map.copyOf(new Object2ObjectArrayMap<>(keys, values, size)); } } - record OptionalTypeImpl(@NotNull Type parent) implements NetworkBufferTypeImpl { + record ListType(@NotNull Type parent, int maxSize) implements NetworkBufferTypeImpl> { @Override - public void write(@NotNull NetworkBuffer buffer, T value) { - buffer.writeOptional(parent, value); + public void write(@NotNull NetworkBuffer buffer, List values) { + if (values == null) { + buffer.write(BYTE, (byte) 0); + return; + } + buffer.write(VAR_INT, values.size()); + for (T value : values) buffer.write(parent, value); } + @SuppressWarnings("unchecked") @Override - public T read(@NotNull NetworkBuffer buffer) { - return buffer.readOptional(parent); + public List read(@NotNull NetworkBuffer buffer) { + final int size = buffer.read(VAR_INT); + Check.argCondition(size > maxSize, "Collection size ({0}) is higher than the maximum allowed size ({1})", size, maxSize); + T[] values = (T[]) new Object[size]; + for (int i = 0; i < size; i++) values[i] = buffer.read(parent); + return List.of(values); } } @@ -687,23 +760,31 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { @NotNull Function> selector) implements NetworkBufferTypeImpl> { @Override public void write(@NotNull NetworkBuffer buffer, DynamicRegistry.Key value) { - Check.stateCondition(buffer.registries == null, "Buffer does not have registries"); - final DynamicRegistry registry = selector.apply(buffer.registries); + final Registries registries = impl(buffer).registries; + Check.stateCondition(registries == null, "Buffer does not have registries"); + final DynamicRegistry registry = selector.apply(registries); // Painting variants may be sent in their entirety rather than a registry reference so the ID is offset by 1 to indicate this. // FIXME: Support sending the entire registry object instead of an ID reference. - final int id = registry.id().equals("minecraft:painting_variant")?registry.getId(value)+1:registry.getId(value); + final int id = registry.id().equals("minecraft:painting_variant") ? registry.getId(value) + 1 : registry.getId(value); Check.argCondition(id == -1, "Key is not registered: {0} > {1}", registry, value); buffer.write(VAR_INT, id); } @Override public DynamicRegistry.Key read(@NotNull NetworkBuffer buffer) { - Check.stateCondition(buffer.registries == null, "Buffer does not have registries"); - DynamicRegistry registry = selector.apply(buffer.registries); + final Registries registries = impl(buffer).registries; + Check.stateCondition(registries == null, "Buffer does not have registries"); + DynamicRegistry registry = selector.apply(registries); final int id = buffer.read(VAR_INT); final DynamicRegistry.Key key = registry.getKey(id); Check.argCondition(key == null, "No such ID in registry: {0} > {1}", registry, id); return key; } } + + static long sizeOf(Type type, T value, Registries registries) { + NetworkBuffer buffer = NetworkBufferImpl.dummy(registries); + type.write(buffer, value); + return buffer.writeIndex(); + } } diff --git a/src/main/java/net/minestom/server/network/NetworkBufferUnsafe.java b/src/main/java/net/minestom/server/network/NetworkBufferUnsafe.java new file mode 100644 index 000000000..5e21ed83f --- /dev/null +++ b/src/main/java/net/minestom/server/network/NetworkBufferUnsafe.java @@ -0,0 +1,48 @@ +package net.minestom.server.network; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; +import java.nio.Buffer; +import java.nio.ByteBuffer; + +final class NetworkBufferUnsafe { + static final Unsafe UNSAFE; + + static final Field ADDRESS, CAPACITY; + static final long ADDRESS_OFFSET, CAPACITY_OFFSET; + + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + ADDRESS = Buffer.class.getDeclaredField("address"); + CAPACITY = Buffer.class.getDeclaredField("capacity"); + // Use Unsafe to read value of the address field. This way it will not fail on JDK9+ which + // will forbid changing the access level via reflection. + ADDRESS_OFFSET = UNSAFE.objectFieldOffset(ADDRESS); + CAPACITY_OFFSET = UNSAFE.objectFieldOffset(CAPACITY); + } catch (NoSuchFieldException e) { + throw new AssertionError(e); + } + } + + /** + * The offset, in bytes, between the base memory address of a byte array and its first element. + */ + static final long BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + + static void updateAddress(ByteBuffer buffer, long address) { + UNSAFE.putLong(buffer, ADDRESS_OFFSET, address); + } + + static void updateCapacity(ByteBuffer buffer, int capacity) { + UNSAFE.putInt(buffer, CAPACITY_OFFSET, capacity); + } +} diff --git a/src/main/java/net/minestom/server/network/packet/PacketParser.java b/src/main/java/net/minestom/server/network/packet/PacketParser.java index 522407170..b8c4d2e1e 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketParser.java +++ b/src/main/java/net/minestom/server/network/packet/PacketParser.java @@ -14,15 +14,15 @@ import org.jetbrains.annotations.NotNull; */ public sealed interface PacketParser { - @NotNull PacketRegistry handshakeRegistry(); + @NotNull PacketRegistry handshake(); - @NotNull PacketRegistry statusRegistry(); + @NotNull PacketRegistry status(); - @NotNull PacketRegistry loginRegistry(); + @NotNull PacketRegistry login(); - @NotNull PacketRegistry configurationRegistry(); + @NotNull PacketRegistry configuration(); - @NotNull PacketRegistry playRegistry(); + @NotNull PacketRegistry play(); default @NotNull T parse(@NotNull ConnectionState connectionState, int packetId, @NotNull NetworkBuffer buffer) { @@ -32,20 +32,20 @@ public sealed interface PacketParser { default @NotNull PacketRegistry stateRegistry(@NotNull ConnectionState connectionState) { return switch (connectionState) { - case HANDSHAKE -> handshakeRegistry(); - case STATUS -> statusRegistry(); - case LOGIN -> loginRegistry(); - case CONFIGURATION -> configurationRegistry(); - case PLAY -> playRegistry(); + case HANDSHAKE -> handshake(); + case STATUS -> status(); + case LOGIN -> login(); + case CONFIGURATION -> configuration(); + case PLAY -> play(); }; } record Client( - PacketRegistry handshakeRegistry, - PacketRegistry statusRegistry, - PacketRegistry loginRegistry, - PacketRegistry configurationRegistry, - PacketRegistry playRegistry + PacketRegistry handshake, + PacketRegistry status, + PacketRegistry login, + PacketRegistry configuration, + PacketRegistry play ) implements PacketParser { public Client() { this( @@ -59,11 +59,11 @@ public sealed interface PacketParser { } record Server( - PacketRegistry handshakeRegistry, - PacketRegistry statusRegistry, - PacketRegistry loginRegistry, - PacketRegistry configurationRegistry, - PacketRegistry playRegistry + PacketRegistry handshake, + PacketRegistry status, + PacketRegistry login, + PacketRegistry configuration, + PacketRegistry play ) implements PacketParser { public Server() { this( diff --git a/src/main/java/net/minestom/server/network/packet/PacketReading.java b/src/main/java/net/minestom/server/network/packet/PacketReading.java new file mode 100644 index 000000000..0cf32f889 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/PacketReading.java @@ -0,0 +1,224 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.ServerFlag; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.zip.DataFormatException; + +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +/** + * Tools to read packets from a {@link NetworkBuffer} for network processing. + *

+ * Fairly internal and performance sensitive. + */ +@SuppressWarnings("ALL") +@ApiStatus.Internal +public final class PacketReading { + private final static Logger LOGGER = LoggerFactory.getLogger(PacketReading.class); + + private static final int MAX_VAR_INT_SIZE = 5; + private static final Result.Empty EMPTY_CLIENT_PACKET = new Result.Empty<>(); + + public sealed interface Result { + + /** + * At least one packet was read. + * The buffer may still contain half-read packets and should therefore be compacted for next read. + */ + record Success(List packets, ConnectionState newState) implements Result { + public Success { + if (packets.isEmpty()) { + throw new IllegalArgumentException("Empty packets"); + } + } + + public Success(T packet, ConnectionState newState) { + this(List.of(packet), newState); + } + } + + /** + * Represents no packet to read. Can generally be ignored. + *

+ * Happens when a packet length or payload couldn't be read, but the buffer has enough capacity. + */ + record Empty() implements Result { + } + + /** + * Represents a failure to read a packet due to insufficient buffer capacity. + *

+ * Buffer should be expanded to at least {@code requiredCapacity} bytes. + *

+ * If the buffer does not allow to read the packet length, max var-int length is returned. + */ + record Failure(long requiredCapacity) implements Result { + } + } + + public static Result readClients( + @NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + boolean compressed + ) throws DataFormatException { + return readPackets(buffer, PacketVanilla.CLIENT_PACKET_PARSER, state, PacketVanilla::nextClientState, compressed); + } + + public static Result readServers( + @NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + boolean compressed + ) throws DataFormatException { + return readPackets(buffer, PacketVanilla.SERVER_PACKET_PARSER, state, PacketVanilla::nextServerState, compressed); + } + + public static Result readPackets( + @NotNull NetworkBuffer buffer, + @NotNull PacketParser parser, + @NotNull ConnectionState state, + @NotNull BiFunction stateUpdater, + boolean compressed + ) throws DataFormatException { + List packets = new ArrayList<>(); + readLoop: + while (buffer.readableBytes() > 0) { + final Result result = readPacket(buffer, parser, state, stateUpdater, compressed); + if (buffer.readableBytes() == 0 && packets.isEmpty()) return result; + switch (result) { + case Result.Success success -> { + assert success.packets().size() == 1; + packets.add(success.packets().getFirst()); + state = success.newState(); + } + case Result.Empty ignored -> { + break readLoop; + } + case Result.Failure failure -> { + return packets.isEmpty() ? failure : new Result.Success<>(packets, state); + } + } + } + return !packets.isEmpty() ? new Result.Success<>(packets, state) : EMPTY_CLIENT_PACKET; + } + + public static Result readClient( + @NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + boolean compressed + ) throws DataFormatException { + return readPacket(buffer, PacketVanilla.CLIENT_PACKET_PARSER, state, PacketVanilla::nextClientState, compressed); + } + + public static Result readServer( + @NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + boolean compressed + ) throws DataFormatException { + return readPacket(buffer, PacketVanilla.SERVER_PACKET_PARSER, state, PacketVanilla::nextServerState, compressed); + } + + public static Result readPacket( + @NotNull NetworkBuffer buffer, + @NotNull PacketParser parser, + @NotNull ConnectionState state, + @NotNull BiFunction stateUpdater, + boolean compressed + ) throws DataFormatException { + final long beginMark = buffer.readIndex(); + // READ PACKET LENGTH + final int packetLength; + try { + packetLength = buffer.read(VAR_INT); + } catch (IndexOutOfBoundsException e) { + // Couldn't read a single var-int + return new Result.Failure<>(MAX_VAR_INT_SIZE); + } + final long readerStart = buffer.readIndex(); + if (readerStart > buffer.writeIndex()) { + // Can't read the packet length, buffer has enough capacity + buffer.readIndex(beginMark); + return EMPTY_CLIENT_PACKET; + } + final int maxPacketSize = maxPacketSize(state); + if (packetLength > maxPacketSize) { + throw new DataFormatException("Packet too large: " + packetLength); + } + // READ PAYLOAD https://wiki.vg/Protocol#Packet_format + if (buffer.readableBytes() < packetLength) { + // Can't read the full packet + buffer.readIndex(beginMark); + final long packetLengthVarIntSize = readerStart - beginMark; + final long requiredCapacity = packetLengthVarIntSize + packetLength; + // Must return a failure if the buffer is too small + // Otherwise do nothing, and hope to read the packet remains next time + if (requiredCapacity > buffer.capacity()) return new Result.Failure<>(requiredCapacity); + else return EMPTY_CLIENT_PACKET; + } + NetworkBuffer content = buffer.slice(buffer.readIndex(), packetLength, 0, packetLength); + final PacketRegistry registry = parser.stateRegistry(state); + final T packet = readFramedPacket(content, registry, compressed); + final ConnectionState nextState = stateUpdater.apply(packet, state); + buffer.readIndex(readerStart + packetLength); + return new Result.Success<>(packet, nextState); + } + + private static T readFramedPacket(NetworkBuffer buffer, + PacketRegistry registry, + boolean compressed) throws DataFormatException { + if (!compressed) { + // No compression format + return readPayload(buffer, registry); + } + + final int dataLength = buffer.read(VAR_INT); + if (dataLength == 0) { + // Uncompressed packet + return readPayload(buffer, registry); + } + + // Decompress the packet into the pooled buffer + // and read the uncompressed packet from it + NetworkBuffer decompressed = PacketVanilla.PACKET_POOL.get(); + try { + if (decompressed.capacity() < dataLength) decompressed.resize(dataLength); + buffer.decompress(buffer.readIndex(), buffer.readableBytes(), decompressed); + return readPayload(decompressed, registry); + } finally { + PacketVanilla.PACKET_POOL.add(decompressed); + } + } + + private static T readPayload(NetworkBuffer buffer, PacketRegistry registry) { + final int packetId = buffer.read(VAR_INT); + final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packetId); + final NetworkBuffer.Type serializer = packetInfo.serializer(); + try { + final T packet = serializer.read(buffer); + if (buffer.readableBytes() != 0) { + LOGGER.warn("WARNING: Packet ({}) 0x{} not fully read ({})", + packetInfo.packetClass().getSimpleName(), Integer.toHexString(packetId), buffer); + } + return packet; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static int maxPacketSize(ConnectionState state) { + return switch (state) { + case HANDSHAKE, LOGIN -> ServerFlag.MAX_PACKET_SIZE_PRE_AUTH; + default -> ServerFlag.MAX_PACKET_SIZE; + }; + } +} diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index 7d265e3c4..ddc8baf39 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -25,9 +25,15 @@ public interface PacketRegistry { @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader); - PacketInfo packetInfo(Class packetClass); + PacketInfo packetInfo(@NotNull Class packetClass); - record PacketInfo(Class packetClass, int id, NetworkBuffer.Type serializer) { + default PacketInfo packetInfo(@NotNull T packet) { + return packetInfo(packet.getClass()); + } + + PacketInfo packetInfo(int packetId); + + record PacketInfo(Class packetClass, int id, NetworkBuffer.Type serializer) { } sealed class Client extends PacketRegistryTemplate { @@ -155,7 +161,9 @@ public interface PacketRegistry { final class ServerHandshake extends Server { public ServerHandshake() { - super(); + super( + // Empty + ); } } @@ -336,16 +344,15 @@ public interface PacketRegistry { } } + @SuppressWarnings({"unchecked", "rawtypes"}) sealed class PacketRegistryTemplate implements PacketRegistry { - private final Entry[] suppliers; + private final PacketInfo[] suppliers; private final ClassValue> packetIds = new ClassValue<>() { @Override protected PacketInfo computeValue(@NotNull Class type) { - for (int i = 0; i < suppliers.length; i++) { - final Entry entry = suppliers[i]; - if (entry != null && entry.type == type) { - //noinspection unchecked - return new PacketInfo(entry.type, i, (NetworkBuffer.Type) entry.reader); + for (PacketInfo info : suppliers) { + if (info != null && info.packetClass == type) { + return (PacketInfo) info; } } throw new IllegalStateException("Packet type " + type + " isn't registered!"); @@ -354,26 +361,39 @@ public interface PacketRegistry { @SafeVarargs PacketRegistryTemplate(Entry... suppliers) { - this.suppliers = suppliers; + PacketInfo[] packetInfos = new PacketInfo[suppliers.length]; + for (int i = 0; i < suppliers.length; i++) { + final Entry entry = suppliers[i]; + if (entry == null) continue; + packetInfos[i] = new PacketInfo(entry.type, i, entry.reader); + } + this.suppliers = packetInfos; } public @UnknownNullability T create(int packetId, @NotNull NetworkBuffer reader) { - final Entry entry = suppliers[packetId]; - if (entry == null) - throw new IllegalStateException("Packet id 0x" + Integer.toHexString(packetId) + " isn't registered!"); - final NetworkBuffer.Type supplier = entry.reader; + final PacketInfo info = packetInfo(packetId); + final NetworkBuffer.Type supplier = info.serializer; final T packet = supplier.read(reader); if (packet == null) { - throw new IllegalStateException("Packet " + entry.type + " failed to read!"); + throw new IllegalStateException("Packet " + info.packetClass + " failed to read!"); } return packet; } @Override - public PacketInfo packetInfo(Class packetClass) { + public PacketInfo packetInfo(@NotNull Class packetClass) { return packetIds.get(packetClass); } + @Override + public PacketInfo packetInfo(int packetId) { + final PacketInfo info; + if (packetId < 0 || packetId >= suppliers.length || (info = (PacketInfo) suppliers[packetId]) == null) { + throw new IllegalStateException("Packet id 0x" + Integer.toHexString(packetId) + " isn't registered!"); + } + return info; + } + record Entry(Class type, NetworkBuffer.Type reader) { } diff --git a/src/main/java/net/minestom/server/network/packet/PacketVanilla.java b/src/main/java/net/minestom/server/network/packet/PacketVanilla.java new file mode 100644 index 000000000..f005c5797 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/PacketVanilla.java @@ -0,0 +1,58 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; +import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; +import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; +import net.minestom.server.network.packet.server.login.LoginSuccessPacket; +import net.minestom.server.network.packet.server.play.StartConfigurationPacket; +import net.minestom.server.utils.ObjectPool; +import org.jetbrains.annotations.ApiStatus; + +/** + * Constants and utilities for vanilla packets. + */ +@ApiStatus.Internal +public final class PacketVanilla { + public static final PacketParser CLIENT_PACKET_PARSER = new PacketParser.Client(); + public static final PacketParser SERVER_PACKET_PARSER = new PacketParser.Server(); + + /** + * Pool containing a buffer able to hold the largest packet. + *

+ * Size starts with {@link ServerFlag#POOLED_BUFFER_SIZE} and doubles until {@link ServerFlag#MAX_PACKET_SIZE}. + */ + public static final ObjectPool PACKET_POOL = ObjectPool.pool( + () -> NetworkBuffer.staticBuffer(ServerFlag.POOLED_BUFFER_SIZE, MinecraftServer.process()), + NetworkBuffer::clear); + + public static ConnectionState nextClientState(ClientPacket packet, ConnectionState currentState) { + return switch (packet) { + case ClientHandshakePacket handshakePacket -> switch (handshakePacket.intent()) { + case STATUS -> ConnectionState.STATUS; + case LOGIN, TRANSFER -> ConnectionState.LOGIN; + }; + case ClientLoginAcknowledgedPacket ignored -> ConnectionState.CONFIGURATION; + case ClientFinishConfigurationPacket ignored -> ConnectionState.PLAY; + default -> currentState; + }; + } + + public static ConnectionState nextServerState(ServerPacket packet, ConnectionState currentState) { + // Client chooses between STATUS or LOGIN state directly after the first handshake packet + if (currentState == ConnectionState.HANDSHAKE) + throw new IllegalStateException("No server Handshake packet exists"); + return switch (packet) { + case LoginSuccessPacket ignored -> ConnectionState.CONFIGURATION; + case StartConfigurationPacket ignored -> ConnectionState.CONFIGURATION; + case FinishConfigurationPacket ignored -> ConnectionState.PLAY; + default -> currentState; + }; + } +} diff --git a/src/main/java/net/minestom/server/network/packet/PacketWriting.java b/src/main/java/net/minestom/server/network/packet/PacketWriting.java new file mode 100644 index 000000000..c7f847823 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/PacketWriting.java @@ -0,0 +1,163 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.ServerFlag; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Tools to write packets into a {@link NetworkBuffer} for network processing. + *

+ * Fairly internal and performance sensitive. + */ +@ApiStatus.Internal +public final class PacketWriting { + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + @NotNull ClientPacket packet, + int compressionThreshold) throws IndexOutOfBoundsException { + writeFramedPacket(buffer, PacketVanilla.CLIENT_PACKET_PARSER, state, packet, compressionThreshold); + } + + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull ConnectionState state, + @NotNull ServerPacket packet, + int compressionThreshold) throws IndexOutOfBoundsException { + writeFramedPacket(buffer, PacketVanilla.SERVER_PACKET_PARSER, state, packet, compressionThreshold); + } + + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull PacketParser parser, + @NotNull ConnectionState state, + @NotNull T packet, + int compressionThreshold) throws IndexOutOfBoundsException { + final PacketRegistry registry = parser.stateRegistry(state); + writeFramedPacket(buffer, registry, packet, compressionThreshold); + } + + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull PacketRegistry registry, + @NotNull T packet, + int compressionThreshold) throws IndexOutOfBoundsException { + final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet); + final int id = packetInfo.id(); + final NetworkBuffer.Type serializer = packetInfo.serializer(); + writeFramedPacket( + buffer, serializer, + id, packet, + compressionThreshold + ); + } + + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull NetworkBuffer.Type type, + int id, @NotNull T packet, + int compressionThreshold) throws IndexOutOfBoundsException { + if (compressionThreshold <= 0) writeUncompressedFormat(buffer, type, id, packet); + else writeCompressedFormat(buffer, type, id, packet, compressionThreshold); + } + + private static void writeUncompressedFormat(NetworkBuffer buffer, + NetworkBuffer.Type type, + int id, T packet) throws IndexOutOfBoundsException { + // Uncompressed format https://wiki.vg/Protocol#Without_compression + final long lengthIndex = buffer.advanceWrite(3); + buffer.write(NetworkBuffer.VAR_INT, id); + buffer.write(type, packet); + final long finalSize = buffer.writeIndex() - (lengthIndex + 3); + buffer.writeAt(lengthIndex, NetworkBuffer.VAR_INT_3, (int) finalSize); + } + + private static void writeCompressedFormat(NetworkBuffer buffer, + NetworkBuffer.Type type, + int id, T packet, + int compressionThreshold) throws IndexOutOfBoundsException { + // Compressed format https://wiki.vg/Protocol#With_compression + final long compressedIndex = buffer.advanceWrite(3); + final long uncompressedIndex = buffer.advanceWrite(3); + final long contentStart = buffer.writeIndex(); + buffer.write(NetworkBuffer.VAR_INT, id); + buffer.write(type, packet); + final long packetSize = buffer.writeIndex() - contentStart; + final boolean compressed = packetSize >= compressionThreshold; + if (compressed) { + // Write the compressed content into the pooled buffer + // and compress it into the current buffer + NetworkBuffer input = PacketVanilla.PACKET_POOL.get(); + try { + if (input.capacity() < packetSize) input.resize(packetSize); + NetworkBuffer.copy(buffer, contentStart, input, 0, packetSize); + buffer.writeIndex(contentStart); + input.compress(0, packetSize, buffer); + } finally { + PacketVanilla.PACKET_POOL.add(input); + } + } + // Packet header (Packet + Data Length) + buffer.writeAt(compressedIndex, NetworkBuffer.VAR_INT_3, (int) (buffer.writeIndex() - uncompressedIndex)); + buffer.writeAt(uncompressedIndex, NetworkBuffer.VAR_INT_3, compressed ? (int) packetSize : 0); + } + + public static NetworkBuffer allocateTrimmedPacket(@NotNull ConnectionState state, + @NotNull ClientPacket packet, + int compressionThreshold) { + return allocateTrimmedPacket(PacketVanilla.CLIENT_PACKET_PARSER, state, packet, compressionThreshold); + } + + public static NetworkBuffer allocateTrimmedPacket(@NotNull ConnectionState state, + @NotNull ServerPacket packet, + int compressionThreshold) { + return allocateTrimmedPacket(PacketVanilla.SERVER_PACKET_PARSER, state, packet, compressionThreshold); + } + + public static NetworkBuffer allocateTrimmedPacket( + @NotNull PacketParser parser, + @NotNull ConnectionState state, + @NotNull T packet, + int compressionThreshold) { + NetworkBuffer buffer = PacketVanilla.PACKET_POOL.get(); + try { + return allocateTrimmedPacket(buffer, parser, state, packet, compressionThreshold); + } finally { + PacketVanilla.PACKET_POOL.add(buffer); + } + } + + public static NetworkBuffer allocateTrimmedPacket( + @NotNull NetworkBuffer tmpBuffer, + @NotNull PacketParser parser, + @NotNull ConnectionState state, + @NotNull T packet, + int compressionThreshold) { + final PacketRegistry registry = parser.stateRegistry(state); + return allocateTrimmedPacket(tmpBuffer, registry, packet, compressionThreshold); + } + + public static NetworkBuffer allocateTrimmedPacket( + @NotNull NetworkBuffer tmpBuffer, + @NotNull PacketRegistry registry, + @NotNull T packet, + int compressionThreshold) { + final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet); + final int id = packetInfo.id(); + final NetworkBuffer.Type serializer = packetInfo.serializer(); + try { + writeFramedPacket(tmpBuffer, serializer, id, packet, compressionThreshold); + return tmpBuffer.copy(0, tmpBuffer.writeIndex()); + } catch (IndexOutOfBoundsException e) { + final long sizeOf = serializer.sizeOf(packet, tmpBuffer.registries()); + if (sizeOf > ServerFlag.MAX_PACKET_SIZE) { + throw new IllegalStateException("Packet too large: " + sizeOf); + } + // Add 15 bytes to account for the 3 potential varints in the packet header + // Packet Length - Data Length - Packet ID + tmpBuffer.resize(sizeOf + 15); + tmpBuffer.writeIndex(0); + writeFramedPacket(tmpBuffer, serializer, id, packet, compressionThreshold); + return tmpBuffer.copy(0, tmpBuffer.writeIndex()); + } + } +} 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 dc7da3ce3..1ee86e6b9 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,21 +1,9 @@ package net.minestom.server.network.packet.client; -import org.jetbrains.annotations.ApiStatus; - /** * Represents a packet received from a client. *

* Packets are value-based, and should therefore not be reliant on identity. */ public interface ClientPacket { - /** - * Determines whether this packet should be processed immediately - * or wait until the next server tick. - * - * @return true if this packet should process immediately - */ - @ApiStatus.Internal - default boolean processImmediately() { - return false; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java index a8ea92cec..39f417dcd 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientCookieResponsePacket.java @@ -24,9 +24,4 @@ public record ClientCookieResponsePacket( Check.argCondition(value != null && value.length > CookieStorePacket.MAX_VALUE_LENGTH, "Value is too long: {0} > {1}", value != null ? value.length : 0, CookieStorePacket.MAX_VALUE_LENGTH); } - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java index 5094d30b2..492c6fe6c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientKeepAlivePacket.java @@ -9,9 +9,4 @@ import static net.minestom.server.network.NetworkBuffer.LONG; public record ClientKeepAlivePacket(long id) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( LONG, ClientKeepAlivePacket::id, ClientKeepAlivePacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java index cac7205b4..213915351 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientPingRequestPacket.java @@ -9,9 +9,4 @@ import static net.minestom.server.network.NetworkBuffer.LONG; public record ClientPingRequestPacket(long number) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( LONG, ClientPingRequestPacket::number, ClientPingRequestPacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java index e60c0cba0..e9bb5986e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientPluginMessagePacket.java @@ -5,6 +5,9 @@ import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Objects; + import static net.minestom.server.network.NetworkBuffer.RAW_BYTES; import static net.minestom.server.network.NetworkBuffer.STRING; @@ -18,4 +21,17 @@ public record ClientPluginMessagePacket(@NotNull String channel, byte[] data) im if (channel.length() > 256) throw new IllegalArgumentException("Channel cannot be more than 256 characters long"); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ClientPluginMessagePacket that = (ClientPluginMessagePacket) o; + return Objects.deepEquals(data, that.data) && Objects.equals(channel, that.channel); + } + + @Override + public int hashCode() { + return Objects.hash(channel, Arrays.hashCode(data)); + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java index 5b5660595..087a53c85 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientResourcePackStatusPacket.java @@ -2,31 +2,27 @@ package net.minestom.server.network.packet.client.common; import net.kyori.adventure.resource.ResourcePackStatus; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; import java.util.UUID; +import static net.minestom.server.network.NetworkBuffer.UUID; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + public record ClientResourcePackStatusPacket( @NotNull UUID id, @NotNull ResourcePackStatus status ) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientResourcePackStatusPacket value) { - buffer.write(NetworkBuffer.UUID, value.id); - buffer.write(NetworkBuffer.VAR_INT, statusId(value.status)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + UUID, ClientResourcePackStatusPacket::id, + VAR_INT.transform(ClientResourcePackStatusPacket::readStatus, ClientResourcePackStatusPacket::statusId), ClientResourcePackStatusPacket::status, + ClientResourcePackStatusPacket::new + ); - @Override - public ClientResourcePackStatusPacket read(@NotNull NetworkBuffer buffer) { - return new ClientResourcePackStatusPacket(buffer.read(NetworkBuffer.UUID), readStatus(buffer)); - } - }; - - private static @NotNull ResourcePackStatus readStatus(@NotNull NetworkBuffer reader) { - var ordinal = reader.read(NetworkBuffer.VAR_INT); - return switch (ordinal) { + private static @NotNull ResourcePackStatus readStatus(int id) { + return switch (id) { case 0 -> ResourcePackStatus.SUCCESSFULLY_LOADED; case 1 -> ResourcePackStatus.DECLINED; case 2 -> ResourcePackStatus.FAILED_DOWNLOAD; @@ -35,7 +31,7 @@ public record ClientResourcePackStatusPacket( case 5 -> ResourcePackStatus.INVALID_URL; case 6 -> ResourcePackStatus.FAILED_RELOAD; case 7 -> ResourcePackStatus.DISCARDED; - default -> throw new IllegalStateException("Unexpected resource pack status: " + ordinal); + default -> throw new IllegalStateException("Unexpected resource pack status: " + id); }; } diff --git a/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java b/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java index a71705e88..e71d05f39 100644 --- a/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/handshake/ClientHandshakePacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.handshake; import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -11,40 +12,19 @@ public record ClientHandshakePacket(int protocolVersion, @NotNull String serverA int serverPort, @NotNull Intent intent) implements ClientPacket { public ClientHandshakePacket { - if (serverAddress.length() > getMaxHandshakeLength()) { + if (serverAddress.length() > maxHandshakeLength()) { throw new IllegalArgumentException("Server address too long: " + serverAddress.length()); } } - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientHandshakePacket value) { - buffer.write(VAR_INT, value.protocolVersion); - int maxLength = getMaxHandshakeLength(); - if (value.serverAddress.length() > maxLength) { - throw new IllegalArgumentException("serverAddress is " + value.serverAddress.length() + " characters long, maximum allowed is " + maxLength); - } - buffer.write(STRING, value.serverAddress); - buffer.write(UNSIGNED_SHORT, value.serverPort); - // Not a writeEnum call because the indices are not 0-based - buffer.write(VAR_INT, value.intent.id()); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientHandshakePacket::protocolVersion, + STRING, ClientHandshakePacket::serverAddress, + UNSIGNED_SHORT, ClientHandshakePacket::serverPort, + VAR_INT.transform(Intent::fromId, Intent::id), ClientHandshakePacket::intent, + ClientHandshakePacket::new); - @Override - public @NotNull ClientHandshakePacket read(@NotNull NetworkBuffer buffer) { - return new ClientHandshakePacket(buffer.read(VAR_INT), buffer.read(STRING), - buffer.read(UNSIGNED_SHORT), - // Not a readEnum call because the indices are not 0-based - Intent.fromId(buffer.read(VAR_INT))); - } - }; - - @Override - public boolean processImmediately() { - return true; - } - - private static int getMaxHandshakeLength() { + private static int maxHandshakeLength() { // BungeeGuard limits handshake length to 2500 characters, while vanilla limits it to 255 return BungeeCordProxy.isEnabled() ? (BungeeCordProxy.isBungeeGuardEnabled() ? 2500 : Short.MAX_VALUE) : 255; } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java index 3985a7a26..305063e75 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientEncryptionResponsePacket.java @@ -12,9 +12,4 @@ public record ClientEncryptionResponsePacket(byte[] sharedSecret, BYTE_ARRAY, ClientEncryptionResponsePacket::sharedSecret, BYTE_ARRAY, ClientEncryptionResponsePacket::encryptedVerifyToken, ClientEncryptionResponsePacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java index ae0161c8a..6faeb37cb 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginAcknowledgedPacket.java @@ -6,9 +6,4 @@ import net.minestom.server.network.packet.client.ClientPacket; public record ClientLoginAcknowledgedPacket() implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(ClientLoginAcknowledgedPacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java index 16f933422..8cabccd74 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginPluginResponsePacket.java @@ -11,11 +11,6 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientLoginPluginResponsePacket(int messageId, byte @Nullable [] data) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( VAR_INT, ClientLoginPluginResponsePacket::messageId, - RAW_BYTES, ClientLoginPluginResponsePacket::data, + RAW_BYTES.optional(), ClientLoginPluginResponsePacket::data, ClientLoginPluginResponsePacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java index 9a4dbf2f0..7c5252ecb 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/ClientLoginStartPacket.java @@ -21,9 +21,4 @@ public record ClientLoginStartPacket(@NotNull String username, if (username.length() > 16) throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters"); } - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java index 05140065e..dee86fdd4 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientAdvancementTabPacket.java @@ -10,10 +10,10 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientAdvancementTabPacket(@NotNull AdvancementAction action, @Nullable String tabIdentifier) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, ClientAdvancementTabPacket value) { - buffer.writeEnum(AdvancementAction.class, value.action); + buffer.write(NetworkBuffer.Enum(AdvancementAction.class), value.action); if (value.action == AdvancementAction.OPENED_TAB) { assert value.tabIdentifier != null; buffer.write(STRING, value.tabIdentifier); @@ -22,7 +22,7 @@ public record ClientAdvancementTabPacket(@NotNull AdvancementAction action, @Override public ClientAdvancementTabPacket read(@NotNull NetworkBuffer buffer) { - var action = buffer.readEnum(AdvancementAction.class); + var action = buffer.read(NetworkBuffer.Enum(AdvancementAction.class)); var tabIdentifier = action == AdvancementAction.OPENED_TAB ? buffer.read(STRING) : null; return new ClientAdvancementTabPacket(action, tabIdentifier); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java index 7f194fa1e..cd72053dc 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatMessagePacket.java @@ -1,11 +1,10 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.BitSet; import static net.minestom.server.network.NetworkBuffer.*; @@ -13,22 +12,13 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientChatMessagePacket(String message, long timestamp, long salt, byte @Nullable [] signature, int ackOffset, BitSet ackList) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientChatMessagePacket value) { - buffer.write(STRING, value.message); - buffer.write(LONG, value.timestamp); - buffer.write(LONG, value.salt); - buffer.writeOptional(BYTE_ARRAY, value.signature); - buffer.write(VAR_INT, value.ackOffset); - buffer.write(RAW_BYTES, Arrays.copyOf(value.ackList.toByteArray(), 3)); - } - - @Override - public ClientChatMessagePacket read(@NotNull NetworkBuffer buffer) { - return new ClientChatMessagePacket(buffer.read(STRING), buffer.read(LONG), - buffer.read(LONG), buffer.readOptional(r -> r.readBytes(256)), - buffer.read(VAR_INT), BitSet.valueOf(buffer.readBytes(3))); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientChatMessagePacket::message, + LONG, ClientChatMessagePacket::timestamp, + LONG, ClientChatMessagePacket::salt, + FixedRawBytes(256).optional(), ClientChatMessagePacket::signature, + VAR_INT, ClientChatMessagePacket::ackOffset, + FixedBitSet(20), ClientChatMessagePacket::ackList, + ClientChatMessagePacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java index 7226def8e..42e5a155c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChatSessionUpdatePacket.java @@ -2,19 +2,13 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.crypto.ChatSession; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; public record ClientChatSessionUpdatePacket(@NotNull ChatSession chatSession) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientChatSessionUpdatePacket value) { - buffer.write(value.chatSession); - } - - @Override - public ClientChatSessionUpdatePacket read(@NotNull NetworkBuffer buffer) { - return new ClientChatSessionUpdatePacket(new ChatSession(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + ChatSession.SERIALIZER, ClientChatSessionUpdatePacket::chatSession, + ClientChatSessionUpdatePacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java index 1912ebc99..ff28de0a9 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientInteractEntityPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.entity.PlayerHand; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -9,40 +10,43 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boolean sneaking) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, ClientInteractEntityPacket value) { buffer.write(VAR_INT, value.targetId); buffer.write(VAR_INT, value.type.id()); - buffer.write(value.type); + @SuppressWarnings("unchecked") NetworkBuffer.Type serializer = (NetworkBuffer.Type) typeSerializer(value.type.id()); + buffer.write(serializer, value.type); buffer.write(BOOLEAN, value.sneaking); } @Override public ClientInteractEntityPacket read(@NotNull NetworkBuffer buffer) { - return new ClientInteractEntityPacket(buffer.read(VAR_INT), switch (buffer.read(VAR_INT)) { - case 0 -> new Interact(buffer); - case 1 -> new Attack(); - case 2 -> new InteractAt(buffer); - default -> throw new RuntimeException("Unknown action id"); - }, buffer.read(BOOLEAN)); + final int targetId = buffer.read(VAR_INT); + final Type type = typeSerializer(buffer.read(VAR_INT)).read(buffer); + final boolean sneaking = buffer.read(BOOLEAN); + return new ClientInteractEntityPacket(targetId, type, sneaking); } }; - public sealed interface Type extends Writer - permits Interact, Attack, InteractAt { + private static NetworkBuffer.Type typeSerializer(int id) { + return switch (id) { + case 0 -> Interact.SERIALIZER; + case 1 -> Attack.SERIALIZER; + case 2 -> InteractAt.SERIALIZER; + default -> throw new RuntimeException("Unknown action id"); + }; + } + + public sealed interface Type permits Interact, Attack, InteractAt { int id(); } public record Interact(@NotNull PlayerHand hand) implements Type { - public Interact(@NotNull NetworkBuffer reader) { - this(reader.readEnum(PlayerHand.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeEnum(PlayerHand.class, hand); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(PlayerHand.class), Interact::hand, + Interact::new + ); @Override public int id() { @@ -51,10 +55,7 @@ public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boole } public record Attack() implements Type { - @Override - public void write(@NotNull NetworkBuffer writer) { - // Empty - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(Attack::new); @Override public int id() { @@ -64,18 +65,13 @@ public record ClientInteractEntityPacket(int targetId, @NotNull Type type, boole public record InteractAt(float targetX, float targetY, float targetZ, @NotNull PlayerHand hand) implements Type { - public InteractAt(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT), reader.read(FLOAT), reader.read(FLOAT), - reader.readEnum(PlayerHand.class)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, targetX); - writer.write(FLOAT, targetY); - writer.write(FLOAT, targetZ); - writer.writeEnum(PlayerHand.class, hand); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, InteractAt::targetX, + FLOAT, InteractAt::targetY, + FLOAT, InteractAt::targetZ, + NetworkBuffer.Enum(PlayerHand.class), InteractAt::hand, + InteractAt::new + ); @Override public int id() { diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java index 370afc626..4ff74671e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerBlockPlacementPacket.java @@ -22,6 +22,6 @@ public record ClientPlayerBlockPlacementPacket(@NotNull PlayerHand hand, @NotNul FLOAT, ClientPlayerBlockPlacementPacket::cursorPositionY, FLOAT, ClientPlayerBlockPlacementPacket::cursorPositionZ, BOOLEAN, ClientPlayerBlockPlacementPacket::insideBlock, - INT, ClientPlayerBlockPlacementPacket::sequence, + VAR_INT, ClientPlayerBlockPlacementPacket::sequence, ClientPlayerBlockPlacementPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java index 1baf77fe6..9ef710d4b 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerDiggingPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; @@ -10,22 +11,12 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientPlayerDiggingPacket(@NotNull Status status, @NotNull Point blockPosition, @NotNull BlockFace blockFace, int sequence) implements ClientPacket { - - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientPlayerDiggingPacket value) { - buffer.writeEnum(Status.class, value.status); - buffer.write(BLOCK_POSITION, value.blockPosition); - buffer.write(BYTE, (byte) value.blockFace.ordinal()); - buffer.write(VAR_INT, value.sequence); - } - - @Override - public ClientPlayerDiggingPacket read(@NotNull NetworkBuffer buffer) { - return new ClientPlayerDiggingPacket(buffer.readEnum(Status.class), buffer.read(BLOCK_POSITION), - BlockFace.values()[buffer.read(BYTE)], buffer.read(VAR_INT)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.Enum(Status.class), ClientPlayerDiggingPacket::status, + BLOCK_POSITION, ClientPlayerDiggingPacket::blockPosition, + BYTE.transform(aByte -> BlockFace.values()[aByte], blockFace1 -> (byte) blockFace1.ordinal()), ClientPlayerDiggingPacket::blockFace, + VAR_INT, ClientPlayerDiggingPacket::sequence, + ClientPlayerDiggingPacket::new); public enum Status { STARTED_DIGGING, diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java index 99a218440..2b69d2c45 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetBeaconEffectPacket.java @@ -1,29 +1,16 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.potion.PotionType; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; -import static net.minestom.server.network.NetworkBuffer.VAR_INT; - public record ClientSetBeaconEffectPacket(@Nullable PotionType primaryEffect, @Nullable PotionType secondaryEffect) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientSetBeaconEffectPacket value) { - buffer.write(BOOLEAN, value.primaryEffect != null); - if (value.primaryEffect != null) buffer.write(VAR_INT, value.primaryEffect.id()); - buffer.write(BOOLEAN, value.secondaryEffect != null); - if (value.secondaryEffect != null) buffer.write(VAR_INT, value.secondaryEffect.id()); - } - - @Override - public ClientSetBeaconEffectPacket read(@NotNull NetworkBuffer buffer) { - return new ClientSetBeaconEffectPacket(buffer.read(BOOLEAN) ? PotionType.fromId(buffer.read(VAR_INT)) : null, - buffer.read(BOOLEAN) ? PotionType.fromId(buffer.read(VAR_INT)) : null); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + PotionType.NETWORK_TYPE.optional(), ClientSetBeaconEffectPacket::primaryEffect, + PotionType.NETWORK_TYPE.optional(), ClientSetBeaconEffectPacket::secondaryEffect, + ClientSetBeaconEffectPacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java index 2f5d9dd87..012d38502 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.crypto.ArgumentSignatures; import net.minestom.server.crypto.LastSeenMessages; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -13,23 +14,14 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public record ClientSignedCommandChatPacket(@NotNull String message, long timestamp, long salt, @NotNull ArgumentSignatures signatures, LastSeenMessages.@NotNull Update lastSeenMessages) implements ClientPacket { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientSignedCommandChatPacket value) { - buffer.write(STRING, value.message); - buffer.write(LONG, value.timestamp); - buffer.write(LONG, value.salt); - buffer.write(value.signatures); - buffer.write(value.lastSeenMessages); - } - - @Override - public ClientSignedCommandChatPacket read(@NotNull NetworkBuffer buffer) { - return new ClientSignedCommandChatPacket(buffer.read(STRING), buffer.read(LONG), - buffer.read(LONG), new ArgumentSignatures(buffer), - new LastSeenMessages.Update(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, ClientSignedCommandChatPacket::message, + LONG, ClientSignedCommandChatPacket::timestamp, + LONG, ClientSignedCommandChatPacket::salt, + ArgumentSignatures.SERIALIZER, ClientSignedCommandChatPacket::signatures, + LastSeenMessages.Update.SERIALIZER, ClientSignedCommandChatPacket::lastSeenMessages, + ClientSignedCommandChatPacket::new + ); public ClientSignedCommandChatPacket { Check.argCondition(message.length() > 256, "Message length cannot be greater than 256"); diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java index 6e2705ba0..736f0d741 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateStructureBlockPacket.java @@ -1,11 +1,10 @@ package net.minestom.server.network.packet.client.play; import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.utils.Rotation; -import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; @@ -15,37 +14,22 @@ public record ClientUpdateStructureBlockPacket(Point location, Action action, Mirror mirror, Rotation rotation, String metadata, float integrity, long seed, byte flags) implements ClientPacket { - public static final NetworkBuffer.Type SERIALIZER = new Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ClientUpdateStructureBlockPacket value) { - buffer.write(BLOCK_POSITION, value.location); - buffer.writeEnum(Action.class, value.action); - buffer.writeEnum(Mode.class, value.mode); - buffer.write(STRING, value.name); - buffer.write(BYTE, (byte) value.offset.x()); - buffer.write(BYTE, (byte) value.offset.y()); - buffer.write(BYTE, (byte) value.offset.z()); - buffer.write(BYTE, (byte) value.size.x()); - buffer.write(BYTE, (byte) value.size.y()); - buffer.write(BYTE, (byte) value.size.z()); - buffer.write(VAR_INT, value.mirror.ordinal()); - buffer.write(VAR_INT, toRestrictedRotation(value.rotation)); - buffer.write(STRING, value.metadata); - buffer.write(FLOAT, value.integrity); - buffer.write(VAR_LONG, value.seed); - buffer.write(BYTE, value.flags); - } - @Override - public ClientUpdateStructureBlockPacket read(@NotNull NetworkBuffer buffer) { - return new ClientUpdateStructureBlockPacket(buffer.read(BLOCK_POSITION), buffer.readEnum(Action.class), - buffer.readEnum(Mode.class), buffer.read(STRING), - new Vec(buffer.read(BYTE), buffer.read(BYTE), buffer.read(BYTE)), new Vec(buffer.read(BYTE), buffer.read(BYTE), buffer.read(BYTE)), - Mirror.values()[buffer.read(VAR_INT)], fromRestrictedRotation(buffer.read(VAR_INT)), - buffer.read(STRING), buffer.read(FLOAT), - buffer.read(VAR_LONG), buffer.read(BYTE)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, ClientUpdateStructureBlockPacket::location, + NetworkBuffer.Enum(Action.class), ClientUpdateStructureBlockPacket::action, + NetworkBuffer.Enum(Mode.class), ClientUpdateStructureBlockPacket::mode, + STRING, ClientUpdateStructureBlockPacket::name, + VECTOR3B, ClientUpdateStructureBlockPacket::offset, + VECTOR3B, ClientUpdateStructureBlockPacket::size, + Enum(Mirror.class), ClientUpdateStructureBlockPacket::mirror, + VAR_INT.transform(ClientUpdateStructureBlockPacket::fromRestrictedRotation, ClientUpdateStructureBlockPacket::toRestrictedRotation), ClientUpdateStructureBlockPacket::rotation, + STRING, ClientUpdateStructureBlockPacket::metadata, + FLOAT, ClientUpdateStructureBlockPacket::integrity, + LONG, ClientUpdateStructureBlockPacket::seed, + BYTE, ClientUpdateStructureBlockPacket::flags, + ClientUpdateStructureBlockPacket::new + ); // Flag values public static final byte IGNORE_ENTITIES = 0x1; diff --git a/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java b/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java index 27c9932da..b1118fd5d 100644 --- a/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/status/StatusRequestPacket.java @@ -6,9 +6,4 @@ import net.minestom.server.network.packet.client.ClientPacket; public record StatusRequestPacket() implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(StatusRequestPacket::new); - - @Override - public boolean processImmediately() { - return true; - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/BufferedPacket.java b/src/main/java/net/minestom/server/network/packet/server/BufferedPacket.java new file mode 100644 index 000000000..79d5d876d --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/BufferedPacket.java @@ -0,0 +1,18 @@ +package net.minestom.server.network.packet.server; + +import net.minestom.server.network.NetworkBuffer; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a buffer to directly write to the network. + *

+ * May contain multiple packets. + */ +@ApiStatus.Internal +public record BufferedPacket(@NotNull NetworkBuffer buffer, + long index, long length) implements SendablePacket { + public BufferedPacket { + buffer.readOnly(); + } +} diff --git a/src/main/java/net/minestom/server/network/packet/server/CachedPacket.java b/src/main/java/net/minestom/server/network/packet/server/CachedPacket.java index cf35b9a4d..e818a249b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/CachedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/CachedPacket.java @@ -1,14 +1,15 @@ package net.minestom.server.network.packet.server; -import net.minestom.server.network.ConnectionState; +import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketWriting; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; -import java.nio.ByteBuffer; import java.util.function.Supplier; /** @@ -40,7 +41,7 @@ public final class CachedPacket implements SendablePacket { return cache != null ? cache.packet() : packetSupplier.get(); } - public @Nullable ByteBuffer body(@NotNull ConnectionState state) { + public @Nullable NetworkBuffer body(@NotNull ConnectionState state) { FramedPacket cache = updatedCache(state); return cache != null ? cache.body() : null; } @@ -51,13 +52,24 @@ public final class CachedPacket implements SendablePacket { SoftReference ref = packet; FramedPacket cache; if (ref == null || (cache = ref.get()) == null) { - cache = PacketUtils.allocateTrimmedPacket(state, packetSupplier.get()); + final ServerPacket packet = packetSupplier.get(); + final NetworkBuffer buffer = PacketWriting.allocateTrimmedPacket(state, packet, + MinecraftServer.getCompressionThreshold()); + cache = new FramedPacket(packet, buffer); this.packet = new SoftReference<>(cache); } return cache; } public boolean isValid() { - return packet != null && packet.get() != null; + final SoftReference ref = packet; + return ref != null && ref.get() != null; + } + + @Override + public String toString() { + final SoftReference ref = packet; + final FramedPacket cache = ref != null ? ref.get() : null; + return String.format("CachedPacket{cache=%s}", cache); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/FramedPacket.java b/src/main/java/net/minestom/server/network/packet/server/FramedPacket.java index 1f38761f9..9698a6e05 100644 --- a/src/main/java/net/minestom/server/network/packet/server/FramedPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/FramedPacket.java @@ -1,20 +1,18 @@ package net.minestom.server.network.packet.server; +import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import java.nio.ByteBuffer; - /** * Represents a packet which is already framed. (packet id+payload) + optional compression * Can be used if you want to send the exact same buffer to multiple clients without processing it more than once. - *

- * The {@link ByteBuffer} will ultimately become a MemorySegment once out of incubation. */ @ApiStatus.Internal public record FramedPacket(@NotNull ServerPacket packet, - @NotNull ByteBuffer body) implements SendablePacket { + @NotNull NetworkBuffer body) implements SendablePacket { public FramedPacket { - body = body.position(0).asReadOnlyBuffer(); + body.readIndex(0); + body.readOnly(); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/SendablePacket.java b/src/main/java/net/minestom/server/network/packet/server/SendablePacket.java index aa65b7e3d..5ee4a1ee4 100644 --- a/src/main/java/net/minestom/server/network/packet/server/SendablePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/SendablePacket.java @@ -2,28 +2,22 @@ package net.minestom.server.network.packet.server; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents a packet that can be sent to a {@link PlayerConnection}. */ -@ApiStatus.Experimental public sealed interface SendablePacket - permits CachedPacket, FramedPacket, LazyPacket, ServerPacket { + permits BufferedPacket, CachedPacket, FramedPacket, LazyPacket, ServerPacket { - @ApiStatus.Experimental - static @NotNull ServerPacket extractServerPacket(@NotNull ConnectionState state, @NotNull SendablePacket packet) { - if (packet instanceof ServerPacket serverPacket) { - return serverPacket; - } else if (packet instanceof CachedPacket cachedPacket) { - return cachedPacket.packet(state); - } else if (packet instanceof FramedPacket framedPacket) { - return framedPacket.packet(); - } else if (packet instanceof LazyPacket lazyPacket) { - return lazyPacket.packet(); - } else { - throw new RuntimeException("Unknown packet type: " + packet.getClass().getName()); - } + static @Nullable ServerPacket extractServerPacket(@NotNull ConnectionState state, @NotNull SendablePacket packet) { + return switch (packet) { + case ServerPacket serverPacket -> serverPacket; + case CachedPacket cachedPacket -> cachedPacket.packet(state); + case FramedPacket framedPacket -> framedPacket.packet(); + case LazyPacket lazyPacket -> lazyPacket.packet(); + case BufferedPacket bufferedPacket -> null; + }; } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java index 962f3a072..18c1f5c7c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/CustomReportDetailsPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.common; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -11,17 +12,10 @@ public record CustomReportDetailsPacket( ) implements ServerPacket.Configuration, ServerPacket.Play { private static final int MAX_DETAILS = 32; - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, CustomReportDetailsPacket packet) { - buffer.writeMap(NetworkBuffer.STRING, NetworkBuffer.STRING, packet.details); - } - - @Override - public CustomReportDetailsPacket read(@NotNull NetworkBuffer buffer) { - return new CustomReportDetailsPacket(buffer.readMap(NetworkBuffer.STRING, NetworkBuffer.STRING, MAX_DETAILS)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.STRING.mapValue(NetworkBuffer.STRING, MAX_DETAILS), CustomReportDetailsPacket::details, + CustomReportDetailsPacket::new + ); public CustomReportDetailsPacket { details = Map.copyOf(details); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java index 05203ce84..b10eaaeea 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/PluginMessagePacket.java @@ -23,7 +23,7 @@ public record PluginMessagePacket(String channel, * @return the current brand name packet */ public static @NotNull PluginMessagePacket brandPacket(String brandName) { - final byte[] data = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(STRING, brandName)); + final byte[] data = NetworkBuffer.makeArray(STRING, brandName); return new PluginMessagePacket("minecraft:brand", data); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java index 88a33110a..4fd802167 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/ServerLinksPacket.java @@ -49,7 +49,6 @@ public record ServerLinksPacket(@NotNull List entries) implements ServerP } } }; - public static final NetworkBuffer.Type> LIST_NETWORK_TYPE = NETWORK_TYPE.list(MAX_ENTRIES); public Entry { Check.argCondition(knownType == null && customType == null, "One of knownType and customType must be present"); diff --git a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java index d1270c54d..186eed003 100644 --- a/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/common/TagsPacket.java @@ -1,70 +1,41 @@ package net.minestom.server.network.packet.server.common; -import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.List; -import java.util.Map; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.STRING; +import static net.minestom.server.network.NetworkBuffer.VAR_INT_ARRAY; -public record TagsPacket( - @NotNull Map> tagsMap) implements ServerPacket.Configuration, ServerPacket.Play { +public record TagsPacket(List registries) implements ServerPacket.Configuration, ServerPacket.Play { public TagsPacket { - tagsMap = Map.copyOf(tagsMap); + registries = List.copyOf(registries); } - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, TagsPacket packet) { - buffer.write(VAR_INT, packet.tagsMap.size()); - for (var entry : packet.tagsMap.entrySet()) { - final var type = entry.getKey(); - final var tags = entry.getValue(); - buffer.write(STRING, type.getIdentifier()); - if (type.getFunction() == null) { - buffer.write(VAR_INT, 0); - continue; - } - buffer.write(VAR_INT, tags.size()); - for (var tag : tags) { - buffer.write(STRING, tag.name()); - final var values = tag.getValues(); - buffer.write(VAR_INT, values.size()); - for (var name : values) { - buffer.write(VAR_INT, type.getFunction().apply(name.asString())); - } - } - } - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Registry.SERIALIZER.list(), TagsPacket::registries, + TagsPacket::new + ); - @Override - public TagsPacket read(@NotNull NetworkBuffer buffer) { - return new TagsPacket(readTagsMap(buffer)); - } - }; + public record Registry(String registry, List tags) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Registry::registry, + Tag.SERIALIZER.list(), Registry::tags, + Registry::new + ); - private static Map> readTagsMap(@NotNull NetworkBuffer reader) { - Map> tagsMap = new EnumMap<>(Tag.BasicType.class); - // Read amount of tag types - final int typeCount = reader.read(VAR_INT); - for (int i = 0; i < typeCount; i++) { - // Read tag type - final Tag.BasicType tagType = Tag.BasicType.fromIdentifer(reader.read(STRING)); - if (tagType == null) { - throw new IllegalArgumentException("Tag type could not be resolved"); - } - - final int tagCount = reader.read(VAR_INT); - for (int j = 0; j < tagCount; j++) { - final String tagName = reader.read(STRING); - final int[] entries = reader.read(VAR_INT_ARRAY); - // TODO convert - } + public Registry { + tags = List.copyOf(tags); } - return tagsMap; + } + + public record Tag(String identifier, int[] entries) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Tag::identifier, + VAR_INT_ARRAY, Tag::entries, + Tag::new + ); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java index d386867c6..45935ea5c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/configuration/UpdateEnabledFeaturesPacket.java @@ -18,7 +18,7 @@ public record UpdateEnabledFeaturesPacket(@NotNull List features) implem features = List.copyOf(features); } - public static NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( STRING.list(MAX_FEATURES), UpdateEnabledFeaturesPacket::features, UpdateEnabledFeaturesPacket::new ); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java index 27eac906e..f584d3075 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java @@ -5,6 +5,7 @@ import net.minestom.server.advancements.FrameType; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,25 +23,13 @@ public record AdvancementsPacket(boolean reset, @NotNull List progressMappings) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final int MAX_ADVANCEMENTS = Short.MAX_VALUE; - public static NetworkBuffer.Type SERIALIZER = new Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, AdvancementsPacket value) { - buffer.write(BOOLEAN, value.reset); - buffer.writeCollection(value.advancementMappings); - buffer.writeCollection(STRING, value.identifiersToRemove); - buffer.writeCollection(value.progressMappings); - } - - @Override - public AdvancementsPacket read(@NotNull NetworkBuffer buffer) { - return new AdvancementsPacket( - buffer.read(BOOLEAN), - buffer.readCollection(AdvancementMapping::new, MAX_ADVANCEMENTS), - buffer.readCollection(STRING, MAX_ADVANCEMENTS), - buffer.readCollection(ProgressMapping::new, MAX_ADVANCEMENTS) - ); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BOOLEAN, AdvancementsPacket::reset, + AdvancementMapping.SERIALIZER.list(MAX_ADVANCEMENTS), AdvancementsPacket::advancementMappings, + STRING.list(MAX_ADVANCEMENTS), AdvancementsPacket::identifiersToRemove, + ProgressMapping.SERIALIZER.list(MAX_ADVANCEMENTS), AdvancementsPacket::progressMappings, + AdvancementsPacket::new + ); public AdvancementsPacket { advancementMappings = List.copyOf(advancementMappings); @@ -77,16 +66,12 @@ public record AdvancementsPacket(boolean reset, @NotNull List { - public AdvancementMapping(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), new Advancement(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, key); - writer.write(value); - } + @NotNull Advancement value) implements ComponentHolder { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, AdvancementMapping::key, + Advancement.SERIALIZER, AdvancementMapping::value, + AdvancementMapping::new + ); @Override public @NotNull Collection components() { @@ -101,23 +86,18 @@ public record AdvancementsPacket(boolean reset, @NotNull List requirements, - boolean sendTelemetryData) implements NetworkBuffer.Writer, ComponentHolder { + boolean sendTelemetryData) implements ComponentHolder { public Advancement { requirements = List.copyOf(requirements); } - public Advancement(@NotNull NetworkBuffer reader) { - this(reader.readOptional(STRING), reader.readOptional(DisplayData::new), - reader.readCollection(Requirement::new, MAX_ADVANCEMENTS), reader.read(BOOLEAN)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeOptional(STRING, parentIdentifier); - writer.writeOptional(displayData); - writer.writeCollection(requirements); - writer.write(BOOLEAN, sendTelemetryData); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.optional(), Advancement::parentIdentifier, + DisplayData.SERIALIZER.optional(), Advancement::displayData, + Requirement.SERIALIZER.list(MAX_ADVANCEMENTS), Advancement::requirements, + BOOLEAN, Advancement::sendTelemetryData, + Advancement::new + ); @Override public @NotNull Collection components() { @@ -130,65 +110,54 @@ public record AdvancementsPacket(boolean reset, @NotNull List requirements) implements NetworkBuffer.Writer { + public record Requirement(@NotNull List requirements) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.list(MAX_ADVANCEMENTS), Requirement::requirements, + Requirement::new + ); + public Requirement { requirements = List.copyOf(requirements); } - - public Requirement(@NotNull NetworkBuffer reader) { - this(reader.readCollection(STRING, MAX_ADVANCEMENTS)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(STRING, requirements); - } } public record DisplayData(@NotNull Component title, @NotNull Component description, @NotNull ItemStack icon, @NotNull FrameType frameType, int flags, @Nullable String backgroundTexture, - float x, float y) implements NetworkBuffer.Writer, ComponentHolder { - public DisplayData(@NotNull NetworkBuffer reader) { - this(read(reader)); - } + float x, float y) implements ComponentHolder { - private DisplayData(DisplayData displayData) { - this(displayData.title, displayData.description, - displayData.icon, displayData.frameType, - displayData.flags, displayData.backgroundTexture, - displayData.x, displayData.y); - } - - private static DisplayData read(@NotNull NetworkBuffer reader) { - var title = reader.read(COMPONENT); - var description = reader.read(COMPONENT); - var icon = reader.read(ItemStack.NETWORK_TYPE); - var frameType = FrameType.values()[reader.read(VAR_INT)]; - var flags = reader.read(INT); - var backgroundTexture = (flags & 0x1) != 0 ? reader.read(STRING) : null; - var x = reader.read(FLOAT); - var y = reader.read(FLOAT); - return new DisplayData(title, description, - icon, frameType, - flags, backgroundTexture, - x, y); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, title); - writer.write(COMPONENT, description); - writer.write(ItemStack.NETWORK_TYPE, icon); - writer.writeEnum(FrameType.class, frameType); - writer.write(INT, flags); - if ((flags & 0x1) != 0) { - assert backgroundTexture != null; - writer.write(STRING, backgroundTexture); + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, DisplayData value) { + buffer.write(COMPONENT, value.title); + buffer.write(COMPONENT, value.description); + buffer.write(ItemStack.NETWORK_TYPE, value.icon); + buffer.write(NetworkBuffer.Enum(FrameType.class), value.frameType); + buffer.write(INT, value.flags); + if ((value.flags & 0x1) != 0) { + assert value.backgroundTexture != null; + buffer.write(STRING, value.backgroundTexture); + } + buffer.write(FLOAT, value.x); + buffer.write(FLOAT, value.y); } - writer.write(FLOAT, x); - writer.write(FLOAT, y); - } + + @Override + public DisplayData read(@NotNull NetworkBuffer buffer) { + var title = buffer.read(COMPONENT); + var description = buffer.read(COMPONENT); + var icon = buffer.read(ItemStack.NETWORK_TYPE); + var frameType = FrameType.values()[buffer.read(VAR_INT)]; + var flags = buffer.read(INT); + var backgroundTexture = (flags & 0x1) != 0 ? buffer.read(STRING) : null; + var x = buffer.read(FLOAT); + var y = buffer.read(FLOAT); + return new DisplayData(title, description, + icon, frameType, + flags, backgroundTexture, + x, y); + } + }; @Override public @NotNull Collection components() { @@ -201,55 +170,37 @@ public record AdvancementsPacket(boolean reset, @NotNull List SERIALIZER = NetworkBufferTemplate.template( + STRING, ProgressMapping::key, + AdvancementProgress.SERIALIZER, ProgressMapping::progress, + ProgressMapping::new + ); } - public record AdvancementProgress(@NotNull List criteria) implements NetworkBuffer.Writer { + public record AdvancementProgress(@NotNull List<@NotNull Criteria> criteria) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Criteria.SERIALIZER.list(MAX_ADVANCEMENTS), AdvancementProgress::criteria, + AdvancementProgress::new + ); + public AdvancementProgress { criteria = List.copyOf(criteria); } - - public AdvancementProgress(@NotNull NetworkBuffer reader) { - this(reader.readCollection(Criteria::new, MAX_ADVANCEMENTS)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(criteria); - } } - public record Criteria(@NotNull String criterionIdentifier, - @NotNull CriterionProgress criterionProgress) implements NetworkBuffer.Writer { - public Criteria(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), new CriterionProgress(reader)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, criterionIdentifier); - writer.write(criterionProgress); - } + public record Criteria(@NotNull String criterionIdentifier, @NotNull CriterionProgress criterionProgress) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Criteria::criterionIdentifier, + CriterionProgress.SERIALIZER, Criteria::criterionProgress, + Criteria::new + ); } - public record CriterionProgress(@Nullable Long dateOfAchieving) implements NetworkBuffer.Writer { - public CriterionProgress(@NotNull NetworkBuffer reader) { - this(reader.readOptional(LONG)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeOptional(LONG, dateOfAchieving); - } + public record CriterionProgress(@Nullable Long dateOfAchieving) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + LONG.optional(), CriterionProgress::dateOfAchieving, + CriterionProgress::new + ); } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java index fceecd900..a117935c9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BlockEntityDataPacket.java @@ -17,7 +17,7 @@ public record BlockEntityDataPacket(@NotNull Point blockPosition, int action, buffer.write(BLOCK_POSITION, value.blockPosition); buffer.write(VAR_INT, value.action); if (value.data != null) { - buffer.write(NBT, value.data); + buffer.write(NBT_COMPOUND, value.data); } else { // TAG_End buffer.write(BYTE, (byte) 0x00); @@ -26,7 +26,7 @@ public record BlockEntityDataPacket(@NotNull Point blockPosition, int action, @Override public BlockEntityDataPacket read(@NotNull NetworkBuffer buffer) { - return new BlockEntityDataPacket(buffer.read(BLOCK_POSITION), buffer.read(VAR_INT), (CompoundBinaryTag) buffer.read(NBT)); + return new BlockEntityDataPacket(buffer.read(BLOCK_POSITION), buffer.read(VAR_INT), buffer.read(NBT_COMPOUND)); } }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java index 4ea9b2410..ee08e028b 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/BossBarPacket.java @@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -22,20 +23,16 @@ public record BossBarPacket(@NotNull UUID uuid, public void write(@NotNull NetworkBuffer buffer, BossBarPacket value) { buffer.write(NetworkBuffer.UUID, value.uuid); buffer.write(VAR_INT, value.action.id()); - buffer.write(value.action); + @SuppressWarnings("unchecked") final Type serializer = (Type) actionSerializer(value.action.id()); + buffer.write(serializer, value.action); } @Override public BossBarPacket read(@NotNull NetworkBuffer buffer) { - return new BossBarPacket(buffer.read(NetworkBuffer.UUID), switch (buffer.read(VAR_INT)) { - case 0 -> new AddAction(buffer); - case 1 -> new RemoveAction(); - case 2 -> new UpdateHealthAction(buffer); - case 3 -> new UpdateTitleAction(buffer); - case 4 -> new UpdateStyleAction(buffer); - case 5 -> new UpdateFlagsAction(buffer); - default -> throw new RuntimeException("Unknown action id"); - }); + final UUID uuid = buffer.read(NetworkBuffer.UUID); + final int id = buffer.read(VAR_INT); + final Type serializer = actionSerializer(id); + return new BossBarPacket(uuid, serializer.read(buffer)); } }; @@ -46,6 +43,18 @@ public record BossBarPacket(@NotNull UUID uuid, : List.of(); } + private static Type actionSerializer(int id) { + return switch (id) { + case 0 -> AddAction.SERIALIZER; + case 1 -> RemoveAction.SERIALIZER; + case 2 -> UpdateHealthAction.SERIALIZER; + case 3 -> UpdateTitleAction.SERIALIZER; + case 4 -> UpdateStyleAction.SERIALIZER; + case 5 -> UpdateFlagsAction.SERIALIZER; + default -> throw new RuntimeException("Unknown action id"); + }; + } + @Override public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator operator) { return this.action instanceof ComponentHolder holder @@ -53,8 +62,9 @@ public record BossBarPacket(@NotNull UUID uuid, : this; } - public sealed interface Action extends NetworkBuffer.Writer - permits AddAction, RemoveAction, UpdateHealthAction, UpdateTitleAction, UpdateStyleAction, UpdateFlagsAction { + public sealed interface Action permits + AddAction, RemoveAction, UpdateHealthAction, + UpdateTitleAction, UpdateStyleAction, UpdateFlagsAction { int id(); } @@ -66,20 +76,14 @@ public record BossBarPacket(@NotNull UUID uuid, AdventurePacketConvertor.getBossBarFlagValue(bar.flags())); } - public AddAction(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.read(FLOAT), - BossBar.Color.values()[reader.read(VAR_INT)], - BossBar.Overlay.values()[reader.read(VAR_INT)], reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, title); - writer.write(FLOAT, health); - writer.write(VAR_INT, AdventurePacketConvertor.getBossBarColorValue(color)); - writer.write(VAR_INT, AdventurePacketConvertor.getBossBarOverlayValue(overlay)); - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, AddAction::title, + FLOAT, AddAction::health, + Enum(BossBar.Color.class), AddAction::color, + Enum(BossBar.Overlay.class), AddAction::overlay, + BYTE, AddAction::flags, + AddAction::new + ); @Override public int id() { @@ -98,9 +102,7 @@ public record BossBarPacket(@NotNull UUID uuid, } public record RemoveAction() implements Action { - @Override - public void write(@NotNull NetworkBuffer writer) { - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(RemoveAction::new); @Override public int id() { @@ -113,14 +115,10 @@ public record BossBarPacket(@NotNull UUID uuid, this(bar.progress()); } - public UpdateHealthAction(@NotNull NetworkBuffer reader) { - this(reader.read(FLOAT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(FLOAT, health); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, UpdateHealthAction::health, + UpdateHealthAction::new + ); @Override public int id() { @@ -133,14 +131,10 @@ public record BossBarPacket(@NotNull UUID uuid, this(bar.name()); } - public UpdateTitleAction(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, title); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, UpdateTitleAction::title, + UpdateTitleAction::new + ); @Override public int id() { @@ -164,15 +158,11 @@ public record BossBarPacket(@NotNull UUID uuid, this(bar.color(), bar.overlay()); } - public UpdateStyleAction(@NotNull NetworkBuffer reader) { - this(BossBar.Color.values()[reader.read(VAR_INT)], BossBar.Overlay.values()[reader.read(VAR_INT)]); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, AdventurePacketConvertor.getBossBarColorValue(color)); - writer.write(VAR_INT, AdventurePacketConvertor.getBossBarOverlayValue(overlay)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Enum(BossBar.Color.class), UpdateStyleAction::color, + Enum(BossBar.Overlay.class), UpdateStyleAction::overlay, + UpdateStyleAction::new + ); @Override public int id() { @@ -185,19 +175,14 @@ public record BossBarPacket(@NotNull UUID uuid, this(AdventurePacketConvertor.getBossBarFlagValue(bar.flags())); } - public UpdateFlagsAction(@NotNull NetworkBuffer reader) { - this(reader.read(BYTE)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, UpdateFlagsAction::flags, + UpdateFlagsAction::new + ); @Override public int id() { return 5; } } - } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index 4751b6060..96321e086 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.data.ChunkData; import net.minestom.server.network.packet.server.play.data.LightData; @@ -11,20 +12,11 @@ import static net.minestom.server.network.NetworkBuffer.INT; public record ChunkDataPacket(int chunkX, int chunkZ, @NotNull ChunkData chunkData, @NotNull LightData lightData) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ChunkDataPacket value) { - buffer.write(INT, value.chunkX); - buffer.write(INT, value.chunkZ); - buffer.write(value.chunkData); - buffer.write(value.lightData); - } - - @Override - public ChunkDataPacket read(@NotNull NetworkBuffer buffer) { - return new ChunkDataPacket(buffer.read(INT), buffer.read(INT), - new ChunkData(buffer), - new LightData(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, ChunkDataPacket::chunkX, + INT, ChunkDataPacket::chunkZ, + ChunkData.NETWORK_TYPE, ChunkDataPacket::chunkData, + LightData.SERIALIZER, ChunkDataPacket::lightData, + ChunkDataPacket::new + ); } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java index 920c6fcf2..c6b52757f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareCommandsPacket.java @@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.registry.StaticProtocolObject; import org.jetbrains.annotations.NotNull; @@ -19,24 +20,18 @@ public record DeclareCommandsPacket(@NotNull List nodes, nodes = List.copyOf(nodes); } - public static final NetworkBuffer.Type SERIALIZER = new Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, DeclareCommandsPacket value) { - buffer.writeCollection(value.nodes); - buffer.write(VAR_INT, value.rootIndex); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Node.SERIALIZER.list(MAX_NODES), DeclareCommandsPacket::nodes, + VAR_INT, DeclareCommandsPacket::rootIndex, + DeclareCommandsPacket::new + ); - @Override - public DeclareCommandsPacket read(@NotNull NetworkBuffer buffer) { - return new DeclareCommandsPacket(buffer.readCollection(r -> { - Node node = new Node(); - node.read(r); - return node; - }, MAX_NODES), buffer.read(VAR_INT)); - } - }; + public static final int NODE_TYPE = 0x03; + public static final int IS_EXECUTABLE = 0x04; + public static final int HAS_REDIRECT = 0x08; + public static final int HAS_SUGGESTION_TYPE = 0x10; - public static final class Node implements NetworkBuffer.Writer { + public static final class Node { public byte flags; public int[] children = new int[0]; public int redirectedNode; // Only if flags & 0x08 @@ -45,57 +40,61 @@ public record DeclareCommandsPacket(@NotNull List nodes, public byte[] properties; // Only for argument public String suggestionsType = ""; // Only if flags 0x10 - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(BYTE, flags); + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer writer, Node value) { + writer.write(BYTE, value.flags); - if (children != null && children.length > 262114) { - throw new RuntimeException("Children length " + children.length + " is bigger than the maximum allowed " + 262114); - } - writer.write(VAR_INT_ARRAY, children); + if (value.children != null && value.children.length > 262114) { + throw new RuntimeException("Children length " + value.children.length + " is bigger than the maximum allowed " + 262114); + } + writer.write(VAR_INT_ARRAY, value.children); - if ((flags & 0x08) != 0) { - writer.write(VAR_INT, redirectedNode); - } + if ((value.flags & HAS_REDIRECT) != 0) { + writer.write(VAR_INT, value.redirectedNode); + } - if (isLiteral() || isArgument()) { - writer.write(STRING, name); - } + if (value.isLiteral() || value.isArgument()) { + writer.write(STRING, value.name); + } - if (isArgument()) { - final int parserId = Argument.CONTAINER.toId(parser); - writer.write(VAR_INT, parserId); - if (properties != null) { - writer.write(RAW_BYTES, properties); + if (value.isArgument()) { + final int parserId = Argument.CONTAINER.toId(value.parser); + writer.write(VAR_INT, parserId); + if (value.properties != null) { + writer.write(RAW_BYTES, value.properties); + } + } + + if ((value.flags & HAS_SUGGESTION_TYPE) != 0) { + writer.write(STRING, value.suggestionsType); } } - if ((flags & 0x10) != 0) { - writer.write(STRING, suggestionsType); - } - } + public Node read(@NotNull NetworkBuffer reader) { + Node node = new Node(); + node.flags = reader.read(BYTE); + node.children = reader.read(VAR_INT_ARRAY); + if ((node.flags & HAS_REDIRECT) != 0) { + node.redirectedNode = reader.read(VAR_INT); + } - public void read(@NotNull NetworkBuffer reader) { - flags = reader.read(BYTE); - children = reader.read(VAR_INT_ARRAY); - if ((flags & 0x08) != 0) { - redirectedNode = reader.read(VAR_INT); - } + if (node.isLiteral() || node.isArgument()) { + node.name = reader.read(STRING); + } - if (isLiteral() || isArgument()) { - name = reader.read(STRING); - } + if (node.isArgument()) { + final StaticProtocolObject object = Argument.CONTAINER.getId(reader.read(VAR_INT)); + node.parser = object.name(); + node.properties = node.getProperties(reader, node.parser); + } - if (isArgument()) { - final StaticProtocolObject object = Argument.CONTAINER.getId(reader.read(VAR_INT)); - parser = object.name(); - properties = getProperties(reader, parser); + if ((node.flags & HAS_SUGGESTION_TYPE) != 0) { + node.suggestionsType = reader.read(STRING); + } + return node; } - - if ((flags & 0x10) != 0) { - suggestionsType = reader.read(STRING); - } - } + }; private byte[] getProperties(@NotNull NetworkBuffer reader, String parser) { final Function, byte[]> minMaxExtractor = (via) -> reader.extractBytes((extractor) -> { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java index cfe2b3846..af10364a7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeleteChatPacket.java @@ -2,19 +2,13 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.crypto.MessageSignature; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; public record DeleteChatPacket(@NotNull MessageSignature signature) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, DeleteChatPacket value) { - buffer.write(value.signature); - } - - @Override - public DeleteChatPacket read(@NotNull NetworkBuffer buffer) { - return new DeleteChatPacket(new MessageSignature(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + MessageSignature.SERIALIZER, DeleteChatPacket::signature, + DeleteChatPacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java index 54aa967e5..99be69a6f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEffectPacket.java @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.potion.Potion; import org.jetbrains.annotations.NotNull; @@ -8,16 +9,9 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record EntityEffectPacket(int entityId, @NotNull Potion potion) implements ServerPacket.Play { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, EntityEffectPacket value) { - buffer.write(VAR_INT, value.entityId); - buffer.write(value.potion); - } - - @Override - public EntityEffectPacket read(@NotNull NetworkBuffer buffer) { - return new EntityEffectPacket(buffer.read(VAR_INT), new Potion(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EntityEffectPacket::entityId, + Potion.NETWORK_TYPE, EntityEffectPacket::potion, + EntityEffectPacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java index 08478ce46..8d7f8f7d1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityMetaDataPacket.java @@ -24,9 +24,9 @@ public record EntityMetaDataPacket(int entityId, @Override public void write(@NotNull NetworkBuffer buffer, EntityMetaDataPacket value) { buffer.write(VAR_INT, value.entityId); - for (var entry : value.entries.entrySet()) { + for (Map.Entry> entry : value.entries.entrySet()) { buffer.write(BYTE, entry.getKey().byteValue()); - buffer.write(entry.getValue()); + buffer.write(Metadata.Entry.SERIALIZER, entry.getValue()); } buffer.write(BYTE, (byte) 0xFF); // End } @@ -44,8 +44,8 @@ public record EntityMetaDataPacket(int entityId, if (index == (byte) 0xFF) { // reached the end break; } - final int type = reader.read(VAR_INT); - entries.put((int) index, Metadata.Entry.read(type, reader)); + Metadata.Entry entry = Metadata.Entry.SERIALIZER.read(reader); + entries.put((int) index, entry); } return entries; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java index cf7c50a5b..d18ddf682 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntitySoundEffectPacket.java @@ -31,7 +31,7 @@ public record EntitySoundEffectPacket( @Override public EntitySoundEffectPacket read(@NotNull NetworkBuffer buffer) { return new EntitySoundEffectPacket(buffer.read(SoundEvent.NETWORK_TYPE), - buffer.readEnum(Sound.Source.class), + buffer.read(NetworkBuffer.Enum(Sound.Source.class)), buffer.read(VAR_INT), buffer.read(FLOAT), buffer.read(FLOAT), diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java index a8168f249..e390db2f3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java @@ -42,9 +42,9 @@ public record ExplosionPacket(double x, double y, double z, float radius, public ExplosionPacket read(@NotNull NetworkBuffer buffer) { double x = buffer.read(DOUBLE), y = buffer.read(DOUBLE), z = buffer.read(DOUBLE); float radius = buffer.read(FLOAT); - byte[] records = buffer.readBytes(buffer.read(VAR_INT) * 3); + byte[] records = buffer.read(FixedRawBytes(buffer.read(VAR_INT) * 3)); float playerMotionX = buffer.read(FLOAT), playerMotionY = buffer.read(FLOAT), playerMotionZ = buffer.read(FLOAT); - BlockInteraction blockInteraction = buffer.readEnum(BlockInteraction.class); + BlockInteraction blockInteraction = buffer.read(NetworkBuffer.Enum(BlockInteraction.class)); int smallParticleId = buffer.read(VAR_INT); byte[] smallParticleData = readParticleData(buffer, Particle.fromId(smallParticleId)); int largeParticleId = buffer.read(VAR_INT); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java index 7b0185711..e33db24b9 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/FacePlayerPacket.java @@ -1,7 +1,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -15,24 +14,21 @@ public record FacePlayerPacket(FacePosition facePosition, public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, @NotNull FacePlayerPacket value) { - buffer.write(VAR_INT, value.facePosition.ordinal()); - buffer.write(DOUBLE, value.target.x()); - buffer.write(DOUBLE, value.target.y()); - buffer.write(DOUBLE, value.target.z()); + buffer.write(Enum(FacePosition.class), value.facePosition); + buffer.write(VECTOR3D, value.target); final boolean isEntity = value.entityId > 0; buffer.write(BOOLEAN, isEntity); if (isEntity) { buffer.write(VAR_INT, value.entityId); - buffer.writeEnum(FacePosition.class, value.entityFacePosition); + buffer.write(Enum(FacePosition.class), value.entityFacePosition); } } @Override public @NotNull FacePlayerPacket read(@NotNull NetworkBuffer buffer) { - return new FacePlayerPacket(FacePosition.values()[buffer.read(VAR_INT)], - new Vec(buffer.read(DOUBLE), buffer.read(DOUBLE), buffer.read(DOUBLE)), - buffer.read(BOOLEAN) ? buffer.read(VAR_INT) : 0, - buffer.readableBytes() > 0 ? buffer.readEnum(FacePosition.class) : null); + return new FacePlayerPacket(buffer.read(Enum(FacePosition.class)), + buffer.read(VECTOR3D), buffer.read(BOOLEAN) ? buffer.read(VAR_INT) : 0, + buffer.readableBytes() > 0 ? buffer.read(Enum(FacePosition.class)) : null); } }; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java index 6214c7517..a459f90dc 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java @@ -2,9 +2,9 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.entity.GameMode; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.data.WorldPos; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -25,67 +25,26 @@ public record JoinGamePacket( worlds = List.copyOf(worlds); } - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, JoinGamePacket value) { - buffer.write(INT, value.entityId); - buffer.write(BOOLEAN, value.isHardcore); - buffer.writeCollection(STRING, value.worlds); - buffer.write(VAR_INT, value.maxPlayers); - buffer.write(VAR_INT, value.viewDistance); - buffer.write(VAR_INT, value.simulationDistance); - buffer.write(BOOLEAN, value.reducedDebugInfo); - buffer.write(BOOLEAN, value.enableRespawnScreen); - buffer.write(BOOLEAN, value.doLimitedCrafting); - buffer.write(VAR_INT, value.dimensionType); - buffer.write(STRING, value.world); - buffer.write(LONG, value.hashedSeed); - buffer.write(BYTE, value.gameMode.id()); - if (value.previousGameMode != null) { - buffer.write(BYTE, value.previousGameMode.id()); - } else { - buffer.write(BYTE, (byte) -1); - } - buffer.write(BOOLEAN, value.isDebug); - buffer.write(BOOLEAN, value.isFlat); - buffer.writeOptional(WorldPos.NETWORK_TYPE, value.deathLocation); - buffer.write(VAR_INT, value.portalCooldown); - buffer.write(BOOLEAN, value.enforcesSecureChat); - } - - @Override - public JoinGamePacket read(@NotNull NetworkBuffer buffer) { - return new JoinGamePacket( - buffer.read(INT), - buffer.read(BOOLEAN), - buffer.readCollection(STRING, MAX_WORLDS), - buffer.read(VAR_INT), - buffer.read(VAR_INT), - buffer.read(VAR_INT), - buffer.read(BOOLEAN), - buffer.read(BOOLEAN), - buffer.read(BOOLEAN), - buffer.read(VAR_INT), - buffer.read(STRING), - buffer.read(LONG), - GameMode.fromId(buffer.read(BYTE)), - getNullableGameMode(buffer.read(BYTE)), - buffer.read(BOOLEAN), - buffer.read(BOOLEAN), - buffer.readOptional(WorldPos.NETWORK_TYPE), - buffer.read(VAR_INT), - buffer.read(BOOLEAN) - ); - } - }; - - /** - * This method exists in lieu of a NetworkBufferType since -1 is only a - * valid value in this packet and changing behaviour of GameMode.fromId() - * to be nullable would be too big of a change. Also, game modes are often - * represented as other data types, including floats. - */ - private static @Nullable GameMode getNullableGameMode(final byte id) { - return id == (byte) -1 ? null : GameMode.fromId(id); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + INT, JoinGamePacket::entityId, + BOOLEAN, JoinGamePacket::isHardcore, + STRING.list(MAX_WORLDS), JoinGamePacket::worlds, + VAR_INT, JoinGamePacket::maxPlayers, + VAR_INT, JoinGamePacket::viewDistance, + VAR_INT, JoinGamePacket::simulationDistance, + BOOLEAN, JoinGamePacket::reducedDebugInfo, + BOOLEAN, JoinGamePacket::enableRespawnScreen, + BOOLEAN, JoinGamePacket::doLimitedCrafting, + VAR_INT, JoinGamePacket::dimensionType, + STRING, JoinGamePacket::world, + LONG, JoinGamePacket::hashedSeed, + GameMode.NETWORK_TYPE, JoinGamePacket::gameMode, + GameMode.OPT_NETWORK_TYPE, JoinGamePacket::previousGameMode, + BOOLEAN, JoinGamePacket::isDebug, + BOOLEAN, JoinGamePacket::isFlat, + WorldPos.NETWORK_TYPE.optional(), JoinGamePacket::deathLocation, + VAR_INT, JoinGamePacket::portalCooldown, + BOOLEAN, JoinGamePacket::enforcesSecureChat, + JoinGamePacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java index af1699c68..9e98a4525 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/MapDataPacket.java @@ -27,7 +27,7 @@ public record MapDataPacket(int mapId, byte scale, boolean locked, buffer.write(BYTE, value.scale); buffer.write(BOOLEAN, value.locked); buffer.write(BOOLEAN, value.trackingPosition); - if (value.trackingPosition) buffer.writeCollection(Icon.SERIALIZER, value.icons); + if (value.trackingPosition) buffer.write(Icon.SERIALIZER.list(), value.icons); if (value.colorContent != null) { buffer.write(ColorContent.SERIALIZER, value.colorContent); } else { @@ -41,7 +41,7 @@ public record MapDataPacket(int mapId, byte scale, boolean locked, var scale = buffer.read(BYTE); var locked = buffer.read(BOOLEAN); var trackingPosition = buffer.read(BOOLEAN); - List icons = trackingPosition ? buffer.readCollection(Icon.SERIALIZER, MAX_ICONS) : List.of(); + List icons = trackingPosition ? buffer.read(Icon.SERIALIZER.list(MAX_ICONS)) : List.of(); var columns = buffer.read(BYTE); if (columns <= 0) return new MapDataPacket(mapId, scale, locked, trackingPosition, icons, null); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java index 727576756..dbd3fc1ef 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/NbtQueryResponsePacket.java @@ -13,7 +13,7 @@ public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) public void write(@NotNull NetworkBuffer buffer, NbtQueryResponsePacket value) { buffer.write(VAR_INT, value.transactionId); if (value.data != null) { - buffer.write(NBT, value.data); + buffer.write(NBT_COMPOUND, value.data); } else { // TAG_End buffer.write(BYTE, (byte) 0x00); @@ -22,7 +22,7 @@ public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) @Override public NbtQueryResponsePacket read(@NotNull NetworkBuffer buffer) { - return new NbtQueryResponsePacket(buffer.read(VAR_INT), (CompoundBinaryTag) buffer.read(NBT)); + return new NbtQueryResponsePacket(buffer.read(VAR_INT), buffer.read(NBT_COMPOUND)); } }; } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java index dc8fc6ba8..241576205 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerChatMessagePacket.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.crypto.FilterMask; import net.minestom.server.crypto.SignedMessageBody; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,29 +26,18 @@ public record PlayerChatMessagePacket(UUID sender, int index, byte @Nullable [] int msgTypeId, Component msgTypeName, @Nullable Component msgTypeTarget) implements ServerPacket.Play, ServerPacket.ComponentHolding { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, @NotNull PlayerChatMessagePacket value) { - buffer.write(UUID, value.sender); - buffer.write(VAR_INT, value.index); - buffer.writeOptional(RAW_BYTES, value.signature); - buffer.write(value.messageBody); - buffer.writeOptional(COMPONENT, value.unsignedContent); - buffer.write(value.filterMask); - buffer.write(VAR_INT, value.msgTypeId); - buffer.write(COMPONENT, value.msgTypeName); - buffer.writeOptional(COMPONENT, value.msgTypeTarget); - } - - @Override - public @NotNull PlayerChatMessagePacket read(@NotNull NetworkBuffer buffer) { - return new PlayerChatMessagePacket(buffer.read(UUID), buffer.read(VAR_INT), buffer.readOptional(r -> r.readBytes(256)), - new SignedMessageBody.Packed(buffer), - buffer.readOptional(COMPONENT), new FilterMask(buffer), - buffer.read(VAR_INT), buffer.read(COMPONENT), - buffer.readOptional(COMPONENT)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + UUID, PlayerChatMessagePacket::sender, + VAR_INT, PlayerChatMessagePacket::index, + RAW_BYTES.optional(), PlayerChatMessagePacket::signature, + SignedMessageBody.Packed.SERIALIZER, PlayerChatMessagePacket::messageBody, + COMPONENT.optional(), PlayerChatMessagePacket::unsignedContent, + FilterMask.SERIALIZER, PlayerChatMessagePacket::filterMask, + VAR_INT, PlayerChatMessagePacket::msgTypeId, + COMPONENT, PlayerChatMessagePacket::msgTypeName, + COMPONENT, PlayerChatMessagePacket::msgTypeTarget, + PlayerChatMessagePacket::new + ); @Override public @NotNull Collection components() { diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java index 4f3c62a68..ebcf00a49 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java @@ -34,42 +34,14 @@ public record PlayerInfoUpdatePacket( public static final NetworkBuffer.Type SERIALIZER = new Type<>() { @Override public void write(@NotNull NetworkBuffer writer, PlayerInfoUpdatePacket value) { - writer.writeEnumSet(value.actions, Action.class); - writer.writeCollection(value.entries, (buffer, entry) -> { - buffer.write(NetworkBuffer.UUID, entry.uuid); - for (Action action : value.actions) { - action.writer.write(buffer, entry); - } - }); + writer.write(EnumSet(Action.class), value.actions); + writer.write(Entry.serializer(value.actions).list(MAX_ENTRIES), value.entries); } @Override public PlayerInfoUpdatePacket read(@NotNull NetworkBuffer reader) { - var actions = reader.readEnumSet(Action.class); - var entries = reader.readCollection(buffer -> { - UUID uuid = buffer.read(NetworkBuffer.UUID); - String username = ""; - List properties = List.of(); - boolean listed = false; - int latency = 0; - GameMode gameMode = GameMode.SURVIVAL; - Component displayName = null; - ChatSession chatSession = null; - for (Action action : actions) { - switch (action) { - case ADD_PLAYER -> { - username = reader.read(STRING); - properties = reader.readCollection(Property.SERIALIZER, GameProfile.MAX_PROPERTIES); - } - case INITIALIZE_CHAT -> chatSession = new ChatSession(reader); - case UPDATE_GAME_MODE -> gameMode = reader.readEnum(GameMode.class); - case UPDATE_LISTED -> listed = reader.read(BOOLEAN); - case UPDATE_LATENCY -> latency = reader.read(VAR_INT); - case UPDATE_DISPLAY_NAME -> displayName = reader.readOptional(COMPONENT); - } - } - return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession); - }, MAX_ENTRIES); + var actions = reader.read(EnumSet(Action.class)); + var entries = reader.read(Entry.serializer(actions).list(MAX_ENTRIES)); return new PlayerInfoUpdatePacket(actions, entries); } }; @@ -80,6 +52,42 @@ public record PlayerInfoUpdatePacket( public Entry { properties = List.copyOf(properties); } + + public static NetworkBuffer.Type serializer(EnumSet actions) { + return new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, Entry value) { + buffer.write(NetworkBuffer.UUID, value.uuid); + for (Action action : actions) action.writer.write(buffer, value); + } + + @Override + public Entry read(@NotNull NetworkBuffer buffer) { + UUID uuid = buffer.read(NetworkBuffer.UUID); + String username = ""; + List properties = List.of(); + boolean listed = false; + int latency = 0; + GameMode gameMode = GameMode.SURVIVAL; + Component displayName = null; + ChatSession chatSession = null; + for (Action action : actions) { + switch (action) { + case ADD_PLAYER -> { + username = buffer.read(STRING); + properties = buffer.read(Property.SERIALIZER.list(GameProfile.MAX_PROPERTIES)); + } + case INITIALIZE_CHAT -> chatSession = ChatSession.SERIALIZER.read(buffer); + case UPDATE_GAME_MODE -> gameMode = buffer.read(NetworkBuffer.Enum(GameMode.class)); + case UPDATE_LISTED -> listed = buffer.read(BOOLEAN); + case UPDATE_LATENCY -> latency = buffer.read(VAR_INT); + case UPDATE_DISPLAY_NAME -> displayName = buffer.read(COMPONENT.optional()); + } + } + return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession); + } + }; + } } public record Property(@NotNull String name, @NotNull String value, @Nullable String signature) { @@ -97,13 +105,13 @@ public record PlayerInfoUpdatePacket( public enum Action { ADD_PLAYER((writer, entry) -> { writer.write(STRING, entry.username); - writer.writeCollection(Property.SERIALIZER, entry.properties); + writer.write(Property.SERIALIZER.list(), entry.properties); }), - INITIALIZE_CHAT((writer, entry) -> writer.writeOptional(entry.chatSession)), + INITIALIZE_CHAT((writer, entry) -> writer.write(ChatSession.SERIALIZER.optional(), entry.chatSession)), UPDATE_GAME_MODE((writer, entry) -> writer.write(VAR_INT, entry.gameMode.ordinal())), UPDATE_LISTED((writer, entry) -> writer.write(BOOLEAN, entry.listed)), UPDATE_LATENCY((writer, entry) -> writer.write(VAR_INT, entry.latency)), - UPDATE_DISPLAY_NAME((writer, entry) -> writer.writeOptional(COMPONENT, entry.displayName)); + UPDATE_DISPLAY_NAME((writer, entry) -> writer.write(COMPONENT.optional(), entry.displayName)); final Writer writer; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java index 562774928..866d27c7c 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RemoveEntityEffectPacket.java @@ -1,25 +1,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.potion.PotionEffect; import org.jetbrains.annotations.NotNull; -import java.util.Objects; - import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record RemoveEntityEffectPacket(int entityId, @NotNull PotionEffect potionEffect) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, RemoveEntityEffectPacket value) { - buffer.write(VAR_INT, value.entityId); - buffer.write(VAR_INT, value.potionEffect.id()); - } - - @Override - public RemoveEntityEffectPacket read(@NotNull NetworkBuffer buffer) { - return new RemoveEntityEffectPacket(buffer.read(VAR_INT), Objects.requireNonNull(PotionEffect.fromId(buffer.read(VAR_INT)))); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, RemoveEntityEffectPacket::entityId, + PotionEffect.NETWORK_TYPE, RemoveEntityEffectPacket::potionEffect, + RemoveEntityEffectPacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java index 4dcb8ee70..abba27a56 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java @@ -26,7 +26,7 @@ public record RespawnPacket( STRING, RespawnPacket::worldName, LONG, RespawnPacket::hashedSeed, GameMode.NETWORK_TYPE, RespawnPacket::gameMode, - GameMode.NETWORK_TYPE, RespawnPacket::previousGameMode, + GameMode.OPT_NETWORK_TYPE, RespawnPacket::previousGameMode, BOOLEAN, RespawnPacket::isDebug, BOOLEAN, RespawnPacket::isFlat, WorldPos.NETWORK_TYPE.optional(), RespawnPacket::deathLocation, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java index 0765abad7..9afbdf487 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ScoreboardObjectivePacket.java @@ -27,7 +27,7 @@ public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode buffer.write(COMPONENT, value.objectiveValue); assert value.type != null; buffer.write(VAR_INT, value.type.ordinal()); - buffer.writeOptional(value.numberFormat); + buffer.write(Sidebar.NumberFormat.SERIALIZER.optional(), value.numberFormat); } } @@ -41,7 +41,7 @@ public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode if (mode == 0 || mode == 2) { objectiveValue = buffer.read(COMPONENT); type = Type.values()[buffer.read(VAR_INT)]; - numberFormat = buffer.readOptional(Sidebar.NumberFormat::new); + numberFormat = buffer.read(Sidebar.NumberFormat.SERIALIZER.optional()); } return new ScoreboardObjectivePacket(objectiveName, mode, objectiveValue, type, numberFormat); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java index 6404a983a..83758bbe3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SoundEffectPacket.java @@ -20,7 +20,7 @@ public record SoundEffectPacket( float pitch, long seed ) implements ServerPacket.Play { - public static NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, SoundEffectPacket value) { buffer.write(SoundEvent.NETWORK_TYPE, value.soundEvent()); @@ -36,7 +36,7 @@ public record SoundEffectPacket( @Override public SoundEffectPacket read(@NotNull NetworkBuffer buffer) { return new SoundEffectPacket(buffer.read(SoundEvent.NETWORK_TYPE), - buffer.readEnum(Source.class), + buffer.read(NetworkBuffer.Enum(Source.class)), buffer.read(INT) * 8, buffer.read(INT) * 8, buffer.read(INT) * 8, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java index f87494d59..de0e842c3 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/StopSoundPacket.java @@ -11,7 +11,7 @@ import static net.minestom.server.network.NetworkBuffer.*; public record StopSoundPacket(byte flags, @Nullable Sound.Source source, @Nullable String sound) implements ServerPacket.Play { - public static NetworkBuffer.Type SERIALIZER = new Type<>() { + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, StopSoundPacket value) { buffer.write(BYTE, value.flags()); @@ -28,7 +28,7 @@ public record StopSoundPacket(byte flags, @Nullable Sound.Source source, @Override public StopSoundPacket read(@NotNull NetworkBuffer buffer) { byte flags = buffer.read(BYTE); - var source = flags == 3 || flags == 1 ? buffer.readEnum(Sound.Source.class) : null; + var source = flags == 3 || flags == 1 ? buffer.read(NetworkBuffer.Enum(Sound.Source.class)) : null; var sound = flags == 2 || flags == 3 ? buffer.read(STRING) : null; return new StopSoundPacket(flags, source, sound); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java index 527317622..5d494afbc 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TabCompletePacket.java @@ -47,11 +47,9 @@ public record TabCompletePacket(int transactionId, int start, int length, if (matches.isEmpty()) return this; final List updatedMatches = matches.stream().map(match -> match.copyWithOperator(operator)).toList(); return new TabCompletePacket(transactionId, start, length, updatedMatches); - } - public record Match(@NotNull String match, - @Nullable Component tooltip) implements ComponentHolder { + public record Match(@NotNull String match, @Nullable Component tooltip) implements ComponentHolder { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( STRING, Match::match, COMPONENT.optional(), Match::tooltip, diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java index b1d284f7b..3ee509e2f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TeamsPacket.java @@ -5,6 +5,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.ComponentHolder; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -26,19 +27,16 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke public void write(@NotNull NetworkBuffer buffer, TeamsPacket value) { buffer.write(STRING, value.teamName); buffer.write(BYTE, (byte) value.action.id()); - buffer.write(value.action); + @SuppressWarnings("unchecked") final Type type = (Type) actionSerializer(value.action.id()); + buffer.write(type, value.action); } @Override public @NotNull TeamsPacket read(@NotNull NetworkBuffer buffer) { - return new TeamsPacket(buffer.read(STRING), switch (buffer.read(BYTE)) { - case 0 -> new CreateTeamAction(buffer); - case 1 -> new RemoveTeamAction(); - case 2 -> new UpdateTeamAction(buffer); - case 3 -> new AddEntitiesToTeamAction(buffer); - case 4 -> new RemoveEntitiesToTeamAction(buffer); - default -> throw new RuntimeException("Unknown action id"); - }); + final String teamName = buffer.read(STRING); + final byte actionId = buffer.read(BYTE); + final var type = actionSerializer(actionId); + return new TeamsPacket(teamName, type.read(buffer)); } }; @@ -47,6 +45,17 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke return this.action instanceof ComponentHolder holder ? holder.components() : List.of(); } + private static Type actionSerializer(int id) { + return switch (id) { + case 0 -> CreateTeamAction.SERIALIZER; + case 1 -> RemoveTeamAction.SERIALIZER; + case 2 -> UpdateTeamAction.SERIALIZER; + case 3 -> AddEntitiesToTeamAction.SERIALIZER; + case 4 -> RemoveEntitiesToTeamAction.SERIALIZER; + default -> throw new RuntimeException("Unknown action id"); + }; + } + @Override public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator operator) { return new TeamsPacket( @@ -57,37 +66,39 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke ); } - public sealed interface Action extends NetworkBuffer.Writer - permits CreateTeamAction, RemoveTeamAction, UpdateTeamAction, AddEntitiesToTeamAction, RemoveEntitiesToTeamAction { + public sealed interface Action permits CreateTeamAction, RemoveTeamAction, UpdateTeamAction, AddEntitiesToTeamAction, RemoveEntitiesToTeamAction { int id(); } public record CreateTeamAction(Component displayName, byte friendlyFlags, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, NamedTextColor teamColor, Component teamPrefix, Component teamSuffix, - Collection entities) implements Action, ComponentHolder { + List entities) implements Action, ComponentHolder { public CreateTeamAction { entities = List.copyOf(entities); } - public CreateTeamAction(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.read(BYTE), - NameTagVisibility.fromIdentifier(reader.read(STRING)), CollisionRule.fromIdentifier(reader.read(STRING)), - NamedTextColor.namedColor(reader.read(VAR_INT)), reader.read(COMPONENT), reader.read(COMPONENT), - reader.readCollection(STRING, MAX_MEMBERS)); - } + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, CreateTeamAction value) { + buffer.write(COMPONENT, value.displayName); + buffer.write(BYTE, value.friendlyFlags); + buffer.write(STRING, value.nameTagVisibility.getIdentifier()); + buffer.write(STRING, value.collisionRule.getIdentifier()); + buffer.write(VAR_INT, AdventurePacketConvertor.getNamedTextColorValue(value.teamColor)); + buffer.write(COMPONENT, value.teamPrefix); + buffer.write(COMPONENT, value.teamSuffix); + buffer.write(STRING.list(), value.entities); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, displayName); - writer.write(BYTE, friendlyFlags); - writer.write(STRING, nameTagVisibility.getIdentifier()); - writer.write(STRING, collisionRule.getIdentifier()); - writer.write(VAR_INT, AdventurePacketConvertor.getNamedTextColorValue(teamColor)); - writer.write(COMPONENT, teamPrefix); - writer.write(COMPONENT, teamSuffix); - writer.writeCollection(STRING, entities); - } + @Override + public CreateTeamAction read(@NotNull NetworkBuffer buffer) { + return new CreateTeamAction(buffer.read(COMPONENT), buffer.read(BYTE), + NameTagVisibility.fromIdentifier(buffer.read(STRING)), CollisionRule.fromIdentifier(buffer.read(STRING)), + NamedTextColor.namedColor(buffer.read(VAR_INT)), buffer.read(COMPONENT), buffer.read(COMPONENT), + buffer.read(STRING.list(MAX_MEMBERS))); + } + }; @Override public int id() { @@ -115,9 +126,7 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke } public record RemoveTeamAction() implements Action { - @Override - public void write(@NotNull NetworkBuffer writer) { - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template(RemoveTeamAction::new); @Override public int id() { @@ -131,23 +140,26 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke Component teamPrefix, Component teamSuffix) implements Action, ComponentHolder { - public UpdateTeamAction(@NotNull NetworkBuffer reader) { - this(reader.read(COMPONENT), reader.read(BYTE), - NameTagVisibility.fromIdentifier(reader.read(STRING)), CollisionRule.fromIdentifier(reader.read(STRING)), - NamedTextColor.namedColor(reader.read(VAR_INT)), - reader.read(COMPONENT), reader.read(COMPONENT)); - } + public static final NetworkBuffer.Type SERIALIZER = new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, UpdateTeamAction value) { + buffer.write(COMPONENT, value.displayName); + buffer.write(BYTE, value.friendlyFlags); + buffer.write(STRING, value.nameTagVisibility.getIdentifier()); + buffer.write(STRING, value.collisionRule.getIdentifier()); + buffer.write(VAR_INT, AdventurePacketConvertor.getNamedTextColorValue(value.teamColor)); + buffer.write(COMPONENT, value.teamPrefix); + buffer.write(COMPONENT, value.teamSuffix); + } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(COMPONENT, displayName); - writer.write(BYTE, friendlyFlags); - writer.write(STRING, nameTagVisibility.getIdentifier()); - writer.write(STRING, collisionRule.getIdentifier()); - writer.write(VAR_INT, AdventurePacketConvertor.getNamedTextColorValue(teamColor)); - writer.write(COMPONENT, teamPrefix); - writer.write(COMPONENT, teamSuffix); - } + @Override + public UpdateTeamAction read(@NotNull NetworkBuffer buffer) { + return new UpdateTeamAction(buffer.read(COMPONENT), buffer.read(BYTE), + NameTagVisibility.fromIdentifier(buffer.read(STRING)), CollisionRule.fromIdentifier(buffer.read(STRING)), + NamedTextColor.namedColor(buffer.read(VAR_INT)), + buffer.read(COMPONENT), buffer.read(COMPONENT)); + } + }; @Override public int id() { @@ -173,19 +185,19 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke } } - public record AddEntitiesToTeamAction(@NotNull Collection<@NotNull String> entities) implements Action { + public record AddEntitiesToTeamAction(@NotNull List<@NotNull String> entities) implements Action { public AddEntitiesToTeamAction { entities = List.copyOf(entities); } - public AddEntitiesToTeamAction(@NotNull NetworkBuffer reader) { - this(reader.readCollection(STRING, MAX_MEMBERS)); + public AddEntitiesToTeamAction(Collection entities) { + this(List.copyOf(entities)); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(STRING, entities); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.list(MAX_MEMBERS), AddEntitiesToTeamAction::entities, + AddEntitiesToTeamAction::new + ); @Override public int id() { @@ -193,19 +205,19 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke } } - public record RemoveEntitiesToTeamAction(@NotNull Collection<@NotNull String> entities) implements Action { + public record RemoveEntitiesToTeamAction(@NotNull List<@NotNull String> entities) implements Action { public RemoveEntitiesToTeamAction { entities = List.copyOf(entities); } - public RemoveEntitiesToTeamAction(@NotNull NetworkBuffer reader) { - this(reader.readCollection(STRING, MAX_MEMBERS)); + public RemoveEntitiesToTeamAction(Collection entities) { + this(List.copyOf(entities)); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.writeCollection(STRING, entities); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING.list(MAX_MEMBERS), RemoveEntitiesToTeamAction::entities, + RemoveEntitiesToTeamAction::new + ); @Override public int id() { 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 a0da0be28..6156d7b64 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 @@ -36,9 +36,9 @@ public record UnlockRecipesPacket(int mode, buffer.write(BOOLEAN, value.smokerRecipeBookOpen); buffer.write(BOOLEAN, value.smokerRecipeBookFilterActive); - buffer.writeCollection(STRING, value.recipeIds); + buffer.write(STRING.list(), value.recipeIds); if (value.mode == 0) { - buffer.writeCollection(STRING, value.initRecipeIds); + buffer.write(STRING.list(), value.initRecipeIds); } } @@ -53,8 +53,8 @@ public record UnlockRecipesPacket(int mode, var blastFurnaceRecipeBookFilterActive = buffer.read(BOOLEAN); var smokerRecipeBookOpen = buffer.read(BOOLEAN); var smokerRecipeBookFilterActive = buffer.read(BOOLEAN); - var recipeIds = buffer.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES); - var initRecipeIds = mode == 0 ? buffer.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES) : null; + var recipeIds = buffer.read(STRING.list(DeclareRecipesPacket.MAX_RECIPES)); + var initRecipeIds = mode == 0 ? buffer.read(STRING.list(DeclareRecipesPacket.MAX_RECIPES)) : null; return new UnlockRecipesPacket(mode, craftingRecipeBookOpen, craftingRecipeBookFilterActive, smeltingRecipeBookOpen, smeltingRecipeBookFilterActive, 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 c06c54007..4f4755b94 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 @@ -1,6 +1,7 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.data.LightData; import org.jetbrains.annotations.NotNull; @@ -9,17 +10,10 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record UpdateLightPacket(int chunkX, int chunkZ, @NotNull LightData lightData) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, UpdateLightPacket value) { - buffer.write(VAR_INT, value.chunkX); - buffer.write(VAR_INT, value.chunkZ); - buffer.write(value.lightData); - } - - @Override - public UpdateLightPacket read(@NotNull NetworkBuffer buffer) { - return new UpdateLightPacket(buffer.read(VAR_INT), buffer.read(VAR_INT), new LightData(buffer)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, UpdateLightPacket::chunkX, + VAR_INT, UpdateLightPacket::chunkZ, + LightData.SERIALIZER, UpdateLightPacket::lightData, + UpdateLightPacket::new + ); } 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 688c9080f..4c6468daf 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.kyori.adventure.text.Component; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.scoreboard.Sidebar; import org.jetbrains.annotations.NotNull; @@ -9,10 +10,6 @@ import org.jetbrains.annotations.Nullable; import static net.minestom.server.network.NetworkBuffer.*; -// public record ClientboundSetScorePacket(String owner, String objectiveName, -// int score, @Nullable Component display, @Nullable NumberFormat numberFormat) implements Packet -//{ - public record UpdateScorePacket( @NotNull String entityName, @NotNull String objectiveName, @@ -20,20 +17,12 @@ public record UpdateScorePacket( @Nullable Component displayName, @Nullable Sidebar.NumberFormat numberFormat ) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, @NotNull UpdateScorePacket value) { - buffer.write(STRING, value.entityName); - buffer.write(STRING, value.objectiveName); - buffer.write(VAR_INT, value.score); - buffer.writeOptional(COMPONENT, value.displayName); - buffer.writeOptional(value.numberFormat); - } - - @Override - public @NotNull UpdateScorePacket read(@NotNull NetworkBuffer buffer) { - return new UpdateScorePacket(buffer.read(STRING), buffer.read(STRING), buffer.read(VAR_INT), - buffer.readOptional(COMPONENT), buffer.readOptional(Sidebar.NumberFormat::new)); - } - }; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, UpdateScorePacket::entityName, + STRING, UpdateScorePacket::objectiveName, + VAR_INT, UpdateScorePacket::score, + COMPONENT.optional(), UpdateScorePacket::displayName, + Sidebar.NumberFormat.SERIALIZER.optional(), UpdateScorePacket::numberFormat, + UpdateScorePacket::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java index 877832732..c0ea0fbdc 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java @@ -15,7 +15,7 @@ import java.util.stream.Collectors; import static net.minestom.server.network.NetworkBuffer.*; public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] data, - @NotNull Map blockEntities) implements NetworkBuffer.Writer { + @NotNull Map blockEntities) { public ChunkData { blockEntities = blockEntities.entrySet() .stream() @@ -23,34 +23,37 @@ public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); } - public ChunkData(@NotNull NetworkBuffer reader) { - this((CompoundBinaryTag) reader.read(NBT), reader.read(BYTE_ARRAY), - readBlockEntities(reader)); - } + public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ChunkData value) { + // Heightmaps + buffer.write(NBT_COMPOUND, value.heightmaps); + // Data + buffer.write(BYTE_ARRAY, value.data); + // Block entities + buffer.write(VAR_INT, value.blockEntities.size()); + for (var entry : value.blockEntities.entrySet()) { + final int index = entry.getKey(); + final Block block = entry.getValue(); + final var registry = block.registry(); - @Override - public void write(@NotNull NetworkBuffer writer) { - // Heightmaps - writer.write(NBT, this.heightmaps); - // Data - writer.write(BYTE_ARRAY, data); - // Block entities - writer.write(VAR_INT, blockEntities.size()); - for (var entry : blockEntities.entrySet()) { - final int index = entry.getKey(); - final Block block = entry.getValue(); - final var registry = block.registry(); + final Point point = ChunkUtils.getBlockPosition(index, 0, 0); + buffer.write(BYTE, (byte) ((point.blockX() & 15) << 4 | point.blockZ() & 15)); // xz + buffer.write(SHORT, (short) point.blockY()); // y - final Point point = ChunkUtils.getBlockPosition(index, 0, 0); - writer.write(BYTE, (byte) ((point.blockX() & 15) << 4 | point.blockZ() & 15)); // xz - writer.write(SHORT, (short) point.blockY()); // y - - writer.write(VAR_INT, registry.blockEntityId()); - final CompoundBinaryTag nbt = BlockUtils.extractClientNbt(block); - assert nbt != null; - writer.write(NBT, nbt); // block nbt + buffer.write(VAR_INT, registry.blockEntityId()); + final CompoundBinaryTag nbt = BlockUtils.extractClientNbt(block); + assert nbt != null; + buffer.write(NBT, nbt); // block nbt + } } - } + + @Override + public ChunkData read(@NotNull NetworkBuffer buffer) { + return new ChunkData(buffer.read(NBT_COMPOUND), buffer.read(BYTE_ARRAY), + readBlockEntities(buffer)); + } + }; private static Map readBlockEntities(@NotNull NetworkBuffer reader) { final Map blockEntities = new HashMap<>(); @@ -59,7 +62,7 @@ public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] final byte xz = reader.read(BYTE); final short y = reader.read(SHORT); final int blockEntityId = reader.read(VAR_INT); - final CompoundBinaryTag nbt = (CompoundBinaryTag) reader.read(NBT); + final CompoundBinaryTag nbt = reader.read(NBT_COMPOUND); // TODO create block object } return blockEntities; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/LightData.java b/src/main/java/net/minestom/server/network/packet/server/play/data/LightData.java index cbcc44958..617bcfacb 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/data/LightData.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/LightData.java @@ -1,39 +1,30 @@ package net.minestom.server.network.packet.server.play.data; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.NotNull; import java.util.BitSet; import java.util.List; +import static net.minestom.server.network.NetworkBuffer.BITSET; import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY; -import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY; public record LightData( @NotNull BitSet skyMask, @NotNull BitSet blockMask, @NotNull BitSet emptySkyMask, @NotNull BitSet emptyBlockMask, @NotNull List skyLight, @NotNull List blockLight -) implements NetworkBuffer.Writer { +) { public static final int MAX_SECTIONS = 4096 / 16; - public LightData(@NotNull NetworkBuffer reader) { - this( - BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)), - BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)), - reader.readCollection(BYTE_ARRAY, MAX_SECTIONS), reader.readCollection(BYTE_ARRAY, MAX_SECTIONS) - ); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(LONG_ARRAY, skyMask.toLongArray()); - writer.write(LONG_ARRAY, blockMask.toLongArray()); - - writer.write(LONG_ARRAY, emptySkyMask.toLongArray()); - writer.write(LONG_ARRAY, emptyBlockMask.toLongArray()); - - writer.writeCollection(BYTE_ARRAY, skyLight); - writer.writeCollection(BYTE_ARRAY, blockLight); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BITSET, LightData::skyMask, + BITSET, LightData::blockMask, + BITSET, LightData::emptySkyMask, + BITSET, LightData::emptyBlockMask, + BYTE_ARRAY.list(MAX_SECTIONS), LightData::skyLight, + BYTE_ARRAY.list(MAX_SECTIONS), LightData::blockLight, + LightData::new + ); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/WorldPos.java b/src/main/java/net/minestom/server/network/packet/server/play/data/WorldPos.java index 42b2d5422..660b51020 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/data/WorldPos.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/WorldPos.java @@ -3,25 +3,17 @@ package net.minestom.server.network.packet.server.play.data; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; -import static net.minestom.server.network.NetworkBuffer.STRING; +public record WorldPos(@NotNull String dimension, @NotNull Point blockPosition) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.STRING, WorldPos::dimension, + NetworkBuffer.BLOCK_POSITION, WorldPos::blockPosition, + WorldPos::new + ); -public record WorldPos(@NotNull String dimension, @NotNull Point blockPosition) implements NetworkBuffer.Writer { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type() { - @Override - public void write(@NotNull NetworkBuffer buffer, WorldPos value) { - buffer.write(NetworkBuffer.STRING, value.dimension); - buffer.write(NetworkBuffer.BLOCK_POSITION, value.blockPosition); - } - - @Override - public WorldPos read(@NotNull NetworkBuffer buffer) { - return new WorldPos(buffer.read(NetworkBuffer.STRING), buffer.read(NetworkBuffer.BLOCK_POSITION)); - } - }; public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new WorldPos(tag.getString("dimension"), BinaryTagSerializer.BLOCK_POSITION.read(tag.get("pos"))), pos -> CompoundBinaryTag.builder() @@ -30,10 +22,6 @@ public record WorldPos(@NotNull String dimension, @NotNull Point blockPosition) .build() ); - public WorldPos(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(BLOCK_POSITION)); - } - public @NotNull WorldPos withDimension(@NotNull String dimension) { return new WorldPos(dimension, blockPosition); } @@ -41,11 +29,4 @@ public record WorldPos(@NotNull String dimension, @NotNull Point blockPosition) public @NotNull WorldPos withBlockPosition(@NotNull Point blockPosition) { return new WorldPos(dimension, blockPosition); } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, dimension); - writer.write(BLOCK_POSITION, blockPosition); - } - } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/player/GameProfile.java b/src/main/java/net/minestom/server/network/player/GameProfile.java index 7ba79c910..63ed3d9c2 100644 --- a/src/main/java/net/minestom/server/network/player/GameProfile.java +++ b/src/main/java/net/minestom/server/network/player/GameProfile.java @@ -1,6 +1,8 @@ package net.minestom.server.network.player; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,33 +23,23 @@ public record GameProfile(@NotNull UUID uuid, @NotNull String name, properties = List.copyOf(properties); } - public GameProfile(@NotNull NetworkBuffer reader) { - this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.readCollection(Property::new, MAX_PROPERTIES)); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.UUID, GameProfile::uuid, + STRING, GameProfile::name, + Property.SERIALIZER.list(MAX_PROPERTIES), GameProfile::properties, + GameProfile::new + ); - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.UUID, uuid); - writer.write(STRING, name); - writer.writeCollection(properties); - } - - public record Property(@NotNull String name, @NotNull String value, - @Nullable String signature) implements NetworkBuffer.Writer { + public record Property(@NotNull String name, @NotNull String value, @Nullable String signature) { public Property(@NotNull String name, @NotNull String value) { this(name, value, null); } - public Property(@NotNull NetworkBuffer reader) { - this(reader.read(STRING), reader.read(STRING), - reader.readOptional(STRING)); - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(STRING, name); - writer.write(STRING, value); - writer.writeOptional(STRING, signature); - } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + STRING, Property::name, + STRING, Property::value, + STRING.optional(), Property::signature, + Property::new + ); } } diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index 2f2fe09f8..a98bef5a7 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -1,40 +1,50 @@ package net.minestom.server.network.player; import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.entity.Player; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.ListenerHandle; import net.minestom.server.event.player.PlayerPacketOutEvent; import net.minestom.server.extras.mojangAuth.MojangCrypt; +import net.minestom.server.network.ConnectionState; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.PacketReading; +import net.minestom.server.network.packet.PacketVanilla; +import net.minestom.server.network.packet.PacketWriting; import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.client.common.ClientCookieResponsePacket; +import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket; +import net.minestom.server.network.packet.client.common.ClientPingRequestPacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; +import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; +import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; +import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; +import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; +import net.minestom.server.network.packet.client.status.StatusRequestPacket; import net.minestom.server.network.packet.server.*; import net.minestom.server.network.packet.server.login.SetCompressionPacket; -import net.minestom.server.network.socket.Worker; -import net.minestom.server.utils.ObjectPool; -import net.minestom.server.utils.PacketUtils; -import net.minestom.server.utils.binary.BinaryBuffer; import net.minestom.server.utils.validate.Check; -import org.jctools.queues.MessagePassingQueue; +import org.jctools.queues.MpscUnboundedXaddArrayQueue; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.crypto.Cipher; import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; +import java.io.EOFException; import java.io.IOException; import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; import java.nio.channels.SocketChannel; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import java.util.zip.DataFormatException; /** @@ -44,16 +54,21 @@ import java.util.zip.DataFormatException; */ @ApiStatus.Internal public class PlayerSocketConnection extends PlayerConnection { - private final static Logger LOGGER = LoggerFactory.getLogger(PlayerSocketConnection.class); - private static final ObjectPool POOL = ObjectPool.BUFFER_POOL; + private static final Set> IMMEDIATE_PROCESS_PACKETS = Set.of( + ClientCookieResponsePacket.class, + StatusRequestPacket.class, + ClientLoginStartPacket.class, + ClientPingRequestPacket.class, + ClientKeepAlivePacket.class, + ClientEncryptionResponsePacket.class, + ClientHandshakePacket.class, + ClientLoginPluginResponsePacket.class, + ClientLoginAcknowledgedPacket.class + ); - private final Worker worker; - private final MessagePassingQueue workerQueue; private final SocketChannel channel; private SocketAddress remoteAddress; - private volatile boolean compressed = false; - //Could be null. Only used for Mojang Auth private volatile EncryptionContext encryptionContext; private byte[] nonce = new byte[4]; @@ -65,74 +80,87 @@ public class PlayerSocketConnection extends PlayerConnection { private int serverPort; private int protocolVersion; - private final List waitingBuffers = new ArrayList<>(); - private final AtomicReference tickBuffer = new AtomicReference<>(POOL.get()); - private BinaryBuffer cacheBuffer; + private final NetworkBuffer readBuffer = NetworkBuffer.resizableBuffer(ServerFlag.POOLED_BUFFER_SIZE, MinecraftServer.process()); + private final MpscUnboundedXaddArrayQueue packetQueue = new MpscUnboundedXaddArrayQueue<>(1024); + + private final AtomicLong sentPacketCounter = new AtomicLong(); + // Index where compression starts, linked to `sentPacketCounter` + // Used instead of a simple boolean so we can get proper timing for serialization + private volatile long compressionStart = Long.MAX_VALUE; + + final ReentrantLock writeLock = new ReentrantLock(); + final Condition writeCondition = writeLock.newCondition(); private final ListenerHandle outgoing = EventDispatcher.getHandle(PlayerPacketOutEvent.class); - public PlayerSocketConnection(@NotNull Worker worker, @NotNull SocketChannel channel, SocketAddress remoteAddress) { + public PlayerSocketConnection(@NotNull SocketChannel channel, SocketAddress remoteAddress) { super(); - this.worker = worker; - this.workerQueue = worker.queue(); this.channel = channel; this.remoteAddress = remoteAddress; } - public void processPackets(BinaryBuffer readBuffer, PacketParser.Client packetParser) { - // Decrypt data - { - final EncryptionContext encryptionContext = this.encryptionContext; - if (encryptionContext != null) { - ByteBuffer input = readBuffer.asByteBuffer(0, readBuffer.writerOffset()); - try { - encryptionContext.decrypt().update(input, input.duplicate()); - } catch (ShortBufferException e) { - MinecraftServer.getExceptionManager().handleException(e); - return; - } - } + public void read(PacketParser packetParser) throws IOException { + NetworkBuffer readBuffer = this.readBuffer; + final long writeIndex = readBuffer.writeIndex(); + final int length = readBuffer.readChannel(channel); + // Decrypt newly read data + final EncryptionContext encryptionContext = this.encryptionContext; + if (encryptionContext != null) { + readBuffer.cipher(encryptionContext.decrypt(), writeIndex, length); } + // Process packets + processPackets(readBuffer, packetParser); + } + + private boolean compression() { + return compressionStart != Long.MAX_VALUE; + } + + private void processPackets(NetworkBuffer readBuffer, PacketParser packetParser) { // Read all packets + final PacketReading.Result result; try { - this.cacheBuffer = PacketUtils.readPackets(readBuffer, compressed, - (id, payload) -> { - if (!isOnline()) - return; // Prevent packet corruption - ClientPacket packet = null; - try { - NetworkBuffer networkBuffer = new NetworkBuffer(payload); - packet = packetParser.parse(getConnectionState(), id, networkBuffer); - payload.position(networkBuffer.readIndex()); - // Process the packet - if (packet.processImmediately()) { - MinecraftServer.getPacketListenerManager().processClientPacket(packet, this); - } else { - // To be processed during the next player tick - final Player player = getPlayer(); - assert player != null; - player.addPacketToQueue(packet); - } - } catch (Exception e) { - // Error while reading the packet - MinecraftServer.getExceptionManager().handleException(e); - } finally { - if (payload.position() != payload.limit()) { - LOGGER.warn("WARNING: Packet ({}) 0x{} not fully read ({}) {}", getConnectionState(), Integer.toHexString(id), payload, packet); - } - } - }); + result = PacketReading.readPackets( + readBuffer, + packetParser, + getConnectionState(), PacketVanilla::nextClientState, + compression() + ); } catch (DataFormatException e) { MinecraftServer.getExceptionManager().handleException(e); disconnect(); + return; } - } - - public void consumeCache(BinaryBuffer buffer) { - final BinaryBuffer cache = this.cacheBuffer; - if (cache != null) { - buffer.write(cache); - this.cacheBuffer = null; + switch (result) { + case PacketReading.Result.Success success -> { + for (ClientPacket packet : success.packets()) { + try { + final boolean processImmediately = IMMEDIATE_PROCESS_PACKETS.contains(packet.getClass()); + if (processImmediately) { + MinecraftServer.getPacketListenerManager().processClientPacket(packet, this); + } else { + // To be processed during the next player tick + final Player player = getPlayer(); + assert player != null; + player.addPacketToQueue(packet); + } + } catch (Exception e) { + MinecraftServer.getExceptionManager().handleException(e); + } + } + // Compact in case of incomplete read + readBuffer.compact(); + } + case PacketReading.Result.Empty ignored -> { + // Empty + } + case PacketReading.Result.Failure failure -> { + // Resize for next read + final long requiredCapacity = failure.requiredCapacity(); + assert requiredCapacity > readBuffer.capacity() : + "New capacity should be greater than the current one: " + requiredCapacity + " <= " + readBuffer.capacity(); + readBuffer.resize(requiredCapacity); + } } } @@ -153,36 +181,23 @@ public class PlayerSocketConnection extends PlayerConnection { * @throws IllegalStateException if encryption is already enabled for this connection */ public void startCompression() { - Check.stateCondition(compressed, "Compression is already enabled!"); + Check.stateCondition(compression(), "Compression is already enabled!"); + this.compressionStart = sentPacketCounter.get(); final int threshold = MinecraftServer.getCompressionThreshold(); Check.stateCondition(threshold == 0, "Compression cannot be enabled because the threshold is equal to 0"); sendPacket(new SetCompressionPacket(threshold)); - this.compressed = true; } @Override public void sendPacket(@NotNull SendablePacket packet) { - final boolean compressed = this.compressed; - this.workerQueue.relaxedOffer(() -> writePacketSync(packet, compressed)); + this.packetQueue.relaxedOffer(packet); + signalWrite(); } @Override public void sendPackets(@NotNull Collection packets) { - final List packetsCopy = List.copyOf(packets); - final boolean compressed = this.compressed; - this.workerQueue.relaxedOffer(() -> { - for (SendablePacket packet : packetsCopy) writePacketSync(packet, compressed); - }); - } - - @ApiStatus.Internal - public void write(@NotNull ByteBuffer buffer, int index, int length) { - this.workerQueue.relaxedOffer(() -> writeBufferSync(buffer, index, length)); - } - - @ApiStatus.Internal - public void write(@NotNull ByteBuffer buffer) { - write(buffer, buffer.position(), buffer.remaining()); + for (SendablePacket packet : packets) this.packetQueue.relaxedOffer(packet); + signalWrite(); } @Override @@ -202,18 +217,6 @@ public class PlayerSocketConnection extends PlayerConnection { this.remoteAddress = remoteAddress; } - @Override - public void disconnect() { - super.disconnect(); - this.workerQueue.relaxedOffer(() -> { - this.worker.disconnect(this, channel); - final BinaryBuffer tick = tickBuffer.getAndSet(null); - if (tick != null) POOL.add(tick); - for (BinaryBuffer buffer : waitingBuffers) POOL.add(buffer); - this.waitingBuffers.clear(); - }); - } - public @NotNull SocketChannel getChannel() { return channel; } @@ -301,112 +304,163 @@ public class PlayerSocketConnection extends PlayerConnection { this.nonce = nonce; } - private void writePacketSync(SendablePacket packet, boolean compressed) { - if (!channel.isConnected()) return; - final Player player = getPlayer(); - // Outgoing event - if (player != null && outgoing.hasListener()) { - final ServerPacket serverPacket = SendablePacket.extractServerPacket(getConnectionState(), packet); - PlayerPacketOutEvent event = new PlayerPacketOutEvent(player, serverPacket); - outgoing.call(event); - if (event.isCancelled()) return; - } - // Write packet - if (packet instanceof ServerPacket serverPacket) { - writeServerPacketSync(serverPacket, compressed); - } else if (packet instanceof FramedPacket framedPacket) { - var buffer = framedPacket.body(); - writeBufferSync(buffer, 0, buffer.limit()); - } else if (packet instanceof CachedPacket cachedPacket) { - var buffer = cachedPacket.body(getConnectionState()); - if (buffer != null) writeBufferSync(buffer, buffer.position(), buffer.remaining()); - else writeServerPacketSync(cachedPacket.packet(getConnectionState()), compressed); - } else if (packet instanceof LazyPacket lazyPacket) { - writeServerPacketSync(lazyPacket.packet(), compressed); - } else { - throw new RuntimeException("Unknown packet type: " + packet.getClass().getName()); + private boolean writeSendable(NetworkBuffer buffer, SendablePacket sendable, boolean compressed) { + final long start = buffer.writeIndex(); + final boolean result = writePacketSync(buffer, sendable, compressed); + if (!result) return false; + // Encrypt data + final long length = buffer.writeIndex() - start; + final EncryptionContext encryptionContext = this.encryptionContext; + if (encryptionContext != null && length > 0) { // Encryption support + buffer.cipher(encryptionContext.encrypt(), start, length); } + return true; } - private void writeServerPacketSync(ServerPacket serverPacket, boolean compressed) { + private boolean writePacketSync(NetworkBuffer buffer, SendablePacket packet, boolean compressed) { final Player player = getPlayer(); + final ConnectionState state = getConnectionState(); if (player != null) { - if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && serverPacket instanceof ServerPacket.ComponentHolding) { - serverPacket = ((ServerPacket.ComponentHolding) serverPacket).copyWithOperator(component -> + // Outgoing event + if (outgoing.hasListener()) { + final ServerPacket serverPacket = SendablePacket.extractServerPacket(state, packet); + if (serverPacket != null) { // Events are not called for buffered packets + PlayerPacketOutEvent event = new PlayerPacketOutEvent(player, serverPacket); + outgoing.call(event); + if (event.isCancelled()) return true; + } + } + // Translation + if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && packet instanceof ServerPacket.ComponentHolding) { + packet = ((ServerPacket.ComponentHolding) packet).copyWithOperator(component -> MinestomAdventure.COMPONENT_TRANSLATOR.apply(component, Objects.requireNonNullElseGet(player.getLocale(), MinestomAdventure::getDefaultLocale))); } } - try (var hold = ObjectPool.PACKET_POOL.hold()) { - var buffer = PacketUtils.createFramedPacket(getConnectionState(), hold.get(), serverPacket, compressed); - writeBufferSync(buffer, 0, buffer.limit()); + // Write packet + final long start = buffer.writeIndex(); + final int compressionThreshold = compressed ? MinecraftServer.getCompressionThreshold() : 0; + try { + return switch (packet) { + case ServerPacket serverPacket -> { + PacketWriting.writeFramedPacket(buffer, state, serverPacket, compressionThreshold); + yield true; + } + case FramedPacket framedPacket -> { + final NetworkBuffer body = framedPacket.body(); + yield writeBuffer(buffer, body, 0, body.capacity()); + } + case CachedPacket cachedPacket -> { + final NetworkBuffer body = cachedPacket.body(state); + if (body != null) { + yield writeBuffer(buffer, body, 0, body.capacity()); + } else { + PacketWriting.writeFramedPacket(buffer, state, cachedPacket.packet(state), compressionThreshold); + yield true; + } + } + case LazyPacket lazyPacket -> { + PacketWriting.writeFramedPacket(buffer, state, lazyPacket.packet(), compressionThreshold); + yield true; + } + case BufferedPacket bufferedPacket -> { + final NetworkBuffer rawBuffer = bufferedPacket.buffer(); + final long index = bufferedPacket.index(); + final long length = bufferedPacket.length(); + yield writeBuffer(buffer, rawBuffer, index, length); + } + }; + } catch (IndexOutOfBoundsException exception) { + buffer.writeIndex(start); + return false; } } - private void writeBufferSync(@NotNull ByteBuffer buffer, int index, int length) { - // Encrypt data - final EncryptionContext encryptionContext = this.encryptionContext; - if (encryptionContext != null) { // Encryption support - try (var hold = ObjectPool.PACKET_POOL.hold()) { - ByteBuffer output = hold.get(); - try { - length = encryptionContext.encrypt().update(buffer.slice(index, length), output); - writeBufferSync0(output, 0, length); - } catch (ShortBufferException e) { - MinecraftServer.getExceptionManager().handleException(e); - } + private boolean writeBuffer(NetworkBuffer buffer, NetworkBuffer body, long index, long length) { + if (buffer.writableBytes() < length) { + // Not enough space in the buffer + return false; + } + NetworkBuffer.copy(body, index, buffer, buffer.writeIndex(), length); + buffer.advanceWrite(length); + return true; + } + + private NetworkBuffer writeLeftover = null; + + public void flushSync() throws IOException { + // Write leftover if any + NetworkBuffer leftover = this.writeLeftover; + if (leftover != null) { + final boolean success = leftover.writeChannel(channel); + if (success) { + this.writeLeftover = null; + PacketVanilla.PACKET_POOL.add(leftover); + } else { + // Failed to write the whole leftover, try again next flush return; } } - writeBufferSync0(buffer, index, length); + // Consume queued packets + var packetQueue = this.packetQueue; + if (packetQueue.isEmpty()) { + awaitWrite(); + } + if (!channel.isConnected()) throw new EOFException("Channel is closed"); + NetworkBuffer buffer = PacketVanilla.PACKET_POOL.get(); + // Write to buffer + SendablePacket packet; + int written = 0; + while ((packet = packetQueue.peek()) != null) { + final boolean compressed = sentPacketCounter.get() > compressionStart; + final boolean success = writeSendable(buffer, packet, compressed); + assert !success || buffer.writeIndex() > 0; + // Poll the packet only if fully written + if (success) { + // Packet fully written + packetQueue.poll(); + sentPacketCounter.getAndIncrement(); + written++; + } else { + if (written == 0) { + assert buffer.writeIndex() == 0; + // Try again with a bigger buffer + final long newSize = Math.min(buffer.capacity() * 2, ServerFlag.MAX_PACKET_SIZE); + buffer.resize(newSize); + } else { + // At least one packet has been written + // Not worth resizing to fit more, we'll try again next flush + break; + } + } + } + // Write to channel + final boolean success = buffer.writeChannel(channel); + // Keep the buffer if not fully written + if (success) PacketVanilla.PACKET_POOL.add(buffer); + else this.writeLeftover = buffer; } - private void writeBufferSync0(@NotNull ByteBuffer buffer, int index, int length) { - BinaryBuffer localBuffer = tickBuffer.getPlain(); - if (localBuffer == null) - return; // Socket is closed - final int capacity = localBuffer.capacity(); - if (length <= capacity) { - if (!localBuffer.canWrite(length)) localBuffer = updateLocalBuffer(); - localBuffer.write(buffer, index, length); - } else { - final int bufferCount = length / capacity + 1; - for (int i = 0; i < bufferCount; i++) { - final int sliceStart = i * capacity; - final int sliceLength = Math.min(length, sliceStart + capacity) - sliceStart; - if (!localBuffer.canWrite(sliceLength)) localBuffer = updateLocalBuffer(); - localBuffer.write(buffer, sliceStart, sliceLength); - } + public void awaitWrite() { + try { + this.writeLock.lock(); + //noinspection ResultOfMethodCallIgnored + this.writeCondition.await(50, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + this.writeLock.unlock(); } } - public void flushSync() throws IOException { - final SocketChannel channel = this.channel; - final List waitingBuffers = this.waitingBuffers; - if (!channel.isConnected()) throw new ClosedChannelException(); - if (waitingBuffers.isEmpty()) { - BinaryBuffer localBuffer = tickBuffer.getPlain(); - if (localBuffer == null) - return; // Socket is closed - localBuffer.writeChannel(channel); - } else { - // Write as much as possible from the waiting list - Iterator iterator = waitingBuffers.iterator(); - while (iterator.hasNext()) { - BinaryBuffer waitingBuffer = iterator.next(); - if (!waitingBuffer.writeChannel(channel)) break; - iterator.remove(); - POOL.add(waitingBuffer); - } + public void signalWrite() { + try { + this.writeLock.lock(); + this.writeCondition.signal(); + } finally { + this.writeLock.unlock(); } } - private BinaryBuffer updateLocalBuffer() { - BinaryBuffer newBuffer = POOL.get(); - this.waitingBuffers.add(tickBuffer.getPlain()); - this.tickBuffer.setPlain(newBuffer); - return newBuffer; - } - record EncryptionContext(Cipher encrypt, Cipher decrypt) { } } diff --git a/src/main/java/net/minestom/server/network/plugin/LoginPlugin.java b/src/main/java/net/minestom/server/network/plugin/LoginPlugin.java new file mode 100644 index 000000000..558d70463 --- /dev/null +++ b/src/main/java/net/minestom/server/network/plugin/LoginPlugin.java @@ -0,0 +1,27 @@ +package net.minestom.server.network.plugin; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +public final class LoginPlugin { + public record Request(String channel, byte @NotNull [] payload, CompletableFuture responseFuture) { + public Request { + Objects.requireNonNull(channel); + Objects.requireNonNull(payload); + Objects.requireNonNull(responseFuture); + } + + public Request(String channel, byte @NotNull [] requestPayload) { + this(channel, requestPayload, new CompletableFuture<>()); + } + } + + public record Response(String channel, byte @Nullable [] payload) { + public Response { + Objects.requireNonNull(channel); + } + } +} diff --git a/src/main/java/net/minestom/server/network/plugin/LoginPluginMessageProcessor.java b/src/main/java/net/minestom/server/network/plugin/LoginPluginMessageProcessor.java index 5872450e5..70a6dc138 100644 --- a/src/main/java/net/minestom/server/network/plugin/LoginPluginMessageProcessor.java +++ b/src/main/java/net/minestom/server/network/plugin/LoginPluginMessageProcessor.java @@ -4,7 +4,6 @@ import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket; import net.minestom.server.network.player.PlayerConnection; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -16,34 +15,34 @@ import java.util.concurrent.atomic.AtomicInteger; public class LoginPluginMessageProcessor { private static final AtomicInteger REQUEST_ID = new AtomicInteger(0); - private final Map requestByMsgId = new ConcurrentHashMap<>(); + private final Map requestByMsgId = new ConcurrentHashMap<>(); private final PlayerConnection connection; public LoginPluginMessageProcessor(@NotNull PlayerConnection connection) { this.connection = connection; } - public @NotNull CompletableFuture request(@NotNull String channel, byte @Nullable [] requestPayload) { - LoginPluginRequest request = new LoginPluginRequest(channel, requestPayload); + public @NotNull CompletableFuture request(@NotNull String channel, byte @NotNull [] requestPayload) { + LoginPlugin.Request request = new LoginPlugin.Request(channel, requestPayload); - int messageId = getNextMessageId(); + final int messageId = nextMessageId(); requestByMsgId.put(messageId, request); - connection.sendPacket(new LoginPluginRequestPacket(messageId, request.getChannel(), request.getRequestPayload())); + connection.sendPacket(new LoginPluginRequestPacket(messageId, request.channel(), request.payload())); - return request.getResponseFuture(); + return request.responseFuture(); } public void handleResponse(int messageId, byte[] responseData) throws Exception { - LoginPluginRequest request = requestByMsgId.remove(messageId); + LoginPlugin.Request request = requestByMsgId.remove(messageId); if (request == null) { throw new Exception("Received unexpected Login Plugin Response id " + messageId + " of " + responseData.length + " bytes"); } try { - LoginPluginResponse response = LoginPluginResponse.fromPayload(request.getChannel(), responseData); - request.getResponseFuture().complete(response); + LoginPlugin.Response response = new LoginPlugin.Response(request.channel(), responseData); + request.responseFuture().complete(response); } catch (Throwable t) { - throw new Exception("Error handling Login Plugin Response on channel '" + request.getChannel() + "'", t); + throw new Exception("Error handling Login Plugin Response on channel '" + request.channel() + "'", t); } } @@ -51,14 +50,13 @@ public class LoginPluginMessageProcessor { if (requestByMsgId.isEmpty()) { return; } - CompletableFuture[] futures = requestByMsgId.values().stream() - .map(LoginPluginRequest::getResponseFuture) + .map(LoginPlugin.Request::responseFuture) .toArray(CompletableFuture[]::new); CompletableFuture.allOf(futures).get(timeout, timeUnit); } - - private static int getNextMessageId() { + + private static int nextMessageId() { return REQUEST_ID.getAndIncrement(); } } diff --git a/src/main/java/net/minestom/server/network/plugin/LoginPluginRequest.java b/src/main/java/net/minestom/server/network/plugin/LoginPluginRequest.java deleted file mode 100644 index bd699a3bb..000000000 --- a/src/main/java/net/minestom/server/network/plugin/LoginPluginRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.minestom.server.network.plugin; - -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.CompletableFuture; - -public class LoginPluginRequest { - private final String channel; - private final byte[] requestPayload; - private final CompletableFuture responseFuture = new CompletableFuture<>(); - - public LoginPluginRequest(String channel, @Nullable byte[] requestPayload) { - this.channel = channel; - this.requestPayload = requestPayload; - } - - public String getChannel() { - return channel; - } - - public @Nullable byte[] getRequestPayload() { - return requestPayload; - } - - public CompletableFuture getResponseFuture() { - return responseFuture; - } -} diff --git a/src/main/java/net/minestom/server/network/plugin/LoginPluginResponse.java b/src/main/java/net/minestom/server/network/plugin/LoginPluginResponse.java deleted file mode 100644 index 1dc92a301..000000000 --- a/src/main/java/net/minestom/server/network/plugin/LoginPluginResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.minestom.server.network.plugin; - -public class LoginPluginResponse { - private final String channel; - private final boolean understood; - private final byte[] payload; - - private LoginPluginResponse(String channel, boolean understood, byte[] payload) { - this.channel = channel; - this.understood = understood; - this.payload = payload; - } - - public String getChannel() { - return channel; - } - - public boolean isUnderstood() { - return understood; - } - - public byte[] getPayload() { - return payload; - } - - public static LoginPluginResponse fromPayload(String channel, byte[] payload) { - boolean understood = payload != null; - return new LoginPluginResponse(channel, understood, payload); - } -} diff --git a/src/main/java/net/minestom/server/network/socket/Server.java b/src/main/java/net/minestom/server/network/socket/Server.java index ee5f0224c..639928909 100644 --- a/src/main/java/net/minestom/server/network/socket/Server.java +++ b/src/main/java/net/minestom/server/network/socket/Server.java @@ -3,62 +3,57 @@ package net.minestom.server.network.socket; import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; import net.minestom.server.network.packet.PacketParser; +import net.minestom.server.network.packet.PacketVanilla; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.player.PlayerSocketConnection; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.EOFException; import java.io.IOException; import java.net.*; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.file.Files; -import java.util.Arrays; -import java.util.List; public final class Server { - private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); - private volatile boolean stop; - private final Selector selector = Selector.open(); - private final PacketParser.Client packetParser; - private final List workers; - private int index; + private final PacketParser packetParser; private ServerSocketChannel serverSocket; private SocketAddress socketAddress; private String address; private int port; - public Server(PacketParser.Client packetParser) throws IOException { + public Server(PacketParser packetParser) { this.packetParser = packetParser; - Worker[] workers = new Worker[ServerFlag.WORKER_COUNT]; - Arrays.setAll(workers, value -> new Worker(this)); - this.workers = List.of(workers); + } + + public Server() { + this(PacketVanilla.CLIENT_PACKET_PARSER); } @ApiStatus.Internal public void init(SocketAddress address) throws IOException { ProtocolFamily family; - if (address instanceof InetSocketAddress inetSocketAddress) { - this.address = inetSocketAddress.getHostString(); - this.port = inetSocketAddress.getPort(); - family = inetSocketAddress.getAddress().getAddress().length == 4 ? StandardProtocolFamily.INET : StandardProtocolFamily.INET6; - } else if (address instanceof UnixDomainSocketAddress unixDomainSocketAddress) { - this.address = "unix://" + unixDomainSocketAddress.getPath(); - this.port = 0; - family = StandardProtocolFamily.UNIX; - } else { - throw new IllegalArgumentException("Address must be an InetSocketAddress or a UnixDomainSocketAddress"); + switch (address) { + case InetSocketAddress inetSocketAddress -> { + this.address = inetSocketAddress.getHostString(); + this.port = inetSocketAddress.getPort(); + family = inetSocketAddress.getAddress().getAddress().length == 4 ? StandardProtocolFamily.INET : StandardProtocolFamily.INET6; + } + case UnixDomainSocketAddress unixDomainSocketAddress -> { + this.address = "unix://" + unixDomainSocketAddress.getPath(); + this.port = 0; + family = StandardProtocolFamily.UNIX; + } + default -> + throw new IllegalArgumentException("Address must be an InetSocketAddress or a UnixDomainSocketAddress"); } ServerSocketChannel server = ServerSocketChannel.open(family); server.bind(address); - server.configureBlocking(false); - server.register(selector, SelectionKey.OP_ACCEPT); this.serverSocket = server; this.socketAddress = address; @@ -69,31 +64,72 @@ public final class Server { @ApiStatus.Internal public void start() { - this.workers.forEach(Thread::start); - new Thread(() -> { + Thread.startVirtualThread(() -> { while (!stop) { - // Busy wait for connections try { - this.selector.select(key -> { - if (!key.isAcceptable()) return; - try { - // Register socket and forward to thread - Worker worker = findWorker(); - final SocketChannel client = serverSocket.accept(); - worker.receiveConnection(client); - } catch (IOException e) { - e.printStackTrace(); - } - }); + final SocketChannel client = serverSocket.accept(); + configureSocket(client); + PlayerSocketConnection connection = new PlayerSocketConnection(client, client.getRemoteAddress()); + Thread.startVirtualThread(() -> playerReadLoop(connection)); + Thread.startVirtualThread(() -> playerWriteLoop(connection)); } catch (IOException e) { - MinecraftServer.getExceptionManager().handleException(e); + throw new RuntimeException(e); } } - }, "Ms-entrypoint").start(); + }); } - public void tick() { - this.workers.forEach(Worker::tick); + private void configureSocket(SocketChannel channel) throws IOException { + if (channel.getLocalAddress() instanceof InetSocketAddress) { + Socket socket = channel.socket(); + socket.setSendBufferSize(ServerFlag.SOCKET_SEND_BUFFER_SIZE); + socket.setReceiveBufferSize(ServerFlag.SOCKET_RECEIVE_BUFFER_SIZE); + socket.setTcpNoDelay(ServerFlag.SOCKET_NO_DELAY); + socket.setSoTimeout(ServerFlag.SOCKET_TIMEOUT); + } + } + + private void playerReadLoop(PlayerSocketConnection connection) { + while (!stop) { + try { + // Read & process packets + connection.read(packetParser); + } catch (EOFException e) { + connection.disconnect(); + break; + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + connection.disconnect(); + break; + } + } + // Ensure the connection is not stuck waiting for packets to write + connection.signalWrite(); + } + + private void playerWriteLoop(PlayerSocketConnection connection) { + while (!stop) { + try { + connection.flushSync(); + } catch (EOFException e) { + connection.disconnect(); + break; + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + connection.disconnect(); + break; + } + if (!connection.isOnline()) { + try { + connection.flushSync(); + connection.getChannel().close(); + break; + } catch (IOException e) { + // Disconnect + break; + } + } + } } public boolean isOpen() { @@ -113,18 +149,10 @@ public final class Server { } catch (IOException e) { MinecraftServer.getExceptionManager().handleException(e); } - try { - this.selector.wakeup(); - this.selector.close(); - } catch (IOException e) { - LOGGER.error("Server socket selector could not be closed", e); - System.exit(-1); - } - this.workers.forEach(Worker::close); } @ApiStatus.Internal - public @NotNull PacketParser.Client packetParser() { + public @NotNull PacketParser packetParser() { return packetParser; } @@ -139,9 +167,4 @@ public final class Server { public int getPort() { return port; } - - private Worker findWorker() { - this.index = ++index % ServerFlag.WORKER_COUNT; - return workers.get(index); - } } diff --git a/src/main/java/net/minestom/server/network/socket/Worker.java b/src/main/java/net/minestom/server/network/socket/Worker.java deleted file mode 100644 index 40b2c5097..000000000 --- a/src/main/java/net/minestom/server/network/socket/Worker.java +++ /dev/null @@ -1,149 +0,0 @@ -package net.minestom.server.network.socket; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.ServerFlag; -import net.minestom.server.network.player.PlayerSocketConnection; -import net.minestom.server.thread.MinestomThread; -import net.minestom.server.utils.ObjectPool; -import net.minestom.server.utils.binary.BinaryBuffer; -import org.jctools.queues.MessagePassingQueue; -import org.jctools.queues.MpscUnboundedXaddArrayQueue; -import org.jetbrains.annotations.ApiStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.SocketChannel; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -@ApiStatus.Internal -public final class Worker extends MinestomThread { - private static final AtomicInteger COUNTER = new AtomicInteger(); - - private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); - - private final Selector selector; - private final Map connectionMap = new ConcurrentHashMap<>(); - private final Server server; - private final MpscUnboundedXaddArrayQueue queue = new MpscUnboundedXaddArrayQueue<>(1024); - - Worker(Server server) { - super("Ms-worker-" + COUNTER.getAndIncrement()); - this.server = server; - try { - this.selector = Selector.open(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void tick() { - this.selector.wakeup(); - } - - public void close() { - try { - this.queue.drain(Runnable::run); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - this.selector.wakeup(); - try { - this.selector.close(); - } catch (IOException e) { - LOGGER.error("Worker Socket Selector could not be closed", e); - System.exit(-1); - } - } - - @Override - public void run() { - while (server.isOpen()) { - try { - try { - this.queue.drain(Runnable::run); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - // Flush all connections if needed - for (PlayerSocketConnection connection : connectionMap.values()) { - try { - connection.flushSync(); - } catch (Exception e) { - connection.disconnect(); - } - } - // Wait for an event - this.selector.select(key -> { - final SocketChannel channel = (SocketChannel) key.channel(); - if (!channel.isOpen()) return; - if (!key.isReadable()) return; - final PlayerSocketConnection connection = connectionMap.get(channel); - if (connection == null) { - try { - channel.close(); - } catch (IOException e) { - // Empty - } - return; - } - try { - try (var holder = ObjectPool.PACKET_POOL.hold()) { - BinaryBuffer readBuffer = BinaryBuffer.wrap(holder.get()); - // Consume last incomplete packet - connection.consumeCache(readBuffer); - // Read & process - readBuffer.readChannel(channel); - connection.processPackets(readBuffer, server.packetParser()); - } - } catch (IOException e) { - // TODO print exception? (should ignore disconnection) - connection.disconnect(); - } catch (Throwable t) { - MinecraftServer.getExceptionManager().handleException(t); - connection.disconnect(); - } - }); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - } - } - - public void disconnect(PlayerSocketConnection connection, SocketChannel channel) { - assert !connection.isOnline(); - assert Thread.currentThread() == this; - this.connectionMap.remove(channel); - if (channel.isOpen()) { - try { - connection.flushSync(); - channel.close(); - } catch (IOException e) { - // Socket operation may fail if the socket is already closed - } - } - } - - void receiveConnection(SocketChannel channel) throws IOException { - this.connectionMap.put(channel, new PlayerSocketConnection(this, channel, channel.getRemoteAddress())); - channel.configureBlocking(false); - channel.register(selector, SelectionKey.OP_READ); - if (channel.getLocalAddress() instanceof InetSocketAddress) { - Socket socket = channel.socket(); - socket.setSendBufferSize(ServerFlag.SOCKET_SEND_BUFFER_SIZE); - socket.setReceiveBufferSize(ServerFlag.SOCKET_RECEIVE_BUFFER_SIZE); - socket.setTcpNoDelay(ServerFlag.SOCKET_NO_DELAY); - socket.setSoTimeout(30 * 1000); // 30 seconds - } - } - - public MessagePassingQueue queue() { - return queue; - } -} diff --git a/src/main/java/net/minestom/server/particle/Particle.java b/src/main/java/net/minestom/server/particle/Particle.java index ecf08689a..239651663 100644 --- a/src/main/java/net/minestom/server/particle/Particle.java +++ b/src/main/java/net/minestom/server/particle/Particle.java @@ -444,7 +444,7 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull Vibration readData(@NotNull NetworkBuffer reader) { - SourceType type = reader.readEnum(SourceType.class); + SourceType type = reader.read(NetworkBuffer.Enum(SourceType.class)); if (type == SourceType.BLOCK) { return this.withSourceBlockPosition(reader.read(NetworkBuffer.BLOCK_POSITION), reader.read(NetworkBuffer.VAR_INT)); } else { @@ -454,7 +454,7 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public void writeData(@NotNull NetworkBuffer writer) { - writer.writeEnum(SourceType.class, sourceType); + writer.write(NetworkBuffer.Enum(SourceType.class), sourceType); if (sourceType == SourceType.BLOCK) { Objects.requireNonNull(sourceBlockPosition); writer.write(NetworkBuffer.BLOCK_POSITION, sourceBlockPosition); diff --git a/src/main/java/net/minestom/server/potion/CustomPotionEffect.java b/src/main/java/net/minestom/server/potion/CustomPotionEffect.java index 2ac3495cf..f1fbd5974 100644 --- a/src/main/java/net/minestom/server/potion/CustomPotionEffect.java +++ b/src/main/java/net/minestom/server/potion/CustomPotionEffect.java @@ -2,27 +2,24 @@ package net.minestom.server.potion; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + /** * Represents a custom effect in {@link net.minestom.server.item.ItemComponent#POTION_CONTENTS}. */ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings settings) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, CustomPotionEffect value) { - buffer.write(NetworkBuffer.VAR_INT, value.id.id()); - buffer.write(Settings.NETWORK_TYPE, value.settings); - } - - @Override - public CustomPotionEffect read(@NotNull NetworkBuffer buffer) { - return new CustomPotionEffect(PotionEffect.fromId(buffer.read(NetworkBuffer.VAR_INT)), buffer.read(Settings.NETWORK_TYPE)); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + PotionEffect.NETWORK_TYPE, CustomPotionEffect::id, + Settings.NETWORK_TYPE, CustomPotionEffect::settings, + CustomPotionEffect::new + ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.lazy(() -> BinaryTagSerializer.COMPOUND.map( tag -> new CustomPotionEffect( @@ -38,7 +35,7 @@ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings set this(id, new Settings(amplifier, duration, isAmbient, showParticles, showIcon, null)); } - public byte amplifier() { + public int amplifier() { return settings.amplifier; } @@ -59,31 +56,30 @@ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings set } public record Settings( - byte amplifier, int duration, + int amplifier, int duration, boolean isAmbient, boolean showParticles, boolean showIcon, @Nullable Settings hiddenEffect ) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, Settings value) { - buffer.write(NetworkBuffer.VAR_INT, (int) value.amplifier); - buffer.write(NetworkBuffer.VAR_INT, value.duration); - buffer.write(NetworkBuffer.BOOLEAN, value.isAmbient); - buffer.write(NetworkBuffer.BOOLEAN, value.showParticles); - buffer.write(NetworkBuffer.BOOLEAN, value.showIcon); - buffer.writeOptional(NETWORK_TYPE, value.hiddenEffect); + buffer.write(VAR_INT, value.amplifier); + buffer.write(VAR_INT, value.duration); + buffer.write(BOOLEAN, value.isAmbient); + buffer.write(BOOLEAN, value.showParticles); + buffer.write(BOOLEAN, value.showIcon); + buffer.write(NETWORK_TYPE.optional(), value.hiddenEffect); } @Override public Settings read(@NotNull NetworkBuffer buffer) { return new Settings( - buffer.read(NetworkBuffer.VAR_INT).byteValue(), - buffer.read(NetworkBuffer.VAR_INT), - buffer.read(NetworkBuffer.BOOLEAN), - buffer.read(NetworkBuffer.BOOLEAN), - buffer.read(NetworkBuffer.BOOLEAN), - buffer.readOptional(NETWORK_TYPE) + buffer.read(VAR_INT), + buffer.read(VAR_INT), + buffer.read(BOOLEAN), + buffer.read(BOOLEAN), + buffer.read(BOOLEAN), + buffer.read(NETWORK_TYPE.optional()) ); } }; @@ -103,7 +99,7 @@ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings set }, value -> { CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() - .putByte("amplifier", value.amplifier) + .putByte("amplifier", (byte) value.amplifier) .putInt("duration", value.duration) .putBoolean("ambient", value.isAmbient) .putBoolean("show_particles", value.showParticles) diff --git a/src/main/java/net/minestom/server/potion/Potion.java b/src/main/java/net/minestom/server/potion/Potion.java index 4a44186c2..9e145ce51 100644 --- a/src/main/java/net/minestom/server/potion/Potion.java +++ b/src/main/java/net/minestom/server/potion/Potion.java @@ -2,12 +2,11 @@ package net.minestom.server.potion; import net.minestom.server.entity.Entity; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.play.EntityEffectPacket; import net.minestom.server.network.packet.server.play.RemoveEntityEffectPacket; import org.jetbrains.annotations.NotNull; -import java.util.Objects; - import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.VAR_INT; @@ -19,8 +18,7 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; * @param duration the duration (in ticks) that the potion will last * @param flags the flags of the potion, see {@link #flags()} */ -public record Potion(@NotNull PotionEffect effect, byte amplifier, - int duration, byte flags) implements NetworkBuffer.Writer { +public record Potion(@NotNull PotionEffect effect, byte amplifier, int duration, byte flags) { /** * A flag indicating that this Potion is ambient (it came from a beacon). * @@ -74,11 +72,6 @@ public record Potion(@NotNull PotionEffect effect, byte amplifier, this(effect, amplifier, duration, (byte) 0); } - public Potion(@NotNull NetworkBuffer reader) { - this(Objects.requireNonNull(PotionEffect.fromId(reader.read(VAR_INT))), reader.read(BYTE), - reader.read(VAR_INT), reader.read(BYTE)); - } - /** * Returns the flags that this Potion has. * @@ -144,11 +137,11 @@ public record Potion(@NotNull PotionEffect effect, byte amplifier, entity.sendPacketToViewersAndSelf(new RemoveEntityEffectPacket(entity.getEntityId(), effect)); } - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(VAR_INT, effect.id()); - writer.write(BYTE, amplifier); - writer.write(VAR_INT, duration); - writer.write(BYTE, flags); - } + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + PotionEffect.NETWORK_TYPE, Potion::effect, + BYTE, Potion::amplifier, + VAR_INT, Potion::duration, + BYTE, Potion::flags, + Potion::new + ); } diff --git a/src/main/java/net/minestom/server/potion/PotionEffect.java b/src/main/java/net/minestom/server/potion/PotionEffect.java index 69da6a597..aeed454c2 100644 --- a/src/main/java/net/minestom/server/potion/PotionEffect.java +++ b/src/main/java/net/minestom/server/potion/PotionEffect.java @@ -12,7 +12,7 @@ import java.util.Collection; public sealed interface PotionEffect extends StaticProtocolObject, PotionEffects permits PotionEffectImpl { - NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.map(PotionEffectImpl::getId, PotionEffect::id); + NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(PotionEffectImpl::getId, PotionEffect::id); @Contract(pure = true) @NotNull Registry.PotionEffectEntry registry(); diff --git a/src/main/java/net/minestom/server/potion/PotionType.java b/src/main/java/net/minestom/server/potion/PotionType.java index 5e28ba308..26201fe7c 100644 --- a/src/main/java/net/minestom/server/potion/PotionType.java +++ b/src/main/java/net/minestom/server/potion/PotionType.java @@ -1,5 +1,6 @@ package net.minestom.server.potion; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.NotNull; @@ -9,6 +10,8 @@ import java.util.Collection; public sealed interface PotionType extends StaticProtocolObject, PotionTypes permits PotionTypeImpl { + NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(PotionTypeImpl::getId, PotionType::id); + static @NotNull Collection<@NotNull PotionType> values() { return PotionTypeImpl.values(); } diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java index ca46d2fd1..a4945b995 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -48,7 +48,7 @@ public final class RecipeSerializers { @Override public void write(@NotNull NetworkBuffer buffer, Shaped shaped) { buffer.write(STRING, shaped.group()); - buffer.writeEnum(Crafting.class, shaped.category()); + buffer.write(NetworkBuffer.Enum(Crafting.class), shaped.category()); buffer.write(VAR_INT, shaped.width()); buffer.write(VAR_INT, shaped.height()); for (Ingredient ingredient : shaped.ingredients()) { @@ -61,7 +61,7 @@ public final class RecipeSerializers { @Override public Shaped read(@NotNull NetworkBuffer buffer) { String group = buffer.read(STRING); - Crafting category = buffer.readEnum(Crafting.class); + Crafting category = buffer.read(NetworkBuffer.Enum(Crafting.class)); int width = buffer.read(VAR_INT); int height = buffer.read(VAR_INT); List ingredients = new ArrayList<>(); diff --git a/src/main/java/net/minestom/server/scoreboard/Sidebar.java b/src/main/java/net/minestom/server/scoreboard/Sidebar.java index d35dd8e04..2515e95a5 100644 --- a/src/main/java/net/minestom/server/scoreboard/Sidebar.java +++ b/src/main/java/net/minestom/server/scoreboard/Sidebar.java @@ -472,38 +472,31 @@ public class Sidebar implements Scoreboard { } - public static class NumberFormat implements NetworkBuffer.Writer { - private final FormatType formatType; - private final Component content; - + public record NumberFormat(FormatType formatType, Component content) { private NumberFormat() { - this.content = null; - this.formatType = FormatType.BLANK; + this(FormatType.BLANK, null); } - private NumberFormat(@NotNull Component content, @NotNull FormatType formatType) { - this.content = content; - this.formatType = formatType; - } - - public NumberFormat(NetworkBuffer reader) { - this.formatType = FormatType.values()[reader.read(NetworkBuffer.VAR_INT)]; - if (formatType != FormatType.BLANK) this.content = reader.read(NetworkBuffer.COMPONENT); - else this.content = null; - } - - @Override - public void write(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.VAR_INT, formatType.ordinal()); - if (formatType == FormatType.STYLED) { - assert content != null; - writer.write(NetworkBuffer.COMPONENT, content); + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, NumberFormat value) { + buffer.write(NetworkBuffer.Enum(FormatType.class), value.formatType); + if (value.formatType == FormatType.STYLED) { + assert value.content != null; + buffer.write(NetworkBuffer.COMPONENT, value.content); + } else if (value.formatType == FormatType.FIXED) { + assert value.content != null; + buffer.write(NetworkBuffer.COMPONENT, value.content); + } } - else if (formatType == FormatType.FIXED) { - assert content != null; - writer.write(NetworkBuffer.COMPONENT, content); + + @Override + public NumberFormat read(@NotNull NetworkBuffer buffer) { + final FormatType formatType = buffer.read(NetworkBuffer.Enum(FormatType.class)); + final Component content = formatType != FormatType.BLANK ? buffer.read(NetworkBuffer.COMPONENT) : null; + return new NumberFormat(formatType, content); } - } + }; /** * A number format which has no sidebar score displayed @@ -520,7 +513,7 @@ public class Sidebar implements Scoreboard { * @param style a styled component */ public static @NotNull NumberFormat styled(@NotNull Component style) { - return new NumberFormat(style, FormatType.STYLED); + return new NumberFormat(FormatType.STYLED, style); } /** @@ -529,7 +522,7 @@ public class Sidebar implements Scoreboard { * @param content the fixed component */ public static @NotNull NumberFormat fixed(@NotNull Component content) { - return new NumberFormat(content, FormatType.FIXED); + return new NumberFormat(FormatType.FIXED, content); } private enum FormatType { diff --git a/src/main/java/net/minestom/server/scoreboard/Team.java b/src/main/java/net/minestom/server/scoreboard/Team.java index 3084820c0..676b3a8d2 100644 --- a/src/main/java/net/minestom/server/scoreboard/Team.java +++ b/src/main/java/net/minestom/server/scoreboard/Team.java @@ -11,7 +11,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.play.TeamsPacket; import net.minestom.server.network.packet.server.play.TeamsPacket.CollisionRule; import net.minestom.server.network.packet.server.play.TeamsPacket.NameTagVisibility; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -128,7 +128,7 @@ public class Team implements PacketGroupingAudience { final TeamsPacket addPlayerPacket = new TeamsPacket(teamName, new TeamsPacket.AddEntitiesToTeamAction(toAdd)); // Sends to all online players the add player packet - PacketUtils.broadcastPlayPacket(addPlayerPacket); + PacketSendingUtils.broadcastPlayPacket(addPlayerPacket); // invalidate player members this.isPlayerMembersUpToDate = false; @@ -159,7 +159,7 @@ public class Team implements PacketGroupingAudience { final TeamsPacket removePlayerPacket = new TeamsPacket(teamName, new TeamsPacket.RemoveEntitiesToTeamAction(toRemove)); // Sends to all online player the remove player packet - PacketUtils.broadcastPlayPacket(removePlayerPacket); + PacketSendingUtils.broadcastPlayPacket(removePlayerPacket); // Removes the member from the team this.members.removeAll(toRemove); @@ -372,7 +372,7 @@ public class Team implements PacketGroupingAudience { */ public @NotNull TeamsPacket createTeamsCreationPacket() { final var info = new TeamsPacket.CreateTeamAction(teamDisplayName, friendlyFlags, - nameTagVisibility, collisionRule, teamColor, prefix, suffix, members); + nameTagVisibility, collisionRule, teamColor, prefix, suffix, List.copyOf(members)); return new TeamsPacket(teamName, info); } @@ -463,7 +463,7 @@ public class Team implements PacketGroupingAudience { public void sendUpdatePacket() { final var info = new TeamsPacket.UpdateTeamAction(teamDisplayName, friendlyFlags, nameTagVisibility, collisionRule, teamColor, prefix, suffix); - PacketUtils.broadcastPlayPacket(new TeamsPacket(teamName, info)); + PacketSendingUtils.broadcastPlayPacket(new TeamsPacket(teamName, info)); } @Override diff --git a/src/main/java/net/minestom/server/scoreboard/TeamManager.java b/src/main/java/net/minestom/server/scoreboard/TeamManager.java index 8eb2a2399..ecca0be73 100644 --- a/src/main/java/net/minestom/server/scoreboard/TeamManager.java +++ b/src/main/java/net/minestom/server/scoreboard/TeamManager.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.entity.LivingEntity; import net.minestom.server.entity.Player; -import net.minestom.server.utils.PacketUtils; +import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.UniqueIdUtils; import org.jetbrains.annotations.NotNull; @@ -37,7 +37,7 @@ public final class TeamManager { */ protected void registerNewTeam(@NotNull Team team) { this.teams.add(team); - PacketUtils.broadcastPlayPacket(team.createTeamsCreationPacket()); + PacketSendingUtils.broadcastPlayPacket(team.createTeamsCreationPacket()); } /** @@ -60,7 +60,7 @@ public final class TeamManager { */ public boolean deleteTeam(@NotNull Team team) { // Sends to all online players a team destroy packet - PacketUtils.broadcastPlayPacket(team.createTeamDestructionPacket()); + PacketSendingUtils.broadcastPlayPacket(team.createTeamDestructionPacket()); return this.teams.remove(team); } diff --git a/src/main/java/net/minestom/server/sound/SoundEvent.java b/src/main/java/net/minestom/server/sound/SoundEvent.java index 6856c6af7..839357c65 100644 --- a/src/main/java/net/minestom/server/sound/SoundEvent.java +++ b/src/main/java/net/minestom/server/sound/SoundEvent.java @@ -25,7 +25,7 @@ public sealed interface SoundEvent extends ProtocolObject, Keyed, Sound.Type, So case CustomSoundEvent soundEvent -> { buffer.write(NetworkBuffer.VAR_INT, 0); // Custom sound buffer.write(NetworkBuffer.STRING, soundEvent.name()); - buffer.writeOptional(NetworkBuffer.FLOAT, soundEvent.range()); + buffer.write(NetworkBuffer.FLOAT.optional(), soundEvent.range()); } } } @@ -36,7 +36,7 @@ public sealed interface SoundEvent extends ProtocolObject, Keyed, Sound.Type, So if (id != -1) return BuiltinSoundEvent.getId(id); NamespaceID namespace = NamespaceID.from(buffer.read(NetworkBuffer.STRING)); - return new CustomSoundEvent(namespace, buffer.readOptional(NetworkBuffer.FLOAT)); + return new CustomSoundEvent(namespace, buffer.read(NetworkBuffer.FLOAT.optional())); } }; @@ -81,7 +81,7 @@ public sealed interface SoundEvent extends ProtocolObject, Keyed, Sound.Type, So * Create a custom sound event. The namespace should match a sound provided in the resource pack. * * @param namespaceID the namespace ID of the custom sound event - * @param range the range of the sound event, or null for (legacy) dynamic range + * @param range the range of the sound event, or null for (legacy) dynamic range * @return the custom sound event */ static @NotNull SoundEvent of(@NotNull String namespaceID, @Nullable Float range) { @@ -90,8 +90,9 @@ public sealed interface SoundEvent extends ProtocolObject, Keyed, Sound.Type, So /** * Create a custom sound event. The {@link NamespaceID} should match a sound provided in the resource pack. + * * @param namespaceID the namespace ID of the custom sound event - * @param range the range of the sound event, or null for (legacy) dynamic range + * @param range the range of the sound event, or null for (legacy) dynamic range * @return the custom sound event */ static @NotNull SoundEvent of(@NotNull NamespaceID namespaceID, @Nullable Float range) { diff --git a/src/main/java/net/minestom/server/utils/ArrayUtils.java b/src/main/java/net/minestom/server/utils/ArrayUtils.java index de23b16d1..c491817ca 100644 --- a/src/main/java/net/minestom/server/utils/ArrayUtils.java +++ b/src/main/java/net/minestom/server/utils/ArrayUtils.java @@ -22,20 +22,6 @@ public final class ArrayUtils { return true; } - public static int[] concatenateIntArrays(int @NotNull []... arrays) { - int totalLength = 0; - for (int[] array : arrays) { - totalLength += array.length; - } - int[] result = new int[totalLength]; - int startingPos = 0; - for (int[] array : arrays) { - System.arraycopy(array, 0, result, startingPos, array.length); - startingPos += array.length; - } - return result; - } - public static int[] mapToIntArray(Collection collection, ToIntFunction function) { final int size = collection.size(); if (size == 0) @@ -76,37 +62,4 @@ public final class ArrayUtils { default -> Map.copyOf(new Object2ObjectArrayMap<>(keys, values, length)); }; } - - public static long[] pack(int[] ints, int bitsPerEntry) { - int intsPerLong = (int) Math.floor(64d / bitsPerEntry); - long[] longs = new long[(int) Math.ceil(ints.length / (double) intsPerLong)]; - - long mask = (1L << bitsPerEntry) - 1L; - for (int i = 0; i < longs.length; i++) { - for (int intIndex = 0; intIndex < intsPerLong; intIndex++) { - int bitIndex = intIndex * bitsPerEntry; - int intActualIndex = intIndex + i * intsPerLong; - if (intActualIndex < ints.length) { - longs[i] |= (ints[intActualIndex] & mask) << bitIndex; - } - } - } - - return longs; - } - - public static void unpack(int[] out, long[] in, int bitsPerEntry) { - assert in.length != 0: "unpack input array is zero"; - - var intsPerLong = Math.floor(64d / bitsPerEntry); - var intsPerLongCeil = (int) Math.ceil(intsPerLong); - - long mask = (1L << bitsPerEntry) - 1L; - for (int i = 0; i < out.length; i++) { - int longIndex = i / intsPerLongCeil; - int subIndex = i % intsPerLongCeil; - - out[i] = (int) ((in[longIndex] >>> (bitsPerEntry * subIndex)) & mask); - } - } } diff --git a/src/main/java/net/minestom/server/utils/Either.java b/src/main/java/net/minestom/server/utils/Either.java deleted file mode 100644 index 29271acff..000000000 --- a/src/main/java/net/minestom/server/utils/Either.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.utils; - -import java.util.function.Function; - -public record Either(boolean isLeft, L left, R right) { - public static Either left(T left) { - return new Either<>(true, left, null); - } - public static Either right(T right) { - return new Either<>(false, null, right); - } - - public T map(Function leftMapper, Function rightMapper) { - if (isLeft) { - return leftMapper.apply(left); - } else { - return rightMapper.apply(right); - } - } -} diff --git a/src/main/java/net/minestom/server/utils/InterfaceUtils.java b/src/main/java/net/minestom/server/utils/InterfaceUtils.java deleted file mode 100644 index e2a158831..000000000 --- a/src/main/java/net/minestom/server/utils/InterfaceUtils.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.minestom.server.utils; - -import java.util.function.BiConsumer; - -public final class InterfaceUtils { - private InterfaceUtils() { - //no instance - } - - public static BiConsumer flipBiConsumer(BiConsumer biConsumer) { - return (t, u) -> biConsumer.accept(u, t); - } -} diff --git a/src/main/java/net/minestom/server/utils/ObjectPool.java b/src/main/java/net/minestom/server/utils/ObjectPool.java index baa5ba026..f3699b003 100644 --- a/src/main/java/net/minestom/server/utils/ObjectPool.java +++ b/src/main/java/net/minestom/server/utils/ObjectPool.java @@ -1,7 +1,5 @@ package net.minestom.server.utils; -import net.minestom.server.ServerFlag; -import net.minestom.server.utils.binary.BinaryBuffer; import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MpmcUnboundedXaddArrayQueue; import org.jetbrains.annotations.ApiStatus; @@ -9,26 +7,32 @@ import org.jetbrains.annotations.NotNull; import java.lang.ref.Cleaner; import java.lang.ref.SoftReference; -import java.nio.ByteBuffer; import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Supplier; import java.util.function.UnaryOperator; @ApiStatus.Internal +@ApiStatus.Experimental public final class ObjectPool { private static final int QUEUE_SIZE = 32_768; + private static final Cleaner CLEANER = Cleaner.create(); - public static final ObjectPool BUFFER_POOL = new ObjectPool<>(() -> BinaryBuffer.ofSize(ServerFlag.POOLED_BUFFER_SIZE), BinaryBuffer::clear); - public static final ObjectPool PACKET_POOL = new ObjectPool<>(() -> ByteBuffer.allocateDirect(ServerFlag.MAX_PACKET_SIZE), ByteBuffer::clear); - - private final Cleaner cleaner = Cleaner.create(); private final MessagePassingQueue> pool = new MpmcUnboundedXaddArrayQueue<>(QUEUE_SIZE); private final Supplier supplier; private final UnaryOperator sanitizer; - ObjectPool(Supplier supplier, UnaryOperator sanitizer) { + public static ObjectPool pool(Supplier supplier, UnaryOperator sanitizer) { + return new ObjectPool<>(supplier, sanitizer); + } + + public static ObjectPool pool(Supplier supplier) { + return new ObjectPool<>(supplier, UnaryOperator.identity()); + } + + private ObjectPool(Supplier supplier, UnaryOperator sanitizer) { this.supplier = supplier; this.sanitizer = sanitizer; } @@ -62,15 +66,15 @@ public final class ObjectPool { } public void register(@NotNull Object ref, @NotNull AtomicReference objectRef) { - this.cleaner.register(ref, new BufferRefCleaner<>(this, objectRef)); + CLEANER.register(ref, new BufferRefCleaner<>(this, objectRef)); } public void register(@NotNull Object ref, @NotNull T object) { - this.cleaner.register(ref, new BufferCleaner<>(this, object)); + CLEANER.register(ref, new BufferCleaner<>(this, object)); } public void register(@NotNull Object ref, @NotNull Collection objects) { - this.cleaner.register(ref, new BuffersCleaner<>(this, objects)); + CLEANER.register(ref, new BuffersCleaner<>(this, objects)); } public @NotNull Holder hold() { @@ -111,21 +115,20 @@ public final class ObjectPool { public final class Holder implements AutoCloseable { private final T object; - private boolean closed; + private final AtomicBoolean closed = new AtomicBoolean(false); Holder(T object) { this.object = object; } public @NotNull T get() { - if (closed) throw new IllegalStateException("Holder is closed"); + if (closed.get()) throw new IllegalStateException("Holder is closed"); return object; } @Override public void close() { - if (!closed) { - closed = true; + if (closed.compareAndSet(false, true)) { add(object); } } diff --git a/src/main/java/net/minestom/server/utils/PacketSendingUtils.java b/src/main/java/net/minestom/server/utils/PacketSendingUtils.java new file mode 100644 index 000000000..b3afb6015 --- /dev/null +++ b/src/main/java/net/minestom/server/utils/PacketSendingUtils.java @@ -0,0 +1,122 @@ +package net.minestom.server.utils; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.audience.ForwardingAudience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TranslatableComponent; +import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; +import net.minestom.server.adventure.ComponentHolder; +import net.minestom.server.adventure.MinestomAdventure; +import net.minestom.server.adventure.audience.PacketGroupingAudience; +import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.packet.server.CachedPacket; +import net.minestom.server.network.packet.server.SendablePacket; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; + +public final class PacketSendingUtils { + /** + * Sends a packet to an audience. This method performs the following steps in the + * following order: + *

    + *
  1. If {@code audience} is a {@link Player}, send the packet to them.
  2. + *
  3. Otherwise, if {@code audience} is a {@link PacketGroupingAudience}, call + * {@link #sendGroupedPacket(Collection, ServerPacket)} on the players that the + * grouping audience contains.
  4. + *
  5. Otherwise, if {@code audience} is a {@link ForwardingAudience.Single}, + * call this method on the single audience inside the forwarding audience.
  6. + *
  7. Otherwise, if {@code audience} is a {@link ForwardingAudience}, call this + * method for each audience member of the forwarding audience.
  8. + *
  9. Otherwise, do nothing.
  10. + *
+ * + * @param audience the audience + * @param packet the packet + */ + @SuppressWarnings("OverrideOnly") // we need to access the audiences inside ForwardingAudience + public static void sendPacket(@NotNull Audience audience, @NotNull ServerPacket packet) { + switch (audience) { + case Player player -> player.sendPacket(packet); + case PacketGroupingAudience groupingAudience -> sendGroupedPacket(groupingAudience.getPlayers(), packet); + case ForwardingAudience.Single singleAudience -> sendPacket(singleAudience.audience(), packet); + case ForwardingAudience forwardingAudience -> { + for (Audience member : forwardingAudience.audiences()) { + sendPacket(member, packet); + } + } + default -> { + } + } + } + + /** + * Sends a {@link ServerPacket} to multiple players. + *

+ * Can drastically improve performance since the packet will not have to be processed as much. + * + * @param players the players to send the packet to + * @param packet the packet to send to the players + * @param predicate predicate to ignore specific players + */ + public static void sendGroupedPacket(@NotNull Collection players, @NotNull ServerPacket packet, + @NotNull Predicate predicate) { + final SendablePacket sendablePacket = groupedPacket(packet); + players.forEach(player -> { + if (predicate.test(player)) player.sendPacket(sendablePacket); + }); + } + + /** + * Same as {@link #sendGroupedPacket(Collection, ServerPacket, Predicate)} + * but without any predicate. + * + * @see #sendGroupedPacket(Collection, ServerPacket, Predicate) + */ + public static void sendGroupedPacket(@NotNull Collection players, @NotNull ServerPacket packet) { + final SendablePacket sendablePacket = groupedPacket(packet); + players.forEach(player -> player.sendPacket(sendablePacket)); + } + + public static void broadcastPlayPacket(@NotNull ServerPacket packet) { + sendGroupedPacket(MinecraftServer.getConnectionManager().getOnlinePlayers(), packet); + } + + static SendablePacket groupedPacket(ServerPacket packet) { + return shouldUseCachePacket(packet) ? new CachedPacket(packet) : packet; + } + + /** + * Checks if the {@link ServerPacket} is suitable to be wrapped into a {@link CachedPacket}. + * Note: {@link ServerPacket.ComponentHolding}s are not translated inside a {@link CachedPacket}. + * + * @see CachedPacket#body(ConnectionState) + */ + static boolean shouldUseCachePacket(final @NotNull ServerPacket packet) { + if (!MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION) return ServerFlag.GROUPED_PACKET; + if (!(packet instanceof ServerPacket.ComponentHolding holder)) return ServerFlag.GROUPED_PACKET; + return !containsTranslatableComponents(holder); + } + + private static boolean containsTranslatableComponents(final @NotNull ComponentHolder holder) { + for (final Component component : holder.components()) { + if (isTranslatable(component)) return true; + } + return false; + } + + private static boolean isTranslatable(final @NotNull Component component) { + if (component instanceof TranslatableComponent) return true; + final List children = component.children(); + if (children.isEmpty()) return false; + for (final Component child : children) { + if (isTranslatable(child)) return true; + } + return false; + } +} diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java deleted file mode 100644 index 8aaec93a7..000000000 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ /dev/null @@ -1,409 +0,0 @@ -package net.minestom.server.utils; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongList; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.audience.ForwardingAudience; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TranslatableComponent; -import net.minestom.server.MinecraftServer; -import net.minestom.server.ServerFlag; -import net.minestom.server.Viewable; -import net.minestom.server.adventure.ComponentHolder; -import net.minestom.server.adventure.MinestomAdventure; -import net.minestom.server.adventure.audience.PacketGroupingAudience; -import net.minestom.server.entity.Entity; -import net.minestom.server.entity.Player; -import net.minestom.server.network.ConnectionState; -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.PacketParser; -import net.minestom.server.network.packet.PacketRegistry; -import net.minestom.server.network.packet.server.CachedPacket; -import net.minestom.server.network.packet.server.FramedPacket; -import net.minestom.server.network.packet.server.SendablePacket; -import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.network.player.PlayerSocketConnection; -import net.minestom.server.utils.binary.BinaryBuffer; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.Collection; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Predicate; -import java.util.zip.DataFormatException; -import java.util.zip.Deflater; -import java.util.zip.Inflater; - -/** - * Utils class for packets. Including writing a {@link ServerPacket} into a {@link ByteBuffer} - * for network processing. - *

- * Note that all methods are mostly internal and can change at any moment. - * This is due to their very unsafe nature (use of local buffers as cache) and their potential performance impact. - * Be sure to check the implementation code. - */ -public final class PacketUtils { - private static final ThreadLocal LOCAL_DEFLATER = ThreadLocal.withInitial(Deflater::new); - - - private static final PacketParser.Server SERVER_PACKET_PARSER = new PacketParser.Server(); - - // Viewable packets - private static final Cache VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); - - private PacketUtils() { - } - - /** - * Sends a packet to an audience. This method performs the following steps in the - * following order: - *

    - *
  1. If {@code audience} is a {@link Player}, send the packet to them.
  2. - *
  3. Otherwise, if {@code audience} is a {@link PacketGroupingAudience}, call - * {@link #sendGroupedPacket(Collection, ServerPacket)} on the players that the - * grouping audience contains.
  4. - *
  5. Otherwise, if {@code audience} is a {@link ForwardingAudience.Single}, - * call this method on the single audience inside the forwarding audience.
  6. - *
  7. Otherwise, if {@code audience} is a {@link ForwardingAudience}, call this - * method for each audience member of the forwarding audience.
  8. - *
  9. Otherwise, do nothing.
  10. - *
- * - * @param audience the audience - * @param packet the packet - */ - @SuppressWarnings("OverrideOnly") // we need to access the audiences inside ForwardingAudience - public static void sendPacket(@NotNull Audience audience, @NotNull ServerPacket packet) { - if (audience instanceof Player player) { - player.sendPacket(packet); - } else if (audience instanceof PacketGroupingAudience groupingAudience) { - PacketUtils.sendGroupedPacket(groupingAudience.getPlayers(), packet); - } else if (audience instanceof ForwardingAudience.Single singleAudience) { - PacketUtils.sendPacket(singleAudience.audience(), packet); - } else if (audience instanceof ForwardingAudience forwardingAudience) { - for (Audience member : forwardingAudience.audiences()) { - PacketUtils.sendPacket(member, packet); - } - } - } - - /** - * Sends a {@link ServerPacket} to multiple players. - *

- * Can drastically improve performance since the packet will not have to be processed as much. - * - * @param players the players to send the packet to - * @param packet the packet to send to the players - * @param predicate predicate to ignore specific players - */ - public static void sendGroupedPacket(@NotNull Collection players, @NotNull ServerPacket packet, - @NotNull Predicate predicate) { - final var sendablePacket = shouldUseCachePacket(packet) ? new CachedPacket(packet) : packet; - - players.forEach(player -> { - if (predicate.test(player)) player.sendPacket(sendablePacket); - }); - } - - /** - * Checks if the {@link ServerPacket} is suitable to be wrapped into a {@link CachedPacket}. - * Note: {@link ServerPacket.ComponentHolding}s are not translated inside a {@link CachedPacket}. - * - * @see CachedPacket#body(ConnectionState) - * @see PlayerSocketConnection#writePacketSync(SendablePacket, boolean) - */ - static boolean shouldUseCachePacket(final @NotNull ServerPacket packet) { - if (!MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION) return ServerFlag.GROUPED_PACKET; - if (!(packet instanceof ServerPacket.ComponentHolding holder)) return ServerFlag.GROUPED_PACKET; - return !containsTranslatableComponents(holder); - } - - private static boolean containsTranslatableComponents(final @NotNull ComponentHolder holder) { - for (final Component component : holder.components()) { - if (isTranslatable(component)) return true; - } - - return false; - } - - private static boolean isTranslatable(final @NotNull Component component) { - if (component instanceof TranslatableComponent) return true; - - final var children = component.children(); - if (children.isEmpty()) return false; - - for (final Component child : children) { - if (isTranslatable(child)) return true; - } - - return false; - } - - /** - * Same as {@link #sendGroupedPacket(Collection, ServerPacket, Predicate)} - * but with the player validator sets to null. - * - * @see #sendGroupedPacket(Collection, ServerPacket, Predicate) - */ - public static void sendGroupedPacket(@NotNull Collection players, @NotNull ServerPacket packet) { - sendGroupedPacket(players, packet, player -> true); - } - - public static void broadcastPlayPacket(@NotNull ServerPacket packet) { - sendGroupedPacket(MinecraftServer.getConnectionManager().getOnlinePlayers(), packet); - } - - @ApiStatus.Experimental - public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket, - @Nullable Entity entity) { - if (entity != null && !entity.hasPredictableViewers()) { - // Operation cannot be optimized - entity.sendPacketToViewers(serverPacket); - return; - } - if (!ServerFlag.VIEWABLE_PACKET) { - sendGroupedPacket(viewable.getViewers(), serverPacket, value -> !Objects.equals(value, entity)); - return; - } - final Player exception = entity instanceof Player ? (Player) entity : null; - ViewableStorage storage = VIEWABLE_STORAGE_MAP.get(viewable, (unused) -> new ViewableStorage()); - storage.append(viewable, serverPacket, exception); - } - - @ApiStatus.Experimental - public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket) { - prepareViewablePacket(viewable, serverPacket, null); - } - - @ApiStatus.Internal - public static void flush() { - if (ServerFlag.VIEWABLE_PACKET) { - VIEWABLE_STORAGE_MAP.asMap().entrySet().parallelStream().forEach(entry -> - entry.getValue().process(entry.getKey())); - } - } - - @ApiStatus.Internal - public static @Nullable BinaryBuffer readPackets(@NotNull BinaryBuffer readBuffer, boolean compressed, - BiConsumer payloadConsumer) throws DataFormatException { - BinaryBuffer remaining = null; - ByteBuffer pool = ObjectPool.PACKET_POOL.get(); - while (readBuffer.readableBytes() > 0) { - final var beginMark = readBuffer.mark(); - try { - // Ensure that the buffer contains the full packet (or wait for next socket read) - final int packetLength = readBuffer.readVarInt(); - final int readerStart = readBuffer.readerOffset(); - if (!readBuffer.canRead(packetLength)) { - // Integrity fail - throw new BufferUnderflowException(); - } - // Read packet https://wiki.vg/Protocol#Packet_format - BinaryBuffer content = readBuffer; - int decompressedSize = packetLength; - if (compressed) { - final int dataLength = readBuffer.readVarInt(); - final int payloadLength = packetLength - (readBuffer.readerOffset() - readerStart); - if (payloadLength < 0) { - throw new DataFormatException("Negative payload length " + payloadLength); - } - if (dataLength == 0) { - // Data is too small to be compressed, payload is following - decompressedSize = payloadLength; - } else { - // Decompress to content buffer - content = BinaryBuffer.wrap(pool); - decompressedSize = dataLength; - Inflater inflater = new Inflater(); // TODO: Pool? - inflater.setInput(readBuffer.asByteBuffer(readBuffer.readerOffset(), payloadLength)); - inflater.inflate(content.asByteBuffer(0, dataLength)); - inflater.reset(); - } - } - // Slice packet - ByteBuffer payload = content.asByteBuffer(content.readerOffset(), decompressedSize); - final int packetId = Utils.readVarInt(payload); - try { - payloadConsumer.accept(packetId, payload); - } catch (Exception e) { - throw new RuntimeException(e); - } - // Position buffer to read the next packet - readBuffer.readerOffset(readerStart + packetLength); - } catch (BufferUnderflowException e) { - readBuffer.reset(beginMark); - remaining = BinaryBuffer.copy(readBuffer); - break; - } - } - ObjectPool.PACKET_POOL.add(pool); - return remaining; - } - - public static void writeFramedPacket(@NotNull ConnectionState state, - @NotNull ByteBuffer buffer, - @NotNull ServerPacket packet, - boolean compression) { - final PacketRegistry registry = SERVER_PACKET_PARSER.stateRegistry(state); - final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet.getClass()); - final int id = packetInfo.id(); - final NetworkBuffer.Type serializer = packetInfo.serializer(); - writeFramedPacket(buffer, id, serializer, packet, compression ? MinecraftServer.getCompressionThreshold() : 0); - } - - public static void writeFramedPacket(@NotNull ByteBuffer buffer, - int id, - @NotNull NetworkBuffer.Type type, - @NotNull T packet, - int compressionThreshold) { - NetworkBuffer networkBuffer = new NetworkBuffer(buffer, false); - if (compressionThreshold <= 0) { - // Uncompressed format https://wiki.vg/Protocol#Without_compression - final int lengthIndex = networkBuffer.skipWrite(3); - networkBuffer.write(NetworkBuffer.VAR_INT, id); - type.write(networkBuffer, packet); - final int finalSize = networkBuffer.writeIndex() - (lengthIndex + 3); - Utils.writeVarIntHeader(buffer, lengthIndex, finalSize); - buffer.position(networkBuffer.writeIndex()); - return; - } - // Compressed format https://wiki.vg/Protocol#With_compression - final int compressedIndex = networkBuffer.skipWrite(3); - final int uncompressedIndex = networkBuffer.skipWrite(3); - - final int contentStart = networkBuffer.writeIndex(); - networkBuffer.write(NetworkBuffer.VAR_INT, id); - type.write(networkBuffer, packet); - final int packetSize = networkBuffer.writeIndex() - contentStart; - final boolean compressed = packetSize >= compressionThreshold; - if (compressed) { - // Packet large enough, compress it - try (var hold = ObjectPool.PACKET_POOL.hold()) { - final ByteBuffer input = hold.get().put(0, buffer, contentStart, packetSize); - Deflater deflater = LOCAL_DEFLATER.get(); - deflater.setInput(input.limit(packetSize)); - deflater.finish(); - deflater.deflate(buffer.position(contentStart)); - deflater.reset(); - - networkBuffer.skipWrite(buffer.position() - contentStart); - } - } - // Packet header (Packet + Data Length) - Utils.writeVarIntHeader(buffer, compressedIndex, networkBuffer.writeIndex() - uncompressedIndex); - Utils.writeVarIntHeader(buffer, uncompressedIndex, compressed ? packetSize : 0); - - buffer.position(networkBuffer.writeIndex()); - } - - @ApiStatus.Internal - public static ByteBuffer createFramedPacket(@NotNull ConnectionState state, @NotNull ByteBuffer buffer, @NotNull ServerPacket packet, boolean compression) { - writeFramedPacket(state, buffer, packet, compression); - return buffer.flip(); - } - - @ApiStatus.Internal - public static ByteBuffer createFramedPacket(@NotNull ConnectionState state, @NotNull ByteBuffer buffer, @NotNull ServerPacket packet) { - return createFramedPacket(state, buffer, packet, MinecraftServer.getCompressionThreshold() > 0); - } - - @ApiStatus.Internal - public static FramedPacket allocateTrimmedPacket(@NotNull ConnectionState state, @NotNull ServerPacket packet) { - try (var hold = ObjectPool.PACKET_POOL.hold()) { - final ByteBuffer temp = PacketUtils.createFramedPacket(state, hold.get(), packet); - final int size = temp.remaining(); - final ByteBuffer buffer = ByteBuffer.allocateDirect(size).put(0, temp, 0, size); - return new FramedPacket(packet, buffer); - } - } - - private static final class ViewableStorage { - // Player id -> list of offsets to ignore (32:32 bits) - private final Int2ObjectMap entityIdMap = new Int2ObjectOpenHashMap<>(); - private final BinaryBuffer buffer = ObjectPool.BUFFER_POOL.getAndRegister(this); - - private synchronized void append(Viewable viewable, ServerPacket serverPacket, @Nullable Player exception) { - try (var hold = ObjectPool.PACKET_POOL.hold()) { - // Viewable storage is only used for play packets, so fine to assume this. - final ByteBuffer framedPacket = createFramedPacket(ConnectionState.PLAY, hold.get(), serverPacket); - final int packetSize = framedPacket.limit(); - if (packetSize >= buffer.capacity()) { - process(viewable); - for (Player viewer : viewable.getViewers()) { - if (!Objects.equals(exception, viewer)) { - writeTo(viewer.getPlayerConnection(), framedPacket, 0, packetSize); - } - } - return; - } - if (!buffer.canWrite(packetSize)) process(viewable); - final int start = buffer.writerOffset(); - this.buffer.write(framedPacket); - final int end = buffer.writerOffset(); - if (exception != null) { - final long offsets = (long) start << 32 | end & 0xFFFFFFFFL; - LongList list = entityIdMap.computeIfAbsent(exception.getEntityId(), id -> new LongArrayList()); - list.add(offsets); - } - } - } - - private synchronized void process(Viewable viewable) { - if (buffer.writerOffset() == 0) return; - ByteBuffer copy = ByteBuffer.allocateDirect(buffer.writerOffset()); - copy.put(buffer.asByteBuffer(0, copy.capacity())); - viewable.getViewers().forEach(player -> processPlayer(player, copy)); - this.buffer.clear(); - this.entityIdMap.clear(); - } - - private void processPlayer(Player player, ByteBuffer buffer) { - final int size = buffer.limit(); - final PlayerConnection connection = player.getPlayerConnection(); - final LongArrayList pairs = entityIdMap.get(player.getEntityId()); - if (pairs != null) { - // Ensure that we skip the specified parts of the buffer - int lastWrite = 0; - final long[] elements = pairs.elements(); - for (int i = 0; i < pairs.size(); ++i) { - final long offsets = elements[i]; - final int start = (int) (offsets >> 32); - if (start != lastWrite) writeTo(connection, buffer, lastWrite, start - lastWrite); - lastWrite = (int) offsets; // End = last 32 bits - } - if (size != lastWrite) writeTo(connection, buffer, lastWrite, size - lastWrite); - } else { - // Write all - writeTo(connection, buffer, 0, size); - } - } - - private static void writeTo(PlayerConnection connection, ByteBuffer buffer, int offset, int length) { - if (connection instanceof PlayerSocketConnection socketConnection) { - socketConnection.write(buffer, offset, length); - return; - } - // TODO for non-socket connection - } - } - - @ApiStatus.Internal - public static int invalidPacketState(@NotNull Class packetClass, @NotNull ConnectionState state, @NotNull ConnectionState... expected) { - assert expected.length > 0 : "Expected states cannot be empty: " + packetClass; - StringBuilder expectedStr = new StringBuilder(); - for (ConnectionState connectionState : expected) { - expectedStr.append(connectionState).append(", "); - } - expectedStr.delete(expectedStr.length() - 2, expectedStr.length()); - throw new IllegalStateException(String.format("Packet %s is not valid in state %s (only %s)", packetClass.getSimpleName(), state, expectedStr)); - } -} diff --git a/src/main/java/net/minestom/server/utils/PacketViewableUtils.java b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java new file mode 100644 index 000000000..094bc958f --- /dev/null +++ b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java @@ -0,0 +1,120 @@ +package net.minestom.server.utils; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; +import net.minestom.server.Viewable; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketWriting; +import net.minestom.server.network.packet.server.BufferedPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.player.PlayerConnection; +import net.minestom.server.network.player.PlayerSocketConnection; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public final class PacketViewableUtils { + // Viewable packets + private static final Cache VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); + + @ApiStatus.Experimental + public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket, + @Nullable Entity entity) { + if (entity != null && !entity.hasPredictableViewers()) { + // Operation cannot be optimized + entity.sendPacketToViewers(serverPacket); + return; + } + if (!ServerFlag.VIEWABLE_PACKET) { + PacketSendingUtils.sendGroupedPacket(viewable.getViewers(), serverPacket, value -> !Objects.equals(value, entity)); + return; + } + final Player exception = entity instanceof Player ? (Player) entity : null; + ViewableStorage storage = VIEWABLE_STORAGE_MAP.get(viewable, (unused) -> new ViewableStorage()); + storage.append(serverPacket, exception); + } + + @ApiStatus.Internal + public static void flush() { + if (ServerFlag.VIEWABLE_PACKET) { + VIEWABLE_STORAGE_MAP.asMap().entrySet().parallelStream().forEach(entry -> + entry.getValue().process(entry.getKey())); + } + } + + @ApiStatus.Experimental + public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket) { + prepareViewablePacket(viewable, serverPacket, null); + } + + static final class ViewableStorage { + static final ObjectPool POOL = ObjectPool.pool( + () -> NetworkBuffer.resizableBuffer(ServerFlag.POOLED_BUFFER_SIZE, MinecraftServer.process()), + NetworkBuffer::clear); + // Player id -> list of offsets to ignore (32:32 bits) + private final Int2ObjectMap entityIdMap = new Int2ObjectOpenHashMap<>(); + private final NetworkBuffer buffer = POOL.getAndRegister(this); + + private synchronized void append(ServerPacket serverPacket, @Nullable Player exception) { + final long start = buffer.writeIndex(); + // Viewable storage is only used for play packets, so fine to assume this. + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, serverPacket, MinecraftServer.getCompressionThreshold()); + final long end = buffer.writeIndex(); + if (exception != null) { + final long offsets = start << 32 | end & 0xFFFFFFFFL; + LongList list = entityIdMap.computeIfAbsent(exception.getEntityId(), id -> new LongArrayList()); + list.add(offsets); + } + } + + private synchronized void process(Viewable viewable) { + if (buffer.writeIndex() == 0) return; + NetworkBuffer copy = buffer.copy(0, buffer.writeIndex()); + copy.readOnly(); + viewable.getViewers().forEach(player -> processPlayer(player, copy)); + this.buffer.clear(); + this.entityIdMap.clear(); + } + + private void processPlayer(Player player, NetworkBuffer buffer) { + final long capacity = buffer.capacity(); + final PlayerConnection connection = player.getPlayerConnection(); + final LongArrayList pairs = entityIdMap.get(player.getEntityId()); + if (pairs == null) { + // No range exception, write the whole buffer + writeTo(connection, buffer, 0, capacity); + return; + } + // Player has range exception(s) + // Ensure that we skip the specified parts of the buffer + int lastWrite = 0; + final long[] elements = pairs.elements(); + for (int i = 0; i < pairs.size(); ++i) { + final long offsets = elements[i]; + final int start = (int) (offsets >> 32); + if (start != lastWrite) writeTo(connection, buffer, lastWrite, start - lastWrite); + lastWrite = (int) offsets; // End = last 32 bits + } + if (capacity != lastWrite) writeTo(connection, buffer, lastWrite, capacity - lastWrite); + } + + private static void writeTo(PlayerConnection connection, NetworkBuffer buffer, long offset, long length) { + if (connection instanceof PlayerSocketConnection socketConnection) { + socketConnection.sendPacket(new BufferedPacket(buffer, offset, length)); + return; + } + // TODO for non-socket connection + } + } +} diff --git a/src/main/java/net/minestom/server/utils/Utils.java b/src/main/java/net/minestom/server/utils/Utils.java deleted file mode 100644 index 972212cba..000000000 --- a/src/main/java/net/minestom/server/utils/Utils.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.minestom.server.utils; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.nio.ByteBuffer; -import java.util.UUID; - -@ApiStatus.Internal -public final class Utils { - - private Utils() { - } - - public static int getVarIntSize(int input) { - return (input & 0xFFFFFF80) == 0 - ? 1 : (input & 0xFFFFC000) == 0 - ? 2 : (input & 0xFFE00000) == 0 - ? 3 : (input & 0xF0000000) == 0 - ? 4 : 5; - } - - public static void writeVarInt(ByteBuffer buf, int value) { - if ((value & (0xFFFFFFFF << 7)) == 0) { - buf.put((byte) value); - } else if ((value & (0xFFFFFFFF << 14)) == 0) { - buf.putShort((short) ((value & 0x7F | 0x80) << 8 | (value >>> 7))); - } else if ((value & (0xFFFFFFFF << 21)) == 0) { - buf.put((byte) (value & 0x7F | 0x80)); - buf.put((byte) ((value >>> 7) & 0x7F | 0x80)); - buf.put((byte) (value >>> 14)); - } else if ((value & (0xFFFFFFFF << 28)) == 0) { - buf.putInt((value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21)); - } else { - buf.putInt((value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80)); - buf.put((byte) (value >>> 28)); - } - } - - public static void writeVarIntHeader(@NotNull ByteBuffer buffer, int startIndex, int value) { - buffer.put(startIndex, (byte) (value & 0x7F | 0x80)); - buffer.put(startIndex + 1, (byte) ((value >>> 7) & 0x7F | 0x80)); - buffer.put(startIndex + 2, (byte) (value >>> 14)); - } - - public static int readVarInt(ByteBuffer buf) { - // https://github.com/jvm-profiling-tools/async-profiler/blob/a38a375dc62b31a8109f3af97366a307abb0fe6f/src/converter/one/jfr/JfrReader.java#L393 - int result = 0; - for (int shift = 0; ; shift += 7) { - byte b = buf.get(); - result |= (b & 0x7f) << shift; - if (b >= 0) { - return result; - } - } - } -} diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java b/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java deleted file mode 100644 index ef3e98355..000000000 --- a/src/main/java/net/minestom/server/utils/binary/BinaryBuffer.java +++ /dev/null @@ -1,185 +0,0 @@ -package net.minestom.server.utils.binary; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; - -/** - * Manages off-heap memory. - * Not thread-safe. - */ -@ApiStatus.Internal -public final class BinaryBuffer { - private ByteBuffer nioBuffer; // To become a `MemorySegment` once released - - private final int capacity; - private int readerOffset, writerOffset; - - private BinaryBuffer(ByteBuffer buffer) { - this.nioBuffer = buffer; - this.capacity = buffer.capacity(); - } - - @ApiStatus.Internal - public static BinaryBuffer ofSize(int size) { - return new BinaryBuffer(ByteBuffer.allocateDirect(size)); - } - - @ApiStatus.Internal - public static BinaryBuffer wrap(ByteBuffer buffer) { - assert buffer.isDirect(); - return new BinaryBuffer(buffer); - } - - - public static BinaryBuffer copy(BinaryBuffer buffer) { - final int size = buffer.readableBytes(); - final var temp = ByteBuffer.allocateDirect(size) - .put(buffer.asByteBuffer(0, size)); - BinaryBuffer newBuffer = new BinaryBuffer(temp); - newBuffer.writerOffset = size; - return newBuffer; - } - - public void write(ByteBuffer buffer, int index, int length) { - this.nioBuffer.put(writerOffset, buffer, index, length); - this.writerOffset += length; - } - - public void write(ByteBuffer buffer) { - write(buffer, buffer.position(), buffer.remaining()); - } - - public void write(BinaryBuffer buffer) { - write(buffer.asByteBuffer(buffer.readerOffset, buffer.writerOffset - buffer.readerOffset)); - } - - public int readVarInt() { - int value = 0; - for (int i = 0; i < 5; i++) { - final int offset = readerOffset + i; - final byte k = nioBuffer.get(offset); - value |= (k & 0x7F) << i * 7; - if ((k & 0x80) != 128) { - this.readerOffset = offset + 1; - return value; - } - } - throw new RuntimeException("VarInt is too big"); - } - - public @NotNull Marker mark() { - return new Marker(readerOffset, writerOffset); - } - - public void reset(int readerOffset, int writerOffset) { - this.readerOffset = readerOffset; - this.writerOffset = writerOffset; - } - - public void reset(@NotNull Marker marker) { - reset(marker.readerOffset(), marker.writerOffset()); - } - - public boolean canRead(int size) { - return readerOffset + size <= writerOffset; - } - - public boolean canWrite(int size) { - return writerOffset + size < capacity; - } - - public int capacity() { - return capacity; - } - - public int readerOffset() { - return readerOffset; - } - - public void readerOffset(int offset) { - this.readerOffset = offset; - } - - public int writerOffset() { - return writerOffset; - } - - public void writerOffset(int offset) { - this.writerOffset = offset; - } - - public int readableBytes() { - return writerOffset - readerOffset; - } - - public void writeBytes(byte[] bytes) { - this.nioBuffer.put(writerOffset, bytes); - this.writerOffset += bytes.length; - } - - public byte[] readBytes(int length) { - byte[] bytes = new byte[length]; - this.nioBuffer.get(readerOffset, bytes); - this.readerOffset += length; - return bytes; - } - - public byte[] readRemainingBytes() { - return readBytes(readableBytes()); - } - - public BinaryBuffer clear() { - this.readerOffset = 0; - this.writerOffset = 0; - this.nioBuffer.limit(capacity); - return this; - } - - public ByteBuffer asByteBuffer(int reader, int length) { - return nioBuffer.slice(reader, length); - } - - @ApiStatus.Internal - public ByteBuffer asByteBuffer() { - return nioBuffer; - } - - public boolean writeChannel(WritableByteChannel channel) throws IOException { - if (readerOffset == writerOffset) - return true; // Nothing to write - var writeBuffer = nioBuffer.slice(readerOffset, writerOffset - readerOffset); - final int count = channel.write(writeBuffer); - if (count == -1) { - // EOS - throw new IOException("Disconnected"); - } - this.readerOffset += count; - return writeBuffer.limit() == writeBuffer.position(); - } - - public void readChannel(ReadableByteChannel channel) throws IOException { - final int count = channel.read(nioBuffer.slice(writerOffset, capacity - writerOffset)); - if (count == -1) { - // EOS - throw new IOException("Disconnected"); - } - this.writerOffset += count; - } - - @Override - public String toString() { - return "BinaryBuffer{" + - "readerOffset=" + readerOffset + - ", writerOffset=" + writerOffset + - ", capacity=" + capacity + - '}'; - } - - public record Marker(int readerOffset, int writerOffset) { - } -} diff --git a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java index a41e60259..fa0db1503 100644 --- a/src/test/java/net/minestom/server/command/ArgumentTypeTest.java +++ b/src/test/java/net/minestom/server/command/ArgumentTypeTest.java @@ -454,7 +454,7 @@ public class ArgumentTypeTest { } @Test - public void testArgumentMapWithSender() { + public void testArgumentTransformWithSender() { var serverSender = new ServerSender(); var arg = ArgumentType.Word("word").from("word1", "word2", "word3") diff --git a/src/test/java/net/minestom/server/instance/anvil/AnvilLoaderIntegrationTest.java b/src/test/java/net/minestom/server/instance/anvil/AnvilLoaderIntegrationTest.java index 04a5e03bb..6bec53dd8 100644 --- a/src/test/java/net/minestom/server/instance/anvil/AnvilLoaderIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/anvil/AnvilLoaderIntegrationTest.java @@ -4,6 +4,7 @@ import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.Section; import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.palette.Palette; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.world.biome.Biome; @@ -19,6 +20,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import static net.minestom.server.network.NetworkBuffer.SHORT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -202,8 +204,16 @@ public class AnvilLoaderIntegrationTest { Section reloadedSection = reloadedChunk.getSection(section); // easiest equality check to write is a memory compare on written output - var original = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(originalSection)); - var reloaded = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(reloadedSection)); + var original = NetworkBuffer.makeArray(buffer -> { + buffer.write(SHORT, (short) originalSection.blockPalette().count()); + buffer.write(Palette.BLOCK_SERIALIZER, originalSection.blockPalette()); + buffer.write(Palette.BIOME_SERIALIZER, originalSection.biomePalette()); + }); + var reloaded = NetworkBuffer.makeArray(buffer -> { + buffer.write(SHORT, (short) reloadedSection.blockPalette().count()); + buffer.write(Palette.BLOCK_SERIALIZER, reloadedSection.blockPalette()); + buffer.write(Palette.BIOME_SERIALIZER, reloadedSection.biomePalette()); + }); Assertions.assertArrayEquals(original, reloaded); } diff --git a/src/test/java/net/minestom/server/instance/palette/PaletteOptimizationTest.java b/src/test/java/net/minestom/server/instance/palette/PaletteOptimizationTest.java index 9916d52ab..9cfa1f95e 100644 --- a/src/test/java/net/minestom/server/instance/palette/PaletteOptimizationTest.java +++ b/src/test/java/net/minestom/server/instance/palette/PaletteOptimizationTest.java @@ -60,9 +60,9 @@ public class PaletteOptimizationTest { } // Verify size { - var array = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(palette)); + var array = NetworkBuffer.makeArray(Palette.BLOCK_SERIALIZER, palette); int length1 = array.length; - array = NetworkBuffer.makeArray(networkBuffer -> networkBuffer.write(optimized)); + array = NetworkBuffer.makeArray(Palette.BLOCK_SERIALIZER, optimized); int length2 = array.length; assertTrue(length1 >= length2, "Optimized palette is bigger than the original one: " + length1 + " : " + length2); } diff --git a/src/test/java/net/minestom/server/item/component/AbstractItemComponentTest.java b/src/test/java/net/minestom/server/item/component/AbstractItemComponentTest.java index 04d42aa17..c71841f80 100644 --- a/src/test/java/net/minestom/server/item/component/AbstractItemComponentTest.java +++ b/src/test/java/net/minestom/server/item/component/AbstractItemComponentTest.java @@ -1,5 +1,6 @@ package net.minestom.server.item.component; +import net.minestom.server.MinecraftServer; import net.minestom.server.component.DataComponent; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.nbt.BinaryTagSerializer; @@ -11,7 +12,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -46,12 +46,13 @@ public abstract class AbstractItemComponentTest { } if (component().isSynced()) { - var written1 = NetworkBuffer.makeArray(b -> component().write(b, entry)); + var written1 = NetworkBuffer.makeArray(b -> component().write(b, entry), MinecraftServer.process()); - var read = component().read(new NetworkBuffer(ByteBuffer.wrap(written1))); + var buffer = NetworkBuffer.wrap(written1, 0, written1.length, MinecraftServer.process()); + var read = component().read(buffer); assertEquals(entry, read); - var written2 = NetworkBuffer.makeArray(b -> component().write(b, entry)); + var written2 = NetworkBuffer.makeArray(b -> component().write(b, entry), MinecraftServer.process()); assertArrayEquals(written1, written2); } } diff --git a/src/test/java/net/minestom/server/network/NetworkBufferTest.java b/src/test/java/net/minestom/server/network/NetworkBufferTest.java index ea02bdedd..65bac2f5e 100644 --- a/src/test/java/net/minestom/server/network/NetworkBufferTest.java +++ b/src/test/java/net/minestom/server/network/NetworkBufferTest.java @@ -2,6 +2,7 @@ package net.minestom.server.network; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; +import net.minestom.server.MinecraftServer; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; @@ -10,9 +11,10 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnknownNullability; import org.junit.jupiter.api.Test; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; import static net.kyori.adventure.nbt.IntBinaryTag.intBinaryTag; import static net.minestom.server.network.NetworkBuffer.*; @@ -22,7 +24,7 @@ public class NetworkBufferTest { @Test public void resize() { - var buffer = new NetworkBuffer(6); + var buffer = NetworkBuffer.resizableBuffer(6); buffer.write(INT, 6); assertEquals(4, buffer.writeIndex()); @@ -33,7 +35,7 @@ public class NetworkBufferTest { assertEquals(7, buffer.read(INT)); // Test one-off length - buffer = new NetworkBuffer(1); + buffer = NetworkBuffer.resizableBuffer(1); buffer.write(BYTE, (byte) 3); assertEquals(1, buffer.writeIndex()); @@ -44,9 +46,118 @@ public class NetworkBufferTest { assertEquals((byte) 4, buffer.read(BYTE)); } + @Test + public void resizeRead() { + var buffer = NetworkBuffer.resizableBuffer(4); + buffer.write(INT, 6); + assertEquals(4, buffer.capacity()); + assertEquals(4, buffer.writeIndex()); + + buffer.resize(8); + assertEquals(8, buffer.capacity()); + assertEquals(6, buffer.read(INT)); + + buffer.write(INT, 7); + assertEquals(8, buffer.capacity()); + assertEquals(8, buffer.writeIndex()); + } + + @Test + public void copyClone() { + var buffer = NetworkBuffer.staticBuffer(10); + buffer.write(INT, 6); + buffer.write(SHORT, (short) 2); + buffer.write(FLOAT, 3.5f); + assertEquals(10, buffer.writeIndex()); + assertEquals(10, buffer.capacity()); + + var copy = buffer.copy(0, 10); + assertEquals(10, copy.writeIndex()); + assertEquals(10, copy.capacity()); + + assertTrue(NetworkBuffer.equals(buffer, copy)); + } + + @Test + public void copyDirectZeroIndex() { + var buffer1 = NetworkBuffer.staticBuffer(10); + buffer1.write(INT, 6); + buffer1.write(SHORT, (short) 2); + buffer1.write(FLOAT, 3.5f); + assertEquals(10, buffer1.writeIndex()); + assertEquals(10, buffer1.capacity()); + + var buffer2 = NetworkBuffer.staticBuffer(10); + NetworkBuffer.copy(buffer1, 0, buffer2, 0, 10); + assertEquals(10, buffer2.capacity()); + + assertEquals(6, buffer2.read(INT)); + assertEquals((short) 2, buffer2.read(SHORT)); + assertEquals(3.5f, buffer2.read(FLOAT)); + } + + @Test + public void copyDirectIndex() { + var buffer1 = NetworkBuffer.staticBuffer(10); + buffer1.write(INT, 6); + buffer1.write(SHORT, (short) 2); + buffer1.write(FLOAT, 3.5f); + assertEquals(10, buffer1.writeIndex()); + assertEquals(10, buffer1.capacity()); + + var buffer2 = NetworkBuffer.staticBuffer(4); + NetworkBuffer.copy(buffer1, 6, buffer2, 0, 4); + assertEquals(4, buffer2.capacity()); + + assertEquals(3.5f, buffer2.read(FLOAT)); + } + + @Test + public void copyDirectIndexOffset() { + var buffer1 = NetworkBuffer.staticBuffer(10); + buffer1.write(INT, 6); + buffer1.write(SHORT, (short) 2); + buffer1.write(FLOAT, 3.5f); + assertEquals(10, buffer1.writeIndex()); + assertEquals(10, buffer1.capacity()); + + var buffer2 = NetworkBuffer.staticBuffer(8); + buffer2.write(INT, 5); + NetworkBuffer.copy(buffer1, 6, buffer2, 4, 4); + assertEquals(8, buffer2.capacity()); + + assertEquals(5, buffer2.read(INT)); + assertEquals(3.5f, buffer2.read(FLOAT)); + } + + @Test + public void compact() { + var buffer = NetworkBuffer.staticBuffer(256); + buffer.write(INT, 6); + buffer.write(SHORT, (short) 2); + buffer.write(FLOAT, 3.5f); + + buffer.read(INT); + buffer.compact(); + // Short should be copied at index 0 + assertEquals(256, buffer.capacity()); + assertEquals(6, buffer.writeIndex()); + assertEquals(0, buffer.readIndex()); + + assertEquals((short) 2, buffer.read(SHORT)); + assertEquals(3.5f, buffer.read(FLOAT)); + } + + @Test + public void outOfBound() { + var buffer = NetworkBuffer.staticBuffer(3); + buffer.write(SHORT, (short) 2); + assertThrows(IndexOutOfBoundsException.class, () -> buffer.write(INT, 6)); + } + @Test public void readableBytes() { - var buffer = new NetworkBuffer(); + var buffer = NetworkBuffer.resizableBuffer(); assertEquals(0, buffer.readableBytes()); buffer.write(BYTE, (byte) 0); @@ -64,7 +175,7 @@ public class NetworkBufferTest { @Test public void extractBytes() { - var buffer = new NetworkBuffer(); + var buffer = NetworkBuffer.resizableBuffer(); buffer.write(BYTE, (byte) 25); assertEquals(1, buffer.writeIndex()); @@ -94,7 +205,7 @@ public class NetworkBufferTest { assertArrayEquals(new byte[0], NetworkBuffer.makeArray(buffer -> { })); - assertArrayEquals(new byte[]{1}, NetworkBuffer.makeArray(buffer -> buffer.write(BYTE, (byte) 1))); + assertArrayEquals(new byte[]{1}, NetworkBuffer.makeArray(BYTE, (byte) 1)); assertArrayEquals(new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 50}, NetworkBuffer.makeArray(buffer -> { buffer.write(BYTE, (byte) 1); @@ -102,6 +213,70 @@ public class NetworkBufferTest { })); } + @Test + public void arrayWrap() { + byte[] array = new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 50}; + var buffer = NetworkBuffer.wrap(array, 0, array.length); + assertEquals(9, buffer.capacity()); + assertEquals(0, buffer.readIndex()); + assertEquals(array.length, buffer.writeIndex()); + + assertEquals((byte) 1, buffer.read(BYTE)); + assertEquals(50L, buffer.read(LONG)); + + assertEquals(9, buffer.readIndex()); + } + + @Test + public void sizeOfPrimitives() { + assertEquals(1, BYTE.sizeOf((byte) 1)); + assertEquals(2, SHORT.sizeOf((short) 1)); + assertEquals(4, INT.sizeOf(1)); + assertEquals(8, LONG.sizeOf(1L)); + assertEquals(4, FLOAT.sizeOf(1f)); + assertEquals(8, DOUBLE.sizeOf(1d)); + } + + @Test + public void sizeOfCompounds() { + var type = new Type() { + @Override + public void write(@NotNull NetworkBuffer buffer, Integer value) { + buffer.write(INT, value); + buffer.write(INT, value); + } + + @Override + public Integer read(@NotNull NetworkBuffer buffer) { + throw new UnsupportedOperationException(); + } + }; + + assertEquals(8, type.sizeOf(1)); + } + + @Test + public void sizeOfThrow() { + Function, Type> fn = networkBufferConsumer -> new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, Integer value) { + networkBufferConsumer.accept(buffer); + } + + @Override + public Integer read(@NotNull NetworkBuffer buffer) { + throw new UnsupportedOperationException(); + } + }; + + assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.resize(2)).sizeOf(1)); + assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.read(INT)).sizeOf(1)); + assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.readAt(0, INT)).sizeOf(1)); + assertThrows(UnsupportedOperationException.class, () -> fn.apply(NetworkBuffer::compact).sizeOf(1)); + assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.slice(0, 0, 0, 0)).sizeOf(1)); + assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.copy(0, 0, 0, 0)).sizeOf(1)); + } + @Test public void numbers() { assertBufferType(BOOLEAN, false, new byte[]{0x00}); @@ -228,9 +403,15 @@ public class NetworkBufferTest { @Test public void rawBytes() { - // FIXME: currently break because the array is identity compared - //assertBufferType(NetworkBuffer.RAW_BYTES, new byte[]{0x0B, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64}, - // new byte[]{0x0B, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64}); + var array = new byte[]{0x0B, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64}; + NetworkBuffer buffer = NetworkBuffer.resizableBuffer(); + buffer.write(RAW_BYTES, array); + assertEquals(0, buffer.readIndex()); + assertEquals(array.length, buffer.writeIndex()); + + var readArray = buffer.read(RAW_BYTES); + assertArrayEquals(array, readArray); + assertEquals(array.length, buffer.readIndex()); } @Test @@ -276,20 +457,18 @@ public class NetworkBufferTest { @Test public void collectionMaxSize() { - var buffer = new NetworkBuffer(); + var buffer = NetworkBuffer.resizableBuffer(); var list = new ArrayList(); for (int i = 0; i < 1000; i++) list.add(true); - buffer.writeCollection(BOOLEAN, list); + buffer.write(BOOLEAN.list(), list); - assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(BOOLEAN, 10)); - buffer.readIndex(0); // reset - assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(b -> b.read(BOOLEAN), 10)); + assertThrows(IllegalArgumentException.class, () -> buffer.read(BOOLEAN.list(10))); } @Test public void oomStringRegression() { - var buffer = new NetworkBuffer(ByteBuffer.allocate(100)); + var buffer = NetworkBuffer.resizableBuffer(100); buffer.write(VAR_INT, Integer.MAX_VALUE); // String length buffer.write(RAW_BYTES, "Hello".getBytes(StandardCharsets.UTF_8)); // String data @@ -297,7 +476,7 @@ public class NetworkBufferTest { } static void assertBufferType(NetworkBuffer.@NotNull Type type, @UnknownNullability T value, byte[] expected, @NotNull Action action) { - var buffer = new NetworkBuffer(); + var buffer = NetworkBuffer.resizableBuffer(MinecraftServer.process()); action.write(buffer, type, value); assertEquals(0, buffer.readIndex()); if (expected != null) assertEquals(expected.length, buffer.writeIndex()); @@ -316,7 +495,7 @@ public class NetworkBufferTest { // Ensure resize support { - var tmp = new NetworkBuffer(0); + var tmp = NetworkBuffer.resizableBuffer(0); action.write(tmp, type, value); assertEquals(0, tmp.readIndex()); if (expected != null) assertEquals(expected.length, tmp.writeIndex()); @@ -351,12 +530,12 @@ public class NetworkBufferTest { assertBufferType(type, value, expected, new Action() { @Override public void write(@NotNull NetworkBuffer buffer, @NotNull NetworkBuffer.Type type, @UnknownNullability T value) { - buffer.writeOptional(type, value); + buffer.write(type.optional(), value); } @Override public T read(@NotNull NetworkBuffer buffer, @NotNull NetworkBuffer.Type type) { - return buffer.readOptional(type); + return buffer.read(type.optional()); } }); } @@ -365,13 +544,13 @@ public class NetworkBufferTest { assertBufferTypeOptional(type, value, null); } - static void assertBufferTypeCollection(NetworkBuffer.@NotNull Type type, @NotNull Collection values, byte @Nullable [] expected) { - var buffer = new NetworkBuffer(); - buffer.writeCollection(type, values); + static void assertBufferTypeCollection(NetworkBuffer.@NotNull Type type, @NotNull List values, byte @Nullable [] expected) { + var buffer = NetworkBuffer.resizableBuffer(MinecraftServer.process()); + buffer.write(type.list(), values); assertEquals(0, buffer.readIndex()); if (expected != null) assertEquals(expected.length, buffer.writeIndex()); - var actual = buffer.readCollection(type, Integer.MAX_VALUE); + var actual = buffer.read(type.list(Integer.MAX_VALUE)); assertEquals(values, actual); if (expected != null) assertEquals(expected.length, buffer.readIndex()); @@ -384,7 +563,7 @@ public class NetworkBufferTest { } } - static void assertBufferTypeCollection(NetworkBuffer.@NotNull Type type, @NotNull Collection value) { + static void assertBufferTypeCollection(NetworkBuffer.@NotNull Type type, @NotNull List value) { assertBufferTypeCollection(type, value, null); } diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index 86bb04e57..e70bb1b16 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -156,6 +156,7 @@ public class PacketWriteReadTest { CLIENT_PACKETS.add(new ClientHandshakePacket(755, "localhost", 25565, ClientHandshakePacket.Intent.LOGIN)); } + @SuppressWarnings("unchecked") @Test public void serverTest() throws NoSuchFieldException, IllegalAccessException { for (var packet : SERVER_PACKETS) { @@ -165,6 +166,7 @@ public class PacketWriteReadTest { } } + @SuppressWarnings("unchecked") @Test public void clientTest() throws NoSuchFieldException, IllegalAccessException { for (var packet : CLIENT_PACKETS) { @@ -175,8 +177,8 @@ public class PacketWriteReadTest { } private static void testPacket(NetworkBuffer.Type networkType, T packet) { - byte[] bytes = NetworkBuffer.makeArray(buffer -> networkType.write(buffer, packet)); - NetworkBuffer reader = new NetworkBuffer(); + byte[] bytes = NetworkBuffer.makeArray(networkType, packet); + NetworkBuffer reader = NetworkBuffer.resizableBuffer(); reader.write(NetworkBuffer.RAW_BYTES, bytes); var createdPacket = networkType.read(reader); assertEquals(packet, createdPacket); diff --git a/src/test/java/net/minestom/server/network/SendablePacketTest.java b/src/test/java/net/minestom/server/network/SendablePacketTest.java index c7d046a6c..3615c1520 100644 --- a/src/test/java/net/minestom/server/network/SendablePacketTest.java +++ b/src/test/java/net/minestom/server/network/SendablePacketTest.java @@ -1,13 +1,19 @@ package net.minestom.server.network; import net.kyori.adventure.text.Component; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.PlayerHand; +import net.minestom.server.network.packet.PacketReading; +import net.minestom.server.network.packet.PacketWriting; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.packet.client.play.ClientAnimationPacket; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.LazyPacket; import net.minestom.server.network.packet.server.play.SystemChatPacket; -import net.minestom.server.utils.PacketUtils; import org.junit.jupiter.api.Test; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.zip.DataFormatException; import static org.junit.jupiter.api.Assertions.*; @@ -32,13 +38,30 @@ public class SendablePacketTest { var cached = new CachedPacket(packet); assertSame(packet, cached.packet(ConnectionState.PLAY)); - var buffer = PacketUtils.allocateTrimmedPacket(ConnectionState.PLAY, packet); + var buffer = PacketWriting.allocateTrimmedPacket(ConnectionState.PLAY, packet, + MinecraftServer.getCompressionThreshold()); var cachedBuffer = cached.body(ConnectionState.PLAY); - assertEquals(buffer.body(), cachedBuffer); + assertTrue(NetworkBuffer.equals(buffer, cachedBuffer)); // May fail in the very unlikely case where soft references are cleared // Rare enough to make this test worth it assertSame(cached.body(ConnectionState.PLAY), cachedBuffer); assertSame(packet, cached.packet(ConnectionState.PLAY)); } + + @Test + public void trimmed() throws DataFormatException { + var packet = new ClientAnimationPacket(PlayerHand.MAIN); + + var buffer = PacketWriting.allocateTrimmedPacket(ConnectionState.PLAY, packet, 0); + + var result = PacketReading.readClient(buffer, ConnectionState.PLAY, false); + if (!(result instanceof PacketReading.Result.Success success)) { + fail(); + return; + } + assertEquals(1, success.packets().size()); + var readPacket = success.packets().getFirst(); + assertEquals(packet, readPacket); + } } diff --git a/src/test/java/net/minestom/server/network/SocketReadTest.java b/src/test/java/net/minestom/server/network/SocketReadTest.java index d2e607061..7706ee19b 100644 --- a/src/test/java/net/minestom/server/network/SocketReadTest.java +++ b/src/test/java/net/minestom/server/network/SocketReadTest.java @@ -1,20 +1,17 @@ package net.minestom.server.network; -import it.unimi.dsi.fastutil.Pair; +import net.minestom.server.network.packet.PacketReading; +import net.minestom.server.network.packet.PacketVanilla; +import net.minestom.server.network.packet.PacketWriting; +import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket; -import net.minestom.server.utils.ObjectPool; -import net.minestom.server.utils.PacketUtils; -import net.minestom.server.utils.Utils; -import net.minestom.server.utils.binary.BinaryBuffer; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.List; import java.util.zip.DataFormatException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SocketReadTest { @@ -23,23 +20,15 @@ public class SocketReadTest { public void complete(boolean compressed) throws DataFormatException { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); - var wrapper = BinaryBuffer.wrap(buffer); - wrapper.reset(0, buffer.position()); - - List> packets = new ArrayList<>(); - var remaining = PacketUtils.readPackets(wrapper, compressed, - (integer, payload) -> packets.add(Pair.of(integer, payload))); - assertNull(remaining); - - assertEquals(1, packets.size()); - var rawPacket = packets.get(0); - assertEquals(0x0A, rawPacket.left()); - var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); - assertEquals("channel", readPacket.channel()); - assertEquals(2000, readPacket.data().length); + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Success success)) { + throw new AssertionError("Expected a success result, got " + readResult); + } + var packets = success.packets(); + assertEquals(List.of(packet), packets); } @ParameterizedTest @@ -47,25 +36,16 @@ public class SocketReadTest { public void completeTwo(boolean compressed) throws DataFormatException { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); - PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); - var wrapper = BinaryBuffer.wrap(buffer); - wrapper.reset(0, buffer.position()); - - List> packets = new ArrayList<>(); - var remaining = PacketUtils.readPackets(wrapper, compressed, - (integer, payload) -> packets.add(Pair.of(integer, payload))); - assertNull(remaining); - - assertEquals(2, packets.size()); - for (var rawPacket : packets) { - assertEquals(0x0A, rawPacket.left()); - var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); - assertEquals("channel", readPacket.channel()); - assertEquals(2000, readPacket.data().length); + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Success success)) { + throw new AssertionError("Expected a success result, got " + readResult); } + var packets = success.packets(); + assertEquals(List.of(packet, packet), packets); } @ParameterizedTest @@ -75,25 +55,21 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); - Utils.writeVarInt(buffer, 200); // incomplete 200 bytes packet + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); + buffer.write(NetworkBuffer.VAR_INT, 200); // incomplete 200 bytes packet - var wrapper = BinaryBuffer.wrap(buffer); - wrapper.reset(0, buffer.position()); + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Success success)) { + throw new AssertionError("Expected a success result, got " + readResult); + } + var packets = success.packets(); + assertEquals(List.of(packet), packets); - List> packets = new ArrayList<>(); - var remaining = PacketUtils.readPackets(wrapper, compressed, - (integer, payload) -> packets.add(Pair.of(integer, payload))); - assertNotNull(remaining); - assertEquals(Utils.getVarIntSize(200), remaining.readableBytes()); - - assertEquals(1, packets.size()); - var rawPacket = packets.get(0); - assertEquals(0x0A, rawPacket.left()); - var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); - assertEquals("channel", readPacket.channel()); - assertEquals(2000, readPacket.data().length); + readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Empty)) { + throw new AssertionError("Expected an empty result, got " + readResult); + } } @ParameterizedTest @@ -103,24 +79,66 @@ public class SocketReadTest { var packet = new ClientPluginMessagePacket("channel", new byte[2000]); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 0x0A, ClientPluginMessagePacket.SERIALIZER, packet, compressed ? 256 : 0); - buffer.put((byte) -85); // incomplete var-int length + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); + buffer.write(NetworkBuffer.BYTE, (byte) -85); // incomplete var-int length - var wrapper = BinaryBuffer.wrap(buffer); - wrapper.reset(0, buffer.position()); + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Success success)) { + throw new AssertionError("Expected a success result, got " + readResult); + } + var packets = success.packets(); + assertEquals(1, buffer.readableBytes()); - List> packets = new ArrayList<>(); - var remaining = PacketUtils.readPackets(wrapper, compressed, - (integer, payload) -> packets.add(Pair.of(integer, payload))); - assertNotNull(remaining); - assertEquals(1, remaining.readableBytes()); + assertEquals(List.of(packet), packets); - assertEquals(1, packets.size()); - var rawPacket = packets.get(0); - assertEquals(0x0A, rawPacket.left()); - var readPacket = ClientPluginMessagePacket.SERIALIZER.read(new NetworkBuffer(rawPacket.right())); - assertEquals("channel", readPacket.channel()); - assertEquals(2000, readPacket.data().length); + // Try to read the next packet + readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Empty)) { + throw new AssertionError("Expected an empty result, got " + readResult); + } + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void resize(boolean compressed) throws DataFormatException { + // Write a complete packet that is larger than the buffer capacity + + var packet = new ClientPluginMessagePacket("channel", new byte[2000]); + + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, ConnectionState.PLAY, packet, compressed ? 256 : 0); + final long packetLength = buffer.writeIndex(); + buffer = buffer.copy(0, packetLength / 2).index(0, packetLength / 2); + + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Failure failure)) { + throw new AssertionError("Expected a failure result, got " + readResult); + } + assertEquals(packetLength, failure.requiredCapacity()); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void resizeHeader(boolean compressed) throws DataFormatException { + // Write a buffer where you cannot read the packet length + + var buffer = NetworkBuffer.staticBuffer(1); + buffer.write(NetworkBuffer.BYTE, (byte) -85); // incomplete var-int length + + var readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); + if (!(readResult instanceof PacketReading.Result.Failure failure)) { + throw new AssertionError("Expected a failure result, got " + readResult); + } + // 5 = max var-int size + assertEquals(5, failure.requiredCapacity()); + } + + private static int getVarIntSize(int input) { + return (input & 0xFFFFFF80) == 0 + ? 1 : (input & 0xFFFFC000) == 0 + ? 2 : (input & 0xFFE00000) == 0 + ? 3 : (input & 0xF0000000) == 0 + ? 4 : 5; } } diff --git a/src/test/java/net/minestom/server/network/SocketWriteTest.java b/src/test/java/net/minestom/server/network/SocketWriteTest.java index d1450cb01..d38665591 100644 --- a/src/test/java/net/minestom/server/network/SocketWriteTest.java +++ b/src/test/java/net/minestom/server/network/SocketWriteTest.java @@ -1,9 +1,8 @@ package net.minestom.server.network; +import net.minestom.server.network.packet.PacketVanilla; +import net.minestom.server.network.packet.PacketWriting; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.utils.ObjectPool; -import net.minestom.server.utils.PacketUtils; -import net.minestom.server.utils.Utils; import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; @@ -31,65 +30,73 @@ public class SocketWriteTest { public void writeSingleUncompressed() { var packet = new IntPacket(5); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future - assertEquals(3 + 1 + 4, buffer.position(), "Invalid buffer position"); + assertEquals(3 + 1 + 4, buffer.writeIndex(), "Invalid buffer position"); } @Test public void writeMultiUncompressed() { var packet = new IntPacket(5); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, -1); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, -1); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, -1); // 3 bytes length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future - assertEquals((3 + 1 + 4) * 2, buffer.position(), "Invalid buffer position"); + assertEquals((3 + 1 + 4) * 2, buffer.writeIndex(), "Invalid buffer position"); } @Test public void writeSingleCompressed() { var string = "Hello world!".repeat(200); var stringLength = string.getBytes(StandardCharsets.UTF_8).length; - var lengthLength = Utils.getVarIntSize(stringLength); + var lengthLength = getVarIntSize(stringLength); var packet = new CompressiblePacket(string); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, CompressiblePacket.SERIALIZER, packet, 256); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, CompressiblePacket.SERIALIZER, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + payload // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future - assertNotEquals(3 + 3 + 1 + lengthLength + stringLength, buffer.position(), "Buffer position does not account for compression"); + assertNotEquals(3 + 3 + 1 + lengthLength + stringLength, buffer.writeIndex(), "Buffer position does not account for compression"); } @Test public void writeSingleCompressedSmall() { var packet = new IntPacket(5); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future - assertEquals(3 + 3 + 1 + 4, buffer.position(), "Invalid buffer position"); + assertEquals(3 + 3 + 1 + 4, buffer.writeIndex(), "Invalid buffer position"); } @Test public void writeMultiCompressedSmall() { var packet = new IntPacket(5); - var buffer = ObjectPool.PACKET_POOL.get(); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); - PacketUtils.writeFramedPacket(buffer, 1, IntPacket.SERIALIZER, packet, 256); + var buffer = PacketVanilla.PACKET_POOL.get(); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, 256); + PacketWriting.writeFramedPacket(buffer, IntPacket.SERIALIZER, 1, packet, 256); // 3 bytes packet length [var-int] + 3 bytes data length [var-int] + 1 byte packet id [var-int] + 4 bytes int // The 3 bytes var-int length is hardcoded for performance purpose, could change in the future - assertEquals((3 + 3 + 1 + 4) * 2, buffer.position(), "Invalid buffer position"); + assertEquals((3 + 3 + 1 + 4) * 2, buffer.writeIndex(), "Invalid buffer position"); + } + + private static int getVarIntSize(int input) { + return (input & 0xFFFFFF80) == 0 + ? 1 : (input & 0xFFFFC000) == 0 + ? 2 : (input & 0xFFE00000) == 0 + ? 3 : (input & 0xF0000000) == 0 + ? 4 : 5; } } diff --git a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java index dd5c72fec..f3245fd96 100644 --- a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java +++ b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java @@ -24,8 +24,6 @@ public class DeclareRecipesPacketTest { ItemStack.of(Material.DIAMOND)) ) )); - - assertThrows(IllegalArgumentException.class, () -> NetworkBuffer.makeArray(networkBuffer -> - DeclareRecipesPacket.SERIALIZER.write(networkBuffer, packet))); + assertThrows(IllegalArgumentException.class, () -> NetworkBuffer.makeArray(DeclareRecipesPacket.SERIALIZER, packet)); } } diff --git a/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java b/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java index d38b84d04..0b0d3125b 100644 --- a/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java +++ b/src/test/java/net/minestom/server/network/socket/ServerAddressTest.java @@ -1,6 +1,5 @@ package net.minestom.server.network.socket; -import net.minestom.server.network.packet.PacketParser; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -19,7 +18,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); InetSocketAddress address = new InetSocketAddress("localhost", 25565); - var server = new Server(new PacketParser.Client()); + var server = new Server(); server.init(address); assertSame(address, server.socketAddress()); assertEquals(address.getHostString(), server.getAddress()); @@ -35,7 +34,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); InetSocketAddress address = new InetSocketAddress("localhost", 0); - var server = new Server(new PacketParser.Client()); + var server = new Server(); server.init(address); assertSame(address, server.socketAddress()); assertEquals(address.getHostString(), server.getAddress()); @@ -51,7 +50,7 @@ public class ServerAddressTest { assumeTrue(System.getenv("GITHUB_ACTIONS") == null); UnixDomainSocketAddress address = UnixDomainSocketAddress.of("minestom.sock"); - var server = new Server(new PacketParser.Client()); + var server = new Server(); server.init(address); assertTrue(Files.exists(address.getPath())); assertSame(address, server.socketAddress()); @@ -64,8 +63,8 @@ public class ServerAddressTest { } @Test - public void noAddressTest() throws IOException { - var server = new Server(new PacketParser.Client()); + public void noAddressTest() { + var server = new Server(); assertDoesNotThrow(server::stop); } } diff --git a/src/test/java/net/minestom/server/particle/ParticleDataTest.java b/src/test/java/net/minestom/server/particle/ParticleDataTest.java index f7aa234f7..a0bce4ae0 100644 --- a/src/test/java/net/minestom/server/particle/ParticleDataTest.java +++ b/src/test/java/net/minestom/server/particle/ParticleDataTest.java @@ -13,34 +13,34 @@ public class ParticleDataTest { public void testDustParticleDefault() { Particle particle = Particle.DUST; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(NetworkBuffer.resizableBuffer(), packet)); } @Test public void testDustParticleInvalid() { var particle = Particle.DUST.withProperties(null, 1); ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); + assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(NetworkBuffer.resizableBuffer(), packet)); } @Test public void testParticleValid() { var particle = Particle.ENTITY_EFFECT; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(NetworkBuffer.resizableBuffer(), packet)); } @Test public void testParticleData() { var particle = Particle.ENTITY_EFFECT; ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); + assertDoesNotThrow(() -> ParticlePacket.SERIALIZER.write(NetworkBuffer.resizableBuffer(), packet)); } @Test public void invalidBlock() { var particle = Particle.BLOCK.withBlock(null); ParticlePacket packet = new ParticlePacket(particle, true, 0, 0, 0, 0, 0, 0, 0, 0); - assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(new NetworkBuffer(), packet)); + assertThrows(NullPointerException.class, () -> ParticlePacket.SERIALIZER.write(NetworkBuffer.resizableBuffer(), packet)); } } diff --git a/src/test/java/net/minestom/server/utils/ObjectPoolTest.java b/src/test/java/net/minestom/server/utils/ObjectPoolTest.java index 42c8557ad..aec1af14e 100644 --- a/src/test/java/net/minestom/server/utils/ObjectPoolTest.java +++ b/src/test/java/net/minestom/server/utils/ObjectPoolTest.java @@ -1,9 +1,11 @@ package net.minestom.server.utils; -import net.minestom.server.utils.binary.BinaryBuffer; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.PacketVanilla; import org.junit.jupiter.api.Test; -import java.util.HashSet; +import java.util.Collections; +import java.util.IdentityHashMap; import java.util.Set; import static org.junit.jupiter.api.Assertions.*; @@ -12,8 +14,8 @@ public class ObjectPoolTest { @Test public void pool() { - var pool = ObjectPool.BUFFER_POOL; - Set pooledBuffers = new HashSet<>(); + var pool = PacketVanilla.PACKET_POOL; + Set pooledBuffers = Collections.newSetFromMap(new IdentityHashMap<>()); pool.clear(); assertEquals(0, pool.count()); @@ -32,7 +34,7 @@ public class ObjectPoolTest { @Test public void autoClose() { - var pool = ObjectPool.BUFFER_POOL; + var pool = PacketVanilla.PACKET_POOL; assertEquals(0, pool.count()); try (var ignored = pool.hold()) { assertEquals(0, pool.count()); diff --git a/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java b/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java index 5a4dc13b7..5d22e599f 100644 --- a/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java +++ b/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java @@ -5,14 +5,14 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.translation.TranslationRegistry; import net.minestom.server.adventure.MinestomAdventure; +import net.minestom.server.coordinate.Pos; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.SetSlotPacket; +import net.minestom.server.network.packet.server.play.SystemChatPacket; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.network.packet.server.play.SystemChatPacket; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -43,7 +43,7 @@ public class TranslationIntegrationTest { MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = true; final var message = Component.translatable("test.key"); final var packet = new SystemChatPacket(message, false); - PacketUtils.sendGroupedPacket(List.of(player), packet); + PacketSendingUtils.sendGroupedPacket(List.of(player), packet); // the message should not be changed if translations are enabled. // the translation of the message itself will be proceeded in PlayerConnectionImpl class @@ -62,7 +62,7 @@ public class TranslationIntegrationTest { MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = false; final var message = Component.translatable("test.key"); final var packet = new SystemChatPacket(message, false); - PacketUtils.sendGroupedPacket(List.of(player), packet); + PacketSendingUtils.sendGroupedPacket(List.of(player), packet); collector.assertSingle(received -> { assertEquals(message, received.message()); @@ -82,7 +82,7 @@ public class TranslationIntegrationTest { .with(ItemComponent.ITEM_NAME, message) .with(ItemComponent.CUSTOM_NAME, message); final var packet = new SetSlotPacket((byte) 0x01, 1, (short) 1, itemStack); - PacketUtils.sendGroupedPacket(List.of(player), packet); + PacketSendingUtils.sendGroupedPacket(List.of(player), packet); collector.assertSingle(received -> { assertNotEquals(message, received.itemStack().get(ItemComponent.ITEM_NAME)); From 879942e6ab5ed38aa56600207d1ce30ddca5591c Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 29 Aug 2024 22:14:59 +0200 Subject: [PATCH 14/97] fixes --- .../ComponentNetworkBufferTypeImpl.java | 29 +++++++++++-------- .../server/network/NetworkBuffer.java | 2 +- .../server/play/EntityAttributesPacket.java | 27 +++++++---------- .../server/network/player/GameProfile.java | 3 +- .../ComponentNetworkBufferTypeTest.java | 4 +-- 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/main/java/net/minestom/server/network/ComponentNetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/ComponentNetworkBufferTypeImpl.java index 35e4cf805..3fcacd3fb 100644 --- a/src/main/java/net/minestom/server/network/ComponentNetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/ComponentNetworkBufferTypeImpl.java @@ -221,7 +221,8 @@ record ComponentNetworkBufferTypeImpl() implements NetworkBufferTypeImpl hoverEvent) { + @SuppressWarnings("unchecked") + private void writeHoverEvent(@NotNull NetworkBuffer buffer, @NotNull HoverEvent hoverEvent) { buffer.write(BYTE, TAG_COMPOUND); writeUtf(buffer, "hoverEvent"); @@ -279,9 +280,9 @@ record ComponentNetworkBufferTypeImpl() implements NetworkBufferTypeImpl= 0x80 || c == 0) break; - buffer.nioBuffer.put(buffer.writeIndex++, (byte) c); + impl._putByte(buffer.writeIndex(), (byte) c); + impl.advanceWrite(1); } for (; i < strlen; i++) { int c = str.charAt(i); if (c < 0x80 && c != 0) { - buffer.nioBuffer.put(buffer.writeIndex++, (byte) c); + impl._putByte(buffer.writeIndex(), (byte) c); + impl.advanceWrite(1); } else if (c >= 0x800) { - buffer.nioBuffer.put(buffer.writeIndex++, (byte) (0xE0 | ((c >> 12) & 0x0F))); - buffer.nioBuffer.put(buffer.writeIndex++, (byte) (0x80 | ((c >> 6) & 0x3F))); - buffer.nioBuffer.put(buffer.writeIndex++, (byte) (0x80 | ((c >> 0) & 0x3F))); + impl._putByte(buffer.writeIndex(), (byte) (0xE0 | ((c >> 12) & 0x0F))); + impl._putByte(buffer.writeIndex() + 1, (byte) (0x80 | ((c >> 6) & 0x3F))); + impl._putByte(buffer.writeIndex() + 2, (byte) (0x80 | ((c >> 0) & 0x3F))); + impl.advanceWrite(3); } else { - buffer.nioBuffer.put(buffer.writeIndex++, (byte) (0xC0 | ((c >> 6) & 0x1F))); - buffer.nioBuffer.put(buffer.writeIndex++, (byte) (0x80 | ((c >> 0) & 0x3F))); + impl._putByte(buffer.writeIndex(), (byte) (0xC0 | ((c >> 6) & 0x1F))); + impl._putByte(buffer.writeIndex() + 1, (byte) (0x80 | ((c >> 0) & 0x3F))); + impl.advanceWrite(2); } } } - } diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index bef9d2929..316212279 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -48,7 +48,7 @@ public sealed interface NetworkBuffer permits NetworkBufferImpl { @SuppressWarnings({"unchecked", "rawtypes"}) Type NBT_COMPOUND = (Type) new NetworkBufferTypeImpl.NbtType(); Type BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType(); - Type COMPONENT = new NetworkBufferTypeImpl.ComponentType(); + Type COMPONENT = new ComponentNetworkBufferTypeImpl(); Type JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType(); Type UUID = new NetworkBufferTypeImpl.UUIDType(); Type POS = new NetworkBufferTypeImpl.PosType(); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java index ef645a47b..4bb2f9c18 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityAttributesPacket.java @@ -5,7 +5,6 @@ import net.minestom.server.entity.attribute.AttributeModifier; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; @@ -18,30 +17,26 @@ public record EntityAttributesPacket(int entityId, List properties) im public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( VAR_INT, EntityAttributesPacket::entityId, - Property.NETWORK_TYPE.list(MAX_ENTRIES), EntityAttributesPacket::properties, + Property.SERIALIZER.list(MAX_ENTRIES), EntityAttributesPacket::properties, EntityAttributesPacket::new); public EntityAttributesPacket { properties = List.copyOf(properties); } - public record Property(Attribute attribute, double value, Collection modifiers) { - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Property value) { - buffer.write(Attribute.NETWORK_TYPE, value.attribute); - buffer.write(DOUBLE, value.value); - buffer.writeCollection(AttributeModifier.NETWORK_TYPE, value.modifiers); - } - - @Override - public Property read(@NotNull NetworkBuffer buffer) { - return new Property(buffer.read(Attribute.NETWORK_TYPE), buffer.read(DOUBLE), buffer.readCollection(AttributeModifier.NETWORK_TYPE, Short.MAX_VALUE)); - } - }; + public record Property(Attribute attribute, double value, List modifiers) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Attribute.NETWORK_TYPE, Property::attribute, + DOUBLE, Property::value, + AttributeModifier.NETWORK_TYPE.list(), Property::modifiers, + Property::new); public Property { modifiers = List.copyOf(modifiers); } + + public Property(Attribute attribute, double value, Collection modifiers) { + this(attribute, value, List.copyOf(modifiers)); + } } } diff --git a/src/main/java/net/minestom/server/network/player/GameProfile.java b/src/main/java/net/minestom/server/network/player/GameProfile.java index 63ed3d9c2..0ca30cc89 100644 --- a/src/main/java/net/minestom/server/network/player/GameProfile.java +++ b/src/main/java/net/minestom/server/network/player/GameProfile.java @@ -2,7 +2,6 @@ package net.minestom.server.network.player; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +11,7 @@ import java.util.UUID; import static net.minestom.server.network.NetworkBuffer.STRING; public record GameProfile(@NotNull UUID uuid, @NotNull String name, - @NotNull List<@NotNull Property> properties) implements NetworkBuffer.Writer { + @NotNull List<@NotNull Property> properties) { public static final int MAX_PROPERTIES = 1024; public GameProfile { diff --git a/src/test/java/net/minestom/server/network/ComponentNetworkBufferTypeTest.java b/src/test/java/net/minestom/server/network/ComponentNetworkBufferTypeTest.java index 54cfca8f4..507f4d475 100644 --- a/src/test/java/net/minestom/server/network/ComponentNetworkBufferTypeTest.java +++ b/src/test/java/net/minestom/server/network/ComponentNetworkBufferTypeTest.java @@ -5,7 +5,6 @@ import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; -import java.nio.ByteBuffer; import java.util.List; import static net.minestom.server.network.NetworkBuffer.COMPONENT; @@ -80,7 +79,8 @@ public class ComponentNetworkBufferTypeTest { private static void assertWriteReadEquality(@NotNull Component comp) { var array = NetworkBuffer.makeArray(buffer -> buffer.write(COMPONENT, comp)); - var actual = NBT_READER.deserialize(new NetworkBuffer(ByteBuffer.wrap(array)).read(NBT)); + var buffer = NetworkBuffer.wrap(array, 0, array.length); + var actual = NBT_READER.deserialize(buffer.read(NBT)); assertEquals(comp, actual); } } From dd1b584cd21f947f45eb3761e9ab6ca54e72e909 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 30 Aug 2024 23:55:56 +0200 Subject: [PATCH 15/97] Add `throws IndexOutOfBoundsException` buffer warning --- .../java/net/minestom/server/network/NetworkBuffer.java | 8 ++++---- .../net/minestom/server/network/NetworkBufferImpl.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index 316212279..58ed37ab9 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -103,13 +103,13 @@ public sealed interface NetworkBuffer permits NetworkBufferImpl { return new NetworkBufferTypeImpl.LazyType<>(supplier); } - void write(@NotNull Type type, @UnknownNullability T value); + void write(@NotNull Type type, @UnknownNullability T value) throws IndexOutOfBoundsException; - @UnknownNullability T read(@NotNull Type type); + @UnknownNullability T read(@NotNull Type type) throws IndexOutOfBoundsException; - void writeAt(long index, @NotNull Type type, @UnknownNullability T value); + void writeAt(long index, @NotNull Type type, @UnknownNullability T value) throws IndexOutOfBoundsException; - @UnknownNullability T readAt(long index, @NotNull Type type); + @UnknownNullability T readAt(long index, @NotNull Type type) throws IndexOutOfBoundsException; void copyTo(long srcOffset, byte @NotNull [] dest, long destOffset, long length); diff --git a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java index 2617349d2..22b34c791 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java @@ -159,14 +159,14 @@ final class NetworkBufferImpl implements NetworkBuffer { public long advanceWrite(long length) { final long oldWriteIndex = writeIndex; - writeIndex += length; + writeIndex = oldWriteIndex + length; return oldWriteIndex; } @Override public long advanceRead(long length) { final long oldReadIndex = readIndex; - readIndex += length; + readIndex = oldReadIndex + length; return oldReadIndex; } From 388ed525aaa19022d739c996a9c35e3034e12254 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 31 Aug 2024 22:59:13 +0200 Subject: [PATCH 16/97] Avoid reallocating buffer view --- .../server/network/NetworkBufferImpl.java | 15 ++++++++++----- .../server/utils/PacketViewableUtils.java | 8 +++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java index 22b34c791..2d33913ff 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java @@ -44,6 +44,8 @@ final class NetworkBufferImpl implements NetworkBuffer { final @Nullable AutoResize autoResize; final @Nullable Registries registries; + ByteBuffer nioBuffer = null; + NetworkBufferImpl(NetworkBufferImpl parent, long address, long capacity, long readIndex, long writeIndex, @@ -354,11 +356,14 @@ final class NetworkBufferImpl implements NetworkBuffer { } private ByteBuffer bufferSlice(int position, int length) { - ByteBuffer buffer = ByteBuffer.allocateDirect(0).order(ByteOrder.BIG_ENDIAN); - updateAddress(buffer, address); - updateCapacity(buffer, (int) capacity); - buffer.limit(position + length).position(position); - return buffer; + ByteBuffer nioBuffer = this.nioBuffer; + if (nioBuffer == null) { + this.nioBuffer = nioBuffer = ByteBuffer.allocateDirect(0).order(ByteOrder.BIG_ENDIAN); + } + updateAddress(nioBuffer, address); + updateCapacity(nioBuffer, (int) capacity); + nioBuffer.limit(position + length).position(position); + return nioBuffer; } @Override diff --git a/src/main/java/net/minestom/server/utils/PacketViewableUtils.java b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java index 094bc958f..b7156422b 100644 --- a/src/main/java/net/minestom/server/utils/PacketViewableUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java @@ -24,11 +24,11 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; +@ApiStatus.Internal public final class PacketViewableUtils { // Viewable packets private static final Cache VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); - @ApiStatus.Experimental public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket, @Nullable Entity entity) { if (entity != null && !entity.hasPredictableViewers()) { @@ -45,7 +45,6 @@ public final class PacketViewableUtils { storage.append(serverPacket, exception); } - @ApiStatus.Internal public static void flush() { if (ServerFlag.VIEWABLE_PACKET) { VIEWABLE_STORAGE_MAP.asMap().entrySet().parallelStream().forEach(entry -> @@ -53,13 +52,12 @@ public final class PacketViewableUtils { } } - @ApiStatus.Experimental public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket) { prepareViewablePacket(viewable, serverPacket, null); } - static final class ViewableStorage { - static final ObjectPool POOL = ObjectPool.pool( + private static final class ViewableStorage { + private static final ObjectPool POOL = ObjectPool.pool( () -> NetworkBuffer.resizableBuffer(ServerFlag.POOLED_BUFFER_SIZE, MinecraftServer.process()), NetworkBuffer::clear); // Player id -> list of offsets to ignore (32:32 bits) From 5ccd0f07896308d57e541a2d290ed440f6782319 Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 4 Sep 2024 01:39:40 +0200 Subject: [PATCH 17/97] PlayerSettings record (#2365) --- .../server/adventure/Localizable.java | 37 ---- .../server/adventure/MinestomAdventure.java | 2 - .../net/minestom/server/entity/Player.java | 203 ++++-------------- .../listener/common/SettingsListener.java | 3 +- .../minestom/server/message/Messenger.java | 2 +- .../client/common/ClientSettingsPacket.java | 24 +-- .../server/network/player/ClientSettings.java | 63 ++++++ .../entity/player/PlayerIntegrationTest.java | 18 +- .../player/PlayerMovementIntegrationTest.java | 14 +- .../PlayerRespawnChunkIntegrationTest.java | 5 +- 10 files changed, 128 insertions(+), 243 deletions(-) delete mode 100644 src/main/java/net/minestom/server/adventure/Localizable.java create mode 100644 src/main/java/net/minestom/server/network/player/ClientSettings.java diff --git a/src/main/java/net/minestom/server/adventure/Localizable.java b/src/main/java/net/minestom/server/adventure/Localizable.java deleted file mode 100644 index b9325a815..000000000 --- a/src/main/java/net/minestom/server/adventure/Localizable.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.minestom.server.adventure; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Locale; - -/** - * Represents something which can have a locale. - */ -public interface Localizable { - - /** - * Gets a localizable that returns {@code null} for all calls to {@link #getLocale()}. - * - * @return the empty localizable - */ - static @NotNull Localizable empty() { - return MinestomAdventure.NULL_LOCALIZABLE; - } - - /** - * Gets the locale. - * - * @return the locale, or {@code null} if they do not have a locale set - */ - @Nullable Locale getLocale(); - - /** - * Sets the locale. This can be set to {@code null} to remove a locale registration. - * - * @param locale the new locale - */ - default void setLocale(@Nullable Locale locale) { - throw new UnsupportedOperationException("You cannot set the locale for this object!"); - } -} diff --git a/src/main/java/net/minestom/server/adventure/MinestomAdventure.java b/src/main/java/net/minestom/server/adventure/MinestomAdventure.java index 10ffcdfa7..3975d8321 100644 --- a/src/main/java/net/minestom/server/adventure/MinestomAdventure.java +++ b/src/main/java/net/minestom/server/adventure/MinestomAdventure.java @@ -30,8 +30,6 @@ public final class MinestomAdventure { // todo: Need to properly add a translator interface so it can check for presence of a key for the flattener. public static BiFunction COMPONENT_TRANSLATOR = GlobalTranslator::render; - static final Localizable NULL_LOCALIZABLE = () -> null; - private static Locale defaultLocale = Locale.getDefault(); private MinestomAdventure() { diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 5f7aa22ee..2bd770cea 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -26,7 +26,6 @@ import net.minestom.server.ServerFlag; import net.minestom.server.advancements.AdvancementTab; import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.AdventurePacketConvertor; -import net.minestom.server.adventure.Localizable; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.collision.BoundingBox; import net.minestom.server.command.CommandSender; @@ -58,7 +57,6 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.WrittenBookContent; import net.minestom.server.listener.manager.PacketListenerManager; -import net.minestom.server.message.ChatMessageType; import net.minestom.server.message.ChatPosition; import net.minestom.server.message.Messenger; import net.minestom.server.network.ConnectionManager; @@ -71,6 +69,7 @@ import net.minestom.server.network.packet.server.common.*; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.data.WorldPos; +import net.minestom.server.network.player.ClientSettings; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; @@ -102,8 +101,6 @@ import org.jctools.queues.MpscArrayQueue; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -120,9 +117,7 @@ import java.util.function.UnaryOperator; *

* You can easily create your own implementation of this and use it with {@link ConnectionManager#setPlayerProvider(PlayerProvider)}. */ -public class Player extends LivingEntity implements CommandSender, Localizable, HoverEventSource, Identified, NamedAndIdentified { - private static final Logger logger = LoggerFactory.getLogger(Player.class); - +public class Player extends LivingEntity implements CommandSender, HoverEventSource, Identified, NamedAndIdentified { private static final DynamicRegistry DIMENSION_TYPE_REGISTRY = MinecraftServer.getDimensionTypeRegistry(); private static final Component REMOVE_MESSAGE = Component.text("You have been removed from the server without reason.", NamedTextColor.RED); @@ -177,7 +172,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, private final MpscArrayQueue packets = new MpscArrayQueue<>(ServerFlag.PLAYER_PACKET_QUEUE_SIZE); private final boolean levelFlat; - private final PlayerSettings settings; + private ClientSettings settings = ClientSettings.DEFAULT; private float exp; private int level; private int portalCooldown = 0; @@ -245,7 +240,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable, setRespawnPoint(Pos.ZERO); - this.settings = new PlayerSettings(); this.inventory = new PlayerInventory(this); setCanPickupItem(true); // By default @@ -536,10 +530,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, Pos respawnPosition = respawnEvent.getRespawnPosition(); // The client unloads chunks when respawning, so resend all chunks next to spawn - ChunkUtils.forChunksInRange(respawnPosition, settings.getEffectiveViewDistance(), chunkAdder); + ChunkUtils.forChunksInRange(respawnPosition, settings.effectiveViewDistance(), chunkAdder); chunksLoadedByClient = new Vec(respawnPosition.chunkX(), respawnPosition.chunkZ()); // Client also needs all entities resent to them, since those are unloaded as well - this.instance.getEntityTracker().nearbyEntitiesByChunkRange(respawnPosition, settings.getEffectiveViewDistance(), + this.instance.getEntityTracker().nearbyEntitiesByChunkRange(respawnPosition, settings.effectiveViewDistance(), EntityTracker.Target.ENTITIES, entity -> { // Skip refreshing self with a new viewer if (!entity.getUuid().equals(getUuid()) && entity.isViewer(this)) { @@ -602,7 +596,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, final int chunkX = position.chunkX(); final int chunkZ = position.chunkZ(); // Clear all viewable chunks - ChunkUtils.forChunksInRange(chunkX, chunkZ, settings.getEffectiveViewDistance(), chunkRemover); + ChunkUtils.forChunksInRange(chunkX, chunkZ, settings.effectiveViewDistance(), chunkRemover); // Remove from the tab-list PacketSendingUtils.broadcastPlayPacket(getRemovePlayerToList()); @@ -650,7 +644,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Ensure that surrounding chunks are loaded List> futures = new ArrayList<>(); - ChunkUtils.forChunksInRange(spawnPosition, settings.getEffectiveViewDistance(), (chunkX, chunkZ) -> { + ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), (chunkX, chunkZ) -> { final CompletableFuture future = instance.loadOptionalChunk(chunkX, chunkZ); if (!future.isDone()) futures.add(future); }); @@ -723,7 +717,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, if (!firstSpawn && !dimensionChange) { // Player instance changed, clear current viewable collections if (updateChunks) - ChunkUtils.forChunksInRange(spawnPosition, settings.getEffectiveViewDistance(), chunkRemover); + ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkRemover); } if (dimensionChange) sendDimension(instance.getDimensionType(), instance.getDimensionName()); @@ -738,7 +732,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, sendPacket(new UpdateViewPositionPacket(chunkX, chunkZ)); // Load the nearby chunks and queue them to be sent to them - ChunkUtils.forChunksInRange(spawnPosition, settings.getEffectiveViewDistance(), chunkAdder); + ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkAdder); sendPendingChunks(); // Send available first chunk immediately to prevent falling through the floor } @@ -1550,10 +1544,25 @@ public class Player extends LivingEntity implements CommandSender, Localizable, * * @return the player settings */ - public @NotNull PlayerSettings getSettings() { + public @NotNull ClientSettings getSettings() { return settings; } + /** + * Changes the player settings internally. + *

+ * WARNING: the player will not be noticed by this change, probably unsafe. + */ + public void refreshSettings(ClientSettings settings) { + this.settings = settings; + boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY; + PlayerMeta playerMeta = getPlayerMeta(); + if (isInPlayState) playerMeta.setNotifyAboutChanges(false); + playerMeta.setDisplayedSkinParts(settings.displayedSkinParts()); + playerMeta.setRightMainHand(settings.mainHand() == ClientSettings.MainHand.RIGHT); + if (isInPlayState) playerMeta.setNotifyAboutChanges(true); + } + /** * Gets the player dimension. * @@ -2288,28 +2297,28 @@ public class Player extends LivingEntity implements CommandSender, Localizable, inventory.setEquipment(slot, itemStack); } - @Override - public Locale getLocale() { - final String locale = settings.locale; - if (locale == null) return null; - return Locale.forLanguageTag(locale.replace("_", "-")); - } - @Override public @NotNull PlayerSnapshot updateSnapshot(@NotNull SnapshotUpdater updater) { final EntitySnapshot snapshot = super.updateSnapshot(updater); return new SnapshotImpl.Player(snapshot, username, gameMode); } + public Locale getLocale() { + return settings.locale(); + } + /** * Sets the player's locale. This will only set the locale of the player as it * is stored in the server. This will also be reset if the settings are refreshed. * * @param locale the new locale */ - @Override - public void setLocale(@Nullable Locale locale) { - settings.locale = locale == null ? null : locale.toLanguageTag(); + public void setLocale(@NotNull Locale locale) { + final ClientSettings settings = this.settings; + refreshSettings(new ClientSettings( + locale, settings.viewDistance(), settings.chatMessageType(), settings.chatColors(), + settings.displayedSkinParts(), settings.mainHand(), settings.enableTextFiltering(), settings.allowServerListings() + )); } @Override @@ -2345,7 +2354,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, final Vec old = chunksLoadedByClient; sendPacket(new UpdateViewPositionPacket(newX, newZ)); ChunkUtils.forDifferingChunksInRange(newX, newZ, (int) old.x(), (int) old.z(), - settings.getEffectiveViewDistance(), chunkAdder, chunkRemover); + settings.effectiveViewDistance(), chunkAdder, chunkRemover); this.chunksLoadedByClient = new Vec(newX, newZ); } } @@ -2376,146 +2385,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Settings enum - /** - * Represents where is located the main hand of the player (can be changed in Minecraft option). - */ - public enum MainHand { - LEFT, - RIGHT - } - - public class PlayerSettings { - - private String locale; - private byte viewDistance; - private ChatMessageType chatMessageType; - private boolean chatColors; - private byte displayedSkinParts; - private MainHand mainHand; - private boolean enableTextFiltering; - private boolean allowServerListings; - - public PlayerSettings() { - viewDistance = (byte) ServerFlag.CHUNK_VIEW_DISTANCE; - } - - /** - * The player game language. - * - * @return the player locale - */ - public String getLocale() { - return locale; - } - - /** - * Gets the player view distance. - * - * @return the player view distance - */ - public byte getViewDistance() { - return viewDistance; - } - - public int getEffectiveViewDistance() { - return Math.min(getViewDistance(), ServerFlag.CHUNK_VIEW_DISTANCE); - } - - /** - * Gets the messages this player wants to receive. - * - * @return the messages - */ - public @Nullable ChatMessageType getChatMessageType() { - return chatMessageType; - } - - /** - * Gets if the player has chat colors enabled. - * - * @return true if chat colors are enabled, false otherwise - */ - public boolean hasChatColors() { - return chatColors; - } - - public byte getDisplayedSkinParts() { - return displayedSkinParts; - } - - /** - * Gets the player main hand. - * - * @return the player main hand - */ - public MainHand getMainHand() { - return mainHand; - } - - public boolean enableTextFiltering() { - return enableTextFiltering; - } - - public boolean allowServerListings() { - return allowServerListings; - } - - /** - * Changes the player settings internally. - *

- * WARNING: the player will not be noticed by this change, probably unsafe. - * - * @param locale the player locale - * @param viewDistance the player view distance - * @param chatMessageType the chat messages the player wishes to receive - * @param chatColors if chat colors should be displayed - * @param displayedSkinParts the player displayed skin parts - * @param mainHand the player main hand - */ - public void refresh(String locale, byte viewDistance, ChatMessageType chatMessageType, boolean chatColors, - byte displayedSkinParts, MainHand mainHand, boolean enableTextFiltering, boolean allowServerListings) { - this.locale = locale; - // Clamp viewDistance to valid bounds - byte previousViewDistance = this.viewDistance; - this.viewDistance = (byte) MathUtils.clamp(viewDistance, 2, 32); - this.chatMessageType = chatMessageType; - this.chatColors = chatColors; - this.displayedSkinParts = displayedSkinParts; - this.mainHand = mainHand; - this.enableTextFiltering = enableTextFiltering; - this.allowServerListings = allowServerListings; - - // Check to see if we're in an instance first, as this method is called when first logging in since the client sends the Settings packet during configuration - if (instance != null) { - // Load/unload chunks if necessary due to view distance changes - if (previousViewDistance < this.viewDistance) { - // View distance expanded, send chunks - ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), this.viewDistance, (chunkX, chunkZ) -> { - if (Math.abs(chunkX - position.chunkX()) > previousViewDistance || Math.abs(chunkZ - position.chunkZ()) > previousViewDistance) { - chunkAdder.accept(chunkX, chunkZ); - } - }); - } else if (previousViewDistance > this.viewDistance) { - // View distance shrunk, unload chunks - ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), previousViewDistance, (chunkX, chunkZ) -> { - if (Math.abs(chunkX - position.chunkX()) > this.viewDistance || Math.abs(chunkZ - position.chunkZ()) > this.viewDistance) { - chunkRemover.accept(chunkX, chunkZ); - } - }); - } - // Else previous and current are equal, do nothing - } - - boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY; - PlayerMeta playerMeta = getPlayerMeta(); - if (isInPlayState) playerMeta.setNotifyAboutChanges(false); - playerMeta.setDisplayedSkinParts(displayedSkinParts); - playerMeta.setRightMainHand(this.mainHand == MainHand.RIGHT); - if (isInPlayState) playerMeta.setNotifyAboutChanges(true); - } - - } - private int compareChunkDistance(long chunkIndexA, long chunkIndexB) { int chunkAX = ChunkUtils.getChunkCoordX(chunkIndexA); int chunkAZ = ChunkUtils.getChunkCoordZ(chunkIndexA); diff --git a/src/main/java/net/minestom/server/listener/common/SettingsListener.java b/src/main/java/net/minestom/server/listener/common/SettingsListener.java index 8d25bfe1d..e3f6fa94b 100644 --- a/src/main/java/net/minestom/server/listener/common/SettingsListener.java +++ b/src/main/java/net/minestom/server/listener/common/SettingsListener.java @@ -7,9 +7,8 @@ import net.minestom.server.network.packet.client.common.ClientSettingsPacket; public final class SettingsListener { public static void listener(ClientSettingsPacket packet, Player player) { - Player.PlayerSettings settings = player.getSettings(); // Since viewDistance bounds checking is performed in the refresh function, it is not necessary to check it here - settings.refresh(packet.locale(), packet.viewDistance(), packet.chatMessageType(), packet.chatColors(), packet.displayedSkinParts(), packet.mainHand(), packet.enableTextFiltering(), packet.allowsListing()); + player.refreshSettings(packet.settings()); EventDispatcher.call(new PlayerSettingsChangeEvent(player)); } } diff --git a/src/main/java/net/minestom/server/message/Messenger.java b/src/main/java/net/minestom/server/message/Messenger.java index 50d779f75..954953416 100644 --- a/src/main/java/net/minestom/server/message/Messenger.java +++ b/src/main/java/net/minestom/server/message/Messenger.java @@ -90,6 +90,6 @@ public final class Messenger { * @return the chat message type */ private static @NotNull ChatMessageType getChatMessageType(@NotNull Player player) { - return Objects.requireNonNullElse(player.getSettings().getChatMessageType(), ChatMessageType.FULL); + return Objects.requireNonNullElse(player.getSettings().chatMessageType(), ChatMessageType.FULL); } } diff --git a/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java b/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java index 0cb96bdaf..67d31d97c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/common/ClientSettingsPacket.java @@ -1,31 +1,13 @@ package net.minestom.server.network.packet.client.common; -import net.minestom.server.entity.Player; -import net.minestom.server.message.ChatMessageType; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.network.player.ClientSettings; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.*; - -public record ClientSettingsPacket(@NotNull String locale, byte viewDistance, - @NotNull ChatMessageType chatMessageType, boolean chatColors, - byte displayedSkinParts, @NotNull Player.MainHand mainHand, - boolean enableTextFiltering, boolean allowsListing) implements ClientPacket { +public record ClientSettingsPacket(@NotNull ClientSettings settings) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - STRING, ClientSettingsPacket::locale, - BYTE, ClientSettingsPacket::viewDistance, - Enum(ChatMessageType.class), ClientSettingsPacket::chatMessageType, - BOOLEAN, ClientSettingsPacket::chatColors, - BYTE, ClientSettingsPacket::displayedSkinParts, - Enum(Player.MainHand.class), ClientSettingsPacket::mainHand, - BOOLEAN, ClientSettingsPacket::enableTextFiltering, - BOOLEAN, ClientSettingsPacket::allowsListing, + ClientSettings.NETWORK_TYPE, ClientSettingsPacket::settings, ClientSettingsPacket::new); - - public ClientSettingsPacket { - if (locale.length() > 128) - throw new IllegalArgumentException("Locale cannot be longer than 128 characters."); - } } diff --git a/src/main/java/net/minestom/server/network/player/ClientSettings.java b/src/main/java/net/minestom/server/network/player/ClientSettings.java new file mode 100644 index 000000000..e65137da1 --- /dev/null +++ b/src/main/java/net/minestom/server/network/player/ClientSettings.java @@ -0,0 +1,63 @@ +package net.minestom.server.network.player; + +import net.minestom.server.ServerFlag; +import net.minestom.server.message.ChatMessageType; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.MathUtils; + +import java.util.Locale; +import java.util.Objects; + +import static net.minestom.server.network.NetworkBuffer.*; + +public record ClientSettings(Locale locale, byte viewDistance, + ChatMessageType chatMessageType, boolean chatColors, + byte displayedSkinParts, MainHand mainHand, + boolean enableTextFiltering, boolean allowServerListings) { + public static ClientSettings DEFAULT = new ClientSettings( + Locale.US, (byte) ServerFlag.CHUNK_VIEW_DISTANCE, + ChatMessageType.FULL, true, + (byte) 0x7F, MainHand.RIGHT, + true, true + ); + + private static final NetworkBuffer.Type LOCALE_SERIALIZER = STRING.transform( + s -> { + final String locale = s.replace("_", "-"); + return Locale.forLanguageTag(locale); + }, + Locale::toLanguageTag + ); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + LOCALE_SERIALIZER, ClientSettings::locale, + BYTE, ClientSettings::viewDistance, + Enum(ChatMessageType.class), ClientSettings::chatMessageType, + BOOLEAN, ClientSettings::chatColors, + BYTE, ClientSettings::displayedSkinParts, + Enum(MainHand.class), ClientSettings::mainHand, + BOOLEAN, ClientSettings::enableTextFiltering, + BOOLEAN, ClientSettings::allowServerListings, + ClientSettings::new); + + public ClientSettings { + Objects.requireNonNull(locale); + // Clamp viewDistance to valid bounds + viewDistance = (byte) MathUtils.clamp(viewDistance, 2, 32); + Objects.requireNonNull(chatMessageType); + Objects.requireNonNull(mainHand); + } + + public int effectiveViewDistance() { + return Math.min(viewDistance(), ServerFlag.CHUNK_VIEW_DISTANCE); + } + + /** + * Represents where is located the main hand of the player (can be changed in Minecraft option). + */ + public enum MainHand { + LEFT, + RIGHT + } +} diff --git a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java index 98b914f82..19667ea4e 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java @@ -11,6 +11,7 @@ import net.minestom.server.message.ChatMessageType; import net.minestom.server.network.packet.client.common.ClientSettingsPacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.play.*; +import net.minestom.server.network.player.ClientSettings; import net.minestom.server.utils.NamespaceID; import net.minestom.server.world.DimensionType; import net.minestom.testing.Collector; @@ -22,6 +23,7 @@ import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import static org.junit.jupiter.api.Assertions.*; @@ -75,8 +77,12 @@ public class PlayerIntegrationTest { @Test public void handSwapTest(Env env) { - ClientSettingsPacket packet = new ClientSettingsPacket("en_us", (byte) 16, ChatMessageType.FULL, - true, (byte) 127, Player.MainHand.LEFT, true, true); + ClientSettingsPacket packet = new ClientSettingsPacket(new ClientSettings( + Locale.US, (byte) 16, + ChatMessageType.FULL, true, + (byte) 127, ClientSettings.MainHand.LEFT, + true, true + )); var instance = env.createFlatInstance(); var connection = env.createConnection(); @@ -89,7 +95,7 @@ public class PlayerIntegrationTest { var collector = connection.trackIncoming(); env.tick(); env.tick(); - assertEquals(Player.MainHand.LEFT, player.getSettings().getMainHand()); + assertEquals(ClientSettings.MainHand.LEFT, player.getSettings().mainHand()); boolean found = false; for (ServerPacket serverPacket : collector.collect()) { @@ -208,7 +214,7 @@ public class PlayerIntegrationTest { connection2.connect(instance, new Pos(0, 42, 0)).join(); var displayNamePackets = tracker2.collect().stream().filter((packet) -> - packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) + packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) .count(); assertEquals(1, displayNamePackets); @@ -217,12 +223,12 @@ public class PlayerIntegrationTest { player.setDisplayName(Component.text("Other Name!")); var displayNamePackets2 = tracker3.collect().stream().filter((packet) -> - packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) + packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) .count(); assertEquals(1, displayNamePackets2); var displayNamePackets3 = tracker.collect().stream().filter((packet) -> - packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) + packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) .count(); assertEquals(2, displayNamePackets3); } diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index 713d64148..824c02e02 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -1,6 +1,5 @@ package net.minestom.server.entity.player; -import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -14,6 +13,7 @@ import net.minestom.server.network.packet.client.play.ClientTeleportConfirmPacke import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.EntityPositionPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket; +import net.minestom.server.network.player.ClientSettings; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.testing.Collector; @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -73,7 +74,7 @@ public class PlayerMovementIntegrationTest { final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; // Preload all possible chunks to avoid issues due to async loading Set> chunks = new HashSet<>(); - ChunkUtils.forChunksInRange(0, 0, viewDiameter+2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + ChunkUtils.forChunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); final TestConnection connection = env.createConnection(); Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); @@ -129,9 +130,14 @@ public class PlayerMovementIntegrationTest { Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)).join(); // Preload all possible chunks to avoid issues due to async loading Set> chunks = new HashSet<>(); - ChunkUtils.forChunksInRange(10, 10, viewDistance+2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + ChunkUtils.forChunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); - player.getSettings().refresh("en_US", (byte) viewDistance, ChatMessageType.FULL, true, (byte) 0, Player.MainHand.RIGHT, false, true); + player.refreshSettings(new ClientSettings( + Locale.US, (byte) viewDistance, + ChatMessageType.FULL, true, + (byte) 0, ClientSettings.MainHand.RIGHT, + false, true + )); Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java index b870c0ec8..0d0f9686a 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java @@ -1,6 +1,5 @@ package net.minestom.server.entity.player; -import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; @@ -47,7 +46,7 @@ public class PlayerRespawnChunkIntegrationTest { player.setHealth(0); player.respawn(); // Player should have all their chunks reloaded - int chunkLoads = ChunkUtils.getChunkCount(Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().getViewDistance())); + int chunkLoads = ChunkUtils.getChunkCount(Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().viewDistance())); loadChunkTracker.assertCount(chunkLoads); } @@ -63,7 +62,7 @@ public class PlayerRespawnChunkIntegrationTest { player.interpretPacketQueue(); List dataPacketList = loadChunkTracker.collect(); Set duplicateCheck = new HashSet<>(); - int actualViewDistance = Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().getViewDistance()); + int actualViewDistance = Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().viewDistance()); int chunkLoads = ChunkUtils.getChunkCount(actualViewDistance); loadChunkTracker.assertCount(chunkLoads); for (ChunkDataPacket packet : dataPacketList) { From a1048133d1de753c7088a08481816cad73a7f5ca Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 4 Sep 2024 01:49:35 +0200 Subject: [PATCH 18/97] GameMode hardcoded abilities (#2366) --- .../net/minestom/server/entity/GameMode.java | 51 ++++++++++--------- .../net/minestom/server/entity/Player.java | 37 ++++---------- .../minestom/server/entity/GameModeTest.java | 16 ++---- 3 files changed, 41 insertions(+), 63 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/GameMode.java b/src/main/java/net/minestom/server/entity/GameMode.java index c72cd4a55..83d473dd4 100644 --- a/src/main/java/net/minestom/server/entity/GameMode.java +++ b/src/main/java/net/minestom/server/entity/GameMode.java @@ -11,49 +11,50 @@ import static net.minestom.server.network.NetworkBuffer.BYTE; * Can be set with {@link Player#setGameMode(GameMode)}. */ public enum GameMode { - SURVIVAL((byte) 0, true), - CREATIVE((byte) 1, false), - ADVENTURE((byte) 2, true), - SPECTATOR((byte) 3, false); + SURVIVAL(false, false, false), + CREATIVE(true, true, true), + ADVENTURE(false, false, false), + SPECTATOR(true, true, false); - private final byte id; - private final boolean canTakeDamage; + private final boolean allowFlying; + private final boolean invulnerable; + private final boolean instantBreak; - GameMode(byte id, boolean canTakeDamage) { - this.id = id; - this.canTakeDamage = canTakeDamage; + GameMode(boolean allowFlying, boolean invulnerable, boolean instantBreak) { + this.allowFlying = allowFlying; + this.invulnerable = invulnerable; + this.instantBreak = instantBreak; } - public byte id() { - return id; + public boolean allowFlying() { + return allowFlying; } public boolean canTakeDamage() { - return canTakeDamage; + return invulnerable; } - public static final NetworkBuffer.Type NETWORK_TYPE = BYTE.transform(GameMode::fromId, gameMode -> gameMode.id); + public boolean instantBreak() { + return instantBreak; + } + + private static final GameMode[] VALUES = values(); + + public static final NetworkBuffer.Type NETWORK_TYPE = BYTE.transform( + id -> VALUES[id], + gameMode -> (byte) gameMode.ordinal() + ); public static final NetworkBuffer.Type OPT_NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, GameMode value) { - buffer.write(BYTE, value != null ? value.id() : -1); + buffer.write(BYTE, value != null ? (byte) value.ordinal() : -1); } @Override public GameMode read(@NotNull NetworkBuffer buffer) { final byte id = buffer.read(BYTE); - return id != -1 ? GameMode.fromId(id) : null; + return id != -1 ? VALUES[id] : null; } }; - - public static @NotNull GameMode fromId(int id) { - return switch (id) { - case 0 -> SURVIVAL; - case 1 -> CREATIVE; - case 2 -> ADVENTURE; - case 3 -> SPECTATOR; - default -> throw new IllegalArgumentException("Unknown game mode id: " + id); - }; - } } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 2bd770cea..622d499c4 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1614,36 +1614,21 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou this.gameMode = gameMode; // Condition to prevent sending the packets before spawning the player if (isActive()) { - sendPacket(new ChangeGameStatePacket(ChangeGameStatePacket.Reason.CHANGE_GAMEMODE, gameMode.id())); + sendPacket(new ChangeGameStatePacket(ChangeGameStatePacket.Reason.CHANGE_GAMEMODE, gameMode.ordinal())); PacketSendingUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, infoEntry())); } // The client updates their abilities based on the GameMode as follows - switch (gameMode) { - case CREATIVE -> { - this.allowFlying = true; - this.instantBreak = true; - this.invulnerable = true; - } - case SPECTATOR -> { - this.allowFlying = true; - this.instantBreak = false; - this.invulnerable = true; - if (isActive()) { - refreshFlying(true); - } else { - this.flying = true; - } - } - default -> { - this.allowFlying = false; - this.instantBreak = false; - this.invulnerable = false; - if (isActive()) { - refreshFlying(false); - } else { - this.flying = false; - } + this.allowFlying = gameMode.allowFlying(); + this.instantBreak = gameMode.instantBreak(); + this.invulnerable = gameMode.canTakeDamage(); + // Spectator automatically enables flying + // If new game mode cannot fly, disable it + if (gameMode == GameMode.SPECTATOR || !gameMode.allowFlying()) { + if (isActive()) { + refreshFlying(gameMode.allowFlying()); + } else { + this.flying = gameMode.allowFlying(); } } // Make sure that the player is in the PLAY state and synchronize their flight speed. diff --git a/src/test/java/net/minestom/server/entity/GameModeTest.java b/src/test/java/net/minestom/server/entity/GameModeTest.java index 2d7ea85dd..8e11426c9 100644 --- a/src/test/java/net/minestom/server/entity/GameModeTest.java +++ b/src/test/java/net/minestom/server/entity/GameModeTest.java @@ -8,17 +8,9 @@ public class GameModeTest { @Test public void toId() { - assertEquals(GameMode.SURVIVAL.id(), 0); - assertEquals(GameMode.CREATIVE.id(), 1); - assertEquals(GameMode.ADVENTURE.id(), 2); - assertEquals(GameMode.SPECTATOR.id(), 3); - } - - @Test - public void fromId() { - assertEquals(GameMode.SURVIVAL, GameMode.fromId(0)); - assertEquals(GameMode.CREATIVE, GameMode.fromId(1)); - assertEquals(GameMode.ADVENTURE, GameMode.fromId(2)); - assertEquals(GameMode.SPECTATOR, GameMode.fromId(3)); + assertEquals(GameMode.SURVIVAL.ordinal(), 0); + assertEquals(GameMode.CREATIVE.ordinal(), 1); + assertEquals(GameMode.ADVENTURE.ordinal(), 2); + assertEquals(GameMode.SPECTATOR.ordinal(), 3); } } From 1913b0acf07e69705ca2769e2f0881615c82b9d0 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 5 Sep 2024 01:44:40 +0200 Subject: [PATCH 19/97] Remove caffeine from viewable packets --- .../server/utils/PacketViewableUtils.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/minestom/server/utils/PacketViewableUtils.java b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java index b7156422b..bfd9529c9 100644 --- a/src/main/java/net/minestom/server/utils/PacketViewableUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketViewableUtils.java @@ -1,7 +1,5 @@ package net.minestom.server.utils; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -22,12 +20,14 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; import java.util.Objects; +import java.util.WeakHashMap; @ApiStatus.Internal public final class PacketViewableUtils { // Viewable packets - private static final Cache VIEWABLE_STORAGE_MAP = Caffeine.newBuilder().weakKeys().build(); + private static volatile Map storageMap = new WeakHashMap<>(); public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket, @Nullable Entity entity) { @@ -41,15 +41,33 @@ public final class PacketViewableUtils { return; } final Player exception = entity instanceof Player ? (Player) entity : null; - ViewableStorage storage = VIEWABLE_STORAGE_MAP.get(viewable, (unused) -> new ViewableStorage()); + ViewableStorage storage = retrieveStorage(viewable); storage.append(serverPacket, exception); } - public static void flush() { - if (ServerFlag.VIEWABLE_PACKET) { - VIEWABLE_STORAGE_MAP.asMap().entrySet().parallelStream().forEach(entry -> - entry.getValue().process(entry.getKey())); + private static ViewableStorage retrieveStorage(Viewable viewable) { + Map map = storageMap; + ViewableStorage storage = map.get(viewable); + if (storage == null) { + synchronized (PacketViewableUtils.class) { + map = storageMap; + storage = map.get(viewable); + if (storage == null) { + storage = new ViewableStorage(); + map = new WeakHashMap<>(map); + map.put(viewable, storage); + storageMap = map; + } + } } + return storage; + } + + public static void flush() { + if (!ServerFlag.VIEWABLE_PACKET) return; + Map map = storageMap; + map.entrySet().parallelStream().forEach(entry -> + entry.getValue().process(entry.getKey())); } public static void prepareViewablePacket(@NotNull Viewable viewable, @NotNull ServerPacket serverPacket) { From 30d86e113494736904e6aee83e02d56591e07074 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 5 Sep 2024 05:37:46 +0200 Subject: [PATCH 20/97] Remove buffer slice --- .../server/network/NetworkBuffer.java | 2 -- .../server/network/NetworkBufferImpl.java | 25 ++++--------------- .../server/network/packet/PacketReading.java | 8 +++--- .../server/network/NetworkBufferTest.java | 1 - 4 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index 58ed37ab9..aef48eb15 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -147,8 +147,6 @@ public sealed interface NetworkBuffer permits NetworkBufferImpl { void compact(); - NetworkBuffer slice(long index, long length, long readIndex, long writeIndex); - NetworkBuffer copy(long index, long length, long readIndex, long writeIndex); default NetworkBuffer copy(long index, long length) { diff --git a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java index 2d33913ff..e5b2eec9b 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferImpl.java @@ -30,7 +30,6 @@ final class NetworkBufferImpl implements NetworkBuffer { private static final Cleaner CLEANER = Cleaner.create(); private static final long DUMMY_ADDRESS = -1; - private final NetworkBufferImpl parent; // Used for slices so we can control GC over the parent buffer private final BufferCleaner state; // Address may be -1 if the buffer is a dummy buffer // Dummy buffers are used for size calculations and do not have memory allocated @@ -46,12 +45,10 @@ final class NetworkBufferImpl implements NetworkBuffer { ByteBuffer nioBuffer = null; - NetworkBufferImpl(NetworkBufferImpl parent, - long address, long capacity, + NetworkBufferImpl(long address, long capacity, long readIndex, long writeIndex, @Nullable AutoResize autoResize, @Nullable Registries registries) { - this.parent = parent; this.address = address; this.capacity = capacity; this.readIndex = readIndex; @@ -60,7 +57,7 @@ final class NetworkBufferImpl implements NetworkBuffer { this.registries = registries; this.state = new BufferCleaner(new AtomicLong(address)); - if (this.parent == null && address != DUMMY_ADDRESS) CLEANER.register(this, state); + if (address != DUMMY_ADDRESS) CLEANER.register(this, state); } private record BufferCleaner(AtomicLong address) implements Runnable { @@ -238,18 +235,6 @@ final class NetworkBufferImpl implements NetworkBuffer { readIndex = 0; } - @Override - public NetworkBuffer slice(long index, long length, long readIndex, long writeIndex) { - assertDummy(); - Objects.checkFromIndexSize(index, length, capacity); - NetworkBufferImpl slice = new NetworkBufferImpl(this, - address + index, length, - readIndex, writeIndex, - autoResize, registries); - slice.readOnly = readOnly; - return slice; - } - @Override public NetworkBuffer copy(long index, long length, long readIndex, long writeIndex) { assertDummy(); @@ -259,7 +244,7 @@ final class NetworkBufferImpl implements NetworkBuffer { throw new OutOfMemoryError("Failed to allocate memory"); } UNSAFE.copyMemory(address + index, newAddress, length); - return new NetworkBufferImpl(null, + return new NetworkBufferImpl( newAddress, length, readIndex, writeIndex, autoResize, registries); @@ -550,7 +535,7 @@ final class NetworkBufferImpl implements NetworkBuffer { @Override public @NotNull NetworkBuffer build() { final long address = UNSAFE.allocateMemory(initialSize); - return new NetworkBufferImpl(null, + return new NetworkBufferImpl( address, initialSize, 0, 0, autoResize, registries); @@ -560,7 +545,7 @@ final class NetworkBufferImpl implements NetworkBuffer { static NetworkBufferImpl dummy(Registries registries) { // Dummy buffer with no memory allocated // Useful for size calculations - return new NetworkBufferImpl(null, + return new NetworkBufferImpl( DUMMY_ADDRESS, Long.MAX_VALUE, 0, 0, null, registries); diff --git a/src/main/java/net/minestom/server/network/packet/PacketReading.java b/src/main/java/net/minestom/server/network/packet/PacketReading.java index 0cf32f889..a032f961b 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketReading.java +++ b/src/main/java/net/minestom/server/network/packet/PacketReading.java @@ -165,11 +165,13 @@ public final class PacketReading { if (requiredCapacity > buffer.capacity()) return new Result.Failure<>(requiredCapacity); else return EMPTY_CLIENT_PACKET; } - NetworkBuffer content = buffer.slice(buffer.readIndex(), packetLength, 0, packetLength); + final long readerEnd = readerStart + packetLength; + final long writerEnd = buffer.writeIndex(); + buffer.writeIndex(readerEnd); final PacketRegistry registry = parser.stateRegistry(state); - final T packet = readFramedPacket(content, registry, compressed); + final T packet = readFramedPacket(buffer, registry, compressed); final ConnectionState nextState = stateUpdater.apply(packet, state); - buffer.readIndex(readerStart + packetLength); + buffer.index(readerEnd, writerEnd); return new Result.Success<>(packet, nextState); } diff --git a/src/test/java/net/minestom/server/network/NetworkBufferTest.java b/src/test/java/net/minestom/server/network/NetworkBufferTest.java index 65bac2f5e..8d782630e 100644 --- a/src/test/java/net/minestom/server/network/NetworkBufferTest.java +++ b/src/test/java/net/minestom/server/network/NetworkBufferTest.java @@ -273,7 +273,6 @@ public class NetworkBufferTest { assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.read(INT)).sizeOf(1)); assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.readAt(0, INT)).sizeOf(1)); assertThrows(UnsupportedOperationException.class, () -> fn.apply(NetworkBuffer::compact).sizeOf(1)); - assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.slice(0, 0, 0, 0)).sizeOf(1)); assertThrows(UnsupportedOperationException.class, () -> fn.apply(buffer -> buffer.copy(0, 0, 0, 0)).sizeOf(1)); } From d04b11eebdd92dc94ac101717a532be3520a8644 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 7 Sep 2024 09:15:35 +0200 Subject: [PATCH 21/97] Additional merging fixes --- .../net/minestom/server/entity/Player.java | 24 +++++++++++++++++++ .../player/PlayerMovementIntegrationTest.java | 8 +++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 622d499c4..9d680122a 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1554,6 +1554,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou * WARNING: the player will not be noticed by this change, probably unsafe. */ public void refreshSettings(ClientSettings settings) { + final ClientSettings previous = this.settings; this.settings = settings; boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY; PlayerMeta playerMeta = getPlayerMeta(); @@ -1561,6 +1562,29 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou playerMeta.setDisplayedSkinParts(settings.displayedSkinParts()); playerMeta.setRightMainHand(settings.mainHand() == ClientSettings.MainHand.RIGHT); if (isInPlayState) playerMeta.setNotifyAboutChanges(true); + + final byte previousViewDistance = previous.viewDistance(); + final byte newViewDistance = settings.viewDistance(); + // Check to see if we're in an instance first, as this method is called when first logging in since the client sends the Settings packet during configuration + if (instance != null) { + // Load/unload chunks if necessary due to view distance changes + if (previousViewDistance < newViewDistance) { + // View distance expanded, send chunks + ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), newViewDistance, (chunkX, chunkZ) -> { + if (Math.abs(chunkX - position.chunkX()) > previousViewDistance || Math.abs(chunkZ - position.chunkZ()) > previousViewDistance) { + chunkAdder.accept(chunkX, chunkZ); + } + }); + } else if (previousViewDistance > newViewDistance) { + // View distance shrunk, unload chunks + ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), previousViewDistance, (chunkX, chunkZ) -> { + if (Math.abs(chunkX - position.chunkX()) > newViewDistance || Math.abs(chunkZ - position.chunkZ()) > newViewDistance) { + chunkRemover.accept(chunkX, chunkZ); + } + }); + } + // Else previous and current are equal, do nothing + } } /** diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index 824c02e02..f1fe2660f 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -23,8 +23,6 @@ import net.minestom.testing.TestConnection; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; -import java.time.Duration; -import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Locale; import java.util.Set; @@ -164,12 +162,14 @@ public class PlayerMovementIntegrationTest { ChunkUtils.forChunksInRange(0, 0, endViewDistance, instance::loadChunk); var tracker = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientSettingsPacket("en_US", endViewDistance, ChatMessageType.FULL, false, (byte) 0, Player.MainHand.RIGHT, false, true)); + player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, + ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); player.interpretPacketQueue(); tracker.assertCount(chunkDifference); var tracker1 = connection.trackIncoming(UnloadChunkPacket.class); - player.addPacketToQueue(new ClientSettingsPacket("en_US", finalViewDistance, ChatMessageType.FULL, false, (byte) 0, Player.MainHand.RIGHT, false, true)); + player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, finalViewDistance, + ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); player.interpretPacketQueue(); int chunkDifference1 = ChunkUtils.getChunkCount(endViewDistance) - ChunkUtils.getChunkCount(finalViewDistance); From ba407a8a37e11712b7c31514ff0e48b87f0b2d3b Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 7 Sep 2024 09:18:14 +0200 Subject: [PATCH 22/97] Remove Caffeine lib --- build.gradle.kts | 3 +-- gradle/libs.versions.toml | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b9b55a567..0ccb3f70d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -72,7 +72,6 @@ dependencies { implementation(libs.minestomData) // Performance/data structures - implementation(libs.caffeine) api(libs.fastutil) implementation(libs.bundles.flare) api(libs.gson) @@ -116,7 +115,7 @@ tasks { replaceToken("\"&ARTIFACT\"", if (artifact == null) "null" else "\"${artifact}\"", gitFile) } - nexusPublishing{ + nexusPublishing { useStaging.set(true) this.packageGroup.set("net.minestom") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d75cacb1e..43260bdb6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,6 @@ jetbrainsAnnotations = "24.1.0" slf4j = "2.0.7" # Performance / Data Structures -caffeine = "3.1.8" fastutil = "8.5.14" flare = "2.0.1" gson = "2.11.0" @@ -49,7 +48,6 @@ jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version. slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j"} # Performance / Data Structures -caffeine = { group = "com.github.ben-manes.caffeine", name = "caffeine", version.ref = "caffeine" } fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" } flare = { group = "space.vectrix.flare", name = "flare", version.ref = "flare" } flare-fastutil = { group = "space.vectrix.flare", name = "flare-fastutil", version.ref = "flare" } From 5e2c1de0a5fb379c1c02b347f354f5ecd1bf5329 Mon Sep 17 00:00:00 2001 From: mudkip Date: Mon, 9 Sep 2024 02:49:22 -0600 Subject: [PATCH 23/97] fix javadoc (#2391) --- .../java/net/minestom/server/network/packet/PacketParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/network/packet/PacketParser.java b/src/main/java/net/minestom/server/network/packet/PacketParser.java index b8c4d2e1e..bf4bc8b3a 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketParser.java +++ b/src/main/java/net/minestom/server/network/packet/PacketParser.java @@ -7,7 +7,7 @@ import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; /** - * Responsible for parsing client & server packets. + * Responsible for parsing client and server packets. *

* You can retrieve the different packets per state (status/login/play) * from the {@link PacketRegistry} classes. From 53e4e8d646f3d590f8b4f0f0e373f159eba6abf8 Mon Sep 17 00:00:00 2001 From: Kerman <46640204+KermanIsPretty@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:09:18 -0500 Subject: [PATCH 24/97] Rework LoginListener (#2384) * Move kick to PlayerConnection * Redo Mojang LoginListener - Move away from HTTPClient and use MojangUtils - Add feature to prevent proxy connections * Kick before handling exception. * Update to throw IOException back to the login listener. * Use PlayerConnection#kick in HandshakeListener Also remove unused import left over in Player --- .../java/net/minestom/server/ServerFlag.java | 1 + .../net/minestom/server/entity/Player.java | 11 +-- .../minestom/server/extras/MojangAuth.java | 2 - .../listener/preplay/HandshakeListener.java | 17 ++-- .../listener/preplay/LoginListener.java | 98 ++++++++----------- .../network/player/PlayerConnection.java | 22 +++++ .../server/utils/mojang/MojangUtils.java | 29 ++++++ 7 files changed, 101 insertions(+), 79 deletions(-) diff --git a/src/main/java/net/minestom/server/ServerFlag.java b/src/main/java/net/minestom/server/ServerFlag.java index 5caed768e..5dcd1dcb2 100644 --- a/src/main/java/net/minestom/server/ServerFlag.java +++ b/src/main/java/net/minestom/server/ServerFlag.java @@ -53,6 +53,7 @@ public final class ServerFlag { // Online Mode public static final @NotNull String AUTH_URL = stringProperty("minestom.auth.url", "https://sessionserver.mojang.com/session/minecraft/hasJoined"); + public static final boolean AUTH_PREVENT_PROXY_CONNECTIONS = booleanProperty("minestom.auth.prevent-proxy-connections", false); // World public static final int WORLD_BORDER_SIZE = intProperty("minestom.world-border-size", 29999984); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 9d680122a..d8c57e365 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -66,7 +66,6 @@ import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.common.*; -import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.data.WorldPos; import net.minestom.server.network.player.ClientSettings; @@ -1686,15 +1685,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou * @param component the reason */ public void kick(@NotNull Component component) { - // Packet type depends on the current player connection state - final ServerPacket disconnectPacket; - if (playerConnection.getConnectionState() == ConnectionState.LOGIN) { - disconnectPacket = new LoginDisconnectPacket(component); - } else { - disconnectPacket = new DisconnectPacket(component); - } - sendPacket(disconnectPacket); - playerConnection.disconnect(); + this.getPlayerConnection().kick(component); } /** diff --git a/src/main/java/net/minestom/server/extras/MojangAuth.java b/src/main/java/net/minestom/server/extras/MojangAuth.java index 92648da72..32c62e97c 100644 --- a/src/main/java/net/minestom/server/extras/MojangAuth.java +++ b/src/main/java/net/minestom/server/extras/MojangAuth.java @@ -1,7 +1,6 @@ package net.minestom.server.extras; import net.minestom.server.MinecraftServer; -import net.minestom.server.ServerFlag; import net.minestom.server.extras.mojangAuth.MojangCrypt; import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.utils.validate.Check; @@ -10,7 +9,6 @@ import org.jetbrains.annotations.Nullable; import java.security.KeyPair; public final class MojangAuth { - public static final String AUTH_URL = ServerFlag.AUTH_URL.concat("?username=%s&serverId=%s"); private static volatile boolean enabled = false; private static volatile KeyPair keyPair; diff --git a/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java b/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java index 06ec2f836..f18d624fe 100644 --- a/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java @@ -10,7 +10,6 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; -import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; @@ -18,6 +17,7 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; @@ -45,7 +45,7 @@ public final class HandshakeListener { connection.setConnectionState(ConnectionState.LOGIN); if (packet.protocolVersion() != MinecraftServer.PROTOCOL_VERSION) { // Incorrect client version - disconnect(connection, INVALID_VERSION_TEXT); + connection.kick(INVALID_VERSION_TEXT); } // Bungee support (IP forwarding) @@ -61,11 +61,11 @@ public final class HandshakeListener { address = split[0]; - final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1], - ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort()); + final SocketAddress socketAddress = new InetSocketAddress(split[1], + ((InetSocketAddress) connection.getRemoteAddress()).getPort()); socketConnection.setRemoteAddress(socketAddress); - UUID playerUuid = java.util.UUID.fromString( + UUID playerUuid = UUID.fromString( split[2] .replaceFirst( "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5" @@ -128,14 +128,9 @@ public final class HandshakeListener { } } - private static void disconnect(@NotNull PlayerConnection connection, @NotNull Component reason) { - connection.sendPacket(new LoginDisconnectPacket(reason)); - connection.disconnect(); - } - private static void bungeeDisconnect(@NotNull PlayerConnection connection) { LOGGER.warn("{} tried to log in without valid BungeeGuard forwarding information.", connection.getIdentifier()); - disconnect(connection, INVALID_BUNGEE_FORWARDING); + connection.kick(INVALID_BUNGEE_FORWARDING); } } diff --git a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java index e0295ba8d..63779de95 100644 --- a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java @@ -1,6 +1,5 @@ package net.minestom.server.listener.preplay; -import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.kyori.adventure.text.Component; @@ -18,22 +17,22 @@ import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPa import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.server.login.EncryptionRequestPacket; -import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; import net.minestom.server.utils.async.AsyncUtils; +import net.minestom.server.utils.mojang.MojangUtils; import org.jetbrains.annotations.NotNull; import javax.crypto.SecretKey; +import java.io.IOException; import java.math.BigInteger; -import java.net.*; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -41,10 +40,13 @@ import static net.minestom.server.network.NetworkBuffer.STRING; public final class LoginListener { private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); - private static final Gson GSON = new Gson(); private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED); private static final Component ERROR_DURING_LOGIN = Component.text("Error during login!", NamedTextColor.RED); + private static final Component ERROR_MALFORMED_USERNAME = Component.text("Error malformed username", NamedTextColor.RED); + private static final Component ENCRYPTION_FAILED = Component.text("Encryption failed!", NamedTextColor.RED); + private static final Component ERROR_MOJANG_RESPONSE = Component.text("Failed to contact Mojang's Session Servers (Are they down?)", NamedTextColor.RED); + public static final Component INVALID_PROXY_RESPONSE = Component.text("Invalid proxy response!", NamedTextColor.RED); public static void loginStartListener(@NotNull ClientLoginStartPacket packet, @NotNull PlayerConnection connection) { @@ -64,8 +66,7 @@ public final class LoginListener { if (MojangAuth.isEnabled() && isSocketConnection) { // Mojang auth if (CONNECTION_MANAGER.getOnlinePlayerByUsername(packet.username()) != null) { - connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED)); - connection.disconnect(); + connection.kick(ALREADY_CONNECTED); return; } final PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection; @@ -87,8 +88,8 @@ public final class LoginListener { CONNECTION_MANAGER.createPlayer(connection, playerUuid, packet.username()); } catch (Exception exception) { - connection.sendPacket(new LoginDisconnectPacket(Component.text(exception.getClass().getSimpleName() + ": " + exception.getMessage()))); - connection.disconnect(); + connection.kick(Component.text(exception.getClass().getSimpleName() + ": " + exception.getMessage())); + MinecraftServer.getExceptionManager().handleException(exception); } }); } @@ -100,7 +101,8 @@ public final class LoginListener { AsyncUtils.runAsync(() -> { final String loginUsername = socketConnection.getLoginUsername(); if (loginUsername == null || loginUsername.isEmpty()) { - // Shouldn't happen + // Shouldn't happen, but in case + connection.kick(ERROR_MALFORMED_USERNAME); return; } @@ -110,6 +112,7 @@ public final class LoginListener { if (verificationFailed) { MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername); + connection.kick(ENCRYPTION_FAILED); return; } @@ -117,52 +120,36 @@ public final class LoginListener { if (digestedData == null) { // Incorrect key, probably because of the client MinecraftServer.LOGGER.error("Connection {} failed initializing encryption.", socketConnection.getRemoteAddress()); - connection.disconnect(); + connection.kick(ENCRYPTION_FAILED); return; } // Query Mojang's session server. final String serverId = new BigInteger(digestedData).toString(16); - final String username = URLEncoder.encode(loginUsername, StandardCharsets.UTF_8); - final String url = String.format(MojangAuth.AUTH_URL, username, serverId); - // TODO: Add ability to add ip query tag. See: https://wiki.vg/Protocol_Encryption#Authentication + try { + final JsonObject gameProfile = MojangUtils.authenticateSession(loginUsername, serverId, socketConnection.getRemoteAddress()); - final HttpClient client = HttpClient.newHttpClient(); - final HttpRequest request = HttpRequest.newBuilder(URI.create(url)).GET().build(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).whenComplete((response, throwable) -> { - final boolean ok = throwable == null && response.statusCode() == 200 && response.body() != null && !response.body().isEmpty(); + // We have verified the session, parse response. + socketConnection.setEncryptionKey(getSecretKey(packet.sharedSecret())); + final UUID profileUUID = UUID.fromString(gameProfile.get("id").getAsString() + .replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + final String profileName = gameProfile.get("name").getAsString(); - if (!ok) { - if (throwable != null) { - MinecraftServer.getExceptionManager().handleException(throwable); - } - - if (socketConnection.getPlayer() != null) { - socketConnection.getPlayer().kick(Component.text("Failed to contact Mojang's Session Servers (Are they down?)")); - } else { - socketConnection.disconnect(); - } - return; + MinecraftServer.LOGGER.info("UUID of player {} is {}", profileName, profileUUID); + CONNECTION_MANAGER.createPlayer(connection, profileUUID, profileName); + List propertyList = new ArrayList<>(); + for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) { + JsonObject object = element.getAsJsonObject(); + propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString())); } - try { - final JsonObject gameProfile = GSON.fromJson(response.body(), JsonObject.class); - socketConnection.setEncryptionKey(getSecretKey(packet.sharedSecret())); - UUID profileUUID = java.util.UUID.fromString(gameProfile.get("id").getAsString() - .replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - final String profileName = gameProfile.get("name").getAsString(); - - MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID); - CONNECTION_MANAGER.createPlayer(connection, profileUUID, profileName); - List propertyList = new ArrayList<>(); - for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) { - JsonObject object = element.getAsJsonObject(); - propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString())); - } - socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList)); - } catch (Exception e) { - MinecraftServer.getExceptionManager().handleException(e); - } - }); + socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList)); + } catch (IOException e) { + socketConnection.kick(ERROR_MOJANG_RESPONSE); + MinecraftServer.getExceptionManager().handleException(e); + } catch (Exception e) { + socketConnection.kick(ERROR_DURING_LOGIN); + MinecraftServer.getExceptionManager().handleException(e); + } }); } @@ -184,6 +171,7 @@ public final class LoginListener { try { address = InetAddress.getByName(buffer.read(STRING)); } catch (UnknownHostException e) { + socketConnection.kick(INVALID_PROXY_RESPONSE); MinecraftServer.getExceptionManager().handleException(e); return; } @@ -198,8 +186,7 @@ public final class LoginListener { socketConnection.UNSAFE_setProfile(gameProfile); CONNECTION_MANAGER.createPlayer(socketConnection, gameProfile.uuid(), gameProfile.name()); } else { - LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(INVALID_PROXY_RESPONSE); - socketConnection.sendPacket(disconnectPacket); + socketConnection.kick(INVALID_PROXY_RESPONSE); } } @@ -208,10 +195,9 @@ public final class LoginListener { LoginPluginMessageProcessor messageProcessor = connection.loginPluginMessageProcessor(); messageProcessor.handleResponse(packet.messageId(), packet.data()); } catch (Throwable t) { + connection.kick(ERROR_DURING_LOGIN); MinecraftServer.LOGGER.error("Error handling Login Plugin Response", t); - LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(ERROR_DURING_LOGIN); - connection.sendPacket(disconnectPacket); - connection.disconnect(); + MinecraftServer.getExceptionManager().handleException(t); } } diff --git a/src/main/java/net/minestom/server/network/player/PlayerConnection.java b/src/main/java/net/minestom/server/network/player/PlayerConnection.java index 06cdd5da9..4f3a9108f 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerConnection.java @@ -1,5 +1,6 @@ package net.minestom.server.network.player; +import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.crypto.PlayerPublicKey; import net.minestom.server.entity.Entity; @@ -8,9 +9,12 @@ import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.server.SendablePacket; +import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.common.CookieRequestPacket; import net.minestom.server.network.packet.server.common.CookieStorePacket; +import net.minestom.server.network.packet.server.common.DisconnectPacket; import net.minestom.server.network.packet.server.configuration.SelectKnownPacksPacket; +import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.validate.Check; @@ -114,6 +118,24 @@ public abstract class PlayerConnection { return MinecraftServer.getServer().getPort(); } + + /** + * Kicks the player with a reason. + * + * @param component the reason + */ + public void kick(@NotNull Component component) { + // Packet type depends on the current player connection state + final ServerPacket disconnectPacket; + if (connectionState == ConnectionState.LOGIN) { + disconnectPacket = new LoginDisconnectPacket(component); + } else { + disconnectPacket = new DisconnectPacket(component); + } + sendPacket(disconnectPacket); + disconnect(); + } + /** * Forcing the player to disconnect. */ diff --git a/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java b/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java index e4aa269fa..03733c011 100644 --- a/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java +++ b/src/main/java/net/minestom/server/utils/mojang/MojangUtils.java @@ -2,12 +2,19 @@ package net.minestom.server.utils.mojang; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import net.minestom.server.ServerFlag; import net.minestom.server.utils.url.URLUtils; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.UUID; /** @@ -17,6 +24,10 @@ public final class MojangUtils { private static final String FROM_UUID_URL = "https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false"; private static final String FROM_USERNAME_URL = "https://api.mojang.com/users/profiles/minecraft/%s"; + // Auth + private static final String BASE_AUTH_URL = ServerFlag.AUTH_URL.concat("?username=%s&serverId=%s"); + private static final String PREVENT_PROXY_CONNECTIONS_AUTH_URL = BASE_AUTH_URL.concat("&ip=%s"); + /** * Gets a player's UUID from their username * @@ -90,6 +101,24 @@ public final class MojangUtils { } } + @Blocking + @ApiStatus.Internal + public static @NotNull JsonObject authenticateSession(String loginUsername, String serverId, @Nullable SocketAddress userSocket) throws IOException { + final String username = URLEncoder.encode(loginUsername, StandardCharsets.UTF_8); + + final String url; + if (ServerFlag.AUTH_PREVENT_PROXY_CONNECTIONS + && userSocket instanceof InetSocketAddress inetSocketAddress + && inetSocketAddress.getAddress() instanceof InetAddress address + ) { + url = String.format(PREVENT_PROXY_CONNECTIONS_AUTH_URL, username, serverId, address.getHostAddress()); + } else { + url = String.format(BASE_AUTH_URL, username, serverId); + } + + return retrieve(url); + } + /** * Gets the JsonObject from a URL, expects a mojang player URL so the errors might not make sense if it is not * From 12e7bb327dc3dda90c6447b97872d52674db54d8 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 13 Sep 2024 23:22:04 +0200 Subject: [PATCH 25/97] entity status/meta storage (#2378) --- .../server/entity/EntityStatuses.java | 56 ++ .../minestom/server/entity/LivingEntity.java | 2 +- .../minestom/server/entity/MetadataDef.java | 554 ++++++++++++++++++ .../server/entity/MetadataDefImpl.java | 63 ++ .../net/minestom/server/entity/Player.java | 15 +- .../listener/PlayerDiggingListener.java | 3 +- 6 files changed, 681 insertions(+), 12 deletions(-) create mode 100644 src/main/java/net/minestom/server/entity/EntityStatuses.java create mode 100644 src/main/java/net/minestom/server/entity/MetadataDef.java create mode 100644 src/main/java/net/minestom/server/entity/MetadataDefImpl.java diff --git a/src/main/java/net/minestom/server/entity/EntityStatuses.java b/src/main/java/net/minestom/server/entity/EntityStatuses.java new file mode 100644 index 000000000..38d7bf523 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/EntityStatuses.java @@ -0,0 +1,56 @@ +package net.minestom.server.entity; + +/** + * Entity status ids used in {@link net.minestom.server.network.packet.server.play.EntityStatusPacket}. + */ +@SuppressWarnings("ALL") +public sealed class EntityStatuses { + public static final int SPAWNS_HONEY_BLOCK_PARTICLES = 53; + + public static final class Arrow extends EntityStatuses { + public static final int SPAWN_TIPPED_ARROW_PARTICLE = 0; + } + + public static sealed class LivingEntity extends EntityStatuses { + public static final int PLAY_DEATH_SOUND = 3; + public static final int PLAY_SHIELD_BLOCK_SOUND = 29; + public static final int PLAY_SHIELD_BREAK_SOUND = 30; + public static final int PLAY_TOTEM_UNDYING_ANIMATION_SOUND = 35; + + public static final int SWAP_HAND_ITEMS = 55; + public static final int SPAWN_DEATH_SMOKE_PARTICLES = 60; + } + + public static final class Player extends LivingEntity { + public static final int MARK_ITEM_FINISHED = 9; + public static final int ENABLE_DEBUG_SCREEN = 22; + public static final int DISABLE_DEBUG_SCREEN = 23; + public static final int PERMISSION_LEVEL_0 = 24; + public static final int PERMISSION_LEVEL_1 = 25; + public static final int PERMISSION_LEVEL_2 = 26; + public static final int PERMISSION_LEVEL_3 = 27; + public static final int PERMISSION_LEVEL_4 = 28; + public static final int SPAWN_CLOUD_PARTICLES = 43; + } + + public static sealed class Animal extends EntityStatuses { + public static final int SPAWN_LOVE_MODE_PARTICLES = 18; + } + + public static final class Ocelot extends Animal { + public static final int SPAWN_SMOKE_PARTICLES = 40; + public static final int SPAWN_HEART_PARTICLES = 41; + } + + public static final class Rabbit extends Animal { + public static final int JUMP_ANIMATION = 1; + } + + public static final class Sheep extends Animal { + public static final int EAT_GRASS = 10; + } + + public static final class Sniffer extends Animal { + public static final int PLAY_DIGGING_SOUND = 63; + } +} diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index e5f7c00df..f5b5d7ac1 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -260,7 +260,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { */ public void kill() { refreshIsDead(true); // So the entity isn't killed over and over again - triggerStatus((byte) 3); // Start death animation status + triggerStatus((byte) EntityStatuses.LivingEntity.PLAY_DEATH_SOUND); // Start death animation status setPose(EntityPose.DYING); setHealth(0); diff --git a/src/main/java/net/minestom/server/entity/MetadataDef.java b/src/main/java/net/minestom/server/entity/MetadataDef.java new file mode 100644 index 000000000..858a5977d --- /dev/null +++ b/src/main/java/net/minestom/server/entity/MetadataDef.java @@ -0,0 +1,554 @@ +package net.minestom.server.entity; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.text.Component; +import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.metadata.animal.FrogMeta; +import net.minestom.server.entity.metadata.animal.SnifferMeta; +import net.minestom.server.entity.metadata.animal.tameable.CatMeta; +import net.minestom.server.entity.metadata.other.PaintingMeta; +import net.minestom.server.instance.block.Block; +import net.minestom.server.item.ItemStack; +import net.minestom.server.particle.Particle; +import net.minestom.server.registry.DynamicRegistry; +import net.minestom.server.utils.Direction; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; +import java.util.function.Function; + +import static net.minestom.server.entity.MetadataDefImpl.index; +import static net.minestom.server.entity.MetadataDefImpl.mask; + +/** + * List of all entity metadata. + *

+ * Classes must be used (and not interfaces) to enforce loading order. + */ +@SuppressWarnings({"unused", "SpellCheckingInspection"}) +public sealed class MetadataDef { + public static final Entry IS_ON_FIRE = mask(0, 0x01, false); + public static final Entry IS_CROUCHING = mask(0, 0x02, false); + public static final Entry UNUSED_RIDING = mask(0, 0x04, false); + public static final Entry IS_SPRINTING = mask(0, 0x08, false); + public static final Entry IS_SWIMMING = mask(0, 0x10, false); + public static final Entry IS_INVISIBLE = mask(0, 0x20, false); + public static final Entry HAS_GLOWING_EFFECT = mask(0, 0x40, false); + public static final Entry IS_FLYING_WITH_ELYTRA = mask(0, 0x80, false); + public static final Entry AIR_TICKS = index(1, Metadata::VarInt, 300); + public static final Entry<@Nullable Component> CUSTOM_NAME = index(2, Metadata::OptChat, null); + public static final Entry CUSTOM_NAME_VISIBLE = index(3, Metadata::Boolean, false); + public static final Entry IS_SILENT = index(4, Metadata::Boolean, false); + public static final Entry HAS_NO_GRAVITY = index(5, Metadata::Boolean, false); + public static final Entry POSE = index(6, Metadata::Pose, EntityPose.STANDING); + public static final Entry TICKS_FROZEN = index(7, Metadata::VarInt, 0); + + public static final class Interaction extends MetadataDef { + public static final Entry WIDTH = index(0, Metadata::Float, 1f); + public static final Entry HEIGHT = index(1, Metadata::Float, 1f); + public static final Entry RESPONSIVE = index(2, Metadata::Boolean, false); + } + + public static sealed class Display extends MetadataDef { + public static final Entry INTERPOLATION_DELAY = index(0, Metadata::VarInt, 0); + public static final Entry TRANSFORMATION_INTERPOLATION_DURATION = index(1, Metadata::VarInt, 0); + public static final Entry POSITION_ROTATION_INTERPOLATION_DURATION = index(2, Metadata::VarInt, 0); + public static final Entry TRANSLATION = index(3, Metadata::Vector3, Vec.ZERO); + public static final Entry SCALE = index(4, Metadata::Vector3, Vec.ONE); + public static final Entry ROTATION_LEFT = index(5, Metadata::Quaternion, new float[]{0, 0, 0, 1}); + public static final Entry ROTATION_RIGHT = index(6, Metadata::Quaternion, new float[]{0, 0, 0, 1}); + public static final Entry BILLBOARD_CONSTRAINTS = index(7, Metadata::Byte, (byte) 0); + public static final Entry BRIGHTNESS_OVERRIDE = index(8, Metadata::VarInt, -1); + public static final Entry VIEW_RANGE = index(9, Metadata::Float, 1f); + public static final Entry SHADOW_RADIUS = index(10, Metadata::Float, 0f); + public static final Entry SHADOW_STRENGTH = index(11, Metadata::Float, 1f); + public static final Entry WIDTH = index(12, Metadata::Float, 0f); + public static final Entry HEIGHT = index(13, Metadata::Float, 0f); + public static final Entry GLOW_COLOR_OVERRIDE = index(14, Metadata::VarInt, -1); + } + + public static final class BlockDisplay extends Display { + public static final Entry DISPLAYED_BLOCK_STATE = index(0, Metadata::BlockState, Block.AIR); + } + + public static final class ItemDisplay extends Display { + public static final Entry DISPLAYED_ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + public static final Entry DISPLAY_TYPE = index(1, Metadata::Byte, (byte) 0); + } + + public static final class TextDisplay extends Display { + public static final Entry TEXT = index(0, Metadata::Chat, Component.empty()); + public static final Entry LINE_WIDTH = index(1, Metadata::VarInt, 200); + public static final Entry BACKGROUND_COLOR = index(2, Metadata::VarInt, 0x40000000); + public static final Entry TEXT_OPACITY = index(3, Metadata::Byte, (byte) -1); + public static final Entry HAS_SHADOW = mask(4, 0x01, false); + public static final Entry IS_SEE_THROUGH = mask(4, 0x02, false); + public static final Entry USE_DEFAULT_BACKGROUND_COLOR = mask(4, 0x04, false); + public static final Entry ALIGNMENT = mask(4, 0x08, false); + } + + public static final class ThrownItemProjectile extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + } + + public static final class EyeOfEnder extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + } + + public static final class FallingBlock extends MetadataDef { + public static final Entry SPAWN_POSITION = index(0, Metadata::BlockPosition, Vec.ZERO); + } + + public static final class AreaEffectCloud extends MetadataDef { + public static final Entry RADIUS = index(0, Metadata::Float, 0.5f); + public static final Entry COLOR = index(1, Metadata::VarInt, 0); + public static final Entry IGNORE_RADIUS_AND_SINGLE_POINT = index(2, Metadata::Boolean, false); + public static final Entry PARTICLE = index(3, Metadata::Particle, Particle.EFFECT); + } + + public static final class FishingHook extends MetadataDef { + public static final Entry HOOKED = index(0, Metadata::VarInt, 0); + public static final Entry IS_CATCHABLE = index(1, Metadata::Boolean, false); + } + + public static sealed class AbstractArrow extends MetadataDef { + public static final Entry IS_CRITICAL = mask(0, 0x01, false); + public static final Entry IS_NO_CLIP = mask(0, 0x02, false); + public static final Entry PIERCING_LEVEL = index(1, Metadata::Byte, (byte) 0); + } + + public static final class Arrow extends AbstractArrow { + public static final Entry COLOR = index(0, Metadata::VarInt, -1); + } + + public static final class ThrownTrident extends AbstractArrow { + public static final Entry LOYALTY_LEVEL = index(0, Metadata::Byte, (byte) 0); + public static final Entry HAS_ENCHANTMENT_GLINT = index(1, Metadata::Boolean, false); + } + + public static sealed class AbstractVehicle extends MetadataDef { + public static final Entry SHAKING_POWER = index(0, Metadata::VarInt, 0); + public static final Entry SHAKING_DIRECTION = index(1, Metadata::VarInt, 1); + public static final Entry SHAKING_MULTIPLIER = index(2, Metadata::Float, 0f); + } + + public static final class Boat extends AbstractVehicle { + public static final Entry TYPE = index(0, Metadata::VarInt, 0); + public static final Entry IS_LEFT_PADDLE_TURNING = index(1, Metadata::Boolean, false); + public static final Entry IS_RIGHT_PADDLE_TURNING = index(2, Metadata::Boolean, false); + public static final Entry SPLASH_TIMER = index(3, Metadata::VarInt, 0); + } + + public static sealed class AbstractMinecart extends AbstractVehicle { + public static final Entry CUSTOM_BLOCK_ID_AND_DAMAGE = index(0, Metadata::VarInt, 0); + public static final Entry CUSTOM_BLOCK_Y_POSITION = index(1, Metadata::VarInt, 6); + public static final Entry SHOW_CUSTOM_BLOCK = index(2, Metadata::Boolean, false); + } + + public static final class MinecartFurnace extends AbstractMinecart { + public static final Entry HAS_FUEL = index(0, Metadata::Boolean, false); + } + + public static final class MinecartCommandBlock extends AbstractMinecart { + public static final Entry COMMAND = index(0, Metadata::String, "false"); + public static final Entry LAST_OUTPUT = index(1, Metadata::Chat, Component.empty()); + } + + public static final class EndCrystal extends MetadataDef { + public static final Entry<@Nullable Point> BEAM_TARGET = index(0, Metadata::OptBlockPosition, null); + public static final Entry SHOW_BOTTOM = index(1, Metadata::Boolean, true); + } + + public static final class SmartFireball extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + } + + public static final class Fireball extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + } + + public static final class WitherSkull extends MetadataDef { + public static final Entry IS_INVULNERABLE = index(0, Metadata::Boolean, false); + } + + public static final class FireworkRocketEntity extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + public static final Entry<@Nullable Integer> ENTITY_ID = index(1, Metadata::OptVarInt, null); + public static final Entry IS_SHOT_AT_ANGLE = index(2, Metadata::Boolean, false); + } + + public static final class ItemFrame extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + public static final Entry ROTATION = index(0, Metadata::VarInt, 0); + } + + public static final class Painting extends MetadataDef { + public static final Entry> ITEM = index(0, Metadata::PaintingVariant, PaintingMeta.Variant.KEBAB); + } + + public static final class ItemEntity extends MetadataDef { + public static final Entry ITEM = index(0, Metadata::ItemStack, ItemStack.AIR); + } + + public static sealed class LivingEntity extends MetadataDef { + public static final Entry IS_HAND_ACTIVE = mask(0, 0x01, false); + public static final Entry ACTIVE_HAND = mask(0, 0x02, false); + public static final Entry IS_RIPTIDE_SPIN_ATTACK = mask(0, 0x04, false); + public static final Entry HEALTH = index(1, Metadata::Float, 1f); + public static final Entry POTION_EFFECT_COLOR = index(2, Metadata::VarInt, 0); + public static final Entry IS_POTION_EFFECT_AMBIANT = index(3, Metadata::Boolean, false); + public static final Entry NUMBER_OF_ARROWS = index(4, Metadata::VarInt, 0); + public static final Entry NUMBER_OF_BEE_STINGERS = index(5, Metadata::VarInt, 0); + public static final Entry<@Nullable Point> LOCATION_OF_BED = index(6, Metadata::OptBlockPosition, null); + } + + public static final class Player extends LivingEntity { + public static final Entry ADDITIONAL_HEARTS = index(0, Metadata::Float, 1f); + public static final Entry SCORE = index(1, Metadata::VarInt, 0); + public static final Entry DISLAYED_SKIN_PARTS = index(2, Metadata::Byte, (byte) 0); + public static final Entry MAIN_HAND = index(3, Metadata::Byte, (byte) 1); + public static final Entry LEFT_SHOULDER_ENTITY_DATA = index(4, Metadata::NBT, CompoundBinaryTag.empty()); + public static final Entry RIGHT_SHOULDER_ENTITY_DATA = index(5, Metadata::NBT, CompoundBinaryTag.empty()); + } + + public static final class ArmorStand extends LivingEntity { + public static final Entry SIZE = index(0, Metadata::Byte, (byte) 0); + public static final Entry HEAD_ROTATION = index(1, Metadata::Rotation, Vec.ZERO); + public static final Entry BODY_ROTATION = index(2, Metadata::Rotation, Vec.ZERO); + public static final Entry LEFT_ARM_ROTATION = index(3, Metadata::Rotation, new Vec(-10, 0, -10)); + public static final Entry RIGHT_ARM_ROTATION = index(4, Metadata::Rotation, new Vec(-15, 0, 10)); + public static final Entry LEFT_LEG_ROTATION = index(5, Metadata::Rotation, new Vec(-1, 0, -1)); + public static final Entry RIGHT_LEG_ROTATION = index(6, Metadata::Rotation, new Vec(1, 0, 1)); + } + + public static sealed class Mob extends LivingEntity { + public static final Entry NO_AI = mask(0, 0x01, false); + public static final Entry IS_LEFT_HANDED = mask(0, 0x02, false); + public static final Entry IS_AGGRESSIVE = mask(0, 0x04, false); + } + + public static final class Bat extends Mob { + public static final Entry IS_HANGING = mask(0, 0x01, false); + } + + public static final class Dolphin extends Mob { + public static final Entry TREASURE_POSITION = index(0, Metadata::BlockPosition, Vec.ZERO); + public static final Entry HAS_FISH = index(1, Metadata::Boolean, false); + public static final Entry MOISTURE_LEVEL = index(2, Metadata::VarInt, 2400); + } + + public static sealed class AbstractFish extends Mob { + public static final Entry FROM_BUCKET = index(0, Metadata::Boolean, false); + } + + public static final class PufferFish extends AbstractFish { + public static final Entry PUFF_STATE = index(0, Metadata::VarInt, 0); + } + + public static final class TropicalFish extends AbstractFish { + public static final Entry VARIANT = index(0, Metadata::VarInt, 0); + } + + public static sealed class AgeableMob extends Mob { + public static final Entry IS_BABY = index(0, Metadata::Boolean, false); + } + + public static final class Sniffer extends AgeableMob { + public static final Entry IS_BABY = index(0, Metadata::SnifferState, SnifferMeta.State.IDLING); + public static final Entry DROP_SEED_AT_TICK = index(1, Metadata::VarInt, 0); + } + + public static sealed class AbstractHorse extends AgeableMob { + public static final Entry UNUSED = mask(0, 0x01, false); + public static final Entry IS_TAME = mask(0, 0x02, false); + public static final Entry IS_SADDLED = mask(0, 0x04, false); + public static final Entry HAS_BRED = mask(0, 0x08, false); + public static final Entry IS_EATING = mask(0, 0x10, false); + public static final Entry IS_REARING = mask(0, 0x20, false); + public static final Entry IS_MOUTH_OPEN = mask(0, 0x40, false); + } + + public static final class Horse extends AbstractHorse { + public static final Entry VARIANT = index(0, Metadata::VarInt, 0); + } + + public static final class Camel extends AbstractHorse { + public static final Entry DASHING = index(0, Metadata::Boolean, false); + public static final Entry VARIANT = index(1, Metadata::VarLong, 0L); + } + + public static sealed class ChestedHorse extends AbstractHorse { + public static final Entry HAS_CHEST = index(0, Metadata::Boolean, false); + } + + public static final class Llama extends ChestedHorse { + public static final Entry STRENGTH = index(0, Metadata::VarInt, 0); + public static final Entry CARPET_COLOR = index(0, Metadata::VarInt, -1); + public static final Entry VARIANT = index(0, Metadata::VarInt, 0); + } + + public static final class Axolotl extends AgeableMob { + public static final Entry VARIANT = index(0, Metadata::VarInt, 0); + public static final Entry PLAYING_DEAD = index(1, Metadata::Boolean, false); + public static final Entry SPAWNED_FROM_BUCKET = index(2, Metadata::Boolean, false); + } + + public static final class Bee extends AgeableMob { + public static final Entry UNUSED = mask(0, 0x01, false); + public static final Entry IS_ANGRY = mask(0, 0x02, false); + public static final Entry HAS_STUNG = mask(0, 0x04, false); + public static final Entry HAS_NECTAR = mask(0, 0x08, false); + public static final Entry ANGER_TIME_TICKS = index(1, Metadata::VarInt, 0); + } + + public static final class Fox extends AgeableMob { + public static final Entry TYPE = index(0, Metadata::VarInt, 0); + public static final Entry IS_SITTING = mask(1, 0x01, false); + public static final Entry UNUSED = mask(1, 0x02, false); + public static final Entry IS_CROUCHING = mask(1, 0x04, false); + public static final Entry IS_INTERESTED = mask(1, 0x08, false); + public static final Entry IS_POUNCING = mask(1, 0x10, false); + public static final Entry IS_SLEEPING = mask(1, 0x20, false); + public static final Entry IS_FACEPLANTED = mask(1, 0x40, false); + public static final Entry IS_DEFENDING = mask(1, 0x80, false); + public static final Entry<@Nullable UUID> FIRST_UUID = index(2, Metadata::OptUUID, null); + public static final Entry<@Nullable UUID> SECOND_UUID = index(3, Metadata::OptUUID, null); + } + + public static final class Frog extends AgeableMob { + public static final Entry VARIANT = index(0, Metadata::FrogVariant, FrogMeta.Variant.TEMPERATE); + public static final Entry<@Nullable Integer> TONGUE_TARGET = index(1, Metadata::OptVarInt, 0); + } + + public static final class Ocelot extends AgeableMob { + public static final Entry IS_TRUSTING = index(0, Metadata::Boolean, false); + } + + public static final class Panda extends AgeableMob { + public static final Entry BREED_TIMER = index(0, Metadata::VarInt, 0); + public static final Entry SNEEZE_TIMER = index(1, Metadata::VarInt, 0); + public static final Entry EAT_TIMER = index(2, Metadata::VarInt, 0); + public static final Entry MAIN_GENE = index(3, Metadata::Byte, (byte) 0); + public static final Entry HIDDEN_GENE = index(4, Metadata::Byte, (byte) 0); + public static final Entry UNUSED = mask(5, 0x01, false); + public static final Entry IS_SNEEZING = mask(5, 0x02, false); + public static final Entry IS_ROLLING = mask(5, 0x04, false); + public static final Entry IS_SITTING = mask(5, 0x08, false); + public static final Entry IS_ON_BACK = mask(5, 0x10, false); + } + + public static final class Pig extends AgeableMob { + public static final Entry HAS_SADDLE = index(0, Metadata::Boolean, false); + public static final Entry BOOST_TIME = index(1, Metadata::VarInt, 0); + } + + public static final class Rabbit extends AgeableMob { + public static final Entry TYPE = index(0, Metadata::VarInt, 0); + } + + public static final class Turtle extends AgeableMob { + public static final Entry HOME_POS = index(0, Metadata::BlockPosition, Vec.ZERO); + public static final Entry HAS_EGG = index(1, Metadata::Boolean, false); + public static final Entry IS_LAYING_EGG = index(2, Metadata::Boolean, false); + public static final Entry TRAVEL_POS = index(3, Metadata::BlockPosition, Vec.ZERO); + public static final Entry IS_GOING_HOME = index(4, Metadata::Boolean, false); + public static final Entry IS_TRAVELING = index(5, Metadata::Boolean, false); + } + + public static final class PolarBear extends AgeableMob { + public static final Entry IS_STANDING_UP = index(0, Metadata::Boolean, false); + } + + public static final class Mooshroom extends AgeableMob { + public static final Entry IS_STANDING_UP = index(0, Metadata::String, "red"); + } + + public static final class Hoglin extends AgeableMob { + public static final Entry IMMUNE_ZOMBIFICATION = index(0, Metadata::Boolean, false); + } + + public static final class Sheep extends AgeableMob { + // TODO: color is 4 bits + public static final Entry COLOR_ID = mask(0, 0x0F, false); + public static final Entry IS_SHEARED = mask(0, 0x10, false); + } + + public static final class Strider extends AgeableMob { + public static final Entry FUNGUS_BOOST = index(0, Metadata::VarInt, 0); + public static final Entry IS_SHAKING = index(1, Metadata::Boolean, false); + public static final Entry HAS_SADDLE = index(2, Metadata::Boolean, false); + } + + public static final class Goat extends AgeableMob { + public static final Entry IS_SCREAMING_GOAT = index(0, Metadata::Boolean, false); + public static final Entry HAS_LEFT_HORN = index(1, Metadata::Boolean, true); + public static final Entry HAS_RIGHT_HORN = index(2, Metadata::Boolean, true); + } + + public static sealed class TameableAnimal extends AgeableMob { + public static final Entry IS_SITTING = mask(0, 0x01, false); + public static final Entry UNUSED = mask(0, 0x02, false); + public static final Entry IS_TAMED = mask(0, 0x04, false); + public static final Entry<@Nullable UUID> OWNER = index(1, Metadata::OptUUID, null); + } + + public static final class Cat extends TameableAnimal { + public static final Entry FUNGUS_BOOST = index(0, Metadata::CatVariant, CatMeta.Variant.BLACK); + public static final Entry IS_LYING = index(2, Metadata::Boolean, false); + public static final Entry IS_RELAXED = index(3, Metadata::Boolean, false); + public static final Entry COLLAR_COLOR = index(4, Metadata::VarInt, 14); + } + + public static final class Wolf extends TameableAnimal { + public static final Entry IS_BEGGING = index(0, Metadata::Boolean, false); + public static final Entry COLLAR_COLOR = index(1, Metadata::VarInt, 14); + public static final Entry ANGER_TIME = index(2, Metadata::VarInt, 0); + } + + public static final class Parrot extends TameableAnimal { + public static final Entry VARIANT = index(0, Metadata::VarInt, 0); + } + + public static sealed class AbstractVillager extends AgeableMob { + public static final Entry HEAD_SHAKE_TIMER = index(0, Metadata::VarInt, 0); + } + + public static final class Villager extends AbstractVillager { + public static final Entry VARIANT = index(0, Metadata::VillagerData, new int[]{0, 0, 0}); + } + + public static final class IronGolem extends Mob { + public static final Entry IS_PLAYER_CREATED = mask(0, 0x01, false); + } + + public static final class SnowGolem extends Mob { + public static final Entry NO_PUMPKIN_HAT = mask(0, 0x01, false); + public static final Entry PUMPKIN_HAT = mask(0, 0x10, true); + } + + public static final class Shulker extends Mob { + public static final Entry ATTACH_FACE = index(0, Metadata::Direction, Direction.DOWN); + public static final Entry SHIELD_HEIGHT = index(1, Metadata::Byte, (byte) 0); + public static final Entry COLOR = index(2, Metadata::Byte, (byte) 16); + } + + public static sealed class BasePiglin extends Mob { + public static final Entry IMMUNE_ZOMBIFICATION = index(0, Metadata::Boolean, false); + } + + public static final class Piglin extends BasePiglin { + public static final Entry IS_BABY = index(0, Metadata::Boolean, false); + public static final Entry IS_CHARGING_CROSSBOW = index(1, Metadata::Boolean, false); + public static final Entry IS_DANCING = index(2, Metadata::Boolean, false); + } + + public static final class Blaze extends Mob { + public static final Entry IS_ON_FIRE = mask(0, 0x01, false); + } + + public static final class Creeper extends Mob { + public static final Entry STATE = index(0, Metadata::VarInt, -1); + public static final Entry IS_CHARGED = index(1, Metadata::Boolean, false); + public static final Entry IS_IGNITED = index(2, Metadata::Boolean, false); + } + + public static final class Guardian extends Mob { + public static final Entry IS_RETRACTING_SPIKES = index(0, Metadata::Boolean, false); + public static final Entry TARGET_EID = index(1, Metadata::VarInt, 0); + } + + public static sealed class Raider extends Mob { + public static final Entry IS_CELEBRATING = index(0, Metadata::Boolean, false); + } + + public static final class Pillager extends Raider { + public static final Entry IS_CHARGING = index(0, Metadata::Boolean, false); + } + + public static final class SpellcasterIllager extends Raider { + public static final Entry SPELL = index(0, Metadata::Byte, (byte) 0); + } + + public static final class Witch extends Raider { + public static final Entry IS_ATTACKING = mask(0, 0x01, false); + } + + public static final class Spider extends Mob { + public static final Entry IS_CLIMBING = mask(0, 0x01, false); + } + + public static final class Warden extends Mob { + public static final Entry ANGER_LEVEL = index(0, Metadata::VarInt, 0); + } + + public static final class Wither extends Mob { + public static final Entry CENTER_HEAD_TARGET = index(0, Metadata::VarInt, 0); + public static final Entry LEFT_HEAD_TARGET = index(1, Metadata::VarInt, 0); + public static final Entry RIGHT_HEAD_TARGET = index(2, Metadata::VarInt, 0); + public static final Entry INVULNERABLE_TIME = index(3, Metadata::VarInt, 0); + } + + public static final class Zoglin extends Mob { + public static final Entry IS_BABY = index(0, Metadata::Boolean, false); + } + + public static final class Zombie extends Mob { + public static final Entry IS_BABY = index(0, Metadata::Boolean, false); + public static final Entry UNUSED = index(1, Metadata::VarInt, 0); + public static final Entry IS_BECOMING_DROWNED = index(2, Metadata::Boolean, false); + } + + public static final class ZombieVillager extends Mob { + public static final Entry IS_CONVERTING = index(0, Metadata::Boolean, false); + public static final Entry VILLAGER_DATA = index(1, Metadata::VillagerData, new int[]{0, 0, 0}); + } + + public static final class Enderman extends Mob { + public static final Entry<@Nullable Integer> CARRIED_BLOCK = index(0, Metadata::OptBlockState, null); + public static final Entry IS_SCREAMING = index(1, Metadata::Boolean, false); + public static final Entry IS_STARING = index(2, Metadata::Boolean, false); + } + + public static final class EnderDragon extends Mob { + public static final Entry DRAGON_PHASE = index(0, Metadata::VarInt, 10); + } + + public static final class Ghast extends Mob { + public static final Entry IS_ATTACKING = index(0, Metadata::Boolean, false); + } + + public static final class Phantom extends Mob { + public static final Entry SIZE = index(0, Metadata::VarInt, 0); + } + + public static final class Slime extends Mob { + public static final Entry SIZE = index(0, Metadata::VarInt, 1); + } + + public static final class PrimedTnt extends Mob { + public static final Entry FUSE_TIME = index(0, Metadata::VarInt, 80); + } + + /** + * Get the number of metadata entries for a specific class. + *

+ * Useful if you want to pre-allocate the metadata array. + */ + public static int count(Class clazz) { + return MetadataDefImpl.count(clazz); + } + + public sealed interface Entry { + int index(); + + T defaultValue(); + + record Index(int index, Function> function, T defaultValue) implements Entry { + } + + record Mask(int index, int bitMask, Boolean defaultValue) implements Entry { + } + } +} diff --git a/src/main/java/net/minestom/server/entity/MetadataDefImpl.java b/src/main/java/net/minestom/server/entity/MetadataDefImpl.java new file mode 100644 index 000000000..07b051faf --- /dev/null +++ b/src/main/java/net/minestom/server/entity/MetadataDefImpl.java @@ -0,0 +1,63 @@ +package net.minestom.server.entity; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +final class MetadataDefImpl { + static final Map MAX_INDEX = new HashMap<>(); + + static MetadataDef.Entry.Index index(int index, Function> function, T defaultValue) { + final String caller = caller(); + storeMaxIndex(caller, index); + final int superIndex = findSuperIndex(caller); + return new MetadataDef.Entry.Index<>(superIndex + index, function, defaultValue); + } + + static MetadataDef.Entry.Mask mask(int index, int bitMask, boolean defaultValue) { + final String caller = caller(); + storeMaxIndex(caller, index); + final int superIndex = findSuperIndex(caller); + return new MetadataDef.Entry.Mask(superIndex + index, bitMask, defaultValue); + } + + static int count(Class clazz) { + final String name = clazz.getName(); + try { + // Force load the class to ensure entries are registered + Class.forName(name); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + final int classIndex = MAX_INDEX.get(name); + final int superIndex = findSuperIndex(name); + return classIndex + superIndex + 1; + } + + private static String caller() { + return Thread.currentThread().getStackTrace()[3].getClassName(); + } + + static void storeMaxIndex(String caller, int index) { + final int currentMax = MAX_INDEX.getOrDefault(caller, 0); + MAX_INDEX.put(caller, Math.max(currentMax, index)); + } + + static int findSuperIndex(String caller) { + try { + final Class subclass = Class.forName(caller); + Class superclass = subclass.getSuperclass(); + if (superclass == Object.class) return 0; + + int index = 0; + do { + index += MAX_INDEX.get(superclass.getName()) + 1; + superclass = superclass.getSuperclass(); + } while (superclass != Object.class); + + return index; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index d8c57e365..c0bd8809b 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -122,11 +122,6 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou private static final Component REMOVE_MESSAGE = Component.text("You have been removed from the server without reason.", NamedTextColor.RED); private static final Component MISSING_REQUIRED_RESOURCE_PACK = Component.text("Required resource pack was not loaded.", NamedTextColor.RED); - // Magic values: https://wiki.vg/Entity_statuses#Player - private static final int STATUS_ENABLE_REDUCED_DEBUG_INFO = 22; - private static final int STATUS_DISABLE_REDUCED_DEBUG_INFO = 23; - private static final int STATUS_PERMISSION_LEVEL_OFFSET = 24; - private long lastKeepAlive; private boolean answerKeepAlive; @@ -364,7 +359,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Some client updates sendPacket(getPropertiesPacket()); // Send default properties - triggerStatus((byte) (STATUS_PERMISSION_LEVEL_OFFSET + permissionLevel)); // Set permission level + triggerStatus((byte) (EntityStatuses.Player.PERMISSION_LEVEL_0 + permissionLevel)); // Set permission level refreshHealth(); // Heal and send health packet refreshAbilities(); // Send abilities packet @@ -429,7 +424,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Eating animation if (isUsingItem()) { if (itemUseTime > 0 && getCurrentItemUseTime() >= itemUseTime) { - triggerStatus((byte) 9); // Mark item use as finished + triggerStatus((byte) EntityStatuses.Player.MARK_ITEM_FINISHED); ItemUpdateStateEvent itemUpdateStateEvent = callItemUpdateStateEvent(itemUseHand); // Refresh hand @@ -550,7 +545,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), false)); sendPacket(new UpdateHealthPacket(this.getHealth(), food, foodSaturation)); sendPacket(new SetExperiencePacket(exp, level, 0)); - triggerStatus((byte) (STATUS_PERMISSION_LEVEL_OFFSET + permissionLevel)); // Set permission level + triggerStatus((byte) (EntityStatuses.Player.PERMISSION_LEVEL_0 + permissionLevel)); // Set permission level refreshAbilities(); } @@ -1924,7 +1919,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Condition to prevent sending the packets before spawning the player if (isActive()) { - final byte permissionLevelStatus = (byte) (STATUS_PERMISSION_LEVEL_OFFSET + permissionLevel); + final byte permissionLevelStatus = (byte) (EntityStatuses.Player.PERMISSION_LEVEL_0 + permissionLevel); triggerStatus(permissionLevelStatus); } } @@ -1937,7 +1932,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou public void setReducedDebugScreenInformation(boolean reduced) { this.reducedDebugScreenInformation = reduced; - final byte debugScreenStatus = (byte) (reduced ? STATUS_ENABLE_REDUCED_DEBUG_INFO : STATUS_DISABLE_REDUCED_DEBUG_INFO); + final byte debugScreenStatus = (byte) (reduced ? EntityStatuses.Player.ENABLE_DEBUG_SCREEN : EntityStatuses.Player.DISABLE_DEBUG_SCREEN); triggerStatus(debugScreenStatus); } diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index af840bcec..f28ecb184 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.EntityStatuses; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.entity.PlayerHand; @@ -153,7 +154,7 @@ public final class PlayerDiggingListener { ItemUpdateStateEvent itemUpdateStateEvent = player.callItemUpdateStateEvent(hand); player.clearItemUse(); - player.triggerStatus((byte) 9); + player.triggerStatus((byte) EntityStatuses.Player.MARK_ITEM_FINISHED); final boolean isOffHand = itemUpdateStateEvent.getHand() == PlayerHand.OFF; player.refreshActiveHand(itemUpdateStateEvent.hasHandAnimation(), From 602078864333c1ea289cc7965162121e8f9af304 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 15 Sep 2024 17:29:36 +0200 Subject: [PATCH 26/97] Add CoordConversion and ChunkRange (#2398) --- .../server/coordinate/ChunkRange.java | 84 +++++++ .../server/coordinate/CoordConversion.java | 97 ++++++++ .../net/minestom/server/coordinate/Point.java | 16 +- .../net/minestom/server/entity/Entity.java | 3 +- .../net/minestom/server/entity/Player.java | 38 ++- .../net/minestom/server/instance/Chunk.java | 4 +- .../server/instance/DynamicChunk.java | 26 +- .../server/instance/EntityTrackerImpl.java | 40 +-- .../minestom/server/instance/Instance.java | 58 +++-- .../server/instance/InstanceContainer.java | 27 +- .../server/instance/LightingChunk.java | 4 +- .../server/instance/anvil/AnvilLoader.java | 18 +- .../server/instance/anvil/RegionFile.java | 4 +- .../instance/batch/AbsoluteBlockBatch.java | 12 +- .../server/instance/batch/ChunkBatch.java | 14 +- .../instance/generator/GeneratorImpl.java | 56 ++--- .../packet/server/play/data/ChunkData.java | 4 +- .../server/snapshot/InstanceSnapshot.java | 7 +- .../server/snapshot/SnapshotImpl.java | 14 +- .../server/utils/chunk/ChunkCache.java | 7 +- .../utils/chunk/ChunkUpdateLimitChecker.java | 3 +- .../server/utils/chunk/ChunkUtils.java | 233 +----------------- .../utils/function/IntegerBiConsumer.java | 9 - .../server/coordinate/CoordinateTest.java | 82 +++--- .../entity/EntityVelocityIntegrationTest.java | 25 +- .../PathfinderIntegrationTest.java | 14 +- .../player/PlayerMovementIntegrationTest.java | 12 +- .../PlayerRespawnChunkIntegrationTest.java | 6 +- .../instance/ChunkViewerIntegrationTest.java | 4 +- .../instance/generator/GeneratorTest.java | 10 +- .../minestom/server/utils/ChunkUtilsTest.java | 10 +- 31 files changed, 449 insertions(+), 492 deletions(-) create mode 100644 src/main/java/net/minestom/server/coordinate/ChunkRange.java create mode 100644 src/main/java/net/minestom/server/coordinate/CoordConversion.java delete mode 100644 src/main/java/net/minestom/server/utils/function/IntegerBiConsumer.java diff --git a/src/main/java/net/minestom/server/coordinate/ChunkRange.java b/src/main/java/net/minestom/server/coordinate/ChunkRange.java new file mode 100644 index 000000000..f0f0c698d --- /dev/null +++ b/src/main/java/net/minestom/server/coordinate/ChunkRange.java @@ -0,0 +1,84 @@ +package net.minestom.server.coordinate; + +import org.jetbrains.annotations.NotNull; + +/** + * Helper class to iterate over chunks within a range. + */ +public final class ChunkRange { + + /** + * Get the amount of chunks in a square range. + * + * @param range the range + * @return the amount of chunks in the square range + */ + public static int chunksCount(int range) { + if (range < 0) throw new IllegalArgumentException("Range cannot be negative"); + final int square = range * 2 + 1; + return square * square; + } + + public static void chunksInRangeDiffering(int newChunkX, int newChunkZ, + int oldChunkX, int oldChunkZ, + int range, @NotNull ChunkConsumer callback) { + for (int x = newChunkX - range; x <= newChunkX + range; x++) { + for (int z = newChunkZ - range; z <= newChunkZ + range; z++) { + if (Math.abs(x - oldChunkX) > range || Math.abs(z - oldChunkZ) > range) { + callback.accept(x, z); + } + } + } + } + + public static void chunksInRangeDiffering(int newChunkX, int newChunkZ, + int oldChunkX, int oldChunkZ, + int range, + @NotNull ChunkConsumer newCallback, @NotNull ChunkConsumer oldCallback) { + // Find the new chunks + chunksInRangeDiffering(newChunkX, newChunkZ, oldChunkX, oldChunkZ, range, newCallback); + // Find the old chunks + chunksInRangeDiffering(oldChunkX, oldChunkZ, newChunkX, newChunkZ, range, oldCallback); + } + + /** + * New implementation comes from Krypton + * which comes from kotlin port by Esophose, which comes from a stackoverflow answer. + */ + public static void chunksInRange(int chunkX, int chunkZ, int range, ChunkConsumer consumer) { + // Send in spiral around the center chunk + // Note: its not really required to start at the center anymore since the chunk queue is sorted by distance, + // however we still should send a circle so this method is still fine, and good for any other case a + // spiral might be needed. + consumer.accept(chunkX, chunkZ); + for (int id = 1; id < (range * 2 + 1) * (range * 2 + 1); id++) { + final int index = id - 1; + // compute radius (inverse arithmetic sum of 8 + 16 + 24 + ...) + final int radius = (int) Math.floor((Math.sqrt(index + 1.0) - 1) / 2) + 1; + // compute total point on radius -1 (arithmetic sum of 8 + 16 + 24 + ...) + final int p = 8 * radius * (radius - 1) / 2; + // points by face + final int en = radius * 2; + // compute de position and shift it so the first is (-r, -r) but (-r + 1, -r) + // so the square can connect + final int a = (1 + index - p) % (radius * 8); + switch (a / (radius * 2)) { + // find the face (0 = top, 1 = right, 2 = bottom, 3 = left) + case 0 -> consumer.accept(a - radius + chunkX, -radius + chunkZ); + case 1 -> consumer.accept(radius + chunkX, a % en - radius + chunkZ); + case 2 -> consumer.accept(radius - a % en + chunkX, radius + chunkZ); + case 3 -> consumer.accept(-radius + chunkX, radius - a % en + chunkZ); + default -> throw new IllegalStateException("unreachable"); + } + } + } + + public static void chunksInRange(@NotNull Point point, int range, ChunkConsumer consumer) { + chunksInRange(point.chunkX(), point.chunkZ(), range, consumer); + } + + @FunctionalInterface + public interface ChunkConsumer { + void accept(int chunkX, int chunkZ); + } +} diff --git a/src/main/java/net/minestom/server/coordinate/CoordConversion.java b/src/main/java/net/minestom/server/coordinate/CoordConversion.java new file mode 100644 index 000000000..f7ae6b61d --- /dev/null +++ b/src/main/java/net/minestom/server/coordinate/CoordConversion.java @@ -0,0 +1,97 @@ +package net.minestom.server.coordinate; + +import org.jetbrains.annotations.NotNull; + +public final class CoordConversion { + // COORDINATE CONVERSIONS + + public static int globalToBlock(double xyz) { + return (int) Math.floor(xyz); + } + + public static int globalToChunk(double xz) { + final int block = globalToBlock(xz); + return globalToChunk(block); + } + + public static int globalToChunk(int xz) { + // Assume chunk/section size being 16 (4 bits) + return xz >> 4; + } + + public static int globalToSectionRelative(int xyz) { + return xyz & 0xF; + } + + public static int chunkToRegion(int chunkCoordinate) { + return chunkCoordinate >> 5; + } + + public static int chunkToRegionLocal(int chunkCoordinate) { + return chunkCoordinate & 0x1F; + } + + public static int floorSection(int coordinate) { + return coordinate - (coordinate & 0xF); + } + + public static int ceilSection(int coordinate) { + return ((coordinate - 1) | 15) + 1; + } + + // CHUNK INDEX + + public static long chunkIndex(int chunkX, int chunkZ) { + return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL); + } + + public static long chunkIndex(@NotNull Point point) { + return chunkIndex(point.chunkX(), point.chunkZ()); + } + + public static int chunkIndexGetX(long index) { + return (int) (index >> 32); + } + + public static int chunkIndexGetZ(long index) { + return (int) index; + } + + // BLOCK INDEX FROM CHUNK + + public static int chunkBlockIndex(int x, int y, int z) { + x = globalToSectionRelative(x); + z = globalToSectionRelative(z); + + int index = x & 0xF; // 4 bits + if (y > 0) { + index |= (y << 4) & 0x07FFFFF0; // 23 bits (24th bit is always 0 because y is positive) + } else { + index |= ((-y) << 4) & 0x7FFFFF0; // Make positive and use 23 bits + index |= 1 << 27; // Set negative sign at 24th bit + } + index |= (z << 28) & 0xF0000000; // 4 bits + return index; + } + + public static int chunkBlockIndexGetX(int index) { + return index & 0xF; // 0-4 bits + } + + public static int chunkBlockIndexGetY(int index) { + int y = (index & 0x07FFFFF0) >>> 4; + if (((index >>> 27) & 1) == 1) y = -y; // Sign bit set, invert sign + return y; // 4-28 bits + } + + public static int chunkBlockIndexGetZ(int index) { + return (index >> 28) & 0xF; // 28-32 bits + } + + public static @NotNull Point chunkBlockIndexGetGlobal(int index, int chunkX, int chunkZ) { + final int x = chunkBlockIndexGetX(index) + 16 * chunkX; + final int y = chunkBlockIndexGetY(index); + final int z = chunkBlockIndexGetZ(index) + 16 * chunkZ; + return new Vec(x, y, z); + } +} diff --git a/src/main/java/net/minestom/server/coordinate/Point.java b/src/main/java/net/minestom/server/coordinate/Point.java index cf8b378f1..17fa52591 100644 --- a/src/main/java/net/minestom/server/coordinate/Point.java +++ b/src/main/java/net/minestom/server/coordinate/Point.java @@ -2,12 +2,14 @@ package net.minestom.server.coordinate; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.function.DoubleUnaryOperator; +import static net.minestom.server.coordinate.CoordConversion.globalToBlock; +import static net.minestom.server.coordinate.CoordConversion.globalToChunk; + /** * Represents a 3D point. */ @@ -44,7 +46,7 @@ public sealed interface Point permits Vec, Pos, BlockVec { */ @Contract(pure = true) default int blockX() { - return (int) Math.floor(x()); + return globalToBlock(x()); } /** @@ -54,7 +56,7 @@ public sealed interface Point permits Vec, Pos, BlockVec { */ @Contract(pure = true) default int blockY() { - return (int) Math.floor(y()); + return globalToBlock(y()); } /** @@ -64,22 +66,22 @@ public sealed interface Point permits Vec, Pos, BlockVec { */ @Contract(pure = true) default int blockZ() { - return (int) Math.floor(z()); + return globalToBlock(z()); } @Contract(pure = true) default int chunkX() { - return ChunkUtils.getChunkCoordinate(x()); + return globalToChunk(x()); } @Contract(pure = true) default int section() { - return ChunkUtils.getChunkCoordinate(y()); + return globalToChunk(y()); } @Contract(pure = true) default int chunkZ() { - return ChunkUtils.getChunkCoordinate(z()); + return globalToChunk(z()); } /** diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 690a2d284..71ebabec8 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -7,6 +7,7 @@ import net.kyori.adventure.text.event.HoverEvent.ShowEntity; import net.kyori.adventure.text.event.HoverEventSource; import net.minestom.server.*; import net.minestom.server.collision.*; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -282,7 +283,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev * * @param position the teleport position * @param chunks the chunk indexes to load before teleporting the entity, - * indexes are from {@link ChunkUtils#getChunkIndex(int, int)}, + * indexes are from {@link CoordConversion#chunkIndex(int, int)}, * can be null or empty to only load the chunk at {@code position} * @param flags flags used to teleport the entity relatively rather than absolutely * use {@link RelativeFlags} to see available flags diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index c0bd8809b..1fb7b433d 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -29,9 +29,7 @@ import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.collision.BoundingBox; import net.minestom.server.command.CommandSender; -import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; +import net.minestom.server.coordinate.*; import net.minestom.server.effects.Effects; import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.damage.DamageType; @@ -88,8 +86,6 @@ import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.chunk.ChunkUpdateLimitChecker; -import net.minestom.server.utils.chunk.ChunkUtils; -import net.minestom.server.utils.function.IntegerBiConsumer; import net.minestom.server.utils.identity.NamedAndIdentified; import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.time.Cooldown; @@ -151,11 +147,11 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou private int maxChunkBatchLead = 1; // Maximum number of batches to send before waiting for a reply private int chunkBatchLead = 0; // Number of batches sent without a reply - final IntegerBiConsumer chunkAdder = (chunkX, chunkZ) -> { + final ChunkRange.ChunkConsumer chunkAdder = (chunkX, chunkZ) -> { // Load new chunks this.instance.loadOptionalChunk(chunkX, chunkZ).thenAccept(this::sendChunk); }; - final IntegerBiConsumer chunkRemover = (chunkX, chunkZ) -> { + final ChunkRange.ChunkConsumer chunkRemover = (chunkX, chunkZ) -> { // Unload old chunks sendPacket(new UnloadChunkPacket(chunkX, chunkZ)); EventDispatcher.call(new PlayerChunkUnloadEvent(this, chunkX, chunkZ)); @@ -524,7 +520,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou Pos respawnPosition = respawnEvent.getRespawnPosition(); // The client unloads chunks when respawning, so resend all chunks next to spawn - ChunkUtils.forChunksInRange(respawnPosition, settings.effectiveViewDistance(), chunkAdder); + ChunkRange.chunksInRange(respawnPosition, settings.effectiveViewDistance(), chunkAdder); chunksLoadedByClient = new Vec(respawnPosition.chunkX(), respawnPosition.chunkZ()); // Client also needs all entities resent to them, since those are unloaded as well this.instance.getEntityTracker().nearbyEntitiesByChunkRange(respawnPosition, settings.effectiveViewDistance(), @@ -590,7 +586,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou final int chunkX = position.chunkX(); final int chunkZ = position.chunkZ(); // Clear all viewable chunks - ChunkUtils.forChunksInRange(chunkX, chunkZ, settings.effectiveViewDistance(), chunkRemover); + ChunkRange.chunksInRange(chunkX, chunkZ, settings.effectiveViewDistance(), chunkRemover); // Remove from the tab-list PacketSendingUtils.broadcastPlayPacket(getRemovePlayerToList()); @@ -638,7 +634,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Ensure that surrounding chunks are loaded List> futures = new ArrayList<>(); - ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), (chunkX, chunkZ) -> { + ChunkRange.chunksInRange(spawnPosition, settings.effectiveViewDistance(), (chunkX, chunkZ) -> { final CompletableFuture future = instance.loadOptionalChunk(chunkX, chunkZ); if (!future.isDone()) futures.add(future); }); @@ -711,7 +707,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou if (!firstSpawn && !dimensionChange) { // Player instance changed, clear current viewable collections if (updateChunks) - ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkRemover); + ChunkRange.chunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkRemover); } if (dimensionChange) sendDimension(instance.getDimensionType(), instance.getDimensionName()); @@ -726,7 +722,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou sendPacket(new UpdateViewPositionPacket(chunkX, chunkZ)); // Load the nearby chunks and queue them to be sent to them - ChunkUtils.forChunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkAdder); + ChunkRange.chunksInRange(spawnPosition, settings.effectiveViewDistance(), chunkAdder); sendPendingChunks(); // Send available first chunk immediately to prevent falling through the floor } @@ -769,7 +765,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou if (!chunk.isLoaded()) return; chunkQueueLock.lock(); try { - chunkQueue.enqueue(ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ())); + chunkQueue.enqueue(CoordConversion.chunkIndex(chunk.getChunkX(), chunk.getChunkZ())); } finally { chunkQueueLock.unlock(); } @@ -789,7 +785,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou sendPacket(new ChunkBatchStartPacket()); while (!chunkQueue.isEmpty() && pendingChunkCount >= 1f) { long chunkIndex = chunkQueue.dequeueLong(); - int chunkX = ChunkUtils.getChunkCoordX(chunkIndex), chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex); + int chunkX = CoordConversion.chunkIndexGetX(chunkIndex), chunkZ = CoordConversion.chunkIndexGetZ(chunkIndex); var chunk = instance.getChunk(chunkX, chunkZ); if (chunk == null || !chunk.isLoaded()) continue; @@ -1564,14 +1560,14 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Load/unload chunks if necessary due to view distance changes if (previousViewDistance < newViewDistance) { // View distance expanded, send chunks - ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), newViewDistance, (chunkX, chunkZ) -> { + ChunkRange.chunksInRange(position.chunkX(), position.chunkZ(), newViewDistance, (chunkX, chunkZ) -> { if (Math.abs(chunkX - position.chunkX()) > previousViewDistance || Math.abs(chunkZ - position.chunkZ()) > previousViewDistance) { chunkAdder.accept(chunkX, chunkZ); } }); } else if (previousViewDistance > newViewDistance) { // View distance shrunk, unload chunks - ChunkUtils.forChunksInRange(position.chunkX(), position.chunkZ(), previousViewDistance, (chunkX, chunkZ) -> { + ChunkRange.chunksInRange(position.chunkX(), position.chunkZ(), previousViewDistance, (chunkX, chunkZ) -> { if (Math.abs(chunkX - position.chunkX()) > newViewDistance || Math.abs(chunkZ - position.chunkZ()) > newViewDistance) { chunkRemover.accept(chunkX, chunkZ); } @@ -2348,7 +2344,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou final int newZ = newChunk.getChunkZ(); final Vec old = chunksLoadedByClient; sendPacket(new UpdateViewPositionPacket(newX, newZ)); - ChunkUtils.forDifferingChunksInRange(newX, newZ, (int) old.x(), (int) old.z(), + ChunkRange.chunksInRangeDiffering(newX, newZ, (int) old.x(), (int) old.z(), settings.effectiveViewDistance(), chunkAdder, chunkRemover); this.chunksLoadedByClient = new Vec(newX, newZ); } @@ -2381,10 +2377,10 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Settings enum private int compareChunkDistance(long chunkIndexA, long chunkIndexB) { - int chunkAX = ChunkUtils.getChunkCoordX(chunkIndexA); - int chunkAZ = ChunkUtils.getChunkCoordZ(chunkIndexA); - int chunkBX = ChunkUtils.getChunkCoordX(chunkIndexB); - int chunkBZ = ChunkUtils.getChunkCoordZ(chunkIndexB); + int chunkAX = CoordConversion.chunkIndexGetX(chunkIndexA); + int chunkAZ = CoordConversion.chunkIndexGetZ(chunkIndexA); + int chunkBX = CoordConversion.chunkIndexGetX(chunkIndexB); + int chunkBZ = CoordConversion.chunkIndexGetZ(chunkIndexB); int chunkDistanceA = Math.abs(chunkAX - chunksLoadedByClient.blockX()) + Math.abs(chunkAZ - chunksLoadedByClient.blockZ()); int chunkDistanceB = Math.abs(chunkBX - chunksLoadedByClient.blockX()) + Math.abs(chunkBZ - chunksLoadedByClient.blockZ()); return Integer.compare(chunkDistanceA, chunkDistanceB); diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 631f14dbd..f6c8967fc 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -3,6 +3,7 @@ package net.minestom.server.instance; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.Tickable; import net.minestom.server.Viewable; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; @@ -16,7 +17,6 @@ import net.minestom.server.snapshot.Snapshotable; import net.minestom.server.tag.TagHandler; import net.minestom.server.tag.Taggable; import net.minestom.server.utils.chunk.ChunkSupplier; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.DimensionType; import net.minestom.server.world.biome.Biome; import org.jetbrains.annotations.ApiStatus; @@ -107,7 +107,7 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter, public abstract void loadHeightmapsFromNBT(CompoundBinaryTag heightmaps); public @NotNull Section getSectionAt(int blockY) { - return getSection(ChunkUtils.getChunkCoordinate(blockY)); + return getSection(CoordConversion.globalToChunk(blockY)); } /** diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 50ef4c9d2..dc89d31e3 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.LongArrayBinaryTag; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; @@ -25,7 +26,6 @@ import net.minestom.server.snapshot.ChunkSnapshot; import net.minestom.server.snapshot.SnapshotImpl; import net.minestom.server.snapshot.SnapshotUpdater; import net.minestom.server.utils.ArrayUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; import net.minestom.server.world.biome.Biome; @@ -36,8 +36,8 @@ import org.slf4j.LoggerFactory; import java.util.*; +import static net.minestom.server.coordinate.CoordConversion.globalToSectionRelative; import static net.minestom.server.network.NetworkBuffer.SHORT; -import static net.minestom.server.utils.chunk.ChunkUtils.toSectionRelativeCoordinate; /** * Represents a {@link Chunk} which store each individual block in memory. @@ -86,17 +86,17 @@ public class DynamicChunk extends Chunk { Section section = getSectionAt(y); - int sectionRelativeX = toSectionRelativeCoordinate(x); - int sectionRelativeZ = toSectionRelativeCoordinate(z); + int sectionRelativeX = globalToSectionRelative(x); + int sectionRelativeZ = globalToSectionRelative(z); section.blockPalette().set( sectionRelativeX, - toSectionRelativeCoordinate(y), + globalToSectionRelative(y), sectionRelativeZ, block.stateId() ); - final int index = ChunkUtils.getBlockIndex(x, y, z); + final int index = CoordConversion.chunkBlockIndex(x, y, z); // Handler final BlockHandler handler = block.handler(); final Block lastCachedBlock; @@ -144,9 +144,9 @@ public class DynamicChunk extends Chunk { if (id == -1) throw new IllegalStateException("Biome has not been registered: " + biome.namespace()); section.biomePalette().set( - toSectionRelativeCoordinate(x) / 4, - toSectionRelativeCoordinate(y) / 4, - toSectionRelativeCoordinate(z) / 4, id); + globalToSectionRelative(x) / 4, + globalToSectionRelative(y) / 4, + globalToSectionRelative(z) / 4, id); } @Override @@ -188,7 +188,7 @@ public class DynamicChunk extends Chunk { final Block block = entry.getValue(); final BlockHandler handler = block.handler(); if (handler == null) return; - final Point blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ); + final Point blockPosition = CoordConversion.chunkBlockIndexGetGlobal(index, chunkX, chunkZ); handler.tick(new BlockHandler.Tick(block, instance, blockPosition)); }); } @@ -202,7 +202,7 @@ public class DynamicChunk extends Chunk { // Verify if the block object is present if (condition != Condition.TYPE) { final Block entry = !entries.isEmpty() ? - entries.get(ChunkUtils.getBlockIndex(x, y, z)) : null; + entries.get(CoordConversion.chunkBlockIndex(x, y, z)) : null; if (entry != null || condition == Condition.CACHED) { return entry; } @@ -210,7 +210,7 @@ public class DynamicChunk extends Chunk { // Retrieve the block from state id final Section section = getSectionAt(y); final int blockStateId = section.blockPalette() - .get(toSectionRelativeCoordinate(x), toSectionRelativeCoordinate(y), toSectionRelativeCoordinate(z)); + .get(globalToSectionRelative(x), globalToSectionRelative(y), globalToSectionRelative(z)); return Objects.requireNonNullElse(Block.fromStateId((short) blockStateId), Block.AIR); } @@ -219,7 +219,7 @@ public class DynamicChunk extends Chunk { assertLock(); final Section section = getSectionAt(y); final int id = section.biomePalette() - .get(toSectionRelativeCoordinate(x) / 4, toSectionRelativeCoordinate(y) / 4, toSectionRelativeCoordinate(z) / 4); + .get(globalToSectionRelative(x) / 4, globalToSectionRelative(y) / 4, globalToSectionRelative(z) / 4); DynamicRegistry.Key biome = BIOME_REGISTRY.getKey(id); Check.notNull(biome, "Biome with id {0} is not registered", id); diff --git a/src/main/java/net/minestom/server/instance/EntityTrackerImpl.java b/src/main/java/net/minestom/server/instance/EntityTrackerImpl.java index 8b387f1da..9cf8b86de 100644 --- a/src/main/java/net/minestom/server/instance/EntityTrackerImpl.java +++ b/src/main/java/net/minestom/server/instance/EntityTrackerImpl.java @@ -3,11 +3,12 @@ package net.minestom.server.instance; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minestom.server.ServerFlag; import net.minestom.server.Viewable; +import net.minestom.server.coordinate.ChunkRange; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +28,6 @@ import java.util.function.Function; import static net.minestom.server.instance.Chunk.CHUNK_SIZE_X; import static net.minestom.server.instance.Chunk.CHUNK_SIZE_Z; -import static net.minestom.server.utils.chunk.ChunkUtils.*; final class EntityTrackerImpl implements EntityTracker { private static final Logger LOGGER = LoggerFactory.getLogger(EntityTrackerImpl.class); @@ -51,7 +51,7 @@ final class EntityTrackerImpl implements EntityTracker { EntityTrackerEntry prevEntryWithUuid = entriesByEntityUuid.putIfAbsent(entity.getUuid(), newEntry); Check.isTrue(prevEntryWithUuid == null, "There is already an entity registered with uuid {0}", entity.getUuid()); - final long index = getChunkIndex(point); + final long index = CoordConversion.chunkIndex(point); for (TargetEntry targetEntry : targetEntries) { if (targetEntry.target.type().isInstance(entity)) { targetEntry.entities.add(entity); @@ -75,7 +75,7 @@ final class EntityTrackerImpl implements EntityTracker { final Point point = entry == null ? null : entry.getLastPosition(); if (point == null) return; - final long index = getChunkIndex(point); + final long index = CoordConversion.chunkIndex(point); for (TargetEntry targetEntry : targetEntries) { if (targetEntry.target.type().isInstance(entity)) { targetEntry.entities.remove(entity); @@ -114,8 +114,8 @@ final class EntityTrackerImpl implements EntityTracker { Point oldPoint = entry.getLastPosition(); entry.setLastPosition(newPoint); if (oldPoint == null || oldPoint.sameChunk(newPoint)) return; - final long oldIndex = getChunkIndex(oldPoint); - final long newIndex = getChunkIndex(newPoint); + final long oldIndex = CoordConversion.chunkIndex(oldPoint); + final long newIndex = CoordConversion.chunkIndex(newPoint); for (TargetEntry targetEntry : targetEntries) { if (targetEntry.target.type().isInstance(entity)) { targetEntry.addToChunk(newIndex, entity); @@ -142,7 +142,7 @@ final class EntityTrackerImpl implements EntityTracker { public @Unmodifiable Collection chunkEntities(int chunkX, int chunkZ, @NotNull Target target) { final TargetEntry entry = targetEntries[target.ordinal()]; //noinspection unchecked - var chunkEntities = (List) entry.chunkEntities(getChunkIndex(chunkX, chunkZ)); + var chunkEntities = (List) entry.chunkEntities(CoordConversion.chunkIndex(chunkX, chunkZ)); return Collections.unmodifiableList(chunkEntities); } @@ -151,14 +151,14 @@ final class EntityTrackerImpl implements EntityTracker { final Long2ObjectSyncMap> entities = targetEntries[target.ordinal()].chunkEntities; if (chunkRange == 0) { // Single chunk - final var chunkEntities = (List) entities.get(getChunkIndex(point)); + final var chunkEntities = (List) entities.get(CoordConversion.chunkIndex(point)); if (chunkEntities != null && !chunkEntities.isEmpty()) { chunkEntities.forEach(query); } } else { // Multiple chunks - forChunksInRange(point, chunkRange, (chunkX, chunkZ) -> { - final var chunkEntities = (List) entities.get(getChunkIndex(chunkX, chunkZ)); + ChunkRange.chunksInRange(point, chunkRange, (chunkX, chunkZ) -> { + final var chunkEntities = (List) entities.get(CoordConversion.chunkIndex(chunkX, chunkZ)); if (chunkEntities == null || chunkEntities.isEmpty()) return; chunkEntities.forEach(query); }); @@ -168,14 +168,14 @@ final class EntityTrackerImpl implements EntityTracker { @Override public void nearbyEntities(@NotNull Point point, double range, @NotNull Target target, @NotNull Consumer query) { final Long2ObjectSyncMap> entities = targetEntries[target.ordinal()].chunkEntities; - final int minChunkX = ChunkUtils.getChunkCoordinate(point.x() - range); - final int minChunkZ = ChunkUtils.getChunkCoordinate(point.z() - range); - final int maxChunkX = ChunkUtils.getChunkCoordinate(point.x() + range); - final int maxChunkZ = ChunkUtils.getChunkCoordinate(point.z() + range); + final int minChunkX = CoordConversion.globalToChunk(point.x() - range); + final int minChunkZ = CoordConversion.globalToChunk(point.z() - range); + final int maxChunkX = CoordConversion.globalToChunk(point.x() + range); + final int maxChunkZ = CoordConversion.globalToChunk(point.z() + range); final double squaredRange = range * range; if (minChunkX == maxChunkX && minChunkZ == maxChunkZ) { // Single chunk - final var chunkEntities = (List) entities.get(getChunkIndex(point)); + final var chunkEntities = (List) entities.get(CoordConversion.chunkIndex(point)); if (chunkEntities != null && !chunkEntities.isEmpty()) { chunkEntities.forEach(entity -> { final Point position = entriesByEntityId.get(entity.getEntityId()).getLastPosition(); @@ -185,8 +185,8 @@ final class EntityTrackerImpl implements EntityTracker { } else { // Multiple chunks final int chunkRange = (int) (range / Chunk.CHUNK_SECTION_SIZE) + 1; - forChunksInRange(point, chunkRange, (chunkX, chunkZ) -> { - final var chunkEntities = (List) entities.get(getChunkIndex(chunkX, chunkZ)); + ChunkRange.chunksInRange(point, chunkRange, (chunkX, chunkZ) -> { + final var chunkEntities = (List) entities.get(CoordConversion.chunkIndex(chunkX, chunkZ)); if (chunkEntities == null || chunkEntities.isEmpty()) return; chunkEntities.forEach(entity -> { final Point position = entriesByEntityId.get(entity.getEntityId()).getLastPosition(); @@ -236,15 +236,15 @@ final class EntityTrackerImpl implements EntityTracker { private void difference(Point oldPoint, Point newPoint, @NotNull Target target, @NotNull Update update) { final TargetEntry entry = targetEntries[target.ordinal()]; - forDifferingChunksInRange(newPoint.chunkX(), newPoint.chunkZ(), oldPoint.chunkX(), oldPoint.chunkZ(), + ChunkRange.chunksInRangeDiffering(newPoint.chunkX(), newPoint.chunkZ(), oldPoint.chunkX(), oldPoint.chunkZ(), ServerFlag.ENTITY_VIEW_DISTANCE, (chunkX, chunkZ) -> { // Add - final List entities = entry.chunkEntities.get(getChunkIndex(chunkX, chunkZ)); + final List entities = entry.chunkEntities.get(CoordConversion.chunkIndex(chunkX, chunkZ)); if (entities == null || entities.isEmpty()) return; for (Entity entity : entities) update.add((T) entity); }, (chunkX, chunkZ) -> { // Remove - final List entities = entry.chunkEntities.get(getChunkIndex(chunkX, chunkZ)); + final List entities = entry.chunkEntities.get(CoordConversion.chunkIndex(chunkX, chunkZ)); if (entities == null || entities.isEmpty()) return; for (Entity entity : entities) update.remove((T) entity); }); diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index b5b28d3cc..26dea6acd 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -12,6 +12,7 @@ import net.minestom.server.ServerProcess; import net.minestom.server.Tickable; import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.audience.PacketGroupingAudience; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityCreature; @@ -44,7 +45,6 @@ import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.PacketSendingUtils; import net.minestom.server.utils.chunk.ChunkCache; import net.minestom.server.utils.chunk.ChunkSupplier; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; import org.jetbrains.annotations.ApiStatus; @@ -210,8 +210,8 @@ public abstract class Instance implements Block.Getter, Block.Setter, * Does call {@link net.minestom.server.event.player.PlayerBlockBreakEvent} * and send particle packets * - * @param player the {@link Player} who break the block - * @param blockPosition the position of the broken block + * @param player the {@link Player} who break the block + * @param blockPosition the position of the broken block * @param doBlockUpdates true to do block updates, false otherwise * @return true if the block has been broken, false if it has been cancelled */ @@ -335,6 +335,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, /** * Gets the chunk supplier of the instance. + * * @return the chunk supplier of the instance */ public abstract ChunkSupplier getChunkSupplier(); @@ -419,6 +420,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, /** * Gets the instance dimension name. + * * @return the dimension name of the instance */ public @NotNull String getDimensionName() { @@ -547,10 +549,9 @@ public abstract class Instance implements Block.Getter, Block.Setter, /** * Set the instance {@link WorldBorder} with a smooth transition. * - * @param worldBorder the desired final state of the world border + * @param worldBorder the desired final state of the world border * @param transitionTime the time in seconds this world border's diameter * will transition for (0 makes this instant) - * */ public void setWorldBorder(@NotNull WorldBorder worldBorder, double transitionTime) { Check.stateCondition(transitionTime < 0, "Transition time cannot be lower than 0"); @@ -588,13 +589,15 @@ public abstract class Instance implements Block.Getter, Block.Setter, if (this.worldBorder.centerX() != newBorder.centerX() || this.worldBorder.centerZ() != newBorder.centerZ()) { sendGroupedPacket(newBorder.createCenterPacket()); } - if (this.worldBorder.warningTime() != newBorder.warningTime()) sendGroupedPacket(newBorder.createWarningDelayPacket()); - if (this.worldBorder.warningDistance() != newBorder.warningDistance()) sendGroupedPacket(newBorder.createWarningReachPacket()); + if (this.worldBorder.warningTime() != newBorder.warningTime()) + sendGroupedPacket(newBorder.createWarningDelayPacket()); + if (this.worldBorder.warningDistance() != newBorder.warningDistance()) + sendGroupedPacket(newBorder.createWarningReachPacket()); } private @NotNull WorldBorder transitionWorldBorder(long remainingTicks) { if (remainingTicks <= 1) return worldBorder.withDiameter(targetBorderDiameter); - return worldBorder.withDiameter(worldBorder.diameter() + (targetBorderDiameter - worldBorder.diameter()) * (1 / (double)remainingTicks)); + return worldBorder.withDiameter(worldBorder.diameter() + (targetBorderDiameter - worldBorder.diameter()) * (1 / (double) remainingTicks)); } /** @@ -731,7 +734,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, * @return the chunk at the given position, null if not loaded */ public @Nullable Chunk getChunkAt(double x, double z) { - return getChunk(ChunkUtils.getChunkCoordinate(x), ChunkUtils.getChunkCoordinate(z)); + return getChunk(CoordConversion.globalToChunk(x), CoordConversion.globalToChunk(z)); } /** @@ -815,7 +818,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, /** * Sets the weather on this instance, transitions over time * - * @param weather the new weather + * @param weather the new weather * @param transitionTicks the ticks to transition to new weather */ public void setWeather(@NotNull Weather weather, int transitionTicks) { @@ -839,15 +842,17 @@ public abstract class Instance implements Block.Getter, Block.Setter, private void sendWeatherPackets(@NotNull Weather previousWeather) { boolean toggledRain = (transitioningWeather.isRaining() != previousWeather.isRaining()); if (toggledRain) sendGroupedPacket(transitioningWeather.createIsRainingPacket()); - if (transitioningWeather.rainLevel() != previousWeather.rainLevel()) sendGroupedPacket(transitioningWeather.createRainLevelPacket()); - if (transitioningWeather.thunderLevel() != previousWeather.thunderLevel()) sendGroupedPacket(transitioningWeather.createThunderLevelPacket()); + if (transitioningWeather.rainLevel() != previousWeather.rainLevel()) + sendGroupedPacket(transitioningWeather.createRainLevelPacket()); + if (transitioningWeather.thunderLevel() != previousWeather.thunderLevel()) + sendGroupedPacket(transitioningWeather.createThunderLevelPacket()); } private @NotNull Weather transitionWeather(int remainingRainTransitionTicks, int remainingThunderTransitionTicks) { Weather target = weather; Weather current = transitioningWeather; - float rainLevel = current.rainLevel() + (target.rainLevel() - current.rainLevel()) * (1 / (float)Math.max(1, remainingRainTransitionTicks)); - float thunderLevel = current.thunderLevel() + (target.thunderLevel() - current.thunderLevel()) * (1 / (float)Math.max(1, remainingThunderTransitionTicks)); + float rainLevel = current.rainLevel() + (target.rainLevel() - current.rainLevel()) * (1 / (float) Math.max(1, remainingRainTransitionTicks)); + float thunderLevel = current.thunderLevel() + (target.thunderLevel() - current.thunderLevel()) * (1 / (float) Math.max(1, remainingThunderTransitionTicks)); return new Weather(rainLevel, thunderLevel); } @@ -869,7 +874,8 @@ public abstract class Instance implements Block.Getter, Block.Setter, @Override public @NotNull InstanceSnapshot updateSnapshot(@NotNull SnapshotUpdater updater) { - final Map> chunksMap = updater.referencesMapLong(getChunks(), ChunkUtils::getChunkIndex); + final Map> chunksMap = updater.referencesMapLong(getChunks(), + value -> CoordConversion.chunkIndex(value.getChunkX(), value.getChunkZ())); final int[] entities = ArrayUtils.mapToIntArray(entityTracker.entities(), Entity::getEntityId); return new SnapshotImpl.Instance(updater.reference(MinecraftServer.process()), getDimensionType(), getWorldAge(), getTime(), chunksMap, entities, @@ -964,13 +970,14 @@ public abstract class Instance implements Block.Getter, Block.Setter, if (chunk == null) return 0; Section section = chunk.getSectionAt(blockY); Light light = section.blockLight(); - int sectionCoordinate = ChunkUtils.getChunkCoordinate(blockY); + int sectionCoordinate = CoordConversion.globalToChunk(blockY); - int coordX = ChunkUtils.toSectionRelativeCoordinate(blockX); - int coordY = ChunkUtils.toSectionRelativeCoordinate(blockY); - int coordZ = ChunkUtils.toSectionRelativeCoordinate(blockZ); + int coordX = CoordConversion.globalToSectionRelative(blockX); + int coordY = CoordConversion.globalToSectionRelative(blockY); + int coordZ = CoordConversion.globalToSectionRelative(blockZ); - if (light.requiresUpdate()) LightingChunk.relightSection(chunk.getInstance(), chunk.chunkX, sectionCoordinate, chunk.chunkZ); + if (light.requiresUpdate()) + LightingChunk.relightSection(chunk.getInstance(), chunk.chunkX, sectionCoordinate, chunk.chunkZ); return light.getLevel(coordX, coordY, coordZ); } @@ -979,13 +986,14 @@ public abstract class Instance implements Block.Getter, Block.Setter, if (chunk == null) return 0; Section section = chunk.getSectionAt(blockY); Light light = section.skyLight(); - int sectionCoordinate = ChunkUtils.getChunkCoordinate(blockY); + int sectionCoordinate = CoordConversion.globalToChunk(blockY); - int coordX = ChunkUtils.toSectionRelativeCoordinate(blockX); - int coordY = ChunkUtils.toSectionRelativeCoordinate(blockY); - int coordZ = ChunkUtils.toSectionRelativeCoordinate(blockZ); + int coordX = CoordConversion.globalToSectionRelative(blockX); + int coordY = CoordConversion.globalToSectionRelative(blockY); + int coordZ = CoordConversion.globalToSectionRelative(blockZ); - if (light.requiresUpdate()) LightingChunk.relightSection(chunk.getInstance(), chunk.chunkX, sectionCoordinate, chunk.chunkZ); + if (light.requiresUpdate()) + LightingChunk.relightSection(chunk.getInstance(), chunk.chunkX, sectionCoordinate, chunk.chunkZ); return light.getLevel(coordX, coordY, coordZ); } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index cac12b2b2..a5e1f8983 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.BlockVec; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; @@ -31,7 +32,6 @@ import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.block.BlockUtils; import net.minestom.server.utils.chunk.ChunkCache; import net.minestom.server.utils.chunk.ChunkSupplier; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.DimensionType; import org.jetbrains.annotations.NotNull; @@ -49,7 +49,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; -import static net.minestom.server.utils.chunk.ChunkUtils.*; +import static net.minestom.server.utils.chunk.ChunkUtils.isLoaded; /** * InstanceContainer is an instance that contains chunks in contrary to SharedInstance. @@ -124,7 +124,7 @@ public class InstanceContainer extends Instance { if (chunk == null) { Check.stateCondition(!hasEnabledAutoChunkLoad(), "Tried to set a block to an unloaded chunk with auto chunk load disabled"); - chunk = loadChunk(getChunkCoordinate(x), getChunkCoordinate(z)).join(); + chunk = loadChunk(CoordConversion.globalToChunk(x), CoordConversion.globalToChunk(z)).join(); } if (isLoaded(chunk)) UNSAFE_setBlock(chunk, x, y, z, block, null, null, doBlockUpdates, 0); } @@ -268,7 +268,7 @@ public class InstanceContainer extends Instance { // Remove all entities in chunk getEntityTracker().chunkEntities(chunkX, chunkZ, EntityTracker.Target.ENTITIES).forEach(Entity::remove); // Clear cache - this.chunks.remove(getChunkIndex(chunkX, chunkZ)); + this.chunks.remove(CoordConversion.chunkIndex(chunkX, chunkZ)); chunk.unload(); chunkLoader.unloadChunk(chunk); var dispatcher = MinecraftServer.process().dispatcher(); @@ -277,7 +277,7 @@ public class InstanceContainer extends Instance { @Override public Chunk getChunk(int chunkX, int chunkZ) { - return chunks.get(getChunkIndex(chunkX, chunkZ)); + return chunks.get(CoordConversion.chunkIndex(chunkX, chunkZ)); } @Override @@ -297,7 +297,7 @@ public class InstanceContainer extends Instance { protected @NotNull CompletableFuture<@NotNull Chunk> retrieveChunk(int chunkX, int chunkZ) { CompletableFuture completableFuture = new CompletableFuture<>(); - final long index = getChunkIndex(chunkX, chunkZ); + final long index = CoordConversion.chunkIndex(chunkX, chunkZ); final CompletableFuture prev = loadingChunks.putIfAbsent(index, completableFuture); if (prev != null) return prev; final IChunkLoader loader = chunkLoader; @@ -377,7 +377,7 @@ public class InstanceContainer extends Instance { forkChunk.invalidate(); forkChunk.sendChunk(); } else { - final long index = getChunkIndex(start); + final long index = CoordConversion.chunkIndex(start); this.generationForks.compute(index, (i, sectionModifiers) -> { if (sectionModifiers == null) sectionModifiers = new ArrayList<>(); sectionModifiers.add(sectionModifier); @@ -406,7 +406,7 @@ public class InstanceContainer extends Instance { } private void processFork(Chunk chunk) { - this.generationForks.compute(ChunkUtils.getChunkIndex(chunk), (aLong, sectionModifiers) -> { + this.generationForks.compute(CoordConversion.chunkIndex(chunk.getChunkX(), chunk.getChunkZ()), (aLong, sectionModifiers) -> { if (sectionModifiers != null) { for (var sectionModifier : sectionModifiers) { applyFork(chunk, sectionModifier); @@ -434,9 +434,9 @@ public class InstanceContainer extends Instance { Int2ObjectMaps.fastForEach(cache, blockEntry -> { final int index = blockEntry.getIntKey(); final Block block = blockEntry.getValue(); - final int x = ChunkUtils.blockIndexToChunkPositionX(index); - final int y = ChunkUtils.blockIndexToChunkPositionY(index) + height; - final int z = ChunkUtils.blockIndexToChunkPositionZ(index); + final int x = CoordConversion.chunkBlockIndexGetX(index); + final int y = CoordConversion.chunkBlockIndexGetY(index) + height; + final int z = CoordConversion.chunkBlockIndexGetZ(index); chunk.setBlock(x, y, z, block); }); } @@ -652,7 +652,8 @@ public class InstanceContainer extends Instance { if (neighborBlock == null || neighborBlock.isAir()) continue; final BlockPlacementRule neighborBlockPlacementRule = MinecraftServer.getBlockManager().getBlockPlacementRule(neighborBlock); - if (neighborBlockPlacementRule == null || updateDistance >= neighborBlockPlacementRule.maxUpdateDistance()) continue; + if (neighborBlockPlacementRule == null || updateDistance >= neighborBlockPlacementRule.maxUpdateDistance()) + continue; final Vec neighborPosition = new Vec(neighborX, neighborY, neighborZ); final Block newNeighborBlock = neighborBlockPlacementRule.blockUpdate(new BlockPlacementRule.UpdateState( @@ -680,7 +681,7 @@ public class InstanceContainer extends Instance { } private void cacheChunk(@NotNull Chunk chunk) { - this.chunks.put(getChunkIndex(chunk), chunk); + this.chunks.put(CoordConversion.chunkIndex(chunk.getChunkX(), chunk.getChunkZ()), chunk); var dispatcher = MinecraftServer.process().dispatcher(); dispatcher.createPartition(chunk); } diff --git a/src/main/java/net/minestom/server/instance/LightingChunk.java b/src/main/java/net/minestom/server/instance/LightingChunk.java index eefa76850..c8872e363 100644 --- a/src/main/java/net/minestom/server/instance/LightingChunk.java +++ b/src/main/java/net/minestom/server/instance/LightingChunk.java @@ -2,6 +2,7 @@ package net.minestom.server.instance; import net.minestom.server.ServerFlag; import net.minestom.server.collision.Shape; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; @@ -13,7 +14,6 @@ import net.minestom.server.instance.palette.Palette; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.play.data.LightData; import net.minestom.server.utils.NamespaceID; -import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -160,7 +160,7 @@ public class LightingChunk extends DynamicChunk { this.occlusionMap = null; // Invalidate neighbor chunks, since they can be updated by this block change - int coordinate = ChunkUtils.getChunkCoordinate(y); + int coordinate = CoordConversion.globalToChunk(y); if (doneInit && !freezeInvalidation) { invalidateNeighborsSection(coordinate); invalidateResendDelay(); diff --git a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java index c4790e64e..ee03276a4 100644 --- a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java +++ b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java @@ -3,6 +3,7 @@ package net.minestom.server.instance.anvil; import it.unimi.dsi.fastutil.ints.*; import net.kyori.adventure.nbt.*; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.IChunkLoader; import net.minestom.server.instance.Instance; @@ -14,7 +15,6 @@ import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.async.AsyncUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.biome.Biome; import org.jetbrains.annotations.NotNull; @@ -126,8 +126,8 @@ public class AnvilLoader implements IChunkLoader { // Cache the index of the loaded chunk perRegionLoadedChunksLock.lock(); try { - int regionX = ChunkUtils.toRegionCoordinate(chunkX); - int regionZ = ChunkUtils.toRegionCoordinate(chunkZ); + int regionX = CoordConversion.chunkToRegion(chunkX); + int regionZ = CoordConversion.chunkToRegion(chunkZ); var chunks = perRegionLoadedChunks.computeIfAbsent(new IntIntImmutablePair(regionX, regionZ), r -> new HashSet<>()); // region cache may have been removed on another thread due to unloadChunk chunks.add(new IntIntImmutablePair(chunkX, chunkZ)); } finally { @@ -137,8 +137,8 @@ public class AnvilLoader implements IChunkLoader { } private @Nullable RegionFile getMCAFile(int chunkX, int chunkZ) { - final int regionX = ChunkUtils.toRegionCoordinate(chunkX); - final int regionZ = ChunkUtils.toRegionCoordinate(chunkZ); + final int regionX = CoordConversion.chunkToRegion(chunkX); + final int regionZ = CoordConversion.chunkToRegion(chunkZ); return alreadyLoaded.computeIfAbsent(RegionFile.getFileName(regionX, regionZ), n -> { final Path regionPath = this.regionPath.resolve(n); if (!Files.exists(regionPath)) { @@ -334,8 +334,8 @@ public class AnvilLoader implements IChunkLoader { try { mcaFile = getMCAFile(chunkX, chunkZ); if (mcaFile == null) { - final int regionX = ChunkUtils.toRegionCoordinate(chunkX); - final int regionZ = ChunkUtils.toRegionCoordinate(chunkZ); + final int regionX = CoordConversion.chunkToRegion(chunkX); + final int regionZ = CoordConversion.chunkToRegion(chunkZ); final String regionFileName = RegionFile.getFileName(regionX, regionZ); try { Path regionFile = regionPath.resolve(regionFileName); @@ -521,8 +521,8 @@ public class AnvilLoader implements IChunkLoader { */ @Override public void unloadChunk(Chunk chunk) { - final int regionX = ChunkUtils.toRegionCoordinate(chunk.getChunkX()); - final int regionZ = ChunkUtils.toRegionCoordinate(chunk.getChunkZ()); + final int regionX = CoordConversion.chunkToRegion(chunk.getChunkX()); + final int regionZ = CoordConversion.chunkToRegion(chunk.getChunkZ()); final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ); perRegionLoadedChunksLock.lock(); diff --git a/src/main/java/net/minestom/server/instance/anvil/RegionFile.java b/src/main/java/net/minestom/server/instance/anvil/RegionFile.java index 3014ab9a1..5c55c9229 100644 --- a/src/main/java/net/minestom/server/instance/anvil/RegionFile.java +++ b/src/main/java/net/minestom/server/instance/anvil/RegionFile.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.booleans.BooleanArrayList; import it.unimi.dsi.fastutil.booleans.BooleanList; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.minestom.server.utils.chunk.ChunkUtils; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -137,7 +137,7 @@ final class RegionFile implements AutoCloseable { } private int getChunkIndex(int chunkX, int chunkZ) { - return (ChunkUtils.toRegionLocal(chunkZ) << 5) | ChunkUtils.toRegionLocal(chunkX); + return (CoordConversion.chunkToRegionLocal(chunkZ) << 5) | CoordConversion.chunkToRegionLocal(chunkX); } private void readHeader() throws IOException { diff --git a/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java b/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java index 3177ebb6b..fab26d9f3 100644 --- a/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/AbsoluteBlockBatch.java @@ -3,12 +3,12 @@ package net.minestom.server.instance.batch; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.LightingChunk; import net.minestom.server.instance.block.Block; -import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,9 +54,9 @@ public class AbsoluteBlockBatch implements Batch { @Override public void setBlock(int x, int y, int z, @NotNull Block block) { - final int chunkX = ChunkUtils.getChunkCoordinate(x); - final int chunkZ = ChunkUtils.getChunkCoordinate(z); - final long chunkIndex = ChunkUtils.getChunkIndex(chunkX, chunkZ); + final int chunkX = CoordConversion.globalToChunk(x); + final int chunkZ = CoordConversion.globalToChunk(z); + final long chunkIndex = CoordConversion.chunkIndex(chunkX, chunkZ); final ChunkBatch chunkBatch; synchronized (chunkBatchesMap) { @@ -132,8 +132,8 @@ public class AbsoluteBlockBatch implements Batch { for (var entry : Long2ObjectMaps.fastIterable(chunkBatchesMap)) { final long chunkIndex = entry.getLongKey(); - final int chunkX = ChunkUtils.getChunkCoordX(chunkIndex); - final int chunkZ = ChunkUtils.getChunkCoordZ(chunkIndex); + final int chunkX = CoordConversion.chunkIndexGetX(chunkIndex); + final int chunkZ = CoordConversion.chunkIndexGetZ(chunkIndex); final ChunkBatch batch = entry.getValue(); ChunkBatch chunkInverse = batch.apply(instance, chunkX, chunkZ, c -> { final boolean isLast = counter.incrementAndGet() == chunkBatchesMap.size(); diff --git a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java index c427442a9..f6ac7795d 100644 --- a/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java +++ b/src/main/java/net/minestom/server/instance/batch/ChunkBatch.java @@ -4,13 +4,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntSet; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.block.Block; import net.minestom.server.utils.callback.OptionalCallback; import net.minestom.server.utils.chunk.ChunkCallback; -import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -54,7 +54,7 @@ public class ChunkBatch implements Batch { @Override public void setBlock(int x, int y, int z, @NotNull Block block) { - final int index = ChunkUtils.getBlockIndex(x, y, z); + final int index = CoordConversion.chunkBlockIndex(x, y, z); synchronized (blocks) { this.blocks.put(index, block); } @@ -201,20 +201,20 @@ public class ChunkBatch implements Batch { * Applies a single block change given a chunk and a value in the described format. * * @param chunk The chunk to apply the change - * @param index the block position computed using {@link ChunkUtils#getBlockIndex(int, int, int)} + * @param index the block position computed using {@link CoordConversion#chunkBlockIndex(int, int, int)} * @param block the block to place * @return The chunk section which the block was placed */ private int apply(@NotNull Chunk chunk, int index, Block block, @Nullable ChunkBatch inverse) { - final int x = ChunkUtils.blockIndexToChunkPositionX(index); - final int y = ChunkUtils.blockIndexToChunkPositionY(index); - final int z = ChunkUtils.blockIndexToChunkPositionZ(index); + final int x = CoordConversion.chunkBlockIndexGetX(index); + final int y = CoordConversion.chunkBlockIndexGetY(index); + final int z = CoordConversion.chunkBlockIndexGetZ(index); if (inverse != null) { Block prevBlock = chunk.getBlock(x, y, z); inverse.setBlock(x, y, z, prevBlock); } chunk.setBlock(x, y, z, block); - return ChunkUtils.getChunkCoordinate(y); + return CoordConversion.globalToChunk(y); } /** diff --git a/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java b/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java index 9d41bc7f2..d940d7096 100644 --- a/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java +++ b/src/main/java/net/minestom/server/instance/generator/GeneratorImpl.java @@ -18,7 +18,7 @@ import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; -import static net.minestom.server.utils.chunk.ChunkUtils.*; +import static net.minestom.server.coordinate.CoordConversion.*; @ApiStatus.Internal public final class GeneratorImpl { @@ -105,17 +105,17 @@ public final class GeneratorImpl { public void setBlock(int x, int y, int z, @NotNull Block block) { resize(x, y, z); GenerationUnit section = findAbsolute(sections, minSection, width, height, depth, x, y, z); - assert section.absoluteStart().chunkX() == getChunkCoordinate(x) && - section.absoluteStart().section() == getChunkCoordinate(y) && - section.absoluteStart().chunkZ() == getChunkCoordinate(z) : + assert section.absoluteStart().chunkX() == globalToChunk(x) && + section.absoluteStart().section() == globalToChunk(y) && + section.absoluteStart().chunkZ() == globalToChunk(z) : "Invalid section " + section.absoluteStart() + " for " + x + ", " + y + ", " + z; section.modifier().setBlock(x, y, z, block); } private void resize(int x, int y, int z) { - final int sectionX = getChunkCoordinate(x); - final int sectionY = getChunkCoordinate(y); - final int sectionZ = getChunkCoordinate(z); + final int sectionX = globalToChunk(x); + final int sectionY = globalToChunk(y); + final int sectionZ = globalToChunk(z); if (sections == null) { this.minSection = Vec.SECTION.mul(sectionX, sectionY, sectionZ); this.width = 1; @@ -131,17 +131,17 @@ public final class GeneratorImpl { final Vec newMax = new Vec(Math.max(minSection.x() + width * 16, sectionX * 16 + 16), Math.max(minSection.y() + height * 16, sectionY * 16 + 16), Math.max(minSection.z() + depth * 16, sectionZ * 16 + 16)); - final int newWidth = getChunkCoordinate(newMax.x() - newMin.x()); - final int newHeight = getChunkCoordinate(newMax.y() - newMin.y()); - final int newDepth = getChunkCoordinate(newMax.z() - newMin.z()); + final int newWidth = globalToChunk(newMax.x() - newMin.x()); + final int newHeight = globalToChunk(newMax.y() - newMin.y()); + final int newDepth = globalToChunk(newMax.z() - newMin.z()); // Resize GenerationUnit[] newSections = new GenerationUnit[newWidth * newHeight * newDepth]; // Copy old sections for (GenerationUnit s : sections) { final Point start = s.absoluteStart(); - final int newX = getChunkCoordinate(start.x() - newMin.x()); - final int newY = getChunkCoordinate(start.y() - newMin.y()); - final int newZ = getChunkCoordinate(start.z() - newMin.z()); + final int newX = globalToChunk(start.x() - newMin.x()); + final int newY = globalToChunk(start.y() - newMin.y()); + final int newZ = globalToChunk(start.z() - newMin.z()); final int index = findIndex(newWidth, newHeight, newDepth, newX, newY, newZ); newSections[index] = s; } @@ -241,16 +241,16 @@ public final class GeneratorImpl { final int id = biomeRegistry.getId(biome); Check.argCondition(id == -1, "Biome has not been registered: {0}", biome); this.genSection.biomes.set( - toSectionRelativeCoordinate(x) / 4, - toSectionRelativeCoordinate(y) / 4, - toSectionRelativeCoordinate(z) / 4, id); + globalToSectionRelative(x) / 4, + globalToSectionRelative(y) / 4, + globalToSectionRelative(z) / 4, id); } @Override public void setBlock(int x, int y, int z, @NotNull Block block) { - final int localX = toSectionRelativeCoordinate(x); - final int localY = toSectionRelativeCoordinate(y); - final int localZ = toSectionRelativeCoordinate(z); + final int localX = globalToSectionRelative(x); + final int localY = globalToSectionRelative(y); + final int localZ = globalToSectionRelative(z); handleCache(localX, localY, localZ, block); this.genSection.blocks.set(localX, localY, localZ, retrieveBlockId(block)); } @@ -276,7 +276,7 @@ public final class GeneratorImpl { for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { - this.genSection.specials.put(getBlockIndex(x, y, z), block); + this.genSection.specials.put(chunkBlockIndex(x, y, z), block); } } } @@ -299,9 +299,9 @@ public final class GeneratorImpl { private void handleCache(int x, int y, int z, Block block) { if (requireCache(block)) { - this.genSection.specials.put(getBlockIndex(x, y, z), block); + this.genSection.specials.put(chunkBlockIndex(x, y, z), block); } else if (!genSection.specials.isEmpty()) { - this.genSection.specials.remove(getBlockIndex(x, y, z)); + this.genSection.specials.remove(chunkBlockIndex(x, y, z)); } } @@ -335,9 +335,9 @@ public final class GeneratorImpl { throw new IllegalArgumentException("x, y and z must be in the chunk: " + x + ", " + y + ", " + z); } final GenerationUnit section = findRelativeSection(x, y, z); - x = toSectionRelativeCoordinate(x); - y = toSectionRelativeCoordinate(y); - z = toSectionRelativeCoordinate(z); + x = globalToSectionRelative(x); + y = globalToSectionRelative(y); + z = globalToSectionRelative(z); section.modifier().setBlock(x, y, z, block); } @@ -519,9 +519,9 @@ public final class GeneratorImpl { private static GenerationUnit findAbsolute(List units, Point start, int width, int height, int depth, int x, int y, int z) { - final int sectionX = getChunkCoordinate(x - start.x()); - final int sectionY = getChunkCoordinate(y - start.y()); - final int sectionZ = getChunkCoordinate(z - start.z()); + final int sectionX = globalToChunk(x - start.x()); + final int sectionY = globalToChunk(y - start.y()); + final int sectionZ = globalToChunk(z - start.z()); final int index = findIndex(width, height, depth, sectionX, sectionY, sectionZ); return units.get(index); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java index c0ea0fbdc..d76d7844f 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/data/ChunkData.java @@ -1,11 +1,11 @@ package net.minestom.server.network.packet.server.play.data; import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.block.BlockUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -37,7 +37,7 @@ public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] final Block block = entry.getValue(); final var registry = block.registry(); - final Point point = ChunkUtils.getBlockPosition(index, 0, 0); + final Point point = CoordConversion.chunkBlockIndexGetGlobal(index, 0, 0); buffer.write(BYTE, (byte) ((point.blockX() & 15) << 4 | point.blockZ() & 15)); // xz buffer.write(SHORT, (short) point.blockY()); // y diff --git a/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java b/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java index 714a2da6d..376923d6e 100644 --- a/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java @@ -1,5 +1,6 @@ package net.minestom.server.snapshot; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.registry.DynamicRegistry; @@ -13,8 +14,6 @@ import org.jetbrains.annotations.UnknownNullability; import java.util.Collection; import java.util.Objects; -import static net.minestom.server.utils.chunk.ChunkUtils.getChunkCoordinate; - public sealed interface InstanceSnapshot extends Snapshot, Block.Getter, Biome.Getter, TagReadable permits SnapshotImpl.Instance { @NotNull DynamicRegistry.Key dimensionType(); @@ -25,13 +24,13 @@ public sealed interface InstanceSnapshot extends Snapshot, Block.Getter, Biome.G @Override default @UnknownNullability Block getBlock(int x, int y, int z, @NotNull Condition condition) { - ChunkSnapshot chunk = chunk(getChunkCoordinate(x), getChunkCoordinate(z)); + ChunkSnapshot chunk = chunk(CoordConversion.globalToChunk(x), CoordConversion.globalToChunk(z)); return Objects.requireNonNull(chunk).getBlock(x, y, z, condition); } @Override default @NotNull DynamicRegistry.Key getBiome(int x, int y, int z) { - ChunkSnapshot chunk = chunk(getChunkCoordinate(x), getChunkCoordinate(z)); + ChunkSnapshot chunk = chunk(CoordConversion.globalToChunk(x), CoordConversion.globalToChunk(z)); return Objects.requireNonNull(chunk).getBiome(x, y, z); } diff --git a/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java b/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java index 839c0e2d9..02e753b8a 100644 --- a/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java +++ b/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java @@ -27,7 +27,7 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; -import static net.minestom.server.utils.chunk.ChunkUtils.*; +import static net.minestom.server.coordinate.CoordConversion.*; @ApiStatus.Internal public final class SnapshotImpl { @@ -52,7 +52,7 @@ public final class SnapshotImpl { TagReadable tagReadable) implements InstanceSnapshot { @Override public @Nullable ChunkSnapshot chunk(int chunkX, int chunkZ) { - var ref = chunksMap.get(getChunkIndex(chunkX, chunkZ)); + var ref = chunksMap.get(chunkIndex(chunkX, chunkZ)); return Objects.requireNonNull(ref, "Chunk not found").getPlain(); } @@ -88,23 +88,23 @@ public final class SnapshotImpl { // Verify if the block object is present if (condition != Condition.TYPE) { final Block entry = !blockEntries.isEmpty() ? - blockEntries.get(getBlockIndex(x, y, z)) : null; + blockEntries.get(chunkBlockIndex(x, y, z)) : null; if (entry != null || condition == Condition.CACHED) { return entry; } } // Retrieve the block from state id - final Section section = sections[getChunkCoordinate(y) - minSection]; + final Section section = sections[globalToChunk(y) - minSection]; final int blockStateId = section.blockPalette() - .get(toSectionRelativeCoordinate(x), toSectionRelativeCoordinate(y), toSectionRelativeCoordinate(z)); + .get(globalToSectionRelative(x), globalToSectionRelative(y), globalToSectionRelative(z)); return Objects.requireNonNullElse(Block.fromStateId((short) blockStateId), Block.AIR); } @Override public @NotNull DynamicRegistry.Key getBiome(int x, int y, int z) { - final Section section = sections[getChunkCoordinate(y) - minSection]; + final Section section = sections[globalToChunk(y) - minSection]; final int id = section.biomePalette() - .get(toSectionRelativeCoordinate(x) / 4, toSectionRelativeCoordinate(y) / 4, toSectionRelativeCoordinate(z) / 4); + .get(globalToSectionRelative(x) / 4, globalToSectionRelative(y) / 4, globalToSectionRelative(z) / 4); DynamicRegistry.Key key = MinecraftServer.getBiomeRegistry().getKey(id); Check.notNull(key, "Biome with id {0} is not registered", id); return key; diff --git a/src/main/java/net/minestom/server/utils/chunk/ChunkCache.java b/src/main/java/net/minestom/server/utils/chunk/ChunkCache.java index 022b8b48e..c23aa9708 100644 --- a/src/main/java/net/minestom/server/utils/chunk/ChunkCache.java +++ b/src/main/java/net/minestom/server/utils/chunk/ChunkCache.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.chunk; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; @@ -7,8 +8,6 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.UnknownNullability; -import static net.minestom.server.utils.chunk.ChunkUtils.getChunkCoordinate; - @ApiStatus.Internal public final class ChunkCache implements Block.Getter { private final Instance instance; @@ -30,8 +29,8 @@ public final class ChunkCache implements Block.Getter { @Override public @UnknownNullability Block getBlock(int x, int y, int z, @NotNull Condition condition) { Chunk chunk = this.chunk; - final int chunkX = getChunkCoordinate(x); - final int chunkZ = getChunkCoordinate(z); + final int chunkX = CoordConversion.globalToChunk(x); + final int chunkZ = CoordConversion.globalToChunk(z); if (chunk == null || !chunk.isLoaded() || chunk.getChunkX() != chunkX || chunk.getChunkZ() != chunkZ) { this.chunk = chunk = this.instance.getChunk(chunkX, chunkZ); diff --git a/src/main/java/net/minestom/server/utils/chunk/ChunkUpdateLimitChecker.java b/src/main/java/net/minestom/server/utils/chunk/ChunkUpdateLimitChecker.java index a690e369e..bff217aa6 100644 --- a/src/main/java/net/minestom/server/utils/chunk/ChunkUpdateLimitChecker.java +++ b/src/main/java/net/minestom/server/utils/chunk/ChunkUpdateLimitChecker.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.chunk; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.instance.Chunk; import org.jetbrains.annotations.ApiStatus; @@ -23,7 +24,7 @@ public final class ChunkUpdateLimitChecker { * @return {@code true} if it's a new chunk in the history */ public boolean addToHistory(Chunk chunk) { - final long index = ChunkUtils.getChunkIndex(chunk); + final long index = CoordConversion.chunkIndex(chunk.getChunkX(), chunk.getChunkZ()); boolean result = true; final int lastIndex = historySize - 1; for (int i = 0; i < lastIndex; i++) { diff --git a/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java b/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java index 9300de8e6..0023730aa 100644 --- a/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java +++ b/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java @@ -1,10 +1,9 @@ package net.minestom.server.utils.chunk; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; -import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; -import net.minestom.server.utils.function.IntegerBiConsumer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,7 +27,7 @@ public final class ChunkUtils { * if {@link Instance#hasEnabledAutoChunkLoad()} returns false and the chunk is not already loaded. * * @param instance the instance to load the chunks from - * @param chunks the chunks to loaded, long value from {@link #getChunkIndex(int, int)} + * @param chunks the chunks to loaded, long value from {@link CoordConversion#chunkIndex(int, int)} * @param eachCallback the optional callback when a chunk get loaded * @return a {@link CompletableFuture} completed once all chunks have been processed */ @@ -38,7 +37,7 @@ public final class ChunkUtils { AtomicInteger counter = new AtomicInteger(0); for (long visibleChunk : chunks) { // WARNING: if autoload is disabled and no chunks are loaded beforehand, player will be stuck. - instance.loadOptionalChunk(getChunkCoordX(visibleChunk), getChunkCoordZ(visibleChunk)) + instance.loadOptionalChunk(CoordConversion.chunkIndexGetX(visibleChunk), CoordConversion.chunkIndexGetZ(visibleChunk)) .thenAccept((chunk) -> { if (eachCallback != null) eachCallback.accept(chunk); if (counter.incrementAndGet() == chunks.length) { @@ -63,7 +62,7 @@ public final class ChunkUtils { * @return true if the chunk is loaded, false otherwise */ public static boolean isLoaded(@NotNull Instance instance, double x, double z) { - final Chunk chunk = instance.getChunk(getChunkCoordinate(x), getChunkCoordinate(z)); + final Chunk chunk = instance.getChunk(CoordConversion.globalToChunk(x), CoordConversion.globalToChunk(z)); return isLoaded(chunk); } @@ -73,8 +72,8 @@ public final class ChunkUtils { } public static Chunk retrieve(Instance instance, Chunk originChunk, double x, double z) { - final int chunkX = getChunkCoordinate(x); - final int chunkZ = getChunkCoordinate(z); + final int chunkX = CoordConversion.globalToChunk(x); + final int chunkZ = CoordConversion.globalToChunk(z); final boolean sameChunk = originChunk != null && originChunk.getChunkX() == chunkX && originChunk.getChunkZ() == chunkZ; return sameChunk ? originChunk : instance.getChunk(chunkX, chunkZ); @@ -83,224 +82,4 @@ public final class ChunkUtils { public static Chunk retrieve(Instance instance, Chunk originChunk, Point position) { return retrieve(instance, originChunk, position.x(), position.z()); } - - /** - * @param xz the instance coordinate to convert - * @return the chunk X or Z based on the argument - */ - public static int getChunkCoordinate(double xz) { - return getChunkCoordinate((int) Math.floor(xz)); - } - - public static int getChunkCoordinate(int xz) { - // Assume chunk/section size being 16 (4 bits) - return xz >> 4; - } - - /** - * Gets the chunk index of chunk coordinates. - *

- * Used when you want to store a chunk somewhere without using a reference to the whole object - * (as this can lead to memory leaks). - * - * @param chunkX the chunk X - * @param chunkZ the chunk Z - * @return a number storing the chunk X and Z - */ - public static long getChunkIndex(int chunkX, int chunkZ) { - return (((long) chunkX) << 32) | (chunkZ & 0xffffffffL); - } - - public static long getChunkIndex(@NotNull Chunk chunk) { - return getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); - } - - public static long getChunkIndex(@NotNull Point point) { - return getChunkIndex(point.chunkX(), point.chunkZ()); - } - - /** - * Converts a chunk index to its chunk X position. - * - * @param index the chunk index computed by {@link #getChunkIndex(int, int)} - * @return the chunk X based on the index - */ - public static int getChunkCoordX(long index) { - return (int) (index >> 32); - } - - /** - * Converts a chunk index to its chunk Z position. - * - * @param index the chunk index computed by {@link #getChunkIndex(int, int)} - * @return the chunk Z based on the index - */ - public static int getChunkCoordZ(long index) { - return (int) index; - } - - public static int getChunkCount(int range) { - if (range < 0) { - throw new IllegalArgumentException("Range cannot be negative"); - } - final int square = range * 2 + 1; - return square * square; - } - - public static void forDifferingChunksInRange(int newChunkX, int newChunkZ, - int oldChunkX, int oldChunkZ, - int range, @NotNull IntegerBiConsumer callback) { - for (int x = newChunkX - range; x <= newChunkX + range; x++) { - for (int z = newChunkZ - range; z <= newChunkZ + range; z++) { - if (Math.abs(x - oldChunkX) > range || Math.abs(z - oldChunkZ) > range) { - callback.accept(x, z); - } - } - } - } - - public static void forDifferingChunksInRange(int newChunkX, int newChunkZ, - int oldChunkX, int oldChunkZ, - int range, - @NotNull IntegerBiConsumer newCallback, @NotNull IntegerBiConsumer oldCallback) { - // Find the new chunks - forDifferingChunksInRange(newChunkX, newChunkZ, oldChunkX, oldChunkZ, range, newCallback); - // Find the old chunks - forDifferingChunksInRange(oldChunkX, oldChunkZ, newChunkX, newChunkZ, range, oldCallback); - } - - /** - * New implementation comes from Krypton - * which comes from kotlin port by Esophose, which comes from a stackoverflow answer. - */ - public static void forChunksInRange(int chunkX, int chunkZ, int range, IntegerBiConsumer consumer) { - // Send in spiral around the center chunk - // Note: its not really required to start at the center anymore since the chunk queue is sorted by distance, - // however we still should send a circle so this method is still fine, and good for any other case a - // spiral might be needed. - consumer.accept(chunkX, chunkZ); - for (int id = 1; id < (range * 2 + 1) * (range * 2 + 1); id++) { - var index = id - 1; - - // compute radius (inverse arithmetic sum of 8 + 16 + 24 + ...) - var radius = (int) Math.floor((Math.sqrt(index + 1.0) - 1) / 2) + 1; - - // compute total point on radius -1 (arithmetic sum of 8 + 16 + 24 + ...) - var p = 8 * radius * (radius - 1) / 2; - - // points by face - var en = radius * 2; - - // compute de position and shift it so the first is (-r, -r) but (-r + 1, -r) - // so the square can connect - var a = (1 + index - p) % (radius * 8); - - switch (a / (radius * 2)) { - // find the face (0 = top, 1 = right, 2 = bottom, 3 = left) - case 0 -> consumer.accept(a - radius + chunkX, -radius + chunkZ); - case 1 -> consumer.accept(radius + chunkX, a % en - radius + chunkZ); - case 2 -> consumer.accept(radius - a % en + chunkX, radius + chunkZ); - case 3 -> consumer.accept(-radius + chunkX, radius - a % en + chunkZ); - default -> throw new IllegalStateException("unreachable"); - } - } - } - - public static void forChunksInRange(@NotNull Point point, int range, IntegerBiConsumer consumer) { - forChunksInRange(point.chunkX(), point.chunkZ(), range, consumer); - } - - /** - * Gets the block index of a position. - * - * @param x the block X - * @param y the block Y - * @param z the block Z - * @return an index which can be used to store and retrieve later data linked to a block position - */ - public static int getBlockIndex(int x, int y, int z) { - x = x % Chunk.CHUNK_SIZE_X; - z = z % Chunk.CHUNK_SIZE_Z; - - int index = x & 0xF; // 4 bits - if (y > 0) { - index |= (y << 4) & 0x07FFFFF0; // 23 bits (24th bit is always 0 because y is positive) - } else { - index |= ((-y) << 4) & 0x7FFFFF0; // Make positive and use 23 bits - index |= 1 << 27; // Set negative sign at 24th bit - } - index |= (z << 28) & 0xF0000000; // 4 bits - return index; - } - - /** - * @param index an index computed from {@link #getBlockIndex(int, int, int)} - * @param chunkX the chunk X - * @param chunkZ the chunk Z - * @return the instance position of the block located in {@code index} - */ - public static @NotNull Point getBlockPosition(int index, int chunkX, int chunkZ) { - final int x = blockIndexToChunkPositionX(index) + Chunk.CHUNK_SIZE_X * chunkX; - final int y = blockIndexToChunkPositionY(index); - final int z = blockIndexToChunkPositionZ(index) + Chunk.CHUNK_SIZE_Z * chunkZ; - return new Vec(x, y, z); - } - - /** - * Converts a block index to a chunk position X. - * - * @param index an index computed from {@link #getBlockIndex(int, int, int)} - * @return the chunk position X (O-15) of the specified index - */ - public static int blockIndexToChunkPositionX(int index) { - return index & 0xF; // 0-4 bits - } - - /** - * Converts a block index to a chunk position Y. - * - * @param index an index computed from {@link #getBlockIndex(int, int, int)} - * @return the chunk position Y of the specified index - */ - public static int blockIndexToChunkPositionY(int index) { - int y = (index & 0x07FFFFF0) >>> 4; - if (((index >>> 27) & 1) == 1) y = -y; // Sign bit set, invert sign - return y; // 4-28 bits - } - - /** - * Converts a block index to a chunk position Z. - * - * @param index an index computed from {@link #getBlockIndex(int, int, int)} - * @return the chunk position Z (O-15) of the specified index - */ - public static int blockIndexToChunkPositionZ(int index) { - return (index >> 28) & 0xF; // 28-32 bits - } - - /** - * Converts a global coordinate value to a section coordinate - * - * @param xyz global coordinate - * @return section coordinate - */ - public static int toSectionRelativeCoordinate(int xyz) { - return xyz & 0xF; - } - - public static int toRegionCoordinate(int chunkCoordinate) { - return chunkCoordinate >> 5; - } - - public static int toRegionLocal(int chunkCoordinate) { - return chunkCoordinate & 0x1F; - } - - public static int floorSection(int coordinate) { - return coordinate - (coordinate & 0xF); - } - - public static int ceilSection(int coordinate) { - return ((coordinate - 1) | 15) + 1; - } } diff --git a/src/main/java/net/minestom/server/utils/function/IntegerBiConsumer.java b/src/main/java/net/minestom/server/utils/function/IntegerBiConsumer.java deleted file mode 100644 index 64b257502..000000000 --- a/src/main/java/net/minestom/server/utils/function/IntegerBiConsumer.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.minestom.server.utils.function; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -@FunctionalInterface -public interface IntegerBiConsumer { - void accept(int v1, int v2); -} diff --git a/src/test/java/net/minestom/server/coordinate/CoordinateTest.java b/src/test/java/net/minestom/server/coordinate/CoordinateTest.java index 560cf470c..aa152eec1 100644 --- a/src/test/java/net/minestom/server/coordinate/CoordinateTest.java +++ b/src/test/java/net/minestom/server/coordinate/CoordinateTest.java @@ -3,53 +3,51 @@ package net.minestom.server.coordinate; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import net.minestom.server.instance.Chunk; -import net.minestom.server.utils.chunk.ChunkUtils; import org.junit.jupiter.api.Test; import java.util.List; -import static net.minestom.server.utils.chunk.ChunkUtils.*; import static org.junit.jupiter.api.Assertions.*; public class CoordinateTest { @Test public void chunkIndex() { - var index = getChunkIndex(2, 5); - assertEquals(2, getChunkCoordX(index)); - assertEquals(5, getChunkCoordZ(index)); + var index = CoordConversion.chunkIndex(2, 5); + assertEquals(2, CoordConversion.chunkIndexGetX(index)); + assertEquals(5, CoordConversion.chunkIndexGetZ(index)); - index = getChunkIndex(-5, 25); - assertEquals(-5, getChunkCoordX(index)); - assertEquals(25, getChunkCoordZ(index)); + index = CoordConversion.chunkIndex(-5, 25); + assertEquals(-5, CoordConversion.chunkIndexGetX(index)); + assertEquals(25, CoordConversion.chunkIndexGetZ(index)); - index = getChunkIndex(Integer.MAX_VALUE, Integer.MIN_VALUE); - assertEquals(Integer.MAX_VALUE, getChunkCoordX(index)); - assertEquals(Integer.MIN_VALUE, getChunkCoordZ(index)); + index = CoordConversion.chunkIndex(Integer.MAX_VALUE, Integer.MIN_VALUE); + assertEquals(Integer.MAX_VALUE, CoordConversion.chunkIndexGetX(index)); + assertEquals(Integer.MIN_VALUE, CoordConversion.chunkIndexGetZ(index)); } @Test public void chunkCoordinate() { - assertEquals(0, getChunkCoordinate(15)); - assertEquals(1, getChunkCoordinate(16)); - assertEquals(-1, getChunkCoordinate(-16)); - assertEquals(3, getChunkCoordinate(48)); + assertEquals(0, CoordConversion.globalToChunk(15)); + assertEquals(1, CoordConversion.globalToChunk(16)); + assertEquals(-1, CoordConversion.globalToChunk(-16)); + assertEquals(3, CoordConversion.globalToChunk(48)); - assertEquals(4, getChunkCoordinate(65)); - assertEquals(4, getChunkCoordinate(64)); - assertEquals(3, getChunkCoordinate(63)); - assertEquals(-2, getChunkCoordinate(-25)); - assertEquals(23, getChunkCoordinate(380)); + assertEquals(4, CoordConversion.globalToChunk(65)); + assertEquals(4, CoordConversion.globalToChunk(64)); + assertEquals(3, CoordConversion.globalToChunk(63)); + assertEquals(-2, CoordConversion.globalToChunk(-25)); + assertEquals(23, CoordConversion.globalToChunk(380)); } @Test public void chunkCount() { - assertEquals(289, getChunkCount(8)); - assertEquals(169, getChunkCount(6)); - assertEquals(121, getChunkCount(5)); - assertEquals(9, getChunkCount(1)); - assertEquals(1, getChunkCount(0)); - assertThrows(IllegalArgumentException.class, () -> getChunkCount(-1)); + assertEquals(289, ChunkRange.chunksCount(8)); + assertEquals(169, ChunkRange.chunksCount(6)); + assertEquals(121, ChunkRange.chunksCount(5)); + assertEquals(9, ChunkRange.chunksCount(1)); + assertEquals(1, ChunkRange.chunksCount(0)); + assertThrows(IllegalArgumentException.class, () -> ChunkRange.chunksCount(-1)); } @Test @@ -95,15 +93,15 @@ public class CoordinateTest { @Test public void toSectionRelativeCoordinate() { - assertEquals(8, ChunkUtils.toSectionRelativeCoordinate(-40)); - assertEquals(12, ChunkUtils.toSectionRelativeCoordinate(-20)); - assertEquals(0, ChunkUtils.toSectionRelativeCoordinate(0)); - assertEquals(5, ChunkUtils.toSectionRelativeCoordinate(5)); - assertEquals(15, ChunkUtils.toSectionRelativeCoordinate(15)); - assertEquals(0, ChunkUtils.toSectionRelativeCoordinate(16)); - assertEquals(4, ChunkUtils.toSectionRelativeCoordinate(20)); - assertEquals(0, ChunkUtils.toSectionRelativeCoordinate(32)); - assertEquals(1, ChunkUtils.toSectionRelativeCoordinate(33)); + assertEquals(8, CoordConversion.globalToSectionRelative(-40)); + assertEquals(12, CoordConversion.globalToSectionRelative(-20)); + assertEquals(0, CoordConversion.globalToSectionRelative(0)); + assertEquals(5, CoordConversion.globalToSectionRelative(5)); + assertEquals(15, CoordConversion.globalToSectionRelative(15)); + assertEquals(0, CoordConversion.globalToSectionRelative(16)); + assertEquals(4, CoordConversion.globalToSectionRelative(20)); + assertEquals(0, CoordConversion.globalToSectionRelative(32)); + assertEquals(1, CoordConversion.globalToSectionRelative(33)); } @Test @@ -130,7 +128,7 @@ public class CoordinateTest { ); for (Vec vec : tempEquals) { - assertEquals(getBlockPosition(getBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()), + assertEquals(CoordConversion.chunkBlockIndexGetGlobal(CoordConversion.chunkBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()), vec.chunkX(), vec.chunkZ()), vec); } @@ -145,7 +143,7 @@ public class CoordinateTest { ); for (Vec vec : tempNotEquals) { - assertNotEquals(getBlockPosition(getBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()), + assertNotEquals(CoordConversion.chunkBlockIndexGetGlobal(CoordConversion.chunkBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()), vec.chunkX(), vec.chunkZ()), vec); } } @@ -158,13 +156,13 @@ public class CoordinateTest { for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { for (int y = -64; y < 364; y++) { var vec = new Vec(x, y, z); - var index = getBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()); + var index = CoordConversion.chunkBlockIndex(vec.blockX(), vec.blockY(), vec.blockZ()); assertTrue(temp.add(index), "Duplicate block index found: " + index + " " + vec); - assertEquals(getBlockPosition(index, vec.chunkX(), vec.chunkZ()), vec); + assertEquals(CoordConversion.chunkBlockIndexGetGlobal(index, vec.chunkX(), vec.chunkZ()), vec); - assertEquals(blockIndexToChunkPositionX(index), x); - assertEquals(blockIndexToChunkPositionY(index), y); - assertEquals(blockIndexToChunkPositionZ(index), z); + assertEquals(CoordConversion.chunkBlockIndexGetX(index), x); + assertEquals(CoordConversion.chunkBlockIndexGetY(index), y); + assertEquals(CoordConversion.chunkBlockIndexGetZ(index), z); } } } diff --git a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java index b9605b60d..96dea24ff 100644 --- a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java @@ -1,13 +1,14 @@ package net.minestom.server.entity; -import net.minestom.server.instance.block.Block; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; import net.minestom.server.network.packet.server.play.EntityVelocityPacket; import net.minestom.server.utils.chunk.ChunkUtils; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import java.util.concurrent.atomic.AtomicInteger; @@ -202,15 +203,15 @@ public class EntityVelocityIntegrationTest { private void loadChunks(Instance instance) { ChunkUtils.optionalLoadAll(instance, new long[]{ - ChunkUtils.getChunkIndex(-1, -1), - ChunkUtils.getChunkIndex(-1, 0), - ChunkUtils.getChunkIndex(-1, 1), - ChunkUtils.getChunkIndex(0, -1), - ChunkUtils.getChunkIndex(0, 0), - ChunkUtils.getChunkIndex(0, 1), - ChunkUtils.getChunkIndex(1, -1), - ChunkUtils.getChunkIndex(1, 0), - ChunkUtils.getChunkIndex(1, 1), + CoordConversion.chunkIndex(-1, -1), + CoordConversion.chunkIndex(-1, 0), + CoordConversion.chunkIndex(-1, 1), + CoordConversion.chunkIndex(0, -1), + CoordConversion.chunkIndex(0, 0), + CoordConversion.chunkIndex(0, 1), + CoordConversion.chunkIndex(1, -1), + CoordConversion.chunkIndex(1, 0), + CoordConversion.chunkIndex(1, 1), }, null).join(); } } diff --git a/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java b/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java index dd203dae8..5fc5b0ce7 100644 --- a/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/pathfinding/PathfinderIntegrationTest.java @@ -1,12 +1,12 @@ package net.minestom.server.entity.pathfinding; +import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.LivingEntity; import net.minestom.server.entity.pathfinding.generators.GroundNodeGenerator; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; @@ -45,7 +45,7 @@ public class PathfinderIntegrationTest { public void testTall(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); @@ -68,7 +68,7 @@ public class PathfinderIntegrationTest { public void testStraightLine(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); @@ -88,7 +88,7 @@ public class PathfinderIntegrationTest { public void testShort(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); @@ -109,7 +109,7 @@ public class PathfinderIntegrationTest { public void testBug(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); @@ -147,7 +147,7 @@ public class PathfinderIntegrationTest { public void testStraightLineBlocked(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); @@ -198,7 +198,7 @@ public class PathfinderIntegrationTest { public void testGravitySnap(Env env) { var i = env.createFlatInstance(); - ChunkUtils.forChunksInRange(0, 0, 10, (x, z) -> { + ChunkRange.chunksInRange(0, 0, 10, (x, z) -> { i.loadChunk(x, z).join(); }); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index f1fe2660f..d8cdf782f 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -1,6 +1,7 @@ package net.minestom.server.entity.player; import net.minestom.server.ServerFlag; +import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; @@ -15,7 +16,6 @@ import net.minestom.server.network.packet.server.play.EntityPositionPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket; import net.minestom.server.network.player.ClientSettings; import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.testing.Collector; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; @@ -72,7 +72,7 @@ public class PlayerMovementIntegrationTest { final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; // Preload all possible chunks to avoid issues due to async loading Set> chunks = new HashSet<>(); - ChunkUtils.forChunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + ChunkRange.chunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); final TestConnection connection = env.createConnection(); Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); @@ -128,7 +128,7 @@ public class PlayerMovementIntegrationTest { Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)).join(); // Preload all possible chunks to avoid issues due to async loading Set> chunks = new HashSet<>(); - ChunkUtils.forChunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); player.refreshSettings(new ClientSettings( Locale.US, (byte) viewDistance, @@ -156,10 +156,10 @@ public class PlayerMovementIntegrationTest { Pos startingPlayerPos = new Pos(0, 42, 0); var player = connection.connect(instance, startingPlayerPos).join(); - int chunkDifference = ChunkUtils.getChunkCount(endViewDistance) - ChunkUtils.getChunkCount(startingViewDistance); + int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); // Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread - ChunkUtils.forChunksInRange(0, 0, endViewDistance, instance::loadChunk); + ChunkRange.chunksInRange(0, 0, endViewDistance, instance::loadChunk); var tracker = connection.trackIncoming(ChunkDataPacket.class); player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, @@ -172,7 +172,7 @@ public class PlayerMovementIntegrationTest { ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); player.interpretPacketQueue(); - int chunkDifference1 = ChunkUtils.getChunkCount(endViewDistance) - ChunkUtils.getChunkCount(finalViewDistance); + int chunkDifference1 = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(finalViewDistance); tracker1.assertCount(chunkDifference1); } } diff --git a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java index 0d0f9686a..3d6fa17d2 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java @@ -1,12 +1,12 @@ package net.minestom.server.entity.player; import net.minestom.server.ServerFlag; +import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.client.play.ClientStatusPacket; import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; @@ -46,7 +46,7 @@ public class PlayerRespawnChunkIntegrationTest { player.setHealth(0); player.respawn(); // Player should have all their chunks reloaded - int chunkLoads = ChunkUtils.getChunkCount(Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().viewDistance())); + int chunkLoads = ChunkRange.chunksCount(Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().viewDistance())); loadChunkTracker.assertCount(chunkLoads); } @@ -63,7 +63,7 @@ public class PlayerRespawnChunkIntegrationTest { List dataPacketList = loadChunkTracker.collect(); Set duplicateCheck = new HashSet<>(); int actualViewDistance = Math.min(ServerFlag.CHUNK_VIEW_DISTANCE, player.getSettings().viewDistance()); - int chunkLoads = ChunkUtils.getChunkCount(actualViewDistance); + int chunkLoads = ChunkRange.chunksCount(actualViewDistance); loadChunkTracker.assertCount(chunkLoads); for (ChunkDataPacket packet : dataPacketList) { assertFalse(duplicateCheck.contains(packet)); diff --git a/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java b/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java index 429a26a0a..cfd976713 100644 --- a/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java @@ -1,9 +1,9 @@ package net.minestom.server.instance; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.play.ChunkDataPacket; -import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; @@ -38,7 +38,7 @@ public class ChunkViewerIntegrationTest { @Test public void renderDistance(Env env) { final int viewRadius = MinecraftServer.getChunkViewDistance(); - final int count = ChunkUtils.getChunkCount(viewRadius); + final int count = ChunkRange.chunksCount(viewRadius); var instance = env.createFlatInstance(); var connection = env.createConnection(); // Check initial load diff --git a/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java b/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java index f961a8ead..477b8cd30 100644 --- a/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java +++ b/src/test/java/net/minestom/server/instance/generator/GeneratorTest.java @@ -1,11 +1,11 @@ package net.minestom.server.instance.generator; +import net.minestom.server.coordinate.CoordConversion; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.generator.GeneratorImpl.GenSection; import net.minestom.server.utils.MathUtils; -import net.minestom.server.utils.chunk.ChunkUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -17,9 +17,9 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; +import static net.minestom.server.coordinate.CoordConversion.ceilSection; +import static net.minestom.server.coordinate.CoordConversion.floorSection; import static net.minestom.server.instance.generator.GeneratorImpl.unit; -import static net.minestom.server.utils.chunk.ChunkUtils.ceilSection; -import static net.minestom.server.utils.chunk.ChunkUtils.floorSection; import static org.junit.jupiter.api.Assertions.*; public class GeneratorTest { @@ -168,8 +168,8 @@ public class GeneratorTest { Set points = new HashSet<>(); modifier.setAll((x, y, z) -> { assertTrue(points.add(new Vec(x, y, z)), "Duplicate point: " + x + ", " + y + ", " + z); - assertEquals(chunkX, ChunkUtils.getChunkCoordinate(x)); - assertEquals(chunkZ, ChunkUtils.getChunkCoordinate(z)); + assertEquals(chunkX, CoordConversion.globalToChunk(x)); + assertEquals(chunkZ, CoordConversion.globalToChunk(z)); return Block.STONE; }); assertEquals(16 * 16 * 16 * sectionCount, points.size()); diff --git a/src/test/java/net/minestom/server/utils/ChunkUtilsTest.java b/src/test/java/net/minestom/server/utils/ChunkUtilsTest.java index 5327ad053..3afb38419 100644 --- a/src/test/java/net/minestom/server/utils/ChunkUtilsTest.java +++ b/src/test/java/net/minestom/server/utils/ChunkUtilsTest.java @@ -1,10 +1,10 @@ package net.minestom.server.utils; -import net.minestom.server.utils.chunk.ChunkUtils; +import net.minestom.server.coordinate.ChunkRange; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.api.Assertions; import java.util.*; import java.util.stream.Stream; @@ -16,12 +16,12 @@ public class ChunkUtilsTest { public void testForDifferingChunksInRange(int nx, int nz, int ox, int oz, int r) { final Set n = new HashSet<>(); final Set o = new HashSet<>(); - ChunkUtils.forChunksInRange(nx, nz, r, (x, z) -> n.add(new ChunkCoordinate(x, z))); - ChunkUtils.forChunksInRange(ox, oz, r, (x, z) -> o.add(new ChunkCoordinate(x, z))); + ChunkRange.chunksInRange(nx, nz, r, (x, z) -> n.add(new ChunkCoordinate(x, z))); + ChunkRange.chunksInRange(ox, oz, r, (x, z) -> o.add(new ChunkCoordinate(x, z))); final List actualNew = new ArrayList<>(); final List actualOld = new ArrayList<>(); - ChunkUtils.forDifferingChunksInRange(nx, nz, ox, oz, r, ((x, z) -> actualNew.add(new ChunkCoordinate(x, z))), + ChunkRange.chunksInRangeDiffering(nx, nz, ox, oz, r, ((x, z) -> actualNew.add(new ChunkCoordinate(x, z))), ((x, z) -> actualOld.add(new ChunkCoordinate(x, z)))); final Comparator sorter = Comparator.comparingInt(ChunkCoordinate::x).thenComparingInt(ChunkCoordinate::z); From 122651ea65ce6552827321b59adceb5ac8866e43 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 15 Sep 2024 18:03:40 +0200 Subject: [PATCH 27/97] Add RecipeCompute --- .../minestom/server/recipe/RecipeCompute.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/main/java/net/minestom/server/recipe/RecipeCompute.java diff --git a/src/main/java/net/minestom/server/recipe/RecipeCompute.java b/src/main/java/net/minestom/server/recipe/RecipeCompute.java new file mode 100644 index 000000000..1a5713b47 --- /dev/null +++ b/src/main/java/net/minestom/server/recipe/RecipeCompute.java @@ -0,0 +1,122 @@ +package net.minestom.server.recipe; + +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@ApiStatus.Experimental +public final class RecipeCompute { + + public static @Nullable CraftResult searchCraft(List recipes, int width, int height, ItemStack[] items) { + for (Recipe recipe : recipes) { + final CraftResult result = switch (recipe.data()) { + case Recipe.Shaped shaped -> searchShaped(shaped, width, height, items); + case Recipe.Shapeless shapeless -> searchShapeless(shapeless, items); + default -> null; + }; + if (result != null) return result; + } + return null; + } + + private static @Nullable CraftResult searchShaped(Recipe.Shaped recipe, int width, int height, ItemStack[] items) { + // Verify if the inventory is too small for the recipe + if (width < recipe.width() || height < recipe.height()) return null; + // Verify if the inventory has items outside the recipe bound + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + final ItemStack item = items[x + y * width]; + if (item.isAir()) continue; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } + } + if (maxX - minX + 1 > recipe.width() || maxY - minY + 1 > recipe.height()) return null; + // Search for the recipe + for (int x = 0; x <= width - recipe.width(); x++) { + for (int y = 0; y <= height - recipe.height(); y++) { + boolean found = true; + for (int recipeX = 0; recipeX < recipe.width(); recipeX++) { + for (int recipeY = 0; recipeY < recipe.height(); recipeY++) { + boolean validIngredient = false; + final int ingredientIndex = recipeX + recipeY * recipe.width(); + final Recipe.Ingredient ingredient = recipe.ingredients().get(ingredientIndex); + final ItemStack item = items[(x + recipeX) + (y + recipeY) * width]; + if (ingredient.items().isEmpty() && item.isAir()) { + validIngredient = true; + } else { + for (ItemStack ingredientItem : ingredient.items()) { + if (ingredientItem.isSimilar(item)) { + validIngredient = true; + break; + } + } + } + if (!validIngredient) { + found = false; + break; + } + } + if (!found) break; + } + if (found) return new CraftResult(recipe.result(), possibleConsume(items)); + } + } + return null; + } + + private static @Nullable CraftResult searchShapeless(Recipe.Shapeless recipe, ItemStack[] items) { + // Count material occurrences + Map materials = new HashMap<>(); + for (ItemStack item : items) { + if (item.isAir()) continue; + materials.put(item.material(), materials.getOrDefault(item.material(), 0) + 1); + } + if (materials.isEmpty()) return null; + + // Check if the recipe is valid + for (Recipe.Ingredient ingredient : recipe.ingredients()) { + boolean success = false; + for (ItemStack item : ingredient.items()) { + final Material material = item.material(); + final int occurrences = materials.getOrDefault(material, 0); + if (occurrences == 0) continue; + final int reduced = occurrences - 1; + if (reduced > 0) { + materials.put(material, reduced); + } else { + materials.remove(material); + } + success = true; + break; + } + if (!success) return null; + } + if (!materials.isEmpty()) return null; + + return new CraftResult(recipe.result(), possibleConsume(items)); + } + + private static int possibleConsume(ItemStack[] items) { + int smallestSize = Integer.MAX_VALUE; + for (ItemStack item : items) { + if (item.isAir()) continue; + if (item.amount() < smallestSize) smallestSize = item.amount(); + } + return smallestSize; + } + + public record CraftResult(ItemStack item, int consumeAbility) { + } +} From 47480f330b2c86d7010cd5eaf6dbc1cd705184ed Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 15 Sep 2024 19:25:50 +0200 Subject: [PATCH 28/97] Fix build --- src/main/java/net/minestom/server/instance/Instance.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 26dea6acd..47215b350 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -884,9 +884,10 @@ public abstract class Instance implements Block.Getter, Block.Setter, /** * Plays a {@link Sound} at a given point, except to the excluded player + * * @param excludedPlayer The player in the instance who won't receive the sound - * @param sound The sound to play - * @param point The point in this instance at which to play the sound + * @param sound The sound to play + * @param point The point in this instance at which to play the sound */ public void playSoundExcept(@Nullable Player excludedPlayer, @NotNull Sound sound, @NotNull Point point) { playSoundExcept(excludedPlayer, sound, point.x(), point.y(), point.z()); @@ -894,13 +895,13 @@ public abstract class Instance implements Block.Getter, Block.Setter, public void playSoundExcept(@Nullable Player excludedPlayer, @NotNull Sound sound, double x, double y, double z) { ServerPacket packet = AdventurePacketConvertor.createSoundPacket(sound, x, y, z); - PacketUtils.sendGroupedPacket(getPlayers(), packet, p -> p != excludedPlayer); + PacketSendingUtils.sendGroupedPacket(getPlayers(), packet, p -> p != excludedPlayer); } public void playSoundExcept(@Nullable Player excludedPlayer, @NotNull Sound sound, Sound.@NotNull Emitter emitter) { if (emitter != Sound.Emitter.self()) { ServerPacket packet = AdventurePacketConvertor.createSoundPacket(sound, emitter); - PacketUtils.sendGroupedPacket(getPlayers(), packet, p -> p != excludedPlayer); + PacketSendingUtils.sendGroupedPacket(getPlayers(), packet, p -> p != excludedPlayer); } else { // if we're playing on self, we need to delegate to each audience member for (Audience audience : this.audiences()) { From 959caeeb750541d7519fc59a25c42029334afece Mon Sep 17 00:00:00 2001 From: themode Date: Mon, 16 Sep 2024 18:46:44 +0200 Subject: [PATCH 29/97] More packet writing utils --- .../server/network/packet/PacketWriting.java | 51 +++++++++++++++++++ .../player/PlayerSocketConnection.java | 29 ++--------- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/main/java/net/minestom/server/network/packet/PacketWriting.java b/src/main/java/net/minestom/server/network/packet/PacketWriting.java index c7f847823..1136a1002 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketWriting.java +++ b/src/main/java/net/minestom/server/network/packet/PacketWriting.java @@ -8,6 +8,9 @@ import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.Queue; +import java.util.function.BiPredicate; + /** * Tools to write packets into a {@link NetworkBuffer} for network processing. *

@@ -43,6 +46,17 @@ public final class PacketWriting { @NotNull T packet, int compressionThreshold) throws IndexOutOfBoundsException { final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet); + writeFramedPacket( + buffer, + packetInfo, packet, + compressionThreshold + ); + } + + public static void writeFramedPacket(@NotNull NetworkBuffer buffer, + @NotNull PacketRegistry.PacketInfo packetInfo, + @NotNull T packet, + int compressionThreshold) throws IndexOutOfBoundsException { final int id = packetInfo.id(); final NetworkBuffer.Type serializer = packetInfo.serializer(); writeFramedPacket( @@ -160,4 +174,41 @@ public final class PacketWriting { return tmpBuffer.copy(0, tmpBuffer.writeIndex()); } } + + public static void writeQueue(NetworkBuffer buffer, Queue queue, int minWrite, + BiPredicate writer) { + // The goal of this method is to write at the very least `minWrite` packets if the queue permits it. + // The buffer is resized if it cannot hold this minimum. + final int size = queue.size(); + minWrite = Math.min(minWrite, size); + T packet; + int written = 0; + while ((packet = queue.peek()) != null) { + final long index = buffer.writeIndex(); + boolean success; + try { + success = writer.test(buffer, packet); + } catch (IndexOutOfBoundsException e) { + success = false; + } + assert !success || buffer.writeIndex() > 0; + // Poll the packet only if fully written + if (success) { + // Packet fully written + queue.poll(); + written++; + } else { + buffer.writeIndex(index); + if (written < minWrite) { + // Try again with a bigger buffer + final long newSize = Math.min(buffer.capacity() * 2, ServerFlag.MAX_PACKET_SIZE); + buffer.resize(newSize); + } else { + // At least one packet has been written + // Not worth resizing to fit more, we'll try again next flush + break; + } + } + } + } } diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index a98bef5a7..92593b4b0 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -408,31 +408,12 @@ public class PlayerSocketConnection extends PlayerConnection { if (!channel.isConnected()) throw new EOFException("Channel is closed"); NetworkBuffer buffer = PacketVanilla.PACKET_POOL.get(); // Write to buffer - SendablePacket packet; - int written = 0; - while ((packet = packetQueue.peek()) != null) { + PacketWriting.writeQueue(buffer, packetQueue, 1, (b, packet) -> { final boolean compressed = sentPacketCounter.get() > compressionStart; - final boolean success = writeSendable(buffer, packet, compressed); - assert !success || buffer.writeIndex() > 0; - // Poll the packet only if fully written - if (success) { - // Packet fully written - packetQueue.poll(); - sentPacketCounter.getAndIncrement(); - written++; - } else { - if (written == 0) { - assert buffer.writeIndex() == 0; - // Try again with a bigger buffer - final long newSize = Math.min(buffer.capacity() * 2, ServerFlag.MAX_PACKET_SIZE); - buffer.resize(newSize); - } else { - // At least one packet has been written - // Not worth resizing to fit more, we'll try again next flush - break; - } - } - } + final boolean success = writeSendable(b, packet, compressed); + if (success) sentPacketCounter.getAndIncrement(); + return success; + }); // Write to channel final boolean success = buffer.writeChannel(channel); // Keep the buffer if not fully written From eeacff801f9889a6277572db04cf5f653006ace3 Mon Sep 17 00:00:00 2001 From: themode Date: Mon, 16 Sep 2024 23:19:32 +0200 Subject: [PATCH 30/97] Remove write condition --- .../player/PlayerSocketConnection.java | 37 ++++--------------- .../server/network/socket/Server.java | 2 - 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index 92593b4b0..453523497 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -41,10 +41,7 @@ import java.nio.channels.SocketChannel; import java.util.Collection; import java.util.Objects; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; import java.util.zip.DataFormatException; /** @@ -88,9 +85,6 @@ public class PlayerSocketConnection extends PlayerConnection { // Used instead of a simple boolean so we can get proper timing for serialization private volatile long compressionStart = Long.MAX_VALUE; - final ReentrantLock writeLock = new ReentrantLock(); - final Condition writeCondition = writeLock.newCondition(); - private final ListenerHandle outgoing = EventDispatcher.getHandle(PlayerPacketOutEvent.class); public PlayerSocketConnection(@NotNull SocketChannel channel, SocketAddress remoteAddress) { @@ -191,13 +185,11 @@ public class PlayerSocketConnection extends PlayerConnection { @Override public void sendPacket(@NotNull SendablePacket packet) { this.packetQueue.relaxedOffer(packet); - signalWrite(); } @Override public void sendPackets(@NotNull Collection packets) { for (SendablePacket packet : packets) this.packetQueue.relaxedOffer(packet); - signalWrite(); } @Override @@ -403,7 +395,13 @@ public class PlayerSocketConnection extends PlayerConnection { // Consume queued packets var packetQueue = this.packetQueue; if (packetQueue.isEmpty()) { - awaitWrite(); + try { + // Can probably be improved by waking up at the end of the tick + // But this work well enough and without additional state. + Thread.sleep(1000 / ServerFlag.SERVER_TICKS_PER_SECOND / 2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } if (!channel.isConnected()) throw new EOFException("Channel is closed"); NetworkBuffer buffer = PacketVanilla.PACKET_POOL.get(); @@ -421,27 +419,6 @@ public class PlayerSocketConnection extends PlayerConnection { else this.writeLeftover = buffer; } - public void awaitWrite() { - try { - this.writeLock.lock(); - //noinspection ResultOfMethodCallIgnored - this.writeCondition.await(50, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - this.writeLock.unlock(); - } - } - - public void signalWrite() { - try { - this.writeLock.lock(); - this.writeCondition.signal(); - } finally { - this.writeLock.unlock(); - } - } - record EncryptionContext(Cipher encrypt, Cipher decrypt) { } } diff --git a/src/main/java/net/minestom/server/network/socket/Server.java b/src/main/java/net/minestom/server/network/socket/Server.java index 639928909..b7949a969 100644 --- a/src/main/java/net/minestom/server/network/socket/Server.java +++ b/src/main/java/net/minestom/server/network/socket/Server.java @@ -103,8 +103,6 @@ public final class Server { break; } } - // Ensure the connection is not stuck waiting for packets to write - connection.signalWrite(); } private void playerWriteLoop(PlayerSocketConnection connection) { From ffd0fabe103078ddd91c561459516e41aab8a5e3 Mon Sep 17 00:00:00 2001 From: mudkip Date: Mon, 16 Sep 2024 15:50:42 -0600 Subject: [PATCH 31/97] Implement missing packets (#2392) --- .../server/network/NetworkBufferTemplate.java | 316 +++++++++++++++++- .../server/network/packet/PacketRegistry.java | 10 +- .../play/ClientChangeDifficultyPacket.java | 17 + .../play/ClientLockDifficultyPacket.java | 13 + .../play/ClientUpdateJigsawBlockPacket.java | 32 ++ .../packet/server/play/ChunkBiomesPacket.java | 39 +++ .../server/play/DisguisedChatPacket.java | 25 ++ 7 files changed, 446 insertions(+), 6 deletions(-) create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientChangeDifficultyPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientLockDifficultyPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateJigsawBlockPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/ChunkBiomesPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/DisguisedChatPacket.java diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java index 9dc142577..d57e001a6 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java @@ -7,7 +7,6 @@ import java.util.function.Function; import java.util.function.Supplier; public final class NetworkBufferTemplate { - @FunctionalInterface public interface F1 { R apply(P1 p1); @@ -68,6 +67,36 @@ public final class NetworkBufferTemplate { R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12); } + @FunctionalInterface + public interface F13 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13); + } + + @FunctionalInterface + public interface F14 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14); + } + + @FunctionalInterface + public interface F15 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15); + } + + @FunctionalInterface + public interface F16 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16); + } + + @FunctionalInterface + public interface F17 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17); + } + + @FunctionalInterface + public interface F18 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18); + } + @FunctionalInterface public interface F19 { R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19); @@ -424,6 +453,291 @@ public final class NetworkBufferTemplate { }; } + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, + F13 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + F14 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, + F15 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, Type p16, Function g16, + F16 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + p16.write(buffer, g16.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer), p16.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, Type p16, Function g16, + Type p17, Function g17, + F17 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + p16.write(buffer, g16.apply(value)); + p17.write(buffer, g17.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer), p16.read(buffer), + p17.read(buffer) + ); + } + }; + } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, Type p16, Function g16, + Type p17, Function g17, Type p18, Function g18, + F18 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + p16.write(buffer, g16.apply(value)); + p17.write(buffer, g17.apply(value)); + p18.write(buffer, g18.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer), p16.read(buffer), + p17.read(buffer), p18.read(buffer) + ); + } + }; + } + public static Type template( Type p1, Function g1, Type p2, Function g2, Type p3, Function g3, Type p4, Function g4, diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index ddc8baf39..6e5559592 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -92,7 +92,7 @@ public interface PacketRegistry { super( entry(ClientTeleportConfirmPacket.class, ClientTeleportConfirmPacket.SERIALIZER), entry(ClientQueryBlockNbtPacket.class, ClientQueryBlockNbtPacket.SERIALIZER), - null, // difficulty packet + entry(ClientChangeDifficultyPacket.class, ClientChangeDifficultyPacket.SERIALIZER), entry(ClientChatAckPacket.class, ClientChatAckPacket.SERIALIZER), entry(ClientCommandChatPacket.class, ClientCommandChatPacket.SERIALIZER), entry(ClientSignedCommandChatPacket.class, ClientSignedCommandChatPacket.SERIALIZER), @@ -115,7 +115,7 @@ public interface PacketRegistry { entry(ClientInteractEntityPacket.class, ClientInteractEntityPacket.SERIALIZER), entry(ClientGenerateStructurePacket.class, ClientGenerateStructurePacket.SERIALIZER), entry(ClientKeepAlivePacket.class, ClientKeepAlivePacket.SERIALIZER), - null, // lock difficulty + entry(ClientLockDifficultyPacket.class, ClientLockDifficultyPacket.SERIALIZER), entry(ClientPlayerPositionPacket.class, ClientPlayerPositionPacket.SERIALIZER), entry(ClientPlayerPositionAndRotationPacket.class, ClientPlayerPositionAndRotationPacket.SERIALIZER), entry(ClientPlayerRotationPacket.class, ClientPlayerRotationPacket.SERIALIZER), @@ -141,7 +141,7 @@ public interface PacketRegistry { entry(ClientUpdateCommandBlockPacket.class, ClientUpdateCommandBlockPacket.SERIALIZER), entry(ClientUpdateCommandBlockMinecartPacket.class, ClientUpdateCommandBlockMinecartPacket.SERIALIZER), entry(ClientCreativeInventoryActionPacket.class, ClientCreativeInventoryActionPacket.SERIALIZER), - null, // Update Jigsaw Block + entry(ClientUpdateJigsawBlockPacket.class, ClientUpdateJigsawBlockPacket.SERIALIZER), entry(ClientUpdateStructureBlockPacket.class, ClientUpdateStructureBlockPacket.SERIALIZER), entry(ClientUpdateSignPacket.class, ClientUpdateSignPacket.SERIALIZER), entry(ClientAnimationPacket.class, ClientAnimationPacket.SERIALIZER), @@ -230,7 +230,7 @@ public interface PacketRegistry { entry(ServerDifficultyPacket.class, ServerDifficultyPacket.SERIALIZER), entry(ChunkBatchFinishedPacket.class, ChunkBatchFinishedPacket.SERIALIZER), entry(ChunkBatchStartPacket.class, ChunkBatchStartPacket.SERIALIZER), - null, // CHUNK_BIOMES + entry(ChunkBiomesPacket.class, ChunkBiomesPacket.SERIALIZER), entry(ClearTitlesPacket.class, ClearTitlesPacket.SERIALIZER), entry(TabCompletePacket.class, TabCompletePacket.SERIALIZER), entry(DeclareCommandsPacket.class, DeclareCommandsPacket.SERIALIZER), @@ -246,7 +246,7 @@ public interface PacketRegistry { entry(DebugSamplePacket.class, DebugSamplePacket.SERIALIZER), entry(DeleteChatPacket.class, DeleteChatPacket.SERIALIZER), entry(DisconnectPacket.class, DisconnectPacket.SERIALIZER), - null, // DISGUISED_CHAT + entry(DisguisedChatPacket.class, DisguisedChatPacket.SERIALIZER), entry(EntityStatusPacket.class, EntityStatusPacket.SERIALIZER), entry(ExplosionPacket.class, ExplosionPacket.SERIALIZER), entry(UnloadChunkPacket.class, UnloadChunkPacket.SERIALIZER), diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientChangeDifficultyPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientChangeDifficultyPacket.java new file mode 100644 index 000000000..e887f89a0 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientChangeDifficultyPacket.java @@ -0,0 +1,17 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; +import net.minestom.server.world.Difficulty; +import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.Enum; + +public record ClientChangeDifficultyPacket(@NotNull Difficulty difficulty, boolean locked) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Enum(Difficulty.class), ClientChangeDifficultyPacket::difficulty, + BOOLEAN, ClientChangeDifficultyPacket::locked, + ClientChangeDifficultyPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientLockDifficultyPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientLockDifficultyPacket.java new file mode 100644 index 000000000..bb4e2b348 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientLockDifficultyPacket.java @@ -0,0 +1,13 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; + +public record ClientLockDifficultyPacket(boolean locked) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BOOLEAN, ClientLockDifficultyPacket::locked, + ClientLockDifficultyPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateJigsawBlockPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateJigsawBlockPacket.java new file mode 100644 index 000000000..9adf8af80 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientUpdateJigsawBlockPacket.java @@ -0,0 +1,32 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.coordinate.Point; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.BLOCK_POSITION; +import static net.minestom.server.network.NetworkBuffer.STRING; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +public record ClientUpdateJigsawBlockPacket( + Point location, + String name, + String target, + String pool, + String finalState, + String jointType, + int selectionPriority, + int placementPriority +) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BLOCK_POSITION, ClientUpdateJigsawBlockPacket::location, + STRING, ClientUpdateJigsawBlockPacket::name, + STRING, ClientUpdateJigsawBlockPacket::target, + STRING, ClientUpdateJigsawBlockPacket::pool, + STRING, ClientUpdateJigsawBlockPacket::finalState, + STRING, ClientUpdateJigsawBlockPacket::jointType, + VAR_INT, ClientUpdateJigsawBlockPacket::selectionPriority, + VAR_INT, ClientUpdateJigsawBlockPacket::placementPriority, + ClientUpdateJigsawBlockPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkBiomesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBiomesPacket.java new file mode 100644 index 000000000..0585129ca --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkBiomesPacket.java @@ -0,0 +1,39 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static net.minestom.server.network.NetworkBuffer.*; + +public record ChunkBiomesPacket(@NotNull List<@NotNull ChunkBiomeData> chunks) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + ChunkBiomeData.SERIALIZER.list(), ChunkBiomesPacket::chunks, + ChunkBiomesPacket::new); + + public ChunkBiomesPacket { + chunks = List.copyOf(chunks); + } + + public record ChunkBiomeData(int chunkX, int chunkZ, byte[] data) { + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, ChunkBiomeData value) { + buffer.write(INT, value.chunkZ); // x and z are inverted, not a bug + buffer.write(INT, value.chunkX); + buffer.write(BYTE_ARRAY, value.data); + } + + @Override + public ChunkBiomeData read(@NotNull NetworkBuffer buffer) { + int chunkZ = buffer.read(INT); + int chunkX = buffer.read(INT); + byte[] data = buffer.read(BYTE_ARRAY); + return new ChunkBiomeData(chunkX, chunkZ, data); + } + }; + } +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DisguisedChatPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DisguisedChatPacket.java new file mode 100644 index 000000000..b811e6044 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/DisguisedChatPacket.java @@ -0,0 +1,25 @@ +package net.minestom.server.network.packet.server.play; + +import net.kyori.adventure.text.Component; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static net.minestom.server.network.NetworkBuffer.COMPONENT; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +public record DisguisedChatPacket( + @NotNull Component message, + int type, + @NotNull Component senderName, + @Nullable Component targetName +) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + COMPONENT, DisguisedChatPacket::message, + VAR_INT, DisguisedChatPacket::type, + COMPONENT, DisguisedChatPacket::senderName, + COMPONENT.optional(), DisguisedChatPacket::targetName, + DisguisedChatPacket::new); +} From 62da78bb457145c86e77cae293e8b22e6c109cf8 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 16 Sep 2024 23:54:18 +0200 Subject: [PATCH 32/97] Handle state change in virtual threads (#2401) --- .../net/minestom/server/entity/Player.java | 46 ++--- .../player/AsyncPlayerPreLoginEvent.java | 64 +++--- .../server/listener/PlayConfigListener.java | 15 -- .../manager/PacketListenerManager.java | 2 +- .../listener/preplay/LoginListener.java | 185 +++++++++-------- .../server/network/ConnectionManager.java | 194 +++++++----------- .../server/network/PlayerProvider.java | 10 +- .../server/login/LoginSuccessPacket.java | 13 +- .../server/network/player/GameProfile.java | 4 + .../player/PlayerSocketConnection.java | 14 +- .../minestom/server/thread/Acquirable.java | 13 -- .../server/thread/AcquirableCollection.java | 5 - .../command/CommandPacketFilteringTest.java | 3 +- .../CommandSuggestionIntegrationTest.java | 9 +- .../server/entity/EntityAttributeTest.java | 5 +- .../EntityBoundingBoxIntegrationTest.java | 4 +- .../entity/EntityInstanceIntegrationTest.java | 4 +- .../entity/EntityMetaIntegrationTest.java | 13 +- .../entity/EntityRemovalIntegrationTest.java | 6 +- .../entity/EntityTeleportIntegrationTest.java | 16 +- .../entity/EntityVelocityIntegrationTest.java | 6 +- .../entity/EntityViewIntegrationTest.java | 6 +- .../entity/PassengerIntegrationTest.java | 4 +- .../entity/PlayerHeldIntegrationTest.java | 4 +- .../PlayerBlockPlacementIntegrationTest.java | 2 +- .../entity/player/PlayerIntegrationTest.java | 18 +- .../player/PlayerMovementIntegrationTest.java | 10 +- .../PlayerRespawnChunkIntegrationTest.java | 6 +- .../instance/ChunkViewerIntegrationTest.java | 6 +- .../InstanceBlockPacketIntegrationTest.java | 4 +- .../InstanceUnregisterIntegrationTest.java | 2 +- .../minestom/server/instance/WeatherTest.java | 2 +- .../inventory/InventoryCloseStateTest.java | 2 +- .../inventory/InventoryIntegrationTest.java | 21 +- .../inventory/PlayerCreativeSlotTest.java | 4 +- .../PlayerInventoryIntegrationTest.java | 20 +- .../server/network/PacketWriteReadTest.java | 3 +- .../server/permission/TestPermissions.java | 3 +- .../utils/TranslationIntegrationTest.java | 6 +- .../main/java/net/minestom/testing/Env.java | 2 +- .../net/minestom/testing/TestConnection.java | 4 +- .../minestom/testing/TestConnectionImpl.java | 50 +++-- .../net/minestom/testing/TestPlayerImpl.java | 20 -- 43 files changed, 366 insertions(+), 464 deletions(-) delete mode 100644 src/main/java/net/minestom/server/listener/PlayConfigListener.java delete mode 100644 testing/src/main/java/net/minestom/testing/TestPlayerImpl.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 1fb7b433d..f0f9697da 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -63,13 +63,15 @@ import net.minestom.server.network.PlayerProvider; import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.common.*; +import net.minestom.server.network.packet.server.common.KeepAlivePacket; +import net.minestom.server.network.packet.server.common.PluginMessagePacket; +import net.minestom.server.network.packet.server.common.ResourcePackPopPacket; +import net.minestom.server.network.packet.server.common.ResourcePackPushPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.data.WorldPos; import net.minestom.server.network.player.ClientSettings; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.registry.DynamicRegistry; @@ -121,6 +123,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou private long lastKeepAlive; private boolean answerKeepAlive; + private final GameProfile gameProfile; private String username; private Component usernameComponent; protected final PlayerConnection playerConnection; @@ -222,9 +225,10 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // The future is non-null when a resource pack is in-flight, and completed when all statuses have been received. private CompletableFuture resourcePackFuture = null; - public Player(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) { - super(EntityType.PLAYER, uuid); - this.username = username; + public Player(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) { + super(EntityType.PLAYER, gameProfile.uuid()); + this.gameProfile = gameProfile; + this.username = gameProfile.name(); this.usernameComponent = Component.text(username); this.playerConnection = playerConnection; @@ -245,7 +249,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // FakePlayer init its connection there playerConnectionInit(); - this.identity = Identity.identity(uuid); + this.identity = Identity.identity(gameProfile.uuid()); this.pointers = Pointers.builder() .withDynamic(Identity.UUID, this::getUuid) .withDynamic(Identity.NAME, this::getUsername) @@ -297,15 +301,10 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Add player to list with spawning skin PlayerSkin profileSkin = null; - if (playerConnection instanceof PlayerSocketConnection socketConnection) { - final GameProfile gameProfile = socketConnection.gameProfile(); - if (gameProfile != null) { - for (GameProfile.Property property : gameProfile.properties()) { - if (property.name().equals("textures")) { - profileSkin = new PlayerSkin(property.value(), property.signature()); - break; - } - } + for (GameProfile.Property property : gameProfile.properties()) { + if (property.name().equals("textures")) { + profileSkin = new PlayerSkin(property.value(), property.signature()); + break; } } PlayerSkinInitEvent skinInitEvent = new PlayerSkinInitEvent(this, profileSkin); @@ -372,13 +371,9 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou public void startConfigurationPhase() { Check.stateCondition(playerConnection.getConnectionState() != ConnectionState.PLAY, "Player must be in the play state for reconfiguration."); - // Remove the player, then send them back to configuration remove(false); - - var connectionManager = MinecraftServer.getConnectionManager(); - connectionManager.transitionPlayToConfig(this); - + MinecraftServer.getConnectionManager().transitionPlayToConfig(this); } /** @@ -1265,17 +1260,6 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou return username; } - /** - * Changes the internal player name, used for the {@link AsyncPlayerPreLoginEvent} - * mostly unsafe outside of it. - * - * @param username the new player name - */ - public void setUsernameField(@NotNull String username) { - this.username = username; - this.usernameComponent = Component.text(username); - } - /** * Calls an {@link ItemDropEvent} with a specified item. *

diff --git a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java index cfe3a4eaa..426af5644 100644 --- a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java +++ b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java @@ -1,7 +1,7 @@ package net.minestom.server.event.player; -import net.minestom.server.entity.Player; -import net.minestom.server.event.trait.PlayerEvent; +import net.minestom.server.event.Event; +import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; import org.jetbrains.annotations.NotNull; @@ -13,63 +13,49 @@ import java.util.concurrent.CompletableFuture; * Called before the player initialization, it can be used to kick the player before any connection * or to change his final username/uuid. */ -public class AsyncPlayerPreLoginEvent implements PlayerEvent { +public class AsyncPlayerPreLoginEvent implements Event { - private final Player player; + private GameProfile gameProfile; private final LoginPluginMessageProcessor pluginMessageProcessor; - private String username; - - public AsyncPlayerPreLoginEvent(@NotNull Player player, @NotNull LoginPluginMessageProcessor pluginMessageProcessor) { - this.player = player; + public AsyncPlayerPreLoginEvent(@NotNull GameProfile gameProfile, + @NotNull LoginPluginMessageProcessor pluginMessageProcessor) { + this.gameProfile = gameProfile; this.pluginMessageProcessor = pluginMessageProcessor; - this.username = player.getUsername(); } - /** - * Gets the player username. - * - * @return the player username - */ - @NotNull - public String getUsername() { - return username; + public GameProfile getGameProfile() { + return gameProfile; } - /** - * Changes the player username. - * - * @param username the new player username - */ - public void setUsername(@NotNull String username) { - this.username = username; - } - - /** - * Gets the player uuid. - * - * @return the player uuid - */ - @NotNull - public UUID getPlayerUuid() { - return player.getUuid(); + public void setGameProfile(GameProfile gameProfile) { + this.gameProfile = gameProfile; } /** * Sends a login plugin message request. Can be useful to negotiate with modded clients or * proxies before moving on to the Configuration state. * - * @param channel the plugin message channel + * @param channel the plugin message channel * @param requestPayload the contents of the plugin message, can be null for empty - * * @return a CompletableFuture for the response. The thread on which it completes is asynchronous. */ public @NotNull CompletableFuture sendPluginRequest(String channel, byte[] requestPayload) { return pluginMessageProcessor.request(channel, requestPayload); } - @Override - public @NotNull Player getPlayer() { - return player; + @Deprecated + public @NotNull String getUsername() { + return gameProfile.name(); + } + + @Deprecated + public void setUsername(@NotNull String username) { + this.gameProfile = new GameProfile(gameProfile.uuid(), username, gameProfile.properties()); + } + + @Deprecated + public @NotNull UUID getPlayerUuid() { + return gameProfile.uuid(); } } diff --git a/src/main/java/net/minestom/server/listener/PlayConfigListener.java b/src/main/java/net/minestom/server/listener/PlayConfigListener.java deleted file mode 100644 index d486125be..000000000 --- a/src/main/java/net/minestom/server/listener/PlayConfigListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.minestom.server.listener; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.entity.Player; -import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; -import org.jetbrains.annotations.NotNull; - -public class PlayConfigListener { - private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); - - public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) { - CONNECTION_MANAGER.doConfiguration(player, false); - } -} diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 9896cd696..646a94a13 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -65,7 +65,7 @@ public final class PacketListenerManager { setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener); setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener); setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener); - setPlayListener(ClientConfigurationAckPacket.class, PlayConfigListener::configAckListener); + setPlayListener(ClientConfigurationAckPacket.class, LoginListener::configAckListener); setPlayListener(ClientPongPacket.class, WindowListener::pong); setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener); setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener); diff --git a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java index 63779de95..0d1aefad6 100644 --- a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java @@ -10,19 +10,18 @@ import net.minestom.server.extras.MojangAuth; import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.mojangAuth.MojangCrypt; import net.minestom.server.extras.velocity.VelocityProxy; -import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; +import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; import net.minestom.server.network.packet.server.login.EncryptionRequestPacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; -import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.mojang.MojangUtils; import org.jetbrains.annotations.NotNull; @@ -33,14 +32,15 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import static net.minestom.server.network.NetworkBuffer.STRING; public final class LoginListener { - private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); - private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED); private static final Component ERROR_DURING_LOGIN = Component.text("Error during login!", NamedTextColor.RED); private static final Component ERROR_MALFORMED_USERNAME = Component.text("Error malformed username", NamedTextColor.RED); @@ -65,7 +65,7 @@ public final class LoginListener { if (MojangAuth.isEnabled() && isSocketConnection) { // Mojang auth - if (CONNECTION_MANAGER.getOnlinePlayerByUsername(packet.username()) != null) { + if (MinecraftServer.getConnectionManager().getOnlinePlayerByUsername(packet.username()) != null) { connection.kick(ALREADY_CONNECTED); return; } @@ -77,84 +77,76 @@ public final class LoginListener { socketConnection.setNonce(nonce); socketConnection.sendPacket(new EncryptionRequestPacket("", publicKey, nonce, true)); } else { - final boolean bungee = BungeeCordProxy.isEnabled(); // Offline - AsyncUtils.runAsync(() -> { - try { - final UUID playerUuid; - if (bungee && isSocketConnection) - playerUuid = ((PlayerSocketConnection) connection).gameProfile().uuid(); - else playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, packet.username()); - CONNECTION_MANAGER.createPlayer(connection, playerUuid, packet.username()); - - } catch (Exception exception) { - connection.kick(Component.text(exception.getClass().getSimpleName() + ": " + exception.getMessage())); - MinecraftServer.getExceptionManager().handleException(exception); - } - }); + final GameProfile gameProfile; + if (BungeeCordProxy.isEnabled()) { + // LEGACY FORWARDING + // Use game profile set during handshake + assert connection instanceof PlayerSocketConnection; + final GameProfile bungeeProfile = ((PlayerSocketConnection) connection).gameProfile(); + assert bungeeProfile != null; + gameProfile = new GameProfile(bungeeProfile.uuid(), packet.username(), bungeeProfile.properties()); + } else { + gameProfile = new GameProfile(packet.profileId(), packet.username()); + } + enterConfig(connection, gameProfile); } } public static void loginEncryptionResponseListener(@NotNull ClientEncryptionResponsePacket packet, @NotNull PlayerConnection connection) { // Encryption is only support for socket connection if (!(connection instanceof PlayerSocketConnection socketConnection)) return; - AsyncUtils.runAsync(() -> { - final String loginUsername = socketConnection.getLoginUsername(); - if (loginUsername == null || loginUsername.isEmpty()) { - // Shouldn't happen, but in case - connection.kick(ERROR_MALFORMED_USERNAME); - return; + final String loginUsername = socketConnection.getLoginUsername(); + if (loginUsername == null || loginUsername.isEmpty()) { + // Shouldn't happen, but in case + connection.kick(ERROR_MALFORMED_USERNAME); + return; + } + + final boolean hasPublicKey = connection.playerPublicKey() != null; + final boolean verificationFailed = hasPublicKey || !Arrays.equals(socketConnection.getNonce(), + MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), packet.encryptedVerifyToken())); + + if (verificationFailed) { + MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername); + connection.kick(ENCRYPTION_FAILED); + return; + } + + final SecretKey secretKey = MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), packet.sharedSecret()); + final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), secretKey); + if (digestedData == null) { + // Incorrect key, probably because of the client + MinecraftServer.LOGGER.error("Connection {} failed initializing encryption.", socketConnection.getRemoteAddress()); + connection.kick(ENCRYPTION_FAILED); + return; + } + // Query Mojang's session server. + final String serverId = new BigInteger(digestedData).toString(16); + + try { + final JsonObject gameProfileJson = MojangUtils.authenticateSession(loginUsername, serverId, socketConnection.getRemoteAddress()); + + // We have verified the session, parse response. + socketConnection.setEncryptionKey(secretKey); + final UUID profileUUID = UUID.fromString(gameProfileJson.get("id").getAsString() + .replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); + final String profileName = gameProfileJson.get("name").getAsString(); + + MinecraftServer.LOGGER.info("UUID of player {} is {}", profileName, profileUUID); + List propertyList = new ArrayList<>(); + for (JsonElement element : gameProfileJson.get("properties").getAsJsonArray()) { + JsonObject object = element.getAsJsonObject(); + propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString())); } - - final boolean hasPublicKey = connection.playerPublicKey() != null; - final boolean verificationFailed = hasPublicKey || !Arrays.equals(socketConnection.getNonce(), - MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), packet.encryptedVerifyToken())); - - if (verificationFailed) { - MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername); - connection.kick(ENCRYPTION_FAILED); - return; - } - - final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), getSecretKey(packet.sharedSecret())); - if (digestedData == null) { - // Incorrect key, probably because of the client - MinecraftServer.LOGGER.error("Connection {} failed initializing encryption.", socketConnection.getRemoteAddress()); - connection.kick(ENCRYPTION_FAILED); - return; - } - // Query Mojang's session server. - final String serverId = new BigInteger(digestedData).toString(16); - - try { - final JsonObject gameProfile = MojangUtils.authenticateSession(loginUsername, serverId, socketConnection.getRemoteAddress()); - - // We have verified the session, parse response. - socketConnection.setEncryptionKey(getSecretKey(packet.sharedSecret())); - final UUID profileUUID = UUID.fromString(gameProfile.get("id").getAsString() - .replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); - final String profileName = gameProfile.get("name").getAsString(); - - MinecraftServer.LOGGER.info("UUID of player {} is {}", profileName, profileUUID); - CONNECTION_MANAGER.createPlayer(connection, profileUUID, profileName); - List propertyList = new ArrayList<>(); - for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) { - JsonObject object = element.getAsJsonObject(); - propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString())); - } - socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList)); - } catch (IOException e) { - socketConnection.kick(ERROR_MOJANG_RESPONSE); - MinecraftServer.getExceptionManager().handleException(e); - } catch (Exception e) { - socketConnection.kick(ERROR_DURING_LOGIN); - MinecraftServer.getExceptionManager().handleException(e); - } - }); - } - - private static SecretKey getSecretKey(byte[] sharedSecret) { - return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret); + enterConfig(connection, new GameProfile(profileUUID, profileName, propertyList)); + } catch (IOException e) { + socketConnection.kick(ERROR_MOJANG_RESPONSE); + MinecraftServer.getExceptionManager().handleException(e); + } catch (Exception e) { + socketConnection.kick(ERROR_DURING_LOGIN); + MinecraftServer.getExceptionManager().handleException(e); + } } private static void handleVelocityProxyResponse(PlayerSocketConnection socketConnection, LoginPlugin.Response response) { @@ -180,14 +172,12 @@ public final class LoginListener { gameProfile = GameProfile.SERIALIZER.read(buffer); } } - - if (success) { - socketConnection.setRemoteAddress(socketAddress); - socketConnection.UNSAFE_setProfile(gameProfile); - CONNECTION_MANAGER.createPlayer(socketConnection, gameProfile.uuid(), gameProfile.name()); - } else { + if (!success) { socketConnection.kick(INVALID_PROXY_RESPONSE); + return; } + socketConnection.setRemoteAddress(socketAddress); + enterConfig(socketConnection, gameProfile); } public static void loginPluginResponseListener(@NotNull ClientLoginPluginResponsePacket packet, @NotNull PlayerConnection connection) { @@ -202,8 +192,35 @@ public final class LoginListener { } public static void loginAckListener(@NotNull ClientLoginAcknowledgedPacket ignored, @NotNull PlayerConnection connection) { - final Player player = Objects.requireNonNull(connection.getPlayer()); - CONNECTION_MANAGER.doConfiguration(player, true); + if (!(connection instanceof PlayerSocketConnection socketConnection)) + throw new UnsupportedOperationException("Only socket"); + final GameProfile gameProfile = socketConnection.gameProfile(); + assert gameProfile != null; + final Player player = MinecraftServer.getConnectionManager().createPlayer(connection, gameProfile); + executeConfig(player, true); } + public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) { + executeConfig(player, false); + } + + private static void enterConfig(PlayerConnection connection, GameProfile gameProfile) { + gameProfile = MinecraftServer.getConnectionManager().transitionLoginToConfig(connection, gameProfile); + if (connection instanceof PlayerSocketConnection socketConnection) { + socketConnection.UNSAFE_setProfile(gameProfile); + } + } + + private static void executeConfig(Player player, boolean isFirstConfig) { + // We have to create another thread (even though we should already be in a virtual thread) + // because configuration handling involves waiting for the client to send a known packs packet. + // Which mean that we have to free up the current thread to continue reading the socket. + Thread.startVirtualThread(() -> { + try { + MinecraftServer.getConnectionManager().doConfiguration(player, isFirstConfig); + } catch (Throwable t) { + MinecraftServer.getExceptionManager().handleException(t); + } + }); + } } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 5154906ba..8f36c863d 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -10,7 +10,6 @@ import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.AsyncPlayerPreLoginEvent; import net.minestom.server.instance.Instance; import net.minestom.server.listener.preplay.LoginListener; -import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.common.KeepAlivePacket; import net.minestom.server.network.packet.server.common.PluginMessagePacket; @@ -21,12 +20,12 @@ import net.minestom.server.network.packet.server.configuration.SelectKnownPacksP import net.minestom.server.network.packet.server.configuration.UpdateEnabledFeaturesPacket; import net.minestom.server.network.packet.server.login.LoginSuccessPacket; import net.minestom.server.network.packet.server.play.StartConfigurationPacket; +import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.StringUtils; -import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.validate.Check; import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MpscUnboundedArrayQueue; @@ -72,11 +71,6 @@ public final class ConnectionManager { private final Set unmodifiableConfigurationPlayers = Collections.unmodifiableSet(configurationPlayers); private final Set unmodifiablePlayPlayers = Collections.unmodifiableSet(playPlayers); - private final CachedPacket resetChatPacket = new CachedPacket(new ResetChatPacket()); - - - // The uuid provider once a player login - private volatile UuidProvider uuidProvider = (playerConnection, username) -> UUID.randomUUID(); // The player provider to have your own Player implementation private volatile PlayerProvider playerProvider = Player::new; @@ -169,35 +163,6 @@ public final class ConnectionManager { .orElse(null); } - /** - * Changes how {@link UUID} are attributed to players. - *

- * Shouldn't be override if already defined. - *

- * Be aware that it is possible for an UUID provider to be ignored, for example in the case of a proxy (eg: velocity). - * - * @param uuidProvider the new player connection uuid provider, - * setting it to null would apply a random UUID for each player connection - * @see #getPlayerConnectionUuid(PlayerConnection, String) - */ - public void setUuidProvider(@Nullable UuidProvider uuidProvider) { - this.uuidProvider = uuidProvider != null ? uuidProvider : (playerConnection, username) -> UUID.randomUUID(); - } - - /** - * Computes the UUID of the specified connection. - * Used in {@link ClientLoginStartPacket} in order - * to give the player the right {@link UUID}. - * - * @param playerConnection the player connection - * @param username the username given by the connection - * @return the uuid based on {@code playerConnection} - * return a random UUID if no UUID provider is defined see {@link #setUuidProvider(UuidProvider)} - */ - public @NotNull UUID getPlayerConnectionUuid(@NotNull PlayerConnection playerConnection, @NotNull String username) { - return uuidProvider.provide(playerConnection, username); - } - /** * Changes the {@link Player} provider, to change which object to link to him. * @@ -207,57 +172,38 @@ public final class ConnectionManager { this.playerProvider = playerProvider != null ? playerProvider : Player::new; } - /** - * Creates a player object and begins the transition from the login state to the config state. - */ @ApiStatus.Internal - public @NotNull Player createPlayer(@NotNull PlayerConnection connection, @NotNull UUID uuid, @NotNull String username) { - final Player player = playerProvider.createPlayer(uuid, username, connection); + public @NotNull Player createPlayer(@NotNull PlayerConnection connection, @NotNull GameProfile gameProfile) { + assert ServerFlag.INSIDE_TEST || Thread.currentThread().isVirtual(); + final Player player = playerProvider.createPlayer(connection, gameProfile); this.connectionPlayerMap.put(connection, player); - var future = transitionLoginToConfig(player); - if (ServerFlag.INSIDE_TEST) future.join(); return player; } - @ApiStatus.Internal - public @NotNull CompletableFuture transitionLoginToConfig(@NotNull Player player) { - return AsyncUtils.runAsync(() -> { - final PlayerConnection playerConnection = player.getPlayerConnection(); - - // Compression - if (playerConnection instanceof PlayerSocketConnection socketConnection) { - final int threshold = MinecraftServer.getCompressionThreshold(); - if (threshold > 0) socketConnection.startCompression(); - } - - // Call pre login event - LoginPluginMessageProcessor pluginMessageProcessor = playerConnection.loginPluginMessageProcessor(); - AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player, pluginMessageProcessor); - EventDispatcher.call(asyncPlayerPreLoginEvent); - if (!player.isOnline()) - return; // Player has been kicked - - // Change UUID/Username based on the event - { - final String eventUsername = asyncPlayerPreLoginEvent.getUsername(); - final UUID eventUuid = asyncPlayerPreLoginEvent.getPlayerUuid(); - if (!player.getUsername().equals(eventUsername)) { - player.setUsernameField(eventUsername); - } - } - - // Wait for pending login plugin messages - try { - pluginMessageProcessor.awaitReplies(ServerFlag.LOGIN_PLUGIN_MESSAGE_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (Throwable t) { - player.kick(LoginListener.INVALID_PROXY_RESPONSE); - throw new RuntimeException("Error getting replies for login plugin messages", t); - } - - // Send login success packet (and switch to configuration phase) - LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(player.getUuid(), player.getUsername(), 0, true); - playerConnection.sendPacket(loginSuccessPacket); - }); + public GameProfile transitionLoginToConfig(@NotNull PlayerConnection connection, @NotNull GameProfile gameProfile) { + assert ServerFlag.INSIDE_TEST || Thread.currentThread().isVirtual(); + // Compression + if (connection instanceof PlayerSocketConnection socketConnection) { + final int threshold = MinecraftServer.getCompressionThreshold(); + if (threshold > 0) socketConnection.startCompression(); + } + // Call pre login event + LoginPluginMessageProcessor pluginMessageProcessor = connection.loginPluginMessageProcessor(); + AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(gameProfile, pluginMessageProcessor); + EventDispatcher.call(asyncPlayerPreLoginEvent); + if (!connection.isOnline()) return gameProfile; // Player has been kicked + // Change UUID/Username based on the event + gameProfile = asyncPlayerPreLoginEvent.getGameProfile(); + // Wait for pending login plugin messages + try { + pluginMessageProcessor.awaitReplies(ServerFlag.LOGIN_PLUGIN_MESSAGE_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (Throwable t) { + connection.kick(LoginListener.INVALID_PROXY_RESPONSE); + throw new RuntimeException("Error getting replies for login plugin messages", t); + } + // Send login success packet (and switch to configuration phase) + connection.sendPacket(new LoginSuccessPacket(gameProfile, true)); + return gameProfile; } @ApiStatus.Internal @@ -270,7 +216,8 @@ public final class ConnectionManager { * Return value exposed for testing */ @ApiStatus.Internal - public CompletableFuture doConfiguration(@NotNull Player player, boolean isFirstConfig) { + public void doConfiguration(@NotNull Player player, boolean isFirstConfig) { + assert ServerFlag.INSIDE_TEST || Thread.currentThread().isVirtual(); if (isFirstConfig) { configurationPlayers.add(player); keepAlivePlayers.add(player); @@ -283,56 +230,53 @@ public final class ConnectionManager { // Request known packs immediately, but don't wait for the response until required (sending registry data). final var knownPacksFuture = connection.requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE)); - return AsyncUtils.runAsync(() -> { - var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig); - EventDispatcher.call(event); - if (!player.isOnline()) return; // Player was kicked during config. + var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig); + EventDispatcher.call(event); + if (!player.isOnline()) return; // Player was kicked during config. - player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags().stream().map(StaticProtocolObject::name).toList())); // send player features that were enabled or disabled during async config event + // send player features that were enabled or disabled during async config event + player.sendPacket(new UpdateEnabledFeaturesPacket(event.getFeatureFlags().stream().map(StaticProtocolObject::name).toList())); - final Instance spawningInstance = event.getSpawningInstance(); - Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); + final Instance spawningInstance = event.getSpawningInstance(); + Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); - if (event.willClearChat()) { - player.sendPacket(resetChatPacket); + if (event.willClearChat()) player.sendPacket(new ResetChatPacket()); + + // Registry data (if it should be sent) + if (event.willSendRegistryData()) { + List knownPacks; + try { + knownPacks = knownPacksFuture.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException e) { + throw new RuntimeException("Client failed to respond to known packs request", e); + } catch (ExecutionException e) { + throw new RuntimeException("Error receiving known packs", e); } + boolean excludeVanilla = knownPacks.contains(SelectKnownPacksPacket.MINECRAFT_CORE); - // Registry data (if it should be sent) - if (event.willSendRegistryData()) { - List knownPacks; - try { - knownPacks = knownPacksFuture.get(5, TimeUnit.SECONDS); - } catch (InterruptedException | TimeoutException e) { - throw new RuntimeException("Client failed to respond to known packs request", e); - } catch (ExecutionException e) { - throw new RuntimeException("Error receiving known packs", e); - } - boolean excludeVanilla = knownPacks.contains(SelectKnownPacksPacket.MINECRAFT_CORE); + var serverProcess = MinecraftServer.process(); + player.sendPacket(serverProcess.chatType().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.dimensionType().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.biome().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.damageType().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.trimMaterial().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.trimPattern().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.bannerPattern().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.wolfVariant().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.enchantment().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.paintingVariant().registryDataPacket(excludeVanilla)); + player.sendPacket(serverProcess.jukeboxSong().registryDataPacket(excludeVanilla)); - var serverProcess = MinecraftServer.process(); - player.sendPacket(serverProcess.chatType().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.dimensionType().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.biome().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.damageType().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.trimMaterial().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.trimPattern().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.bannerPattern().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.wolfVariant().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.enchantment().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.paintingVariant().registryDataPacket(excludeVanilla)); - player.sendPacket(serverProcess.jukeboxSong().registryDataPacket(excludeVanilla)); + player.sendPacket(getDefaultTags()); + } - player.sendPacket(getDefaultTags()); - } + // Wait for pending resource packs if any + var packFuture = player.getResourcePackFuture(); + if (packFuture != null) packFuture.join(); - // Wait for pending resource packs if any - var packFuture = player.getResourcePackFuture(); - if (packFuture != null) packFuture.join(); - - keepAlivePlayers.remove(player); - player.setPendingOptions(spawningInstance, event.isHardcore()); - player.sendPacket(new FinishConfigurationPacket()); - }); + keepAlivePlayers.remove(player); + player.setPendingOptions(spawningInstance, event.isHardcore()); + player.sendPacket(new FinishConfigurationPacket()); } @ApiStatus.Internal diff --git a/src/main/java/net/minestom/server/network/PlayerProvider.java b/src/main/java/net/minestom/server/network/PlayerProvider.java index e967daacb..565ad339c 100644 --- a/src/main/java/net/minestom/server/network/PlayerProvider.java +++ b/src/main/java/net/minestom/server/network/PlayerProvider.java @@ -1,11 +1,10 @@ package net.minestom.server.network; import net.minestom.server.entity.Player; +import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import org.jetbrains.annotations.NotNull; -import java.util.UUID; - /** * Used when you want to provide your own player object instead of using the default one. *

@@ -19,10 +18,9 @@ public interface PlayerProvider { *

* Called once a client want to join the server and need to have an assigned player object. * - * @param uuid the player {@link UUID} - * @param username the player username - * @param connection the player connection + * @param connection the player connection + * @param gameProfile the player game profile * @return a newly create {@link Player} object */ - @NotNull Player createPlayer(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection connection); + @NotNull Player createPlayer(@NotNull PlayerConnection connection, @NotNull GameProfile gameProfile); } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java index e2d0a147d..8ab58aa16 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java @@ -3,18 +3,15 @@ package net.minestom.server.network.packet.server.login; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.player.GameProfile; import org.jetbrains.annotations.NotNull; -import java.util.UUID; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; -import static net.minestom.server.network.NetworkBuffer.*; - -public record LoginSuccessPacket(@NotNull UUID uuid, @NotNull String username, - int properties, boolean strictErrorHandling) implements ServerPacket.Login { +public record LoginSuccessPacket(@NotNull GameProfile gameProfile, + boolean strictErrorHandling) implements ServerPacket.Login { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - UUID, LoginSuccessPacket::uuid, - STRING, LoginSuccessPacket::username, - VAR_INT, LoginSuccessPacket::properties, + GameProfile.SERIALIZER, LoginSuccessPacket::gameProfile, BOOLEAN, LoginSuccessPacket::strictErrorHandling, LoginSuccessPacket::new); } diff --git a/src/main/java/net/minestom/server/network/player/GameProfile.java b/src/main/java/net/minestom/server/network/player/GameProfile.java index 0ca30cc89..6928bf8b4 100644 --- a/src/main/java/net/minestom/server/network/player/GameProfile.java +++ b/src/main/java/net/minestom/server/network/player/GameProfile.java @@ -22,6 +22,10 @@ public record GameProfile(@NotNull UUID uuid, @NotNull String name, properties = List.copyOf(properties); } + public GameProfile(@NotNull UUID uuid, @NotNull String name) { + this(uuid, name, List.of()); + } + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( NetworkBuffer.UUID, GameProfile::uuid, STRING, GameProfile::name, diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index 453523497..5366cddfc 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -18,11 +18,13 @@ import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.common.ClientCookieResponsePacket; import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket; import net.minestom.server.network.packet.client.common.ClientPingRequestPacket; +import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; +import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; import net.minestom.server.network.packet.client.status.StatusRequestPacket; import net.minestom.server.network.packet.server.*; import net.minestom.server.network.packet.server.login.SetCompressionPacket; @@ -52,15 +54,17 @@ import java.util.zip.DataFormatException; @ApiStatus.Internal public class PlayerSocketConnection extends PlayerConnection { private static final Set> IMMEDIATE_PROCESS_PACKETS = Set.of( + ClientHandshakePacket.class, // First received packet ClientCookieResponsePacket.class, StatusRequestPacket.class, - ClientLoginStartPacket.class, ClientPingRequestPacket.class, - ClientKeepAlivePacket.class, - ClientEncryptionResponsePacket.class, - ClientHandshakePacket.class, + ClientKeepAlivePacket.class, // Used to calculate latency + ClientLoginStartPacket.class, + ClientEncryptionResponsePacket.class, // Auth request ClientLoginPluginResponsePacket.class, - ClientLoginAcknowledgedPacket.class + ClientSelectKnownPacksPacket.class, // Immediate answer to server request on config + ClientConfigurationAckPacket.class, // Handle config state + ClientLoginAcknowledgedPacket.class // Handle config state ); private final SocketChannel channel; diff --git a/src/main/java/net/minestom/server/thread/Acquirable.java b/src/main/java/net/minestom/server/thread/Acquirable.java index ab56f33af..38636242f 100644 --- a/src/main/java/net/minestom/server/thread/Acquirable.java +++ b/src/main/java/net/minestom/server/thread/Acquirable.java @@ -1,7 +1,6 @@ package net.minestom.server.thread; import net.minestom.server.entity.Entity; -import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -98,7 +97,6 @@ public sealed interface Acquirable permits AcquirableImpl { * Free if the element is already present in the current thread, blocking otherwise. * * @param consumer the callback to execute once the element has been safely acquired - * @see #async(Consumer) */ default void sync(@NotNull Consumer consumer) { Acquired acquired = lock(); @@ -109,17 +107,6 @@ public sealed interface Acquirable permits AcquirableImpl { } } - /** - * Async version of {@link #sync(Consumer)}. - * - * @param consumer the callback to execute once the element has been safely acquired - * @see #sync(Consumer) - */ - default void async(@NotNull Consumer consumer) { - // TODO per-thread list - AsyncUtils.runAsync(() -> sync(consumer)); - } - /** * Unwrap the contained object unsafely. *

diff --git a/src/main/java/net/minestom/server/thread/AcquirableCollection.java b/src/main/java/net/minestom/server/thread/AcquirableCollection.java index cf8541b28..17125e57d 100644 --- a/src/main/java/net/minestom/server/thread/AcquirableCollection.java +++ b/src/main/java/net/minestom/server/thread/AcquirableCollection.java @@ -1,6 +1,5 @@ package net.minestom.server.thread; -import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -35,10 +34,6 @@ public class AcquirableCollection implements Collection> { } } - public void acquireAsync(@NotNull Consumer consumer) { - AsyncUtils.runAsync(() -> acquireSync(consumer)); - } - public @NotNull Stream unwrap() { return acquirableCollection.stream().map(Acquirable::unwrap); } diff --git a/src/test/java/net/minestom/server/command/CommandPacketFilteringTest.java b/src/test/java/net/minestom/server/command/CommandPacketFilteringTest.java index 0ce8a207f..72933e7f8 100644 --- a/src/test/java/net/minestom/server/command/CommandPacketFilteringTest.java +++ b/src/test/java/net/minestom/server/command/CommandPacketFilteringTest.java @@ -4,6 +4,7 @@ import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.ArgumentType; import net.minestom.server.entity.Player; import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import net.minestom.server.network.player.GameProfile; import org.junit.jupiter.api.Test; import java.util.Set; @@ -11,7 +12,7 @@ import java.util.UUID; @SuppressWarnings("ConstantConditions") public class CommandPacketFilteringTest { - private static final Player PLAYER = new Player(UUID.randomUUID(), "", null); + private static final Player PLAYER = new Player(null, new GameProfile(UUID.randomUUID(), "Test")); @Test public void singleCommandFilteredFalse() { diff --git a/src/test/java/net/minestom/server/command/CommandSuggestionIntegrationTest.java b/src/test/java/net/minestom/server/command/CommandSuggestionIntegrationTest.java index 28fc868a8..d86530f3e 100644 --- a/src/test/java/net/minestom/server/command/CommandSuggestionIntegrationTest.java +++ b/src/test/java/net/minestom/server/command/CommandSuggestionIntegrationTest.java @@ -22,7 +22,7 @@ public class CommandSuggestionIntegrationTest { public void suggestion(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); var command = new Command("test"); command.addSyntax((sender, context) -> { @@ -53,7 +53,7 @@ public class CommandSuggestionIntegrationTest { public void suggestionWithDefaults(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); var suggestArg = Word("suggestArg").setSuggestionCallback( (sender, context, suggestion) -> suggestion.addEntry(new SuggestionEntry("suggestion")) @@ -78,7 +78,7 @@ public class CommandSuggestionIntegrationTest { public void suggestionWithSubcommand(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); var command = new Command("foo"); @@ -112,7 +112,7 @@ public class CommandSuggestionIntegrationTest { public void suggestionWithTwoLiterals(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); var command = new Command("foo"); @@ -137,5 +137,4 @@ public class CommandSuggestionIntegrationTest { assertEquals(List.of(new TabCompletePacket.Match("suggestionB", null)), tabCompletePacket.matches()); }); } - } diff --git a/src/test/java/net/minestom/server/entity/EntityAttributeTest.java b/src/test/java/net/minestom/server/entity/EntityAttributeTest.java index 521d3712a..2105f8be4 100644 --- a/src/test/java/net/minestom/server/entity/EntityAttributeTest.java +++ b/src/test/java/net/minestom/server/entity/EntityAttributeTest.java @@ -14,7 +14,6 @@ import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; @EnvTest public class EntityAttributeTest { @@ -49,7 +48,7 @@ public class EntityAttributeTest { public void testPlayerUpdatesAttributes(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 1)).join(); + var player = connection.connect(instance, new Pos(0, 42, 1)); double baseHealth = 20; double addition = 10; @@ -77,7 +76,7 @@ public class EntityAttributeTest { public void testDirectlyAddAttributes(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 1)).join(); + var player = connection.connect(instance, new Pos(0, 42, 1)); double baseHealth = 20; double addition = 10; diff --git a/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java index caaf72511..33a58b434 100644 --- a/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityBoundingBoxIntegrationTest.java @@ -18,7 +18,7 @@ public class EntityBoundingBoxIntegrationTest { public void pose(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); // Bounding box should be from the registry assertEquals(player.getEntityType().registry().boundingBox(), player.getBoundingBox()); @@ -39,7 +39,7 @@ public class EntityBoundingBoxIntegrationTest { public void eyeHeight(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(1.62, player.getEyeHeight()); diff --git a/src/test/java/net/minestom/server/entity/EntityInstanceIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityInstanceIntegrationTest.java index 5a9d128ef..051af85cf 100644 --- a/src/test/java/net/minestom/server/entity/EntityInstanceIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityInstanceIntegrationTest.java @@ -1,8 +1,8 @@ package net.minestom.server.entity; +import net.minestom.server.coordinate.Pos; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; -import net.minestom.server.coordinate.Pos; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -35,7 +35,7 @@ public class EntityInstanceIntegrationTest { var instance = env.createFlatInstance(); var instance2 = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); // #join may cause the thread to hang as scheduled for the next tick when initially in a pool Assertions.assertTimeout(Duration.ofSeconds(2), () -> player.setInstance(instance2).join()); diff --git a/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java index bf3e916e2..417367d88 100644 --- a/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityMetaIntegrationTest.java @@ -20,8 +20,9 @@ public class EntityMetaIntegrationTest { public void notifyAboutChanges(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var otherPlayer = connection.connect(instance, new Pos(0, 42, 0)).join(); - var player = connection.connect(instance, new Pos(0, 42, 1)).join(); + var connection2 = env.createConnection(); + var player = connection.connect(instance, new Pos(0, 42, 1)); + var otherPlayer = connection2.connect(instance, new Pos(0, 42, 0)); assertTrue(player.getViewers().contains(otherPlayer)); @@ -38,8 +39,7 @@ public class EntityMetaIntegrationTest { player.getEntityMeta().setNotifyAboutChanges(true); var packets = incomingPackets.collect(); - // Two packets should be received: One for the player, one for the viewer - assertEquals(2, packets.size()); + assertEquals(1, packets.size()); validMetaDataPackets(packets, player.getEntityId(), entry -> { final Object content = entry.value(); if (entry.type() == Metadata.TYPE_BYTE) { @@ -71,8 +71,7 @@ public class EntityMetaIntegrationTest { Assertions.fail("Invalid MetaData entry"); } }); - // 4 changes, for two viewers - assertEquals(4 * 2, packets.size()); + assertEquals(4, packets.size()); } private void validMetaDataPackets(List packets, int entityId, Consumer> contentChecker) { @@ -92,7 +91,7 @@ public class EntityMetaIntegrationTest { Pos startPos = new Pos(0, 42, 1); //Viewer. - var player = connection.connect(instance, startPos).join(); + var player = connection.connect(instance, startPos); //Tracks incoming packets. var incomingPackets = connection.trackIncoming(EntityMetaDataPacket.class); diff --git a/src/test/java/net/minestom/server/entity/EntityRemovalIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityRemovalIntegrationTest.java index 42d6e2f23..2f67a9c6f 100644 --- a/src/test/java/net/minestom/server/entity/EntityRemovalIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityRemovalIntegrationTest.java @@ -1,11 +1,11 @@ package net.minestom.server.entity; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.event.entity.EntityTickEvent; import net.minestom.server.network.packet.server.play.DestroyEntitiesPacket; import net.minestom.server.utils.time.TimeUnit; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import java.lang.ref.WeakReference; @@ -22,7 +22,7 @@ public class EntityRemovalIntegrationTest { public void destructionPacket(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - connection.connect(instance, new Pos(0, 40, 0)).join(); + connection.connect(instance, new Pos(0, 40, 0)); var entity = new Entity(EntityType.ZOMBIE); entity.setInstance(instance, new Pos(0, 40, 0)).join(); diff --git a/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java index f9d5cc148..df9b8f3b9 100644 --- a/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java @@ -1,12 +1,12 @@ package net.minestom.server.entity; -import net.minestom.server.network.packet.server.play.EntityHeadLookPacket; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.packet.server.play.EntityHeadLookPacket; import net.minestom.server.network.packet.server.play.EntityTeleportPacket; import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import java.util.List; @@ -44,12 +44,12 @@ public class EntityTeleportIntegrationTest { public void playerChunkTeleport(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); assertEquals(instance, player.getInstance()); assertEquals(new Pos(0, 40, 0), player.getPosition()); var viewerConnection = env.createConnection(); - viewerConnection.connect(instance, new Pos(0, 40, 0)).join(); + viewerConnection.connect(instance, new Pos(0, 40, 0)); var tracker = connection.trackIncoming(ServerPacket.class); var viewerTracker = viewerConnection.trackIncoming(ServerPacket.class); @@ -77,12 +77,12 @@ public class EntityTeleportIntegrationTest { public void playerTeleport(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); assertEquals(instance, player.getInstance()); assertEquals(new Pos(0, 40, 0), player.getPosition()); var viewerConnection = env.createConnection(); - viewerConnection.connect(instance, new Pos(0, 40, 0)).join(); + viewerConnection.connect(instance, new Pos(0, 40, 0)); var teleportPosition = new Pos(4999, 42, 4999); player.teleport(teleportPosition).join(); @@ -93,7 +93,7 @@ public class EntityTeleportIntegrationTest { public void playerTeleportWithFlagsTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 0, 0)).join(); + var player = connection.connect(instance, new Pos(0, 0, 0)); player.teleport(new Pos(10, 10, 10, 90, 0)).join(); assertEquals(player.getPosition(), new Pos(10, 10, 10, 90, 0)); diff --git a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java index 96dea24ff..c28639f50 100644 --- a/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityVelocityIntegrationTest.java @@ -135,7 +135,7 @@ public class EntityVelocityIntegrationTest { var player = env.createPlayer(instance, new Pos(0, 42, 0)); player.setFlying(true); var witness = env.createConnection(); - witness.connect(instance, new Pos(0, 42, 0)).join(); + witness.connect(instance, new Pos(0, 42, 0)); var tracker = witness.trackIncoming(EntityVelocityPacket.class); env.tick(); // Process gravity velocity @@ -173,9 +173,9 @@ public class EntityVelocityIntegrationTest { public void countVelocityPackets(Env env) { var instance = env.createFlatInstance(); var viewerConnection = env.createConnection(); - viewerConnection.connect(instance, new Pos(1, 40, 1)).join(); + viewerConnection.connect(instance, new Pos(1, 40, 1)); var entity = new Entity(EntityType.ZOMBIE); - entity.setInstance(instance, new Pos(0,40,0)).join(); + entity.setInstance(instance, new Pos(0, 40, 0)).join(); instance.setBlock(new Vec(0, 39, 0), Block.STONE); env.tick(); // Tick because the entity is in the air, they'll send velocity from gravity diff --git a/src/test/java/net/minestom/server/entity/EntityViewIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityViewIntegrationTest.java index 181b30325..bf1bed8fb 100644 --- a/src/test/java/net/minestom/server/entity/EntityViewIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityViewIntegrationTest.java @@ -1,9 +1,9 @@ package net.minestom.server.entity; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.play.SpawnEntityPacket; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -126,7 +126,7 @@ public class EntityViewIntegrationTest { public void livingVehicle(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); var vehicle = new Entity(EntityType.ZOMBIE); var passenger = new Entity(EntityType.ZOMBIE); diff --git a/src/test/java/net/minestom/server/entity/PassengerIntegrationTest.java b/src/test/java/net/minestom/server/entity/PassengerIntegrationTest.java index 2ce48c46d..929764108 100644 --- a/src/test/java/net/minestom/server/entity/PassengerIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/PassengerIntegrationTest.java @@ -1,10 +1,10 @@ package net.minestom.server.entity; +import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.play.SetPassengersPacket; import net.minestom.server.network.packet.server.play.SpawnEntityPacket; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; -import net.minestom.server.coordinate.Pos; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -65,7 +65,7 @@ public class PassengerIntegrationTest { var spawnTracker = connection.trackIncoming(SpawnEntityPacket.class); var passengerTracker = connection.trackIncoming(SetPassengersPacket.class); - connection.connect(instance, new Pos(0, 40, 0)).join(); + connection.connect(instance, new Pos(0, 40, 0)); int startingId = passenger3.getEntityId(); passengerTracker.assertCount(3); diff --git a/src/test/java/net/minestom/server/entity/PlayerHeldIntegrationTest.java b/src/test/java/net/minestom/server/entity/PlayerHeldIntegrationTest.java index ecd9a07bd..e3566e4dc 100644 --- a/src/test/java/net/minestom/server/entity/PlayerHeldIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/PlayerHeldIntegrationTest.java @@ -18,7 +18,7 @@ public class PlayerHeldIntegrationTest { public void playerHeld(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); player.getInventory().setItemStack(1, ItemStack.of(Material.STONE)); assertEquals(ItemStack.AIR, player.getItemInMainHand()); @@ -35,7 +35,7 @@ public class PlayerHeldIntegrationTest { public void playerHeldEvent(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); player.getInventory().setItemStack(1, ItemStack.of(Material.STONE)); assertEquals(ItemStack.AIR, player.getItemInMainHand()); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java index c6e0a8c33..a5753d931 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerBlockPlacementIntegrationTest.java @@ -31,7 +31,7 @@ public class PlayerBlockPlacementIntegrationTest { public void placeBlockFromAdventureMode(Block baseBlock, BlockPredicates canPlaceOn, Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); instance.setBlock(2, 41, 0, baseBlock); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java index 19667ea4e..daead97a7 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java @@ -38,7 +38,7 @@ public class PlayerIntegrationTest { public void gamemodeTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); // Abilities @@ -86,7 +86,7 @@ public class PlayerIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); env.tick(); env.tick(); @@ -134,7 +134,7 @@ public class PlayerIntegrationTest { var trackerAll = connection.trackIncoming(ServerPacket.class); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); assertEquals(instance, player.getInstance()); assertEquals(new Pos(0, 40, 0), player.getPosition()); @@ -157,7 +157,7 @@ public class PlayerIntegrationTest { var instance2 = env.process().instance().createInstanceContainer(testDimension); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var tracker1 = connection.trackIncoming(UpdateHealthPacket.class); @@ -190,7 +190,7 @@ public class PlayerIntegrationTest { var instance = env.process().instance().createInstanceContainer(testDimension); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(5, 42, 2)).join(); + var player = connection.connect(instance, new Pos(5, 42, 2)); assertNull(player.getDeathLocation()); player.damage(DamageType.OUT_OF_WORLD, 30); @@ -205,13 +205,13 @@ public class PlayerIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); var tracker = connection.trackIncoming(PlayerInfoUpdatePacket.class); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); player.setDisplayName(Component.text("Display Name!")); var connection2 = env.createConnection(); var tracker2 = connection2.trackIncoming(PlayerInfoUpdatePacket.class); - connection2.connect(instance, new Pos(0, 42, 0)).join(); + connection2.connect(instance, new Pos(0, 42, 0)); var displayNamePackets = tracker2.collect().stream().filter((packet) -> packet.actions().stream().anyMatch((act) -> act == PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) @@ -238,7 +238,7 @@ public class PlayerIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); Pos startingPlayerPos = new Pos(0, 42, 0); - var player = connection.connect(instance, startingPlayerPos).join(); + var player = connection.connect(instance, startingPlayerPos); var tracker = connection.trackIncoming(PlayerPositionAndLookPacket.class); player.setView(30, 20); @@ -256,7 +256,7 @@ public class PlayerIntegrationTest { var connection = env.createConnection(); var tracker = connection.trackIncoming(FacePlayerPacket.class); Pos startingPlayerPos = new Pos(0, 42, 0); - var player = connection.connect(instance, startingPlayerPos).join(); + var player = connection.connect(instance, startingPlayerPos); Point pointLookAt = new Vec(3, 3, 3); player.lookAt(pointLookAt); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index d8cdf782f..200a151e4 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -20,7 +20,6 @@ import net.minestom.testing.Collector; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import net.minestom.testing.TestConnection; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import java.util.HashSet; @@ -54,7 +53,7 @@ public class PlayerMovementIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); - connection.connect(instance, new Pos(0, 40, 0)).join(); + connection.connect(instance, new Pos(0, 40, 0)); p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); @@ -76,8 +75,7 @@ public class PlayerMovementIntegrationTest { CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); final TestConnection connection = env.createConnection(); Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - final CompletableFuture<@NotNull Player> future = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); - final Player player = future.join(); + final Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); // Initial join chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); @@ -125,7 +123,7 @@ public class PlayerMovementIntegrationTest { int viewDistance = 4; final Instance flatInstance = env.createFlatInstance(); var connection = env.createConnection(); - Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)).join(); + Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); // Preload all possible chunks to avoid issues due to async loading Set> chunks = new HashSet<>(); ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); @@ -154,7 +152,7 @@ public class PlayerMovementIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); Pos startingPlayerPos = new Pos(0, 42, 0); - var player = connection.connect(instance, startingPlayerPos).join(); + var player = connection.connect(instance, startingPlayerPos); int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java index 3d6fa17d2..810477ab9 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerRespawnChunkIntegrationTest.java @@ -26,7 +26,7 @@ public class PlayerRespawnChunkIntegrationTest { public void testChunkUnloadsOnRespawn(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - Player player = connection.connect(instance, new Pos(0, 40, 0)).join(); + Player player = connection.connect(instance, new Pos(0, 40, 0)); player.teleport(new Pos(32, 40, 32)).join(); var unloadChunkTracker = connection.trackIncoming(UnloadChunkPacket.class); @@ -40,7 +40,7 @@ public class PlayerRespawnChunkIntegrationTest { public void testChunkReloadCount(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - Player player = connection.connect(instance, new Pos(0, 40, 0)).join(); + Player player = connection.connect(instance, new Pos(0, 40, 0)); var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class); player.setHealth(0); @@ -54,7 +54,7 @@ public class PlayerRespawnChunkIntegrationTest { public void testPlayerTryRespawn(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - Player player = connection.connect(instance, new Pos(0, 40, 0)).join(); + Player player = connection.connect(instance, new Pos(0, 40, 0)); var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class); player.setHealth(0); diff --git a/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java b/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java index cfd976713..fade9ece0 100644 --- a/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/ChunkViewerIntegrationTest.java @@ -1,6 +1,6 @@ package net.minestom.server.instance; -import net.minestom.server.MinecraftServer; +import net.minestom.server.ServerFlag; import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.play.ChunkDataPacket; @@ -37,14 +37,14 @@ public class ChunkViewerIntegrationTest { @Test public void renderDistance(Env env) { - final int viewRadius = MinecraftServer.getChunkViewDistance(); + final int viewRadius = ServerFlag.CHUNK_VIEW_DISTANCE; final int count = ChunkRange.chunksCount(viewRadius); var instance = env.createFlatInstance(); var connection = env.createConnection(); // Check initial load { var tracker = connection.trackIncoming(ChunkDataPacket.class); - var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + var player = connection.connect(instance, new Pos(0, 40, 0)); assertEquals(instance, player.getInstance()); assertEquals(new Pos(0, 40, 0), player.getPosition()); assertEquals(count, tracker.collect().size()); diff --git a/src/test/java/net/minestom/server/instance/InstanceBlockPacketIntegrationTest.java b/src/test/java/net/minestom/server/instance/InstanceBlockPacketIntegrationTest.java index 1c73062d6..4382de302 100644 --- a/src/test/java/net/minestom/server/instance/InstanceBlockPacketIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/InstanceBlockPacketIntegrationTest.java @@ -27,7 +27,7 @@ public class InstanceBlockPacketIntegrationTest { public void replaceAir(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - connection.connect(instance, new Pos(0, 40, 0)).join(); + connection.connect(instance, new Pos(0, 40, 0)); var blockPoint = new Vec(5, 41, 0); @@ -47,7 +47,7 @@ public class InstanceBlockPacketIntegrationTest { public void placeBlockEntity(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - connection.connect(instance, new Pos(0, 40, 0)).join(); + connection.connect(instance, new Pos(0, 40, 0)); var blockPoint = new Vec(5, 41, 0); diff --git a/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java b/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java index ed7173f89..45e43c555 100644 --- a/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/InstanceUnregisterIntegrationTest.java @@ -24,7 +24,7 @@ public class InstanceUnregisterIntegrationTest { var instance = instanceManager.createInstanceContainer(); var shared1 = instanceManager.createSharedInstance(instance); var connection = env.createConnection(); - var player = connection.connect(shared1, new Pos(0, 40, 0)).join(); + var player = connection.connect(shared1, new Pos(0, 40, 0)); var listener = env.listen(PlayerTickEvent.class); listener.followup(); diff --git a/src/test/java/net/minestom/server/instance/WeatherTest.java b/src/test/java/net/minestom/server/instance/WeatherTest.java index 42e4a0371..7b5862e17 100644 --- a/src/test/java/net/minestom/server/instance/WeatherTest.java +++ b/src/test/java/net/minestom/server/instance/WeatherTest.java @@ -29,7 +29,7 @@ public class WeatherTest { // Weather sent on instance join var connection = env.createConnection(); var tracker = connection.trackIncoming(ChangeGameStatePacket.class); - connection.connect(instance, new Pos(0, 0, 0)).join(); + connection.connect(instance, new Pos(0, 0, 0)); tracker.assertCount(4); List packets = tracker.collect(); var state = packets.get(0); diff --git a/src/test/java/net/minestom/server/inventory/InventoryCloseStateTest.java b/src/test/java/net/minestom/server/inventory/InventoryCloseStateTest.java index 21d92088f..a35f5f693 100644 --- a/src/test/java/net/minestom/server/inventory/InventoryCloseStateTest.java +++ b/src/test/java/net/minestom/server/inventory/InventoryCloseStateTest.java @@ -18,7 +18,7 @@ public class InventoryCloseStateTest { public void doNotReceiveClosePacketFromServerWhenSendingClientCloseWindowPacket(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var packetTracker = connection.trackIncoming(CloseWindowPacket.class); diff --git a/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java b/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java index 0dd16e9c3..8dbd2cfcd 100644 --- a/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java +++ b/src/test/java/net/minestom/server/inventory/InventoryIntegrationTest.java @@ -1,9 +1,6 @@ package net.minestom.server.inventory; import net.kyori.adventure.text.Component; -import net.minestom.server.utils.inventory.PlayerInventoryUtils; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.item.ItemStack; @@ -11,6 +8,9 @@ import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; +import net.minestom.server.utils.inventory.PlayerInventoryUtils; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -24,7 +24,7 @@ public class InventoryIntegrationTest { public void setSlotDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); Inventory inventory = new Inventory(InventoryType.CHEST_6_ROW, Component.empty()); @@ -48,7 +48,7 @@ public class InventoryIntegrationTest { public void setCursorItemDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); Inventory inventory = new Inventory(InventoryType.CHEST_6_ROW, Component.empty()); @@ -72,7 +72,7 @@ public class InventoryIntegrationTest { public void clearInventoryTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); Inventory inventory = new Inventory(InventoryType.CHEST_6_ROW, Component.empty()); @@ -116,7 +116,7 @@ public class InventoryIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var setSlotTracker = connection.trackIncoming(SetSlotPacket.class); @@ -148,7 +148,7 @@ public class InventoryIntegrationTest { public void closeInventoryTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); final var inventory = new Inventory(InventoryType.CHEST_1_ROW, "title"); player.openInventory(inventory); assertSame(inventory, player.getOpenInventory()); @@ -160,7 +160,7 @@ public class InventoryIntegrationTest { public void openInventoryOnItemDropFromInventoryClosingTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); var listener = env.listen(ItemDropEvent.class); final var firstInventory = new Inventory(InventoryType.CHEST_1_ROW, "title"); player.openInventory(firstInventory); @@ -186,7 +186,7 @@ public class InventoryIntegrationTest { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); Inventory inventory = new Inventory(InventoryType.CHEST_6_ROW, Component.empty()); @@ -221,5 +221,4 @@ public class InventoryIntegrationTest { assertEquals(MAGIC_STACK, slot.itemStack()); }); } - } diff --git a/src/test/java/net/minestom/server/inventory/PlayerCreativeSlotTest.java b/src/test/java/net/minestom/server/inventory/PlayerCreativeSlotTest.java index a18215deb..921d80128 100644 --- a/src/test/java/net/minestom/server/inventory/PlayerCreativeSlotTest.java +++ b/src/test/java/net/minestom/server/inventory/PlayerCreativeSlotTest.java @@ -21,7 +21,7 @@ public class PlayerCreativeSlotTest { public void testCreativeSlots(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); player.setGameMode(GameMode.CREATIVE); @@ -34,7 +34,7 @@ public class PlayerCreativeSlotTest { public void testBoundsCheck(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); player.setGameMode(GameMode.CREATIVE); assertDoesNotThrow(() -> CreativeInventoryActionListener.listener(new ClientCreativeInventoryActionPacket((short) 76, ItemStack.of(Material.OAK_LOG)), player)); diff --git a/src/test/java/net/minestom/server/inventory/PlayerInventoryIntegrationTest.java b/src/test/java/net/minestom/server/inventory/PlayerInventoryIntegrationTest.java index d3eb03664..4cccb0ae7 100644 --- a/src/test/java/net/minestom/server/inventory/PlayerInventoryIntegrationTest.java +++ b/src/test/java/net/minestom/server/inventory/PlayerInventoryIntegrationTest.java @@ -1,7 +1,5 @@ package net.minestom.server.inventory; -import net.minestom.testing.Env; -import net.minestom.testing.EnvTest; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.item.ItemStack; @@ -9,11 +7,13 @@ import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; import java.util.Map; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; @EnvTest public class PlayerInventoryIntegrationTest { @@ -24,7 +24,7 @@ public class PlayerInventoryIntegrationTest { public void setSlotDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var packetTracker = connection.trackIncoming(SetSlotPacket.class); @@ -44,7 +44,7 @@ public class PlayerInventoryIntegrationTest { public void setCursorItemDuplicateTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var packetTracker = connection.trackIncoming(SetSlotPacket.class); @@ -64,7 +64,7 @@ public class PlayerInventoryIntegrationTest { public void clearInventoryTest(Env env) { var instance = env.createFlatInstance(); var connection = env.createConnection(); - var player = connection.connect(instance, new Pos(0, 42, 0)).join(); + var player = connection.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, player.getInstance()); var setSlotTracker = connection.trackIncoming(SetSlotPacket.class); @@ -108,9 +108,9 @@ public class PlayerInventoryIntegrationTest { public void equipmentViewTest(Env env) { var instance = env.createFlatInstance(); var connectionArmored = env.createConnection(); - var playerArmored = connectionArmored.connect(instance, new Pos(0, 42, 0)).join(); + var playerArmored = connectionArmored.connect(instance, new Pos(0, 42, 0)); var connectionViewer = env.createConnection(); - var playerViewer = connectionViewer.connect(instance, new Pos(0, 42, 0)).join(); + var playerViewer = connectionViewer.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, playerArmored.getInstance()); assertEquals(instance, playerViewer.getInstance()); @@ -140,9 +140,9 @@ public class PlayerInventoryIntegrationTest { public void heldItemViewTest(Env env) { var instance = env.createFlatInstance(); var connectionHolder = env.createConnection(); - var playerHolder = connectionHolder.connect(instance, new Pos(0, 42, 0)).join(); + var playerHolder = connectionHolder.connect(instance, new Pos(0, 42, 0)); var connectionViewer = env.createConnection(); - var playerViewer = connectionViewer.connect(instance, new Pos(0, 42, 0)).join(); + var playerViewer = connectionViewer.connect(instance, new Pos(0, 42, 0)); assertEquals(instance, playerHolder.getInstance()); assertEquals(instance, playerViewer.getInstance()); diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index e70bb1b16..196a79cf7 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -21,6 +21,7 @@ import net.minestom.server.network.packet.server.login.LoginSuccessPacket; import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.status.ResponsePacket; +import net.minestom.server.network.player.GameProfile; import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeCategory; import org.junit.jupiter.api.BeforeAll; @@ -53,7 +54,7 @@ public class PacketWriteReadTest { //SERVER_PACKETS.add(new EncryptionRequestPacket("server", generateByteArray(16), generateByteArray(16))); SERVER_PACKETS.add(new LoginDisconnectPacket(COMPONENT)); //SERVER_PACKETS.add(new LoginPluginRequestPacket(5, "id", generateByteArray(16))); - SERVER_PACKETS.add(new LoginSuccessPacket(UUID.randomUUID(), "TheMode911", 0, false)); + SERVER_PACKETS.add(new LoginSuccessPacket(new GameProfile(UUID.randomUUID(), "TheMode911"), false)); SERVER_PACKETS.add(new SetCompressionPacket(256)); // Play SERVER_PACKETS.add(new AcknowledgeBlockChangePacket(0)); diff --git a/src/test/java/net/minestom/server/permission/TestPermissions.java b/src/test/java/net/minestom/server/permission/TestPermissions.java index f6bcde9c6..676abcad9 100644 --- a/src/test/java/net/minestom/server/permission/TestPermissions.java +++ b/src/test/java/net/minestom/server/permission/TestPermissions.java @@ -3,6 +3,7 @@ package net.minestom.server.permission; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; +import net.minestom.server.network.player.GameProfile; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -23,7 +24,7 @@ public class TestPermissions { @BeforeEach public void init() { MinecraftServer.init(); // for entity manager - player = new Player(UUID.randomUUID(), "TestPlayer", null) { + player = new Player(null, new GameProfile(UUID.randomUUID(), "TestPlayer")) { @Override protected void playerConnectionInit() { } diff --git a/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java b/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java index 5d22e599f..89504a37b 100644 --- a/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java +++ b/src/test/java/net/minestom/server/utils/TranslationIntegrationTest.java @@ -37,7 +37,7 @@ public class TranslationIntegrationTest { public void testTranslationEnabled(final Env env) { final var instance = env.createFlatInstance(); final var connection = env.createConnection(); - final var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + final var player = connection.connect(instance, new Pos(0, 40, 0)); final var collector = connection.trackIncoming(SystemChatPacket.class); MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = true; @@ -56,7 +56,7 @@ public class TranslationIntegrationTest { public void testTranslationDisabled(final Env env) { final var instance = env.createFlatInstance(); final var connection = env.createConnection(); - final var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + final var player = connection.connect(instance, new Pos(0, 40, 0)); final var collector = connection.trackIncoming(SystemChatPacket.class); MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = false; @@ -73,7 +73,7 @@ public class TranslationIntegrationTest { public void testItemStackTranslation(final Env env) { final var instance = env.createFlatInstance(); final var connection = env.createConnection(); - final var player = connection.connect(instance, new Pos(0, 40, 0)).join(); + final var player = connection.connect(instance, new Pos(0, 40, 0)); final var collector = connection.trackIncoming(SetSlotPacket.class); MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = true; diff --git a/testing/src/main/java/net/minestom/testing/Env.java b/testing/src/main/java/net/minestom/testing/Env.java index 23f264767..9c01a15f8 100644 --- a/testing/src/main/java/net/minestom/testing/Env.java +++ b/testing/src/main/java/net/minestom/testing/Env.java @@ -40,7 +40,7 @@ public interface Env { } default @NotNull Player createPlayer(@NotNull Instance instance, @NotNull Pos pos) { - return createConnection().connect(instance, pos).join(); + return createConnection().connect(instance, pos); } default @NotNull Instance createFlatInstance() { diff --git a/testing/src/main/java/net/minestom/testing/TestConnection.java b/testing/src/main/java/net/minestom/testing/TestConnection.java index c25b74be0..382e3f8f1 100644 --- a/testing/src/main/java/net/minestom/testing/TestConnection.java +++ b/testing/src/main/java/net/minestom/testing/TestConnection.java @@ -6,10 +6,8 @@ import net.minestom.server.instance.Instance; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.CompletableFuture; - public interface TestConnection { - @NotNull CompletableFuture<@NotNull Player> connect(@NotNull Instance instance, @NotNull Pos pos); + @NotNull Player connect(@NotNull Instance instance, @NotNull Pos pos); @NotNull Collector trackIncoming(@NotNull Class type); diff --git a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java index f6d963728..6c193d298 100644 --- a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java +++ b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java @@ -6,11 +6,12 @@ import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; +import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.configuration.SelectKnownPacksPacket; +import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; import org.jetbrains.annotations.NotNull; @@ -21,39 +22,51 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; final class TestConnectionImpl implements TestConnection { private final Env env; private final ServerProcess process; private final PlayerConnectionImpl playerConnection = new PlayerConnectionImpl(); + private final AtomicBoolean connected = new AtomicBoolean(false); + private final List> incomingTrackers = new CopyOnWriteArrayList<>(); TestConnectionImpl(Env env) { this.env = env; this.process = env.process(); + // Use player provider to disable queued chunk sending + env.process().connection().setPlayerProvider(TestPlayerImpl::new); } @Override - public @NotNull CompletableFuture connect(@NotNull Instance instance, @NotNull Pos pos) { - // Use player provider to disable queued chunk sending - process.connection().setPlayerProvider(TestPlayerImpl::new); + public @NotNull Player connect(@NotNull Instance instance, @NotNull Pos pos) { + if (!connected.compareAndSet(false, true)) { + throw new IllegalStateException("Already connected"); + } playerConnection.setConnectionState(ConnectionState.LOGIN); - var player = process.connection().createPlayer(playerConnection, UUID.randomUUID(), "RandName"); + final GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "RandName"); + var player = process.connection().createPlayer(playerConnection, gameProfile); player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> { event.setSpawningInstance(instance); event.getPlayer().setRespawnPoint(pos); }); // Force the player through the entirety of the login process manually - var configFuture = process.connection().doConfiguration(player, true); - playerConnection.receiveKnownPacksResponse(List.of(SelectKnownPacksPacket.MINECRAFT_CORE)); - configFuture.join(); - - process.connection().transitionConfigToPlay(player); + CompletableFuture future = new CompletableFuture<>(); + Thread.startVirtualThread(() -> { + // `isFirstConfig` is set to false in order to not block the thread + // waiting for known packs. + // The consequence is that registry packets cannot be listened to. + process.connection().doConfiguration(player, false); + process.connection().transitionConfigToPlay(player); + future.complete(player); + }); + future.join(); process.connection().updateWaitingPlayers(); - return CompletableFuture.completedFuture(player); + return player; } @Override @@ -75,7 +88,8 @@ final class TestConnectionImpl implements TestConnection { } private ServerPacket extractPacket(final SendablePacket packet) { - if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(getConnectionState(), packet); + if (!(packet instanceof ServerPacket serverPacket)) + return SendablePacket.extractServerPacket(getConnectionState(), packet); final Player player = getPlayer(); if (player == null) return serverPacket; @@ -118,4 +132,16 @@ final class TestConnectionImpl implements TestConnection { return List.copyOf(packets); } } + + final class TestPlayerImpl extends Player { + public TestPlayerImpl(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) { + super(playerConnection, gameProfile); + } + + @Override + public void sendChunk(@NotNull Chunk chunk) { + // Send immediately + sendPacket(chunk.getFullDataPacket()); + } + } } diff --git a/testing/src/main/java/net/minestom/testing/TestPlayerImpl.java b/testing/src/main/java/net/minestom/testing/TestPlayerImpl.java deleted file mode 100644 index b21aed14a..000000000 --- a/testing/src/main/java/net/minestom/testing/TestPlayerImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.testing; - -import net.minestom.server.entity.Player; -import net.minestom.server.instance.Chunk; -import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.NotNull; - -import java.util.UUID; - -public class TestPlayerImpl extends Player { - public TestPlayerImpl(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) { - super(uuid, username, playerConnection); - } - - @Override - public void sendChunk(@NotNull Chunk chunk) { - // Send immediately - sendPacket(chunk.getFullDataPacket()); - } -} From c092e7dd0b9e21a6f5eb625b24e6ce8bf61fc10d Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 17 Sep 2024 00:52:12 +0200 Subject: [PATCH 33/97] World generation/loading in virtual threads (#2400) --- .../server/instance/IChunkLoader.java | 58 ++--- .../server/instance/InstanceContainer.java | 201 ++++++++++-------- .../server/instance/NoopChunkLoaderImpl.java | 18 +- .../server/instance/anvil/AnvilLoader.java | 29 +-- .../light/LightParityIntegrationTest.java | 2 +- 5 files changed, 153 insertions(+), 155 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/IChunkLoader.java b/src/main/java/net/minestom/server/instance/IChunkLoader.java index 09b47ffd1..26e0e807b 100644 --- a/src/main/java/net/minestom/server/instance/IChunkLoader.java +++ b/src/main/java/net/minestom/server/instance/IChunkLoader.java @@ -2,15 +2,11 @@ package net.minestom.server.instance; import net.minestom.server.MinecraftServer; import net.minestom.server.instance.anvil.AnvilLoader; -import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.Phaser; /** * Interface implemented to change the way chunks are loaded/saved. @@ -37,22 +33,19 @@ public interface IChunkLoader { * @param instance the {@link Instance} where the {@link Chunk} belong * @param chunkX the chunk X * @param chunkZ the chunk Z - * @return a {@link CompletableFuture} containing the chunk, or null if not present + * @return the chunk, or null if not present */ - @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ); + @Nullable Chunk loadChunk(@NotNull Instance instance, int chunkX, int chunkZ); - default @NotNull CompletableFuture saveInstance(@NotNull Instance instance) { - return AsyncUtils.VOID_FUTURE; + default void saveInstance(@NotNull Instance instance) { } /** * Saves a {@link Chunk} with an optional callback for when it is done. * * @param chunk the {@link Chunk} to save - * @return a {@link CompletableFuture} executed when the {@link Chunk} is done saving, - * should be called even if the saving failed (you can throw an exception). */ - @NotNull CompletableFuture saveChunk(@NotNull Chunk chunk); + void saveChunk(@NotNull Chunk chunk); /** * Saves multiple chunks with an optional callback for when it is done. @@ -60,37 +53,31 @@ public interface IChunkLoader { * Implementations need to check {@link #supportsParallelSaving()} to support the feature if possible. * * @param chunks the chunks to save - * @return a {@link CompletableFuture} executed when the {@link Chunk} is done saving, - * should be called even if the saving failed (you can throw an exception). */ - default @NotNull CompletableFuture saveChunks(@NotNull Collection chunks) { + default void saveChunks(@NotNull Collection chunks) { if (supportsParallelSaving()) { - ExecutorService parallelSavingThreadPool = ForkJoinPool.commonPool(); - chunks.forEach(c -> parallelSavingThreadPool.execute(() -> saveChunk(c))); - try { - parallelSavingThreadPool.shutdown(); - parallelSavingThreadPool.awaitTermination(1L, java.util.concurrent.TimeUnit.DAYS); - } catch (InterruptedException e) { - MinecraftServer.getExceptionManager().handleException(e); - } - return AsyncUtils.VOID_FUTURE; - } else { - CompletableFuture completableFuture = new CompletableFuture<>(); - AtomicInteger counter = new AtomicInteger(); + Phaser phaser = new Phaser(1); for (Chunk chunk : chunks) { - saveChunk(chunk).whenComplete((unused, throwable) -> { - final boolean isLast = counter.incrementAndGet() == chunks.size(); - if (isLast) { - completableFuture.complete(null); + phaser.register(); + Thread.startVirtualThread(() -> { + try { + saveChunk(chunk); + phaser.arriveAndDeregister(); + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); } }); } - return completableFuture; + phaser.arriveAndAwaitAdvance(); + } else { + for (Chunk chunk : chunks) { + saveChunk(chunk); + } } } /** - * Does this {@link IChunkLoader} allow for multi-threaded saving of {@link Chunk}? + * Supports for instance/chunk saving in virtual threads. * * @return true if the chunk loader supports parallel saving */ @@ -99,7 +86,7 @@ public interface IChunkLoader { } /** - * Does this {@link IChunkLoader} allow for multi-threaded loading of {@link Chunk}? + * Supports for instance/chunk loading in virtual threads. * * @return true if the chunk loader supports parallel loading */ @@ -114,5 +101,6 @@ public interface IChunkLoader { * * @param chunk the chunk to unload */ - default void unloadChunk(Chunk chunk) {} + default void unloadChunk(Chunk chunk) { + } } diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index a5e1f8983..a1ebbf950 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -44,9 +44,9 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ForkJoinPool; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; import java.util.function.Supplier; import static net.minestom.server.utils.chunk.ChunkUtils.isLoaded; @@ -282,17 +282,37 @@ public class InstanceContainer extends Instance { @Override public @NotNull CompletableFuture saveInstance() { - return chunkLoader.saveInstance(this); + final IChunkLoader chunkLoader = this.chunkLoader; + return optionalAsync(chunkLoader.supportsParallelSaving(), () -> chunkLoader.saveInstance(this)); } @Override public @NotNull CompletableFuture saveChunkToStorage(@NotNull Chunk chunk) { - return chunkLoader.saveChunk(chunk); + final IChunkLoader chunkLoader = this.chunkLoader; + return optionalAsync(chunkLoader.supportsParallelSaving(), () -> chunkLoader.saveChunk(chunk)); } @Override public @NotNull CompletableFuture saveChunksToStorage() { - return chunkLoader.saveChunks(getChunks()); + final IChunkLoader chunkLoader = this.chunkLoader; + return optionalAsync(chunkLoader.supportsParallelSaving(), () -> chunkLoader.saveChunks(getChunks())); + } + + private CompletableFuture optionalAsync(boolean async, Runnable runnable) { + if (!async) { + runnable.run(); + return CompletableFuture.completedFuture(null); + } + final CompletableFuture future = new CompletableFuture<>(); + Thread.startVirtualThread(() -> { + try { + runnable.run(); + future.complete(null); + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + } + }); + return future; } protected @NotNull CompletableFuture<@NotNull Chunk> retrieveChunk(int chunkX, int chunkZ) { @@ -301,108 +321,107 @@ public class InstanceContainer extends Instance { final CompletableFuture prev = loadingChunks.putIfAbsent(index, completableFuture); if (prev != null) return prev; final IChunkLoader loader = chunkLoader; - final Runnable retriever = () -> loader.loadChunk(this, chunkX, chunkZ) - .thenCompose(chunk -> { - if (chunk != null) { - // Chunk has been loaded from storage - return CompletableFuture.completedFuture(chunk); - } else { - // Loader couldn't load the chunk, generate it - return createChunk(chunkX, chunkZ).whenComplete((c, a) -> c.onGenerate()); - } - }) - // cache the retrieved chunk - .thenAccept(chunk -> { - // TODO run in the instance thread? - cacheChunk(chunk); - chunk.onLoad(); + final Consumer generate = chunk -> { + if (chunk == null) { + // Loader couldn't load the chunk, generate it + chunk = createChunk(chunkX, chunkZ); + chunk.onGenerate(); + } - EventDispatcher.call(new InstanceChunkLoadEvent(this, chunk)); - final CompletableFuture future = this.loadingChunks.remove(index); - assert future == completableFuture : "Invalid future: " + future; - completableFuture.complete(chunk); - }) - .exceptionally(throwable -> { - MinecraftServer.getExceptionManager().handleException(throwable); - return null; - }); + // TODO run in the instance thread? + cacheChunk(chunk); + chunk.onLoad(); + + EventDispatcher.call(new InstanceChunkLoadEvent(this, chunk)); + final CompletableFuture future = this.loadingChunks.remove(index); + assert future == completableFuture : "Invalid future: " + future; + completableFuture.complete(chunk); + }; if (loader.supportsParallelLoading()) { - CompletableFuture.runAsync(retriever); + Thread.startVirtualThread(() -> { + try { + final Chunk chunk = loader.loadChunk(this, chunkX, chunkZ); + generate.accept(chunk); + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + } + }); } else { - retriever.run(); + final Chunk chunk = loader.loadChunk(this, chunkX, chunkZ); + Thread.startVirtualThread(() -> { + try { + generate.accept(chunk); + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + } + }); } return completableFuture; } Map> generationForks = new ConcurrentHashMap<>(); - protected @NotNull CompletableFuture<@NotNull Chunk> createChunk(int chunkX, int chunkZ) { + protected @NotNull Chunk createChunk(int chunkX, int chunkZ) { final Chunk chunk = chunkSupplier.createChunk(this, chunkX, chunkZ); Check.notNull(chunk, "Chunks supplied by a ChunkSupplier cannot be null."); Generator generator = generator(); - if (generator != null && chunk.shouldGenerate()) { - CompletableFuture resultFuture = new CompletableFuture<>(); - // TODO: virtual thread once Loom is available - ForkJoinPool.commonPool().submit(() -> { - GeneratorImpl.GenSection[] genSections = new GeneratorImpl.GenSection[chunk.getSections().size()]; - Arrays.setAll(genSections, i -> { - Section section = chunk.getSections().get(i); - return new GeneratorImpl.GenSection(section.blockPalette(), section.biomePalette()); - }); - var chunkUnit = GeneratorImpl.chunk(MinecraftServer.getBiomeRegistry(), genSections, - chunk.getChunkX(), chunk.minSection, chunk.getChunkZ()); - try { - // Generate block/biome palette - generator.generate(chunkUnit); - // Apply nbt/handler - if (chunkUnit.modifier() instanceof GeneratorImpl.AreaModifierImpl chunkModifier) { - for (var section : chunkModifier.sections()) { - if (section.modifier() instanceof GeneratorImpl.SectionModifierImpl sectionModifier) { - applyGenerationData(chunk, sectionModifier); - } - } - } - // Register forks or apply locally - for (var fork : chunkUnit.forks()) { - var sections = ((GeneratorImpl.AreaModifierImpl) fork.modifier()).sections(); - for (var section : sections) { - if (section.modifier() instanceof GeneratorImpl.SectionModifierImpl sectionModifier) { - if (sectionModifier.genSection().blocks().count() == 0) - continue; - final Point start = section.absoluteStart(); - final Chunk forkChunk = start.chunkX() == chunkX && start.chunkZ() == chunkZ ? chunk : getChunkAt(start); - if (forkChunk != null) { - applyFork(forkChunk, sectionModifier); - // Update players - forkChunk.invalidate(); - forkChunk.sendChunk(); - } else { - final long index = CoordConversion.chunkIndex(start); - this.generationForks.compute(index, (i, sectionModifiers) -> { - if (sectionModifiers == null) sectionModifiers = new ArrayList<>(); - sectionModifiers.add(sectionModifier); - return sectionModifiers; - }); - } - } - } - } - // Apply awaiting forks - processFork(chunk); - } catch (Throwable e) { - MinecraftServer.getExceptionManager().handleException(e); - } finally { - // End generation - refreshLastBlockChangeTime(); - resultFuture.complete(chunk); - } - }); - return resultFuture; - } else { + if (generator == null || !chunk.shouldGenerate()) { // No chunk generator, execute the callback with the empty chunk processFork(chunk); - return CompletableFuture.completedFuture(chunk); + return chunk; } + GeneratorImpl.GenSection[] genSections = new GeneratorImpl.GenSection[chunk.getSections().size()]; + Arrays.setAll(genSections, i -> { + Section section = chunk.getSections().get(i); + return new GeneratorImpl.GenSection(section.blockPalette(), section.biomePalette()); + }); + var chunkUnit = GeneratorImpl.chunk(MinecraftServer.getBiomeRegistry(), genSections, + chunk.getChunkX(), chunk.minSection, chunk.getChunkZ()); + try { + // Generate block/biome palette + generator.generate(chunkUnit); + // Apply nbt/handler + if (chunkUnit.modifier() instanceof GeneratorImpl.AreaModifierImpl chunkModifier) { + for (var section : chunkModifier.sections()) { + if (section.modifier() instanceof GeneratorImpl.SectionModifierImpl sectionModifier) { + applyGenerationData(chunk, sectionModifier); + } + } + } + // Register forks or apply locally + for (var fork : chunkUnit.forks()) { + var sections = ((GeneratorImpl.AreaModifierImpl) fork.modifier()).sections(); + for (var section : sections) { + if (section.modifier() instanceof GeneratorImpl.SectionModifierImpl sectionModifier) { + if (sectionModifier.genSection().blocks().count() == 0) + continue; + final Point start = section.absoluteStart(); + final Chunk forkChunk = start.chunkX() == chunkX && start.chunkZ() == chunkZ ? chunk : getChunkAt(start); + if (forkChunk != null) { + applyFork(forkChunk, sectionModifier); + // Update players + forkChunk.invalidate(); + forkChunk.sendChunk(); + } else { + final long index = CoordConversion.chunkIndex(start); + this.generationForks.compute(index, (i, sectionModifiers) -> { + if (sectionModifiers == null) sectionModifiers = new ArrayList<>(); + sectionModifiers.add(sectionModifier); + return sectionModifiers; + }); + } + } + } + } + // Apply awaiting forks + processFork(chunk); + } catch (Throwable e) { + MinecraftServer.getExceptionManager().handleException(e); + } finally { + // End generation + refreshLastBlockChangeTime(); + } + return chunk; } private void processFork(Chunk chunk) { diff --git a/src/main/java/net/minestom/server/instance/NoopChunkLoaderImpl.java b/src/main/java/net/minestom/server/instance/NoopChunkLoaderImpl.java index 96b6fab67..f0a59df75 100644 --- a/src/main/java/net/minestom/server/instance/NoopChunkLoaderImpl.java +++ b/src/main/java/net/minestom/server/instance/NoopChunkLoaderImpl.java @@ -1,23 +1,21 @@ package net.minestom.server.instance; -import net.minestom.server.utils.async.AsyncUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.concurrent.CompletableFuture; - final class NoopChunkLoaderImpl implements IChunkLoader { static final NoopChunkLoaderImpl INSTANCE = new NoopChunkLoaderImpl(); - private NoopChunkLoaderImpl(){} - - @Override - public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { - return CompletableFuture.completedFuture(null); + private NoopChunkLoaderImpl() { } @Override - public @NotNull CompletableFuture saveChunk(@NotNull Chunk chunk) { - return AsyncUtils.VOID_FUTURE; + public @Nullable Chunk loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { + return null; + } + + @Override + public void saveChunk(@NotNull Chunk chunk) { + // Empty } } diff --git a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java index ee03276a4..df77a7d73 100644 --- a/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java +++ b/src/main/java/net/minestom/server/instance/anvil/AnvilLoader.java @@ -14,7 +14,6 @@ import net.minestom.server.instance.palette.Palettes; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.NamespaceID; -import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.validate.Check; import net.minestom.server.world.biome.Biome; import org.jetbrains.annotations.NotNull; @@ -30,7 +29,6 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -82,26 +80,24 @@ public class AnvilLoader implements IChunkLoader { } @Override - public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { + public @Nullable Chunk loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) { if (!Files.exists(path)) { // No world folder - return CompletableFuture.completedFuture(null); + return null; } try { return loadMCA(instance, chunkX, chunkZ); } catch (Exception e) { MinecraftServer.getExceptionManager().handleException(e); - return CompletableFuture.completedFuture(null); + return null; } } - private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException { + private @Nullable Chunk loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException { final RegionFile mcaFile = getMCAFile(chunkX, chunkZ); - if (mcaFile == null) - return CompletableFuture.completedFuture(null); + if (mcaFile == null) return null; final CompoundBinaryTag chunkData = mcaFile.readChunkData(chunkX, chunkZ); - if (chunkData == null) - return CompletableFuture.completedFuture(null); + if (chunkData == null) return null; // Load the chunk data (assuming it is fully generated) final Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ); @@ -113,7 +109,6 @@ public class AnvilLoader implements IChunkLoader { // TODO: Parallelize block, block entities and biome loading // Blocks + Biomes loadSections(chunk, chunkData); - // Block entities loadBlockEntities(chunk, chunkData); @@ -133,7 +128,7 @@ public class AnvilLoader implements IChunkLoader { } finally { perRegionLoadedChunksLock.unlock(); } - return CompletableFuture.completedFuture(chunk); + return chunk; } private @Nullable RegionFile getMCAFile(int chunkX, int chunkZ) { @@ -309,22 +304,21 @@ public class AnvilLoader implements IChunkLoader { } @Override - public @NotNull CompletableFuture saveInstance(@NotNull Instance instance) { + public void saveInstance(@NotNull Instance instance) { final CompoundBinaryTag nbt = instance.tagHandler().asCompound(); if (nbt.size() == 0) { // Instance has no data - return AsyncUtils.VOID_FUTURE; + return; } try (OutputStream os = Files.newOutputStream(levelPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { BinaryTagIO.writer().writeNamed(Map.entry("", nbt), os, BinaryTagIO.Compression.GZIP); } catch (IOException e) { MinecraftServer.getExceptionManager().handleException(e); } - return AsyncUtils.VOID_FUTURE; } @Override - public @NotNull CompletableFuture saveChunk(@NotNull Chunk chunk) { + public void saveChunk(@NotNull Chunk chunk) { final int chunkX = chunk.getChunkX(); final int chunkZ = chunk.getChunkZ(); @@ -349,7 +343,7 @@ public class AnvilLoader implements IChunkLoader { } catch (IOException e) { LOGGER.error("Failed to create region file for " + chunkX + ", " + chunkZ, e); MinecraftServer.getExceptionManager().handleException(e); - return AsyncUtils.VOID_FUTURE; + return; } } } finally { @@ -373,7 +367,6 @@ public class AnvilLoader implements IChunkLoader { LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e); MinecraftServer.getExceptionManager().handleException(e); } - return AsyncUtils.VOID_FUTURE; } private void saveSectionData(@NotNull Chunk chunk, @NotNull CompoundBinaryTag.Builder chunkData) { diff --git a/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java b/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java index 10d6c8598..b8c239222 100644 --- a/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java +++ b/src/test/java/net/minestom/server/instance/light/LightParityIntegrationTest.java @@ -139,7 +139,7 @@ public class LightParityIntegrationTest { // Read from anvil for (int x = 1; x < REGION_SIZE - 1; x++) { for (int z = 1; z < REGION_SIZE - 1; z++) { - var chunk = anvilLoader.loadChunk(instance, x, z).join(); + var chunk = anvilLoader.loadChunk(instance, x, z); if (chunk == null) continue; for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) { From 21b21005a25a5754d38135dda32abcc2c86477da Mon Sep 17 00:00:00 2001 From: themode Date: Tue, 17 Sep 2024 01:38:45 +0200 Subject: [PATCH 34/97] Handle connection state in reading --- .../manager/PacketListenerManager.java | 5 ++-- .../listener/preplay/ConfigListener.java | 20 ---------------- .../listener/preplay/HandshakeListener.java | 10 ++++---- .../listener/preplay/LoginListener.java | 10 ++++++++ .../server/network/ConnectionManager.java | 7 +----- .../server/network/packet/PacketReading.java | 23 +++++++++++-------- .../player/PlayerSocketConnection.java | 15 +++++++++--- .../server/network/SendablePacketTest.java | 2 +- .../server/network/SocketReadTest.java | 8 +++---- .../minestom/testing/TestConnectionImpl.java | 2 +- 10 files changed, 49 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/net/minestom/server/listener/preplay/ConfigListener.java diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 646a94a13..58ab14742 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -5,7 +5,6 @@ import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerPacketEvent; import net.minestom.server.listener.*; import net.minestom.server.listener.common.*; -import net.minestom.server.listener.preplay.ConfigListener; import net.minestom.server.listener.preplay.HandshakeListener; import net.minestom.server.listener.preplay.LoginListener; import net.minestom.server.listener.preplay.StatusListener; @@ -56,8 +55,8 @@ public final class PacketListenerManager { setConfigurationListener(ClientKeepAlivePacket.class, KeepAliveListener::listener); setConfigurationListener(ClientPongPacket.class, (packet, player) -> {/* empty */}); setConfigurationListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener); - setConfigurationListener(ClientSelectKnownPacksPacket.class, ConfigListener::selectKnownPacks); - setConfigurationListener(ClientFinishConfigurationPacket.class, ConfigListener::finishConfigListener); + setConfigurationListener(ClientSelectKnownPacksPacket.class, LoginListener::selectKnownPacks); + setConfigurationListener(ClientFinishConfigurationPacket.class, LoginListener::finishConfigListener); setListener(ConnectionState.CONFIGURATION, ClientCookieResponsePacket.class, CookieListener::handleCookieResponse); setPlayListener(ClientKeepAlivePacket.class, KeepAliveListener::listener); diff --git a/src/main/java/net/minestom/server/listener/preplay/ConfigListener.java b/src/main/java/net/minestom/server/listener/preplay/ConfigListener.java deleted file mode 100644 index ab9329034..000000000 --- a/src/main/java/net/minestom/server/listener/preplay/ConfigListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.listener.preplay; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.entity.Player; -import net.minestom.server.network.ConnectionManager; -import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; -import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; -import org.jetbrains.annotations.NotNull; - -public final class ConfigListener { - private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); - - public static void selectKnownPacks(@NotNull ClientSelectKnownPacksPacket packet, @NotNull Player player) { - player.getPlayerConnection().receiveKnownPacksResponse(packet.entries()); - } - - public static void finishConfigListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) { - CONNECTION_MANAGER.transitionConfigToPlay(player); - } -} diff --git a/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java b/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java index f18d624fe..6435df111 100644 --- a/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/HandshakeListener.java @@ -8,7 +8,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.extras.bungee.BungeeCordProxy; -import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.PlayerConnection; @@ -40,9 +39,9 @@ public final class HandshakeListener { public static void listener(@NotNull ClientHandshakePacket packet, @NotNull PlayerConnection connection) { String address = packet.serverAddress(); switch (packet.intent()) { - case STATUS -> connection.setConnectionState(ConnectionState.STATUS); + case STATUS -> { + } case LOGIN -> { - connection.setConnectionState(ConnectionState.LOGIN); if (packet.protocolVersion() != MinecraftServer.PROTOCOL_VERSION) { // Incorrect client version connection.kick(INVALID_VERSION_TEXT); @@ -114,9 +113,8 @@ public final class HandshakeListener { } } } - case TRANSFER -> { - throw new UnsupportedOperationException("Transfer intent is not supported in HandshakeListener"); - } + case TRANSFER -> + throw new UnsupportedOperationException("Transfer intent is not supported in HandshakeListener"); default -> { // Unexpected error } diff --git a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java index 0d1aefad6..ba6821dca 100644 --- a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java @@ -11,6 +11,8 @@ import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.mojangAuth.MojangCrypt; import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; +import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; @@ -204,6 +206,14 @@ public final class LoginListener { executeConfig(player, false); } + public static void selectKnownPacks(@NotNull ClientSelectKnownPacksPacket packet, @NotNull Player player) { + player.getPlayerConnection().receiveKnownPacksResponse(packet.entries()); + } + + public static void finishConfigListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) { + MinecraftServer.getConnectionManager().transitionConfigToPlay(player); + } + private static void enterConfig(PlayerConnection connection, GameProfile gameProfile) { gameProfile = MinecraftServer.getConnectionManager().transitionLoginToConfig(connection, gameProfile); if (connection instanceof PlayerSocketConnection socketConnection) { diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 8f36c863d..e2b96ad15 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -222,13 +222,9 @@ public final class ConnectionManager { configurationPlayers.add(player); keepAlivePlayers.add(player); } - - final PlayerConnection connection = player.getPlayerConnection(); - connection.setConnectionState(ConnectionState.CONFIGURATION); - player.sendPacket(PluginMessagePacket.brandPacket(MinecraftServer.getBrandName())); // Request known packs immediately, but don't wait for the response until required (sending registry data). - final var knownPacksFuture = connection.requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE)); + final var knownPacksFuture = player.getPlayerConnection().requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE)); var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig); EventDispatcher.call(event); @@ -329,7 +325,6 @@ public final class ConnectionManager { public void updateWaitingPlayers() { this.waitingPlayers.drain(player -> { if (!player.isOnline()) return; // Player disconnected while in queued to join - player.getPlayerConnection().setConnectionState(ConnectionState.PLAY); playPlayers.add(player); keepAlivePlayers.add(player); diff --git a/src/main/java/net/minestom/server/network/packet/PacketReading.java b/src/main/java/net/minestom/server/network/packet/PacketReading.java index a032f961b..1936049bb 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketReading.java +++ b/src/main/java/net/minestom/server/network/packet/PacketReading.java @@ -36,15 +36,16 @@ public final class PacketReading { * At least one packet was read. * The buffer may still contain half-read packets and should therefore be compacted for next read. */ - record Success(List packets, ConnectionState newState) implements Result { + record Success(List> packets) implements Result { public Success { if (packets.isEmpty()) { throw new IllegalArgumentException("Empty packets"); } + packets = List.copyOf(packets); } - public Success(T packet, ConnectionState newState) { - this(List.of(packet), newState); + public Success(ParsedPacket packet) { + this(List.of(packet)); } } @@ -67,6 +68,9 @@ public final class PacketReading { } } + public record ParsedPacket(ConnectionState nextState, T packet) { + } + public static Result readClients( @NotNull NetworkBuffer buffer, @NotNull ConnectionState state, @@ -90,7 +94,7 @@ public final class PacketReading { @NotNull BiFunction stateUpdater, boolean compressed ) throws DataFormatException { - List packets = new ArrayList<>(); + List> packets = new ArrayList<>(); readLoop: while (buffer.readableBytes() > 0) { final Result result = readPacket(buffer, parser, state, stateUpdater, compressed); @@ -98,18 +102,19 @@ public final class PacketReading { switch (result) { case Result.Success success -> { assert success.packets().size() == 1; - packets.add(success.packets().getFirst()); - state = success.newState(); + final ParsedPacket parsedPacket = success.packets().getFirst(); + packets.add(parsedPacket); + state = parsedPacket.nextState(); } case Result.Empty ignored -> { break readLoop; } case Result.Failure failure -> { - return packets.isEmpty() ? failure : new Result.Success<>(packets, state); + return packets.isEmpty() ? failure : new Result.Success<>(packets); } } } - return !packets.isEmpty() ? new Result.Success<>(packets, state) : EMPTY_CLIENT_PACKET; + return !packets.isEmpty() ? new Result.Success<>(packets) : EMPTY_CLIENT_PACKET; } public static Result readClient( @@ -172,7 +177,7 @@ public final class PacketReading { final T packet = readFramedPacket(buffer, registry, compressed); final ConnectionState nextState = stateUpdater.apply(packet, state); buffer.index(readerEnd, writerEnd); - return new Result.Success<>(packet, nextState); + return new Result.Success<>(new ParsedPacket<>(nextState, packet)); } private static T readFramedPacket(NetworkBuffer buffer, diff --git a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java index 5366cddfc..df4676591 100644 --- a/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java +++ b/src/main/java/net/minestom/server/network/player/PlayerSocketConnection.java @@ -18,6 +18,7 @@ import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.common.ClientCookieResponsePacket; import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket; import net.minestom.server.network.packet.client.common.ClientPingRequestPacket; +import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket; @@ -64,7 +65,8 @@ public class PlayerSocketConnection extends PlayerConnection { ClientLoginPluginResponsePacket.class, ClientSelectKnownPacksPacket.class, // Immediate answer to server request on config ClientConfigurationAckPacket.class, // Handle config state - ClientLoginAcknowledgedPacket.class // Handle config state + ClientLoginAcknowledgedPacket.class, // Handle config state + ClientFinishConfigurationPacket.class // Enter play state ); private final SocketChannel channel; @@ -116,12 +118,13 @@ public class PlayerSocketConnection extends PlayerConnection { private void processPackets(NetworkBuffer readBuffer, PacketParser packetParser) { // Read all packets + final ConnectionState startingState = getConnectionState(); final PacketReading.Result result; try { result = PacketReading.readPackets( readBuffer, packetParser, - getConnectionState(), PacketVanilla::nextClientState, + startingState, PacketVanilla::nextClientState, compression() ); } catch (DataFormatException e) { @@ -131,7 +134,8 @@ public class PlayerSocketConnection extends PlayerConnection { } switch (result) { case PacketReading.Result.Success success -> { - for (ClientPacket packet : success.packets()) { + for (PacketReading.ParsedPacket parsedPacket : success.packets()) { + final ClientPacket packet = parsedPacket.packet(); try { final boolean processImmediately = IMMEDIATE_PROCESS_PACKETS.contains(packet.getClass()); if (processImmediately) { @@ -145,6 +149,11 @@ public class PlayerSocketConnection extends PlayerConnection { } catch (Exception e) { MinecraftServer.getExceptionManager().handleException(e); } + // Update state to properly interpret next packet + final ConnectionState nextState = parsedPacket.nextState(); + if (nextState != getConnectionState()) { + setConnectionState(nextState); + } } // Compact in case of incomplete read readBuffer.compact(); diff --git a/src/test/java/net/minestom/server/network/SendablePacketTest.java b/src/test/java/net/minestom/server/network/SendablePacketTest.java index 3615c1520..15f629233 100644 --- a/src/test/java/net/minestom/server/network/SendablePacketTest.java +++ b/src/test/java/net/minestom/server/network/SendablePacketTest.java @@ -61,7 +61,7 @@ public class SendablePacketTest { return; } assertEquals(1, success.packets().size()); - var readPacket = success.packets().getFirst(); + ClientPacket readPacket = success.packets().getFirst().packet(); assertEquals(packet, readPacket); } } diff --git a/src/test/java/net/minestom/server/network/SocketReadTest.java b/src/test/java/net/minestom/server/network/SocketReadTest.java index 7706ee19b..77835eb9a 100644 --- a/src/test/java/net/minestom/server/network/SocketReadTest.java +++ b/src/test/java/net/minestom/server/network/SocketReadTest.java @@ -27,7 +27,7 @@ public class SocketReadTest { if (!(readResult instanceof PacketReading.Result.Success success)) { throw new AssertionError("Expected a success result, got " + readResult); } - var packets = success.packets(); + List packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList(); assertEquals(List.of(packet), packets); } @@ -44,7 +44,7 @@ public class SocketReadTest { if (!(readResult instanceof PacketReading.Result.Success success)) { throw new AssertionError("Expected a success result, got " + readResult); } - var packets = success.packets(); + List packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList(); assertEquals(List.of(packet, packet), packets); } @@ -63,7 +63,7 @@ public class SocketReadTest { if (!(readResult instanceof PacketReading.Result.Success success)) { throw new AssertionError("Expected a success result, got " + readResult); } - var packets = success.packets(); + List packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList(); assertEquals(List.of(packet), packets); readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed); @@ -87,7 +87,7 @@ public class SocketReadTest { if (!(readResult instanceof PacketReading.Result.Success success)) { throw new AssertionError("Expected a success result, got " + readResult); } - var packets = success.packets(); + List packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList(); assertEquals(1, buffer.readableBytes()); assertEquals(List.of(packet), packets); diff --git a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java index 6c193d298..114adee4d 100644 --- a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java +++ b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java @@ -46,7 +46,6 @@ final class TestConnectionImpl implements TestConnection { throw new IllegalStateException("Already connected"); } - playerConnection.setConnectionState(ConnectionState.LOGIN); final GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "RandName"); var player = process.connection().createPlayer(playerConnection, gameProfile); player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> { @@ -65,6 +64,7 @@ final class TestConnectionImpl implements TestConnection { future.complete(player); }); future.join(); + playerConnection.setConnectionState(ConnectionState.PLAY); process.connection().updateWaitingPlayers(); return player; } From 884a093c3a20de153d2d7053aed1f733f564c092 Mon Sep 17 00:00:00 2001 From: xZeGoe Date: Sat, 21 Sep 2024 15:30:08 +0300 Subject: [PATCH 35/97] fix javadoc (#2410) --- .../minestom/server/network/UuidProvider.java | 27 ------------------- .../server/thread/AcquirableSource.java | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 src/main/java/net/minestom/server/network/UuidProvider.java diff --git a/src/main/java/net/minestom/server/network/UuidProvider.java b/src/main/java/net/minestom/server/network/UuidProvider.java deleted file mode 100644 index 7fe21c17e..000000000 --- a/src/main/java/net/minestom/server/network/UuidProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.minestom.server.network; - -import net.minestom.server.network.player.PlayerConnection; -import org.jetbrains.annotations.NotNull; - -import java.util.UUID; - -/** - * Used when you want to provide your own {@link UUID} object for players instead of using the default one. - *

- * Sets with {@link ConnectionManager#setUuidProvider(UuidProvider)}. - */ -@FunctionalInterface -public interface UuidProvider { - - /** - * Called when a new {@link UUID} is requested. - *

- * The {@link UUID} does not need to be persistent between restart, but being sure that all players have a different - * one is good practice. Otherwise, undefined behavior can happen. - * - * @param playerConnection the connection who requires a new unique id - * @param username the username given by the connection - * @return the new {@link UUID} for the player - */ - @NotNull UUID provide(@NotNull PlayerConnection playerConnection, @NotNull String username); -} diff --git a/src/main/java/net/minestom/server/thread/AcquirableSource.java b/src/main/java/net/minestom/server/thread/AcquirableSource.java index 637ac0870..d8c9db744 100644 --- a/src/main/java/net/minestom/server/thread/AcquirableSource.java +++ b/src/main/java/net/minestom/server/thread/AcquirableSource.java @@ -14,7 +14,7 @@ import java.util.function.Consumer; public interface AcquirableSource { /** * Obtains an {@link Acquirable}. To safely perform operations on this object, the user must call - * {@link Acquirable#sync(Consumer)}, {@link Acquirable#async(Consumer)}, or {@link Acquirable#lock()} (followed by + * {@link Acquirable#sync(Consumer)} or {@link Acquirable#lock()} (followed by * a subsequent unlock) on the Acquirable instance. * * @return an Acquirable which can be used to synchronize access to this object From 72e9bb9930d3ea0e4e536bda07d3caef54af77b3 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 8 Oct 2024 21:45:59 -0400 Subject: [PATCH 36/97] feat: data gen & most packet changes --- build.gradle.kts | 1 + gradle/libs.versions.toml | 2 +- .../net/minestom/server/FeatureFlags.java | 6 +- .../minestom/server/MinecraftConstants.java | 10 +- .../minestom/server/entity/EntityTypes.java | 62 +++++++++-- .../server/entity/attribute/Attributes.java | 64 +++++------ .../server/entity/damage/DamageTypes.java | 78 +++++++------- .../server/instance/block/Blocks.java | 48 +++++++++ .../net/minestom/server/item/Materials.java | 100 ++++++++++++++++-- .../minestom/server/particle/Particles.java | 4 + .../minestom/server/recipe/RecipeType.java | 4 +- .../minestom/server/sound/SoundEvents.java | 58 +++++++++- .../listener/PlayerPositionListener.java | 2 +- .../server/listener/RecipeListener.java | 8 +- .../manager/PacketListenerManager.java | 4 +- .../server/network/NetworkBufferTemplate.java | 61 +++++++++++ .../server/network/packet/PacketRegistry.java | 20 ++-- .../play/ClientClickWindowButtonPacket.java | 8 +- .../client/play/ClientClickWindowPacket.java | 4 +- .../client/play/ClientCloseWindowPacket.java | 6 +- .../client/play/ClientCraftRecipeRequest.java | 20 ---- .../client/play/ClientEditBookPacket.java | 15 ++- .../client/play/ClientPlaceRecipePacket.java | 20 ++++ .../client/play/ClientPlayerPacket.java | 13 --- ...ClientPlayerPositionAndRotationPacket.java | 22 +++- .../play/ClientPlayerPositionPacket.java | 24 ++++- .../ClientPlayerPositionStatusPacket.java | 29 +++++ .../play/ClientPlayerRotationPacket.java | 21 +++- .../ClientRecipeBookSeenRecipePacket.java | 13 +++ .../play/ClientSelectBundleItemPacket.java | 14 +++ .../play/ClientSetDisplayedRecipePacket.java | 20 ---- .../client/play/ClientSteerVehiclePacket.java | 52 ++++++++- .../client/play/ClientTickEndPacket.java | 11 ++ .../network/packet/server/ServerPacket.java | 3 +- .../server/login/LoginSuccessPacket.java | 6 +- .../packet/server/play/CloseWindowPacket.java | 6 +- .../server/play/CraftRecipeResponse.java | 15 --- .../server/play/EntityPositionSyncPacket.java | 23 ++++ .../packet/server/play/ExplosionPacket.java | 96 +++-------------- .../packet/server/play/JoinGamePacket.java | 3 +- .../server/play/MoveMinecartPacket.java | 31 ++++++ .../server/play/OpenHorseWindowPacket.java | 7 +- .../server/play/PlaceGhostRecipePacket.java | 17 +++ .../server/play/PlayerInfoUpdatePacket.java | 10 +- .../play/PlayerPositionAndLookPacket.java | 29 ++++- .../server/play/PlayerRotationPacket.java | 14 +++ .../server/play/RecipeBookAddPacket.java | 43 ++++++++ .../server/play/RecipeBookRemovePacket.java | 11 ++ .../server/play/RecipeBookSettingsPacket.java | 11 ++ .../packet/server/play/RespawnPacket.java | 3 +- .../packet/server/play/SetCooldownPacket.java | 6 +- .../server/play/SetCursorItemPacket.java | 13 +++ .../server/play/SetPlayerInventoryPacket.java | 16 +++ .../packet/server/play/SetSlotPacket.java | 7 +- .../packet/server/play/TimeUpdatePacket.java | 4 +- .../server/play/UnlockRecipesPacket.java | 66 ------------ .../packet/server/play/WindowItemsPacket.java | 5 +- .../server/play/WindowPropertyPacket.java | 6 +- .../server/network/PacketWriteReadTest.java | 2 +- 59 files changed, 883 insertions(+), 394 deletions(-) delete mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientPlaceRecipePacket.java delete mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionStatusPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientRecipeBookSeenRecipePacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientSelectBundleItemPacket.java delete mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/client/play/ClientTickEndPacket.java delete mode 100644 src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/EntityPositionSyncPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/MoveMinecartPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/PlaceGhostRecipePacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/PlayerRotationPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/RecipeBookSettingsPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/SetCursorItemPacket.java create mode 100644 src/main/java/net/minestom/server/network/packet/server/play/SetPlayerInventoryPacket.java delete mode 100644 src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java diff --git a/build.gradle.kts b/build.gradle.kts index 0ccb3f70d..304a3d4e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,7 @@ allprojects { description = shortDescription repositories { + mavenLocal() mavenCentral() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 43260bdb6..11656b91d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # Important dependencies -data = "1.21-rv3" +data = "1.21.2-pre1-dev" adventure = "4.17.0" jetbrainsAnnotations = "24.1.0" slf4j = "2.0.7" diff --git a/src/autogenerated/java/net/minestom/server/FeatureFlags.java b/src/autogenerated/java/net/minestom/server/FeatureFlags.java index 8122bd62b..94d03c217 100644 --- a/src/autogenerated/java/net/minestom/server/FeatureFlags.java +++ b/src/autogenerated/java/net/minestom/server/FeatureFlags.java @@ -5,9 +5,13 @@ package net.minestom.server; */ @SuppressWarnings("unused") interface FeatureFlags { - FeatureFlag BUNDLE = FeatureFlagImpl.get("minecraft:bundle"); + FeatureFlag REDSTONE_EXPERIMENTS = FeatureFlagImpl.get("minecraft:redstone_experiments"); FeatureFlag VANILLA = FeatureFlagImpl.get("minecraft:vanilla"); + FeatureFlag WINTER_DROP = FeatureFlagImpl.get("minecraft:winter_drop"); + FeatureFlag TRADE_REBALANCE = FeatureFlagImpl.get("minecraft:trade_rebalance"); + + FeatureFlag MINECART_IMPROVEMENTS = FeatureFlagImpl.get("minecraft:minecart_improvements"); } diff --git a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java index 47ac87d07..69c802dbd 100644 --- a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java +++ b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java @@ -4,13 +4,13 @@ package net.minestom.server; * AUTOGENERATED by ConstantsGenerator */ interface MinecraftConstants { - String VERSION_NAME = "1.21"; + String VERSION_NAME = "1.21.2-pre1"; - int PROTOCOL_VERSION = 767; + int PROTOCOL_VERSION = 1073742037; - int DATA_VERSION = 3953; + int DATA_VERSION = 4073; - int RESOURCE_PACK_VERSION = 34; + int RESOURCE_PACK_VERSION = 41; - int DATA_PACK_VERSION = 48; + int DATA_PACK_VERSION = 57; } diff --git a/src/autogenerated/java/net/minestom/server/entity/EntityTypes.java b/src/autogenerated/java/net/minestom/server/entity/EntityTypes.java index 0574ffcf2..f4b6f1ea9 100644 --- a/src/autogenerated/java/net/minestom/server/entity/EntityTypes.java +++ b/src/autogenerated/java/net/minestom/server/entity/EntityTypes.java @@ -5,6 +5,10 @@ package net.minestom.server.entity; */ @SuppressWarnings("unused") interface EntityTypes { + EntityType ACACIA_BOAT = EntityTypeImpl.get("minecraft:acacia_boat"); + + EntityType ACACIA_CHEST_BOAT = EntityTypeImpl.get("minecraft:acacia_chest_boat"); + EntityType ALLAY = EntityTypeImpl.get("minecraft:allay"); EntityType AREA_EFFECT_CLOUD = EntityTypeImpl.get("minecraft:area_effect_cloud"); @@ -17,16 +21,22 @@ interface EntityTypes { EntityType AXOLOTL = EntityTypeImpl.get("minecraft:axolotl"); + EntityType BAMBOO_CHEST_RAFT = EntityTypeImpl.get("minecraft:bamboo_chest_raft"); + + EntityType BAMBOO_RAFT = EntityTypeImpl.get("minecraft:bamboo_raft"); + EntityType BAT = EntityTypeImpl.get("minecraft:bat"); EntityType BEE = EntityTypeImpl.get("minecraft:bee"); + EntityType BIRCH_BOAT = EntityTypeImpl.get("minecraft:birch_boat"); + + EntityType BIRCH_CHEST_BOAT = EntityTypeImpl.get("minecraft:birch_chest_boat"); + EntityType BLAZE = EntityTypeImpl.get("minecraft:blaze"); EntityType BLOCK_DISPLAY = EntityTypeImpl.get("minecraft:block_display"); - EntityType BOAT = EntityTypeImpl.get("minecraft:boat"); - EntityType BOGGED = EntityTypeImpl.get("minecraft:bogged"); EntityType BREEZE = EntityTypeImpl.get("minecraft:breeze"); @@ -39,7 +49,9 @@ interface EntityTypes { EntityType CAVE_SPIDER = EntityTypeImpl.get("minecraft:cave_spider"); - EntityType CHEST_BOAT = EntityTypeImpl.get("minecraft:chest_boat"); + EntityType CHERRY_BOAT = EntityTypeImpl.get("minecraft:cherry_boat"); + + EntityType CHERRY_CHEST_BOAT = EntityTypeImpl.get("minecraft:cherry_chest_boat"); EntityType CHEST_MINECART = EntityTypeImpl.get("minecraft:chest_minecart"); @@ -51,8 +63,16 @@ interface EntityTypes { EntityType COW = EntityTypeImpl.get("minecraft:cow"); + EntityType CREAKING = EntityTypeImpl.get("minecraft:creaking"); + + EntityType CREAKING_TRANSIENT = EntityTypeImpl.get("minecraft:creaking_transient"); + EntityType CREEPER = EntityTypeImpl.get("minecraft:creeper"); + EntityType DARK_OAK_BOAT = EntityTypeImpl.get("minecraft:dark_oak_boat"); + + EntityType DARK_OAK_CHEST_BOAT = EntityTypeImpl.get("minecraft:dark_oak_chest_boat"); + EntityType DOLPHIN = EntityTypeImpl.get("minecraft:dolphin"); EntityType DONKEY = EntityTypeImpl.get("minecraft:donkey"); @@ -65,15 +85,15 @@ interface EntityTypes { EntityType ELDER_GUARDIAN = EntityTypeImpl.get("minecraft:elder_guardian"); - EntityType END_CRYSTAL = EntityTypeImpl.get("minecraft:end_crystal"); + EntityType ENDERMAN = EntityTypeImpl.get("minecraft:enderman"); + + EntityType ENDERMITE = EntityTypeImpl.get("minecraft:endermite"); EntityType ENDER_DRAGON = EntityTypeImpl.get("minecraft:ender_dragon"); EntityType ENDER_PEARL = EntityTypeImpl.get("minecraft:ender_pearl"); - EntityType ENDERMAN = EntityTypeImpl.get("minecraft:enderman"); - - EntityType ENDERMITE = EntityTypeImpl.get("minecraft:endermite"); + EntityType END_CRYSTAL = EntityTypeImpl.get("minecraft:end_crystal"); EntityType EVOKER = EntityTypeImpl.get("minecraft:evoker"); @@ -87,6 +107,8 @@ interface EntityTypes { EntityType FALLING_BLOCK = EntityTypeImpl.get("minecraft:falling_block"); + EntityType FIREBALL = EntityTypeImpl.get("minecraft:fireball"); + EntityType FIREWORK_ROCKET = EntityTypeImpl.get("minecraft:firework_rocket"); EntityType FOX = EntityTypeImpl.get("minecraft:fox"); @@ -127,9 +149,9 @@ interface EntityTypes { EntityType ITEM_FRAME = EntityTypeImpl.get("minecraft:item_frame"); - EntityType OMINOUS_ITEM_SPAWNER = EntityTypeImpl.get("minecraft:ominous_item_spawner"); + EntityType JUNGLE_BOAT = EntityTypeImpl.get("minecraft:jungle_boat"); - EntityType FIREBALL = EntityTypeImpl.get("minecraft:fireball"); + EntityType JUNGLE_CHEST_BOAT = EntityTypeImpl.get("minecraft:jungle_chest_boat"); EntityType LEASH_KNOT = EntityTypeImpl.get("minecraft:leash_knot"); @@ -141,6 +163,10 @@ interface EntityTypes { EntityType MAGMA_CUBE = EntityTypeImpl.get("minecraft:magma_cube"); + EntityType MANGROVE_BOAT = EntityTypeImpl.get("minecraft:mangrove_boat"); + + EntityType MANGROVE_CHEST_BOAT = EntityTypeImpl.get("minecraft:mangrove_chest_boat"); + EntityType MARKER = EntityTypeImpl.get("minecraft:marker"); EntityType MINECART = EntityTypeImpl.get("minecraft:minecart"); @@ -149,10 +175,20 @@ interface EntityTypes { EntityType MULE = EntityTypeImpl.get("minecraft:mule"); + EntityType OAK_BOAT = EntityTypeImpl.get("minecraft:oak_boat"); + + EntityType OAK_CHEST_BOAT = EntityTypeImpl.get("minecraft:oak_chest_boat"); + EntityType OCELOT = EntityTypeImpl.get("minecraft:ocelot"); + EntityType OMINOUS_ITEM_SPAWNER = EntityTypeImpl.get("minecraft:ominous_item_spawner"); + EntityType PAINTING = EntityTypeImpl.get("minecraft:painting"); + EntityType PALE_OAK_BOAT = EntityTypeImpl.get("minecraft:pale_oak_boat"); + + EntityType PALE_OAK_CHEST_BOAT = EntityTypeImpl.get("minecraft:pale_oak_chest_boat"); + EntityType PANDA = EntityTypeImpl.get("minecraft:panda"); EntityType PARROT = EntityTypeImpl.get("minecraft:parrot"); @@ -197,16 +233,20 @@ interface EntityTypes { EntityType SNIFFER = EntityTypeImpl.get("minecraft:sniffer"); - EntityType SNOW_GOLEM = EntityTypeImpl.get("minecraft:snow_golem"); - EntityType SNOWBALL = EntityTypeImpl.get("minecraft:snowball"); + EntityType SNOW_GOLEM = EntityTypeImpl.get("minecraft:snow_golem"); + EntityType SPAWNER_MINECART = EntityTypeImpl.get("minecraft:spawner_minecart"); EntityType SPECTRAL_ARROW = EntityTypeImpl.get("minecraft:spectral_arrow"); EntityType SPIDER = EntityTypeImpl.get("minecraft:spider"); + EntityType SPRUCE_BOAT = EntityTypeImpl.get("minecraft:spruce_boat"); + + EntityType SPRUCE_CHEST_BOAT = EntityTypeImpl.get("minecraft:spruce_chest_boat"); + EntityType SQUID = EntityTypeImpl.get("minecraft:squid"); EntityType STRAY = EntityTypeImpl.get("minecraft:stray"); diff --git a/src/autogenerated/java/net/minestom/server/entity/attribute/Attributes.java b/src/autogenerated/java/net/minestom/server/entity/attribute/Attributes.java index e660d3b29..6e714d0e9 100644 --- a/src/autogenerated/java/net/minestom/server/entity/attribute/Attributes.java +++ b/src/autogenerated/java/net/minestom/server/entity/attribute/Attributes.java @@ -5,65 +5,67 @@ package net.minestom.server.entity.attribute; */ @SuppressWarnings("unused") interface Attributes { - Attribute GENERIC_ARMOR = AttributeImpl.get("minecraft:generic.armor"); + Attribute ARMOR = AttributeImpl.get("minecraft:armor"); - Attribute GENERIC_ARMOR_TOUGHNESS = AttributeImpl.get("minecraft:generic.armor_toughness"); + Attribute ARMOR_TOUGHNESS = AttributeImpl.get("minecraft:armor_toughness"); - Attribute GENERIC_ATTACK_DAMAGE = AttributeImpl.get("minecraft:generic.attack_damage"); + Attribute ATTACK_DAMAGE = AttributeImpl.get("minecraft:attack_damage"); - Attribute GENERIC_ATTACK_KNOCKBACK = AttributeImpl.get("minecraft:generic.attack_knockback"); + Attribute ATTACK_KNOCKBACK = AttributeImpl.get("minecraft:attack_knockback"); - Attribute GENERIC_ATTACK_SPEED = AttributeImpl.get("minecraft:generic.attack_speed"); + Attribute ATTACK_SPEED = AttributeImpl.get("minecraft:attack_speed"); - Attribute PLAYER_BLOCK_BREAK_SPEED = AttributeImpl.get("minecraft:player.block_break_speed"); + Attribute BLOCK_BREAK_SPEED = AttributeImpl.get("minecraft:block_break_speed"); - Attribute PLAYER_BLOCK_INTERACTION_RANGE = AttributeImpl.get("minecraft:player.block_interaction_range"); + Attribute BLOCK_INTERACTION_RANGE = AttributeImpl.get("minecraft:block_interaction_range"); - Attribute GENERIC_BURNING_TIME = AttributeImpl.get("minecraft:generic.burning_time"); + Attribute BURNING_TIME = AttributeImpl.get("minecraft:burning_time"); - Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = AttributeImpl.get("minecraft:generic.explosion_knockback_resistance"); + Attribute EXPLOSION_KNOCKBACK_RESISTANCE = AttributeImpl.get("minecraft:explosion_knockback_resistance"); - Attribute PLAYER_ENTITY_INTERACTION_RANGE = AttributeImpl.get("minecraft:player.entity_interaction_range"); + Attribute ENTITY_INTERACTION_RANGE = AttributeImpl.get("minecraft:entity_interaction_range"); - Attribute GENERIC_FALL_DAMAGE_MULTIPLIER = AttributeImpl.get("minecraft:generic.fall_damage_multiplier"); + Attribute FALL_DAMAGE_MULTIPLIER = AttributeImpl.get("minecraft:fall_damage_multiplier"); - Attribute GENERIC_FLYING_SPEED = AttributeImpl.get("minecraft:generic.flying_speed"); + Attribute FLYING_SPEED = AttributeImpl.get("minecraft:flying_speed"); - Attribute GENERIC_FOLLOW_RANGE = AttributeImpl.get("minecraft:generic.follow_range"); + Attribute FOLLOW_RANGE = AttributeImpl.get("minecraft:follow_range"); - Attribute GENERIC_GRAVITY = AttributeImpl.get("minecraft:generic.gravity"); + Attribute GRAVITY = AttributeImpl.get("minecraft:gravity"); - Attribute GENERIC_JUMP_STRENGTH = AttributeImpl.get("minecraft:generic.jump_strength"); + Attribute JUMP_STRENGTH = AttributeImpl.get("minecraft:jump_strength"); - Attribute GENERIC_KNOCKBACK_RESISTANCE = AttributeImpl.get("minecraft:generic.knockback_resistance"); + Attribute KNOCKBACK_RESISTANCE = AttributeImpl.get("minecraft:knockback_resistance"); - Attribute GENERIC_LUCK = AttributeImpl.get("minecraft:generic.luck"); + Attribute LUCK = AttributeImpl.get("minecraft:luck"); - Attribute GENERIC_MAX_ABSORPTION = AttributeImpl.get("minecraft:generic.max_absorption"); + Attribute MAX_ABSORPTION = AttributeImpl.get("minecraft:max_absorption"); - Attribute GENERIC_MAX_HEALTH = AttributeImpl.get("minecraft:generic.max_health"); + Attribute MAX_HEALTH = AttributeImpl.get("minecraft:max_health"); - Attribute PLAYER_MINING_EFFICIENCY = AttributeImpl.get("minecraft:player.mining_efficiency"); + Attribute MINING_EFFICIENCY = AttributeImpl.get("minecraft:mining_efficiency"); - Attribute GENERIC_MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:generic.movement_efficiency"); + Attribute MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:movement_efficiency"); - Attribute GENERIC_MOVEMENT_SPEED = AttributeImpl.get("minecraft:generic.movement_speed"); + Attribute MOVEMENT_SPEED = AttributeImpl.get("minecraft:movement_speed"); - Attribute GENERIC_OXYGEN_BONUS = AttributeImpl.get("minecraft:generic.oxygen_bonus"); + Attribute OXYGEN_BONUS = AttributeImpl.get("minecraft:oxygen_bonus"); - Attribute GENERIC_SAFE_FALL_DISTANCE = AttributeImpl.get("minecraft:generic.safe_fall_distance"); + Attribute SAFE_FALL_DISTANCE = AttributeImpl.get("minecraft:safe_fall_distance"); - Attribute GENERIC_SCALE = AttributeImpl.get("minecraft:generic.scale"); + Attribute SCALE = AttributeImpl.get("minecraft:scale"); - Attribute PLAYER_SNEAKING_SPEED = AttributeImpl.get("minecraft:player.sneaking_speed"); + Attribute SNEAKING_SPEED = AttributeImpl.get("minecraft:sneaking_speed"); - Attribute ZOMBIE_SPAWN_REINFORCEMENTS = AttributeImpl.get("minecraft:zombie.spawn_reinforcements"); + Attribute SPAWN_REINFORCEMENTS = AttributeImpl.get("minecraft:spawn_reinforcements"); - Attribute GENERIC_STEP_HEIGHT = AttributeImpl.get("minecraft:generic.step_height"); + Attribute STEP_HEIGHT = AttributeImpl.get("minecraft:step_height"); - Attribute PLAYER_SUBMERGED_MINING_SPEED = AttributeImpl.get("minecraft:player.submerged_mining_speed"); + Attribute SUBMERGED_MINING_SPEED = AttributeImpl.get("minecraft:submerged_mining_speed"); - Attribute PLAYER_SWEEPING_DAMAGE_RATIO = AttributeImpl.get("minecraft:player.sweeping_damage_ratio"); + Attribute SWEEPING_DAMAGE_RATIO = AttributeImpl.get("minecraft:sweeping_damage_ratio"); - Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:generic.water_movement_efficiency"); + Attribute TEMPT_RANGE = AttributeImpl.get("minecraft:tempt_range"); + + Attribute WATER_MOVEMENT_EFFICIENCY = AttributeImpl.get("minecraft:water_movement_efficiency"); } diff --git a/src/autogenerated/java/net/minestom/server/entity/damage/DamageTypes.java b/src/autogenerated/java/net/minestom/server/entity/damage/DamageTypes.java index 806d7a300..18adead63 100644 --- a/src/autogenerated/java/net/minestom/server/entity/damage/DamageTypes.java +++ b/src/autogenerated/java/net/minestom/server/entity/damage/DamageTypes.java @@ -9,44 +9,24 @@ import net.minestom.server.registry.DynamicRegistry; interface DamageTypes { DynamicRegistry.Key WITHER = DynamicRegistry.Key.of("minecraft:wither"); - DynamicRegistry.Key SONIC_BOOM = DynamicRegistry.Key.of("minecraft:sonic_boom"); - DynamicRegistry.Key WITHER_SKULL = DynamicRegistry.Key.of("minecraft:wither_skull"); - DynamicRegistry.Key DRY_OUT = DynamicRegistry.Key.of("minecraft:dry_out"); + DynamicRegistry.Key MACE_SMASH = DynamicRegistry.Key.of("minecraft:mace_smash"); DynamicRegistry.Key TRIDENT = DynamicRegistry.Key.of("minecraft:trident"); DynamicRegistry.Key ON_FIRE = DynamicRegistry.Key.of("minecraft:on_fire"); - DynamicRegistry.Key FALL = DynamicRegistry.Key.of("minecraft:fall"); - - DynamicRegistry.Key MOB_ATTACK = DynamicRegistry.Key.of("minecraft:mob_attack"); - - DynamicRegistry.Key MOB_PROJECTILE = DynamicRegistry.Key.of("minecraft:mob_projectile"); - DynamicRegistry.Key CAMPFIRE = DynamicRegistry.Key.of("minecraft:campfire"); - DynamicRegistry.Key THROWN = DynamicRegistry.Key.of("minecraft:thrown"); - DynamicRegistry.Key FALLING_STALACTITE = DynamicRegistry.Key.of("minecraft:falling_stalactite"); DynamicRegistry.Key FIREBALL = DynamicRegistry.Key.of("minecraft:fireball"); - DynamicRegistry.Key FALLING_BLOCK = DynamicRegistry.Key.of("minecraft:falling_block"); - - DynamicRegistry.Key WIND_CHARGE = DynamicRegistry.Key.of("minecraft:wind_charge"); - - DynamicRegistry.Key PLAYER_EXPLOSION = DynamicRegistry.Key.of("minecraft:player_explosion"); - DynamicRegistry.Key SPIT = DynamicRegistry.Key.of("minecraft:spit"); DynamicRegistry.Key STING = DynamicRegistry.Key.of("minecraft:sting"); - DynamicRegistry.Key UNATTRIBUTED_FIREBALL = DynamicRegistry.Key.of("minecraft:unattributed_fireball"); - - DynamicRegistry.Key IN_WALL = DynamicRegistry.Key.of("minecraft:in_wall"); - DynamicRegistry.Key IN_FIRE = DynamicRegistry.Key.of("minecraft:in_fire"); DynamicRegistry.Key ARROW = DynamicRegistry.Key.of("minecraft:arrow"); @@ -55,42 +35,68 @@ interface DamageTypes { DynamicRegistry.Key DROWN = DynamicRegistry.Key.of("minecraft:drown"); - DynamicRegistry.Key STARVE = DynamicRegistry.Key.of("minecraft:starve"); - DynamicRegistry.Key GENERIC_KILL = DynamicRegistry.Key.of("minecraft:generic_kill"); DynamicRegistry.Key DRAGON_BREATH = DynamicRegistry.Key.of("minecraft:dragon_breath"); - DynamicRegistry.Key MOB_ATTACK_NO_AGGRO = DynamicRegistry.Key.of("minecraft:mob_attack_no_aggro"); - DynamicRegistry.Key LAVA = DynamicRegistry.Key.of("minecraft:lava"); - DynamicRegistry.Key OUTSIDE_BORDER = DynamicRegistry.Key.of("minecraft:outside_border"); - DynamicRegistry.Key FLY_INTO_WALL = DynamicRegistry.Key.of("minecraft:fly_into_wall"); - DynamicRegistry.Key LIGHTNING_BOLT = DynamicRegistry.Key.of("minecraft:lightning_bolt"); - DynamicRegistry.Key PLAYER_ATTACK = DynamicRegistry.Key.of("minecraft:player_attack"); DynamicRegistry.Key FREEZE = DynamicRegistry.Key.of("minecraft:freeze"); DynamicRegistry.Key FALLING_ANVIL = DynamicRegistry.Key.of("minecraft:falling_anvil"); - DynamicRegistry.Key OUT_OF_WORLD = DynamicRegistry.Key.of("minecraft:out_of_world"); - - DynamicRegistry.Key MAGIC = DynamicRegistry.Key.of("minecraft:magic"); - DynamicRegistry.Key SWEET_BERRY_BUSH = DynamicRegistry.Key.of("minecraft:sweet_berry_bush"); DynamicRegistry.Key FIREWORKS = DynamicRegistry.Key.of("minecraft:fireworks"); + DynamicRegistry.Key STALAGMITE = DynamicRegistry.Key.of("minecraft:stalagmite"); + + DynamicRegistry.Key GENERIC = DynamicRegistry.Key.of("minecraft:generic"); + + DynamicRegistry.Key SONIC_BOOM = DynamicRegistry.Key.of("minecraft:sonic_boom"); + + DynamicRegistry.Key DRY_OUT = DynamicRegistry.Key.of("minecraft:dry_out"); + + DynamicRegistry.Key ENDER_PEARL = DynamicRegistry.Key.of("minecraft:ender_pearl"); + + DynamicRegistry.Key FALL = DynamicRegistry.Key.of("minecraft:fall"); + + DynamicRegistry.Key MOB_ATTACK = DynamicRegistry.Key.of("minecraft:mob_attack"); + + DynamicRegistry.Key MOB_PROJECTILE = DynamicRegistry.Key.of("minecraft:mob_projectile"); + + DynamicRegistry.Key THROWN = DynamicRegistry.Key.of("minecraft:thrown"); + + DynamicRegistry.Key FALLING_BLOCK = DynamicRegistry.Key.of("minecraft:falling_block"); + + DynamicRegistry.Key WIND_CHARGE = DynamicRegistry.Key.of("minecraft:wind_charge"); + + DynamicRegistry.Key PLAYER_EXPLOSION = DynamicRegistry.Key.of("minecraft:player_explosion"); + + DynamicRegistry.Key UNATTRIBUTED_FIREBALL = DynamicRegistry.Key.of("minecraft:unattributed_fireball"); + + DynamicRegistry.Key IN_WALL = DynamicRegistry.Key.of("minecraft:in_wall"); + + DynamicRegistry.Key STARVE = DynamicRegistry.Key.of("minecraft:starve"); + + DynamicRegistry.Key MOB_ATTACK_NO_AGGRO = DynamicRegistry.Key.of("minecraft:mob_attack_no_aggro"); + + DynamicRegistry.Key OUTSIDE_BORDER = DynamicRegistry.Key.of("minecraft:outside_border"); + + DynamicRegistry.Key LIGHTNING_BOLT = DynamicRegistry.Key.of("minecraft:lightning_bolt"); + + DynamicRegistry.Key OUT_OF_WORLD = DynamicRegistry.Key.of("minecraft:out_of_world"); + + DynamicRegistry.Key MAGIC = DynamicRegistry.Key.of("minecraft:magic"); + DynamicRegistry.Key EXPLOSION = DynamicRegistry.Key.of("minecraft:explosion"); DynamicRegistry.Key BAD_RESPAWN_POINT = DynamicRegistry.Key.of("minecraft:bad_respawn_point"); - DynamicRegistry.Key STALAGMITE = DynamicRegistry.Key.of("minecraft:stalagmite"); - DynamicRegistry.Key THORNS = DynamicRegistry.Key.of("minecraft:thorns"); DynamicRegistry.Key INDIRECT_MAGIC = DynamicRegistry.Key.of("minecraft:indirect_magic"); @@ -98,6 +104,4 @@ interface DamageTypes { DynamicRegistry.Key CRAMMING = DynamicRegistry.Key.of("minecraft:cramming"); DynamicRegistry.Key CACTUS = DynamicRegistry.Key.of("minecraft:cactus"); - - DynamicRegistry.Key GENERIC = DynamicRegistry.Key.of("minecraft:generic"); } diff --git a/src/autogenerated/java/net/minestom/server/instance/block/Blocks.java b/src/autogenerated/java/net/minestom/server/instance/block/Blocks.java index 974c15bb9..dafc5c222 100644 --- a/src/autogenerated/java/net/minestom/server/instance/block/Blocks.java +++ b/src/autogenerated/java/net/minestom/server/instance/block/Blocks.java @@ -45,6 +45,10 @@ interface Blocks { Block DARK_OAK_PLANKS = BlockImpl.get("minecraft:dark_oak_planks"); + Block PALE_OAK_WOOD = BlockImpl.get("minecraft:pale_oak_wood"); + + Block PALE_OAK_PLANKS = BlockImpl.get("minecraft:pale_oak_planks"); + Block MANGROVE_PLANKS = BlockImpl.get("minecraft:mangrove_planks"); Block BAMBOO_PLANKS = BlockImpl.get("minecraft:bamboo_planks"); @@ -65,6 +69,8 @@ interface Blocks { Block DARK_OAK_SAPLING = BlockImpl.get("minecraft:dark_oak_sapling"); + Block PALE_OAK_SAPLING = BlockImpl.get("minecraft:pale_oak_sapling"); + Block MANGROVE_PROPAGULE = BlockImpl.get("minecraft:mangrove_propagule"); Block BEDROCK = BlockImpl.get("minecraft:bedrock"); @@ -111,6 +117,8 @@ interface Blocks { Block DARK_OAK_LOG = BlockImpl.get("minecraft:dark_oak_log"); + Block PALE_OAK_LOG = BlockImpl.get("minecraft:pale_oak_log"); + Block MANGROVE_LOG = BlockImpl.get("minecraft:mangrove_log"); Block MANGROVE_ROOTS = BlockImpl.get("minecraft:mangrove_roots"); @@ -131,6 +139,8 @@ interface Blocks { Block STRIPPED_DARK_OAK_LOG = BlockImpl.get("minecraft:stripped_dark_oak_log"); + Block STRIPPED_PALE_OAK_LOG = BlockImpl.get("minecraft:stripped_pale_oak_log"); + Block STRIPPED_OAK_LOG = BlockImpl.get("minecraft:stripped_oak_log"); Block STRIPPED_MANGROVE_LOG = BlockImpl.get("minecraft:stripped_mangrove_log"); @@ -167,6 +177,8 @@ interface Blocks { Block STRIPPED_DARK_OAK_WOOD = BlockImpl.get("minecraft:stripped_dark_oak_wood"); + Block STRIPPED_PALE_OAK_WOOD = BlockImpl.get("minecraft:stripped_pale_oak_wood"); + Block STRIPPED_MANGROVE_WOOD = BlockImpl.get("minecraft:stripped_mangrove_wood"); Block OAK_LEAVES = BlockImpl.get("minecraft:oak_leaves"); @@ -183,6 +195,8 @@ interface Blocks { Block DARK_OAK_LEAVES = BlockImpl.get("minecraft:dark_oak_leaves"); + Block PALE_OAK_LEAVES = BlockImpl.get("minecraft:pale_oak_leaves"); + Block MANGROVE_LEAVES = BlockImpl.get("minecraft:mangrove_leaves"); Block AZALEA_LEAVES = BlockImpl.get("minecraft:azalea_leaves"); @@ -357,6 +371,8 @@ interface Blocks { Block SPAWNER = BlockImpl.get("minecraft:spawner"); + Block CREAKING_HEART = BlockImpl.get("minecraft:creaking_heart"); + Block OAK_STAIRS = BlockImpl.get("minecraft:oak_stairs"); Block CHEST = BlockImpl.get("minecraft:chest"); @@ -391,6 +407,8 @@ interface Blocks { Block DARK_OAK_SIGN = BlockImpl.get("minecraft:dark_oak_sign"); + Block PALE_OAK_SIGN = BlockImpl.get("minecraft:pale_oak_sign"); + Block MANGROVE_SIGN = BlockImpl.get("minecraft:mangrove_sign"); Block BAMBOO_SIGN = BlockImpl.get("minecraft:bamboo_sign"); @@ -417,6 +435,8 @@ interface Blocks { Block DARK_OAK_WALL_SIGN = BlockImpl.get("minecraft:dark_oak_wall_sign"); + Block PALE_OAK_WALL_SIGN = BlockImpl.get("minecraft:pale_oak_wall_sign"); + Block MANGROVE_WALL_SIGN = BlockImpl.get("minecraft:mangrove_wall_sign"); Block BAMBOO_WALL_SIGN = BlockImpl.get("minecraft:bamboo_wall_sign"); @@ -435,6 +455,8 @@ interface Blocks { Block DARK_OAK_HANGING_SIGN = BlockImpl.get("minecraft:dark_oak_hanging_sign"); + Block PALE_OAK_HANGING_SIGN = BlockImpl.get("minecraft:pale_oak_hanging_sign"); + Block CRIMSON_HANGING_SIGN = BlockImpl.get("minecraft:crimson_hanging_sign"); Block WARPED_HANGING_SIGN = BlockImpl.get("minecraft:warped_hanging_sign"); @@ -457,6 +479,8 @@ interface Blocks { Block DARK_OAK_WALL_HANGING_SIGN = BlockImpl.get("minecraft:dark_oak_wall_hanging_sign"); + Block PALE_OAK_WALL_HANGING_SIGN = BlockImpl.get("minecraft:pale_oak_wall_hanging_sign"); + Block MANGROVE_WALL_HANGING_SIGN = BlockImpl.get("minecraft:mangrove_wall_hanging_sign"); Block CRIMSON_WALL_HANGING_SIGN = BlockImpl.get("minecraft:crimson_wall_hanging_sign"); @@ -485,6 +509,8 @@ interface Blocks { Block DARK_OAK_PRESSURE_PLATE = BlockImpl.get("minecraft:dark_oak_pressure_plate"); + Block PALE_OAK_PRESSURE_PLATE = BlockImpl.get("minecraft:pale_oak_pressure_plate"); + Block MANGROVE_PRESSURE_PLATE = BlockImpl.get("minecraft:mangrove_pressure_plate"); Block BAMBOO_PRESSURE_PLATE = BlockImpl.get("minecraft:bamboo_pressure_plate"); @@ -587,6 +613,8 @@ interface Blocks { Block DARK_OAK_TRAPDOOR = BlockImpl.get("minecraft:dark_oak_trapdoor"); + Block PALE_OAK_TRAPDOOR = BlockImpl.get("minecraft:pale_oak_trapdoor"); + Block MANGROVE_TRAPDOOR = BlockImpl.get("minecraft:mangrove_trapdoor"); Block BAMBOO_TRAPDOOR = BlockImpl.get("minecraft:bamboo_trapdoor"); @@ -733,6 +761,8 @@ interface Blocks { Block POTTED_DARK_OAK_SAPLING = BlockImpl.get("minecraft:potted_dark_oak_sapling"); + Block POTTED_PALE_OAK_SAPLING = BlockImpl.get("minecraft:potted_pale_oak_sapling"); + Block POTTED_MANGROVE_PROPAGULE = BlockImpl.get("minecraft:potted_mangrove_propagule"); Block POTTED_FERN = BlockImpl.get("minecraft:potted_fern"); @@ -789,6 +819,8 @@ interface Blocks { Block DARK_OAK_BUTTON = BlockImpl.get("minecraft:dark_oak_button"); + Block PALE_OAK_BUTTON = BlockImpl.get("minecraft:pale_oak_button"); + Block MANGROVE_BUTTON = BlockImpl.get("minecraft:mangrove_button"); Block BAMBOO_BUTTON = BlockImpl.get("minecraft:bamboo_button"); @@ -925,6 +957,8 @@ interface Blocks { Block DARK_OAK_STAIRS = BlockImpl.get("minecraft:dark_oak_stairs"); + Block PALE_OAK_STAIRS = BlockImpl.get("minecraft:pale_oak_stairs"); + Block MANGROVE_STAIRS = BlockImpl.get("minecraft:mangrove_stairs"); Block BAMBOO_STAIRS = BlockImpl.get("minecraft:bamboo_stairs"); @@ -1097,6 +1131,8 @@ interface Blocks { Block DARK_OAK_SLAB = BlockImpl.get("minecraft:dark_oak_slab"); + Block PALE_OAK_SLAB = BlockImpl.get("minecraft:pale_oak_slab"); + Block MANGROVE_SLAB = BlockImpl.get("minecraft:mangrove_slab"); Block BAMBOO_SLAB = BlockImpl.get("minecraft:bamboo_slab"); @@ -1151,6 +1187,8 @@ interface Blocks { Block DARK_OAK_FENCE_GATE = BlockImpl.get("minecraft:dark_oak_fence_gate"); + Block PALE_OAK_FENCE_GATE = BlockImpl.get("minecraft:pale_oak_fence_gate"); + Block MANGROVE_FENCE_GATE = BlockImpl.get("minecraft:mangrove_fence_gate"); Block BAMBOO_FENCE_GATE = BlockImpl.get("minecraft:bamboo_fence_gate"); @@ -1167,6 +1205,8 @@ interface Blocks { Block DARK_OAK_FENCE = BlockImpl.get("minecraft:dark_oak_fence"); + Block PALE_OAK_FENCE = BlockImpl.get("minecraft:pale_oak_fence"); + Block MANGROVE_FENCE = BlockImpl.get("minecraft:mangrove_fence"); Block BAMBOO_FENCE = BlockImpl.get("minecraft:bamboo_fence"); @@ -1183,6 +1223,8 @@ interface Blocks { Block DARK_OAK_DOOR = BlockImpl.get("minecraft:dark_oak_door"); + Block PALE_OAK_DOOR = BlockImpl.get("minecraft:pale_oak_door"); + Block MANGROVE_DOOR = BlockImpl.get("minecraft:mangrove_door"); Block BAMBOO_DOOR = BlockImpl.get("minecraft:bamboo_door"); @@ -2124,4 +2166,10 @@ interface Blocks { Block VAULT = BlockImpl.get("minecraft:vault"); Block HEAVY_CORE = BlockImpl.get("minecraft:heavy_core"); + + Block PALE_MOSS_BLOCK = BlockImpl.get("minecraft:pale_moss_block"); + + Block PALE_MOSS_CARPET = BlockImpl.get("minecraft:pale_moss_carpet"); + + Block PALE_HANGING_MOSS = BlockImpl.get("minecraft:pale_hanging_moss"); } diff --git a/src/autogenerated/java/net/minestom/server/item/Materials.java b/src/autogenerated/java/net/minestom/server/item/Materials.java index 23f5ff7ba..7ba872bbf 100644 --- a/src/autogenerated/java/net/minestom/server/item/Materials.java +++ b/src/autogenerated/java/net/minestom/server/item/Materials.java @@ -91,6 +91,8 @@ interface Materials { Material DARK_OAK_PLANKS = MaterialImpl.get("minecraft:dark_oak_planks"); + Material PALE_OAK_PLANKS = MaterialImpl.get("minecraft:pale_oak_planks"); + Material MANGROVE_PLANKS = MaterialImpl.get("minecraft:mangrove_planks"); Material BAMBOO_PLANKS = MaterialImpl.get("minecraft:bamboo_planks"); @@ -115,6 +117,8 @@ interface Materials { Material DARK_OAK_SAPLING = MaterialImpl.get("minecraft:dark_oak_sapling"); + Material PALE_OAK_SAPLING = MaterialImpl.get("minecraft:pale_oak_sapling"); + Material MANGROVE_PROPAGULE = MaterialImpl.get("minecraft:mangrove_propagule"); Material BEDROCK = MaterialImpl.get("minecraft:bedrock"); @@ -281,6 +285,8 @@ interface Materials { Material CHERRY_LOG = MaterialImpl.get("minecraft:cherry_log"); + Material PALE_OAK_LOG = MaterialImpl.get("minecraft:pale_oak_log"); + Material DARK_OAK_LOG = MaterialImpl.get("minecraft:dark_oak_log"); Material MANGROVE_LOG = MaterialImpl.get("minecraft:mangrove_log"); @@ -309,6 +315,8 @@ interface Materials { Material STRIPPED_DARK_OAK_LOG = MaterialImpl.get("minecraft:stripped_dark_oak_log"); + Material STRIPPED_PALE_OAK_LOG = MaterialImpl.get("minecraft:stripped_pale_oak_log"); + Material STRIPPED_MANGROVE_LOG = MaterialImpl.get("minecraft:stripped_mangrove_log"); Material STRIPPED_CRIMSON_STEM = MaterialImpl.get("minecraft:stripped_crimson_stem"); @@ -329,6 +337,8 @@ interface Materials { Material STRIPPED_DARK_OAK_WOOD = MaterialImpl.get("minecraft:stripped_dark_oak_wood"); + Material STRIPPED_PALE_OAK_WOOD = MaterialImpl.get("minecraft:stripped_pale_oak_wood"); + Material STRIPPED_MANGROVE_WOOD = MaterialImpl.get("minecraft:stripped_mangrove_wood"); Material STRIPPED_CRIMSON_HYPHAE = MaterialImpl.get("minecraft:stripped_crimson_hyphae"); @@ -349,6 +359,8 @@ interface Materials { Material CHERRY_WOOD = MaterialImpl.get("minecraft:cherry_wood"); + Material PALE_OAK_WOOD = MaterialImpl.get("minecraft:pale_oak_wood"); + Material DARK_OAK_WOOD = MaterialImpl.get("minecraft:dark_oak_wood"); Material MANGROVE_WOOD = MaterialImpl.get("minecraft:mangrove_wood"); @@ -371,6 +383,8 @@ interface Materials { Material DARK_OAK_LEAVES = MaterialImpl.get("minecraft:dark_oak_leaves"); + Material PALE_OAK_LEAVES = MaterialImpl.get("minecraft:pale_oak_leaves"); + Material MANGROVE_LEAVES = MaterialImpl.get("minecraft:mangrove_leaves"); Material AZALEA_LEAVES = MaterialImpl.get("minecraft:azalea_leaves"); @@ -495,12 +509,18 @@ interface Materials { Material KELP = MaterialImpl.get("minecraft:kelp"); - Material MOSS_CARPET = MaterialImpl.get("minecraft:moss_carpet"); - Material PINK_PETALS = MaterialImpl.get("minecraft:pink_petals"); + Material MOSS_CARPET = MaterialImpl.get("minecraft:moss_carpet"); + Material MOSS_BLOCK = MaterialImpl.get("minecraft:moss_block"); + Material PALE_MOSS_CARPET = MaterialImpl.get("minecraft:pale_moss_carpet"); + + Material PALE_HANGING_MOSS = MaterialImpl.get("minecraft:pale_hanging_moss"); + + Material PALE_MOSS_BLOCK = MaterialImpl.get("minecraft:pale_moss_block"); + Material HANGING_ROOTS = MaterialImpl.get("minecraft:hanging_roots"); Material BIG_DRIPLEAF = MaterialImpl.get("minecraft:big_dripleaf"); @@ -523,6 +543,8 @@ interface Materials { Material DARK_OAK_SLAB = MaterialImpl.get("minecraft:dark_oak_slab"); + Material PALE_OAK_SLAB = MaterialImpl.get("minecraft:pale_oak_slab"); + Material MANGROVE_SLAB = MaterialImpl.get("minecraft:mangrove_slab"); Material BAMBOO_SLAB = MaterialImpl.get("minecraft:bamboo_slab"); @@ -603,6 +625,8 @@ interface Materials { Material SPAWNER = MaterialImpl.get("minecraft:spawner"); + Material CREAKING_HEART = MaterialImpl.get("minecraft:creaking_heart"); + Material CHEST = MaterialImpl.get("minecraft:chest"); Material CRAFTING_TABLE = MaterialImpl.get("minecraft:crafting_table"); @@ -641,6 +665,8 @@ interface Materials { Material DARK_OAK_FENCE = MaterialImpl.get("minecraft:dark_oak_fence"); + Material PALE_OAK_FENCE = MaterialImpl.get("minecraft:pale_oak_fence"); + Material MANGROVE_FENCE = MaterialImpl.get("minecraft:mangrove_fence"); Material BAMBOO_FENCE = MaterialImpl.get("minecraft:bamboo_fence"); @@ -785,6 +811,8 @@ interface Materials { Material DARK_OAK_STAIRS = MaterialImpl.get("minecraft:dark_oak_stairs"); + Material PALE_OAK_STAIRS = MaterialImpl.get("minecraft:pale_oak_stairs"); + Material MANGROVE_STAIRS = MaterialImpl.get("minecraft:mangrove_stairs"); Material BAMBOO_STAIRS = MaterialImpl.get("minecraft:bamboo_stairs"); @@ -1387,6 +1415,8 @@ interface Materials { Material DARK_OAK_BUTTON = MaterialImpl.get("minecraft:dark_oak_button"); + Material PALE_OAK_BUTTON = MaterialImpl.get("minecraft:pale_oak_button"); + Material MANGROVE_BUTTON = MaterialImpl.get("minecraft:mangrove_button"); Material BAMBOO_BUTTON = MaterialImpl.get("minecraft:bamboo_button"); @@ -1417,6 +1447,8 @@ interface Materials { Material DARK_OAK_PRESSURE_PLATE = MaterialImpl.get("minecraft:dark_oak_pressure_plate"); + Material PALE_OAK_PRESSURE_PLATE = MaterialImpl.get("minecraft:pale_oak_pressure_plate"); + Material MANGROVE_PRESSURE_PLATE = MaterialImpl.get("minecraft:mangrove_pressure_plate"); Material BAMBOO_PRESSURE_PLATE = MaterialImpl.get("minecraft:bamboo_pressure_plate"); @@ -1441,6 +1473,8 @@ interface Materials { Material DARK_OAK_DOOR = MaterialImpl.get("minecraft:dark_oak_door"); + Material PALE_OAK_DOOR = MaterialImpl.get("minecraft:pale_oak_door"); + Material MANGROVE_DOOR = MaterialImpl.get("minecraft:mangrove_door"); Material BAMBOO_DOOR = MaterialImpl.get("minecraft:bamboo_door"); @@ -1481,6 +1515,8 @@ interface Materials { Material DARK_OAK_TRAPDOOR = MaterialImpl.get("minecraft:dark_oak_trapdoor"); + Material PALE_OAK_TRAPDOOR = MaterialImpl.get("minecraft:pale_oak_trapdoor"); + Material MANGROVE_TRAPDOOR = MaterialImpl.get("minecraft:mangrove_trapdoor"); Material BAMBOO_TRAPDOOR = MaterialImpl.get("minecraft:bamboo_trapdoor"); @@ -1519,6 +1555,8 @@ interface Materials { Material DARK_OAK_FENCE_GATE = MaterialImpl.get("minecraft:dark_oak_fence_gate"); + Material PALE_OAK_FENCE_GATE = MaterialImpl.get("minecraft:pale_oak_fence_gate"); + Material MANGROVE_FENCE_GATE = MaterialImpl.get("minecraft:mangrove_fence_gate"); Material BAMBOO_FENCE_GATE = MaterialImpl.get("minecraft:bamboo_fence_gate"); @@ -1551,6 +1589,8 @@ interface Materials { Material WARPED_FUNGUS_ON_A_STICK = MaterialImpl.get("minecraft:warped_fungus_on_a_stick"); + Material PHANTOM_MEMBRANE = MaterialImpl.get("minecraft:phantom_membrane"); + Material ELYTRA = MaterialImpl.get("minecraft:elytra"); Material OAK_BOAT = MaterialImpl.get("minecraft:oak_boat"); @@ -1581,6 +1621,10 @@ interface Materials { Material DARK_OAK_CHEST_BOAT = MaterialImpl.get("minecraft:dark_oak_chest_boat"); + Material PALE_OAK_BOAT = MaterialImpl.get("minecraft:pale_oak_boat"); + + Material PALE_OAK_CHEST_BOAT = MaterialImpl.get("minecraft:pale_oak_chest_boat"); + Material MANGROVE_BOAT = MaterialImpl.get("minecraft:mangrove_boat"); Material MANGROVE_CHEST_BOAT = MaterialImpl.get("minecraft:mangrove_chest_boat"); @@ -1791,6 +1835,8 @@ interface Materials { Material DARK_OAK_SIGN = MaterialImpl.get("minecraft:dark_oak_sign"); + Material PALE_OAK_SIGN = MaterialImpl.get("minecraft:pale_oak_sign"); + Material MANGROVE_SIGN = MaterialImpl.get("minecraft:mangrove_sign"); Material BAMBOO_SIGN = MaterialImpl.get("minecraft:bamboo_sign"); @@ -1813,6 +1859,8 @@ interface Materials { Material DARK_OAK_HANGING_SIGN = MaterialImpl.get("minecraft:dark_oak_hanging_sign"); + Material PALE_OAK_HANGING_SIGN = MaterialImpl.get("minecraft:pale_oak_hanging_sign"); + Material MANGROVE_HANGING_SIGN = MaterialImpl.get("minecraft:mangrove_hanging_sign"); Material BAMBOO_HANGING_SIGN = MaterialImpl.get("minecraft:bamboo_hanging_sign"); @@ -1867,6 +1915,38 @@ interface Materials { Material BUNDLE = MaterialImpl.get("minecraft:bundle"); + Material WHITE_BUNDLE = MaterialImpl.get("minecraft:white_bundle"); + + Material ORANGE_BUNDLE = MaterialImpl.get("minecraft:orange_bundle"); + + Material MAGENTA_BUNDLE = MaterialImpl.get("minecraft:magenta_bundle"); + + Material LIGHT_BLUE_BUNDLE = MaterialImpl.get("minecraft:light_blue_bundle"); + + Material YELLOW_BUNDLE = MaterialImpl.get("minecraft:yellow_bundle"); + + Material LIME_BUNDLE = MaterialImpl.get("minecraft:lime_bundle"); + + Material PINK_BUNDLE = MaterialImpl.get("minecraft:pink_bundle"); + + Material GRAY_BUNDLE = MaterialImpl.get("minecraft:gray_bundle"); + + Material LIGHT_GRAY_BUNDLE = MaterialImpl.get("minecraft:light_gray_bundle"); + + Material CYAN_BUNDLE = MaterialImpl.get("minecraft:cyan_bundle"); + + Material PURPLE_BUNDLE = MaterialImpl.get("minecraft:purple_bundle"); + + Material BLUE_BUNDLE = MaterialImpl.get("minecraft:blue_bundle"); + + Material BROWN_BUNDLE = MaterialImpl.get("minecraft:brown_bundle"); + + Material GREEN_BUNDLE = MaterialImpl.get("minecraft:green_bundle"); + + Material RED_BUNDLE = MaterialImpl.get("minecraft:red_bundle"); + + Material BLACK_BUNDLE = MaterialImpl.get("minecraft:black_bundle"); + Material FISHING_ROD = MaterialImpl.get("minecraft:fishing_rod"); Material CLOCK = MaterialImpl.get("minecraft:clock"); @@ -2001,10 +2081,10 @@ interface Materials { Material NETHER_WART = MaterialImpl.get("minecraft:nether_wart"); - Material POTION = MaterialImpl.get("minecraft:potion"); - Material GLASS_BOTTLE = MaterialImpl.get("minecraft:glass_bottle"); + Material POTION = MaterialImpl.get("minecraft:potion"); + Material SPIDER_EYE = MaterialImpl.get("minecraft:spider_eye"); Material FERMENTED_SPIDER_EYE = MaterialImpl.get("minecraft:fermented_spider_eye"); @@ -2173,6 +2253,8 @@ interface Materials { Material ZOGLIN_SPAWN_EGG = MaterialImpl.get("minecraft:zoglin_spawn_egg"); + Material CREAKING_SPAWN_EGG = MaterialImpl.get("minecraft:creaking_spawn_egg"); + Material ZOMBIE_SPAWN_EGG = MaterialImpl.get("minecraft:zombie_spawn_egg"); Material ZOMBIE_HORSE_SPAWN_EGG = MaterialImpl.get("minecraft:zombie_horse_spawn_egg"); @@ -2191,6 +2273,8 @@ interface Materials { Material WRITTEN_BOOK = MaterialImpl.get("minecraft:written_book"); + Material BREEZE_ROD = MaterialImpl.get("minecraft:breeze_rod"); + Material MACE = MaterialImpl.get("minecraft:mace"); Material ITEM_FRAME = MaterialImpl.get("minecraft:item_frame"); @@ -2383,8 +2467,6 @@ interface Materials { Material TRIDENT = MaterialImpl.get("minecraft:trident"); - Material PHANTOM_MEMBRANE = MaterialImpl.get("minecraft:phantom_membrane"); - Material NAUTILUS_SHELL = MaterialImpl.get("minecraft:nautilus_shell"); Material HEART_OF_THE_SEA = MaterialImpl.get("minecraft:heart_of_the_sea"); @@ -2411,6 +2493,10 @@ interface Materials { Material GUSTER_BANNER_PATTERN = MaterialImpl.get("minecraft:guster_banner_pattern"); + Material FIELD_MASONED_BANNER_PATTERN = MaterialImpl.get("minecraft:field_masoned_banner_pattern"); + + Material BORDURE_INDENTED_BANNER_PATTERN = MaterialImpl.get("minecraft:bordure_indented_banner_pattern"); + Material GOAT_HORN = MaterialImpl.get("minecraft:goat_horn"); Material COMPOSTER = MaterialImpl.get("minecraft:composter"); @@ -2668,6 +2754,4 @@ interface Materials { Material VAULT = MaterialImpl.get("minecraft:vault"); Material OMINOUS_BOTTLE = MaterialImpl.get("minecraft:ominous_bottle"); - - Material BREEZE_ROD = MaterialImpl.get("minecraft:breeze_rod"); } diff --git a/src/autogenerated/java/net/minestom/server/particle/Particles.java b/src/autogenerated/java/net/minestom/server/particle/Particles.java index 37ecf045e..9369be577 100644 --- a/src/autogenerated/java/net/minestom/server/particle/Particles.java +++ b/src/autogenerated/java/net/minestom/server/particle/Particles.java @@ -96,6 +96,8 @@ interface Particles { Particle.Vibration VIBRATION = (Particle.Vibration) ParticleImpl.get("minecraft:vibration"); + Particle.Trail TRAIL = (Particle.Trail) ParticleImpl.get("minecraft:trail"); + Particle ITEM_SLIME = ParticleImpl.get("minecraft:item_slime"); Particle ITEM_COBWEB = ParticleImpl.get("minecraft:item_cobweb"); @@ -221,4 +223,6 @@ interface Particles { Particle RAID_OMEN = ParticleImpl.get("minecraft:raid_omen"); Particle TRIAL_OMEN = ParticleImpl.get("minecraft:trial_omen"); + + Particle.BlockCrumble BLOCK_CRUMBLE = (Particle.BlockCrumble) ParticleImpl.get("minecraft:block_crumble"); } diff --git a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java index 16735c2d4..422737c9d 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java +++ b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java @@ -33,9 +33,7 @@ public enum RecipeType implements StaticProtocolObject { SPECIAL_SHIELDDECORATION(NamespaceID.from("minecraft:crafting_special_shielddecoration")), - SPECIAL_SHULKERBOXCOLORING(NamespaceID.from("minecraft:crafting_special_shulkerboxcoloring")), - - SPECIAL_SUSPICIOUSSTEW(NamespaceID.from("minecraft:crafting_special_suspiciousstew")), + TRANSMUTE(NamespaceID.from("minecraft:crafting_transmute")), SPECIAL_REPAIRITEM(NamespaceID.from("minecraft:crafting_special_repairitem")), diff --git a/src/autogenerated/java/net/minestom/server/sound/SoundEvents.java b/src/autogenerated/java/net/minestom/server/sound/SoundEvents.java index f886a7aa7..0c30cb41b 100644 --- a/src/autogenerated/java/net/minestom/server/sound/SoundEvents.java +++ b/src/autogenerated/java/net/minestom/server/sound/SoundEvents.java @@ -425,6 +425,8 @@ interface SoundEvents { SoundEvent BLOCK_BUBBLE_COLUMN_WHIRLPOOL_INSIDE = BuiltinSoundEvent.get("minecraft:block.bubble_column.whirlpool_inside"); + SoundEvent UI_HUD_BUBBLE_POP = BuiltinSoundEvent.get("minecraft:ui.hud.bubble_pop"); + SoundEvent ITEM_BUCKET_EMPTY = BuiltinSoundEvent.get("minecraft:item.bucket.empty"); SoundEvent ITEM_BUCKET_EMPTY_AXOLOTL = BuiltinSoundEvent.get("minecraft:item.bucket.empty_axolotl"); @@ -453,6 +455,8 @@ interface SoundEvents { SoundEvent ITEM_BUNDLE_INSERT = BuiltinSoundEvent.get("minecraft:item.bundle.insert"); + SoundEvent ITEM_BUNDLE_INSERT_FAIL = BuiltinSoundEvent.get("minecraft:item.bundle.insert_fail"); + SoundEvent ITEM_BUNDLE_REMOVE_ONE = BuiltinSoundEvent.get("minecraft:item.bundle.remove_one"); SoundEvent BLOCK_CAKE_ADD_CANDLE = BuiltinSoundEvent.get("minecraft:block.cake.add_candle"); @@ -749,6 +753,42 @@ interface SoundEvents { SoundEvent BLOCK_CRAFTER_FAIL = BuiltinSoundEvent.get("minecraft:block.crafter.fail"); + SoundEvent ENTITY_CREAKING_AMBIENT = BuiltinSoundEvent.get("minecraft:entity.creaking.ambient"); + + SoundEvent ENTITY_CREAKING_ACTIVATE = BuiltinSoundEvent.get("minecraft:entity.creaking.activate"); + + SoundEvent ENTITY_CREAKING_DEACTIVATE = BuiltinSoundEvent.get("minecraft:entity.creaking.deactivate"); + + SoundEvent ENTITY_CREAKING_ATTACK = BuiltinSoundEvent.get("minecraft:entity.creaking.attack"); + + SoundEvent ENTITY_CREAKING_DEATH = BuiltinSoundEvent.get("minecraft:entity.creaking.death"); + + SoundEvent ENTITY_CREAKING_STEP = BuiltinSoundEvent.get("minecraft:entity.creaking.step"); + + SoundEvent ENTITY_CREAKING_FREEZE = BuiltinSoundEvent.get("minecraft:entity.creaking.freeze"); + + SoundEvent ENTITY_CREAKING_UNFREEZE = BuiltinSoundEvent.get("minecraft:entity.creaking.unfreeze"); + + SoundEvent ENTITY_CREAKING_SPAWN = BuiltinSoundEvent.get("minecraft:entity.creaking.spawn"); + + SoundEvent ENTITY_CREAKING_SWAY = BuiltinSoundEvent.get("minecraft:entity.creaking.sway"); + + SoundEvent BLOCK_CREAKING_HEART_BREAK = BuiltinSoundEvent.get("minecraft:block.creaking_heart.break"); + + SoundEvent BLOCK_CREAKING_HEART_FALL = BuiltinSoundEvent.get("minecraft:block.creaking_heart.fall"); + + SoundEvent BLOCK_CREAKING_HEART_HIT = BuiltinSoundEvent.get("minecraft:block.creaking_heart.hit"); + + SoundEvent BLOCK_CREAKING_HEART_HURT = BuiltinSoundEvent.get("minecraft:block.creaking_heart.hurt"); + + SoundEvent BLOCK_CREAKING_HEART_PLACE = BuiltinSoundEvent.get("minecraft:block.creaking_heart.place"); + + SoundEvent BLOCK_CREAKING_HEART_STEP = BuiltinSoundEvent.get("minecraft:block.creaking_heart.step"); + + SoundEvent BLOCK_CREAKING_HEART_IDLE = BuiltinSoundEvent.get("minecraft:block.creaking_heart.idle"); + + SoundEvent BLOCK_CREAKING_HEART_SPAWN = BuiltinSoundEvent.get("minecraft:block.creaking_heart.spawn"); + SoundEvent ENTITY_CREEPER_DEATH = BuiltinSoundEvent.get("minecraft:entity.creeper.death"); SoundEvent ENTITY_CREEPER_HURT = BuiltinSoundEvent.get("minecraft:entity.creeper.hurt"); @@ -1239,8 +1279,6 @@ interface SoundEvents { SoundEvent ENTITY_GOAT_HORN_BREAK = BuiltinSoundEvent.get("minecraft:entity.goat.horn_break"); - SoundEvent ITEM_GOAT_HORN_PLAY = BuiltinSoundEvent.get("minecraft:item.goat_horn.play"); - SoundEvent ENTITY_GOAT_SCREAMING_AMBIENT = BuiltinSoundEvent.get("minecraft:entity.goat.screaming.ambient"); SoundEvent ENTITY_GOAT_SCREAMING_DEATH = BuiltinSoundEvent.get("minecraft:entity.goat.screaming.death"); @@ -1257,8 +1295,6 @@ interface SoundEvents { SoundEvent ENTITY_GOAT_SCREAMING_RAM_IMPACT = BuiltinSoundEvent.get("minecraft:entity.goat.screaming.ram_impact"); - SoundEvent ENTITY_GOAT_SCREAMING_HORN_BREAK = BuiltinSoundEvent.get("minecraft:entity.goat.screaming.horn_break"); - SoundEvent ENTITY_GOAT_STEP = BuiltinSoundEvent.get("minecraft:entity.goat.step"); SoundEvent BLOCK_GRASS_BREAK = BuiltinSoundEvent.get("minecraft:block.grass.break"); @@ -2033,6 +2069,8 @@ interface SoundEvents { SoundEvent ENTITY_PAINTING_PLACE = BuiltinSoundEvent.get("minecraft:entity.painting.place"); + SoundEvent BLOCK_PALE_HANGING_MOSS_IDLE = BuiltinSoundEvent.get("minecraft:block.pale_hanging_moss.idle"); + SoundEvent ENTITY_PANDA_PRE_SNEEZE = BuiltinSoundEvent.get("minecraft:entity.panda.pre_sneeze"); SoundEvent ENTITY_PANDA_SNEEZE = BuiltinSoundEvent.get("minecraft:entity.panda.sneeze"); @@ -2071,6 +2109,8 @@ interface SoundEvents { SoundEvent ENTITY_PARROT_IMITATE_BREEZE = BuiltinSoundEvent.get("minecraft:entity.parrot.imitate.breeze"); + SoundEvent ENTITY_PARROT_IMITATE_CREAKING = BuiltinSoundEvent.get("minecraft:entity.parrot.imitate.creaking"); + SoundEvent ENTITY_PARROT_IMITATE_CREEPER = BuiltinSoundEvent.get("minecraft:entity.parrot.imitate.creeper"); SoundEvent ENTITY_PARROT_IMITATE_DROWNED = BuiltinSoundEvent.get("minecraft:entity.parrot.imitate.drowned"); @@ -2599,6 +2639,16 @@ interface SoundEvents { SoundEvent PARTICLE_SOUL_ESCAPE = BuiltinSoundEvent.get("minecraft:particle.soul_escape"); + SoundEvent BLOCK_SPAWNER_BREAK = BuiltinSoundEvent.get("minecraft:block.spawner.break"); + + SoundEvent BLOCK_SPAWNER_FALL = BuiltinSoundEvent.get("minecraft:block.spawner.fall"); + + SoundEvent BLOCK_SPAWNER_HIT = BuiltinSoundEvent.get("minecraft:block.spawner.hit"); + + SoundEvent BLOCK_SPAWNER_PLACE = BuiltinSoundEvent.get("minecraft:block.spawner.place"); + + SoundEvent BLOCK_SPAWNER_STEP = BuiltinSoundEvent.get("minecraft:block.spawner.step"); + SoundEvent BLOCK_SPORE_BLOSSOM_BREAK = BuiltinSoundEvent.get("minecraft:block.spore_blossom.break"); SoundEvent BLOCK_SPORE_BLOSSOM_FALL = BuiltinSoundEvent.get("minecraft:block.spore_blossom.fall"); diff --git a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java index f58d386ae..9c3e2bfc7 100644 --- a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java @@ -15,7 +15,7 @@ public class PlayerPositionListener { private static final double MAX_COORDINATE = 30_000_000; private static final Component KICK_MESSAGE = Component.text("You moved too far away!"); - public static void playerPacketListener(ClientPlayerPacket packet, Player player) { + public static void playerPacketListener(ClientPlayerPositionStatusPacket packet, Player player) { player.refreshOnGround(packet.onGround()); } diff --git a/src/main/java/net/minestom/server/listener/RecipeListener.java b/src/main/java/net/minestom/server/listener/RecipeListener.java index 39065db60..efa3a1973 100644 --- a/src/main/java/net/minestom/server/listener/RecipeListener.java +++ b/src/main/java/net/minestom/server/listener/RecipeListener.java @@ -1,12 +1,12 @@ package net.minestom.server.listener; import net.minestom.server.entity.Player; -import net.minestom.server.network.packet.client.play.ClientCraftRecipeRequest; -import net.minestom.server.network.packet.server.play.CraftRecipeResponse; +import net.minestom.server.network.packet.client.play.ClientPlaceRecipePacket; +import net.minestom.server.network.packet.server.play.PlaceGhostRecipePacket; public class RecipeListener { - public static void listener(ClientCraftRecipeRequest packet, Player player) { - player.sendPacket(new CraftRecipeResponse(packet.windowId(), packet.recipe())); + public static void listener(ClientPlaceRecipePacket packet, Player player) { + player.sendPacket(new PlaceGhostRecipePacket(packet.windowId(), packet.recipe())); } } diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 58ab14742..32647da75 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -72,7 +72,7 @@ public final class PacketListenerManager { setPlayListener(ClientSteerVehiclePacket.class, PlayerVehicleListener::steerVehicleListener); setPlayListener(ClientVehicleMovePacket.class, PlayerVehicleListener::vehicleMoveListener); setPlayListener(ClientSteerBoatPacket.class, PlayerVehicleListener::boatSteerListener); - setPlayListener(ClientPlayerPacket.class, PlayerPositionListener::playerPacketListener); + setPlayListener(ClientPlayerPositionStatusPacket.class, PlayerPositionListener::playerPacketListener); setPlayListener(ClientPlayerRotationPacket.class, PlayerPositionListener::playerLookListener); setPlayListener(ClientPlayerPositionPacket.class, PlayerPositionListener::playerPositionListener); setPlayListener(ClientPlayerPositionAndRotationPacket.class, PlayerPositionListener::playerPositionAndLookListener); @@ -84,7 +84,7 @@ public final class PacketListenerManager { setPlayListener(ClientStatusPacket.class, PlayStatusListener::listener); setPlayListener(ClientSettingsPacket.class, SettingsListener::listener); setPlayListener(ClientCreativeInventoryActionPacket.class, CreativeInventoryActionListener::listener); - setPlayListener(ClientCraftRecipeRequest.class, RecipeListener::listener); + setPlayListener(ClientPlaceRecipePacket.class, RecipeListener::listener); setPlayListener(ClientTabCompletePacket.class, TabCompleteListener::listener); setPlayListener(ClientPluginMessagePacket.class, PluginMessageListener::listener); setPlayListener(ClientPlayerAbilitiesPacket.class, AbilitiesListener::listener); diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java index d57e001a6..00bf78627 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTemplate.java @@ -102,6 +102,11 @@ public final class NetworkBufferTemplate { R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19); } + @FunctionalInterface + public interface F20 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16, P17 p17, P18 p18, P19 p19, P20 p20); + } + public static Type template(Supplier supplier) { return new NetworkBufferTypeImpl<>() { @Override @@ -791,4 +796,60 @@ public final class NetworkBufferTemplate { } }; } + + public static Type template( + Type p1, Function g1, Type p2, Function g2, + Type p3, Function g3, Type p4, Function g4, + Type p5, Function g5, Type p6, Function g6, + Type p7, Function g7, Type p8, Function g8, + Type p9, Function g9, Type p10, Function g10, + Type p11, Function g11, Type p12, Function g12, + Type p13, Function g13, Type p14, Function g14, + Type p15, Function g15, Type p16, Function g16, + Type p17, Function g17, Type p18, Function g18, + Type p19, Function g19, Type p20, Function g20, + F20 reader + ) { + return new NetworkBufferTypeImpl<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, R value) { + p1.write(buffer, g1.apply(value)); + p2.write(buffer, g2.apply(value)); + p3.write(buffer, g3.apply(value)); + p4.write(buffer, g4.apply(value)); + p5.write(buffer, g5.apply(value)); + p6.write(buffer, g6.apply(value)); + p7.write(buffer, g7.apply(value)); + p8.write(buffer, g8.apply(value)); + p9.write(buffer, g9.apply(value)); + p10.write(buffer, g10.apply(value)); + p11.write(buffer, g11.apply(value)); + p12.write(buffer, g12.apply(value)); + p13.write(buffer, g13.apply(value)); + p14.write(buffer, g14.apply(value)); + p15.write(buffer, g15.apply(value)); + p16.write(buffer, g16.apply(value)); + p17.write(buffer, g17.apply(value)); + p18.write(buffer, g18.apply(value)); + p19.write(buffer, g19.apply(value)); + p20.write(buffer, g20.apply(value)); + } + + @Override + public R read(@NotNull NetworkBuffer buffer) { + return reader.apply( + p1.read(buffer), p2.read(buffer), + p3.read(buffer), p4.read(buffer), + p5.read(buffer), p6.read(buffer), + p7.read(buffer), p8.read(buffer), + p9.read(buffer), p10.read(buffer), + p11.read(buffer), p12.read(buffer), + p13.read(buffer), p14.read(buffer), + p15.read(buffer), p16.read(buffer), + p17.read(buffer), p18.read(buffer), + p19.read(buffer), p20.read(buffer) + ); + } + }; + } } diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index 6e5559592..374944314 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -92,6 +92,7 @@ public interface PacketRegistry { super( entry(ClientTeleportConfirmPacket.class, ClientTeleportConfirmPacket.SERIALIZER), entry(ClientQueryBlockNbtPacket.class, ClientQueryBlockNbtPacket.SERIALIZER), + entry(ClientSelectBundleItemPacket.class, ClientSelectBundleItemPacket.SERIALIZER), entry(ClientChangeDifficultyPacket.class, ClientChangeDifficultyPacket.SERIALIZER), entry(ClientChatAckPacket.class, ClientChatAckPacket.SERIALIZER), entry(ClientCommandChatPacket.class, ClientCommandChatPacket.SERIALIZER), @@ -100,6 +101,7 @@ public interface PacketRegistry { entry(ClientChatSessionUpdatePacket.class, ClientChatSessionUpdatePacket.SERIALIZER), entry(ClientChunkBatchReceivedPacket.class, ClientChunkBatchReceivedPacket.SERIALIZER), entry(ClientStatusPacket.class, ClientStatusPacket.SERIALIZER), + entry(ClientTickEndPacket.class, ClientTickEndPacket.SERIALIZER), entry(ClientSettingsPacket.class, ClientSettingsPacket.SERIALIZER), entry(ClientTabCompletePacket.class, ClientTabCompletePacket.SERIALIZER), entry(ClientConfigurationAckPacket.class, ClientConfigurationAckPacket.SERIALIZER), @@ -119,19 +121,19 @@ public interface PacketRegistry { entry(ClientPlayerPositionPacket.class, ClientPlayerPositionPacket.SERIALIZER), entry(ClientPlayerPositionAndRotationPacket.class, ClientPlayerPositionAndRotationPacket.SERIALIZER), entry(ClientPlayerRotationPacket.class, ClientPlayerRotationPacket.SERIALIZER), - entry(ClientPlayerPacket.class, ClientPlayerPacket.SERIALIZER), + entry(ClientPlayerPositionStatusPacket.class, ClientPlayerPositionStatusPacket.SERIALIZER), entry(ClientVehicleMovePacket.class, ClientVehicleMovePacket.SERIALIZER), entry(ClientSteerBoatPacket.class, ClientSteerBoatPacket.SERIALIZER), entry(ClientPickItemPacket.class, ClientPickItemPacket.SERIALIZER), entry(ClientPingRequestPacket.class, ClientPingRequestPacket.SERIALIZER), - entry(ClientCraftRecipeRequest.class, ClientCraftRecipeRequest.SERIALIZER), + entry(ClientPlaceRecipePacket.class, ClientPlaceRecipePacket.SERIALIZER), entry(ClientPlayerAbilitiesPacket.class, ClientPlayerAbilitiesPacket.SERIALIZER), entry(ClientPlayerDiggingPacket.class, ClientPlayerDiggingPacket.SERIALIZER), entry(ClientEntityActionPacket.class, ClientEntityActionPacket.SERIALIZER), entry(ClientSteerVehiclePacket.class, ClientSteerVehiclePacket.SERIALIZER), entry(ClientPongPacket.class, ClientPongPacket.SERIALIZER), entry(ClientSetRecipeBookStatePacket.class, ClientSetRecipeBookStatePacket.SERIALIZER), - entry(ClientSetDisplayedRecipePacket.class, ClientSetDisplayedRecipePacket.SERIALIZER), + entry(ClientRecipeBookSeenRecipePacket.class, ClientRecipeBookSeenRecipePacket.SERIALIZER), entry(ClientNameItemPacket.class, ClientNameItemPacket.SERIALIZER), entry(ClientResourcePackStatusPacket.class, ClientResourcePackStatusPacket.SERIALIZER), entry(ClientAdvancementTabPacket.class, ClientAdvancementTabPacket.SERIALIZER), @@ -264,6 +266,7 @@ public interface PacketRegistry { entry(TradeListPacket.class, TradeListPacket.SERIALIZER), entry(EntityPositionPacket.class, EntityPositionPacket.SERIALIZER), entry(EntityPositionAndRotationPacket.class, EntityPositionAndRotationPacket.SERIALIZER), + entry(MoveMinecartPacket.class, MoveMinecartPacket.SERIALIZER), entry(EntityRotationPacket.class, EntityRotationPacket.SERIALIZER), entry(VehicleMovePacket.class, VehicleMovePacket.SERIALIZER), entry(OpenBookPacket.class, OpenBookPacket.SERIALIZER), @@ -271,7 +274,7 @@ public interface PacketRegistry { entry(OpenSignEditorPacket.class, OpenSignEditorPacket.SERIALIZER), entry(PingPacket.class, PingPacket.SERIALIZER), entry(PingResponsePacket.class, PingResponsePacket.SERIALIZER), - entry(CraftRecipeResponse.class, CraftRecipeResponse.SERIALIZER), + entry(PlaceGhostRecipePacket.class, PlaceGhostRecipePacket.SERIALIZER), entry(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket.SERIALIZER), entry(PlayerChatMessagePacket.class, PlayerChatMessagePacket.SERIALIZER), entry(EndCombatEventPacket.class, EndCombatEventPacket.SERIALIZER), @@ -281,7 +284,10 @@ public interface PacketRegistry { entry(PlayerInfoUpdatePacket.class, PlayerInfoUpdatePacket.SERIALIZER), entry(FacePlayerPacket.class, FacePlayerPacket.SERIALIZER), entry(PlayerPositionAndLookPacket.class, PlayerPositionAndLookPacket.SERIALIZER), - entry(UnlockRecipesPacket.class, UnlockRecipesPacket.SERIALIZER), + entry(PlayerRotationPacket.class, PlayerRotationPacket.SERIALIZER), + entry(RecipeBookAddPacket.class, RecipeBookAddPacket.SERIALIZER), + entry(RecipeBookRemovePacket.class, RecipeBookRemovePacket.SERIALIZER), + entry(RecipeBookSettingsPacket.class, RecipeBookSettingsPacket.SERIALIZER), entry(DestroyEntitiesPacket.class, DestroyEntitiesPacket.SERIALIZER), entry(RemoveEntityEffectPacket.class, RemoveEntityEffectPacket.SERIALIZER), entry(ResetScorePacket.class, ResetScorePacket.SERIALIZER), @@ -299,9 +305,9 @@ public interface PacketRegistry { entry(WorldBorderWarningDelayPacket.class, WorldBorderWarningDelayPacket.SERIALIZER), entry(WorldBorderWarningReachPacket.class, WorldBorderWarningReachPacket.SERIALIZER), entry(CameraPacket.class, CameraPacket.SERIALIZER), - entry(HeldItemChangePacket.class, HeldItemChangePacket.SERIALIZER), entry(UpdateViewPositionPacket.class, UpdateViewPositionPacket.SERIALIZER), entry(UpdateViewDistancePacket.class, UpdateViewDistancePacket.SERIALIZER), + entry(SetCursorItemPacket.class, SetCursorItemPacket.SERIALIZER), entry(SpawnPositionPacket.class, SpawnPositionPacket.SERIALIZER), entry(DisplayScoreboardPacket.class, DisplayScoreboardPacket.SERIALIZER), entry(EntityMetaDataPacket.class, EntityMetaDataPacket.SERIALIZER), @@ -310,8 +316,10 @@ public interface PacketRegistry { entry(EntityEquipmentPacket.class, EntityEquipmentPacket.SERIALIZER), entry(SetExperiencePacket.class, SetExperiencePacket.SERIALIZER), entry(UpdateHealthPacket.class, UpdateHealthPacket.SERIALIZER), + entry(HeldItemChangePacket.class, HeldItemChangePacket.SERIALIZER), entry(ScoreboardObjectivePacket.class, ScoreboardObjectivePacket.SERIALIZER), entry(SetPassengersPacket.class, SetPassengersPacket.SERIALIZER), + entry(SetPlayerInventoryPacket.class, SetPlayerInventoryPacket.SERIALIZER), entry(TeamsPacket.class, TeamsPacket.SERIALIZER), entry(UpdateScorePacket.class, UpdateScorePacket.SERIALIZER), entry(UpdateSimulationDistancePacket.class, UpdateSimulationDistancePacket.SERIALIZER), diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java index b97a5d880..0317eb1f0 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowButtonPacket.java @@ -4,11 +4,11 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import static net.minestom.server.network.NetworkBuffer.BYTE; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record ClientClickWindowButtonPacket(byte windowId, byte buttonId) implements ClientPacket { +public record ClientClickWindowButtonPacket(int windowId, int buttonId) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, ClientClickWindowButtonPacket::windowId, - BYTE, ClientClickWindowButtonPacket::buttonId, + VAR_INT, ClientClickWindowButtonPacket::windowId, + VAR_INT, ClientClickWindowButtonPacket::buttonId, ClientClickWindowButtonPacket::new); } 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 fdd11a776..9be14f521 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 @@ -10,14 +10,14 @@ import java.util.List; import static net.minestom.server.network.NetworkBuffer.*; -public record ClientClickWindowPacket(byte windowId, int stateId, +public record ClientClickWindowPacket(int windowId, int stateId, short slot, byte button, @NotNull ClickType clickType, @NotNull List changedSlots, @NotNull ItemStack clickedItem) implements ClientPacket { public static final int MAX_CHANGED_SLOTS = 128; public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, ClientClickWindowPacket::windowId, + VAR_INT, ClientClickWindowPacket::windowId, VAR_INT, ClientClickWindowPacket::stateId, SHORT, ClientClickWindowPacket::slot, BYTE, ClientClickWindowPacket::button, diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java index 49ce2b32c..82bcf6d0e 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCloseWindowPacket.java @@ -4,10 +4,10 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import static net.minestom.server.network.NetworkBuffer.BYTE; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record ClientCloseWindowPacket(byte windowId) implements ClientPacket { +public record ClientCloseWindowPacket(int windowId) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, ClientCloseWindowPacket::windowId, + VAR_INT, ClientCloseWindowPacket::windowId, ClientCloseWindowPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java deleted file mode 100644 index 3920ca3e4..000000000 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCraftRecipeRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.network.packet.client.play; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.NetworkBufferTemplate; -import net.minestom.server.network.packet.client.ClientPacket; - -import static net.minestom.server.network.NetworkBuffer.*; - -public record ClientCraftRecipeRequest(byte windowId, String recipe, boolean makeAll) implements ClientPacket { - public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, ClientCraftRecipeRequest::windowId, - STRING, ClientCraftRecipeRequest::recipe, - BOOLEAN, ClientCraftRecipeRequest::makeAll, - ClientCraftRecipeRequest::new); - public ClientCraftRecipeRequest { - if (recipe.length() > 256) { - throw new IllegalArgumentException("'recipe' cannot be longer than 256 characters."); - } - } -} 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 e0b089167..adde0e0af 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 @@ -13,7 +13,9 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT; public record ClientEditBookPacket(int slot, @NotNull List pages, @Nullable String title) implements ClientPacket { - public static final int MAX_PAGES = 200; + public static final int MAX_PAGES = 100; + public static final int MAX_TITLE_LENGTH = 32; + public static final int MAX_PAGE_LENGTH = 1024; public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( VAR_INT, ClientEditBookPacket::slot, @@ -22,9 +24,14 @@ public record ClientEditBookPacket(int slot, @NotNull List pages, ClientEditBookPacket::new); public ClientEditBookPacket { - pages = List.copyOf(pages); - if (title != null && title.length() > 128) { - throw new IllegalArgumentException("Title length cannot be greater than 128"); + for (var page : pages) { + if (page.length() > MAX_PAGE_LENGTH) { + throw new IllegalArgumentException("Page length cannot be greater than " + MAX_PAGE_LENGTH); + } } + if (title != null && title.length() > MAX_TITLE_LENGTH) { + throw new IllegalArgumentException("Title length cannot be greater than " + MAX_TITLE_LENGTH); + } + pages = List.copyOf(pages); } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlaceRecipePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlaceRecipePacket.java new file mode 100644 index 000000000..7c4619461 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlaceRecipePacket.java @@ -0,0 +1,20 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.*; + +public record ClientPlaceRecipePacket(byte windowId, String recipe, boolean makeAll) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientPlaceRecipePacket::windowId, + STRING, ClientPlaceRecipePacket::recipe, + BOOLEAN, ClientPlaceRecipePacket::makeAll, + ClientPlaceRecipePacket::new); + public ClientPlaceRecipePacket { + if (recipe.length() > 256) { + throw new IllegalArgumentException("'recipe' cannot be longer than 256 characters."); + } + } +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java deleted file mode 100644 index 0c500e88b..000000000 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPacket.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.minestom.server.network.packet.client.play; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.NetworkBufferTemplate; -import net.minestom.server.network.packet.client.ClientPacket; - -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; - -public record ClientPlayerPacket(boolean onGround) implements ClientPacket { - public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BOOLEAN, ClientPlayerPacket::onGround, - ClientPlayerPacket::new); -} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java index 9605e931b..622f11e76 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionAndRotationPacket.java @@ -6,13 +6,27 @@ import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.POS; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_HORIZONTAL_COLLISION; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_ON_GROUND; -public record ClientPlayerPositionAndRotationPacket(@NotNull Pos position, - boolean onGround) implements ClientPacket { +public record ClientPlayerPositionAndRotationPacket(@NotNull Pos position, byte flags) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( POS, ClientPlayerPositionAndRotationPacket::position, - BOOLEAN, ClientPlayerPositionAndRotationPacket::onGround, + BYTE, ClientPlayerPositionAndRotationPacket::flags, ClientPlayerPositionAndRotationPacket::new); + + public ClientPlayerPositionAndRotationPacket(@NotNull Pos position, boolean onGround, boolean horizontalCollision) { + this(position, (byte) ((onGround ? FLAG_ON_GROUND : 0) | + (byte) (horizontalCollision ? FLAG_HORIZONTAL_COLLISION : 0))); + } + + public boolean onGround() { + return (flags & FLAG_ON_GROUND) != 0; + } + + public boolean horizontalCollision() { + return (flags & FLAG_HORIZONTAL_COLLISION) != 0; + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java index 643d4af2a..50ea94490 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionPacket.java @@ -6,13 +6,29 @@ import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.VECTOR3D; -public record ClientPlayerPositionPacket(@NotNull Point position, - boolean onGround) implements ClientPacket { +public record ClientPlayerPositionPacket(@NotNull Point position, byte flags) implements ClientPacket { + public static final int FLAG_ON_GROUND = 1; + public static final int FLAG_HORIZONTAL_COLLISION = 1 << 1; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( VECTOR3D, ClientPlayerPositionPacket::position, - BOOLEAN, ClientPlayerPositionPacket::onGround, + BYTE, ClientPlayerPositionPacket::flags, ClientPlayerPositionPacket::new); + + public ClientPlayerPositionPacket(@NotNull Point position, boolean onGround, boolean horizontalCollision) { + this(position, (byte) ((onGround ? FLAG_ON_GROUND : 0) | + (byte) (horizontalCollision ? FLAG_HORIZONTAL_COLLISION : 0))); + } + + public boolean onGround() { + return (flags & FLAG_ON_GROUND) != 0; + } + + public boolean horizontalCollision() { + return (flags & FLAG_HORIZONTAL_COLLISION) != 0; + } + } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionStatusPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionStatusPacket.java new file mode 100644 index 000000000..dc64c5ef8 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerPositionStatusPacket.java @@ -0,0 +1,29 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.BYTE; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_HORIZONTAL_COLLISION; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_ON_GROUND; + +public record ClientPlayerPositionStatusPacket(byte flags) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + BYTE, ClientPlayerPositionStatusPacket::flags, + ClientPlayerPositionStatusPacket::new); + + public ClientPlayerPositionStatusPacket(boolean onGround, boolean horizontalCollision) { + this((byte) ((onGround ? FLAG_ON_GROUND : 0) | + (byte) (horizontalCollision ? FLAG_HORIZONTAL_COLLISION : 0))); + } + + public boolean onGround() { + return (flags & FLAG_ON_GROUND) != 0; + } + + public boolean horizontalCollision() { + return (flags & FLAG_HORIZONTAL_COLLISION) != 0; + } + +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java index 1e36449c1..d8cf86a23 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientPlayerRotationPacket.java @@ -4,13 +4,28 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; +import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.FLOAT; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_HORIZONTAL_COLLISION; +import static net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket.FLAG_ON_GROUND; -public record ClientPlayerRotationPacket(float yaw, float pitch, boolean onGround) implements ClientPacket { +public record ClientPlayerRotationPacket(float yaw, float pitch, byte flags) implements ClientPacket { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( FLOAT, ClientPlayerRotationPacket::yaw, FLOAT, ClientPlayerRotationPacket::pitch, - BOOLEAN, ClientPlayerRotationPacket::onGround, + BYTE, ClientPlayerRotationPacket::flags, ClientPlayerRotationPacket::new); + + public ClientPlayerRotationPacket(float yaw, float pitch, boolean onGround, boolean horizontalCollision) { + this(yaw, pitch, (byte) ((onGround ? FLAG_ON_GROUND : 0) | + (byte) (horizontalCollision ? FLAG_HORIZONTAL_COLLISION : 0))); + } + + public boolean onGround() { + return (flags & FLAG_ON_GROUND) != 0; + } + + public boolean horizontalCollision() { + return (flags & FLAG_HORIZONTAL_COLLISION) != 0; + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientRecipeBookSeenRecipePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientRecipeBookSeenRecipePacket.java new file mode 100644 index 000000000..bf1fd99dc --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientRecipeBookSeenRecipePacket.java @@ -0,0 +1,13 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +public record ClientRecipeBookSeenRecipePacket(int index) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientRecipeBookSeenRecipePacket::index, + ClientRecipeBookSeenRecipePacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectBundleItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectBundleItemPacket.java new file mode 100644 index 000000000..2d50b5c98 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSelectBundleItemPacket.java @@ -0,0 +1,14 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +public record ClientSelectBundleItemPacket(int slot, int selectedIndex) implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, ClientSelectBundleItemPacket::slot, + VAR_INT, ClientSelectBundleItemPacket::selectedIndex, + ClientSelectBundleItemPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java deleted file mode 100644 index 38f6b1c48..000000000 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSetDisplayedRecipePacket.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.minestom.server.network.packet.client.play; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.NetworkBufferTemplate; -import net.minestom.server.network.packet.client.ClientPacket; -import org.jetbrains.annotations.NotNull; - -import static net.minestom.server.network.NetworkBuffer.STRING; - -public record ClientSetDisplayedRecipePacket(@NotNull String recipeId) implements ClientPacket { - public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - STRING, ClientSetDisplayedRecipePacket::recipeId, - ClientSetDisplayedRecipePacket::new); - - public ClientSetDisplayedRecipePacket { - if (recipeId.length() > 256) { - throw new IllegalArgumentException("'recipeId' cannot be longer than 256 characters."); - } - } -} diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java index f5279496b..fc13cbdcd 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientSteerVehiclePacket.java @@ -5,13 +5,55 @@ import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.client.ClientPacket; import static net.minestom.server.network.NetworkBuffer.BYTE; -import static net.minestom.server.network.NetworkBuffer.FLOAT; -public record ClientSteerVehiclePacket(float sideways, float forward, - byte flags) implements ClientPacket { +public record ClientSteerVehiclePacket(byte flags) implements ClientPacket { + private static final byte FLAG_FORWARD = 1; + private static final byte FLAG_BACKWARD = 1 << 1; + private static final byte FLAG_LEFT = 1 << 2; + private static final byte FLAG_RIGHT = 1 << 3; + private static final byte FLAG_JUMP = 1 << 4; + private static final byte FLAG_SHIFT = 1 << 5; + private static final byte FLAG_SPRINT = 1 << 6; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - FLOAT, ClientSteerVehiclePacket::sideways, - FLOAT, ClientSteerVehiclePacket::forward, BYTE, ClientSteerVehiclePacket::flags, ClientSteerVehiclePacket::new); + + public ClientSteerVehiclePacket(boolean forward, boolean backward, boolean left, boolean right, boolean jump, boolean shift, boolean sprint) { + this((byte) ((forward ? FLAG_FORWARD : 0) | + (backward ? FLAG_BACKWARD : 0) | + (left ? FLAG_LEFT : 0) | + (right ? FLAG_RIGHT : 0) | + (jump ? FLAG_JUMP : 0) | + (shift ? FLAG_SHIFT : 0) | + (sprint ? FLAG_SPRINT : 0))); + } + + public boolean forward() { + return (flags & FLAG_FORWARD) != 0; + } + + public boolean backward() { + return (flags & FLAG_BACKWARD) != 0; + } + + public boolean left() { + return (flags & FLAG_LEFT) != 0; + } + + public boolean right() { + return (flags & FLAG_RIGHT) != 0; + } + + public boolean jump() { + return (flags & FLAG_JUMP) != 0; + } + + public boolean shift() { + return (flags & FLAG_SHIFT) != 0; + } + + public boolean sprint() { + return (flags & FLAG_SPRINT) != 0; + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientTickEndPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientTickEndPacket.java new file mode 100644 index 000000000..89eb58b10 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientTickEndPacket.java @@ -0,0 +1,11 @@ +package net.minestom.server.network.packet.client.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.client.ClientPacket; + +public record ClientTickEndPacket() implements ClientPacket { + public static final NetworkBuffer.Type SERIALIZER = + NetworkBufferTemplate.template(ClientTickEndPacket::new); + +} 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 b41ee4f42..65877131a 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 @@ -8,8 +8,7 @@ import net.minestom.server.network.player.PlayerConnection; *

* Packets are value-based, and should therefore not be reliant on identity. */ -public sealed interface ServerPacket extends SendablePacket permits - ServerPacket.Configuration, ServerPacket.Status, ServerPacket.Login, ServerPacket.Play { +public sealed interface ServerPacket extends SendablePacket permits ServerPacket.Configuration, ServerPacket.Login, ServerPacket.Play, ServerPacket.Status { non-sealed interface Configuration extends ServerPacket { } diff --git a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java index 8ab58aa16..a25a0a18d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/login/LoginSuccessPacket.java @@ -6,12 +6,8 @@ import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.player.GameProfile; import org.jetbrains.annotations.NotNull; -import static net.minestom.server.network.NetworkBuffer.BOOLEAN; - -public record LoginSuccessPacket(@NotNull GameProfile gameProfile, - boolean strictErrorHandling) implements ServerPacket.Login { +public record LoginSuccessPacket(@NotNull GameProfile gameProfile) implements ServerPacket.Login { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( GameProfile.SERIALIZER, LoginSuccessPacket::gameProfile, - BOOLEAN, LoginSuccessPacket::strictErrorHandling, LoginSuccessPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java index d2623524c..a6ec0a30d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/CloseWindowPacket.java @@ -4,10 +4,10 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import static net.minestom.server.network.NetworkBuffer.BYTE; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record CloseWindowPacket(byte windowId) implements ServerPacket.Play { +public record CloseWindowPacket(int windowId) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, CloseWindowPacket::windowId, + VAR_INT, CloseWindowPacket::windowId, CloseWindowPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java b/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java deleted file mode 100644 index 400cf1baf..000000000 --- a/src/main/java/net/minestom/server/network/packet/server/play/CraftRecipeResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.minestom.server.network.packet.server.play; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.NetworkBufferTemplate; -import net.minestom.server.network.packet.server.ServerPacket; - -import static net.minestom.server.network.NetworkBuffer.BYTE; -import static net.minestom.server.network.NetworkBuffer.STRING; - -public record CraftRecipeResponse(byte windowId, String recipe) implements ServerPacket.Play { - public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, CraftRecipeResponse::windowId, - STRING, CraftRecipeResponse::recipe, - CraftRecipeResponse::new); -} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionSyncPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionSyncPacket.java new file mode 100644 index 000000000..ab84aeedb --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityPositionSyncPacket.java @@ -0,0 +1,23 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.coordinate.Point; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.*; + +public record EntityPositionSyncPacket( + int entityId, @NotNull Point position, @NotNull Point delta, + float yaw, float pitch, boolean onGround +) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, EntityPositionSyncPacket::entityId, + VECTOR3D, EntityPositionSyncPacket::position, + VECTOR3D, EntityPositionSyncPacket::delta, + FLOAT, EntityPositionSyncPacket::yaw, + FLOAT, EntityPositionSyncPacket::pitch, + BOOLEAN, EntityPositionSyncPacket::onGround, + EntityPositionSyncPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java index e390db2f3..292411e74 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ExplosionPacket.java @@ -1,93 +1,25 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.item.ItemStack; +import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.particle.Particle; import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.VECTOR3D; -public record ExplosionPacket(double x, double y, double z, float radius, - byte @NotNull [] records, - float playerMotionX, float playerMotionY, float playerMotionZ, - @NotNull BlockInteraction blockInteraction, - int smallParticleId, byte @NotNull [] smallParticleData, - int largeParticleId, byte @NotNull [] largeParticleData, - @NotNull SoundEvent sound) implements ServerPacket.Play { - public static final SoundEvent DEFAULT_SOUND = SoundEvent.ENTITY_GENERIC_EXPLODE; +public record ExplosionPacket( + @NotNull Point center, @Nullable Point playerKnockback, + @NotNull Particle particle, @NotNull SoundEvent sound +) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VECTOR3D, ExplosionPacket::center, + VECTOR3D.optional(), ExplosionPacket::playerKnockback, + Particle.NETWORK_TYPE, ExplosionPacket::particle, + SoundEvent.NETWORK_TYPE, ExplosionPacket::sound, + ExplosionPacket::new); - public static final NetworkBuffer.Type SERIALIZER = new Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, ExplosionPacket value) { - buffer.write(DOUBLE, value.x); - buffer.write(DOUBLE, value.y); - buffer.write(DOUBLE, value.z); - buffer.write(FLOAT, value.radius); - buffer.write(VAR_INT, value.records.length / 3); // each record is 3 bytes long - buffer.write(RAW_BYTES, value.records); - buffer.write(FLOAT, value.playerMotionX); - buffer.write(FLOAT, value.playerMotionY); - buffer.write(FLOAT, value.playerMotionZ); - buffer.write(VAR_INT, value.blockInteraction.ordinal()); - buffer.write(VAR_INT, value.smallParticleId); - buffer.write(RAW_BYTES, value.smallParticleData); - buffer.write(VAR_INT, value.largeParticleId); - buffer.write(RAW_BYTES, value.largeParticleData); - buffer.write(SoundEvent.NETWORK_TYPE, value.sound); - } - - @Override - public ExplosionPacket read(@NotNull NetworkBuffer buffer) { - double x = buffer.read(DOUBLE), y = buffer.read(DOUBLE), z = buffer.read(DOUBLE); - float radius = buffer.read(FLOAT); - byte[] records = buffer.read(FixedRawBytes(buffer.read(VAR_INT) * 3)); - float playerMotionX = buffer.read(FLOAT), playerMotionY = buffer.read(FLOAT), playerMotionZ = buffer.read(FLOAT); - BlockInteraction blockInteraction = buffer.read(NetworkBuffer.Enum(BlockInteraction.class)); - int smallParticleId = buffer.read(VAR_INT); - byte[] smallParticleData = readParticleData(buffer, Particle.fromId(smallParticleId)); - int largeParticleId = buffer.read(VAR_INT); - byte[] largeParticleData = readParticleData(buffer, Particle.fromId(largeParticleId)); - SoundEvent sound = buffer.read(SoundEvent.NETWORK_TYPE); - return new ExplosionPacket(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ, - blockInteraction, smallParticleId, smallParticleData, largeParticleId, largeParticleData, - sound); - } - }; - - private static byte @NotNull [] readParticleData(@NotNull NetworkBuffer reader, Particle particle) { - return NetworkBuffer.makeArray(buffer -> { - //Need to do this because particle data isn't at the end of the packet - if (particle.equals(Particle.BLOCK) || particle.equals(Particle.BLOCK_MARKER) || particle.equals(Particle.FALLING_DUST) || particle.equals(Particle.SHRIEK)) { - buffer.write(VAR_INT, reader.read(VAR_INT)); - } else if (particle.equals(Particle.VIBRATION)) { - buffer.write(VAR_INT, reader.read(VAR_INT)); - buffer.write(BLOCK_POSITION, reader.read(BLOCK_POSITION)); - buffer.write(VAR_INT, reader.read(VAR_INT)); - buffer.write(FLOAT, reader.read(FLOAT)); - buffer.write(VAR_INT, reader.read(VAR_INT)); - } else if (particle.equals(Particle.SCULK_CHARGE)) { - buffer.write(FLOAT, reader.read(FLOAT)); - } else if (particle.equals(Particle.ITEM)) { - buffer.write(ItemStack.NETWORK_TYPE, reader.read(ItemStack.NETWORK_TYPE)); - } else if (particle.equals(Particle.DUST_COLOR_TRANSITION)) { - for (int i = 0; i < 7; i++) buffer.write(FLOAT, reader.read(FLOAT)); - } else if (particle.equals(Particle.DUST)) { - for (int i = 0; i < 4; i++) buffer.write(FLOAT, reader.read(FLOAT)); - } - }); - } - - public ExplosionPacket(double x, double y, double z, float radius, byte @NotNull [] records, - float playerMotionX, float playerMotionY, float playerMotionZ) { - this(x, y, z, radius, records, playerMotionX, playerMotionY, playerMotionZ, - BlockInteraction.DESTROY, Particle.EXPLOSION.id(), new byte[]{}, - Particle.EXPLOSION_EMITTER.id(), new byte[]{}, - DEFAULT_SOUND); - } - - public enum BlockInteraction { - KEEP, DESTROY, DESTROY_WITH_DECAY, TRIGGER_BLOCK - } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java index a459f90dc..032ea8841 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/JoinGamePacket.java @@ -17,7 +17,7 @@ public record JoinGamePacket( boolean doLimitedCrafting, int dimensionType, String world, long hashedSeed, GameMode gameMode, GameMode previousGameMode, boolean isDebug, boolean isFlat, @Nullable WorldPos deathLocation, int portalCooldown, - boolean enforcesSecureChat + int seaLevel, boolean enforcesSecureChat ) implements ServerPacket.Play { public static final int MAX_WORLDS = Short.MAX_VALUE; @@ -44,6 +44,7 @@ public record JoinGamePacket( BOOLEAN, JoinGamePacket::isFlat, WorldPos.NETWORK_TYPE.optional(), JoinGamePacket::deathLocation, VAR_INT, JoinGamePacket::portalCooldown, + VAR_INT, JoinGamePacket::seaLevel, BOOLEAN, JoinGamePacket::enforcesSecureChat, JoinGamePacket::new ); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/MoveMinecartPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/MoveMinecartPacket.java new file mode 100644 index 000000000..38b6c413c --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/MoveMinecartPacket.java @@ -0,0 +1,31 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.coordinate.Point; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static net.minestom.server.network.NetworkBuffer.VECTOR3D; + +public record MoveMinecartPacket(int entityId, @NotNull List lerpSteps) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.VAR_INT, MoveMinecartPacket::entityId, + LerpStep.SERIALIZER.list(Short.MAX_VALUE), MoveMinecartPacket::lerpSteps, + MoveMinecartPacket::new); + + public record LerpStep( + @NotNull Point position, @NotNull Point velocity, + float yaw, float pitch, float weight + ) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VECTOR3D, LerpStep::position, + VECTOR3D, LerpStep::velocity, + NetworkBuffer.FLOAT, LerpStep::yaw, + NetworkBuffer.FLOAT, LerpStep::pitch, + NetworkBuffer.FLOAT, LerpStep::weight, + LerpStep::new); + } +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java index 96a0ea381..41bc99b41 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenHorseWindowPacket.java @@ -4,11 +4,12 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.INT; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record OpenHorseWindowPacket(byte windowId, int slotCount, int entityId) implements ServerPacket.Play { +public record OpenHorseWindowPacket(int windowId, int slotCount, int entityId) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, OpenHorseWindowPacket::windowId, + VAR_INT, OpenHorseWindowPacket::windowId, VAR_INT, OpenHorseWindowPacket::slotCount, INT, OpenHorseWindowPacket::entityId, OpenHorseWindowPacket::new); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlaceGhostRecipePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlaceGhostRecipePacket.java new file mode 100644 index 000000000..68a8b6153 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlaceGhostRecipePacket.java @@ -0,0 +1,17 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.STRING; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +// TODO: Recipe is now a RecipeDisplay object need to look further into it. +public record PlaceGhostRecipePacket(int windowId, @NotNull String recipe) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, PlaceGhostRecipePacket::windowId, + STRING, PlaceGhostRecipePacket::recipe, + PlaceGhostRecipePacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java index ebcf00a49..8c4256516 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerInfoUpdatePacket.java @@ -48,7 +48,8 @@ public record PlayerInfoUpdatePacket( public record Entry(UUID uuid, String username, List properties, boolean listed, int latency, GameMode gameMode, - @Nullable Component displayName, @Nullable ChatSession chatSession) { + @Nullable Component displayName, @Nullable ChatSession chatSession, + int listOrder) { public Entry { properties = List.copyOf(properties); } @@ -71,6 +72,7 @@ public record PlayerInfoUpdatePacket( GameMode gameMode = GameMode.SURVIVAL; Component displayName = null; ChatSession chatSession = null; + int listOrder = 0; for (Action action : actions) { switch (action) { case ADD_PLAYER -> { @@ -82,9 +84,10 @@ public record PlayerInfoUpdatePacket( case UPDATE_LISTED -> listed = buffer.read(BOOLEAN); case UPDATE_LATENCY -> latency = buffer.read(VAR_INT); case UPDATE_DISPLAY_NAME -> displayName = buffer.read(COMPONENT.optional()); + case UPDATE_LIST_ORDER -> listOrder = buffer.read(VAR_INT); } } - return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession); + return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession, listOrder); } }; } @@ -111,7 +114,8 @@ public record PlayerInfoUpdatePacket( UPDATE_GAME_MODE((writer, entry) -> writer.write(VAR_INT, entry.gameMode.ordinal())), UPDATE_LISTED((writer, entry) -> writer.write(BOOLEAN, entry.listed)), UPDATE_LATENCY((writer, entry) -> writer.write(VAR_INT, entry.latency)), - UPDATE_DISPLAY_NAME((writer, entry) -> writer.write(COMPONENT.optional(), entry.displayName)); + UPDATE_DISPLAY_NAME((writer, entry) -> writer.write(COMPONENT.optional(), entry.displayName)), + UPDATE_LIST_ORDER((writer, entry) -> writer.write(VAR_INT, entry.listOrder)); final Writer writer; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java index 50e548651..4d3b9e19e 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerPositionAndLookPacket.java @@ -1,16 +1,37 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Point; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; -public record PlayerPositionAndLookPacket(Pos position, byte flags, int teleportId) implements ServerPacket.Play { +public record PlayerPositionAndLookPacket( + int teleportId, @NotNull Point position, @NotNull Point delta, + float yaw, float pitch, int flags +) implements ServerPacket.Play { + public static final int FLAG_X = 1; + public static final int FLAG_Y = 1 << 1; + public static final int FLAG_Z = 1 << 2; + public static final int FLAG_Y_ROT = 1 << 3; + public static final int FLAG_X_ROT = 1 << 4; + public static final int FLAG_DELTA_X = 1 << 5; + public static final int FLAG_DELTA_Y = 1 << 6; + public static final int FLAG_DELTA_Z = 1 << 7; + public static final int FLAG_ROTATE_DELTA = 1 << 8; + + public static final int FLAG_DELTA = FLAG_DELTA_X | FLAG_DELTA_Y | FLAG_DELTA_Z | FLAG_ROTATE_DELTA; + public static final int FLAG_ROTATION = FLAG_X_ROT | FLAG_Y_ROT; + public static final int FLAG_ALL = FLAG_X | FLAG_Y | FLAG_Z | FLAG_ROTATION | FLAG_DELTA; + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - POS, PlayerPositionAndLookPacket::position, - BYTE, PlayerPositionAndLookPacket::flags, VAR_INT, PlayerPositionAndLookPacket::teleportId, + VECTOR3D, PlayerPositionAndLookPacket::position, + VECTOR3D, PlayerPositionAndLookPacket::delta, + FLOAT, PlayerPositionAndLookPacket::yaw, + FLOAT, PlayerPositionAndLookPacket::pitch, + INT, PlayerPositionAndLookPacket::flags, PlayerPositionAndLookPacket::new); } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/network/packet/server/play/PlayerRotationPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/PlayerRotationPacket.java new file mode 100644 index 000000000..ca67dae40 --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/PlayerRotationPacket.java @@ -0,0 +1,14 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; + +import static net.minestom.server.network.NetworkBuffer.FLOAT; + +public record PlayerRotationPacket(float yaw, float pitch) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + FLOAT, PlayerRotationPacket::yaw, + FLOAT, PlayerRotationPacket::pitch, + PlayerRotationPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java new file mode 100644 index 000000000..cf176e29b --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java @@ -0,0 +1,43 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; + +public record RecipeBookAddPacket(@NotNull List entries, boolean replace) implements ServerPacket.Play { + public static final byte FLAG_NOTIFICATION = 1; + public static final byte FLAG_HIGHLIGHT = 1 << 1; + + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Entry.SERIALIZER.list(), RecipeBookAddPacket::entries, + BOOLEAN, RecipeBookAddPacket::replace, + RecipeBookAddPacket::new); + + public record Entry( +// int recipeIndex, Object display, +// @Nullable Integer group, @NotNull RecipeCategory category, +// @Nullable List craftingRequirements, +// byte flags + ) { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + Entry::new); + +// public Entry(Object contents, boolean notification, boolean highlight) { +// this(contents, (byte) ((notification ? FLAG_NOTIFICATION : 0) | (highlight ? FLAG_HIGHLIGHT : 0))); +// } +// +// public boolean notification() { +// return (flags & FLAG_NOTIFICATION) != 0; +// } +// +// public boolean highlight() { +// return (flags & FLAG_HIGHLIGHT) != 0; +// } + } + +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java new file mode 100644 index 000000000..255a6e51e --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java @@ -0,0 +1,11 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; + +public record RecipeBookRemovePacket() implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + RecipeBookRemovePacket::new); + +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookSettingsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookSettingsPacket.java new file mode 100644 index 000000000..ffa93087d --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookSettingsPacket.java @@ -0,0 +1,11 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; + +public record RecipeBookSettingsPacket() implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + RecipeBookSettingsPacket::new); + +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java index abba27a56..ee08d26f0 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RespawnPacket.java @@ -14,7 +14,7 @@ public record RespawnPacket( int dimensionType, @NotNull String worldName, long hashedSeed, @NotNull GameMode gameMode, @NotNull GameMode previousGameMode, boolean isDebug, boolean isFlat, @Nullable WorldPos deathLocation, - int portalCooldown, byte copyData + int portalCooldown, byte copyData, int seaLevel ) implements ServerPacket.Play { public static final int COPY_NONE = 0x0; public static final int COPY_ATTRIBUTES = 0x1; @@ -32,5 +32,6 @@ public record RespawnPacket( WorldPos.NETWORK_TYPE.optional(), RespawnPacket::deathLocation, VAR_INT, RespawnPacket::portalCooldown, BYTE, RespawnPacket::copyData, + VAR_INT, RespawnPacket::seaLevel, RespawnPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java index a35cd5c93..2f93a014d 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetCooldownPacket.java @@ -3,12 +3,14 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; +import static net.minestom.server.network.NetworkBuffer.STRING; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record SetCooldownPacket(int itemId, int cooldownTicks) implements ServerPacket.Play { +public record SetCooldownPacket(@NotNull String cooldownGroup, int cooldownTicks) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - VAR_INT, SetCooldownPacket::itemId, + STRING, SetCooldownPacket::cooldownGroup, VAR_INT, SetCooldownPacket::cooldownTicks, SetCooldownPacket::new); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetCursorItemPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetCursorItemPacket.java new file mode 100644 index 000000000..cf3dc82fa --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetCursorItemPacket.java @@ -0,0 +1,13 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.item.ItemStack; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +public record SetCursorItemPacket(@NotNull ItemStack itemStack) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + ItemStack.NETWORK_TYPE, SetCursorItemPacket::itemStack, + SetCursorItemPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetPlayerInventoryPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetPlayerInventoryPacket.java new file mode 100644 index 000000000..7111b2c8b --- /dev/null +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetPlayerInventoryPacket.java @@ -0,0 +1,16 @@ +package net.minestom.server.network.packet.server.play; + +import net.minestom.server.item.ItemStack; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; + +import static net.minestom.server.network.NetworkBuffer.VAR_INT; + +public record SetPlayerInventoryPacket(int slot, @NotNull ItemStack itemStack) implements ServerPacket.Play { + public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + VAR_INT, SetPlayerInventoryPacket::slot, + ItemStack.NETWORK_TYPE, SetPlayerInventoryPacket::itemStack, + SetPlayerInventoryPacket::new); +} diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java index 6bfd23af4..1e43e2df1 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java @@ -13,12 +13,13 @@ import java.util.Collection; import java.util.List; import java.util.function.UnaryOperator; -import static net.minestom.server.network.NetworkBuffer.*; +import static net.minestom.server.network.NetworkBuffer.SHORT; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record SetSlotPacket(byte windowId, int stateId, short slot, +public record SetSlotPacket(int windowId, int stateId, short slot, @NotNull ItemStack itemStack) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, SetSlotPacket::windowId, + VAR_INT, SetSlotPacket::windowId, VAR_INT, SetSlotPacket::stateId, SHORT, SetSlotPacket::slot, ItemStack.NETWORK_TYPE, SetSlotPacket::itemStack, 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 da23b5009..845b4c820 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 @@ -4,11 +4,13 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.LONG; -public record TimeUpdatePacket(long worldAge, long timeOfDay) implements ServerPacket.Play { +public record TimeUpdatePacket(long worldAge, long timeOfDay, boolean tickDayTime) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( LONG, TimeUpdatePacket::worldAge, LONG, TimeUpdatePacket::timeOfDay, + BOOLEAN, TimeUpdatePacket::tickDayTime, TimeUpdatePacket::new); } 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 deleted file mode 100644 index 6156d7b64..000000000 --- a/src/main/java/net/minestom/server/network/packet/server/play/UnlockRecipesPacket.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.minestom.server.network.packet.server.play; - -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.ServerPacket; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.List; - -import static net.minestom.server.network.NetworkBuffer.*; - -public record UnlockRecipesPacket(int mode, - boolean craftingRecipeBookOpen, boolean craftingRecipeBookFilterActive, - boolean smeltingRecipeBookOpen, boolean smeltingRecipeBookFilterActive, - boolean blastFurnaceRecipeBookOpen, boolean blastFurnaceRecipeBookFilterActive, - boolean smokerRecipeBookOpen, boolean smokerRecipeBookFilterActive, - @NotNull List recipeIds, - @UnknownNullability List initRecipeIds) implements ServerPacket.Play { - public UnlockRecipesPacket { - recipeIds = List.copyOf(recipeIds); - if (initRecipeIds != null) { - initRecipeIds = List.copyOf(initRecipeIds); - } - } - - public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, UnlockRecipesPacket value) { - buffer.write(VAR_INT, value.mode); - buffer.write(BOOLEAN, value.craftingRecipeBookOpen); - buffer.write(BOOLEAN, value.craftingRecipeBookFilterActive); - buffer.write(BOOLEAN, value.smeltingRecipeBookOpen); - buffer.write(BOOLEAN, value.smeltingRecipeBookFilterActive); - buffer.write(BOOLEAN, value.blastFurnaceRecipeBookOpen); - buffer.write(BOOLEAN, value.blastFurnaceRecipeBookFilterActive); - buffer.write(BOOLEAN, value.smokerRecipeBookOpen); - buffer.write(BOOLEAN, value.smokerRecipeBookFilterActive); - - buffer.write(STRING.list(), value.recipeIds); - if (value.mode == 0) { - buffer.write(STRING.list(), value.initRecipeIds); - } - } - - @Override - public UnlockRecipesPacket read(@NotNull NetworkBuffer buffer) { - var mode = buffer.read(VAR_INT); - var craftingRecipeBookOpen = buffer.read(BOOLEAN); - var craftingRecipeBookFilterActive = buffer.read(BOOLEAN); - var smeltingRecipeBookOpen = buffer.read(BOOLEAN); - var smeltingRecipeBookFilterActive = buffer.read(BOOLEAN); - var blastFurnaceRecipeBookOpen = buffer.read(BOOLEAN); - var blastFurnaceRecipeBookFilterActive = buffer.read(BOOLEAN); - var smokerRecipeBookOpen = buffer.read(BOOLEAN); - var smokerRecipeBookFilterActive = buffer.read(BOOLEAN); - var recipeIds = buffer.read(STRING.list(DeclareRecipesPacket.MAX_RECIPES)); - var initRecipeIds = mode == 0 ? buffer.read(STRING.list(DeclareRecipesPacket.MAX_RECIPES)) : null; - return new UnlockRecipesPacket(mode, - craftingRecipeBookOpen, craftingRecipeBookFilterActive, - smeltingRecipeBookOpen, smeltingRecipeBookFilterActive, - blastFurnaceRecipeBookOpen, blastFurnaceRecipeBookFilterActive, - smokerRecipeBookOpen, smokerRecipeBookFilterActive, - recipeIds, initRecipeIds); - } - }; -} 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 fcc73c8f0..233460491 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 @@ -13,15 +13,14 @@ import java.util.Collection; import java.util.List; import java.util.function.UnaryOperator; -import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record WindowItemsPacket(byte windowId, int stateId, @NotNull List items, +public record WindowItemsPacket(int windowId, int stateId, @NotNull List items, @NotNull ItemStack carriedItem) implements ServerPacket.Play, ServerPacket.ComponentHolding { public static final int MAX_ENTRIES = 128; public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, WindowItemsPacket::windowId, + VAR_INT, WindowItemsPacket::windowId, VAR_INT, WindowItemsPacket::stateId, ItemStack.NETWORK_TYPE.list(MAX_ENTRIES), WindowItemsPacket::items, ItemStack.NETWORK_TYPE, WindowItemsPacket::carriedItem, 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 f00485901..a95218bdb 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 @@ -4,12 +4,12 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; -import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.SHORT; +import static net.minestom.server.network.NetworkBuffer.VAR_INT; -public record WindowPropertyPacket(byte windowId, short property, short value) implements ServerPacket.Play { +public record WindowPropertyPacket(int windowId, short property, short value) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - BYTE, WindowPropertyPacket::windowId, + VAR_INT, WindowPropertyPacket::windowId, SHORT, WindowPropertyPacket::property, SHORT, WindowPropertyPacket::value, WindowPropertyPacket::new); diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index 196a79cf7..9a1b40a68 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -76,7 +76,7 @@ public class PacketWriteReadTest { SERVER_PACKETS.add(new ClearTitlesPacket(false)); SERVER_PACKETS.add(new CloseWindowPacket((byte) 2)); SERVER_PACKETS.add(new CollectItemPacket(5, 5, 5)); - SERVER_PACKETS.add(new CraftRecipeResponse((byte) 2, "recipe")); + SERVER_PACKETS.add(new PlaceGhostRecipePacket((byte) 2, "recipe")); SERVER_PACKETS.add(new DeathCombatEventPacket(5, COMPONENT)); SERVER_PACKETS.add(new DeclareRecipesPacket( List.of(new Recipe( From ce968a9b36e0c46ec5a2ddc7780cd38939834d84 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 8 Oct 2024 22:07:35 -0400 Subject: [PATCH 37/97] feat: particle changes --- .../net/minestom/server/color/AlphaColor.java | 5 + .../java/net/minestom/server/color/Color.java | 3 + .../minestom/server/particle/Particle.java | 178 +++++++++++------- .../server/particle/ParticleImpl.java | 9 +- .../server/utils/block/BlockUtils.java | 17 ++ .../server/utils/nbt/BinaryTagSerializer.java | 16 ++ 6 files changed, 160 insertions(+), 68 deletions(-) diff --git a/src/main/java/net/minestom/server/color/AlphaColor.java b/src/main/java/net/minestom/server/color/AlphaColor.java index e61a4684c..d0d68d071 100644 --- a/src/main/java/net/minestom/server/color/AlphaColor.java +++ b/src/main/java/net/minestom/server/color/AlphaColor.java @@ -3,6 +3,7 @@ package net.minestom.server.color; import net.kyori.adventure.util.RGBLike; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.MathUtils; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,10 @@ public final class AlphaColor extends Color { private static final int BIT_MASK = 0xff; public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.INT.transform(AlphaColor::new, AlphaColor::asARGB); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.INT.map(AlphaColor::new, AlphaColor::asARGB); + + public static final AlphaColor WHITE = new AlphaColor(255, 255, 255, 255); + private final int alpha; public AlphaColor(int alpha, int red, int green, int blue) { diff --git a/src/main/java/net/minestom/server/color/Color.java b/src/main/java/net/minestom/server/color/Color.java index 7f62c67c8..f6240e295 100644 --- a/src/main/java/net/minestom/server/color/Color.java +++ b/src/main/java/net/minestom/server/color/Color.java @@ -23,6 +23,9 @@ public class Color implements RGBLike { ); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.INT .map(Color::new, color -> Color.fromRGBLike(color).asRGB()); + + public static final RGBLike WHITE = new Color(255, 255, 255); + private final int red; private final int green; private final int blue; diff --git a/src/main/java/net/minestom/server/particle/Particle.java b/src/main/java/net/minestom/server/particle/Particle.java index 239651663..ed7ad3dda 100644 --- a/src/main/java/net/minestom/server/particle/Particle.java +++ b/src/main/java/net/minestom/server/particle/Particle.java @@ -1,9 +1,6 @@ package net.minestom.server.particle; -import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.kyori.adventure.nbt.FloatBinaryTag; -import net.kyori.adventure.nbt.ListBinaryTag; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.AlphaColor; import net.minestom.server.color.Color; @@ -12,6 +9,8 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.block.BlockUtils; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -21,10 +20,12 @@ import java.util.Collection; import java.util.Objects; import static net.minestom.server.network.NetworkBuffer.VAR_INT; +import static net.minestom.server.network.NetworkBuffer.VECTOR3D; public sealed interface Particle extends StaticProtocolObject, Particles permits Particle.Block, Particle.BlockMarker, Particle.Dust, Particle.DustColorTransition, Particle.DustPillar, Particle.EntityEffect, Particle.FallingDust, - Particle.Item, Particle.SculkCharge, Particle.Shriek, Particle.Simple, Particle.Vibration { + Particle.Item, Particle.SculkCharge, Particle.Shriek, Particle.Simple, Particle.Vibration, Particle.Trail, + Particle.BlockCrumble { @NotNull NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { @Override @@ -81,7 +82,8 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits } } - record Block(@NotNull NamespaceID namespace, int id, @NotNull net.minestom.server.instance.block.Block block) implements Particle { + record Block(@NotNull NamespaceID namespace, int id, + @NotNull net.minestom.server.instance.block.Block block) implements Particle { @Contract(pure = true) public @NotNull Block withBlock(@NotNull net.minestom.server.instance.block.Block block) { @@ -103,11 +105,15 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull CompoundBinaryTag toNbt() { - throw new UnsupportedOperationException("Block particle cannot be serialized to NBT"); + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .putString("block_state", BlockUtils.toString(block)) + .build(); } } - record BlockMarker(@NotNull NamespaceID namespace, int id, @NotNull net.minestom.server.instance.block.Block block) implements Particle { + record BlockMarker(@NotNull NamespaceID namespace, int id, + @NotNull net.minestom.server.instance.block.Block block) implements Particle { @Contract(pure = true) public @NotNull BlockMarker withBlock(@NotNull net.minestom.server.instance.block.Block block) { @@ -129,14 +135,17 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull CompoundBinaryTag toNbt() { - throw new UnsupportedOperationException("BlockMarker particle cannot be serialized to NBT"); + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .putString("block_state", BlockUtils.toString(block)) + .build(); } } record Dust(@NotNull NamespaceID namespace, int id, @NotNull RGBLike color, float scale) implements Particle { - @Contract (pure = true) + @Contract(pure = true) public @NotNull Dust withProperties(@NotNull RGBLike color, float scale) { return new Dust(namespace(), id(), color, scale); } @@ -153,40 +162,29 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull Dust readData(@NotNull NetworkBuffer reader) { - return this.withProperties(new Color( - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255) - ), reader.read(NetworkBuffer.FLOAT)); + return this.withProperties(reader.read(Color.NETWORK_TYPE), reader.read(NetworkBuffer.FLOAT)); } @Override public void writeData(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.FLOAT, color.red() / 255f); - writer.write(NetworkBuffer.FLOAT, color.green() / 255f); - writer.write(NetworkBuffer.FLOAT, color.blue() / 255f); + writer.write(Color.NETWORK_TYPE, color); writer.write(NetworkBuffer.FLOAT, scale); } @Override public @NotNull CompoundBinaryTag toNbt() { - ListBinaryTag colorTag = ListBinaryTag.builder(BinaryTagTypes.FLOAT) - .add(FloatBinaryTag.floatBinaryTag(color.red() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(color.green() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(color.blue() / 255f)) - .build(); - return CompoundBinaryTag.builder() .putString("type", namespace.asString()) - .put("color", colorTag) + .put("color", Color.NBT_TYPE.write(color)) .putFloat("scale", scale) .build(); } } - record DustColorTransition(@NotNull NamespaceID namespace, int id, @NotNull RGBLike color, @NotNull RGBLike transitionColor, float scale) implements Particle { + record DustColorTransition(@NotNull NamespaceID namespace, int id, @NotNull RGBLike color, + @NotNull RGBLike transitionColor, float scale) implements Particle { - @Contract (pure = true) + @Contract(pure = true) public @NotNull DustColorTransition withProperties(@NotNull RGBLike color, @NotNull RGBLike transitionColor, float scale) { return new DustColorTransition(namespace, id, color, transitionColor, scale); } @@ -208,52 +206,31 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull DustColorTransition readData(@NotNull NetworkBuffer reader) { - return this.withProperties(new Color( - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255) - ), new Color( - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255), - (int) (reader.read(NetworkBuffer.FLOAT) * 255) - ), reader.read(NetworkBuffer.FLOAT)); + return this.withProperties(reader.read(Color.NETWORK_TYPE), + reader.read(Color.NETWORK_TYPE), + reader.read(NetworkBuffer.FLOAT)); } @Override public void writeData(@NotNull NetworkBuffer writer) { - writer.write(NetworkBuffer.FLOAT, color.red() / 255f); - writer.write(NetworkBuffer.FLOAT, color.green() / 255f); - writer.write(NetworkBuffer.FLOAT, color.blue() / 255f); - writer.write(NetworkBuffer.FLOAT, transitionColor.red() / 255f); - writer.write(NetworkBuffer.FLOAT, transitionColor.green() / 255f); - writer.write(NetworkBuffer.FLOAT, transitionColor.blue() / 255f); + writer.write(Color.NETWORK_TYPE, color); + writer.write(Color.NETWORK_TYPE, transitionColor); writer.write(NetworkBuffer.FLOAT, scale); } @Override public @NotNull CompoundBinaryTag toNbt() { - ListBinaryTag fromColorTag = ListBinaryTag.builder(BinaryTagTypes.FLOAT) - .add(FloatBinaryTag.floatBinaryTag(color.red() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(color.green() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(color.blue() / 255f)) - .build(); - - ListBinaryTag toColorTag = ListBinaryTag.builder(BinaryTagTypes.FLOAT) - .add(FloatBinaryTag.floatBinaryTag(transitionColor.red() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(transitionColor.green() / 255f)) - .add(FloatBinaryTag.floatBinaryTag(transitionColor.blue() / 255f)) - .build(); - return CompoundBinaryTag.builder() .putString("type", namespace.asString()) .putFloat("scale", scale) - .put("from_color", fromColorTag) - .put("to_color", toColorTag) + .put("from_color", Color.NBT_TYPE.write(color)) + .put("to_color", Color.NBT_TYPE.write(transitionColor)) .build(); } } - record DustPillar(@NotNull NamespaceID namespace, int id, @NotNull net.minestom.server.instance.block.Block block) implements Particle { + record DustPillar(@NotNull NamespaceID namespace, int id, + @NotNull net.minestom.server.instance.block.Block block) implements Particle { @Contract(pure = true) public @NotNull DustPillar withBlock(@NotNull net.minestom.server.instance.block.Block block) { @@ -275,12 +252,16 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull CompoundBinaryTag toNbt() { - throw new UnsupportedOperationException("DustPillar particle cannot be serialized to NBT"); + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .putString("block_state", BlockUtils.toString(block)) + .build(); } } - record FallingDust(@NotNull NamespaceID namespace, int id, @NotNull net.minestom.server.instance.block.Block block) implements Particle { + record FallingDust(@NotNull NamespaceID namespace, int id, + @NotNull net.minestom.server.instance.block.Block block) implements Particle { @Contract(pure = true) public @NotNull FallingDust withBlock(@NotNull net.minestom.server.instance.block.Block block) { @@ -302,7 +283,10 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull CompoundBinaryTag toNbt() { - throw new UnsupportedOperationException("FallingDust particle cannot be serialized to NBT"); + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .putString("block_state", BlockUtils.toString(block)) + .build(); } } @@ -362,11 +346,9 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits @Override public @NotNull CompoundBinaryTag toNbt() { - int color = (0xFF << 24) | (color().red() << 16) | (color().green() << 8) | color().blue(); - return CompoundBinaryTag.builder() .putString("type", namespace.asString()) - .putInt("color", color) + .put("color", AlphaColor.NBT_TYPE.write(color)) .build(); } } @@ -424,11 +406,13 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits } } - record Vibration(@NotNull NamespaceID namespace, int id, @NotNull SourceType sourceType, @Nullable Point sourceBlockPosition, int sourceEntityId, float sourceEntityEyeHeight, int travelTicks) implements Particle { + record Vibration(@NotNull NamespaceID namespace, int id, @NotNull SourceType sourceType, + @Nullable Point sourceBlockPosition, int sourceEntityId, float sourceEntityEyeHeight, + int travelTicks) implements Particle { @Contract(pure = true) public @NotNull Vibration withProperties(@NotNull SourceType sourceType, @Nullable Point sourceBlockPosition, - int sourceEntityId, float sourceEntityEyeHeight, int travelTicks) { + int sourceEntityId, float sourceEntityEyeHeight, int travelTicks) { return new Vibration(namespace(), id(), sourceType, sourceBlockPosition, sourceEntityId, sourceEntityEyeHeight, travelTicks); } @@ -477,4 +461,70 @@ public sealed interface Particle extends StaticProtocolObject, Particles permits } } + record Trail(@NotNull NamespaceID namespace, int id, @NotNull Point target, @NotNull RGBLike color) implements Particle { + + public @NotNull Trail withProperties(@NotNull Point target, @NotNull RGBLike color) { + return new Trail(namespace(), id(), target, color); + } + + public @NotNull Trail withTarget(@NotNull Point target) { + return new Trail(namespace(), id(), target, color); + } + + public @NotNull Trail withColor(@NotNull RGBLike color) { + return new Trail(namespace(), id(), target, color); + } + + @Override + public @NotNull Trail readData(@NotNull NetworkBuffer reader) { + return this.withProperties(reader.read(VECTOR3D), reader.read(Color.NETWORK_TYPE)); + } + + @Override + public void writeData(@NotNull NetworkBuffer writer) { + writer.write(VECTOR3D, target); + writer.write(Color.NETWORK_TYPE, color); + } + + @Override + public @NotNull CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .put("target", BinaryTagSerializer.VECTOR3D.write(target)) + .put("color", Color.NBT_TYPE.write(color)) + .build(); + } + + } + + record BlockCrumble(@NotNull NamespaceID namespace, int id, + @NotNull net.minestom.server.instance.block.Block block) implements Particle { + + @Contract(pure = true) + public @NotNull Block withBlock(@NotNull net.minestom.server.instance.block.Block block) { + return new Block(namespace(), id(), block); + } + + @Override + public @NotNull Block readData(@NotNull NetworkBuffer reader) { + short blockState = reader.read(NetworkBuffer.VAR_INT).shortValue(); + var block = net.minestom.server.instance.block.Block.fromStateId(blockState); + Check.stateCondition(block == null, "Block state " + blockState + " is invalid"); + return this.withBlock(block); + } + + @Override + public void writeData(@NotNull NetworkBuffer writer) { + writer.write(NetworkBuffer.VAR_INT, block.stateId()); + } + + @Override + public @NotNull CompoundBinaryTag toNbt() { + return CompoundBinaryTag.builder() + .putString("type", namespace.asString()) + .putString("block_state", BlockUtils.toString(block)) + .build(); + } + } + } diff --git a/src/main/java/net/minestom/server/particle/ParticleImpl.java b/src/main/java/net/minestom/server/particle/ParticleImpl.java index 62e85aa32..bdc53cff9 100644 --- a/src/main/java/net/minestom/server/particle/ParticleImpl.java +++ b/src/main/java/net/minestom/server/particle/ParticleImpl.java @@ -37,14 +37,15 @@ final class ParticleImpl { case "minecraft:block_marker" -> new Particle.BlockMarker(namespace, id, Block.STONE); case "minecraft:falling_dust" -> new Particle.FallingDust(namespace, id, Block.STONE); case "minecraft:dust_pillar" -> new Particle.DustPillar(namespace, id, Block.STONE); - case "minecraft:dust" -> new Particle.Dust(namespace, id, new Color(255, 255, 255), 1); - case "minecraft:dust_color_transition" -> new Particle.DustColorTransition(namespace, id, new Color(255, 255, 255), - new Color(255, 255, 255), 1); + case "minecraft:dust" -> new Particle.Dust(namespace, id, Color.WHITE, 1); + case "minecraft:dust_color_transition" -> new Particle.DustColorTransition(namespace, id, Color.WHITE, Color.WHITE, 1); case "minecraft:sculk_charge" -> new Particle.SculkCharge(namespace, id, 0); case "minecraft:item" -> new Particle.Item(namespace, id, ItemStack.AIR); case "minecraft:vibration" -> new Particle.Vibration(namespace, id, Particle.Vibration.SourceType.BLOCK, Vec.ZERO, 0, 0, 0); case "minecraft:shriek" -> new Particle.Shriek(namespace, id, 0); - case "minecraft:entity_effect" -> new Particle.EntityEffect(namespace, id, new AlphaColor(255, 0, 0, 0)); + case "minecraft:entity_effect" -> new Particle.EntityEffect(namespace, id, AlphaColor.WHITE); + case "minecraft:trail" -> new Particle.Trail(namespace, id, Vec.ZERO, Color.WHITE); + case "minecraft:block_crumble" -> new Particle.BlockCrumble(namespace, id, Block.STONE); default -> new Particle.Simple(namespace, id); }; } diff --git a/src/main/java/net/minestom/server/utils/block/BlockUtils.java b/src/main/java/net/minestom/server/utils/block/BlockUtils.java index 36034d1e3..f9b297832 100644 --- a/src/main/java/net/minestom/server/utils/block/BlockUtils.java +++ b/src/main/java/net/minestom/server/utils/block/BlockUtils.java @@ -109,4 +109,21 @@ public class BlockUtils { // Necessary to support all vanilla blocks return blockNbt; } + + public static @NotNull String toString(@NotNull Block block) { + if (block.properties().isEmpty()) + return block.name(); + + var builder = new StringBuilder(block.name()); + builder.append('['); + for (var entry : block.properties().entrySet()) { + builder.append(entry.getKey()) + .append('=') + .append(entry.getValue()) + .append(','); + } + builder.deleteCharAt(builder.length() - 1); + builder.append(']'); + return builder.toString(); + } } diff --git a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java index d7f41f1dc..34b7d40f5 100644 --- a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java +++ b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java @@ -28,6 +28,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; +import static net.kyori.adventure.nbt.DoubleBinaryTag.doubleBinaryTag; import static net.kyori.adventure.nbt.StringBinaryTag.stringBinaryTag; /** @@ -264,6 +265,21 @@ public interface BinaryTagSerializer { } }; + BinaryTagSerializer VECTOR3D = new BinaryTagSerializer() { + @Override + public @NotNull BinaryTag write(@NotNull Point value) { + return ListBinaryTag.listBinaryTag(BinaryTagTypes.DOUBLE, List.of( + doubleBinaryTag(value.x()), doubleBinaryTag(value.y()), doubleBinaryTag(value.z()))); + } + + @Override + public @NotNull Point read(@NotNull BinaryTag tag) { + if (!(tag instanceof ListBinaryTag listTag && listTag.elementType() == BinaryTagTypes.DOUBLE)) + return Vec.ZERO; + return new Vec(listTag.getDouble(0), listTag.getDouble(1), listTag.getDouble(2)); + } + }; + static @NotNull BinaryTagSerializer> registryKey(@NotNull Function> registrySelector) { return new BinaryTagSerializer<>() { @Override From 86491c464cde76e7910e4ee30dd5c2dfe8da825e Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 8 Oct 2024 23:04:56 -0400 Subject: [PATCH 38/97] feat: most item component updates. biome crash on join :sob: --- .../java/net/minestom/demo/PlayerInit.java | 2 +- .../minestom/demo/entity/ChickenCreature.java | 2 +- .../minestom/server/entity/EntityType.java | 7 +- .../minestom/server/entity/EquipmentSlot.java | 5 + .../minestom/server/entity/LivingEntity.java | 10 +- .../net/minestom/server/entity/Player.java | 52 +++++---- .../followers/FlyingNodeFollower.java | 3 +- .../followers/GroundNodeFollower.java | 3 +- .../followers/NoPhysicsNodeFollower.java | 2 +- .../followers/WaterNodeFollower.java | 3 +- .../minestom/server/instance/Explosion.java | 10 +- .../minestom/server/instance/Instance.java | 8 +- .../minestom/server/item/ItemComponent.java | 27 ++++- .../server/item/component/Consumable.java | 48 ++++++++ .../server/item/component/ConsumeEffect.java | 13 +++ .../item/component/DeathProtection.java | 17 +++ .../server/item/component/Equippable.java | 42 +++++++ .../server/item/component/UseCooldown.java | 17 +++ .../server/item/enchant/Enchantment.java | 5 +- .../listener/PlayerPositionListener.java | 4 +- .../listener/PlayerVehicleListener.java | 3 +- .../server/network/ConnectionManager.java | 2 +- .../server/network/player/ClientSettings.java | 16 ++- .../net/minestom/server/recipe/Recipe.java | 8 -- .../server/recipe/RecipeSerializers.java | 15 +-- .../net/minestom/server/sound/SoundEvent.java | 32 ++++++ .../server/utils/entity/EntityUtils.java | 5 +- .../server/utils/nbt/BinaryTagSerializer.java | 103 +++++++++++++++++- 28 files changed, 384 insertions(+), 80 deletions(-) create mode 100644 src/main/java/net/minestom/server/item/component/Consumable.java create mode 100644 src/main/java/net/minestom/server/item/component/ConsumeEffect.java create mode 100644 src/main/java/net/minestom/server/item/component/DeathProtection.java create mode 100644 src/main/java/net/minestom/server/item/component/Equippable.java create mode 100644 src/main/java/net/minestom/server/item/component/UseCooldown.java diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index f012a5b72..12ca626c7 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -106,7 +106,7 @@ public class PlayerInit { final Player player = event.getPlayer(); // Show off adding and removing feature flags - event.addFeatureFlag(FeatureFlag.BUNDLE); + event.addFeatureFlag(FeatureFlag.WINTER_DROP); event.removeFeatureFlag(FeatureFlag.TRADE_REBALANCE); // not enabled by default, just removed for demonstration var instances = MinecraftServer.getInstanceManager().getInstances(); diff --git a/demo/src/main/java/net/minestom/demo/entity/ChickenCreature.java b/demo/src/main/java/net/minestom/demo/entity/ChickenCreature.java index 14ea776f0..1dd300a23 100644 --- a/demo/src/main/java/net/minestom/demo/entity/ChickenCreature.java +++ b/demo/src/main/java/net/minestom/demo/entity/ChickenCreature.java @@ -35,7 +35,7 @@ public class ChickenCreature extends EntityCreature { // .build() // ); - getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.1); + getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.1); } @Override diff --git a/src/main/java/net/minestom/server/entity/EntityType.java b/src/main/java/net/minestom/server/entity/EntityType.java index fef2e66db..e0e902a0e 100644 --- a/src/main/java/net/minestom/server/entity/EntityType.java +++ b/src/main/java/net/minestom/server/entity/EntityType.java @@ -1,8 +1,10 @@ package net.minestom.server.entity; -import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.Registry; +import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,6 +12,9 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; public sealed interface EntityType extends StaticProtocolObject, EntityTypes permits EntityTypeImpl { + NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.VAR_INT.transform(EntityType::fromId, EntityType::id); + BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.INT.map(EntityType::fromId, EntityType::id); + /** * Returns the entity registry. * diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index 2fe93f3eb..0651c2161 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -1,5 +1,7 @@ package net.minestom.server.entity; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -17,6 +19,9 @@ public enum EquipmentSlot { private static final List ARMORS = List.of(BOOTS, LEGGINGS, CHESTPLATE, HELMET); + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(EquipmentSlot.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(EquipmentSlot.class); + private final boolean armor; private final int armorSlot; diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index f5b5d7ac1..65c1d887b 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -111,7 +111,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { // We must set the sprinting attribute serverside because when we resend modifiers it overwrites what // the client has, meaning if they are sprinting and we send no modifiers, they will no longer be // getting the speed boost of sprinting. - final AttributeInstance speed = getAttribute(Attribute.GENERIC_MOVEMENT_SPEED); + final AttributeInstance speed = getAttribute(Attribute.MOVEMENT_SPEED); if (sprinting) speed.addModifier(SPRINTING_SPEED_MODIFIER); else speed.removeModifier(SPRINTING_SPEED_MODIFIER); } @@ -402,7 +402,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { * @param health the new entity health */ public void setHealth(float health) { - this.health = Math.min(health, (float) getAttributeValue(Attribute.GENERIC_MAX_HEALTH)); + this.health = Math.min(health, (float) getAttributeValue(Attribute.MAX_HEALTH)); if (this.health <= 0 && !isDead) { kill(); } @@ -424,10 +424,10 @@ public class LivingEntity extends Entity implements EquipmentHandler { /** * Sets the heal of the entity as its max health. *

- * Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attribute#GENERIC_MAX_HEALTH}. + * Retrieved from {@link #getAttributeValue(Attribute)} with the attribute {@link Attribute#MAX_HEALTH}. */ public void heal() { - setHealth((float) getAttributeValue(Attribute.GENERIC_MAX_HEALTH)); + setHealth((float) getAttributeValue(Attribute.MAX_HEALTH)); } /** @@ -698,7 +698,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { */ @Override public void takeKnockback(float strength, final double x, final double z) { - strength *= (float) (1 - getAttributeValue(Attribute.GENERIC_KNOCKBACK_RESISTANCE)); + strength *= (float) (1 - getAttributeValue(Attribute.KNOCKBACK_RESISTANCE)); super.takeKnockback(strength, x, z); } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index f0f9697da..0607a0772 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -120,6 +120,9 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou private static final Component REMOVE_MESSAGE = Component.text("You have been removed from the server without reason.", NamedTextColor.RED); private static final Component MISSING_REQUIRED_RESOURCE_PACK = Component.text("Required resource pack was not loaded.", NamedTextColor.RED); + // TODO(1.21.2): Should this be configurable? What does it actually do? + private static final int DEFAULT_SEA_LEVEL = 63; + private long lastKeepAlive; private boolean answerKeepAlive; @@ -244,7 +247,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou this.gameMode = GameMode.SURVIVAL; this.dimensionTypeId = DIMENSION_TYPE_REGISTRY.getId(DimensionType.OVERWORLD); // Default dimension this.levelFlat = true; - getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.1); + getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.1); // FakePlayer init its connection there playerConnectionInit(); @@ -286,8 +289,11 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou final JoinGamePacket joinGamePacket = new JoinGamePacket( getEntityId(), this.hardcore, List.of(), 0, ServerFlag.CHUNK_VIEW_DISTANCE, ServerFlag.CHUNK_VIEW_DISTANCE, - false, true, false, dimensionTypeId, spawnInstance.getDimensionName(), - 0, gameMode, null, false, levelFlat, deathLocation, portalCooldown, true); + false, true, false, + dimensionTypeId, spawnInstance.getDimensionName(), 0, + gameMode, null, false, levelFlat, + deathLocation, portalCooldown, DEFAULT_SEA_LEVEL, + true); sendPacket(joinGamePacket); // Difficulty @@ -341,13 +347,14 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou recipesIdentifier.add(recipe.id()); } if (!recipesIdentifier.isEmpty()) { - UnlockRecipesPacket unlockRecipesPacket = new UnlockRecipesPacket(0, - false, false, - false, false, - false, false, - false, false, - recipesIdentifier, recipesIdentifier); - sendPacket(unlockRecipesPacket); + // TODO(1.21.2): Recipes +// UnlockRecipesPacket unlockRecipesPacket = new UnlockRecipesPacket(0, +// false, false, +// false, false, +// false, false, +// false, false, +// recipesIdentifier, recipesIdentifier); +// sendPacket(unlockRecipesPacket); } } // Recipes end @@ -503,8 +510,10 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou entityMeta.setOnFire(false); refreshHealth(); - sendPacket(new RespawnPacket(dimensionTypeId, instance.getDimensionName(), 0, gameMode, gameMode, - false, levelFlat, deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL)); + sendPacket(new RespawnPacket(dimensionTypeId, instance.getDimensionName(), + 0, gameMode, gameMode, false, levelFlat, + deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL, + DEFAULT_SEA_LEVEL)); refreshClientStateAfterRespawn(); PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(this); @@ -726,7 +735,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou if (dimensionChange) { sendPacket(new SpawnPositionPacket(spawnPosition, 0)); sendPacket(instance.createInitializeWorldBorderPacket()); - sendPacket(new TimeUpdatePacket(instance.getWorldAge(), instance.getTime())); + sendPacket(instance.createTimePacket()); } if (dimensionChange || firstSpawn) { @@ -1186,8 +1195,10 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou final PlayerInfoRemovePacket removePlayerPacket = getRemovePlayerToList(); final PlayerInfoUpdatePacket addPlayerPacket = getAddPlayerToList(); - RespawnPacket respawnPacket = new RespawnPacket(dimensionTypeId, instance.getDimensionName(), - 0, gameMode, gameMode, false, levelFlat, deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL); + final RespawnPacket respawnPacket = new RespawnPacket(dimensionTypeId, + instance.getDimensionName(), 0, gameMode, gameMode, + false, levelFlat, deathLocation, portalCooldown, + (byte) RespawnPacket.COPY_ALL, DEFAULT_SEA_LEVEL); sendPacket(removePlayerPacket); sendPacket(destroyEntitiesPacket); @@ -1650,7 +1661,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou this.dimensionTypeId = DIMENSION_TYPE_REGISTRY.getId(dimensionType); sendPacket(new RespawnPacket(dimensionTypeId, dimensionName, 0, gameMode, gameMode, false, levelFlat, - deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL)); + deathLocation, portalCooldown, (byte) RespawnPacket.COPY_ALL, + DEFAULT_SEA_LEVEL)); refreshClientStateAfterRespawn(); } @@ -1833,7 +1845,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou @ApiStatus.Internal void synchronizePositionAfterTeleport(@NotNull Pos position, int relativeFlags, boolean shouldConfirm) { int teleportId = shouldConfirm ? getNextTeleportId() : -1; - sendPacket(new PlayerPositionAndLookPacket(position, (byte) relativeFlags, teleportId)); + // TODO(1.21.2): Fix/reenable this +// sendPacket(new PlayerPositionAndLookPacket(position, (byte) relativeFlags, teleportId)); super.synchronizePosition(); } @@ -2240,7 +2253,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou List.of(new PlayerInfoUpdatePacket.Property("textures", skin.textures(), skin.signature())) : List.of(); return new PlayerInfoUpdatePacket.Entry(getUuid(), getUsername(), prop, - true, getLatency(), getGameMode(), displayName, null); + true, getLatency(), getGameMode(), displayName, null, 0); } /** @@ -2292,7 +2305,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou final ClientSettings settings = this.settings; refreshSettings(new ClientSettings( locale, settings.viewDistance(), settings.chatMessageType(), settings.chatColors(), - settings.displayedSkinParts(), settings.mainHand(), settings.enableTextFiltering(), settings.allowServerListings() + settings.displayedSkinParts(), settings.mainHand(), settings.enableTextFiltering(), + settings.allowServerListings(), settings.particleStatus() )); } diff --git a/src/main/java/net/minestom/server/entity/pathfinding/followers/FlyingNodeFollower.java b/src/main/java/net/minestom/server/entity/pathfinding/followers/FlyingNodeFollower.java index 575054524..5d5e2c504 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/followers/FlyingNodeFollower.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/followers/FlyingNodeFollower.java @@ -1,7 +1,6 @@ package net.minestom.server.entity.pathfinding.followers; import net.minestom.server.collision.CollisionUtils; -import net.minestom.server.collision.PhysicsResult; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -70,7 +69,7 @@ public class FlyingNodeFollower implements NodeFollower { @Override public double movementSpeed() { if (entity instanceof LivingEntity living) { - return living.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue(); + return living.getAttribute(Attribute.MOVEMENT_SPEED).getValue(); } return 0.1f; diff --git a/src/main/java/net/minestom/server/entity/pathfinding/followers/GroundNodeFollower.java b/src/main/java/net/minestom/server/entity/pathfinding/followers/GroundNodeFollower.java index d20118a3a..ddd7b14cf 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/followers/GroundNodeFollower.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/followers/GroundNodeFollower.java @@ -1,7 +1,6 @@ package net.minestom.server.entity.pathfinding.followers; import net.minestom.server.collision.CollisionUtils; -import net.minestom.server.collision.PhysicsResult; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -72,7 +71,7 @@ public class GroundNodeFollower implements NodeFollower { @Override public double movementSpeed() { if (entity instanceof LivingEntity living) { - return living.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue(); + return living.getAttribute(Attribute.MOVEMENT_SPEED).getValue(); } return 0.1f; diff --git a/src/main/java/net/minestom/server/entity/pathfinding/followers/NoPhysicsNodeFollower.java b/src/main/java/net/minestom/server/entity/pathfinding/followers/NoPhysicsNodeFollower.java index 6e24f1fa3..0106d4c83 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/followers/NoPhysicsNodeFollower.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/followers/NoPhysicsNodeFollower.java @@ -72,7 +72,7 @@ public class NoPhysicsNodeFollower implements NodeFollower { @Override public double movementSpeed() { if (entity instanceof LivingEntity living) { - return living.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue(); + return living.getAttribute(Attribute.MOVEMENT_SPEED).getValue(); } return 0.1f; diff --git a/src/main/java/net/minestom/server/entity/pathfinding/followers/WaterNodeFollower.java b/src/main/java/net/minestom/server/entity/pathfinding/followers/WaterNodeFollower.java index ee1a42763..72868acf8 100644 --- a/src/main/java/net/minestom/server/entity/pathfinding/followers/WaterNodeFollower.java +++ b/src/main/java/net/minestom/server/entity/pathfinding/followers/WaterNodeFollower.java @@ -1,7 +1,6 @@ package net.minestom.server.entity.pathfinding.followers; import net.minestom.server.collision.CollisionUtils; -import net.minestom.server.collision.PhysicsResult; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -77,7 +76,7 @@ public class WaterNodeFollower implements NodeFollower { @Override public double movementSpeed() { if (entity instanceof LivingEntity living) { - return living.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue(); + return living.getAttribute(Attribute.MOVEMENT_SPEED).getValue(); } return 0.1f; diff --git a/src/main/java/net/minestom/server/instance/Explosion.java b/src/main/java/net/minestom/server/instance/Explosion.java index 20dc8abd7..5a8b58b28 100644 --- a/src/main/java/net/minestom/server/instance/Explosion.java +++ b/src/main/java/net/minestom/server/instance/Explosion.java @@ -3,7 +3,6 @@ package net.minestom.server.instance; import net.minestom.server.coordinate.Point; import net.minestom.server.instance.block.Block; import net.minestom.server.network.packet.server.play.ExplosionPacket; -import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -70,10 +69,11 @@ public abstract class Explosion { } // TODO send only to close players - ExplosionPacket packet = new ExplosionPacket(centerX, centerY, centerZ, strength, - records, 0, 0, 0); - postExplosion(instance, blocks, packet); - PacketSendingUtils.sendGroupedPacket(instance.getPlayers(), packet); + // TODO(1.21.2) simplified packet +// ExplosionPacket packet = new ExplosionPacket(centerX, centerY, centerZ, strength, +// records, 0, 0, 0); +// postExplosion(instance, blocks, packet); +// PacketSendingUtils.sendGroupedPacket(instance.getPlayers(), packet); postSend(instance, blocks); } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 47215b350..f1c1cae2c 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -528,13 +528,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, */ @ApiStatus.Internal public @NotNull TimeUpdatePacket createTimePacket() { - long time = this.time; - if (timeRate == 0) { - //Negative values stop the sun and moon from moving - //0 as a long cannot be negative - time = time == 0 ? -24000L : -Math.abs(time); - } - return new TimeUpdatePacket(worldAge, time); + return new TimeUpdatePacket(worldAge, time, timeRate != 0); } /** diff --git a/src/main/java/net/minestom/server/item/ItemComponent.java b/src/main/java/net/minestom/server/item/ItemComponent.java index 4c66c448d..7825f6620 100644 --- a/src/main/java/net/minestom/server/item/ItemComponent.java +++ b/src/main/java/net/minestom/server/item/ItemComponent.java @@ -1,5 +1,7 @@ package net.minestom.server.item; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.Color; @@ -34,6 +36,7 @@ public final class ItemComponent { public static final DataComponent UNBREAKABLE = register("unbreakable", Unbreakable.NETWORK_TYPE, Unbreakable.NBT_TYPE); public static final DataComponent CUSTOM_NAME = register("custom_name", NetworkBuffer.COMPONENT, BinaryTagSerializer.JSON_COMPONENT); public static final DataComponent ITEM_NAME = register("item_name", NetworkBuffer.COMPONENT, BinaryTagSerializer.JSON_COMPONENT); + public static final DataComponent ITEM_MODEL = register("item_model", NetworkBuffer.STRING, BinaryTagSerializer.STRING); public static final DataComponent> LORE = register("lore", NetworkBuffer.COMPONENT.list(256), BinaryTagSerializer.JSON_COMPONENT.list()); public static final DataComponent RARITY = register("rarity", ItemRarity.NETWORK_TYPE, ItemRarity.NBT_TYPE); public static final DataComponent ENCHANTMENTS = register("enchantments", EnchantmentList.NETWORK_TYPE, EnchantmentList.NBT_TYPE); @@ -48,8 +51,30 @@ public final class ItemComponent { public static final DataComponent ENCHANTMENT_GLINT_OVERRIDE = register("enchantment_glint_override", NetworkBuffer.BOOLEAN, BinaryTagSerializer.BOOLEAN); public static final DataComponent INTANGIBLE_PROJECTILE = register("intangible_projectile", null, BinaryTagSerializer.UNIT); public static final DataComponent FOOD = register("food", Food.NETWORK_TYPE, Food.NBT_TYPE); - public static final DataComponent FIRE_RESISTANT = register("fire_resistant", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT); + public static final DataComponent CONSUMABLE = register("consumable", Consumable.NETWORK_TYPE, Consumable.NBT_TYPE); + public static final DataComponent USE_REMAINDER = register("use_remainder", ItemStack.NETWORK_TYPE, BinaryTagSerializer.ITEM); + public static final DataComponent USE_COOLDOWN = register("use_cooldown", UseCooldown.NETWORK_TYPE, UseCooldown.NBT_TYPE); + public static final DataComponent DAMAGE_RESISTANT = register("damage_resistant", NetworkBuffer.STRING, new BinaryTagSerializer() { + // TODO(1.21.2): This is a key to a game tag in the DamageType registry. We should probably have some fancier type to represent this. + // Also this serializer should not be inlined here. + + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull String value) { + return CompoundBinaryTag.builder().putString("value", value).build(); + } + + @Override + public @NotNull String read(@NotNull Context context, @NotNull BinaryTag tag) { + return ((CompoundBinaryTag) tag).getString("value"); + } + }); public static final DataComponent TOOL = register("tool", Tool.NETWORK_TYPE, Tool.NBT_TYPE); + public static final DataComponent ENCHANTABLE = register("enchantable", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT); + public static final DataComponent EQUIPPABLE = register("equippable", Equippable.NETWORK_TYPE, Equippable.NBT_TYPE); + public static final DataComponent> REPAIRABLE = register("repairable", Material.NETWORK_TYPE.list(Short.MAX_VALUE), Material.NBT_TYPE.list()); + public static final DataComponent GLIDER = register("glider", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT); + public static final DataComponent TOOLTIP_STYLE = register("tooltip_style", NetworkBuffer.STRING, BinaryTagSerializer.STRING); + public static final DataComponent DEATH_PROTECTION = register("death_protection", DeathProtection.NETWORK_TYPE, DeathProtection.NBT_TYPE); public static final DataComponent STORED_ENCHANTMENTS = register("stored_enchantments", EnchantmentList.NETWORK_TYPE, EnchantmentList.NBT_TYPE); public static final DataComponent DYED_COLOR = register("dyed_color", DyedItemColor.NETWORK_TYPE, DyedItemColor.NBT_TYPE); public static final DataComponent MAP_COLOR = register("map_color", Color.NETWORK_TYPE, Color.NBT_TYPE); diff --git a/src/main/java/net/minestom/server/item/component/Consumable.java b/src/main/java/net/minestom/server/item/component/Consumable.java new file mode 100644 index 000000000..ce446973f --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/Consumable.java @@ -0,0 +1,48 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public record Consumable( + float consumeSeconds, + @NotNull Animation animation, + @NotNull SoundEvent sound, + boolean hasParticles, + @NotNull List effects +) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.FLOAT, Consumable::consumeSeconds, + Animation.NETWORK_TYPE, Consumable::animation, + SoundEvent.NETWORK_TYPE, Consumable::sound, + NetworkBuffer.BOOLEAN, Consumable::hasParticles, + ConsumeEffect.NETWORK_TYPE.list(Short.MAX_VALUE), Consumable::effects, + Consumable::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + "consume_seconds", BinaryTagSerializer.FLOAT, Consumable::consumeSeconds, + "animation", Animation.NBT_TYPE, Consumable::animation, + "sound", SoundEvent.NBT_TYPE, Consumable::sound, + "has_particles", BinaryTagSerializer.BOOLEAN, Consumable::hasParticles, + "effects", ConsumeEffect.NBT_TYPE.list(), Consumable::effects, + Consumable::new); + + public enum Animation { + NONE, + EAT, + DRINK, + BLOCK, + BOW, + SPEAR, + CROSSBOW, + SPYGLASS, + TOOT_HORN, + BRUSH; + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(Animation.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(Animation.class); + } +} diff --git a/src/main/java/net/minestom/server/item/component/ConsumeEffect.java b/src/main/java/net/minestom/server/item/component/ConsumeEffect.java new file mode 100644 index 000000000..2d2041941 --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/ConsumeEffect.java @@ -0,0 +1,13 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.nbt.BinaryTagSerializer; + +public record ConsumeEffect() { + // TODO(1.21.2): APPLY_EFFECTS, REMOVE_EFFECTS, CLEAR_ALL_EFFECTS, TELEPORT_RANDOMLY, PLAY_SOUND + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + ConsumeEffect::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.UNIT + .map(ignored -> new ConsumeEffect(), effect -> null); +} diff --git a/src/main/java/net/minestom/server/item/component/DeathProtection.java b/src/main/java/net/minestom/server/item/component/DeathProtection.java new file mode 100644 index 000000000..7a6949590 --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/DeathProtection.java @@ -0,0 +1,17 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public record DeathProtection(@NotNull List deathEffects) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + ConsumeEffect.NETWORK_TYPE.list(1024), DeathProtection::deathEffects, + DeathProtection::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + "death_effects", ConsumeEffect.NBT_TYPE.list(), DeathProtection::deathEffects, + DeathProtection::new); +} diff --git a/src/main/java/net/minestom/server/item/component/Equippable.java b/src/main/java/net/minestom/server/item/component/Equippable.java new file mode 100644 index 000000000..b7a5026ce --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/Equippable.java @@ -0,0 +1,42 @@ +package net.minestom.server.item.component; + +import net.minestom.server.entity.EquipmentSlot; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public record Equippable( + @NotNull EquipmentSlot slot, + @NotNull SoundEvent equipSound, + @Nullable String model, + @Nullable String cameraOverlay, +// @Nullable List allowedEntities, // TODO(1.21.2): this is an ObjectSet + boolean dispensable, + boolean swappable, + boolean damageOnHurt + ) { + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + EquipmentSlot.NETWORK_TYPE, Equippable::slot, + SoundEvent.NETWORK_TYPE, Equippable::equipSound, + NetworkBuffer.STRING.optional(), Equippable::model, + NetworkBuffer.STRING.optional(), Equippable::cameraOverlay, +// STRING.list().optional(), Equippable::allowedEntities, + NetworkBuffer.BOOLEAN, Equippable::dispensable, + NetworkBuffer.BOOLEAN, Equippable::swappable, + NetworkBuffer.BOOLEAN, Equippable::damageOnHurt, + Equippable::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + "slot", EquipmentSlot.NBT_TYPE, Equippable::slot, + "equip_sound", SoundEvent.NBT_TYPE, Equippable::equipSound, + "model", BinaryTagSerializer.STRING.optional(), Equippable::model, + "camera_overlay", BinaryTagSerializer.STRING.optional(), Equippable::cameraOverlay, +// "allowed_entities", STRING.list().optional(), Equippable::allowedEntities, + "dispensable", BinaryTagSerializer.BOOLEAN, Equippable::dispensable, + "swappable", BinaryTagSerializer.BOOLEAN, Equippable::swappable, + "damage_on_hurt", BinaryTagSerializer.BOOLEAN, Equippable::damageOnHurt, + Equippable::new); +} diff --git a/src/main/java/net/minestom/server/item/component/UseCooldown.java b/src/main/java/net/minestom/server/item/component/UseCooldown.java new file mode 100644 index 000000000..3edd09b34 --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/UseCooldown.java @@ -0,0 +1,17 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.Nullable; + +public record UseCooldown(float seconds, @Nullable String cooldownGroup) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.FLOAT, UseCooldown::seconds, + NetworkBuffer.STRING.optional(), UseCooldown::cooldownGroup, + UseCooldown::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + "seconds", BinaryTagSerializer.FLOAT, UseCooldown::seconds, + "cooldown_group", BinaryTagSerializer.STRING.optional(), UseCooldown::cooldownGroup, + UseCooldown::new); +} diff --git a/src/main/java/net/minestom/server/item/enchant/Enchantment.java b/src/main/java/net/minestom/server/item/enchant/Enchantment.java index 91b345b06..a01ac1677 100644 --- a/src/main/java/net/minestom/server/item/enchant/Enchantment.java +++ b/src/main/java/net/minestom/server/item/enchant/Enchantment.java @@ -31,8 +31,9 @@ public sealed interface Enchantment extends ProtocolObject, Enchantments permits @ApiStatus.Internal static @NotNull DynamicRegistry createDefaultRegistry(@NotNull Registries registries) { return DynamicRegistry.create( - "minecraft:enchantment", EnchantmentImpl.REGISTRY_NBT_TYPE, - registries, Registry.Resource.ENCHANTMENTS + // TODO(1.21.2) new enchantment types + "minecraft:enchantment", EnchantmentImpl.REGISTRY_NBT_TYPE//, + //registries, Registry.Resource.ENCHANTMENTS ); } diff --git a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java index 9c3e2bfc7..44e6d2b95 100644 --- a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java @@ -7,7 +7,6 @@ import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.instance.Instance; import net.minestom.server.network.packet.client.play.*; -import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; @@ -73,7 +72,8 @@ public class PlayerPositionListener { } if (playerMoveEvent.isCancelled()) { // Teleport to previous position - player.sendPacket(new PlayerPositionAndLookPacket(currentPosition, (byte) 0x00, player.getNextTeleportId())); + // TODO(1.21.2) +// player.sendPacket(new PlayerPositionAndLookPacket(currentPosition, (byte) 0x00, player.getNextTeleportId())); return; } final Pos eventPosition = playerMoveEvent.getNewPosition(); diff --git a/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java b/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java index 090744a22..2dd35abf3 100644 --- a/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java @@ -13,7 +13,8 @@ public class PlayerVehicleListener { final byte flags = packet.flags(); final boolean jump = (flags & 0x1) != 0; final boolean unmount = (flags & 0x2) != 0; - player.refreshVehicleSteer(packet.sideways(), packet.forward(), jump, unmount); + // TODO(1.21.2) +// player.refreshVehicleSteer(packet.sideways(), packet.forward(), jump, unmount); } public static void vehicleMoveListener(ClientVehicleMovePacket packet, Player player) { diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index e2b96ad15..624ece2ce 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -202,7 +202,7 @@ public final class ConnectionManager { throw new RuntimeException("Error getting replies for login plugin messages", t); } // Send login success packet (and switch to configuration phase) - connection.sendPacket(new LoginSuccessPacket(gameProfile, true)); + connection.sendPacket(new LoginSuccessPacket(gameProfile)); return gameProfile; } diff --git a/src/main/java/net/minestom/server/network/player/ClientSettings.java b/src/main/java/net/minestom/server/network/player/ClientSettings.java index e65137da1..cd12d6041 100644 --- a/src/main/java/net/minestom/server/network/player/ClientSettings.java +++ b/src/main/java/net/minestom/server/network/player/ClientSettings.java @@ -5,6 +5,7 @@ import net.minestom.server.message.ChatMessageType; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.MathUtils; +import org.jetbrains.annotations.NotNull; import java.util.Locale; import java.util.Objects; @@ -14,12 +15,14 @@ import static net.minestom.server.network.NetworkBuffer.*; public record ClientSettings(Locale locale, byte viewDistance, ChatMessageType chatMessageType, boolean chatColors, byte displayedSkinParts, MainHand mainHand, - boolean enableTextFiltering, boolean allowServerListings) { + boolean enableTextFiltering, boolean allowServerListings, + @NotNull ParticleStatus particleStatus) { public static ClientSettings DEFAULT = new ClientSettings( Locale.US, (byte) ServerFlag.CHUNK_VIEW_DISTANCE, ChatMessageType.FULL, true, (byte) 0x7F, MainHand.RIGHT, - true, true + true, true, + ParticleStatus.ALL ); private static final NetworkBuffer.Type LOCALE_SERIALIZER = STRING.transform( @@ -39,6 +42,7 @@ public record ClientSettings(Locale locale, byte viewDistance, Enum(MainHand.class), ClientSettings::mainHand, BOOLEAN, ClientSettings::enableTextFiltering, BOOLEAN, ClientSettings::allowServerListings, + ParticleStatus.NETWORK_TYPE, ClientSettings::particleStatus, ClientSettings::new); public ClientSettings { @@ -60,4 +64,12 @@ public record ClientSettings(Locale locale, byte viewDistance, LEFT, RIGHT } + + public enum ParticleStatus { + ALL, + DECREASED, + MINIMAL; + + public static final NetworkBuffer.Type NETWORK_TYPE = Enum(ParticleStatus.class); + } } diff --git a/src/main/java/net/minestom/server/recipe/Recipe.java b/src/main/java/net/minestom/server/recipe/Recipe.java index c751acf4a..bbc526d94 100644 --- a/src/main/java/net/minestom/server/recipe/Recipe.java +++ b/src/main/java/net/minestom/server/recipe/Recipe.java @@ -124,14 +124,6 @@ public record Recipe(@NotNull String id, @NotNull Data data) { public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SHIELD_DECORATION; } - public record SpecialShulkerBoxColoring(RecipeCategory.Crafting category) implements Data { - public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SPECIAL_SHULKER_BOX_COLORING; - } - - public record SpecialSuspiciousStew(RecipeCategory.Crafting category) implements Data { - public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SUSPICIOUS_STEW; - } - public record SpecialRepairItem(RecipeCategory.Crafting category) implements Data { public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.REPAIR_ITEM; } diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java index a4945b995..82d28d6f3 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -184,14 +184,6 @@ public final class RecipeSerializers { Enum(Crafting.class), SpecialShieldDecoration::category, SpecialShieldDecoration::new ); - public static final Type SPECIAL_SHULKER_BOX_COLORING = NetworkBufferTemplate.template( - Enum(Crafting.class), SpecialShulkerBoxColoring::category, SpecialShulkerBoxColoring::new - ); - - public static final Type SUSPICIOUS_STEW = NetworkBufferTemplate.template( - Enum(Crafting.class), SpecialSuspiciousStew::category, SpecialSuspiciousStew::new - ); - public static final Type REPAIR_ITEM = NetworkBufferTemplate.template( Enum(Crafting.class), SpecialRepairItem::category, SpecialRepairItem::new ); @@ -216,8 +208,9 @@ public final class RecipeSerializers { case SPECIAL_TIPPEDARROW -> TIPPED_ARROW; case SPECIAL_BANNERDUPLICATE -> BANNER_DUPLICATE; case SPECIAL_SHIELDDECORATION -> SHIELD_DECORATION; - case SPECIAL_SHULKERBOXCOLORING -> SPECIAL_SHULKER_BOX_COLORING; - case SPECIAL_SUSPICIOUSSTEW -> SUSPICIOUS_STEW; +// case SPECIAL_SHULKERBOXCOLORING -> SPECIAL_SHULKER_BOX_COLORING; +// case SPECIAL_SUSPICIOUSSTEW -> SUSPICIOUS_STEW; + case TRANSMUTE -> null; // TODO(1.21.2) case SPECIAL_REPAIRITEM -> REPAIR_ITEM; case SMELTING -> SMELTING; case BLASTING -> BLASTING; @@ -252,8 +245,6 @@ public final class RecipeSerializers { case SpecialMapExtending ignored -> RecipeType.SPECIAL_MAPEXTENDING; case SpecialRepairItem ignored -> RecipeType.SPECIAL_REPAIRITEM; case SpecialShieldDecoration ignored -> RecipeType.SPECIAL_SHIELDDECORATION; - case SpecialShulkerBoxColoring ignored -> RecipeType.SPECIAL_SHULKERBOXCOLORING; - case SpecialSuspiciousStew ignored -> RecipeType.SPECIAL_SUSPICIOUSSTEW; case SpecialTippedArrow ignored -> RecipeType.SPECIAL_TIPPEDARROW; }; } diff --git a/src/main/java/net/minestom/server/sound/SoundEvent.java b/src/main/java/net/minestom/server/sound/SoundEvent.java index 839357c65..a582641bb 100644 --- a/src/main/java/net/minestom/server/sound/SoundEvent.java +++ b/src/main/java/net/minestom/server/sound/SoundEvent.java @@ -2,16 +2,22 @@ package net.minestom.server.sound; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Keyed; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.kyori.adventure.nbt.StringBinaryTag; import net.kyori.adventure.sound.Sound; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.ProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import static net.kyori.adventure.nbt.StringBinaryTag.stringBinaryTag; + /** * Can represent a builtin/vanilla sound or a custom sound. */ @@ -39,6 +45,32 @@ public sealed interface SoundEvent extends ProtocolObject, Keyed, Sound.Type, So return new CustomSoundEvent(namespace, buffer.read(NetworkBuffer.FLOAT.optional())); } }; + @NotNull BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull SoundEvent value) { + return switch (value) { + case BuiltinSoundEvent soundEvent -> stringBinaryTag(soundEvent.name()); + case CustomSoundEvent soundEvent -> { + final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .putString("sound_id", soundEvent.name()); + if (soundEvent.range() != null) { + builder.putFloat("range", soundEvent.range()); + } + yield builder.build(); + } + }; + } + + @Override + public @NotNull SoundEvent read(@NotNull Context context, @NotNull BinaryTag tag) { + if (tag instanceof CompoundBinaryTag compound) { + final String soundId = compound.getString("sound_id"); + final Float range = compound.getFloat("range"); + return new CustomSoundEvent(NamespaceID.from(soundId), range); + } + return BuiltinSoundEvent.getSafe(((StringBinaryTag) tag).value()); + } + }; /** * Get all the builtin sound events. Resource pack sounds will never be returned from this method. diff --git a/src/main/java/net/minestom/server/utils/entity/EntityUtils.java b/src/main/java/net/minestom/server/utils/entity/EntityUtils.java index 4d2054519..068c05262 100644 --- a/src/main/java/net/minestom/server/utils/entity/EntityUtils.java +++ b/src/main/java/net/minestom/server/utils/entity/EntityUtils.java @@ -1,10 +1,7 @@ package net.minestom.server.utils.entity; -import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityType; -import net.minestom.server.instance.Chunk; -import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; import java.util.Set; @@ -21,7 +18,7 @@ public final class EntityUtils { */ public static double getPassengerHeightOffset(@NotNull Entity vehicle, @NotNull Entity passenger) { // TODO: Refactor this in 1.20.5 - if (vehicle.getEntityType() == EntityType.BOAT) return -0.1; + if (vehicle.getEntityType().name().contains("boat")) return -0.1; if (vehicle.getEntityType() == EntityType.MINECART) return 0.0; if (SITTING_ENTITIES.contains(passenger.getEntityType())) return vehicle.getBoundingBox().height() * 0.75; diff --git a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java index 34b7d40f5..9b706c5b4 100644 --- a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java +++ b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java @@ -289,7 +289,8 @@ public interface BinaryTagSerializer { @Override public @NotNull DynamicRegistry.Key read(@NotNull Context context, @NotNull BinaryTag tag) { - if (!(tag instanceof StringBinaryTag s)) throw new IllegalArgumentException("Expected string tag for registry key"); + if (!(tag instanceof StringBinaryTag s)) + throw new IllegalArgumentException("Expected string tag for registry key"); final Registries registries = Objects.requireNonNull(context.registries(), "No registries in context"); final DynamicRegistry registry = registrySelector.apply(registries); final DynamicRegistry.Key key = DynamicRegistry.Key.of(s.value()); @@ -470,6 +471,106 @@ public interface BinaryTagSerializer { }; } + interface Function6 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); + } + + static @NotNull BinaryTagSerializer object( + @NotNull String param1, @NotNull BinaryTagSerializer serializer1, @NotNull Function getter1, + @NotNull String param2, @NotNull BinaryTagSerializer serializer2, @NotNull Function getter2, + @NotNull String param3, @NotNull BinaryTagSerializer serializer3, @NotNull Function getter3, + @NotNull String param4, @NotNull BinaryTagSerializer serializer4, @NotNull Function getter4, + @NotNull String param5, @NotNull BinaryTagSerializer serializer5, @NotNull Function getter5, + @NotNull String param6, @NotNull BinaryTagSerializer serializer6, @NotNull Function getter6, + @NotNull Function6 constructor + ) { + return new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull R value) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + P1 p1 = getter1.apply(value); + if (p1 != null) builder.put(param1, serializer1.write(context, p1)); + P2 p2 = getter2.apply(value); + if (p2 != null) builder.put(param2, serializer2.write(context, p2)); + P3 p3 = getter3.apply(value); + if (p3 != null) builder.put(param3, serializer3.write(context, p3)); + P4 p4 = getter4.apply(value); + if (p4 != null) builder.put(param4, serializer4.write(context, p4)); + P5 p5 = getter5.apply(value); + if (p5 != null) builder.put(param5, serializer5.write(context, p5)); + P6 p6 = getter6.apply(value); + if (p6 != null) builder.put(param6, serializer6.write(context, p6)); + return builder.build(); + } + + @Override + public @NotNull R read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) + return constructor.apply(null, null, null, null, null, null); + return constructor.apply( + serializer1.read(context, compound.get(param1)), + serializer2.read(context, compound.get(param2)), + serializer3.read(context, compound.get(param3)), + serializer4.read(context, compound.get(param4)), + serializer5.read(context, compound.get(param5)), + serializer6.read(context, compound.get(param6)) + ); + } + }; + } + + interface Function7 { + R apply(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); + } + + static @NotNull BinaryTagSerializer object( + @NotNull String param1, @NotNull BinaryTagSerializer serializer1, @NotNull Function getter1, + @NotNull String param2, @NotNull BinaryTagSerializer serializer2, @NotNull Function getter2, + @NotNull String param3, @NotNull BinaryTagSerializer serializer3, @NotNull Function getter3, + @NotNull String param4, @NotNull BinaryTagSerializer serializer4, @NotNull Function getter4, + @NotNull String param5, @NotNull BinaryTagSerializer serializer5, @NotNull Function getter5, + @NotNull String param6, @NotNull BinaryTagSerializer serializer6, @NotNull Function getter6, + @NotNull String param7, @NotNull BinaryTagSerializer serializer7, @NotNull Function getter7, + @NotNull Function7 constructor + ) { + return new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull R value) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + P1 p1 = getter1.apply(value); + if (p1 != null) builder.put(param1, serializer1.write(context, p1)); + P2 p2 = getter2.apply(value); + if (p2 != null) builder.put(param2, serializer2.write(context, p2)); + P3 p3 = getter3.apply(value); + if (p3 != null) builder.put(param3, serializer3.write(context, p3)); + P4 p4 = getter4.apply(value); + if (p4 != null) builder.put(param4, serializer4.write(context, p4)); + P5 p5 = getter5.apply(value); + if (p5 != null) builder.put(param5, serializer5.write(context, p5)); + P6 p6 = getter6.apply(value); + if (p6 != null) builder.put(param6, serializer6.write(context, p6)); + P7 p7 = getter7.apply(value); + if (p7 != null) builder.put(param7, serializer7.write(context, p7)); + return builder.build(); + } + + @Override + public @NotNull R read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) + return constructor.apply(null, null, null, null, null, null, null); + return constructor.apply( + serializer1.read(context, compound.get(param1)), + serializer2.read(context, compound.get(param2)), + serializer3.read(context, compound.get(param3)), + serializer4.read(context, compound.get(param4)), + serializer5.read(context, compound.get(param5)), + serializer6.read(context, compound.get(param6)), + serializer7.read(context, compound.get(param7)) + ); + } + }; + } + static @NotNull BinaryTagSerializer registryTaggedUnion( @NotNull Function>> registrySelector, @NotNull Function> serializerGetter, From 78bf734919c19a122dc93bcd9f674a7012983de8 Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 9 Oct 2024 21:12:33 -0400 Subject: [PATCH 39/97] feat: first join --- .../java/net/minestom/demo/PlayerInit.java | 95 ++++++++----------- .../net/minestom/server/entity/Player.java | 3 +- .../minestom/server/gamedata/tags/Tag.java | 4 +- .../server/network/packet/PacketRegistry.java | 1 + .../minestom/server/registry/Registry.java | 1 + 5 files changed, 49 insertions(+), 55 deletions(-) diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 12ca626c7..3cd2712af 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -1,11 +1,8 @@ package net.minestom.demo; -import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.minestom.server.FeatureFlag; import net.minestom.server.MinecraftServer; -import net.minestom.server.advancements.FrameType; -import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.coordinate.Pos; @@ -33,22 +30,14 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.BlockPredicates; -import net.minestom.server.item.component.EnchantmentList; -import net.minestom.server.item.component.LodestoneTracker; -import net.minestom.server.item.component.PotionContents; -import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.network.packet.server.common.CustomReportDetailsPacket; import net.minestom.server.network.packet.server.common.ServerLinksPacket; -import net.minestom.server.potion.CustomPotionEffect; -import net.minestom.server.potion.PotionEffect; -import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.time.TimeUnit; import java.time.Duration; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; @@ -139,48 +128,48 @@ public class PlayerInit { new ServerLinksPacket.Entry(Component.text("Hello world!"), "https://minestom.net") )); - ItemStack bundle = ItemStack.builder(Material.BUNDLE) - .set(ItemComponent.BUNDLE_CONTENTS, List.of( - ItemStack.of(Material.DIAMOND, 5), - ItemStack.of(Material.RABBIT_FOOT, 5) - )) - .build(); - player.getInventory().addItemStack(bundle); - - player.getInventory().addItemStack(ItemStack.builder(Material.COMPASS) - .set(ItemComponent.LODESTONE_TRACKER, new LodestoneTracker(player.getInstance().getDimensionName(), new Vec(10, 10, 10), true)) - .build()); - - player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) - .set(ItemComponent.ENCHANTMENTS, new EnchantmentList(Map.of( - Enchantment.SHARPNESS, 10 - ))) - .build()); - - player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) - .build()); - - player.getInventory().addItemStack(ItemStack.builder(Material.BLACK_BANNER) - .build()); - - player.getInventory().addItemStack(ItemStack.builder(Material.POTION) - .set(ItemComponent.POTION_CONTENTS, new PotionContents(null, null, List.of( - new CustomPotionEffect(PotionEffect.JUMP_BOOST, new CustomPotionEffect.Settings((byte) 4, - 45 * 20, false, true, true, null)) - ))) - .customName(Component.text("Sharpness 10 Sword").append(Component.space()).append(Component.text("§c§l[LEGENDARY]"))) - .build()); - - - if (event.isFirstSpawn()) { - event.getPlayer().sendNotification(new Notification( - Component.text("Welcome!"), - FrameType.TASK, - Material.IRON_SWORD - )); - - player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); - } +// ItemStack bundle = ItemStack.builder(Material.BUNDLE) +// .set(ItemComponent.BUNDLE_CONTENTS, List.of( +// ItemStack.of(Material.DIAMOND, 5), +// ItemStack.of(Material.RABBIT_FOOT, 5) +// )) +// .build(); +// player.getInventory().addItemStack(bundle); +// +// player.getInventory().addItemStack(ItemStack.builder(Material.COMPASS) +// .set(ItemComponent.LODESTONE_TRACKER, new LodestoneTracker(player.getInstance().getDimensionName(), new Vec(10, 10, 10), true)) +// .build()); +// +// player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) +// .set(ItemComponent.ENCHANTMENTS, new EnchantmentList(Map.of( +// Enchantment.SHARPNESS, 10 +// ))) +// .build()); +// +// player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) +// .build()); +// +// player.getInventory().addItemStack(ItemStack.builder(Material.BLACK_BANNER) +// .build()); +// +// player.getInventory().addItemStack(ItemStack.builder(Material.POTION) +// .set(ItemComponent.POTION_CONTENTS, new PotionContents(null, null, List.of( +// new CustomPotionEffect(PotionEffect.JUMP_BOOST, new CustomPotionEffect.Settings((byte) 4, +// 45 * 20, false, true, true, null)) +// ))) +// .customName(Component.text("Sharpness 10 Sword").append(Component.space()).append(Component.text("§c§l[LEGENDARY]"))) +// .build()); +// +// +// if (event.isFirstSpawn()) { +// event.getPlayer().sendNotification(new Notification( +// Component.text("Welcome!"), +// FrameType.TASK, +// Material.IRON_SWORD +// )); +// +// player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); +// } }) .addListener(PlayerPacketOutEvent.class, event -> { //System.out.println("out " + event.getPacket().getClass().getSimpleName()); diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 0607a0772..d1da229e7 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -340,7 +340,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Recipes start { RecipeManager recipeManager = MinecraftServer.getRecipeManager(); - sendPacket(recipeManager.getDeclareRecipesPacket()); + // TODO(1.21.2): Recipes +// sendPacket(recipeManager.getDeclareRecipesPacket()); List recipesIdentifier = new ArrayList<>(); for (Recipe recipe : recipeManager.consumeRecipes(this)) { 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 663f9a129..4c3bfea93 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java +++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java @@ -103,7 +103,9 @@ public final class Tag implements ProtocolObject, Keyed { //todo this is cursed. it does not update as the registry changes. Fix later. ENCHANTMENTS("minecraft:enchantment", Registry.Resource.ENCHANTMENT_TAGS, - name -> MinecraftServer.getEnchantmentRegistry().getId(DynamicRegistry.Key.of(name))); + name -> MinecraftServer.getEnchantmentRegistry().getId(DynamicRegistry.Key.of(name))), + BIOMES("minecraft:worldgen/biome", Registry.Resource.BIOME_TAGS, + name -> MinecraftServer.getBiomeRegistry().getId(DynamicRegistry.Key.of(name))); private final static BasicType[] VALUES = values(); private final String identifier; diff --git a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java index 374944314..2e55d7e2b 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketRegistry.java +++ b/src/main/java/net/minestom/server/network/packet/PacketRegistry.java @@ -250,6 +250,7 @@ public interface PacketRegistry { entry(DisconnectPacket.class, DisconnectPacket.SERIALIZER), entry(DisguisedChatPacket.class, DisguisedChatPacket.SERIALIZER), entry(EntityStatusPacket.class, EntityStatusPacket.SERIALIZER), + entry(EntityPositionSyncPacket.class, EntityPositionSyncPacket.SERIALIZER), entry(ExplosionPacket.class, ExplosionPacket.SERIALIZER), entry(UnloadChunkPacket.class, UnloadChunkPacket.SERIALIZER), entry(ChangeGameStatePacket.class, ChangeGameStatePacket.SERIALIZER), diff --git a/src/main/java/net/minestom/server/registry/Registry.java b/src/main/java/net/minestom/server/registry/Registry.java index 8093e7a87..fadaa6268 100644 --- a/src/main/java/net/minestom/server/registry/Registry.java +++ b/src/main/java/net/minestom/server/registry/Registry.java @@ -228,6 +228,7 @@ public final class Registry { GAMEPLAY_TAGS("tags/game_event.json"), ITEM_TAGS("tags/item.json"), ENCHANTMENT_TAGS("tags/enchantment.json"), + BIOME_TAGS("tags/biome.json"), DIMENSION_TYPES("dimension_types.json"), BIOMES("biomes.json"), ATTRIBUTES("attributes.json"), From bc563d62cc52f9d6461b768c827de01128cafa3e Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 9 Oct 2024 21:30:59 -0400 Subject: [PATCH 40/97] feat: add PlayerTickEndEvent, other minor tweaks --- .../net/minestom/server/entity/Player.java | 2 +- .../event/player/PlayerTickEndEvent.java | 18 ++++++++++++++++++ .../server/listener/PlayerTickListener.java | 15 +++++++++++++++ .../manager/PacketListenerManager.java | 1 + .../server/network/player/ClientSettings.java | 10 +++++----- 5 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/main/java/net/minestom/server/event/player/PlayerTickEndEvent.java create mode 100644 src/main/java/net/minestom/server/listener/PlayerTickListener.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index d1da229e7..9fcd7764f 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2307,7 +2307,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou refreshSettings(new ClientSettings( locale, settings.viewDistance(), settings.chatMessageType(), settings.chatColors(), settings.displayedSkinParts(), settings.mainHand(), settings.enableTextFiltering(), - settings.allowServerListings(), settings.particleStatus() + settings.allowServerListings(), settings.particleSetting() )); } diff --git a/src/main/java/net/minestom/server/event/player/PlayerTickEndEvent.java b/src/main/java/net/minestom/server/event/player/PlayerTickEndEvent.java new file mode 100644 index 000000000..38db44006 --- /dev/null +++ b/src/main/java/net/minestom/server/event/player/PlayerTickEndEvent.java @@ -0,0 +1,18 @@ +package net.minestom.server.event.player; + +import net.minestom.server.entity.Player; +import net.minestom.server.event.trait.PlayerInstanceEvent; +import org.jetbrains.annotations.NotNull; + +public class PlayerTickEndEvent implements PlayerInstanceEvent { + private final Player player; + + public PlayerTickEndEvent(@NotNull Player player) { + this.player = player; + } + + @Override + public @NotNull Player getPlayer() { + return player; + } +} diff --git a/src/main/java/net/minestom/server/listener/PlayerTickListener.java b/src/main/java/net/minestom/server/listener/PlayerTickListener.java new file mode 100644 index 000000000..d14b2c982 --- /dev/null +++ b/src/main/java/net/minestom/server/listener/PlayerTickListener.java @@ -0,0 +1,15 @@ +package net.minestom.server.listener; + +import net.minestom.server.entity.Player; +import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.player.PlayerTickEndEvent; +import net.minestom.server.network.packet.client.play.ClientTickEndPacket; +import org.jetbrains.annotations.NotNull; + +public final class PlayerTickListener { + + public static void listener(@NotNull ClientTickEndPacket packet, @NotNull Player player) { + EventDispatcher.call(new PlayerTickEndEvent(player)); + } + +} diff --git a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java index 32647da75..243b2f471 100644 --- a/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java +++ b/src/main/java/net/minestom/server/listener/manager/PacketListenerManager.java @@ -97,6 +97,7 @@ public final class PacketListenerManager { setPlayListener(ClientPingRequestPacket.class, PlayPingListener::requestListener); setListener(ConnectionState.PLAY, ClientCookieResponsePacket.class, CookieListener::handleCookieResponse); setPlayListener(ClientNameItemPacket.class, AnvilListener::nameItemListener); + setPlayListener(ClientTickEndPacket.class, PlayerTickListener::listener); } /** diff --git a/src/main/java/net/minestom/server/network/player/ClientSettings.java b/src/main/java/net/minestom/server/network/player/ClientSettings.java index cd12d6041..b62c472f4 100644 --- a/src/main/java/net/minestom/server/network/player/ClientSettings.java +++ b/src/main/java/net/minestom/server/network/player/ClientSettings.java @@ -16,13 +16,13 @@ public record ClientSettings(Locale locale, byte viewDistance, ChatMessageType chatMessageType, boolean chatColors, byte displayedSkinParts, MainHand mainHand, boolean enableTextFiltering, boolean allowServerListings, - @NotNull ParticleStatus particleStatus) { + @NotNull ClientSettings.ParticleSetting particleSetting) { public static ClientSettings DEFAULT = new ClientSettings( Locale.US, (byte) ServerFlag.CHUNK_VIEW_DISTANCE, ChatMessageType.FULL, true, (byte) 0x7F, MainHand.RIGHT, true, true, - ParticleStatus.ALL + ParticleSetting.ALL ); private static final NetworkBuffer.Type LOCALE_SERIALIZER = STRING.transform( @@ -42,7 +42,7 @@ public record ClientSettings(Locale locale, byte viewDistance, Enum(MainHand.class), ClientSettings::mainHand, BOOLEAN, ClientSettings::enableTextFiltering, BOOLEAN, ClientSettings::allowServerListings, - ParticleStatus.NETWORK_TYPE, ClientSettings::particleStatus, + ParticleSetting.NETWORK_TYPE, ClientSettings::particleSetting, ClientSettings::new); public ClientSettings { @@ -65,11 +65,11 @@ public record ClientSettings(Locale locale, byte viewDistance, RIGHT } - public enum ParticleStatus { + public enum ParticleSetting { ALL, DECREASED, MINIMAL; - public static final NetworkBuffer.Type NETWORK_TYPE = Enum(ParticleStatus.class); + public static final NetworkBuffer.Type NETWORK_TYPE = Enum(ParticleSetting.class); } } From c2c16e28a23098053a53d2cec4123c16646c1aa0 Mon Sep 17 00:00:00 2001 From: mworzala Date: Sat, 19 Oct 2024 20:17:43 -0400 Subject: [PATCH 41/97] feat: new recipe types, not migrated from old Recipe --- .../java/net/minestom/codegen/Generators.java | 9 +- .../codegen/recipe/RecipeTypeGenerator.java | 102 +-------------- .../codegen/util/GenericEnumGenerator.java | 122 ++++++++++++++++++ gradle/libs.versions.toml | 2 +- .../minestom/server/MinecraftConstants.java | 8 +- .../server/recipe/RecipeBookCategory.java | 56 ++++++++ .../minestom/server/recipe/RecipeType.java | 34 +---- .../recipe/display/RecipeDisplayType.java | 40 ++++++ .../recipe/display/SlotDisplayType.java | 46 +++++++ .../net/minestom/server/entity/Player.java | 3 +- .../server/network/NetworkBuffer.java | 5 + .../server/network/NetworkBufferTypeImpl.java | 37 ++++++ .../server/play/DeclareRecipesPacket.java | 29 ++++- .../server/play/RecipeBookAddPacket.java | 45 ++++--- .../server/play/RecipeBookRemovePacket.java | 10 +- .../net/minestom/server/recipe/Recipe.java | 6 + .../minestom/server/recipe/RecipeManager.java | 3 +- .../server/recipe/RecipeProperty.java | 54 ++++++++ .../server/recipe/RecipeSerializers.java | 93 ++++++------- .../server/recipe/display/RecipeDisplay.java | 115 +++++++++++++++++ .../server/recipe/display/SlotDisplay.java | 108 ++++++++++++++++ 21 files changed, 712 insertions(+), 215 deletions(-) create mode 100644 code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java create mode 100644 src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java create mode 100644 src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java create mode 100644 src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java create mode 100644 src/main/java/net/minestom/server/recipe/RecipeProperty.java create mode 100644 src/main/java/net/minestom/server/recipe/display/RecipeDisplay.java create mode 100644 src/main/java/net/minestom/server/recipe/display/SlotDisplay.java diff --git a/code-generators/src/main/java/net/minestom/codegen/Generators.java b/code-generators/src/main/java/net/minestom/codegen/Generators.java index deddd0e90..59223e231 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -4,6 +4,7 @@ import net.minestom.codegen.color.DyeColorGenerator; import net.minestom.codegen.fluid.FluidGenerator; import net.minestom.codegen.particle.ParticleGenerator; import net.minestom.codegen.recipe.RecipeTypeGenerator; +import net.minestom.codegen.util.GenericEnumGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,9 +23,15 @@ public class Generators { // Special generators new DyeColorGenerator(resource("dye_colors.json"), outputFolder).generate(); - new RecipeTypeGenerator(resource("recipe_types.json"), outputFolder).generate(); new ParticleGenerator(resource("particles.json"), outputFolder).generate(); new ConstantsGenerator(resource("constants.json"), outputFolder).generate(); + new RecipeTypeGenerator(resource("recipe_types.json"), outputFolder).generate(); + new GenericEnumGenerator("net.minestom.server.recipe.display", "RecipeDisplayType", + resource("recipe_display_types.json"), outputFolder).generate(); + new GenericEnumGenerator("net.minestom.server.recipe.display", "SlotDisplayType", + resource("slot_display_types.json"), outputFolder).generate(); + new GenericEnumGenerator("net.minestom.server.recipe", "RecipeBookCategory", + resource("recipe_book_categories.json"), outputFolder).generate(); var generator = new CodeGenerator(outputFolder); diff --git a/code-generators/src/main/java/net/minestom/codegen/recipe/RecipeTypeGenerator.java b/code-generators/src/main/java/net/minestom/codegen/recipe/RecipeTypeGenerator.java index 749dfc091..a575a0f2a 100644 --- a/code-generators/src/main/java/net/minestom/codegen/recipe/RecipeTypeGenerator.java +++ b/code-generators/src/main/java/net/minestom/codegen/recipe/RecipeTypeGenerator.java @@ -1,113 +1,21 @@ package net.minestom.codegen.recipe; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.squareup.javapoet.*; -import net.minestom.codegen.MinestomCodeGenerator; +import net.minestom.codegen.util.GenericEnumGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.lang.model.element.Modifier; import java.io.File; import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Comparator; -import java.util.List; -import java.util.stream.StreamSupport; -public class RecipeTypeGenerator extends MinestomCodeGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(RecipeTypeGenerator.class); - private final InputStream recipeTypesFile; - private final File outputFolder; +public class RecipeTypeGenerator extends GenericEnumGenerator { public RecipeTypeGenerator(@Nullable InputStream recipeTypesFile, @NotNull File outputFolder) { - this.recipeTypesFile = recipeTypesFile; - this.outputFolder = outputFolder; + super("net.minestom.server.recipe", "RecipeType", recipeTypesFile, outputFolder); } @Override - public void generate() { - if (recipeTypesFile == null) { - LOGGER.error("Failed to find recipe_types.json."); - LOGGER.error("Stopped code generation for recipe types."); - return; - } - if (!outputFolder.exists() && !outputFolder.mkdirs()) { - LOGGER.error("Output folder for code generation does not exist and could not be created."); - return; - } - - // Important classes we use alot - JsonArray recipeTypes = GSON.fromJson(new InputStreamReader(recipeTypesFile), JsonArray.class); - ClassName recipeTypeCN = ClassName.get("net.minestom.server.recipe", "RecipeType"); - TypeSpec.Builder recipeTypeEnum = TypeSpec.enumBuilder(recipeTypeCN) - .addSuperinterface(ClassName.get("net.minestom.server.registry", "StaticProtocolObject")) - .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); - ClassName namespaceIdCN = ClassName.get("net.minestom.server.utils", "NamespaceID"); - - ClassName networkBufferCN = ClassName.get("net.minestom.server.network", "NetworkBuffer"); - ParameterizedTypeName networkBufferTypeCN = ParameterizedTypeName.get(networkBufferCN.nestedClass("Type"), recipeTypeCN); - - // Fields - recipeTypeEnum.addFields( - List.of( - FieldSpec.builder(networkBufferTypeCN, "NETWORK_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) - .initializer("$T.Enum($T.class)", networkBufferCN, recipeTypeCN) - .build(), - FieldSpec.builder(namespaceIdCN, "namespace", Modifier.PRIVATE, Modifier.FINAL).build() - ) - ); - - // Methods - recipeTypeEnum.addMethods( - List.of( - // Constructor - MethodSpec.constructorBuilder() - .addParameter(ParameterSpec.builder(namespaceIdCN, "namespace").addAnnotation(NotNull.class).build()) - .addStatement("this.namespace = namespace") - .build(), - MethodSpec.methodBuilder("namespace") - .addModifiers(Modifier.PUBLIC) - .addAnnotation(NotNull.class) - .addAnnotation(Override.class) - .returns(namespaceIdCN) - .addStatement("return this.namespace") - .build(), - MethodSpec.methodBuilder("id") - .addModifiers(Modifier.PUBLIC) - .returns(TypeName.INT) - .addAnnotation(Override.class) - .addStatement("return this.ordinal()") - .build() - ) - ); - - // Use data - for (JsonObject recipeTypeObject : StreamSupport.stream(recipeTypes.spliterator(), true).map(JsonElement::getAsJsonObject).sorted(Comparator.comparingInt(o -> o.get("id").getAsInt())).toList()) { - String recipeTypeName = recipeTypeObject.get("name").getAsString(); - recipeTypeEnum.addEnumConstant(recipeTypeConstantName(recipeTypeName), TypeSpec.anonymousClassBuilder( - "$T.from($S)", - namespaceIdCN, recipeTypeName - ).build() - ); - } - - // Write files to outputFolder - writeFiles( - List.of( - JavaFile.builder("net.minestom.server.recipe", recipeTypeEnum.build()) - .indent(" ") - .skipJavaLangImports(true) - .build() - ), - outputFolder - ); + protected @NotNull String nameGenerator(@NotNull String namespaceId) { + return toConstant(namespaceId).replace("CRAFTING_", ""); } - private static @NotNull String recipeTypeConstantName(@NotNull String name) { - return toConstant(name).replace("CRAFTING_", ""); - } } diff --git a/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java b/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java new file mode 100644 index 000000000..b5529895e --- /dev/null +++ b/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java @@ -0,0 +1,122 @@ +package net.minestom.codegen.util; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.squareup.javapoet.*; +import net.minestom.codegen.MinestomCodeGenerator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.lang.model.element.Modifier; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Comparator; +import java.util.List; +import java.util.stream.StreamSupport; + +public class GenericEnumGenerator extends MinestomCodeGenerator { + private static final Logger LOGGER = LoggerFactory.getLogger(GenericEnumGenerator.class); + + private final String packageName; + private final String className; + private final InputStream entriesFile; + private final File outputFolder; + + public GenericEnumGenerator( + @NotNull String packageName, @NotNull String className, + @Nullable InputStream entriesFile, @NotNull File outputFolder + ) { + this.packageName = packageName; + this.className = className; + this.entriesFile = entriesFile; + this.outputFolder = outputFolder; + } + + @Override + public void generate() { + if (entriesFile == null) { + LOGGER.error("Failed to find entries file."); + LOGGER.error("Stopped code generation for {}.", className); + return; + } + if (!outputFolder.exists() && !outputFolder.mkdirs()) { + LOGGER.error("Output folder for code generation does not exist and could not be created."); + return; + } + + // Important classes we use alot + JsonArray entryList = GSON.fromJson(new InputStreamReader(entriesFile), JsonArray.class); + ClassName entryCN = ClassName.get(packageName, className); + TypeSpec.Builder entryEnum = TypeSpec.enumBuilder(entryCN) + .addSuperinterface(ClassName.get("net.minestom.server.registry", "StaticProtocolObject")) + .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); + ClassName namespaceIdCN = ClassName.get("net.minestom.server.utils", "NamespaceID"); + + ClassName networkBufferCN = ClassName.get("net.minestom.server.network", "NetworkBuffer"); + ParameterizedTypeName networkBufferTypeCN = ParameterizedTypeName.get(networkBufferCN.nestedClass("Type"), entryCN); + + // Fields + entryEnum.addFields( + List.of( + FieldSpec.builder(networkBufferTypeCN, "NETWORK_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer("$T.Enum($T.class)", networkBufferCN, entryCN) + .build(), + FieldSpec.builder(namespaceIdCN, "namespace", Modifier.PRIVATE, Modifier.FINAL).build() + ) + ); + + // Methods + entryEnum.addMethods( + List.of( + // Constructor + MethodSpec.constructorBuilder() + .addParameter(ParameterSpec.builder(namespaceIdCN, "namespace").addAnnotation(NotNull.class).build()) + .addStatement("this.namespace = namespace") + .build(), + MethodSpec.methodBuilder("namespace") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(NotNull.class) + .addAnnotation(Override.class) + .returns(namespaceIdCN) + .addStatement("return this.namespace") + .build(), + MethodSpec.methodBuilder("id") + .addModifiers(Modifier.PUBLIC) + .returns(TypeName.INT) + .addAnnotation(Override.class) + .addStatement("return this.ordinal()") + .build() + ) + ); + + // Use data + for (JsonObject entryObject : StreamSupport.stream(entryList.spliterator(), true).map(JsonElement::getAsJsonObject).sorted(Comparator.comparingInt(o -> o.get("id").getAsInt())).toList()) { + String entryName = entryObject.get("name").getAsString(); + entryEnum.addEnumConstant(nameGenerator(entryName), TypeSpec.anonymousClassBuilder( + "$T.from($S)", + namespaceIdCN, entryName + ).build() + ); + } + + // Write files to outputFolder + writeFiles( + List.of( + JavaFile.builder(packageName, entryEnum.build()) + .indent(" ") + .skipJavaLangImports(true) + .build() + ), + outputFolder + ); + } + + protected @NotNull String nameGenerator(@NotNull String namespaceId) { + return toConstant(namespaceId); + } + +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 11656b91d..b3564e09c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # Important dependencies -data = "1.21.2-pre1-dev" +data = "1.21.2-rc1-dev" adventure = "4.17.0" jetbrainsAnnotations = "24.1.0" slf4j = "2.0.7" diff --git a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java index 69c802dbd..afbf53560 100644 --- a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java +++ b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java @@ -4,13 +4,13 @@ package net.minestom.server; * AUTOGENERATED by ConstantsGenerator */ interface MinecraftConstants { - String VERSION_NAME = "1.21.2-pre1"; + String VERSION_NAME = "1.21.2-rc1"; - int PROTOCOL_VERSION = 1073742037; + int PROTOCOL_VERSION = 1073742042; - int DATA_VERSION = 4073; + int DATA_VERSION = 4078; - int RESOURCE_PACK_VERSION = 41; + int RESOURCE_PACK_VERSION = 42; int DATA_PACK_VERSION = 57; } diff --git a/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java b/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java new file mode 100644 index 000000000..42154de0d --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java @@ -0,0 +1,56 @@ +package net.minestom.server.recipe; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +/** + * AUTOGENERATED by GenericEnumGenerator + */ +public enum RecipeBookCategory implements StaticProtocolObject { + CRAFTING_BUILDING_BLOCKS(NamespaceID.from("minecraft:crafting_building_blocks")), + + CRAFTING_REDSTONE(NamespaceID.from("minecraft:crafting_redstone")), + + CRAFTING_EQUIPMENT(NamespaceID.from("minecraft:crafting_equipment")), + + CRAFTING_MISC(NamespaceID.from("minecraft:crafting_misc")), + + FURNACE_FOOD(NamespaceID.from("minecraft:furnace_food")), + + FURNACE_BLOCKS(NamespaceID.from("minecraft:furnace_blocks")), + + FURNACE_MISC(NamespaceID.from("minecraft:furnace_misc")), + + BLAST_FURNACE_BLOCKS(NamespaceID.from("minecraft:blast_furnace_blocks")), + + BLAST_FURNACE_MISC(NamespaceID.from("minecraft:blast_furnace_misc")), + + SMOKER_FOOD(NamespaceID.from("minecraft:smoker_food")), + + STONECUTTER(NamespaceID.from("minecraft:stonecutter")), + + SMITHING(NamespaceID.from("minecraft:smithing")), + + CAMPFIRE(NamespaceID.from("minecraft:campfire")); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeBookCategory.class); + + private final NamespaceID namespace; + + RecipeBookCategory(@NotNull NamespaceID namespace) { + this.namespace = namespace; + } + + @NotNull + @Override + public NamespaceID namespace() { + return this.namespace; + } + + @Override + public int id() { + return this.ordinal(); + } +} diff --git a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java index 422737c9d..f931fd63f 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java +++ b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java @@ -9,33 +9,7 @@ import org.jetbrains.annotations.NotNull; * AUTOGENERATED by RecipeTypeGenerator */ public enum RecipeType implements StaticProtocolObject { - SHAPED(NamespaceID.from("minecraft:crafting_shaped")), - - SHAPELESS(NamespaceID.from("minecraft:crafting_shapeless")), - - SPECIAL_ARMORDYE(NamespaceID.from("minecraft:crafting_special_armordye")), - - SPECIAL_BOOKCLONING(NamespaceID.from("minecraft:crafting_special_bookcloning")), - - SPECIAL_MAPCLONING(NamespaceID.from("minecraft:crafting_special_mapcloning")), - - SPECIAL_MAPEXTENDING(NamespaceID.from("minecraft:crafting_special_mapextending")), - - SPECIAL_FIREWORK_ROCKET(NamespaceID.from("minecraft:crafting_special_firework_rocket")), - - SPECIAL_FIREWORK_STAR(NamespaceID.from("minecraft:crafting_special_firework_star")), - - SPECIAL_FIREWORK_STAR_FADE(NamespaceID.from("minecraft:crafting_special_firework_star_fade")), - - SPECIAL_TIPPEDARROW(NamespaceID.from("minecraft:crafting_special_tippedarrow")), - - SPECIAL_BANNERDUPLICATE(NamespaceID.from("minecraft:crafting_special_bannerduplicate")), - - SPECIAL_SHIELDDECORATION(NamespaceID.from("minecraft:crafting_special_shielddecoration")), - - TRANSMUTE(NamespaceID.from("minecraft:crafting_transmute")), - - SPECIAL_REPAIRITEM(NamespaceID.from("minecraft:crafting_special_repairitem")), + CRAFTING(NamespaceID.from("minecraft:crafting")), SMELTING(NamespaceID.from("minecraft:smelting")), @@ -47,11 +21,7 @@ public enum RecipeType implements StaticProtocolObject { STONECUTTING(NamespaceID.from("minecraft:stonecutting")), - SMITHING_TRANSFORM(NamespaceID.from("minecraft:smithing_transform")), - - SMITHING_TRIM(NamespaceID.from("minecraft:smithing_trim")), - - DECORATED_POT(NamespaceID.from("minecraft:crafting_decorated_pot")); + SMITHING(NamespaceID.from("minecraft:smithing")); public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeType.class); diff --git a/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java b/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java new file mode 100644 index 000000000..ecb7d1da2 --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java @@ -0,0 +1,40 @@ +package net.minestom.server.recipe.display; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +/** + * AUTOGENERATED by GenericEnumGenerator + */ +public enum RecipeDisplayType implements StaticProtocolObject { + CRAFTING_SHAPELESS(NamespaceID.from("minecraft:crafting_shapeless")), + + CRAFTING_SHAPED(NamespaceID.from("minecraft:crafting_shaped")), + + FURNACE(NamespaceID.from("minecraft:furnace")), + + STONECUTTER(NamespaceID.from("minecraft:stonecutter")), + + SMITHING(NamespaceID.from("minecraft:smithing")); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeDisplayType.class); + + private final NamespaceID namespace; + + RecipeDisplayType(@NotNull NamespaceID namespace) { + this.namespace = namespace; + } + + @NotNull + @Override + public NamespaceID namespace() { + return this.namespace; + } + + @Override + public int id() { + return this.ordinal(); + } +} diff --git a/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java b/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java new file mode 100644 index 000000000..12709dc7c --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java @@ -0,0 +1,46 @@ +package net.minestom.server.recipe.display; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +/** + * AUTOGENERATED by GenericEnumGenerator + */ +public enum SlotDisplayType implements StaticProtocolObject { + EMPTY(NamespaceID.from("minecraft:empty")), + + ANY_FUEL(NamespaceID.from("minecraft:any_fuel")), + + ITEM(NamespaceID.from("minecraft:item")), + + ITEM_STACK(NamespaceID.from("minecraft:item_stack")), + + TAG(NamespaceID.from("minecraft:tag")), + + SMITHING_TRIM(NamespaceID.from("minecraft:smithing_trim")), + + WITH_REMAINDER(NamespaceID.from("minecraft:with_remainder")), + + COMPOSITE(NamespaceID.from("minecraft:composite")); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(SlotDisplayType.class); + + private final NamespaceID namespace; + + SlotDisplayType(@NotNull NamespaceID namespace) { + this.namespace = namespace; + } + + @NotNull + @Override + public NamespaceID namespace() { + return this.namespace; + } + + @Override + public int id() { + return this.ordinal(); + } +} diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 9fcd7764f..cc8e6c91b 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -340,8 +340,7 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou // Recipes start { RecipeManager recipeManager = MinecraftServer.getRecipeManager(); - // TODO(1.21.2): Recipes -// sendPacket(recipeManager.getDeclareRecipesPacket()); + sendPacket(recipeManager.getDeclareRecipesPacket()); List recipesIdentifier = new ArrayList<>(); for (Recipe recipe : recipeManager.consumeRecipes(this)) { diff --git a/src/main/java/net/minestom/server/network/NetworkBuffer.java b/src/main/java/net/minestom/server/network/NetworkBuffer.java index aef48eb15..068e34b36 100644 --- a/src/main/java/net/minestom/server/network/NetworkBuffer.java +++ b/src/main/java/net/minestom/server/network/NetworkBuffer.java @@ -39,6 +39,7 @@ public sealed interface NetworkBuffer permits NetworkBufferImpl { Type FLOAT = new NetworkBufferTypeImpl.FloatType(); Type DOUBLE = new NetworkBufferTypeImpl.DoubleType(); Type VAR_INT = new NetworkBufferTypeImpl.VarIntType(); + Type<@Nullable Integer> OPTIONAL_VAR_INT = new NetworkBufferTypeImpl.OptionalVarIntType(); Type VAR_INT_3 = new NetworkBufferTypeImpl.VarInt3Type(); Type VAR_LONG = new NetworkBufferTypeImpl.VarLongType(); Type RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType(-1); @@ -201,6 +202,10 @@ public sealed interface NetworkBuffer permits NetworkBufferImpl { default @NotNull Type optional() { return new NetworkBufferTypeImpl.OptionalType<>(this); } + + default @NotNull Type unionType(@NotNull Function> serializers, @NotNull Function keyFunc) { + return new NetworkBufferTypeImpl.UnionType<>(this, keyFunc, serializers); + } } static @NotNull Builder builder(long size) { diff --git a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java index b911b5c47..b7c2efd8d 100644 --- a/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java +++ b/src/main/java/net/minestom/server/network/NetworkBufferTypeImpl.java @@ -205,6 +205,19 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } + record OptionalVarIntType() implements NetworkBufferTypeImpl<@Nullable Integer> { + @Override + public void write(@NotNull NetworkBuffer buffer, @Nullable Integer value) { + buffer.write(VAR_INT, value == null ? 0 : value + 1); + } + + @Override + public @Nullable Integer read(@NotNull NetworkBuffer buffer) { + final int value = buffer.read(VAR_INT); + return value == 0 ? null : value - 1; + } + } + record VarInt3Type() implements NetworkBufferTypeImpl { @Override public void write(@NotNull NetworkBuffer buffer, Integer boxed) { @@ -756,6 +769,30 @@ interface NetworkBufferTypeImpl extends NetworkBuffer.Type { } } + record UnionType( + @NotNull Type keyType, @NotNull Function keyFunc, + @NotNull Function> serializers + ) implements NetworkBufferTypeImpl { + + @Override + public void write(@NotNull NetworkBuffer buffer, T value) { + final K key = keyFunc.apply(value); + buffer.write(keyType, key); + var serializer = serializers.apply(key); + if (serializer == null) + throw new UnsupportedOperationException("Unrecognized type: " + key); + serializer.write(buffer, value); + } + + @Override + public T read(@NotNull NetworkBuffer buffer) { + final K key = buffer.read(keyType); + var serializer = serializers.apply(key); + if (serializer == null) throw new UnsupportedOperationException("Unrecognized type: " + key); + return serializer.read(buffer); + } + } + record RegistryTypeType( @NotNull Function> selector) implements NetworkBufferTypeImpl> { @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java index 260b48bd2..990a70525 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java @@ -1,22 +1,43 @@ package net.minestom.server.network.packet.server.play; +import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.recipe.Recipe; +import net.minestom.server.recipe.RecipeProperty; import net.minestom.server.recipe.RecipeSerializers; +import net.minestom.server.recipe.display.SlotDisplay; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Map; -public record DeclareRecipesPacket(@NotNull List recipes) implements ServerPacket.Play { - public static final int MAX_RECIPES = Short.MAX_VALUE; +public record DeclareRecipesPacket( + @NotNull Map> itemProperties, + @NotNull List stonecutterRecipes +) implements ServerPacket.Play { + private static final int MAX_ITEMS_PER_PROPERTY = Short.MAX_VALUE; + private static final int MAX_STONECUTTER_RECIPES = Short.MAX_VALUE; public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( - RecipeSerializers.RECIPE.list(MAX_RECIPES), DeclareRecipesPacket::recipes, + RecipeProperty.NETWORK_TYPE.mapValue(Material.NETWORK_TYPE.list(MAX_ITEMS_PER_PROPERTY)), DeclareRecipesPacket::itemProperties, + StonecutterRecipe.NETWORK_TYPE.list(MAX_STONECUTTER_RECIPES), DeclareRecipesPacket::stonecutterRecipes, DeclareRecipesPacket::new); public DeclareRecipesPacket { - recipes = List.copyOf(recipes); + itemProperties = Map.copyOf(itemProperties); + stonecutterRecipes = List.copyOf(stonecutterRecipes); } + + public record StonecutterRecipe( + @NotNull Recipe.Ingredient ingredient, + @NotNull SlotDisplay optionDisplay + ) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + RecipeSerializers.INGREDIENT, StonecutterRecipe::ingredient, + SlotDisplay.NETWORK_TYPE, StonecutterRecipe::optionDisplay, + StonecutterRecipe::new); + } + } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java index cf176e29b..e0cee497a 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookAddPacket.java @@ -3,7 +3,12 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.recipe.Recipe; +import net.minestom.server.recipe.RecipeBookCategory; +import net.minestom.server.recipe.RecipeSerializers; +import net.minestom.server.recipe.display.RecipeDisplay; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -19,25 +24,35 @@ public record RecipeBookAddPacket(@NotNull List entries, boolean replace) RecipeBookAddPacket::new); public record Entry( -// int recipeIndex, Object display, -// @Nullable Integer group, @NotNull RecipeCategory category, -// @Nullable List craftingRequirements, -// byte flags + int displayId, @NotNull RecipeDisplay display, + @Nullable Integer group, @NotNull RecipeBookCategory category, + @Nullable List craftingRequirements, + byte flags ) { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.VAR_INT, Entry::displayId, + RecipeDisplay.NETWORK_TYPE, Entry::display, + NetworkBuffer.OPTIONAL_VAR_INT, Entry::group, + RecipeBookCategory.NETWORK_TYPE, Entry::category, + RecipeSerializers.INGREDIENT.list().optional(), Entry::craftingRequirements, + NetworkBuffer.BYTE, Entry::flags, Entry::new); -// public Entry(Object contents, boolean notification, boolean highlight) { -// this(contents, (byte) ((notification ? FLAG_NOTIFICATION : 0) | (highlight ? FLAG_HIGHLIGHT : 0))); -// } -// -// public boolean notification() { -// return (flags & FLAG_NOTIFICATION) != 0; -// } -// -// public boolean highlight() { -// return (flags & FLAG_HIGHLIGHT) != 0; -// } + public Entry(int displayId, @NotNull RecipeDisplay display, + @Nullable Integer group, @NotNull RecipeBookCategory category, + @Nullable List craftingRequirements, + boolean notification, boolean highlight) { + this(displayId, display, group, category, craftingRequirements, + (byte) ((notification ? FLAG_NOTIFICATION : 0) | (highlight ? FLAG_HIGHLIGHT : 0))); + } + + public boolean notification() { + return (flags & FLAG_NOTIFICATION) != 0; + } + + public boolean highlight() { + return (flags & FLAG_HIGHLIGHT) != 0; + } } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java index 255a6e51e..484a73c45 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/RecipeBookRemovePacket.java @@ -3,9 +3,17 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.packet.server.ServerPacket; +import org.jetbrains.annotations.NotNull; -public record RecipeBookRemovePacket() implements ServerPacket.Play { +import java.util.List; + +public record RecipeBookRemovePacket(@NotNull List displayIds) implements ServerPacket.Play { public static final NetworkBuffer.Type SERIALIZER = NetworkBufferTemplate.template( + NetworkBuffer.VAR_INT.list(), RecipeBookRemovePacket::displayIds, RecipeBookRemovePacket::new); + public RecipeBookRemovePacket { + displayIds = List.copyOf(displayIds); + } + } diff --git a/src/main/java/net/minestom/server/recipe/Recipe.java b/src/main/java/net/minestom/server/recipe/Recipe.java index bbc526d94..547e10722 100644 --- a/src/main/java/net/minestom/server/recipe/Recipe.java +++ b/src/main/java/net/minestom/server/recipe/Recipe.java @@ -1,6 +1,7 @@ package net.minestom.server.recipe; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; import org.jetbrains.annotations.NotNull; @@ -131,4 +132,9 @@ public record Recipe(@NotNull String id, @NotNull Data data) { public record DecoratedPot(RecipeCategory.Crafting category) implements Data { public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.DECORATED_POT; } + + public record Transmute(String group, RecipeCategory.Crafting category, Ingredient input, + Ingredient material, Material result) implements Data { + public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.TRANSMUTE; + } } diff --git a/src/main/java/net/minestom/server/recipe/RecipeManager.java b/src/main/java/net/minestom/server/recipe/RecipeManager.java index 49faf063d..a7118d390 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeManager.java +++ b/src/main/java/net/minestom/server/recipe/RecipeManager.java @@ -49,6 +49,7 @@ public final class RecipeManager { } private @NotNull DeclareRecipesPacket createDeclareRecipesPacket() { - return new DeclareRecipesPacket(List.copyOf(recipes.keySet())); + //TODO(1.21.2): Recipe property lists & stonecutter recipes + return new DeclareRecipesPacket(Map.of(), List.of()); } } diff --git a/src/main/java/net/minestom/server/recipe/RecipeProperty.java b/src/main/java/net/minestom/server/recipe/RecipeProperty.java new file mode 100644 index 000000000..30c6d0a66 --- /dev/null +++ b/src/main/java/net/minestom/server/recipe/RecipeProperty.java @@ -0,0 +1,54 @@ +package net.minestom.server.recipe; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.Keyed; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +public enum RecipeProperty implements Keyed { + SMITHING_BASE("smithing_base"), + SMITHING_TEMPLATE("smithing_template"), + SMITHING_ADDITION("smithing_addition"), + FURNACE_INPUT("furnace_input"), + BLAST_FURNACE_INPUT("blast_furnace_input"), + SMOKER_INPUT("smoker_input"), + CAMPFIRE_INPUT("campfire_input"); + + private static final Map BY_NAMESPACE = Arrays.stream(values()) + .collect(Collectors.toMap(RecipeProperty::namespace, Function.identity())); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.STRING.transform( + namespaceId -> Objects.requireNonNull(fromNamespaceId(namespaceId)), + recipeProperty -> recipeProperty.namespace().asMinimalString()); + + public static @Nullable RecipeProperty fromNamespaceId(@NotNull String namespaceId) { + return fromNamespaceId(net.minestom.server.utils.NamespaceID.from(namespaceId)); + } + + public static @Nullable RecipeProperty fromNamespaceId(@NotNull NamespaceID namespaceId) { + return BY_NAMESPACE.get(namespaceId); + } + + private final NamespaceID namespace; + + RecipeProperty(@NotNull String id) { + this.namespace = NamespaceID.from("minecraft", id); + } + + public @NotNull NamespaceID namespace() { + return namespace; + } + + @Override + public @NotNull Key key() { + return namespace; + } +} diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java index 82d28d6f3..d1c483047 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -1,6 +1,7 @@ package net.minestom.server.recipe; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import org.jetbrains.annotations.ApiStatus; @@ -16,31 +17,32 @@ import static net.minestom.server.recipe.RecipeCategory.Crafting; @ApiStatus.Internal public final class RecipeSerializers { - public static final Type RECIPE = new Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, Recipe shaped) { - buffer.write(STRING, shaped.id()); - final RecipeType recipeType = recipeToType(shaped.data()); - buffer.write(RecipeType.NETWORK_TYPE, recipeType); - var serializer = RecipeSerializers.dataSerializer(recipeType); - if (serializer == null) - throw new UnsupportedOperationException("Unrecognized type: " + recipeType); - serializer.write(buffer, shaped.data()); - } + public static final Type DATA = RecipeType.NETWORK_TYPE + .unionType(RecipeSerializers::dataSerializer, RecipeSerializers::recipeToType); - @Override - public Recipe read(@NotNull NetworkBuffer buffer) { - final String identifier = buffer.read(STRING); - final RecipeType type = buffer.read(RecipeType.NETWORK_TYPE); - var serializer = RecipeSerializers.dataSerializer(type); - if (serializer == null) throw new UnsupportedOperationException("Unrecognized type: " + type); - final Data data = serializer.read(buffer); - return new Recipe(identifier, data); - } - }; + public static final Type RECIPE = NetworkBufferTemplate.template( + STRING, Recipe::id, + DATA, Recipe::data, + Recipe::new); public static final Type INGREDIENT = NetworkBufferTemplate.template( - ItemStack.STRICT_NETWORK_TYPE.list(MAX_INGREDIENTS), Ingredient::items, + // FIXME(1.21.2): This is really an ObjectSet, but currently ObjectSet does not properly support + // non-dynamic registry types. We need to improve how the tag system works generally. + new Type<>() { + @Override + public void write(@NotNull NetworkBuffer buffer, List value) { + // +1 because 0 indicates that an item tag name follows (in this case it does not). + buffer.write(VAR_INT, value.size() + 1); + for (ItemStack itemStack : value) { + buffer.write(ItemStack.STRICT_NETWORK_TYPE, itemStack); + } + } + + @Override + public List read(@NotNull NetworkBuffer buffer) { + throw new UnsupportedOperationException("cannot read ingredients yet"); + } + }, Ingredient::items, Ingredient::new ); @@ -192,60 +194,37 @@ public final class RecipeSerializers { Enum(Crafting.class), DecoratedPot::category, DecoratedPot::new ); + public static final Type TRANSMUTE = NetworkBufferTemplate.template( + STRING, Transmute::group, + Enum(Crafting.class), Transmute::category, + INGREDIENT, Transmute::input, + INGREDIENT, Transmute::material, + Material.NETWORK_TYPE, Transmute::result, + Transmute::new + ); + @SuppressWarnings({"unchecked", "rawtypes"}) public static Type dataSerializer(RecipeType type) { return (Type) switch (type) { - case SHAPED -> SHAPED; - case SHAPELESS -> SHAPELESS; - case SPECIAL_ARMORDYE -> ARMOR_DYE; - case SPECIAL_BOOKCLONING -> BOOK_CLONING; - case SPECIAL_MAPCLONING -> MAP_CLONING; - case SPECIAL_MAPEXTENDING -> MAP_EXTENDING; - case SPECIAL_FIREWORK_ROCKET -> FIREWORK_ROCKET; - case SPECIAL_FIREWORK_STAR -> FIREWORK_STAR; - case SPECIAL_FIREWORK_STAR_FADE -> FIREWORK_STAR_FADE; - case SPECIAL_TIPPEDARROW -> TIPPED_ARROW; - case SPECIAL_BANNERDUPLICATE -> BANNER_DUPLICATE; - case SPECIAL_SHIELDDECORATION -> SHIELD_DECORATION; -// case SPECIAL_SHULKERBOXCOLORING -> SPECIAL_SHULKER_BOX_COLORING; -// case SPECIAL_SUSPICIOUSSTEW -> SUSPICIOUS_STEW; - case TRANSMUTE -> null; // TODO(1.21.2) - case SPECIAL_REPAIRITEM -> REPAIR_ITEM; + case CRAFTING -> null; case SMELTING -> SMELTING; case BLASTING -> BLASTING; case SMOKING -> SMOKING; case CAMPFIRE_COOKING -> CAMPFIRE_COOKING; case STONECUTTING -> STONECUTTING; - case SMITHING_TRANSFORM -> SMITHING_TRANSFORM; - case SMITHING_TRIM -> SMITHING_TRIM; - case DECORATED_POT -> DECORATED_POT; + case SMITHING -> null; }; } public static RecipeType recipeToType(Data data) { return switch (data) { - case Shaped ignored -> RecipeType.SHAPED; - case Shapeless ignored -> RecipeType.SHAPELESS; case Smelting ignored -> RecipeType.SMELTING; case Blasting ignored -> RecipeType.BLASTING; case Smoking ignored -> RecipeType.SMOKING; case CampfireCooking ignored -> RecipeType.CAMPFIRE_COOKING; case Stonecutting ignored -> RecipeType.STONECUTTING; - case SmithingTransform ignored -> RecipeType.SMITHING_TRANSFORM; - case SmithingTrim ignored -> RecipeType.SMITHING_TRIM; - case SpecialArmorDye ignored -> RecipeType.SPECIAL_ARMORDYE; - case SpecialBannerDuplicate ignored -> RecipeType.SPECIAL_BANNERDUPLICATE; - case SpecialBookCloning ignored -> RecipeType.SPECIAL_BOOKCLONING; - case DecoratedPot ignored -> RecipeType.DECORATED_POT; - case SpecialFireworkRocket ignored -> RecipeType.SPECIAL_FIREWORK_ROCKET; - case SpecialFireworkStar ignored -> RecipeType.SPECIAL_FIREWORK_STAR; - case SpecialFireworkStarFade ignored -> RecipeType.SPECIAL_FIREWORK_STAR_FADE; - case SpecialMapCloning ignored -> RecipeType.SPECIAL_MAPCLONING; - case SpecialMapExtending ignored -> RecipeType.SPECIAL_MAPEXTENDING; - case SpecialRepairItem ignored -> RecipeType.SPECIAL_REPAIRITEM; - case SpecialShieldDecoration ignored -> RecipeType.SPECIAL_SHIELDDECORATION; - case SpecialTippedArrow ignored -> RecipeType.SPECIAL_TIPPEDARROW; + default -> throw new IllegalStateException("Unexpected value: " + data); }; } } diff --git a/src/main/java/net/minestom/server/recipe/display/RecipeDisplay.java b/src/main/java/net/minestom/server/recipe/display/RecipeDisplay.java new file mode 100644 index 000000000..5b5bd8467 --- /dev/null +++ b/src/main/java/net/minestom/server/recipe/display/RecipeDisplay.java @@ -0,0 +1,115 @@ +package net.minestom.server.recipe.display; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public sealed interface RecipeDisplay { + @NotNull NetworkBuffer.Type NETWORK_TYPE = RecipeDisplayType.NETWORK_TYPE + .unionType(RecipeDisplay::dataSerializer, RecipeDisplay::recipeDisplayToType); + + record CraftingShapeless( + @NotNull List ingredients, + @NotNull SlotDisplay result, + @NotNull SlotDisplay craftingStation + ) implements RecipeDisplay { + private static final int MAX_INGREDIENTS = Short.MAX_VALUE; + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE.list(MAX_INGREDIENTS), CraftingShapeless::ingredients, + SlotDisplay.NETWORK_TYPE, CraftingShapeless::result, + SlotDisplay.NETWORK_TYPE, CraftingShapeless::craftingStation, + CraftingShapeless::new); + } + + record CraftingShaped( + int width, int height, + @NotNull List ingredients, + @NotNull SlotDisplay result, + @NotNull SlotDisplay craftingStation + ) implements RecipeDisplay { + private static final int MAX_INGREDIENTS = Short.MAX_VALUE; + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.VAR_INT, CraftingShaped::width, + NetworkBuffer.VAR_INT, CraftingShaped::height, + SlotDisplay.NETWORK_TYPE.list(MAX_INGREDIENTS), CraftingShaped::ingredients, + SlotDisplay.NETWORK_TYPE, CraftingShaped::result, + SlotDisplay.NETWORK_TYPE, CraftingShaped::craftingStation, + CraftingShaped::new); + + public CraftingShaped { + if (ingredients.size() != width * height) + throw new IllegalArgumentException("Invalid shaped recipe, ingredients size must be equal to width * height"); + ingredients = List.copyOf(ingredients); + } + } + + record Furnace( + @NotNull SlotDisplay ingredient, + @NotNull SlotDisplay fuel, + @NotNull SlotDisplay result, + @NotNull SlotDisplay craftingStation, + int duration, float experience + ) implements RecipeDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE, Furnace::ingredient, + SlotDisplay.NETWORK_TYPE, Furnace::fuel, + SlotDisplay.NETWORK_TYPE, Furnace::result, + SlotDisplay.NETWORK_TYPE, Furnace::craftingStation, + NetworkBuffer.VAR_INT, Furnace::duration, + NetworkBuffer.FLOAT, Furnace::experience, + Furnace::new); + } + + record Stonecutter( + @NotNull SlotDisplay ingredient, + @NotNull SlotDisplay result, + @NotNull SlotDisplay craftingStation + ) implements RecipeDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE, Stonecutter::ingredient, + SlotDisplay.NETWORK_TYPE, Stonecutter::result, + SlotDisplay.NETWORK_TYPE, Stonecutter::craftingStation, + Stonecutter::new); + } + + record Smithing( + @NotNull SlotDisplay template, + @NotNull SlotDisplay base, + @NotNull SlotDisplay addition, + @NotNull SlotDisplay result, + @NotNull SlotDisplay craftingStation + ) implements RecipeDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE, Smithing::template, + SlotDisplay.NETWORK_TYPE, Smithing::base, + SlotDisplay.NETWORK_TYPE, Smithing::addition, + SlotDisplay.NETWORK_TYPE, Smithing::result, + SlotDisplay.NETWORK_TYPE, Smithing::craftingStation, + Smithing::new); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private static NetworkBuffer.Type dataSerializer(@NotNull RecipeDisplayType type) { + return (NetworkBuffer.Type) switch (type) { + case CRAFTING_SHAPELESS -> CraftingShapeless.NETWORK_TYPE; + case CRAFTING_SHAPED -> CraftingShaped.NETWORK_TYPE; + case FURNACE -> Furnace.NETWORK_TYPE; + case STONECUTTER -> Stonecutter.NETWORK_TYPE; + case SMITHING -> Smithing.NETWORK_TYPE; + }; + } + + private static RecipeDisplayType recipeDisplayToType(@NotNull RecipeDisplay recipeDisplay) { + return switch (recipeDisplay) { + case CraftingShapeless ignored -> RecipeDisplayType.CRAFTING_SHAPELESS; + case CraftingShaped ignored -> RecipeDisplayType.CRAFTING_SHAPED; + case Furnace ignored -> RecipeDisplayType.FURNACE; + case Stonecutter ignored -> RecipeDisplayType.STONECUTTER; + case Smithing ignored -> RecipeDisplayType.SMITHING; + }; + } +} diff --git a/src/main/java/net/minestom/server/recipe/display/SlotDisplay.java b/src/main/java/net/minestom/server/recipe/display/SlotDisplay.java new file mode 100644 index 000000000..b8127f7ac --- /dev/null +++ b/src/main/java/net/minestom/server/recipe/display/SlotDisplay.java @@ -0,0 +1,108 @@ +package net.minestom.server.recipe.display; + +import net.minestom.server.item.Material; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.Unit; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public sealed interface SlotDisplay { + + @NotNull NetworkBuffer.Type NETWORK_TYPE = SlotDisplayType.NETWORK_TYPE + .unionType(SlotDisplay::dataSerializer, SlotDisplay::slotDisplayToType); + + final class Empty implements SlotDisplay { + public static final Empty INSTANCE = new Empty(); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.UNIT.transform( + buffer -> INSTANCE, empty -> Unit.INSTANCE); + + private Empty() {} + } + + final class AnyFuel implements SlotDisplay { + public static final AnyFuel INSTANCE = new AnyFuel(); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.UNIT.transform( + buffer -> INSTANCE, empty -> Unit.INSTANCE); + + private AnyFuel() {} + } + + record Item(@NotNull Material material) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Material.NETWORK_TYPE, Item::material, + Item::new); + } + + record ItemStack(@NotNull net.minestom.server.item.ItemStack itemStack) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + net.minestom.server.item.ItemStack.STRICT_NETWORK_TYPE, ItemStack::itemStack, + ItemStack::new); + } + + record Tag(@NotNull String tagKey) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.STRING, Tag::tagKey, + Tag::new); + } + + record SmithingTrim( + @NotNull SlotDisplay base, + @NotNull SlotDisplay trimMaterial, + @NotNull SlotDisplay trimPattern + ) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE, SmithingTrim::base, + SlotDisplay.NETWORK_TYPE, SmithingTrim::trimMaterial, + SlotDisplay.NETWORK_TYPE, SmithingTrim::trimPattern, + SmithingTrim::new); + } + + record WithRemainder(@NotNull SlotDisplay input, @NotNull SlotDisplay remainder) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE, WithRemainder::input, + SlotDisplay.NETWORK_TYPE, WithRemainder::remainder, + WithRemainder::new); + } + + record Composite(@NotNull List contents) implements SlotDisplay { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SlotDisplay.NETWORK_TYPE.list(), Composite::contents, + Composite::new); + + public Composite { + contents = List.copyOf(contents); + } + } + + private static NetworkBuffer.Type dataSerializer(@NotNull SlotDisplayType type) { + //noinspection unchecked + return (NetworkBuffer.Type) switch (type) { + case EMPTY -> Empty.NETWORK_TYPE; + case ANY_FUEL -> AnyFuel.NETWORK_TYPE; + case ITEM -> Item.NETWORK_TYPE; + case ITEM_STACK -> ItemStack.NETWORK_TYPE; + case TAG -> Tag.NETWORK_TYPE; + case SMITHING_TRIM -> SmithingTrim.NETWORK_TYPE; + case WITH_REMAINDER -> WithRemainder.NETWORK_TYPE; + case COMPOSITE -> Composite.NETWORK_TYPE; + }; + } + + private static SlotDisplayType slotDisplayToType(@NotNull SlotDisplay slotDisplay) { + return switch (slotDisplay) { + case Empty ignored -> SlotDisplayType.EMPTY; + case AnyFuel ignored -> SlotDisplayType.ANY_FUEL; + case Item ignored -> SlotDisplayType.ITEM; + case ItemStack ignored -> SlotDisplayType.ITEM_STACK; + case Tag ignored -> SlotDisplayType.TAG; + case SmithingTrim ignored -> SlotDisplayType.SMITHING_TRIM; + case WithRemainder ignored -> SlotDisplayType.WITH_REMAINDER; + case Composite ignored -> SlotDisplayType.COMPOSITE; + }; + } + +} From 6b541aa9d3cea1820d1c8d1d74d5ed816fa45c76 Mon Sep 17 00:00:00 2001 From: mworzala Date: Sat, 19 Oct 2024 20:31:30 -0400 Subject: [PATCH 42/97] feat: explosion & vehicle info updates --- .../net/minestom/server/entity/Player.java | 4 +- .../vehicle/PlayerVehicleInformation.java | 54 +++++++++++-------- .../minestom/server/instance/Explosion.java | 25 ++++----- .../listener/PlayerVehicleListener.java | 12 +++-- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index cc8e6c91b..5f532cf95 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -2210,8 +2210,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou return itemUpdateStateEvent; } - public void refreshVehicleSteer(float sideways, float forward, boolean jump, boolean unmount) { - this.vehicleInformation.refresh(sideways, forward, jump, unmount); + public void refreshVehicleSteer(boolean forward, boolean backward, boolean left, boolean right, boolean jump, boolean shift, boolean sprint) { + this.vehicleInformation.refresh(forward, backward, left, right, jump, shift, sprint); } /** diff --git a/src/main/java/net/minestom/server/entity/vehicle/PlayerVehicleInformation.java b/src/main/java/net/minestom/server/entity/vehicle/PlayerVehicleInformation.java index 4bce56318..13e47b3bf 100644 --- a/src/main/java/net/minestom/server/entity/vehicle/PlayerVehicleInformation.java +++ b/src/main/java/net/minestom/server/entity/vehicle/PlayerVehicleInformation.java @@ -2,39 +2,49 @@ package net.minestom.server.entity.vehicle; public class PlayerVehicleInformation { - private float sideways; - private float forward; + private boolean forward; + private boolean backward; + private boolean left; + private boolean right; private boolean jump; - private boolean unmount; + private boolean shift; + private boolean sprint; - public float getSideways() { - return sideways; - } - - public float getForward() { + public boolean forward() { return forward; } - public boolean shouldJump() { + public boolean backward() { + return backward; + } + + public boolean left() { + return left; + } + + public boolean right() { + return right; + } + + public boolean jump() { return jump; } - public boolean shouldUnmount() { - return unmount; + public boolean shift() { + return shift; } - /** - * Refresh internal data - * - * @param sideways the new sideways value - * @param forward the new forward value - * @param jump the new jump value - * @param unmount the new unmount value - */ - public void refresh(float sideways, float forward, boolean jump, boolean unmount) { - this.sideways = sideways; + public boolean sprint() { + return sprint; + } + + public void refresh(boolean forward, boolean backward, boolean left, boolean right, boolean jump, boolean shift, boolean sprint) { this.forward = forward; + this.backward = backward; + this.left = left; + this.right = right; this.jump = jump; - this.unmount = unmount; + this.shift = shift; + this.sprint = sprint; } } diff --git a/src/main/java/net/minestom/server/instance/Explosion.java b/src/main/java/net/minestom/server/instance/Explosion.java index 5a8b58b28..6061b3d43 100644 --- a/src/main/java/net/minestom/server/instance/Explosion.java +++ b/src/main/java/net/minestom/server/instance/Explosion.java @@ -1,8 +1,12 @@ package net.minestom.server.instance; import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; import net.minestom.server.network.packet.server.play.ExplosionPacket; +import net.minestom.server.particle.Particle; +import net.minestom.server.sound.SoundEvent; +import net.minestom.server.utils.PacketSendingUtils; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -56,24 +60,15 @@ public abstract class Explosion { */ public void apply(@NotNull Instance instance) { List blocks = prepare(instance); - byte[] records = new byte[3 * blocks.size()]; - for (int i = 0; i < blocks.size(); i++) { - final var pos = blocks.get(i); + for (final Point pos : blocks) { instance.setBlock(pos, Block.AIR); - final byte x = (byte) (pos.x() - Math.floor(getCenterX())); - final byte y = (byte) (pos.y() - Math.floor(getCenterY())); - final byte z = (byte) (pos.z() - Math.floor(getCenterZ())); - records[i * 3 + 0] = x; - records[i * 3 + 1] = y; - records[i * 3 + 2] = z; } - // TODO send only to close players - // TODO(1.21.2) simplified packet -// ExplosionPacket packet = new ExplosionPacket(centerX, centerY, centerZ, strength, -// records, 0, 0, 0); -// postExplosion(instance, blocks, packet); -// PacketSendingUtils.sendGroupedPacket(instance.getPlayers(), packet); + ExplosionPacket packet = new ExplosionPacket( + new Vec(centerX, centerY, centerZ), Vec.ZERO, + Particle.EXPLOSION, SoundEvent.ENTITY_GENERIC_EXPLODE); + postExplosion(instance, blocks, packet); + PacketSendingUtils.sendGroupedPacket(instance.getPlayers(), packet); postSend(instance, blocks); } diff --git a/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java b/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java index 2dd35abf3..a140c384c 100644 --- a/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerVehicleListener.java @@ -10,11 +10,13 @@ import net.minestom.server.network.packet.client.play.ClientVehicleMovePacket; public class PlayerVehicleListener { public static void steerVehicleListener(ClientSteerVehiclePacket packet, Player player) { - final byte flags = packet.flags(); - final boolean jump = (flags & 0x1) != 0; - final boolean unmount = (flags & 0x2) != 0; - // TODO(1.21.2) -// player.refreshVehicleSteer(packet.sideways(), packet.forward(), jump, unmount); + player.refreshVehicleSteer( + packet.forward(), packet.backward(), + packet.left(), packet.right(), + packet.jump(), + packet.shift(), + packet.sprint() + ); } public static void vehicleMoveListener(ClientVehicleMovePacket packet, Player player) { From efae42a45d76f2aafef47334f216a191d0a2bcc2 Mon Sep 17 00:00:00 2001 From: mworzala Date: Sat, 19 Oct 2024 23:02:24 -0400 Subject: [PATCH 43/97] feat: lots of minor fixes to item components --- .../minestom/server/entity/EquipmentSlot.java | 30 +- .../server/entity/EquipmentSlotGroup.java | 46 +- .../net/minestom/server/entity/Player.java | 3 +- .../block/predicate/BlockTypeFilter.java | 5 + .../minestom/server/item/ItemComponent.java | 12 +- .../server/item/component/AttributeList.java | 12 +- .../server/item/component/Consumable.java | 38 +- .../item/component/EnchantmentList.java | 11 +- .../server/item/component/Equippable.java | 23 +- .../server/item/component/FireworkList.java | 30 +- .../minestom/server/item/component/Food.java | 71 +--- .../item/component/JukeboxPlayable.java | 25 +- .../minestom/server/item/component/Tool.java | 56 +-- .../item/component/WritableBookContent.java | 35 +- .../server/listener/UseItemListener.java | 16 +- .../minestom/server/registry/ObjectSet.java | 8 +- .../server/registry/ObjectSetImpl.java | 26 +- .../server/utils/nbt/BinaryTagSerializer.java | 30 ++ .../server/utils/nbt/BinaryTagTemplate.java | 402 ++++++++++++++++++ .../server/entity/EntityAttributeTest.java | 28 +- .../attribute/AttributeInstanceTest.java | 4 +- .../entity/player/PlayerIntegrationTest.java | 7 +- .../player/PlayerMovementIntegrationTest.java | 265 ++++++------ .../item/component/ItemAttributeTest.java | 8 +- .../component/ItemComponentReadWriteTest.java | 100 +++++ .../server/item/component/UnitTest.java | 30 +- .../server/network/PacketWriteReadTest.java | 100 ++--- .../packet/DeclareRecipesPacketTest.java | 29 -- .../recipe/IngredientSerializationTest.java | 19 + .../java/net/minestom/testing/TestUtils.java | 1 + 30 files changed, 966 insertions(+), 504 deletions(-) create mode 100644 src/main/java/net/minestom/server/utils/nbt/BinaryTagTemplate.java create mode 100644 src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java delete mode 100644 src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java create mode 100644 src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlot.java b/src/main/java/net/minestom/server/entity/EquipmentSlot.java index 0651c2161..cc032bef7 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlot.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlot.java @@ -4,30 +4,38 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; public enum EquipmentSlot { - MAIN_HAND(false, -1), - OFF_HAND(false, -1), - BOOTS(true, BOOTS_SLOT), - LEGGINGS(true, LEGGINGS_SLOT), - CHESTPLATE(true, CHESTPLATE_SLOT), - HELMET(true, HELMET_SLOT), - BODY(false, -1); + MAIN_HAND(false, -1, "mainhand"), + OFF_HAND(false, -1, "offhand"), + BOOTS(true, BOOTS_SLOT, "feet"), + LEGGINGS(true, LEGGINGS_SLOT, "legs"), + CHESTPLATE(true, CHESTPLATE_SLOT, "chest"), + HELMET(true, HELMET_SLOT, "head"), + BODY(false, -1, "body"); private static final List ARMORS = List.of(BOOTS, LEGGINGS, CHESTPLATE, HELMET); + private static final Map BY_NBT_NAME = Arrays.stream(values()) + .collect(Collectors.toMap(EquipmentSlot::nbtName, slot -> slot)); public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(EquipmentSlot.class); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(EquipmentSlot.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.STRING.map( + BY_NBT_NAME::get, EquipmentSlot::nbtName); private final boolean armor; private final int armorSlot; + private final String nbtName; - EquipmentSlot(boolean armor, int armorSlot) { + EquipmentSlot(boolean armor, int armorSlot, String nbtName) { this.armor = armor; this.armorSlot = armorSlot; + this.nbtName = nbtName; } public boolean isHand() { @@ -42,6 +50,10 @@ public enum EquipmentSlot { return armorSlot; } + public @NotNull String nbtName() { + return nbtName; + } + public static @NotNull List<@NotNull EquipmentSlot> armors() { return ARMORS; } diff --git a/src/main/java/net/minestom/server/entity/EquipmentSlotGroup.java b/src/main/java/net/minestom/server/entity/EquipmentSlotGroup.java index 5e3a1290c..662971c69 100644 --- a/src/main/java/net/minestom/server/entity/EquipmentSlotGroup.java +++ b/src/main/java/net/minestom/server/entity/EquipmentSlotGroup.java @@ -4,27 +4,38 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; -public enum EquipmentSlotGroup { - ANY(EquipmentSlot.values()), - MAIN_HAND(EquipmentSlot.MAIN_HAND), - OFF_HAND(EquipmentSlot.OFF_HAND), - HAND(EquipmentSlot.MAIN_HAND, EquipmentSlot.OFF_HAND), - FEET(EquipmentSlot.BOOTS), - LEGS(EquipmentSlot.LEGGINGS), - CHEST(EquipmentSlot.CHESTPLATE), - HEAD(EquipmentSlot.HELMET), - ARMOR(EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS, EquipmentSlot.BOOTS, EquipmentSlot.HELMET), - BODY(EquipmentSlot.BODY); +public enum EquipmentSlotGroup implements Predicate { + ANY("any", EquipmentSlot.values()), + MAIN_HAND("mainhand", EquipmentSlot.MAIN_HAND), + OFF_HAND("offhand", EquipmentSlot.OFF_HAND), + HAND("hand", EquipmentSlot.MAIN_HAND, EquipmentSlot.OFF_HAND), + FEET("feet", EquipmentSlot.BOOTS), + LEGS("legs", EquipmentSlot.LEGGINGS), + CHEST("chest", EquipmentSlot.CHESTPLATE), + HEAD("head", EquipmentSlot.HELMET), + ARMOR("armor", EquipmentSlot.CHESTPLATE, EquipmentSlot.LEGGINGS, EquipmentSlot.BOOTS, EquipmentSlot.HELMET), + BODY("body", EquipmentSlot.BODY); + + private static final Map BY_NBT_NAME = Arrays.stream(values()) + .collect(Collectors.toMap(EquipmentSlotGroup::nbtName, Function.identity())); public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(EquipmentSlotGroup.class); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(EquipmentSlotGroup.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.STRING + .map(BY_NBT_NAME::get, EquipmentSlotGroup::nbtName); + private final String nbtName; private final List equipmentSlots; - EquipmentSlotGroup(@NotNull EquipmentSlot... equipmentSlots) { + EquipmentSlotGroup(@NotNull String nbtName, @NotNull EquipmentSlot... equipmentSlots) { this.equipmentSlots = List.of(equipmentSlots); + this.nbtName = nbtName; } /** @@ -34,10 +45,19 @@ public enum EquipmentSlotGroup { return this.equipmentSlots; } + public @NotNull String nbtName() { + return this.nbtName; + } + /** * Returns true if this attribute slot has an effect on the given {@link EquipmentSlot}, false otherwise. */ public boolean contains(@NotNull EquipmentSlot equipmentSlot) { return this.equipmentSlots.contains(equipmentSlot); } + + @Override + public boolean test(EquipmentSlot equipmentSlot) { + return this.contains(equipmentSlot); + } } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 5f532cf95..b8ed99807 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -120,7 +120,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou private static final Component REMOVE_MESSAGE = Component.text("You have been removed from the server without reason.", NamedTextColor.RED); private static final Component MISSING_REQUIRED_RESOURCE_PACK = Component.text("Required resource pack was not loaded.", NamedTextColor.RED); - // TODO(1.21.2): Should this be configurable? What does it actually do? + // This probably should be configurable (eg an instance field). However I(matt) am unclear + // on what it actually does so am holding off on adding API for this until I understand. private static final int DEFAULT_SEA_LEVEL = 63; private long lastKeepAlive; diff --git a/src/main/java/net/minestom/server/instance/block/predicate/BlockTypeFilter.java b/src/main/java/net/minestom/server/instance/block/predicate/BlockTypeFilter.java index acb8b1c99..6ad67bfbf 100644 --- a/src/main/java/net/minestom/server/instance/block/predicate/BlockTypeFilter.java +++ b/src/main/java/net/minestom/server/instance/block/predicate/BlockTypeFilter.java @@ -90,6 +90,11 @@ public sealed interface BlockTypeFilter extends Predicate permits BlockTy public @NotNull BinaryTag write(@NotNull BlockTypeFilter value) { return switch (value) { case Blocks blocks -> { + if (blocks.blocks.size() == 1) { + // Special case to match mojang serialization + yield StringBinaryTag.stringBinaryTag(blocks.blocks.get(0).name()); + } + ListBinaryTag.Builder builder = ListBinaryTag.builder(BinaryTagTypes.STRING); for (Block block : blocks.blocks) { builder.add(StringBinaryTag.stringBinaryTag(block.name())); diff --git a/src/main/java/net/minestom/server/item/ItemComponent.java b/src/main/java/net/minestom/server/item/ItemComponent.java index 7825f6620..75c9d3914 100644 --- a/src/main/java/net/minestom/server/item/ItemComponent.java +++ b/src/main/java/net/minestom/server/item/ItemComponent.java @@ -8,12 +8,15 @@ import net.minestom.server.color.Color; import net.minestom.server.color.DyeColor; import net.minestom.server.component.DataComponent; import net.minestom.server.component.DataComponentMap; +import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.item.component.*; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.ObjectSet; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.Unit; import net.minestom.server.utils.collection.ObjectArray; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -69,9 +72,9 @@ public final class ItemComponent { } }); public static final DataComponent TOOL = register("tool", Tool.NETWORK_TYPE, Tool.NBT_TYPE); - public static final DataComponent ENCHANTABLE = register("enchantable", NetworkBuffer.VAR_INT, BinaryTagSerializer.INT); + public static final DataComponent ENCHANTABLE = register("enchantable", NetworkBuffer.VAR_INT, wrapObject("value", BinaryTagSerializer.INT)); public static final DataComponent EQUIPPABLE = register("equippable", Equippable.NETWORK_TYPE, Equippable.NBT_TYPE); - public static final DataComponent> REPAIRABLE = register("repairable", Material.NETWORK_TYPE.list(Short.MAX_VALUE), Material.NBT_TYPE.list()); + public static final DataComponent> REPAIRABLE = register("repairable", ObjectSet.networkType(Tag.BasicType.ITEMS), wrapObject("items", ObjectSet.nbtType(Tag.BasicType.ITEMS))); public static final DataComponent GLIDER = register("glider", NetworkBuffer.UNIT, BinaryTagSerializer.UNIT); public static final DataComponent TOOLTIP_STYLE = register("tooltip_style", NetworkBuffer.STRING, BinaryTagSerializer.STRING); public static final DataComponent DEATH_PROTECTION = register("death_protection", DeathProtection.NETWORK_TYPE, DeathProtection.NBT_TYPE); @@ -136,6 +139,11 @@ public final class ItemComponent { return impl; } + // There are some components that are serialized to nbt as an object containing a single field, for now we just inline them here. + private static @NotNull BinaryTagSerializer wrapObject(@NotNull String fieldName, @NotNull BinaryTagSerializer serializer) { + return BinaryTagTemplate.object(fieldName, serializer, t -> t, t -> t); + } + private ItemComponent() { } } diff --git a/src/main/java/net/minestom/server/item/component/AttributeList.java b/src/main/java/net/minestom/server/item/component/AttributeList.java index c2dae4386..ab711744a 100644 --- a/src/main/java/net/minestom/server/item/component/AttributeList.java +++ b/src/main/java/net/minestom/server/item/component/AttributeList.java @@ -33,10 +33,11 @@ public record AttributeList(@NotNull List modifiers, boolean showInToo for (Modifier modifier : value.modifiers) { modifiers.add(Modifier.NBT_TYPE.write(modifier)); } - return CompoundBinaryTag.builder() - .put("modifiers", modifiers.build()) - .putBoolean("show_in_tooltip", value.showInTooltip) - .build(); + + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .put("modifiers", modifiers.build()); + if (!value.showInTooltip) builder.putBoolean("show_in_tooltip", false); + return builder.build(); } @Override @@ -58,8 +59,7 @@ public record AttributeList(@NotNull List modifiers, boolean showInToo Attribute.NETWORK_TYPE, Modifier::attribute, AttributeModifier.NETWORK_TYPE, Modifier::modifier, NetworkBuffer.Enum(EquipmentSlotGroup.class), Modifier::slot, - Modifier::new - ); + Modifier::new); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( tag -> new Modifier( Attribute.NBT_TYPE.read(tag.get("type")), diff --git a/src/main/java/net/minestom/server/item/component/Consumable.java b/src/main/java/net/minestom/server/item/component/Consumable.java index ce446973f..93846373f 100644 --- a/src/main/java/net/minestom/server/item/component/Consumable.java +++ b/src/main/java/net/minestom/server/item/component/Consumable.java @@ -1,9 +1,11 @@ package net.minestom.server.item.component; +import net.minestom.server.ServerFlag; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -12,23 +14,10 @@ public record Consumable( float consumeSeconds, @NotNull Animation animation, @NotNull SoundEvent sound, - boolean hasParticles, + boolean hasConsumeParticles, @NotNull List effects ) { - public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( - NetworkBuffer.FLOAT, Consumable::consumeSeconds, - Animation.NETWORK_TYPE, Consumable::animation, - SoundEvent.NETWORK_TYPE, Consumable::sound, - NetworkBuffer.BOOLEAN, Consumable::hasParticles, - ConsumeEffect.NETWORK_TYPE.list(Short.MAX_VALUE), Consumable::effects, - Consumable::new); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( - "consume_seconds", BinaryTagSerializer.FLOAT, Consumable::consumeSeconds, - "animation", Animation.NBT_TYPE, Consumable::animation, - "sound", SoundEvent.NBT_TYPE, Consumable::sound, - "has_particles", BinaryTagSerializer.BOOLEAN, Consumable::hasParticles, - "effects", ConsumeEffect.NBT_TYPE.list(), Consumable::effects, - Consumable::new); + public static final float DEFAULT_CONSUME_SECONDS = 1.6f; public enum Animation { NONE, @@ -45,4 +34,23 @@ public record Consumable( public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(Animation.class); public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumStringable(Animation.class); } + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.FLOAT, Consumable::consumeSeconds, + Animation.NETWORK_TYPE, Consumable::animation, + SoundEvent.NETWORK_TYPE, Consumable::sound, + NetworkBuffer.BOOLEAN, Consumable::hasConsumeParticles, + ConsumeEffect.NETWORK_TYPE.list(Short.MAX_VALUE), Consumable::effects, + Consumable::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "consume_seconds", BinaryTagSerializer.FLOAT.optional(DEFAULT_CONSUME_SECONDS), Consumable::consumeSeconds, + "animation", Animation.NBT_TYPE.optional(Animation.EAT), Consumable::animation, + "sound", SoundEvent.NBT_TYPE.optional(SoundEvent.ENTITY_GENERIC_EAT), Consumable::sound, + "has_consume_particles", BinaryTagSerializer.BOOLEAN.optional(true), Consumable::hasConsumeParticles, + "consume_effects", ConsumeEffect.NBT_TYPE.list().optional(List.of()), Consumable::effects, + Consumable::new); + + public int consumeTicks() { + return (int) (consumeSeconds * ServerFlag.SERVER_TICKS_PER_SECOND); + } } diff --git a/src/main/java/net/minestom/server/item/component/EnchantmentList.java b/src/main/java/net/minestom/server/item/component/EnchantmentList.java index 01c515940..e644ad34e 100644 --- a/src/main/java/net/minestom/server/item/component/EnchantmentList.java +++ b/src/main/java/net/minestom/server/item/component/EnchantmentList.java @@ -23,6 +23,9 @@ public record EnchantmentList(@NotNull Map, Int NetworkBuffer.BOOLEAN, EnchantmentList::showInTooltip, EnchantmentList::new ); + // TODO: this is non trivial for binary tag serializer because the root can either be {levels: {...} or {...}. + // we should support a serializer which can try multiple in order failing to the next (always writing with + // either first or last not sure). public static BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override public @NotNull BinaryTag write(@NotNull Context context, @NotNull EnchantmentList value) { @@ -31,10 +34,10 @@ public record EnchantmentList(@NotNull Map, Int levels.put(entry.getKey().name(), BinaryTagSerializer.INT.write(context, entry.getValue())); } - return CompoundBinaryTag.builder() - .put("levels", levels.build()) - .putBoolean("show_in_tooltip", value.showInTooltip) - .build(); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() + .put("levels", levels.build()); + if (!value.showInTooltip) builder.putBoolean("show_in_tooltip", false); + return builder.build(); } @Override diff --git a/src/main/java/net/minestom/server/item/component/Equippable.java b/src/main/java/net/minestom/server/item/component/Equippable.java index b7a5026ce..7de5e7f4b 100644 --- a/src/main/java/net/minestom/server/item/component/Equippable.java +++ b/src/main/java/net/minestom/server/item/component/Equippable.java @@ -1,10 +1,14 @@ package net.minestom.server.item.component; +import net.minestom.server.entity.EntityType; import net.minestom.server.entity.EquipmentSlot; +import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.registry.ObjectSet; import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -13,30 +17,29 @@ public record Equippable( @NotNull SoundEvent equipSound, @Nullable String model, @Nullable String cameraOverlay, -// @Nullable List allowedEntities, // TODO(1.21.2): this is an ObjectSet + @Nullable ObjectSet allowedEntities, boolean dispensable, boolean swappable, boolean damageOnHurt - ) { - +) { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( EquipmentSlot.NETWORK_TYPE, Equippable::slot, SoundEvent.NETWORK_TYPE, Equippable::equipSound, NetworkBuffer.STRING.optional(), Equippable::model, NetworkBuffer.STRING.optional(), Equippable::cameraOverlay, -// STRING.list().optional(), Equippable::allowedEntities, + ObjectSet.networkType(Tag.BasicType.ENTITY_TYPES).optional(), Equippable::allowedEntities, NetworkBuffer.BOOLEAN, Equippable::dispensable, NetworkBuffer.BOOLEAN, Equippable::swappable, NetworkBuffer.BOOLEAN, Equippable::damageOnHurt, Equippable::new); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( "slot", EquipmentSlot.NBT_TYPE, Equippable::slot, - "equip_sound", SoundEvent.NBT_TYPE, Equippable::equipSound, + "equip_sound", SoundEvent.NBT_TYPE.optional(SoundEvent.ITEM_ARMOR_EQUIP_GENERIC), Equippable::equipSound, "model", BinaryTagSerializer.STRING.optional(), Equippable::model, "camera_overlay", BinaryTagSerializer.STRING.optional(), Equippable::cameraOverlay, -// "allowed_entities", STRING.list().optional(), Equippable::allowedEntities, - "dispensable", BinaryTagSerializer.BOOLEAN, Equippable::dispensable, - "swappable", BinaryTagSerializer.BOOLEAN, Equippable::swappable, - "damage_on_hurt", BinaryTagSerializer.BOOLEAN, Equippable::damageOnHurt, + "allowed_entities", ObjectSet.nbtType(Tag.BasicType.ENTITY_TYPES).optional(), Equippable::allowedEntities, + "dispensable", BinaryTagSerializer.BOOLEAN.optional(true), Equippable::dispensable, + "swappable", BinaryTagSerializer.BOOLEAN.optional(true), Equippable::swappable, + "damage_on_hurt", BinaryTagSerializer.BOOLEAN.optional(true), Equippable::damageOnHurt, Equippable::new); } diff --git a/src/main/java/net/minestom/server/item/component/FireworkList.java b/src/main/java/net/minestom/server/item/component/FireworkList.java index 12ddb6790..710d5d6fd 100644 --- a/src/main/java/net/minestom/server/item/component/FireworkList.java +++ b/src/main/java/net/minestom/server/item/component/FireworkList.java @@ -1,12 +1,11 @@ package net.minestom.server.item.component; -import net.kyori.adventure.nbt.*; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; public record FireworkList(int flightDuration, @NotNull List explosions) { @@ -15,28 +14,11 @@ public record FireworkList(int flightDuration, @NotNull List public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( NetworkBuffer.VAR_INT, FireworkList::flightDuration, FireworkExplosion.NETWORK_TYPE.list(256), FireworkList::explosions, - FireworkList::new - ); - - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( - tag -> { - byte flightDuration = tag.get("flight_duration") instanceof NumberBinaryTag number ? number.byteValue() : 0; - ListBinaryTag explosionsTag = tag.getList("explosions", BinaryTagTypes.COMPOUND); - List explosions = new ArrayList<>(explosionsTag.size()); - for (BinaryTag explosionTag : explosionsTag) - explosions.add(FireworkExplosion.NBT_TYPE.read(explosionTag)); - return new FireworkList(flightDuration, explosions); - }, - value -> { - ListBinaryTag.Builder explosionsTag = ListBinaryTag.builder(); - for (FireworkExplosion explosion : value.explosions) - explosionsTag.add(FireworkExplosion.NBT_TYPE.write(explosion)); - return CompoundBinaryTag.builder() - .putInt("flight_duration", value.flightDuration) - .put("explosions", explosionsTag.build()) - .build(); - } - ); + FireworkList::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "flight_duration", BinaryTagSerializer.INT, FireworkList::flightDuration, + "explosions", FireworkExplosion.NBT_TYPE.list().optional(List.of()), FireworkList::explosions, + FireworkList::new); public FireworkList { explosions = List.copyOf(explosions); diff --git a/src/main/java/net/minestom/server/item/component/Food.java b/src/main/java/net/minestom/server/item/component/Food.java index 076828444..a6ac15f07 100644 --- a/src/main/java/net/minestom/server/item/component/Food.java +++ b/src/main/java/net/minestom/server/item/component/Food.java @@ -1,81 +1,24 @@ package net.minestom.server.item.component; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.BinaryTagTypes; -import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.minestom.server.ServerFlag; -import net.minestom.server.item.ItemStack; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; -import net.minestom.server.potion.CustomPotionEffect; import net.minestom.server.utils.nbt.BinaryTagSerializer; -import org.jetbrains.annotations.NotNull; - -import java.util.List; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import static net.minestom.server.network.NetworkBuffer.*; -public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, - @NotNull ItemStack usingConvertsTo, @NotNull List effects) { - public static final float DEFAULT_EAT_SECONDS = 1.6f; +public record Food(int nutrition, float saturationModifier, boolean canAlwaysEat) { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( VAR_INT, Food::nutrition, FLOAT, Food::saturationModifier, BOOLEAN, Food::canAlwaysEat, - FLOAT, Food::eatSeconds, - ItemStack.NETWORK_TYPE, Food::usingConvertsTo, - EffectChance.NETWORK_TYPE.list(Short.MAX_VALUE), Food::effects, + Food::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "nutrition", BinaryTagSerializer.INT, Food::nutrition, + "saturation", BinaryTagSerializer.FLOAT, Food::saturationModifier, + "can_always_eat", BinaryTagSerializer.BOOLEAN.optional(false), Food::canAlwaysEat, Food::new ); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( - tag -> new Food( - tag.getInt("nutrition"), - tag.getFloat("saturation_modifier"), - tag.getBoolean("can_always_eat"), - tag.getFloat("eat_seconds", DEFAULT_EAT_SECONDS), - tag.get("using_converts_to") instanceof BinaryTag usingConvertsTo - ? ItemStack.NBT_TYPE.read(usingConvertsTo) : ItemStack.AIR, - EffectChance.NBT_LIST_TYPE.read(tag.getList("effects", BinaryTagTypes.COMPOUND))), - value -> { - CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() - .putInt("nutrition", value.nutrition) - .putFloat("saturation_odifier", value.saturationModifier) - .putBoolean("can_always_eat", value.canAlwaysEat) - .putFloat("eat_seconds", value.eatSeconds) - .put("effects", EffectChance.NBT_LIST_TYPE.write(value.effects)); - if (!value.usingConvertsTo.isAir()) { - builder.put("using_converts_to", ItemStack.NBT_TYPE.write(value.usingConvertsTo)); - } - return builder.build(); - } - ); - - public Food { - effects = List.copyOf(effects); - } - - public int eatDurationTicks() { - return (int) (eatSeconds * ServerFlag.SERVER_TICKS_PER_SECOND); - } - - public record EffectChance(@NotNull CustomPotionEffect effect, float probability) { - public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( - CustomPotionEffect.NETWORK_TYPE, EffectChance::effect, - FLOAT, EffectChance::probability, - EffectChance::new - ); - - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.COMPOUND.map( - tag -> new EffectChance( - CustomPotionEffect.NBT_TYPE.read(tag.getCompound("effect")), - tag.getFloat("probability", 1f)), - value -> CompoundBinaryTag.builder() - .put("effect", CustomPotionEffect.NBT_TYPE.write(value.effect())) - .putFloat("probability", value.probability) - .build() - ); - public static final BinaryTagSerializer> NBT_LIST_TYPE = NBT_TYPE.list(); - } } diff --git a/src/main/java/net/minestom/server/item/component/JukeboxPlayable.java b/src/main/java/net/minestom/server/item/component/JukeboxPlayable.java index b47858a73..88f5cd4fc 100644 --- a/src/main/java/net/minestom/server/item/component/JukeboxPlayable.java +++ b/src/main/java/net/minestom/server/item/component/JukeboxPlayable.java @@ -1,12 +1,11 @@ package net.minestom.server.item.component; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.CompoundBinaryTag; import net.minestom.server.MinecraftServer; import net.minestom.server.instance.block.jukebox.JukeboxSong; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.DynamicRegistry; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -35,24 +34,10 @@ public record JukeboxPlayable(@NotNull DynamicRegistry.Key song, bo return new JukeboxPlayable(song, buffer.read(NetworkBuffer.BOOLEAN)); } }; - public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { - @Override - public @NotNull BinaryTag write(@NotNull Context context, @NotNull JukeboxPlayable value) { - return CompoundBinaryTag.builder() - .put("song", JukeboxSong.NBT_TYPE.write(context, value.song)) - .putBoolean("show_in_tooltip", value.showInTooltip) - .build(); - } - - @Override - public @NotNull JukeboxPlayable read(@NotNull Context context, @NotNull BinaryTag raw) { - if (!(raw instanceof CompoundBinaryTag tag)) throw new IllegalArgumentException("expected compound tag"); - return new JukeboxPlayable( - JukeboxSong.NBT_TYPE.read(context, tag.get("song")), - tag.getBoolean("show_in_tooltip") - ); - } - }; + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "song", JukeboxSong.NBT_TYPE, JukeboxPlayable::song, + "show_in_tooltip", BinaryTagSerializer.BOOLEAN.optional(true), JukeboxPlayable::showInTooltip, + JukeboxPlayable::new); public JukeboxPlayable(@NotNull DynamicRegistry.Key song) { this(song, true); diff --git a/src/main/java/net/minestom/server/item/component/Tool.java b/src/main/java/net/minestom/server/item/component/Tool.java index 32379f8e0..5589ef7a9 100644 --- a/src/main/java/net/minestom/server/item/component/Tool.java +++ b/src/main/java/net/minestom/server/item/component/Tool.java @@ -1,6 +1,5 @@ package net.minestom.server.item.component; -import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.ByteBinaryTag; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.FloatBinaryTag; @@ -8,6 +7,7 @@ import net.minestom.server.instance.block.predicate.BlockTypeFilter; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,54 +18,22 @@ public record Tool(@NotNull List rules, float defaultMiningSpeed, int dama public static final float DEFAULT_MINING_SPEED = 1.0f; public static final int DEFAULT_DAMAGE_PER_BLOCK = 1; - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - private static final NetworkBuffer.Type> RULE_LIST_TYPE = Rule.NETWORK_TYPE.list(Short.MAX_VALUE); - - @Override - public void write(@NotNull NetworkBuffer buffer, Tool value) { - RULE_LIST_TYPE.write(buffer, value.rules()); - buffer.write(NetworkBuffer.FLOAT, value.defaultMiningSpeed()); - buffer.write(NetworkBuffer.VAR_INT, value.damagePerBlock()); - } - - @Override - public Tool read(@NotNull NetworkBuffer buffer) { - return new Tool( - RULE_LIST_TYPE.read(buffer), - buffer.read(NetworkBuffer.FLOAT), - buffer.read(NetworkBuffer.VAR_INT) - ); - } - }; - public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { - private static final BinaryTagSerializer> RULE_LIST_TYPE = Rule.NBT_TYPE.list(); - - @Override - public @NotNull BinaryTag write(@NotNull Tool value) { - return CompoundBinaryTag.builder() - .put("rules", RULE_LIST_TYPE.write(value.rules())) - .putFloat("default_mining_speed", value.defaultMiningSpeed()) - .putInt("damage_per_block", value.damagePerBlock()) - .build(); - } - - @Override - public @NotNull Tool read(@NotNull BinaryTag tag) { - if (!(tag instanceof CompoundBinaryTag compound)) - throw new IllegalArgumentException("Expected a compound tag, got " + tag.type()); - return new Tool( - RULE_LIST_TYPE.read(Objects.requireNonNull(compound.get("rules"))), - compound.getFloat("default_mining_speed", DEFAULT_MINING_SPEED), - compound.getInt("damage_per_block", DEFAULT_DAMAGE_PER_BLOCK) - ); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + Rule.NETWORK_TYPE.list(Short.MAX_VALUE), Tool::rules, + NetworkBuffer.FLOAT, Tool::defaultMiningSpeed, + NetworkBuffer.VAR_INT, Tool::damagePerBlock, + Tool::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "rules", Rule.NBT_TYPE.list(), Tool::rules, + "default_mining_speed", BinaryTagSerializer.FLOAT.optional(DEFAULT_MINING_SPEED), Tool::defaultMiningSpeed, + "damage_per_block", BinaryTagSerializer.INT.optional(DEFAULT_DAMAGE_PER_BLOCK), Tool::damagePerBlock, + Tool::new); public record Rule(@NotNull BlockTypeFilter blocks, @Nullable Float speed, @Nullable Boolean correctForDrops) { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( BlockTypeFilter.NETWORK_TYPE, Rule::blocks, - NetworkBuffer.FLOAT, Rule::speed, + NetworkBuffer.FLOAT.optional(), Rule::speed, NetworkBuffer.BOOLEAN.optional(), Rule::correctForDrops, Rule::new ); diff --git a/src/main/java/net/minestom/server/item/component/WritableBookContent.java b/src/main/java/net/minestom/server/item/component/WritableBookContent.java index 8fab0af5f..cd1610644 100644 --- a/src/main/java/net/minestom/server/item/component/WritableBookContent.java +++ b/src/main/java/net/minestom/server/item/component/WritableBookContent.java @@ -1,15 +1,12 @@ package net.minestom.server.item.component; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.kyori.adventure.nbt.ListBinaryTag; import net.minestom.server.item.book.FilteredText; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; public record WritableBookContent(@NotNull List> pages) { @@ -17,32 +14,10 @@ public record WritableBookContent(@NotNull List> pages) { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( FilteredText.STRING_NETWORK_TYPE.list(100), WritableBookContent::pages, - WritableBookContent::new - ); - - public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { - @Override - public @NotNull BinaryTag write(@NotNull WritableBookContent value) { - ListBinaryTag.Builder pages = ListBinaryTag.builder(); - for (FilteredText page : value.pages) { - pages.add(FilteredText.STRING_NBT_TYPE.write(page)); - } - return CompoundBinaryTag.builder().put("pages", pages.build()).build(); - } - - @Override - public @NotNull WritableBookContent read(@NotNull BinaryTag tag) { - if (!(tag instanceof CompoundBinaryTag compound)) return EMPTY; - ListBinaryTag pagesTag = compound.getList("pages"); - if (pagesTag.size() == 0) return EMPTY; - - List> pages = new ArrayList<>(pagesTag.size()); - for (BinaryTag pageTag : pagesTag) { - pages.add(FilteredText.STRING_NBT_TYPE.read(pageTag)); - } - return new WritableBookContent(pages); - } - }; + WritableBookContent::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "pages", FilteredText.STRING_NBT_TYPE.list().optional(List.of()), WritableBookContent::pages, + WritableBookContent::new); public WritableBookContent { pages = List.copyOf(pages); diff --git a/src/main/java/net/minestom/server/listener/UseItemListener.java b/src/main/java/net/minestom/server/listener/UseItemListener.java index 65ba27b35..8b93ae22a 100644 --- a/src/main/java/net/minestom/server/listener/UseItemListener.java +++ b/src/main/java/net/minestom/server/listener/UseItemListener.java @@ -11,8 +11,7 @@ import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.component.Food; -import net.minestom.server.item.component.PotionContents; +import net.minestom.server.item.component.Consumable; import net.minestom.server.network.packet.client.play.ClientUseItemPacket; import net.minestom.server.network.packet.server.play.AcknowledgeBlockChangePacket; import org.jetbrains.annotations.NotNull; @@ -83,16 +82,7 @@ public class UseItemListener { } private static int defaultUseItemTime(@NotNull ItemStack itemStack) { - final Food food = itemStack.get(ItemComponent.FOOD); - if (food != null) return food.eatDurationTicks(); - else if (itemStack.material() == Material.POTION) return PotionContents.POTION_DRINK_TIME; - else if (itemStack.material() == Material.BOW - || itemStack.material() == Material.CROSSBOW - || itemStack.material() == Material.SHIELD - || itemStack.material() == Material.TRIDENT - || itemStack.material() == Material.SPYGLASS - || itemStack.material() == Material.GOAT_HORN - || itemStack.material() == Material.BRUSH) return -1; - return 0; + final Consumable consumable = itemStack.get(ItemComponent.CONSUMABLE); + return consumable != null ? consumable.consumeTicks() : 0; } } diff --git a/src/main/java/net/minestom/server/registry/ObjectSet.java b/src/main/java/net/minestom/server/registry/ObjectSet.java index 4d2ceaebe..e49beeef8 100644 --- a/src/main/java/net/minestom/server/registry/ObjectSet.java +++ b/src/main/java/net/minestom/server/registry/ObjectSet.java @@ -1,12 +1,12 @@ package net.minestom.server.registry; import net.minestom.server.gamedata.tags.Tag; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; import java.util.Collection; -import java.util.Set; /** * A set of some protocol objects. May contain a single element, multiple elements, or a single tag (which itself contains multiple elements). @@ -21,13 +21,17 @@ public sealed interface ObjectSet permits ObjectSetImp } static @NotNull ObjectSet of(@NotNull Collection entries) { - return new ObjectSetImpl.Entries<>(Set.copyOf(entries)); + return new ObjectSetImpl.Entries<>(java.util.List.copyOf(entries)); } static @NotNull ObjectSet of(@NotNull Tag tag) { return new ObjectSetImpl.Tag<>(tag); } + static NetworkBuffer.@NotNull Type> networkType(@NotNull Tag.BasicType tagType) { + return new ObjectSetImpl.NetworkType<>(tagType); + } + static @NotNull BinaryTagSerializer> nbtType(@NotNull Tag.BasicType tagType) { return new ObjectSetImpl.NbtType<>(tagType); } diff --git a/src/main/java/net/minestom/server/registry/ObjectSetImpl.java b/src/main/java/net/minestom/server/registry/ObjectSetImpl.java index 9d42bcd3a..d2684d2c4 100644 --- a/src/main/java/net/minestom/server/registry/ObjectSetImpl.java +++ b/src/main/java/net/minestom/server/registry/ObjectSetImpl.java @@ -5,11 +5,13 @@ import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.ListBinaryTag; import net.kyori.adventure.nbt.StringBinaryTag; import net.minestom.server.MinecraftServer; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import static net.kyori.adventure.nbt.StringBinaryTag.stringBinaryTag; @@ -25,10 +27,10 @@ sealed interface ObjectSetImpl extends ObjectSet pe } } - record Entries(@NotNull Set entries) implements ObjectSetImpl { + record Entries(@NotNull List entries) implements ObjectSetImpl { public Entries { - entries = Set.copyOf(entries); + entries = List.copyOf(entries); } @Override @@ -75,6 +77,20 @@ sealed interface ObjectSetImpl extends ObjectSet pe } } + record NetworkType( + @NotNull net.minestom.server.gamedata.tags.Tag.BasicType tagType + ) implements NetworkBuffer.Type> { + @Override + public void write(@NotNull NetworkBuffer buffer, ObjectSet value) { + throw new UnsupportedOperationException("todo"); + } + + @Override + public ObjectSet read(@NotNull NetworkBuffer buffer) { + throw new UnsupportedOperationException("todo"); + } + } + record NbtType( @NotNull net.minestom.server.gamedata.tags.Tag.BasicType tagType ) implements BinaryTagSerializer> { @@ -86,7 +102,7 @@ sealed interface ObjectSetImpl extends ObjectSet pe case ListBinaryTag list -> { if (list.size() == 0) yield ObjectSet.empty(); - final Set entries = new HashSet<>(list.size()); + final List entries = new ArrayList<>(list.size()); for (BinaryTag entryTag : list) { if (!(entryTag instanceof StringBinaryTag stringTag)) throw new IllegalArgumentException("Invalid entry type: " + entryTag.type()); @@ -100,7 +116,7 @@ sealed interface ObjectSetImpl extends ObjectSet pe if (value.startsWith("#")) { yield new Tag<>(tagType(), value.substring(1)); } else { - yield new Entries<>(Set.of(NamespaceID.from(value))); + yield new Entries<>(List.of(NamespaceID.from(value))); } } default -> throw new IllegalArgumentException("Invalid tag type: " + tag.type()); diff --git a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java index 9b706c5b4..b007f6ea9 100644 --- a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java +++ b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java @@ -711,4 +711,34 @@ public interface BinaryTagSerializer { } }; } + + default BinaryTagSerializer> mapValue(@NotNull BinaryTagSerializer valueType) { + return new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull Map value) { + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + for (Map.Entry entry : value.entrySet()) { + var rawKey = BinaryTagSerializer.this.write(context, entry.getKey()); + if (!(rawKey instanceof StringBinaryTag keyTag)) { + throw new IllegalArgumentException("Map key must be a string, got " + rawKey); + } + BinaryTag val = valueType.write(context, entry.getValue()); + if (val != null) builder.put(keyTag.value(), val); + } + return builder.build(); + } + + @Override + public @NotNull Map read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) return Map.of(); + Map map = new HashMap<>(); + for (Map.Entry entry : compound) { + T key = BinaryTagSerializer.this.read(context, stringBinaryTag(entry.getKey())); + V value = valueType.read(context, entry.getValue()); + map.put(key, value); + } + return Map.copyOf(map); + } + }; + } } diff --git a/src/main/java/net/minestom/server/utils/nbt/BinaryTagTemplate.java b/src/main/java/net/minestom/server/utils/nbt/BinaryTagTemplate.java new file mode 100644 index 000000000..ab5b7f771 --- /dev/null +++ b/src/main/java/net/minestom/server/utils/nbt/BinaryTagTemplate.java @@ -0,0 +1,402 @@ +package net.minestom.server.utils.nbt; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; +import java.util.function.Supplier; + +import static net.minestom.server.network.NetworkBufferTemplate.*; + +public final class BinaryTagTemplate { + + public static BinaryTagSerializer object(Supplier supplier) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return supplier.get(); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + return CompoundBinaryTag.empty(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + F1 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply(type1.read(context, tag.get(name1))); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + F2 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + F3 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + F4 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + F5 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + String name6, BinaryTagSerializer type6, Function getter6, + F6 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)), + type6.read(context, tag.get(name6)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + if ((tag = type6.write(context, getter6.apply(value))) != null) builder.put(name6, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + String name6, BinaryTagSerializer type6, Function getter6, + String name7, BinaryTagSerializer type7, Function getter7, + F7 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)), + type6.read(context, tag.get(name6)), + type7.read(context, tag.get(name7)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + if ((tag = type6.write(context, getter6.apply(value))) != null) builder.put(name6, tag); + if ((tag = type7.write(context, getter7.apply(value))) != null) builder.put(name7, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + String name6, BinaryTagSerializer type6, Function getter6, + String name7, BinaryTagSerializer type7, Function getter7, + String name8, BinaryTagSerializer type8, Function getter8, + F8 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)), + type6.read(context, tag.get(name6)), + type7.read(context, tag.get(name7)), + type8.read(context, tag.get(name8)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + if ((tag = type6.write(context, getter6.apply(value))) != null) builder.put(name6, tag); + if ((tag = type7.write(context, getter7.apply(value))) != null) builder.put(name7, tag); + if ((tag = type8.write(context, getter8.apply(value))) != null) builder.put(name8, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + String name6, BinaryTagSerializer type6, Function getter6, + String name7, BinaryTagSerializer type7, Function getter7, + String name8, BinaryTagSerializer type8, Function getter8, + String name9, BinaryTagSerializer type9, Function getter9, + F9 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)), + type6.read(context, tag.get(name6)), + type7.read(context, tag.get(name7)), + type8.read(context, tag.get(name8)), + type9.read(context, tag.get(name9)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + if ((tag = type6.write(context, getter6.apply(value))) != null) builder.put(name6, tag); + if ((tag = type7.write(context, getter7.apply(value))) != null) builder.put(name7, tag); + if ((tag = type8.write(context, getter8.apply(value))) != null) builder.put(name8, tag); + if ((tag = type9.write(context, getter9.apply(value))) != null) builder.put(name9, tag); + return builder.build(); + } + }; + } + + public static BinaryTagSerializer object( + String name1, BinaryTagSerializer type1, Function getter1, + String name2, BinaryTagSerializer type2, Function getter2, + String name3, BinaryTagSerializer type3, Function getter3, + String name4, BinaryTagSerializer type4, Function getter4, + String name5, BinaryTagSerializer type5, Function getter5, + String name6, BinaryTagSerializer type6, Function getter6, + String name7, BinaryTagSerializer type7, Function getter7, + String name8, BinaryTagSerializer type8, Function getter8, + String name9, BinaryTagSerializer type9, Function getter9, + String name10, BinaryTagSerializer type10, Function getter10, + F10 ctor + ) { + return new ObjectBase<>(){ + @Override + protected @NotNull R readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag) { + return ctor.apply( + type1.read(context, tag.get(name1)), + type2.read(context, tag.get(name2)), + type3.read(context, tag.get(name3)), + type4.read(context, tag.get(name4)), + type5.read(context, tag.get(name5)), + type6.read(context, tag.get(name6)), + type7.read(context, tag.get(name7)), + type8.read(context, tag.get(name8)), + type9.read(context, tag.get(name9)), + type10.read(context, tag.get(name10)) + ); + } + + @Override + protected @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull R value) { + BinaryTag tag; + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if ((tag = type1.write(context, getter1.apply(value))) != null) builder.put(name1, tag); + if ((tag = type2.write(context, getter2.apply(value))) != null) builder.put(name2, tag); + if ((tag = type3.write(context, getter3.apply(value))) != null) builder.put(name3, tag); + if ((tag = type4.write(context, getter4.apply(value))) != null) builder.put(name4, tag); + if ((tag = type5.write(context, getter5.apply(value))) != null) builder.put(name5, tag); + if ((tag = type6.write(context, getter6.apply(value))) != null) builder.put(name6, tag); + if ((tag = type7.write(context, getter7.apply(value))) != null) builder.put(name7, tag); + if ((tag = type8.write(context, getter8.apply(value))) != null) builder.put(name8, tag); + if ((tag = type9.write(context, getter9.apply(value))) != null) builder.put(name9, tag); + if ((tag = type10.write(context, getter10.apply(value))) != null) builder.put(name10, tag); + return builder.build(); + } + }; + } + + + // IMPLEMENTATION + + static abstract class ObjectBase implements BinaryTagSerializer { + @Override + public @NotNull T read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) { + throw new IllegalArgumentException("Expected a compound tag, got " + tag); + } + return readObject(context, compound); + } + + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull T value) { + return writeObject(context, value); + } + + protected abstract @NotNull T readObject(@NotNull Context context, @NotNull CompoundBinaryTag tag); + + protected abstract @NotNull CompoundBinaryTag writeObject(@NotNull Context context, @NotNull T value); + } +} diff --git a/src/test/java/net/minestom/server/entity/EntityAttributeTest.java b/src/test/java/net/minestom/server/entity/EntityAttributeTest.java index 2105f8be4..0edd3f641 100644 --- a/src/test/java/net/minestom/server/entity/EntityAttributeTest.java +++ b/src/test/java/net/minestom/server/entity/EntityAttributeTest.java @@ -29,19 +29,19 @@ public class EntityAttributeTest { double baseHealth = 20; double addition = 10; - double baseAmount = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(); + double baseAmount = entity.getAttribute(Attribute.MAX_HEALTH).getValue(); assertEquals(0, Double.compare(baseAmount, baseHealth)); // Avoid floating-point rounding issues ItemStack itemStack = ItemStack.builder(Material.DIAMOND).set(ItemComponent.ATTRIBUTE_MODIFIERS, - new AttributeList(new AttributeList.Modifier(Attribute.GENERIC_MAX_HEALTH, + new AttributeList(new AttributeList.Modifier(Attribute.MAX_HEALTH, new AttributeModifier(NamespaceID.from("minestom:health"), addition, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.HEAD))).build(); entity.setBoots(itemStack); - assertEquals(0, Double.compare(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth)); // No change since we are in the wrong slot + assertEquals(0, Double.compare(entity.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth)); // No change since we are in the wrong slot entity.setHelmet(itemStack); - assertEquals(0, Double.compare(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth + addition)); // Should change + assertEquals(0, Double.compare(entity.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth + addition)); // Should change entity.setHelmet(ItemStack.AIR); - assertEquals(0, Double.compare(entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth)); // Reset back to base + assertEquals(0, Double.compare(entity.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth)); // Reset back to base } @Test @@ -53,23 +53,23 @@ public class EntityAttributeTest { double baseHealth = 20; double addition = 10; - double baseAmount = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(); + double baseAmount = player.getAttribute(Attribute.MAX_HEALTH).getValue(); assertEquals(0, Double.compare(baseAmount, baseHealth)); // Avoid floating-point rounding issues ItemStack itemStack = ItemStack.builder(Material.DIAMOND).set(ItemComponent.ATTRIBUTE_MODIFIERS, - new AttributeList(new AttributeList.Modifier(Attribute.GENERIC_MAX_HEALTH, + new AttributeList(new AttributeList.Modifier(Attribute.MAX_HEALTH, new AttributeModifier(NamespaceID.from("minestom:health"), addition, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND))).build(); player.setBoots(itemStack); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth)); // No change since we are in the wrong slot + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth)); // No change since we are in the wrong slot player.setItemInMainHand(itemStack); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth + addition)); // Should change + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth + addition)); // Should change player.refreshHeldSlot((byte) 1); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth)); // Changes since the player switched the main hand item + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth)); // Changes since the player switched the main hand item player.refreshHeldSlot((byte) 0); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth + addition)); // Switched back + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth + addition)); // Switched back player.setItemInMainHand(ItemStack.AIR); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth)); + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth)); } @Test @@ -83,10 +83,10 @@ public class EntityAttributeTest { // Don't compare against base health first (that will initialize the attribute, and we want to make sure we don't error when we add an item with attribute modifiers) ItemStack itemStack = ItemStack.builder(Material.DIAMOND).set(ItemComponent.ATTRIBUTE_MODIFIERS, - new AttributeList(new AttributeList.Modifier(Attribute.GENERIC_MAX_HEALTH, + new AttributeList(new AttributeList.Modifier(Attribute.MAX_HEALTH, new AttributeModifier(NamespaceID.from("minestom:health"), addition, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND))).build(); player.setItemInMainHand(itemStack); - assertEquals(0, Double.compare(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(), baseHealth + addition)); + assertEquals(0, Double.compare(player.getAttribute(Attribute.MAX_HEALTH).getValue(), baseHealth + addition)); } } diff --git a/src/test/java/net/minestom/server/entity/attribute/AttributeInstanceTest.java b/src/test/java/net/minestom/server/entity/attribute/AttributeInstanceTest.java index 04a113ece..fa7c63954 100644 --- a/src/test/java/net/minestom/server/entity/attribute/AttributeInstanceTest.java +++ b/src/test/java/net/minestom/server/entity/attribute/AttributeInstanceTest.java @@ -8,7 +8,7 @@ public class AttributeInstanceTest { @Test void testReplaceAttributeSameValue() { - var attribute = new AttributeInstance(Attribute.GENERIC_SAFE_FALL_DISTANCE, null); + var attribute = new AttributeInstance(Attribute.SAFE_FALL_DISTANCE, null); var modifier = new AttributeModifier("test", 1.0, AttributeOperation.ADD_VALUE); attribute.addModifier(modifier); @@ -20,7 +20,7 @@ public class AttributeInstanceTest { @Test void testReplaceAttributeNewValue() { - var attribute = new AttributeInstance(Attribute.GENERIC_SAFE_FALL_DISTANCE, null); + var attribute = new AttributeInstance(Attribute.SAFE_FALL_DISTANCE, null); attribute.addModifier(new AttributeModifier("test", 1.0, AttributeOperation.ADD_VALUE)); assertEquals(4, attribute.getValue()); diff --git a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java index daead97a7..2f527f3a4 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java @@ -81,7 +81,8 @@ public class PlayerIntegrationTest { Locale.US, (byte) 16, ChatMessageType.FULL, true, (byte) 127, ClientSettings.MainHand.LEFT, - true, true + true, true, + ClientSettings.ParticleSetting.ALL )); var instance = env.createFlatInstance(); @@ -106,7 +107,9 @@ public class PlayerIntegrationTest { "EntityMetaDataPacket has the incorrect hand after client settings update."); found = true; } - Assertions.assertTrue(found, "EntityMetaDataPacket not sent after client settings update."); + assertTrue(found, "EntityMetaDataPacket not sent after client settings update."); + + assertEquals(ClientSettings.ParticleSetting.ALL, player.getSettings().particleSetting()); } private void assertAbilities(Player player, boolean isInvulnerable, boolean isFlying, boolean isAllowFlying, diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index 200a151e4..b0d3ae223 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -1,33 +1,11 @@ package net.minestom.server.entity.player; -import net.minestom.server.ServerFlag; -import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.Player; -import net.minestom.server.instance.Chunk; -import net.minestom.server.instance.Instance; -import net.minestom.server.message.ChatMessageType; -import net.minestom.server.network.packet.client.common.ClientSettingsPacket; -import net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket; -import net.minestom.server.network.packet.client.play.ClientTeleportConfirmPacket; -import net.minestom.server.network.packet.server.play.ChunkDataPacket; -import net.minestom.server.network.packet.server.play.EntityPositionPacket; -import net.minestom.server.network.packet.server.play.UnloadChunkPacket; -import net.minestom.server.network.player.ClientSettings; -import net.minestom.server.utils.MathUtils; -import net.minestom.testing.Collector; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; -import net.minestom.testing.TestConnection; import org.junit.jupiter.api.Test; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; @EnvTest public class PlayerMovementIntegrationTest { @@ -37,140 +15,145 @@ public class PlayerMovementIntegrationTest { var instance = env.createFlatInstance(); var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); // No confirmation - p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); - p1.interpretPacketQueue(); - assertEquals(new Pos(0, 40, 0), p1.getPosition()); - // Confirmation - p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); - p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); - p1.interpretPacketQueue(); - assertEquals(new Pos(0.2, 40, 0), p1.getPosition()); +// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); +// p1.interpretPacketQueue(); +// assertEquals(new Pos(0, 40, 0), p1.getPosition()); +// // Confirmation +// p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); +// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); +// p1.interpretPacketQueue(); +// assertEquals(new Pos(0.2, 40, 0), p1.getPosition()); + fail("TODO(1.21.2) position packet change"); } // FIXME //@Test public void singleTickMovementUpdate(Env env) { - var instance = env.createFlatInstance(); - var connection = env.createConnection(); - var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); - connection.connect(instance, new Pos(0, 40, 0)); - - p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); - p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); - p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true)); - var tracker = connection.trackIncoming(EntityPositionPacket.class); - p1.interpretPacketQueue(); - - // Position update should only be sent once per tick independently of the number of packets - tracker.assertSingle(); +// var instance = env.createFlatInstance(); +// var connection = env.createConnection(); +// var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); +// connection.connect(instance, new Pos(0, 40, 0)); +// +// p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); +// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); +// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true)); +// var tracker = connection.trackIncoming(EntityPositionPacket.class); +// p1.interpretPacketQueue(); +// +// // Position update should only be sent once per tick independently of the number of packets +// tracker.assertSingle(); + fail("TODO(1.21.2) position packet change"); } @Test public void chunkUpdateDebounceTest(Env env) { - final Instance flatInstance = env.createFlatInstance(); - final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; - // Preload all possible chunks to avoid issues due to async loading - Set> chunks = new HashSet<>(); - ChunkRange.chunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); - CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); - final TestConnection connection = env.createConnection(); - Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - final Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); - // Initial join - chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); - player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertCount(viewDiameter); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertCount(viewDiameter); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertCount(viewDiameter); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertEmpty(); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertEmpty(); - - // Move to next chunk - chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - // Abuse the fact that there is no delta check - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1); +// final Instance flatInstance = env.createFlatInstance(); +// final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; +// // Preload all possible chunks to avoid issues due to async loading +// Set> chunks = new HashSet<>(); +// ChunkRange.chunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); +// CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); +// final TestConnection connection = env.createConnection(); +// Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// final Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); +// // Initial join +// chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); +// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertCount(viewDiameter); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertCount(viewDiameter); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertCount(viewDiameter); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertEmpty(); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertEmpty(); +// +// // Move to next chunk +// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// // Abuse the fact that there is no delta check +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1); + fail("TODO(1.21.2) position packet change"); } @Test public void testClientViewDistanceSettings(Env env) { - int viewDistance = 4; - final Instance flatInstance = env.createFlatInstance(); - var connection = env.createConnection(); - Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); - // Preload all possible chunks to avoid issues due to async loading - Set> chunks = new HashSet<>(); - ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); - CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); - player.refreshSettings(new ClientSettings( - Locale.US, (byte) viewDistance, - ChatMessageType.FULL, true, - (byte) 0, ClientSettings.MainHand.RIGHT, - false, true - )); - - Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); - player.teleport(new Pos(160, 40, 160)); - player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); - player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(160.5, 40, 160.5), true)); - player.interpretPacketQueue(); - chunkDataPacketCollector.assertCount(MathUtils.square(viewDistance * 2 + 1)); +// int viewDistance = 4; +// final Instance flatInstance = env.createFlatInstance(); +// var connection = env.createConnection(); +// Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); +// // Preload all possible chunks to avoid issues due to async loading +// Set> chunks = new HashSet<>(); +// ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); +// CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); +// player.refreshSettings(new ClientSettings( +// Locale.US, (byte) viewDistance, +// ChatMessageType.FULL, true, +// (byte) 0, ClientSettings.MainHand.RIGHT, +// false, true +// )); +// +// Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); +// player.teleport(new Pos(160, 40, 160)); +// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); +// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(160.5, 40, 160.5), true)); +// player.interpretPacketQueue(); +// chunkDataPacketCollector.assertCount(MathUtils.square(viewDistance * 2 + 1)); + fail("TODO(1.21.2) position packet change"); } @Test public void testSettingsViewDistanceExpansionAndShrink(Env env) { - int startingViewDistance = 8; - byte endViewDistance = 12; - byte finalViewDistance = 10; - var instance = env.createFlatInstance(); - var connection = env.createConnection(); - Pos startingPlayerPos = new Pos(0, 42, 0); - var player = connection.connect(instance, startingPlayerPos); - - int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); - - // Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread - ChunkRange.chunksInRange(0, 0, endViewDistance, instance::loadChunk); - - var tracker = connection.trackIncoming(ChunkDataPacket.class); - player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, - ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); - player.interpretPacketQueue(); - tracker.assertCount(chunkDifference); - - var tracker1 = connection.trackIncoming(UnloadChunkPacket.class); - player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, finalViewDistance, - ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); - player.interpretPacketQueue(); - - int chunkDifference1 = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(finalViewDistance); - tracker1.assertCount(chunkDifference1); +// int startingViewDistance = 8; +// byte endViewDistance = 12; +// byte finalViewDistance = 10; +// var instance = env.createFlatInstance(); +// var connection = env.createConnection(); +// Pos startingPlayerPos = new Pos(0, 42, 0); +// var player = connection.connect(instance, startingPlayerPos); +// +// int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); +// +// // Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread +// ChunkRange.chunksInRange(0, 0, endViewDistance, instance::loadChunk); +// +// var tracker = connection.trackIncoming(ChunkDataPacket.class); +// player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, +// ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); +// player.interpretPacketQueue(); +// tracker.assertCount(chunkDifference); +// +// var tracker1 = connection.trackIncoming(UnloadChunkPacket.class); +// player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, finalViewDistance, +// ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); +// player.interpretPacketQueue(); +// +// int chunkDifference1 = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(finalViewDistance); +// tracker1.assertCount(chunkDifference1); + fail("TODO(1.21.2) position packet change"); } } diff --git a/src/test/java/net/minestom/server/item/component/ItemAttributeTest.java b/src/test/java/net/minestom/server/item/component/ItemAttributeTest.java index e99fb7241..45d1444f9 100644 --- a/src/test/java/net/minestom/server/item/component/ItemAttributeTest.java +++ b/src/test/java/net/minestom/server/item/component/ItemAttributeTest.java @@ -21,11 +21,11 @@ public class ItemAttributeTest extends AbstractItemComponentTest protected @NotNull List> directReadWriteEntries() { return List.of( Map.entry("empty", AttributeList.EMPTY), - Map.entry("single", new AttributeList(new AttributeList.Modifier(Attribute.GENERIC_MOVEMENT_SPEED, new AttributeModifier("minestom:movement_test", 0.1, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND))), + Map.entry("single", new AttributeList(new AttributeList.Modifier(Attribute.MOVEMENT_SPEED, new AttributeModifier("minestom:movement_test", 0.1, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND))), Map.entry("multiple", new AttributeList(List.of( - new AttributeList.Modifier(Attribute.GENERIC_MAX_HEALTH, new AttributeModifier("minestom:health_test", 5, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND), - new AttributeList.Modifier(Attribute.GENERIC_ATTACK_DAMAGE, new AttributeModifier("minestom:attack_test", 3, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.ANY), - new AttributeList.Modifier(Attribute.GENERIC_ATTACK_DAMAGE, new AttributeModifier("minestom:attack_test_1", 1.4, AttributeOperation.MULTIPLY_BASE), EquipmentSlotGroup.CHEST) + new AttributeList.Modifier(Attribute.MAX_HEALTH, new AttributeModifier("minestom:health_test", 5, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.MAIN_HAND), + new AttributeList.Modifier(Attribute.ATTACK_DAMAGE, new AttributeModifier("minestom:attack_test", 3, AttributeOperation.ADD_VALUE), EquipmentSlotGroup.ANY), + new AttributeList.Modifier(Attribute.ATTACK_DAMAGE, new AttributeModifier("minestom:attack_test_1", 1.4, AttributeOperation.MULTIPLY_BASE), EquipmentSlotGroup.CHEST) ))) ); diff --git a/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java b/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java new file mode 100644 index 000000000..786d1664b --- /dev/null +++ b/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java @@ -0,0 +1,100 @@ +package net.minestom.server.item.component; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.kyori.adventure.nbt.TagStringIOExt; +import net.minestom.server.MinecraftServer; +import net.minestom.server.component.DataComponent; +import net.minestom.server.item.ItemComponent; +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; + +import static java.util.Map.entry; +import static org.junit.jupiter.api.Assertions.*; + +public class ItemComponentReadWriteTest { + private static final Gson GSON = new Gson(); + + private static final BinaryTagSerializer.Context CONTEXT; + + static { + MinecraftServer.init(); + CONTEXT = new BinaryTagSerializer.ContextWithRegistries(MinecraftServer.process()); + } + + // This test will go through all of the default components present on vanilla items and make sure that we are + // capable of reading/writing them correctly. This will help to find cases where fields have changed in case + // they are otherwise missed. + // Notably this does not test every component because they are not all used in vanilla, let alone on default items. + // + // Additional entries can be added by appending them to the following list: + private static final Map EXTRA_CASES = Map.ofEntries( + entry("minecraft:glider", "{}") + ); + + @Test + public void testReadWrite() throws IOException { + var componentEntries = new ArrayList<>(EXTRA_CASES.entrySet()); + try (InputStream is = ItemComponentReadWriteTest.class.getResourceAsStream("/items.json")) { + Check.notNull(is, "items.json not found"); + + var object = GSON.fromJson(new InputStreamReader(is), JsonObject.class); + for (var itemEntry : object.entrySet()) { + for (var componentEntry : itemEntry.getValue().getAsJsonObject().getAsJsonObject("components").entrySet()) { + componentEntries.add(entry(componentEntry.getKey(), componentEntry.getValue().getAsString())); + } + } + } + + assertAll(componentEntries.stream().map(entry -> () -> { + var component = ItemComponent.fromNamespaceId(entry.getKey()); + assertNotNull(component, "Component not found: " + entry.getKey()); + //noinspection unchecked + readWriteTestImpl((DataComponent) component, entry.getValue()); + })); + } + + private static void readWriteTestImpl(@NotNull DataComponent component, @NotNull String input) { + if (Objects.equals(ItemComponent.DAMAGE_RESISTANT, component) || Objects.equals(ItemComponent.CONSUMABLE, component) || Objects.equals(ItemComponent.DEATH_PROTECTION, component)) + return; + try { + var nbt = TagStringIOExt.readTag(input); + var value = component.read(CONTEXT, nbt); + var actual = component.write(CONTEXT, value); + + // Need to rewrite because adventure formats slightly different from vanilla. + var expected = nbt; + assertEquals(expected, actual, () -> "\n--- " + component.name() +" (NBT) ---\n" + + "EXP: " + TagStringIOExt.writeTag(expected) + "\n" + + "ACT: " + TagStringIOExt.writeTag(actual)); + + if (component.isSynced()) { + try { + var buffer = NetworkBuffer.resizableBuffer(MinecraftServer.process()); + component.write(buffer, value); + var comp2 = component.read(buffer); + var expected2 = component.write(CONTEXT, comp2); + assertEquals(expected2, actual, () -> "\n--- " + component.name() +" (NETWORK) ---\n" + + "EXP: " + TagStringIOExt.writeTag(expected2) + "\n" + + "ACT: " + TagStringIOExt.writeTag(actual)); + } catch (UnsupportedOperationException ignored) { + //todo + } + } + } catch (Exception e) { + throw new AssertionError(component.name() + " failed on \"" + input + "\"", e); + } + + } +} + diff --git a/src/test/java/net/minestom/server/item/component/UnitTest.java b/src/test/java/net/minestom/server/item/component/UnitTest.java index 783738f7f..e0a5f7e8c 100644 --- a/src/test/java/net/minestom/server/item/component/UnitTest.java +++ b/src/test/java/net/minestom/server/item/component/UnitTest.java @@ -2,13 +2,17 @@ package net.minestom.server.item.component; import net.minestom.server.component.DataComponent; import net.minestom.server.item.ItemComponent; +import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.Unit; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import java.util.Map; import static java.util.Map.entry; +import static org.junit.jupiter.api.Assertions.fail; public class UnitTest extends AbstractItemComponentTest { // This is not a test, but it creates a compile error if the component type is changed away from Unit, @@ -18,7 +22,7 @@ public class UnitTest extends AbstractItemComponentTest { ItemComponent.HIDE_TOOLTIP, ItemComponent.CREATIVE_SLOT_LOCK, ItemComponent.INTANGIBLE_PROJECTILE, - ItemComponent.FIRE_RESISTANT + ItemComponent.GLIDER ); @Override @@ -32,4 +36,28 @@ public class UnitTest extends AbstractItemComponentTest { entry("instance", Unit.INSTANCE) ); } + + @Test + public void ensureUnitComponentsPresent() { + var fails = new ArrayList(); + for (var component : ItemComponent.values()) { + if (!component.isSynced()) continue; + + // Try to write as a Unit and if it fails we can ignore that type + try { + //noinspection unchecked + ((DataComponent) component).write(NetworkBuffer.resizableBuffer(), Unit.INSTANCE); + } catch (ClassCastException ignored) { + continue; + } + + if (!UNIT_COMPONENTS.contains(component)) { + fails.add(component.name()); + } + } + + if (!fails.isEmpty()) { + fail("Some components are not included in UnitTest: " + fails); + } + } } diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index 9a1b40a68..a43167a18 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -22,8 +22,6 @@ import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.status.ResponsePacket; import net.minestom.server.network.player.GameProfile; -import net.minestom.server.recipe.Recipe; -import net.minestom.server.recipe.RecipeCategory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -33,6 +31,7 @@ import java.util.Map; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; /** * Ensures that packet can be written and read correctly. @@ -54,7 +53,7 @@ public class PacketWriteReadTest { //SERVER_PACKETS.add(new EncryptionRequestPacket("server", generateByteArray(16), generateByteArray(16))); SERVER_PACKETS.add(new LoginDisconnectPacket(COMPONENT)); //SERVER_PACKETS.add(new LoginPluginRequestPacket(5, "id", generateByteArray(16))); - SERVER_PACKETS.add(new LoginSuccessPacket(new GameProfile(UUID.randomUUID(), "TheMode911"), false)); + SERVER_PACKETS.add(new LoginSuccessPacket(new GameProfile(UUID.randomUUID(), "TheMode911"))); SERVER_PACKETS.add(new SetCompressionPacket(256)); // Play SERVER_PACKETS.add(new AcknowledgeBlockChangePacket(0)); @@ -78,47 +77,48 @@ public class PacketWriteReadTest { SERVER_PACKETS.add(new CollectItemPacket(5, 5, 5)); SERVER_PACKETS.add(new PlaceGhostRecipePacket((byte) 2, "recipe")); SERVER_PACKETS.add(new DeathCombatEventPacket(5, COMPONENT)); - SERVER_PACKETS.add(new DeclareRecipesPacket( - List.of(new Recipe( - "minecraft:sticks", - new Recipe.Shapeless("sticks", RecipeCategory.Crafting.MISC, - List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.OAK_PLANKS)))), - ItemStack.of(Material.STICK)) - ), - new Recipe( - "minecraft:torch", - new Recipe.Shaped("", - RecipeCategory.Crafting.MISC, - 1, - 2, - List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), - new Recipe.Ingredient(List.of(ItemStack.of(Material.STICK)))), - ItemStack.of(Material.TORCH), - true) - ), - new Recipe( - "minecraft:coal", - new Recipe.Blasting("forging", - RecipeCategory.Cooking.MISC, - new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), - ItemStack.of(Material.IRON_INGOT), - 5, - 5) - ), - new Recipe( - "minecraft:iron_to_diamond", - new Recipe.SmithingTransform(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), - new Recipe.Ingredient(List.of(ItemStack.of(Material.DIAMOND))), - new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - ItemStack.of(Material.DIAMOND)) - ), - new Recipe( - "minecraft:iron_to_coast", - new Recipe.SmithingTrim(new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), - new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), - new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL)))) - ) - ))); +// SERVER_PACKETS.add(new DeclareRecipesPacket( +// List.of(new Recipe( +// "minecraft:sticks", +// new Recipe.Shapeless("sticks", RecipeCategory.Crafting.MISC, +// List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.OAK_PLANKS)))), +// ItemStack.of(Material.STICK)) +// ), +// new Recipe( +// "minecraft:torch", +// new Recipe.Shaped("", +// RecipeCategory.Crafting.MISC, +// 1, +// 2, +// List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), +// new Recipe.Ingredient(List.of(ItemStack.of(Material.STICK)))), +// ItemStack.of(Material.TORCH), +// true) +// ), +// new Recipe( +// "minecraft:coal", +// new Recipe.Blasting("forging", +// RecipeCategory.Cooking.MISC, +// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), +// ItemStack.of(Material.IRON_INGOT), +// 5, +// 5) +// ), +// new Recipe( +// "minecraft:iron_to_diamond", +// new Recipe.SmithingTransform(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), +// new Recipe.Ingredient(List.of(ItemStack.of(Material.DIAMOND))), +// new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), +// ItemStack.of(Material.DIAMOND)) +// ), +// new Recipe( +// "minecraft:iron_to_coast", +// new Recipe.SmithingTrim(new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), +// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), +// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL)))) +// ) +// ))); + fail("TODO(1.21.2) recipe packet change"); SERVER_PACKETS.add(new DestroyEntitiesPacket(List.of(5, 5, 5))); SERVER_PACKETS.add(new DisconnectPacket(COMPONENT)); @@ -140,15 +140,17 @@ public class PacketWriteReadTest { List prop = List.of(new PlayerInfoUpdatePacket.Property("textures", skin.textures(), skin.signature())); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.ADD_PLAYER, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "TheMode911", prop, false, 0, GameMode.SURVIVAL, null, null))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "TheMode911", prop, false, 0, GameMode.SURVIVAL, null, null, 0))); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 0, GameMode.SURVIVAL, Component.text("NotTheMode911"), null))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 0, GameMode.SURVIVAL, Component.text("NotTheMode911"), null, 0))); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 0, GameMode.CREATIVE, null, null))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 0, GameMode.CREATIVE, null, null, 0))); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 20, GameMode.SURVIVAL, null, null))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 20, GameMode.SURVIVAL, null, null, 0))); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LISTED, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), true, 0, GameMode.SURVIVAL, null, null))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), true, 0, GameMode.SURVIVAL, null, null, 0))); + SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LIST_ORDER, + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), true, 0, GameMode.SURVIVAL, null, null, 42))); SERVER_PACKETS.add(new PlayerInfoRemovePacket(UUID.randomUUID())); } diff --git a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java b/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java deleted file mode 100644 index f3245fd96..000000000 --- a/src/test/java/net/minestom/server/network/packet/DeclareRecipesPacketTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.minestom.server.network.packet; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.minestom.server.network.NetworkBuffer; -import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; -import net.minestom.server.recipe.Recipe; -import net.minestom.server.recipe.RecipeCategory; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class DeclareRecipesPacketTest { - - @Test - public void cannotWriteAirIngredient() { - var packet = new DeclareRecipesPacket(List.of( - new Recipe( - "recipe1", - new Recipe.Shapeless("group1", RecipeCategory.Crafting.BUILDING, - List.of(new Recipe.Ingredient(List.of(ItemStack.AIR))), - ItemStack.of(Material.DIAMOND)) - ) - )); - assertThrows(IllegalArgumentException.class, () -> NetworkBuffer.makeArray(DeclareRecipesPacket.SERIALIZER, packet)); - } -} diff --git a/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java b/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java new file mode 100644 index 000000000..f05d9f037 --- /dev/null +++ b/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java @@ -0,0 +1,19 @@ +package net.minestom.server.recipe; + +import net.minestom.server.item.ItemStack; +import net.minestom.server.network.NetworkBuffer; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class IngredientSerializationTest { + + @Test + public void cannotWriteAirIngredient() { + var ingredient = new Recipe.Ingredient(List.of(ItemStack.AIR)); + assertThrows(IllegalArgumentException.class, () -> + NetworkBuffer.makeArray(RecipeSerializers.INGREDIENT, ingredient)); + } +} diff --git a/testing/src/main/java/net/minestom/testing/TestUtils.java b/testing/src/main/java/net/minestom/testing/TestUtils.java index 0ccf73176..b7f218602 100644 --- a/testing/src/main/java/net/minestom/testing/TestUtils.java +++ b/testing/src/main/java/net/minestom/testing/TestUtils.java @@ -63,4 +63,5 @@ public final class TestUtils { } return formattedString.toString().trim(); } + } From 5e71adffa6e63ae159f76fc3869a0160ddd3a0ee Mon Sep 17 00:00:00 2001 From: mworzala Date: Sat, 19 Oct 2024 23:48:31 -0400 Subject: [PATCH 44/97] feat: ConsumeEffect impl & enum nbt type generation --- .../java/net/minestom/codegen/Generators.java | 2 + .../codegen/util/GenericEnumGenerator.java | 15 ++- .../item/component/ConsumeEffectType.java | 43 +++++++ .../server/recipe/RecipeBookCategory.java | 3 + .../minestom/server/recipe/RecipeType.java | 3 + .../recipe/display/RecipeDisplayType.java | 3 + .../recipe/display/SlotDisplayType.java | 3 + .../minestom/server/gamedata/tags/Tag.java | 2 +- .../minestom/server/item/ItemComponent.java | 17 +-- .../server/item/component/Consumable.java | 2 +- .../server/item/component/ConsumeEffect.java | 120 +++++++++++++++++- .../item/component/DamageResistant.java | 16 +++ .../item/component/DeathProtection.java | 5 +- .../server/potion/CustomPotionEffect.java | 14 +- .../server/utils/nbt/BinaryTagSerializer.java | 49 +++++++ .../component/ItemComponentReadWriteTest.java | 3 - 16 files changed, 263 insertions(+), 37 deletions(-) create mode 100644 src/autogenerated/java/net/minestom/server/item/component/ConsumeEffectType.java create mode 100644 src/main/java/net/minestom/server/item/component/DamageResistant.java diff --git a/code-generators/src/main/java/net/minestom/codegen/Generators.java b/code-generators/src/main/java/net/minestom/codegen/Generators.java index 59223e231..cc8229009 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -32,6 +32,8 @@ public class Generators { resource("slot_display_types.json"), outputFolder).generate(); new GenericEnumGenerator("net.minestom.server.recipe", "RecipeBookCategory", resource("recipe_book_categories.json"), outputFolder).generate(); + new GenericEnumGenerator("net.minestom.server.item.component", "ConsumeEffectType", + resource("consume_effects.json"), outputFolder).packagePrivate().generate(); var generator = new CodeGenerator(outputFolder); diff --git a/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java b/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java index b5529895e..284ec8474 100644 --- a/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java +++ b/code-generators/src/main/java/net/minestom/codegen/util/GenericEnumGenerator.java @@ -26,6 +26,8 @@ public class GenericEnumGenerator extends MinestomCodeGenerator { private final InputStream entriesFile; private final File outputFolder; + private boolean isPackagePrivate = false; + public GenericEnumGenerator( @NotNull String packageName, @NotNull String className, @Nullable InputStream entriesFile, @NotNull File outputFolder @@ -36,6 +38,11 @@ public class GenericEnumGenerator extends MinestomCodeGenerator { this.outputFolder = outputFolder; } + public GenericEnumGenerator packagePrivate() { + this.isPackagePrivate = true; + return this; + } + @Override public void generate() { if (entriesFile == null) { @@ -51,13 +58,16 @@ public class GenericEnumGenerator extends MinestomCodeGenerator { // Important classes we use alot JsonArray entryList = GSON.fromJson(new InputStreamReader(entriesFile), JsonArray.class); ClassName entryCN = ClassName.get(packageName, className); + Modifier[] modifiers = isPackagePrivate ? new Modifier[0] : new Modifier[]{Modifier.PUBLIC}; TypeSpec.Builder entryEnum = TypeSpec.enumBuilder(entryCN) .addSuperinterface(ClassName.get("net.minestom.server.registry", "StaticProtocolObject")) - .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); + .addModifiers(modifiers).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); ClassName namespaceIdCN = ClassName.get("net.minestom.server.utils", "NamespaceID"); ClassName networkBufferCN = ClassName.get("net.minestom.server.network", "NetworkBuffer"); ParameterizedTypeName networkBufferTypeCN = ParameterizedTypeName.get(networkBufferCN.nestedClass("Type"), entryCN); + ClassName binaryTagSerializerRawCN = ClassName.get("net.minestom.server.utils.nbt", "BinaryTagSerializer"); + ParameterizedTypeName binaryTagSerializerCN = ParameterizedTypeName.get(binaryTagSerializerRawCN, entryCN); // Fields entryEnum.addFields( @@ -65,6 +75,9 @@ public class GenericEnumGenerator extends MinestomCodeGenerator { FieldSpec.builder(networkBufferTypeCN, "NETWORK_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) .initializer("$T.Enum($T.class)", networkBufferCN, entryCN) .build(), + FieldSpec.builder(binaryTagSerializerCN, "NBT_TYPE", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer("$T.fromEnumKeyed($T.class)", binaryTagSerializerRawCN, entryCN) + .build(), FieldSpec.builder(namespaceIdCN, "namespace", Modifier.PRIVATE, Modifier.FINAL).build() ) ); diff --git a/src/autogenerated/java/net/minestom/server/item/component/ConsumeEffectType.java b/src/autogenerated/java/net/minestom/server/item/component/ConsumeEffectType.java new file mode 100644 index 000000000..33572cbdf --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/item/component/ConsumeEffectType.java @@ -0,0 +1,43 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.NotNull; + +/** + * AUTOGENERATED by GenericEnumGenerator + */ +enum ConsumeEffectType implements StaticProtocolObject { + APPLY_EFFECTS(NamespaceID.from("minecraft:apply_effects")), + + REMOVE_EFFECTS(NamespaceID.from("minecraft:remove_effects")), + + CLEAR_ALL_EFFECTS(NamespaceID.from("minecraft:clear_all_effects")), + + TELEPORT_RANDOMLY(NamespaceID.from("minecraft:teleport_randomly")), + + PLAY_SOUND(NamespaceID.from("minecraft:play_sound")); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(ConsumeEffectType.class); + + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(ConsumeEffectType.class); + + private final NamespaceID namespace; + + ConsumeEffectType(@NotNull NamespaceID namespace) { + this.namespace = namespace; + } + + @NotNull + @Override + public NamespaceID namespace() { + return this.namespace; + } + + @Override + public int id() { + return this.ordinal(); + } +} diff --git a/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java b/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java index 42154de0d..e8f176bef 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java +++ b/src/autogenerated/java/net/minestom/server/recipe/RecipeBookCategory.java @@ -3,6 +3,7 @@ package net.minestom.server.recipe; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; /** @@ -37,6 +38,8 @@ public enum RecipeBookCategory implements StaticProtocolObject { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeBookCategory.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(RecipeBookCategory.class); + private final NamespaceID namespace; RecipeBookCategory(@NotNull NamespaceID namespace) { diff --git a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java index f931fd63f..75429bdc9 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java +++ b/src/autogenerated/java/net/minestom/server/recipe/RecipeType.java @@ -3,6 +3,7 @@ package net.minestom.server.recipe; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; /** @@ -25,6 +26,8 @@ public enum RecipeType implements StaticProtocolObject { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeType.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(RecipeType.class); + private final NamespaceID namespace; RecipeType(@NotNull NamespaceID namespace) { diff --git a/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java b/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java index ecb7d1da2..8f39c1624 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java +++ b/src/autogenerated/java/net/minestom/server/recipe/display/RecipeDisplayType.java @@ -3,6 +3,7 @@ package net.minestom.server.recipe.display; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; /** @@ -21,6 +22,8 @@ public enum RecipeDisplayType implements StaticProtocolObject { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(RecipeDisplayType.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(RecipeDisplayType.class); + private final NamespaceID namespace; RecipeDisplayType(@NotNull NamespaceID namespace) { diff --git a/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java b/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java index 12709dc7c..24334a2ef 100644 --- a/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java +++ b/src/autogenerated/java/net/minestom/server/recipe/display/SlotDisplayType.java @@ -3,6 +3,7 @@ package net.minestom.server.recipe.display; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.registry.StaticProtocolObject; import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; import org.jetbrains.annotations.NotNull; /** @@ -27,6 +28,8 @@ public enum SlotDisplayType implements StaticProtocolObject { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(SlotDisplayType.class); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(SlotDisplayType.class); + private final NamespaceID namespace; SlotDisplayType(@NotNull NamespaceID namespace) { 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 4c3bfea93..9b1cfede4 100644 --- a/src/main/java/net/minestom/server/gamedata/tags/Tag.java +++ b/src/main/java/net/minestom/server/gamedata/tags/Tag.java @@ -99,7 +99,7 @@ public final class Tag implements ProtocolObject, Keyed { GAME_EVENTS("minecraft:game_event", Registry.Resource.GAMEPLAY_TAGS, name -> FluidRegistries.getFluid(name).ordinal()), SOUND_EVENTS("minecraft:sound_event", null, null), // Seems not to be included in server data - POTION_EFFECTS("minecraft:sound_event", null, null), // Seems not to be included in server data + POTION_EFFECTS("minecraft:potion_effect", null, null), // Seems not to be included in server data //todo this is cursed. it does not update as the registry changes. Fix later. ENCHANTMENTS("minecraft:enchantment", Registry.Resource.ENCHANTMENT_TAGS, diff --git a/src/main/java/net/minestom/server/item/ItemComponent.java b/src/main/java/net/minestom/server/item/ItemComponent.java index 75c9d3914..02982ade9 100644 --- a/src/main/java/net/minestom/server/item/ItemComponent.java +++ b/src/main/java/net/minestom/server/item/ItemComponent.java @@ -1,7 +1,5 @@ package net.minestom.server.item; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.Color; @@ -57,20 +55,7 @@ public final class ItemComponent { public static final DataComponent CONSUMABLE = register("consumable", Consumable.NETWORK_TYPE, Consumable.NBT_TYPE); public static final DataComponent USE_REMAINDER = register("use_remainder", ItemStack.NETWORK_TYPE, BinaryTagSerializer.ITEM); public static final DataComponent USE_COOLDOWN = register("use_cooldown", UseCooldown.NETWORK_TYPE, UseCooldown.NBT_TYPE); - public static final DataComponent DAMAGE_RESISTANT = register("damage_resistant", NetworkBuffer.STRING, new BinaryTagSerializer() { - // TODO(1.21.2): This is a key to a game tag in the DamageType registry. We should probably have some fancier type to represent this. - // Also this serializer should not be inlined here. - - @Override - public @NotNull BinaryTag write(@NotNull Context context, @NotNull String value) { - return CompoundBinaryTag.builder().putString("value", value).build(); - } - - @Override - public @NotNull String read(@NotNull Context context, @NotNull BinaryTag tag) { - return ((CompoundBinaryTag) tag).getString("value"); - } - }); + public static final DataComponent DAMAGE_RESISTANT = register("damage_resistant", DamageResistant.NETWORK_TYPE, DamageResistant.NBT_TYPE); public static final DataComponent TOOL = register("tool", Tool.NETWORK_TYPE, Tool.NBT_TYPE); public static final DataComponent ENCHANTABLE = register("enchantable", NetworkBuffer.VAR_INT, wrapObject("value", BinaryTagSerializer.INT)); public static final DataComponent EQUIPPABLE = register("equippable", Equippable.NETWORK_TYPE, Equippable.NBT_TYPE); diff --git a/src/main/java/net/minestom/server/item/component/Consumable.java b/src/main/java/net/minestom/server/item/component/Consumable.java index 93846373f..404c97b90 100644 --- a/src/main/java/net/minestom/server/item/component/Consumable.java +++ b/src/main/java/net/minestom/server/item/component/Consumable.java @@ -47,7 +47,7 @@ public record Consumable( "animation", Animation.NBT_TYPE.optional(Animation.EAT), Consumable::animation, "sound", SoundEvent.NBT_TYPE.optional(SoundEvent.ENTITY_GENERIC_EAT), Consumable::sound, "has_consume_particles", BinaryTagSerializer.BOOLEAN.optional(true), Consumable::hasConsumeParticles, - "consume_effects", ConsumeEffect.NBT_TYPE.list().optional(List.of()), Consumable::effects, + "on_consume_effects", ConsumeEffect.NBT_TYPE.list().optional(List.of()), Consumable::effects, Consumable::new); public int consumeTicks() { diff --git a/src/main/java/net/minestom/server/item/component/ConsumeEffect.java b/src/main/java/net/minestom/server/item/component/ConsumeEffect.java index 2d2041941..7e7812de4 100644 --- a/src/main/java/net/minestom/server/item/component/ConsumeEffect.java +++ b/src/main/java/net/minestom/server/item/component/ConsumeEffect.java @@ -1,13 +1,121 @@ package net.minestom.server.item.component; +import net.minestom.server.gamedata.tags.Tag; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.potion.CustomPotionEffect; +import net.minestom.server.potion.PotionEffect; +import net.minestom.server.registry.ObjectSet; +import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; +import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public sealed interface ConsumeEffect { + NetworkBuffer.Type NETWORK_TYPE = ConsumeEffectType.NETWORK_TYPE + .unionType(ConsumeEffect::networkType, ConsumeEffect::consumeEffectToType); + BinaryTagSerializer NBT_TYPE = ConsumeEffectType.NBT_TYPE + .unionType(ConsumeEffect::nbtType, ConsumeEffect::consumeEffectToType); + + record ApplyEffects(@NotNull List effects, float probability) implements ConsumeEffect { + private static final int MAX_EFFECTS = 256; + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + CustomPotionEffect.NETWORK_TYPE.list(MAX_EFFECTS), ApplyEffects::effects, + NetworkBuffer.FLOAT, ApplyEffects::probability, + ApplyEffects::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "effects", CustomPotionEffect.NBT_TYPE.list(), ApplyEffects::effects, + "probability", BinaryTagSerializer.FLOAT.optional(1f), ApplyEffects::probability, + ApplyEffects::new); + + public ApplyEffects { + Check.argCondition(probability < 0 || probability > 1, "Probability must be between 0 and 1"); + effects = List.copyOf(effects); + } + + public ApplyEffects(@NotNull CustomPotionEffect effect, float probability) { + this(List.of(effect), probability); + } + } + + record RemoveEffects(@NotNull ObjectSet effects) implements ConsumeEffect { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + ObjectSet.networkType(Tag.BasicType.POTION_EFFECTS), RemoveEffects::effects, + RemoveEffects::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "effects", ObjectSet.nbtType(Tag.BasicType.POTION_EFFECTS), RemoveEffects::effects, + RemoveEffects::new); + } + + final class ClearAllEffects implements ConsumeEffect { + public static final ClearAllEffects INSTANCE = new ClearAllEffects(); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.UNIT + .transform(buffer -> INSTANCE, ignored -> null); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.UNIT + .map(ignored -> INSTANCE, ignored -> null); + + private ClearAllEffects() {} + } + + record TeleportRandomly(float diameter) implements ConsumeEffect { + public static final float DEFAULT_DIAMETER = 16.0f; + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.FLOAT, TeleportRandomly::diameter, + TeleportRandomly::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "diameter", BinaryTagSerializer.FLOAT.optional(DEFAULT_DIAMETER), TeleportRandomly::diameter, + TeleportRandomly::new); + + public TeleportRandomly() { + this(DEFAULT_DIAMETER); + } + } + + record PlaySound(@NotNull SoundEvent sound) implements ConsumeEffect { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + SoundEvent.NETWORK_TYPE, PlaySound::sound, + PlaySound::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "sound", SoundEvent.NBT_TYPE, PlaySound::sound, + PlaySound::new); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private static NetworkBuffer.Type networkType(@NotNull ConsumeEffectType type) { + return (NetworkBuffer.Type) switch (type) { + case APPLY_EFFECTS -> ApplyEffects.NETWORK_TYPE; + case REMOVE_EFFECTS -> RemoveEffects.NETWORK_TYPE; + case CLEAR_ALL_EFFECTS -> ClearAllEffects.NETWORK_TYPE; + case TELEPORT_RANDOMLY -> TeleportRandomly.NETWORK_TYPE; + case PLAY_SOUND -> PlaySound.NETWORK_TYPE; + }; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private static BinaryTagSerializer nbtType(@NotNull ConsumeEffectType type) { + return (BinaryTagSerializer) switch (type) { + case APPLY_EFFECTS -> ApplyEffects.NBT_TYPE; + case REMOVE_EFFECTS -> RemoveEffects.NBT_TYPE; + case CLEAR_ALL_EFFECTS -> ClearAllEffects.NBT_TYPE; + case TELEPORT_RANDOMLY -> TeleportRandomly.NBT_TYPE; + case PLAY_SOUND -> PlaySound.NBT_TYPE; + }; + } + + private static ConsumeEffectType consumeEffectToType(@NotNull ConsumeEffect consumeEffect) { + return switch (consumeEffect) { + case ApplyEffects ignored -> ConsumeEffectType.APPLY_EFFECTS; + case RemoveEffects ignored -> ConsumeEffectType.REMOVE_EFFECTS; + case ClearAllEffects ignored -> ConsumeEffectType.CLEAR_ALL_EFFECTS; + case TeleportRandomly ignored -> ConsumeEffectType.TELEPORT_RANDOMLY; + case PlaySound ignored -> ConsumeEffectType.PLAY_SOUND; + }; + } -public record ConsumeEffect() { - // TODO(1.21.2): APPLY_EFFECTS, REMOVE_EFFECTS, CLEAR_ALL_EFFECTS, TELEPORT_RANDOMLY, PLAY_SOUND - public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( - ConsumeEffect::new); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.UNIT - .map(ignored -> new ConsumeEffect(), effect -> null); } diff --git a/src/main/java/net/minestom/server/item/component/DamageResistant.java b/src/main/java/net/minestom/server/item/component/DamageResistant.java new file mode 100644 index 000000000..7ce1e637e --- /dev/null +++ b/src/main/java/net/minestom/server/item/component/DamageResistant.java @@ -0,0 +1,16 @@ +package net.minestom.server.item.component; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; +import org.jetbrains.annotations.NotNull; + +public record DamageResistant(@NotNull String tagKey) { + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + NetworkBuffer.STRING, DamageResistant::tagKey, + DamageResistant::new); + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( + "types", BinaryTagSerializer.STRING, DamageResistant::tagKey, + DamageResistant::new); +} diff --git a/src/main/java/net/minestom/server/item/component/DeathProtection.java b/src/main/java/net/minestom/server/item/component/DeathProtection.java index 7a6949590..91f3be5fe 100644 --- a/src/main/java/net/minestom/server/item/component/DeathProtection.java +++ b/src/main/java/net/minestom/server/item/component/DeathProtection.java @@ -3,15 +3,16 @@ package net.minestom.server.item.component; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.utils.nbt.BinaryTagSerializer; +import net.minestom.server.utils.nbt.BinaryTagTemplate; import org.jetbrains.annotations.NotNull; import java.util.List; public record DeathProtection(@NotNull List deathEffects) { public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( - ConsumeEffect.NETWORK_TYPE.list(1024), DeathProtection::deathEffects, + ConsumeEffect.NETWORK_TYPE.list(256), DeathProtection::deathEffects, DeathProtection::new); - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + public static final BinaryTagSerializer NBT_TYPE = BinaryTagTemplate.object( "death_effects", ConsumeEffect.NBT_TYPE.list(), DeathProtection::deathEffects, DeathProtection::new); } diff --git a/src/main/java/net/minestom/server/potion/CustomPotionEffect.java b/src/main/java/net/minestom/server/potion/CustomPotionEffect.java index f1fbd5974..c42581527 100644 --- a/src/main/java/net/minestom/server/potion/CustomPotionEffect.java +++ b/src/main/java/net/minestom/server/potion/CustomPotionEffect.java @@ -88,7 +88,7 @@ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings set tag -> { byte amplifier = tag.getByte("amplifier"); int duration = tag.getInt("duration"); - boolean ambient = tag.getBoolean("ambient"); + boolean ambient = tag.getBoolean("ambient", false); boolean showParticles = tag.getBoolean("show_particles", true); boolean showIcon = tag.getBoolean("show_icon", showParticles); Settings hiddenEffect = null; @@ -98,12 +98,12 @@ public record CustomPotionEffect(@NotNull PotionEffect id, @NotNull Settings set return new Settings(amplifier, duration, ambient, showParticles, showIcon, hiddenEffect); }, value -> { - CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder() - .putByte("amplifier", (byte) value.amplifier) - .putInt("duration", value.duration) - .putBoolean("ambient", value.isAmbient) - .putBoolean("show_particles", value.showParticles) - .putBoolean("show_icon", value.showIcon); + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + if (value.amplifier != 0) builder.putByte("amplifier", (byte) value.amplifier); + builder.putInt("duration", value.duration); + if (value.isAmbient) builder.putBoolean("ambient", true); + if (!value.showParticles) builder.putBoolean("show_particles", false); + builder.putBoolean("show_icon", value.showIcon); if (value.hiddenEffect != null) { builder.put("hidden_effect", self.write(value.hiddenEffect)); } diff --git a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java index b007f6ea9..b00918286 100644 --- a/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java +++ b/src/main/java/net/minestom/server/utils/nbt/BinaryTagSerializer.java @@ -1,5 +1,6 @@ package net.minestom.server.utils.nbt; +import net.kyori.adventure.key.Keyed; import net.kyori.adventure.nbt.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.Style; @@ -111,6 +112,24 @@ public interface BinaryTagSerializer { }; } + static & Keyed> @NotNull BinaryTagSerializer fromEnumKeyed(@NotNull Class enumClass) { + final E[] values = enumClass.getEnumConstants(); + final Map nameMap = Arrays.stream(values).collect(Collectors.toMap(e -> NamespaceID.from(e.key()), Function.identity())); + return new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull E value) { + return stringBinaryTag(value.key().asString()); + } + + @Override + public @NotNull E read(@NotNull BinaryTag tag) { + if (!(tag instanceof StringBinaryTag string)) + throw new IllegalArgumentException("Expected string, got " + tag.type()); + return nameMap.getOrDefault(NamespaceID.from(string.value()), values[0]); + } + }; + } + static > @NotNull BinaryTagSerializer fromEnumStringable(@NotNull Class enumClass) { final E[] values = enumClass.getEnumConstants(); final Map nameMap = Arrays.stream(values).collect(Collectors.toMap(e -> e.name().toLowerCase(Locale.ROOT), Function.identity())); @@ -741,4 +760,34 @@ public interface BinaryTagSerializer { } }; } + + default BinaryTagSerializer unionType(@NotNull Function> serializers, @NotNull Function keyFunc) { + return unionType("type", serializers, keyFunc); + } + + default BinaryTagSerializer unionType(@NotNull String keyField, @NotNull Function> serializers, @NotNull Function keyFunc) { + return new BinaryTagSerializer<>() { + @Override + public @NotNull BinaryTag write(@NotNull Context context, @NotNull R value) { + final T key = keyFunc.apply(value); + Check.notNull(key, "unknown key: {0}", key); + var serializer = serializers.apply(key); + + CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + builder.put((CompoundBinaryTag) serializer.write(context, value)); + builder.put(keyField, BinaryTagSerializer.this.write(context, key)); + return builder.build(); + } + + @Override + public @NotNull R read(@NotNull Context context, @NotNull BinaryTag tag) { + if (!(tag instanceof CompoundBinaryTag compound)) return null; + + final T key = BinaryTagSerializer.this.read(context, compound.get(keyField)); + Check.notNull(key, "unknown key: {0}", key); + + return serializers.apply(key).read(context, compound); + } + }; + } } diff --git a/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java b/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java index 786d1664b..4492d75df 100644 --- a/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java +++ b/src/test/java/net/minestom/server/item/component/ItemComponentReadWriteTest.java @@ -17,7 +17,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Map; -import java.util.Objects; import static java.util.Map.entry; import static org.junit.jupiter.api.Assertions.*; @@ -65,8 +64,6 @@ public class ItemComponentReadWriteTest { } private static void readWriteTestImpl(@NotNull DataComponent component, @NotNull String input) { - if (Objects.equals(ItemComponent.DAMAGE_RESISTANT, component) || Objects.equals(ItemComponent.CONSUMABLE, component) || Objects.equals(ItemComponent.DEATH_PROTECTION, component)) - return; try { var nbt = TagStringIOExt.readTag(input); var value = component.read(CONTEXT, nbt); From ac9615dbd5248406e8b068bce6283ba98b03ce2c Mon Sep 17 00:00:00 2001 From: mworzala Date: Sat, 19 Oct 2024 23:54:09 -0400 Subject: [PATCH 45/97] fix: enchantment component rename --- .../minestom/server/item/enchant/Enchantment.java | 5 ++--- .../minestom/server/item/enchant/EntityEffect.java | 12 ++++++------ .../minestom/server/item/enchant/LocationEffect.java | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/minestom/server/item/enchant/Enchantment.java b/src/main/java/net/minestom/server/item/enchant/Enchantment.java index a01ac1677..91b345b06 100644 --- a/src/main/java/net/minestom/server/item/enchant/Enchantment.java +++ b/src/main/java/net/minestom/server/item/enchant/Enchantment.java @@ -31,9 +31,8 @@ public sealed interface Enchantment extends ProtocolObject, Enchantments permits @ApiStatus.Internal static @NotNull DynamicRegistry createDefaultRegistry(@NotNull Registries registries) { return DynamicRegistry.create( - // TODO(1.21.2) new enchantment types - "minecraft:enchantment", EnchantmentImpl.REGISTRY_NBT_TYPE//, - //registries, Registry.Resource.ENCHANTMENTS + "minecraft:enchantment", EnchantmentImpl.REGISTRY_NBT_TYPE, + registries, Registry.Resource.ENCHANTMENTS ); } diff --git a/src/main/java/net/minestom/server/item/enchant/EntityEffect.java b/src/main/java/net/minestom/server/item/enchant/EntityEffect.java index cdd2edb7e..10f19670c 100644 --- a/src/main/java/net/minestom/server/item/enchant/EntityEffect.java +++ b/src/main/java/net/minestom/server/item/enchant/EntityEffect.java @@ -25,8 +25,8 @@ public non-sealed interface EntityEffect extends Enchantment.Effect { final DynamicRegistry> registry = DynamicRegistry.create("minestom:enchantment_value_effect"); registry.register("all_of", AllOf.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("apply_mob_effect", ApplyPotionEffect.NBT_TYPE, DataPack.MINECRAFT_CORE); + registry.register("change_item_damage", ChangeItemDamage.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("damage_entity", DamageEntity.NBT_TYPE, DataPack.MINECRAFT_CORE); - registry.register("damage_item", DamageItem.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("explode", Explode.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("ignite", Ignite.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("play_sound", PlaySound.NBT_TYPE, DataPack.MINECRAFT_CORE); @@ -97,14 +97,14 @@ public non-sealed interface EntityEffect extends Enchantment.Effect { } } - record DamageItem(@NotNull LevelBasedValue amount) implements EntityEffect, LocationEffect { - public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( - "amount", LevelBasedValue.NBT_TYPE, DamageItem::amount, - DamageItem::new + record ChangeItemDamage(@NotNull LevelBasedValue amount) implements EntityEffect, LocationEffect { + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.object( + "amount", LevelBasedValue.NBT_TYPE, ChangeItemDamage::amount, + ChangeItemDamage::new ); @Override - public @NotNull BinaryTagSerializer nbtType() { + public @NotNull BinaryTagSerializer nbtType() { return NBT_TYPE; } } diff --git a/src/main/java/net/minestom/server/item/enchant/LocationEffect.java b/src/main/java/net/minestom/server/item/enchant/LocationEffect.java index 846d9c9f9..a32f4cc00 100644 --- a/src/main/java/net/minestom/server/item/enchant/LocationEffect.java +++ b/src/main/java/net/minestom/server/item/enchant/LocationEffect.java @@ -18,10 +18,10 @@ public non-sealed interface LocationEffect extends Enchantment.Effect { static @NotNull DynamicRegistry> createDefaultRegistry() { final DynamicRegistry> registry = DynamicRegistry.create("minestom:enchantment_value_effect"); registry.register("all_of", AllOf.NBT_TYPE, DataPack.MINECRAFT_CORE); - registry.register("attribute", AttributeEffect.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("apply_mob_effect", EntityEffect.ApplyPotionEffect.NBT_TYPE, DataPack.MINECRAFT_CORE); + registry.register("attribute", AttributeEffect.NBT_TYPE, DataPack.MINECRAFT_CORE); + registry.register("change_item_damage", EntityEffect.ChangeItemDamage.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("damage_entity", EntityEffect.DamageEntity.NBT_TYPE, DataPack.MINECRAFT_CORE); - registry.register("damage_item", EntityEffect.DamageItem.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("explode", EntityEffect.Explode.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("ignite", EntityEffect.Ignite.NBT_TYPE, DataPack.MINECRAFT_CORE); registry.register("play_sound", EntityEffect.PlaySound.NBT_TYPE, DataPack.MINECRAFT_CORE); From 0605a87b5d9d7e366610c0b97dab0f09ffedff20 Mon Sep 17 00:00:00 2001 From: GreatWyrm Date: Sat, 19 Oct 2024 21:11:39 -0700 Subject: [PATCH 46/97] Fix EntityTeleportPacket (#2442) --- .../net/minestom/server/entity/Entity.java | 4 +- .../server/play/EntityTeleportPacket.java | 37 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 71ebabec8..8b2a52b5b 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -1245,7 +1245,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev final Chunk chunk = getChunk(); assert chunk != null; if (distanceX > 8 || distanceY > 8 || distanceZ > 8) { - PacketViewableUtils.prepareViewablePacket(chunk, new EntityTeleportPacket(getEntityId(), position, isOnGround()), this); + PacketViewableUtils.prepareViewablePacket(chunk, new EntityTeleportPacket(getEntityId(), position, Vec.ZERO, 0, isOnGround()), this); nextSynchronizationTick = synchronizationTicks + 1; } else if (positionChange && viewChange) { PacketViewableUtils.prepareViewablePacket(chunk, EntityPositionAndRotationPacket.getPacket(getEntityId(), position, @@ -1535,7 +1535,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev @ApiStatus.Internal protected void synchronizePosition() { final Pos posCache = this.position; - PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityTeleportPacket(getEntityId(), posCache, isOnGround()), this); + PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityTeleportPacket(getEntityId(), posCache, Vec.ZERO, 0, isOnGround()), this); if (posCache.yaw() != lastSyncedPosition.yaw()) { PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java index 9e707e646..8aab361a6 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java @@ -1,30 +1,49 @@ package net.minestom.server.network.packet.server.play; +import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; -public record EntityTeleportPacket(int entityId, Pos position, boolean onGround) implements ServerPacket.Play { +public record EntityTeleportPacket(int entityId, Pos position, Point delta, int flags, boolean onGround) implements ServerPacket.Play { + public static final int FLAG_X = 1; + public static final int FLAG_Y = 1 << 1; + public static final int FLAG_Z = 1 << 2; + public static final int FLAG_Y_ROT = 1 << 3; + public static final int FLAG_X_ROT = 1 << 4; + public static final int FLAG_DELTA_X = 1 << 5; + public static final int FLAG_DELTA_Y = 1 << 6; + public static final int FLAG_DELTA_Z = 1 << 7; + public static final int FLAG_ROTATE_DELTA = 1 << 8; + + public static final int FLAG_DELTA = FLAG_DELTA_X | FLAG_DELTA_Y | FLAG_DELTA_Z | FLAG_ROTATE_DELTA; + public static final int FLAG_ROTATION = FLAG_X_ROT | FLAG_Y_ROT; + public static final int FLAG_ALL = FLAG_X | FLAG_Y | FLAG_Z | FLAG_ROTATION | FLAG_DELTA; + public static final NetworkBuffer.Type SERIALIZER = new NetworkBuffer.Type<>() { @Override public void write(@NotNull NetworkBuffer buffer, @NotNull EntityTeleportPacket value) { buffer.write(VAR_INT, value.entityId); - buffer.write(DOUBLE, value.position.x()); - buffer.write(DOUBLE, value.position.y()); - buffer.write(DOUBLE, value.position.z()); - buffer.write(BYTE, (byte) (value.position.yaw() * 256f / 360f)); - buffer.write(BYTE, (byte) (value.position.pitch() * 256f / 360f)); + buffer.write(VECTOR3D, value.position.asVec()); + buffer.write(VECTOR3D, value.delta); + buffer.write(FLOAT, value.position.yaw()); + buffer.write(FLOAT, value.position.pitch()); + buffer.write(INT, value.flags); buffer.write(BOOLEAN, value.onGround); } @Override public @NotNull EntityTeleportPacket read(@NotNull NetworkBuffer buffer) { - return new EntityTeleportPacket(buffer.read(VAR_INT), new Pos(buffer.read(DOUBLE), buffer.read(DOUBLE), buffer.read(DOUBLE), - buffer.read(BYTE) * 360f / 256f, buffer.read(BYTE) * 360f / 256f), - buffer.read(BOOLEAN)); + int entityId = buffer.read(VAR_INT); + // Order is x,y,z for position, then x,y,z for delta move, then yaw and pitch + Point absPosition = buffer.read(VECTOR3D); + Point deltaMovement = buffer.read(VECTOR3D); + return new EntityTeleportPacket(entityId, new Pos(absPosition, buffer.read(FLOAT), buffer.read(FLOAT)), + deltaMovement, buffer.read(INT), buffer.read(BOOLEAN)); } }; } From ffe42a243f65391de17f2470bfceae6f0a98e9b9 Mon Sep 17 00:00:00 2001 From: mworzala Date: Sun, 20 Oct 2024 00:36:43 -0400 Subject: [PATCH 47/97] chore: experimentation with delta component of moves --- demo/src/main/java/net/minestom/demo/PlayerInit.java | 10 ---------- src/main/java/net/minestom/server/entity/Entity.java | 7 +++---- src/main/java/net/minestom/server/entity/Player.java | 5 +++-- .../server/listener/PlayerPositionListener.java | 6 ++++-- .../packet/server/play/EntityTeleportPacket.java | 3 ++- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 3cd2712af..3be9a2a24 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -9,7 +9,6 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.*; import net.minestom.server.entity.damage.Damage; -import net.minestom.server.entity.metadata.projectile.FireworkRocketMeta; import net.minestom.server.event.Event; import net.minestom.server.event.EventNode; import net.minestom.server.event.entity.EntityAttackEvent; @@ -82,13 +81,6 @@ public class PlayerInit { itemEntity.setInstance(player.getInstance(), playerPos.withY(y -> y + 1.5)); Vec velocity = playerPos.direction().mul(6); itemEntity.setVelocity(velocity); - - var firework = new Entity(EntityType.FIREWORK_ROCKET); - firework.setInstance(player.getInstance()); - var meta = (FireworkRocketMeta) firework.getEntityMeta(); - meta.setFireworkInfo(ItemStack.of(Material.FIREWORK_ROCKET)); - meta.setShooter(player); - player.addPassenger(firework); }) .addListener(PlayerDisconnectEvent.class, event -> System.out.println("DISCONNECTION " + event.getPlayer().getUsername())) .addListener(AsyncPlayerConfigurationEvent.class, event -> { @@ -120,8 +112,6 @@ public class PlayerInit { "hello", "world" ))); - player.setChestplate(ItemStack.of(Material.ELYTRA)); - player.sendPacket(new ServerLinksPacket( new ServerLinksPacket.Entry(ServerLinksPacket.KnownLinkType.NEWS, "https://minestom.net"), new ServerLinksPacket.Entry(ServerLinksPacket.KnownLinkType.BUG_REPORT, "https://minestom.net"), diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index 8b2a52b5b..31daf3ef9 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -1245,6 +1245,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev final Chunk chunk = getChunk(); assert chunk != null; if (distanceX > 8 || distanceY > 8 || distanceZ > 8) { + // TODO(1.21.2) should we be setting delta to zero? PacketViewableUtils.prepareViewablePacket(chunk, new EntityTeleportPacket(getEntityId(), position, Vec.ZERO, 0, isOnGround()), this); nextSynchronizationTick = synchronizationTicks + 1; } else if (positionChange && viewChange) { @@ -1535,10 +1536,8 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev @ApiStatus.Internal protected void synchronizePosition() { final Pos posCache = this.position; - PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityTeleportPacket(getEntityId(), posCache, Vec.ZERO, 0, isOnGround()), this); - if (posCache.yaw() != lastSyncedPosition.yaw()) { - PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityHeadLookPacket(getEntityId(), position.yaw()), this); - } + final Pos delta = posCache.sub(lastSyncedPosition); + PacketViewableUtils.prepareViewablePacket(currentChunk, new EntityPositionSyncPacket(getEntityId(), posCache, delta, posCache.yaw(), posCache.pitch(), isOnGround()), this); nextSynchronizationTick = ticks + synchronizationTicks; this.lastSyncedPosition = posCache; } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index b8ed99807..c39a96013 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1846,8 +1846,9 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou @ApiStatus.Internal void synchronizePositionAfterTeleport(@NotNull Pos position, int relativeFlags, boolean shouldConfirm) { int teleportId = shouldConfirm ? getNextTeleportId() : -1; - // TODO(1.21.2): Fix/reenable this -// sendPacket(new PlayerPositionAndLookPacket(position, (byte) relativeFlags, teleportId)); + var posCache = this.position; + // TODO(1.21.2): should delta be zero? + sendPacket(new PlayerPositionAndLookPacket(teleportId, posCache, Vec.ZERO, posCache.yaw(), posCache.pitch(), (byte) relativeFlags)); super.synchronizePosition(); } diff --git a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java index 44e6d2b95..4904058eb 100644 --- a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java @@ -2,11 +2,13 @@ package net.minestom.server.listener; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; import net.minestom.server.event.EventDispatcher; import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.instance.Instance; import net.minestom.server.network.packet.client.play.*; +import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; @@ -72,8 +74,8 @@ public class PlayerPositionListener { } if (playerMoveEvent.isCancelled()) { // Teleport to previous position - // TODO(1.21.2) -// player.sendPacket(new PlayerPositionAndLookPacket(currentPosition, (byte) 0x00, player.getNextTeleportId())); + // TODO(1.21.2) verify that setting to zero delta is correct. might need to send opposite of intended move + player.sendPacket(new PlayerPositionAndLookPacket(player.getNextTeleportId(), currentPosition, Vec.ZERO, currentPosition.yaw(), currentPosition.pitch(), (byte) 0x00)); return; } final Pos eventPosition = playerMoveEvent.getNewPosition(); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java index 8aab361a6..9a882d2a5 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityTeleportPacket.java @@ -2,7 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.server.ServerPacket; import org.jetbrains.annotations.NotNull; @@ -10,6 +9,8 @@ import org.jetbrains.annotations.NotNull; import static net.minestom.server.network.NetworkBuffer.*; public record EntityTeleportPacket(int entityId, Pos position, Point delta, int flags, boolean onGround) implements ServerPacket.Play { + + // TODO(1.21.2) these flags are duplicated multiple times now i(matt) think public static final int FLAG_X = 1; public static final int FLAG_Y = 1 << 1; public static final int FLAG_Z = 1 << 2; From 5cf30408d286208376c6380c283d650e6f15f903 Mon Sep 17 00:00:00 2001 From: GreatWyrm Date: Tue, 22 Oct 2024 17:27:26 -0700 Subject: [PATCH 48/97] Refactor boat and minecart metadata to pull out common fields, register new boats, and add a default metadata for the creaking (#2444) --- .../server/entity/MetadataHolder.java | 26 ++++++++-- .../entity/metadata/AbstractVehicleMeta.java | 40 ++++++++++++++++ .../minecart/AbstractMinecartMeta.java | 47 +++++++------------ .../entity/metadata/monster/CreakingMeta.java | 15 ++++++ .../entity/metadata/other/BoatMeta.java | 47 +++++-------------- 5 files changed, 106 insertions(+), 69 deletions(-) create mode 100644 src/main/java/net/minestom/server/entity/metadata/AbstractVehicleMeta.java create mode 100644 src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java diff --git a/src/main/java/net/minestom/server/entity/MetadataHolder.java b/src/main/java/net/minestom/server/entity/MetadataHolder.java index 03391408b..5b6c97643 100644 --- a/src/main/java/net/minestom/server/entity/MetadataHolder.java +++ b/src/main/java/net/minestom/server/entity/MetadataHolder.java @@ -138,28 +138,38 @@ public final class MetadataHolder { private static Map> createMetaMap() { return Map.>ofEntries( + Map.entry("minecraft:acacia_boat", BoatMeta::new), + Map.entry("minecraft:acacia_chest_boat", BoatMeta::new), Map.entry("minecraft:allay", AllayMeta::new), Map.entry("minecraft:area_effect_cloud", AreaEffectCloudMeta::new), Map.entry("minecraft:armadillo", ArmadilloMeta::new), Map.entry("minecraft:armor_stand", ArmorStandMeta::new), Map.entry("minecraft:arrow", ArrowMeta::new), Map.entry("minecraft:axolotl", AxolotlMeta::new), + Map.entry("minecraft:bamboo_raft", BoatMeta::new), + Map.entry("minecraft:bamboo_chest_raft", BoatMeta::new), Map.entry("minecraft:bat", BatMeta::new), Map.entry("minecraft:bee", BeeMeta::new), + Map.entry("minecraft:birch_boat", BoatMeta::new), + Map.entry("minecraft:birch_chest_boat", BoatMeta::new), Map.entry("minecraft:blaze", BlazeMeta::new), Map.entry("minecraft:block_display", BlockDisplayMeta::new), - Map.entry("minecraft:boat", BoatMeta::new), Map.entry("minecraft:bogged", BoggedMeta::new), Map.entry("minecraft:breeze", BreezeMeta::new), Map.entry("minecraft:breeze_wind_charge", BreezeWindChargeMeta::new), - Map.entry("minecraft:chest_boat", BoatMeta::new), Map.entry("minecraft:camel", CamelMeta::new), Map.entry("minecraft:cat", CatMeta::new), Map.entry("minecraft:cave_spider", CaveSpiderMeta::new), + Map.entry("minecraft:cherry_boat", BoatMeta::new), + Map.entry("minecraft:cherry_chest_boat", BoatMeta::new), Map.entry("minecraft:chicken", ChickenMeta::new), Map.entry("minecraft:cod", CodMeta::new), Map.entry("minecraft:cow", CowMeta::new), + Map.entry("minecraft:creaking", CreakingMeta::new), + Map.entry("minecraft:creaking_transient", CreakingMeta::new), Map.entry("minecraft:creeper", CreeperMeta::new), + Map.entry("minecraft:dark_oak_boat", BoatMeta::new), + Map.entry("minecraft:dark_oak_chest_boat", BoatMeta::new), Map.entry("minecraft:dolphin", DolphinMeta::new), Map.entry("minecraft:donkey", DonkeyMeta::new), Map.entry("minecraft:dragon_fireball", DragonFireballMeta::new), @@ -192,12 +202,16 @@ public final class MetadataHolder { Map.entry("minecraft:item", ItemEntityMeta::new), Map.entry("minecraft:item_display", ItemDisplayMeta::new), Map.entry("minecraft:item_frame", ItemFrameMeta::new), + Map.entry("minecraft:jungle_boat", BoatMeta::new), + Map.entry("minecraft:jungle_chest_boat", BoatMeta::new), Map.entry("minecraft:fireball", FireballMeta::new), Map.entry("minecraft:leash_knot", LeashKnotMeta::new), Map.entry("minecraft:lightning_bolt", LightningBoltMeta::new), Map.entry("minecraft:llama", LlamaMeta::new), Map.entry("minecraft:llama_spit", LlamaSpitMeta::new), Map.entry("minecraft:magma_cube", MagmaCubeMeta::new), + Map.entry("minecraft:mangrove_boat", BoatMeta::new), + Map.entry("minecraft:mangrove_chest_boat", BoatMeta::new), Map.entry("minecraft:marker", MarkerMeta::new), Map.entry("minecraft:minecart", MinecartMeta::new), Map.entry("minecraft:chest_minecart", ChestMinecartMeta::new), @@ -207,11 +221,15 @@ public final class MetadataHolder { Map.entry("minecraft:spawner_minecart", SpawnerMinecartMeta::new), Map.entry("minecraft:text_display", TextDisplayMeta::new), Map.entry("minecraft:tnt_minecart", TntMinecartMeta::new), - Map.entry("minecraft:mule", MuleMeta::new), Map.entry("minecraft:mooshroom", MooshroomMeta::new), + Map.entry("minecraft:mule", MuleMeta::new), + Map.entry("minecraft:oak_boat", BoatMeta::new), + Map.entry("minecraft:oak_chest_boat", BoatMeta::new), Map.entry("minecraft:ocelot", OcelotMeta::new), Map.entry("minecraft:ominous_item_spawner", OminousItemSpawnerMeta::new), Map.entry("minecraft:painting", PaintingMeta::new), + Map.entry("minecraft:pale_oak_boat", BoatMeta::new), + Map.entry("minecraft:pale_oak_chest_boat", BoatMeta::new), Map.entry("minecraft:panda", PandaMeta::new), Map.entry("minecraft:parrot", ParrotMeta::new), Map.entry("minecraft:phantom", PhantomMeta::new), @@ -238,6 +256,8 @@ public final class MetadataHolder { Map.entry("minecraft:snowball", SnowballMeta::new), Map.entry("minecraft:spectral_arrow", SpectralArrowMeta::new), Map.entry("minecraft:spider", SpiderMeta::new), + Map.entry("minecraft:spruce_boat", BoatMeta::new), + Map.entry("minecraft:spruce_chest_boat", BoatMeta::new), Map.entry("minecraft:squid", SquidMeta::new), Map.entry("minecraft:stray", StrayMeta::new), Map.entry("minecraft:strider", StriderMeta::new), diff --git a/src/main/java/net/minestom/server/entity/metadata/AbstractVehicleMeta.java b/src/main/java/net/minestom/server/entity/metadata/AbstractVehicleMeta.java new file mode 100644 index 000000000..346d364d3 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/metadata/AbstractVehicleMeta.java @@ -0,0 +1,40 @@ +package net.minestom.server.entity.metadata; + +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Metadata; +import net.minestom.server.entity.MetadataHolder; +import org.jetbrains.annotations.NotNull; + +public class AbstractVehicleMeta extends EntityMeta { + + public static final byte OFFSET = EntityMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 3; + + public AbstractVehicleMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { + super(entity, metadata); + } + + public int getShakingTicks() { + return super.metadata.getIndex(OFFSET, 0); + } + + public void setShakingTicks(int value) { + super.metadata.setIndex(OFFSET, Metadata.VarInt(value)); + } + + public int getShakingDirection() { + return super.metadata.getIndex(OFFSET + 1, 1); + } + + public void setShakingDirection(int value) { + super.metadata.setIndex(OFFSET + 1, Metadata.VarInt(value)); + } + + public float getShakingMultiplier() { + return super.metadata.getIndex(OFFSET + 2, 0); + } + + public void setShakingMultiplier(float value) { + super.metadata.setIndex(OFFSET + 2, Metadata.Float(value)); + } +} diff --git a/src/main/java/net/minestom/server/entity/metadata/minecart/AbstractMinecartMeta.java b/src/main/java/net/minestom/server/entity/metadata/minecart/AbstractMinecartMeta.java index c238c6689..2648cb758 100644 --- a/src/main/java/net/minestom/server/entity/metadata/minecart/AbstractMinecartMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/minecart/AbstractMinecartMeta.java @@ -3,57 +3,42 @@ package net.minestom.server.entity.metadata.minecart; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; +import net.minestom.server.entity.metadata.AbstractVehicleMeta; import net.minestom.server.entity.metadata.EntityMeta; import net.minestom.server.entity.metadata.ObjectDataProvider; import org.jetbrains.annotations.NotNull; -public abstract class AbstractMinecartMeta extends EntityMeta implements ObjectDataProvider { - public static final byte OFFSET = EntityMeta.MAX_OFFSET; - public static final byte MAX_OFFSET = OFFSET + 6; +public abstract class AbstractMinecartMeta extends AbstractVehicleMeta implements ObjectDataProvider { + public static final byte OFFSET = AbstractVehicleMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 3; protected AbstractMinecartMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { super(entity, metadata); } - public int getShakingPower() { + public int getCustomBlockIdAndDamage() { return super.metadata.getIndex(OFFSET, 0); } - public void setShakingPower(int value) { - super.metadata.setIndex(OFFSET, Metadata.VarInt(value)); - } - - public int getShakingDirection() { - return super.metadata.getIndex(OFFSET + 1, 1); - } - - public void setShakingDirection(int value) { - super.metadata.setIndex(OFFSET + 1, Metadata.VarInt(value)); - } - - public float getShakingMultiplier() { - return super.metadata.getIndex(OFFSET + 2, 0F); - } - - public void setShakingMultiplier(float value) { - super.metadata.setIndex(OFFSET + 2, Metadata.Float(value)); - } - - public int getCustomBlockIdAndDamage() { - return super.metadata.getIndex(OFFSET + 3, 0); - } - public void setCustomBlockIdAndDamage(int value) { - super.metadata.setIndex(OFFSET + 3, Metadata.VarInt(value)); + super.metadata.setIndex(OFFSET, Metadata.VarInt(value)); } // in 16th of a block public int getCustomBlockYPosition() { - return super.metadata.getIndex(OFFSET + 4, 6); + return super.metadata.getIndex(OFFSET + 1, 6); } public void setCustomBlockYPosition(int value) { - super.metadata.setIndex(OFFSET + 4, Metadata.VarInt(value)); + super.metadata.setIndex(OFFSET + 1, Metadata.VarInt(value)); + } + + public boolean getShowCustomBlock() { + return super.metadata.getIndex(OFFSET + 2, false); + } + + public void setShowCustomBlock(boolean show) { + super.metadata.setIndex(OFFSET + 2, Metadata.Boolean(show)); } @Override diff --git a/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java b/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java new file mode 100644 index 000000000..ba6c2c549 --- /dev/null +++ b/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java @@ -0,0 +1,15 @@ +package net.minestom.server.entity.metadata.monster; + +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.MetadataHolder; +import org.jetbrains.annotations.NotNull; + +// TODO(1.21.2) - Find out what the metadata fields of a creaking are +public class CreakingMeta extends MonsterMeta { + public static final byte OFFSET = MonsterMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 0; + + public CreakingMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { + super(entity, metadata); + } +} diff --git a/src/main/java/net/minestom/server/entity/metadata/other/BoatMeta.java b/src/main/java/net/minestom/server/entity/metadata/other/BoatMeta.java index f1c954cdf..1906c3a21 100644 --- a/src/main/java/net/minestom/server/entity/metadata/other/BoatMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/other/BoatMeta.java @@ -3,72 +3,49 @@ package net.minestom.server.entity.metadata.other; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; +import net.minestom.server.entity.metadata.AbstractVehicleMeta; import net.minestom.server.entity.metadata.EntityMeta; import org.jetbrains.annotations.NotNull; -public class BoatMeta extends EntityMeta { - public static final byte OFFSET = EntityMeta.MAX_OFFSET; - public static final byte MAX_OFFSET = OFFSET + 7; +public class BoatMeta extends AbstractVehicleMeta { + public static final byte OFFSET = AbstractVehicleMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 4; public BoatMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { super(entity, metadata); } - public int getTimeSinceLastHit() { - return super.metadata.getIndex(OFFSET, 0); - } - - public void setTimeSinceLastHit(int value) { - super.metadata.setIndex(OFFSET, Metadata.VarInt(value)); - } - - public int getForwardDirection() { - return super.metadata.getIndex(OFFSET + 1, 1); - } - - public void setForwardDirection(int value) { - super.metadata.setIndex(OFFSET + 1, Metadata.VarInt(value)); - } - - public float getDamageTaken() { - return super.metadata.getIndex(OFFSET + 2, 0); - } - - public void setDamageTaken(float value) { - super.metadata.setIndex(OFFSET + 2, Metadata.Float(value)); - } - @NotNull public Type getType() { - return Type.VALUES[super.metadata.getIndex(OFFSET + 3, 0)]; + return Type.VALUES[super.metadata.getIndex(OFFSET, 0)]; } public void setType(@NotNull Type value) { - super.metadata.setIndex(OFFSET + 3, Metadata.VarInt(value.ordinal())); + super.metadata.setIndex(OFFSET, Metadata.VarInt(value.ordinal())); } public boolean isLeftPaddleTurning() { - return super.metadata.getIndex(OFFSET + 4, false); + return super.metadata.getIndex(OFFSET + 1, false); } public void setLeftPaddleTurning(boolean value) { - super.metadata.setIndex(OFFSET + 4, Metadata.Boolean(value)); + super.metadata.setIndex(OFFSET + 1, Metadata.Boolean(value)); } public boolean isRightPaddleTurning() { - return super.metadata.getIndex(OFFSET + 5, false); + return super.metadata.getIndex(OFFSET + 2, false); } public void setRightPaddleTurning(boolean value) { - super.metadata.setIndex(OFFSET + 5, Metadata.Boolean(value)); + super.metadata.setIndex(OFFSET + 2, Metadata.Boolean(value)); } public int getSplashTimer() { - return super.metadata.getIndex(OFFSET + 6, 0); + return super.metadata.getIndex(OFFSET + 3, 0); } public void setSplashTimer(int value) { - super.metadata.setIndex(OFFSET + 6, Metadata.VarInt(value)); + super.metadata.setIndex(OFFSET + 3, Metadata.VarInt(value)); } public enum Type { From 12586323ec3fb25fcfe0aab84a40affd8aa9fd3b Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 22 Oct 2024 20:46:12 -0400 Subject: [PATCH 49/97] feat: entity meta changes --- .../metadata/animal/tameable/WolfMeta.java | 2 -- .../entity/metadata/monster/CreakingMeta.java | 20 ++++++++++++-- .../water/AgeableWaterAnimalMeta.java | 15 +++++++++++ .../entity/metadata/water/DolphinMeta.java | 4 +-- .../entity/metadata/water/GlowSquidMeta.java | 4 +-- .../entity/metadata/water/SquidMeta.java | 2 +- .../metadata/water/fish/SalmonMeta.java | 26 +++++++++++++++++++ 7 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/minestom/server/entity/metadata/water/AgeableWaterAnimalMeta.java diff --git a/src/main/java/net/minestom/server/entity/metadata/animal/tameable/WolfMeta.java b/src/main/java/net/minestom/server/entity/metadata/animal/tameable/WolfMeta.java index 5c6a6ed0d..dd27be3f2 100644 --- a/src/main/java/net/minestom/server/entity/metadata/animal/tameable/WolfMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/animal/tameable/WolfMeta.java @@ -28,8 +28,6 @@ public class WolfMeta extends TameableAnimalMeta { super(entity, metadata); } - //todo variant - public boolean isBegging() { return super.metadata.getIndex(OFFSET, false); } diff --git a/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java b/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java index ba6c2c549..7bb7ceb1c 100644 --- a/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/monster/CreakingMeta.java @@ -1,15 +1,31 @@ package net.minestom.server.entity.metadata.monster; import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; -// TODO(1.21.2) - Find out what the metadata fields of a creaking are public class CreakingMeta extends MonsterMeta { public static final byte OFFSET = MonsterMeta.MAX_OFFSET; - public static final byte MAX_OFFSET = OFFSET + 0; + public static final byte MAX_OFFSET = OFFSET + 2; public CreakingMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { super(entity, metadata); } + + public boolean canMove() { + return super.metadata.getIndex(OFFSET, true); + } + + public void setCanMove(boolean value) { + super.metadata.setIndex(OFFSET, Metadata.Boolean(value)); + } + + public boolean isActive() { + return super.metadata.getIndex(OFFSET + 1, false); + } + + public void setActive(boolean value) { + super.metadata.setIndex(OFFSET + 1, Metadata.Boolean(value)); + } } diff --git a/src/main/java/net/minestom/server/entity/metadata/water/AgeableWaterAnimalMeta.java b/src/main/java/net/minestom/server/entity/metadata/water/AgeableWaterAnimalMeta.java new file mode 100644 index 000000000..605fc922e --- /dev/null +++ b/src/main/java/net/minestom/server/entity/metadata/water/AgeableWaterAnimalMeta.java @@ -0,0 +1,15 @@ +package net.minestom.server.entity.metadata.water; + +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.MetadataHolder; +import net.minestom.server.entity.metadata.AgeableMobMeta; +import org.jetbrains.annotations.NotNull; + +public class AgeableWaterAnimalMeta extends AgeableMobMeta { + public static final byte OFFSET = AgeableMobMeta.MAX_OFFSET; + public static final byte MAX_OFFSET = OFFSET + 0; + + public AgeableWaterAnimalMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { + super(entity, metadata); + } +} diff --git a/src/main/java/net/minestom/server/entity/metadata/water/DolphinMeta.java b/src/main/java/net/minestom/server/entity/metadata/water/DolphinMeta.java index 8ecd228db..ac66acb81 100644 --- a/src/main/java/net/minestom/server/entity/metadata/water/DolphinMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/water/DolphinMeta.java @@ -7,8 +7,8 @@ import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; -public class DolphinMeta extends WaterAnimalMeta { - public static final byte OFFSET = WaterAnimalMeta.MAX_OFFSET; +public class DolphinMeta extends AgeableWaterAnimalMeta { + public static final byte OFFSET = AgeableWaterAnimalMeta.MAX_OFFSET; public static final byte MAX_OFFSET = OFFSET + 3; public DolphinMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { diff --git a/src/main/java/net/minestom/server/entity/metadata/water/GlowSquidMeta.java b/src/main/java/net/minestom/server/entity/metadata/water/GlowSquidMeta.java index aedeaf983..8659533f2 100644 --- a/src/main/java/net/minestom/server/entity/metadata/water/GlowSquidMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/water/GlowSquidMeta.java @@ -5,8 +5,8 @@ import net.minestom.server.entity.Metadata; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; -public class GlowSquidMeta extends WaterAnimalMeta { - public static final byte OFFSET = WaterAnimalMeta.MAX_OFFSET; +public class GlowSquidMeta extends AgeableWaterAnimalMeta { + public static final byte OFFSET = AgeableWaterAnimalMeta.MAX_OFFSET; public static final byte MAX_OFFSET = OFFSET + 1; public GlowSquidMeta(@NotNull Entity entity, @NotNull MetadataHolder metadata) { diff --git a/src/main/java/net/minestom/server/entity/metadata/water/SquidMeta.java b/src/main/java/net/minestom/server/entity/metadata/water/SquidMeta.java index c27f6dc4f..32ce5d781 100644 --- a/src/main/java/net/minestom/server/entity/metadata/water/SquidMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/water/SquidMeta.java @@ -4,7 +4,7 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; -public class SquidMeta extends WaterAnimalMeta { +public class SquidMeta extends AgeableWaterAnimalMeta { public static final byte OFFSET = WaterAnimalMeta.MAX_OFFSET; public static final byte MAX_OFFSET = OFFSET + 0; diff --git a/src/main/java/net/minestom/server/entity/metadata/water/fish/SalmonMeta.java b/src/main/java/net/minestom/server/entity/metadata/water/fish/SalmonMeta.java index fb1dde66a..df0b78ce9 100644 --- a/src/main/java/net/minestom/server/entity/metadata/water/fish/SalmonMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/water/fish/SalmonMeta.java @@ -4,6 +4,10 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.MetadataHolder; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + public class SalmonMeta extends AbstractFishMeta { public static final byte OFFSET = AbstractFishMeta.MAX_OFFSET; public static final byte MAX_OFFSET = OFFSET + 0; @@ -12,4 +16,26 @@ public class SalmonMeta extends AbstractFishMeta { super(entity, metadata); } + public @NotNull Variant getVariant() { + return Variant.BY_ID.getOrDefault(super.metadata.getIndex(OFFSET, ""), Variant.MEDIUM); + } + + public enum Variant { + SMALL("small"), + MEDIUM("medium"), + LARGE("large"); + + private static final Map BY_ID = Arrays.stream(values()) + .collect(Collectors.toMap(Variant::id, (variant) -> variant)); + + private final String id; + Variant(@NotNull String id) { + this.id = id; + } + + public @NotNull String id() { + return id; + } + } + } From 14aa2d5d5c54625d0dad046675650d8f99d12505 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 22 Oct 2024 21:56:36 -0400 Subject: [PATCH 50/97] feat: 1.21.2 release, test/behavior fixes --- .../src/main/java/net/minestom/demo/Main.java | 10 +- .../java/net/minestom/demo/PlayerInit.java | 96 +++--- gradle/libs.versions.toml | 2 +- .../minestom/server/MinecraftConstants.java | 6 +- .../net/minestom/server/entity/Player.java | 3 +- .../server/item/component/Equippable.java | 32 ++ .../listener/PlayerPositionListener.java | 7 +- .../server/listener/UseItemListener.java | 10 +- .../server/network/socket/Server.java | 7 +- .../net/minestom/server/recipe/Recipe.java | 7 +- .../minestom/server/recipe/RecipeCompute.java | 7 +- .../minestom/server/recipe/RecipeManager.java | 6 +- .../server/recipe/RecipeSerializers.java | 20 +- .../entity/EntityTeleportIntegrationTest.java | 20 +- .../entity/player/PlayerIntegrationTest.java | 2 +- .../player/PlayerMovementIntegrationTest.java | 292 ++++++++++-------- .../TestUseItemListenerIntegration.java | 34 ++ .../server/network/PacketWriteReadTest.java | 63 ++-- .../recipe/IngredientSerializationTest.java | 19 -- .../server/recipe/IngredientTest.java | 21 ++ 20 files changed, 388 insertions(+), 276 deletions(-) delete mode 100644 src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java create mode 100644 src/test/java/net/minestom/server/recipe/IngredientTest.java diff --git a/demo/src/main/java/net/minestom/demo/Main.java b/demo/src/main/java/net/minestom/demo/Main.java index e410ad8a3..3e1bdda61 100644 --- a/demo/src/main/java/net/minestom/demo/Main.java +++ b/demo/src/main/java/net/minestom/demo/Main.java @@ -122,10 +122,10 @@ public class Main { "minestom:test", new Recipe.Shaped("", RecipeCategory.Crafting.MISC, 2, 2, List.of( - new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), - new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), - new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)), - new Recipe.Ingredient(ItemStack.of(Material.IRON_INGOT)) + new Recipe.Ingredient(Material.IRON_INGOT), + new Recipe.Ingredient(Material.IRON_INGOT), + new Recipe.Ingredient(Material.IRON_INGOT), + new Recipe.Ingredient(Material.IRON_INGOT) ), ItemStack.of(Material.IRON_BLOCK), true)); MinecraftServer.getRecipeManager().addRecipe(ironBlockRecipe); var recipe = new Recipe( @@ -133,7 +133,7 @@ public class Main { new Recipe.Shapeless("abc", RecipeCategory.Crafting.MISC, List.of( - new Recipe.Ingredient(ItemStack.of(Material.DIRT)) + new Recipe.Ingredient(Material.DIRT) ), ItemStack.builder(Material.GOLD_BLOCK) .set(ItemComponent.CUSTOM_NAME, Component.text("abc")) diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 3be9a2a24..7b77abd76 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -1,8 +1,11 @@ package net.minestom.demo; +import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.minestom.server.FeatureFlag; import net.minestom.server.MinecraftServer; +import net.minestom.server.advancements.FrameType; +import net.minestom.server.advancements.Notification; import net.minestom.server.adventure.MinestomAdventure; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.coordinate.Pos; @@ -29,14 +32,22 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.BlockPredicates; +import net.minestom.server.item.component.EnchantmentList; +import net.minestom.server.item.component.LodestoneTracker; +import net.minestom.server.item.component.PotionContents; +import net.minestom.server.item.enchant.Enchantment; import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.network.packet.server.common.CustomReportDetailsPacket; import net.minestom.server.network.packet.server.common.ServerLinksPacket; +import net.minestom.server.potion.CustomPotionEffect; +import net.minestom.server.potion.PotionEffect; +import net.minestom.server.sound.SoundEvent; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.time.TimeUnit; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; @@ -118,48 +129,49 @@ public class PlayerInit { new ServerLinksPacket.Entry(Component.text("Hello world!"), "https://minestom.net") )); -// ItemStack bundle = ItemStack.builder(Material.BUNDLE) -// .set(ItemComponent.BUNDLE_CONTENTS, List.of( -// ItemStack.of(Material.DIAMOND, 5), -// ItemStack.of(Material.RABBIT_FOOT, 5) -// )) -// .build(); -// player.getInventory().addItemStack(bundle); -// -// player.getInventory().addItemStack(ItemStack.builder(Material.COMPASS) -// .set(ItemComponent.LODESTONE_TRACKER, new LodestoneTracker(player.getInstance().getDimensionName(), new Vec(10, 10, 10), true)) -// .build()); -// -// player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) -// .set(ItemComponent.ENCHANTMENTS, new EnchantmentList(Map.of( -// Enchantment.SHARPNESS, 10 -// ))) -// .build()); -// -// player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) -// .build()); -// -// player.getInventory().addItemStack(ItemStack.builder(Material.BLACK_BANNER) -// .build()); -// -// player.getInventory().addItemStack(ItemStack.builder(Material.POTION) -// .set(ItemComponent.POTION_CONTENTS, new PotionContents(null, null, List.of( -// new CustomPotionEffect(PotionEffect.JUMP_BOOST, new CustomPotionEffect.Settings((byte) 4, -// 45 * 20, false, true, true, null)) -// ))) -// .customName(Component.text("Sharpness 10 Sword").append(Component.space()).append(Component.text("§c§l[LEGENDARY]"))) -// .build()); -// -// -// if (event.isFirstSpawn()) { -// event.getPlayer().sendNotification(new Notification( -// Component.text("Welcome!"), -// FrameType.TASK, -// Material.IRON_SWORD -// )); -// -// player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); -// } + // TODO(1.21.2): Handle bundle slot selection + ItemStack bundle = ItemStack.builder(Material.BUNDLE) + .set(ItemComponent.BUNDLE_CONTENTS, List.of( + ItemStack.of(Material.DIAMOND, 5), + ItemStack.of(Material.RABBIT_FOOT, 5) + )) + .build(); + player.getInventory().addItemStack(bundle); + + player.getInventory().addItemStack(ItemStack.builder(Material.COMPASS) + .set(ItemComponent.LODESTONE_TRACKER, new LodestoneTracker(player.getInstance().getDimensionName(), new Vec(10, 10, 10), true)) + .build()); + + player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) + .set(ItemComponent.ENCHANTMENTS, new EnchantmentList(Map.of( + Enchantment.SHARPNESS, 10 + ))) + .build()); + + player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) + .build()); + + player.getInventory().addItemStack(ItemStack.builder(Material.BLACK_BANNER) + .build()); + + player.getInventory().addItemStack(ItemStack.builder(Material.POTION) + .set(ItemComponent.POTION_CONTENTS, new PotionContents(null, null, List.of( + new CustomPotionEffect(PotionEffect.JUMP_BOOST, new CustomPotionEffect.Settings((byte) 4, + 45 * 20, false, true, true, null)) + ))) + .customName(Component.text("Sharpness 10 Sword").append(Component.space()).append(Component.text("§c§l[LEGENDARY]"))) + .build()); + + + if (event.isFirstSpawn()) { + event.getPlayer().sendNotification(new Notification( + Component.text("Welcome!"), + FrameType.TASK, + Material.IRON_SWORD + )); + + player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 0.5f, 1f)); + } }) .addListener(PlayerPacketOutEvent.class, event -> { //System.out.println("out " + event.getPacket().getClass().getSimpleName()); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b3564e09c..b7fb8ce7c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # Important dependencies -data = "1.21.2-rc1-dev" +data = "1.21.2-rv1" adventure = "4.17.0" jetbrainsAnnotations = "24.1.0" slf4j = "2.0.7" diff --git a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java index afbf53560..193fb3bd3 100644 --- a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java +++ b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java @@ -4,11 +4,11 @@ package net.minestom.server; * AUTOGENERATED by ConstantsGenerator */ interface MinecraftConstants { - String VERSION_NAME = "1.21.2-rc1"; + String VERSION_NAME = "1.21.2"; - int PROTOCOL_VERSION = 1073742042; + int PROTOCOL_VERSION = 768; - int DATA_VERSION = 4078; + int DATA_VERSION = 4080; int RESOURCE_PACK_VERSION = 42; diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index c39a96013..1c41abd0b 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -1846,9 +1846,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou @ApiStatus.Internal void synchronizePositionAfterTeleport(@NotNull Pos position, int relativeFlags, boolean shouldConfirm) { int teleportId = shouldConfirm ? getNextTeleportId() : -1; - var posCache = this.position; // TODO(1.21.2): should delta be zero? - sendPacket(new PlayerPositionAndLookPacket(teleportId, posCache, Vec.ZERO, posCache.yaw(), posCache.pitch(), (byte) relativeFlags)); + sendPacket(new PlayerPositionAndLookPacket(teleportId, position, Vec.ZERO, position.yaw(), position.pitch(), (byte) relativeFlags)); super.synchronizePosition(); } diff --git a/src/main/java/net/minestom/server/item/component/Equippable.java b/src/main/java/net/minestom/server/item/component/Equippable.java index 7de5e7f4b..19b047324 100644 --- a/src/main/java/net/minestom/server/item/component/Equippable.java +++ b/src/main/java/net/minestom/server/item/component/Equippable.java @@ -42,4 +42,36 @@ public record Equippable( "swappable", BinaryTagSerializer.BOOLEAN.optional(true), Equippable::swappable, "damage_on_hurt", BinaryTagSerializer.BOOLEAN.optional(true), Equippable::damageOnHurt, Equippable::new); + + public @NotNull Equippable withSlot(@NotNull EquipmentSlot slot) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withEquipSound(@NotNull SoundEvent equipSound) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withModel(@Nullable String model) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withCameraOverlay(@Nullable String cameraOverlay) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withAllowedEntities(@Nullable ObjectSet allowedEntities) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withDispensable(boolean dispensable) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withSwappable(boolean swappable) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + public @NotNull Equippable withDamageOnHurt(boolean damageOnHurt) { + return new Equippable(slot, equipSound, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } } diff --git a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java index 4904058eb..59500f169 100644 --- a/src/main/java/net/minestom/server/listener/PlayerPositionListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerPositionListener.java @@ -17,6 +17,7 @@ public class PlayerPositionListener { private static final Component KICK_MESSAGE = Component.text("You moved too far away!"); public static void playerPacketListener(ClientPlayerPositionStatusPacket packet, Player player) { + // TODO: Should we expose horizontal collision here and the methods below? player.refreshOnGround(packet.onGround()); } @@ -73,9 +74,9 @@ public class PlayerPositionListener { return; } if (playerMoveEvent.isCancelled()) { - // Teleport to previous position - // TODO(1.21.2) verify that setting to zero delta is correct. might need to send opposite of intended move - player.sendPacket(new PlayerPositionAndLookPacket(player.getNextTeleportId(), currentPosition, Vec.ZERO, currentPosition.yaw(), currentPosition.pitch(), (byte) 0x00)); + // Teleport to previous position & cancel any velocity + player.sendPacket(new PlayerPositionAndLookPacket(player.getNextTeleportId(), currentPosition, + Vec.ZERO, currentPosition.yaw(), currentPosition.pitch(), (byte) 0x00)); return; } final Pos eventPosition = playerMoveEvent.getNewPosition(); diff --git a/src/main/java/net/minestom/server/listener/UseItemListener.java b/src/main/java/net/minestom/server/listener/UseItemListener.java index 8b93ae22a..97cc0e777 100644 --- a/src/main/java/net/minestom/server/listener/UseItemListener.java +++ b/src/main/java/net/minestom/server/listener/UseItemListener.java @@ -1,6 +1,5 @@ package net.minestom.server.listener; -import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.Player; import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventDispatcher; @@ -12,6 +11,7 @@ import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.component.Consumable; +import net.minestom.server.item.component.Equippable; import net.minestom.server.network.packet.client.play.ClientUseItemPacket; import net.minestom.server.network.packet.server.play.AcknowledgeBlockChangePacket; import org.jetbrains.annotations.NotNull; @@ -35,10 +35,10 @@ public class UseItemListener { } // Equip armor with right click - final EquipmentSlot equipmentSlot = material.registry().equipmentSlot(); - if (equipmentSlot != null) { - final ItemStack currentlyEquipped = player.getEquipment(equipmentSlot); - player.setEquipment(equipmentSlot, itemStack); + final Equippable equippable = itemStack.get(ItemComponent.EQUIPPABLE); + if (equippable != null && equippable.swappable()) { + final ItemStack currentlyEquipped = player.getEquipment(equippable.slot()); + player.setEquipment(equippable.slot(), itemStack); player.setItemInHand(hand, currentlyEquipped); } diff --git a/src/main/java/net/minestom/server/network/socket/Server.java b/src/main/java/net/minestom/server/network/socket/Server.java index b7949a969..415224415 100644 --- a/src/main/java/net/minestom/server/network/socket/Server.java +++ b/src/main/java/net/minestom/server/network/socket/Server.java @@ -98,7 +98,8 @@ public final class Server { connection.disconnect(); break; } catch (Throwable e) { - MinecraftServer.getExceptionManager().handleException(e); + boolean isExpected = e instanceof SocketException && e.getMessage().equals("Connection reset"); + if (!isExpected) MinecraftServer.getExceptionManager().handleException(e); connection.disconnect(); break; } @@ -113,7 +114,9 @@ public final class Server { connection.disconnect(); break; } catch (Throwable e) { - MinecraftServer.getExceptionManager().handleException(e); + boolean isExpected = e instanceof IOException && e.getMessage().equals("Broken pipe"); + if (!isExpected) MinecraftServer.getExceptionManager().handleException(e); + connection.disconnect(); break; } diff --git a/src/main/java/net/minestom/server/recipe/Recipe.java b/src/main/java/net/minestom/server/recipe/Recipe.java index 547e10722..7ca9c52ee 100644 --- a/src/main/java/net/minestom/server/recipe/Recipe.java +++ b/src/main/java/net/minestom/server/recipe/Recipe.java @@ -3,6 +3,7 @@ package net.minestom.server.recipe; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -75,12 +76,14 @@ public record Recipe(@NotNull String id, @NotNull Data data) { public static final NetworkBuffer.Type SERIALIZER = RecipeSerializers.SMITHING_TRIM; } - public record Ingredient(@NotNull List<@NotNull ItemStack> items) { + public record Ingredient(@NotNull List<@NotNull Material> items) { public Ingredient { items = List.copyOf(items); + Check.argCondition(items.isEmpty(), "Ingredients can't be empty"); + Check.argCondition(items.contains(Material.AIR), "Ingredient can't contain air"); } - public Ingredient(@NotNull ItemStack @NotNull ... items) { + public Ingredient(@NotNull Material @NotNull ... items) { this(List.of(items)); } } diff --git a/src/main/java/net/minestom/server/recipe/RecipeCompute.java b/src/main/java/net/minestom/server/recipe/RecipeCompute.java index 1a5713b47..d5afa6471 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeCompute.java +++ b/src/main/java/net/minestom/server/recipe/RecipeCompute.java @@ -56,8 +56,8 @@ public final class RecipeCompute { if (ingredient.items().isEmpty() && item.isAir()) { validIngredient = true; } else { - for (ItemStack ingredientItem : ingredient.items()) { - if (ingredientItem.isSimilar(item)) { + for (Material ingredientItem : ingredient.items()) { + if (ingredientItem.equals(item.material())) { validIngredient = true; break; } @@ -88,8 +88,7 @@ public final class RecipeCompute { // Check if the recipe is valid for (Recipe.Ingredient ingredient : recipe.ingredients()) { boolean success = false; - for (ItemStack item : ingredient.items()) { - final Material material = item.material(); + for (Material material : ingredient.items()) { final int occurrences = materials.getOrDefault(material, 0); if (occurrences == 0) continue; final int reduced = occurrences - 1; diff --git a/src/main/java/net/minestom/server/recipe/RecipeManager.java b/src/main/java/net/minestom/server/recipe/RecipeManager.java index a7118d390..8f4979e29 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeManager.java +++ b/src/main/java/net/minestom/server/recipe/RecipeManager.java @@ -1,9 +1,11 @@ package net.minestom.server.recipe; import net.minestom.server.entity.Player; +import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.play.DeclareRecipesPacket; +import net.minestom.server.recipe.display.SlotDisplay; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -50,6 +52,8 @@ public final class RecipeManager { private @NotNull DeclareRecipesPacket createDeclareRecipesPacket() { //TODO(1.21.2): Recipe property lists & stonecutter recipes - return new DeclareRecipesPacket(Map.of(), List.of()); + return new DeclareRecipesPacket(Map.of(), List.of(new DeclareRecipesPacket.StonecutterRecipe( + new Recipe.Ingredient(Material.DIAMOND), + SlotDisplay.AnyFuel.INSTANCE))); } } diff --git a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java index d1c483047..71722e2d1 100644 --- a/src/main/java/net/minestom/server/recipe/RecipeSerializers.java +++ b/src/main/java/net/minestom/server/recipe/RecipeSerializers.java @@ -4,6 +4,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBufferTemplate; +import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -30,17 +31,26 @@ public final class RecipeSerializers { // non-dynamic registry types. We need to improve how the tag system works generally. new Type<>() { @Override - public void write(@NotNull NetworkBuffer buffer, List value) { + public void write(@NotNull NetworkBuffer buffer, List value) { // +1 because 0 indicates that an item tag name follows (in this case it does not). buffer.write(VAR_INT, value.size() + 1); - for (ItemStack itemStack : value) { - buffer.write(ItemStack.STRICT_NETWORK_TYPE, itemStack); + for (Material material : value) { + buffer.write(Material.NETWORK_TYPE, material); } } @Override - public List read(@NotNull NetworkBuffer buffer) { - throw new UnsupportedOperationException("cannot read ingredients yet"); + public List read(@NotNull NetworkBuffer buffer) { + int size = buffer.read(VAR_INT) - 1; + Check.notNull(size > Short.MAX_VALUE, "too many ingredients"); + if (size == -1) { + throw new UnsupportedOperationException("cannot read ingredient tags yet"); + } + + final List materials = new ArrayList<>(size); + for (int i = 0; i < size; i++) + materials.add(buffer.read(Material.NETWORK_TYPE)); + return materials; } }, Ingredient::items, Ingredient::new diff --git a/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java b/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java index df9b8f3b9..eaa513b9d 100644 --- a/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/EntityTeleportIntegrationTest.java @@ -2,15 +2,12 @@ package net.minestom.server.entity; import net.minestom.server.coordinate.Pos; import net.minestom.server.network.packet.server.ServerPacket; -import net.minestom.server.network.packet.server.play.EntityHeadLookPacket; -import net.minestom.server.network.packet.server.play.EntityTeleportPacket; +import net.minestom.server.network.packet.server.play.EntityPositionSyncPacket; import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; @EnvTest @@ -62,15 +59,12 @@ public class EntityTeleportIntegrationTest { packet -> assertEquals(teleportPosition, packet.position())); // Verify broadcast packet(s) - viewerTracker.assertCount(2); - List packets = viewerTracker.collect(); - var teleportPacket = (EntityTeleportPacket) packets.get(0); - assertEquals(player.getEntityId(), teleportPacket.entityId()); - assertEquals(teleportPosition, teleportPacket.position()); - - var headLookPacket = (EntityHeadLookPacket) packets.get(1); - assertEquals(player.getEntityId(), headLookPacket.entityId()); - assertEquals(teleportPosition.yaw(), headLookPacket.yaw()); + viewerTracker.assertCount(1); + viewerTracker.assertSingle(EntityPositionSyncPacket.class, packet -> { + assertEquals(player.getEntityId(), packet.entityId()); + assertEquals(teleportPosition, packet.position()); + assertEquals(teleportPosition.yaw(), packet.yaw()); + }); } @Test diff --git a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java index 2f527f3a4..8a019ff35 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerIntegrationTest.java @@ -249,7 +249,7 @@ public class PlayerIntegrationTest { assertEquals(startingPlayerPos.withView(30, 20), player.getPosition()); tracker.assertSingle(PlayerPositionAndLookPacket.class, packet -> { assertEquals(RelativeFlags.COORD, packet.flags()); - assertEquals(packet.position(), new Pos(0, 0, 0, 30, 20)); + assertEquals(new Pos(0, 0, 0, 30, 20), packet.position()); }); } diff --git a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java index b0d3ae223..f18bc3ab3 100644 --- a/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java +++ b/src/test/java/net/minestom/server/entity/player/PlayerMovementIntegrationTest.java @@ -1,11 +1,35 @@ package net.minestom.server.entity.player; +import net.minestom.server.ServerFlag; +import net.minestom.server.coordinate.ChunkRange; import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Player; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.instance.Chunk; +import net.minestom.server.instance.Instance; +import net.minestom.server.message.ChatMessageType; +import net.minestom.server.network.packet.client.common.ClientSettingsPacket; +import net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket; +import net.minestom.server.network.packet.client.play.ClientTeleportConfirmPacket; +import net.minestom.server.network.packet.server.play.ChunkDataPacket; +import net.minestom.server.network.packet.server.play.EntityPositionPacket; +import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket; +import net.minestom.server.network.packet.server.play.UnloadChunkPacket; +import net.minestom.server.network.player.ClientSettings; +import net.minestom.server.utils.MathUtils; +import net.minestom.testing.Collector; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; +import net.minestom.testing.TestConnection; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.fail; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import static org.junit.jupiter.api.Assertions.assertEquals; @EnvTest public class PlayerMovementIntegrationTest { @@ -15,145 +39,165 @@ public class PlayerMovementIntegrationTest { var instance = env.createFlatInstance(); var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); // No confirmation -// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); -// p1.interpretPacketQueue(); -// assertEquals(new Pos(0, 40, 0), p1.getPosition()); -// // Confirmation -// p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); -// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); -// p1.interpretPacketQueue(); -// assertEquals(new Pos(0.2, 40, 0), p1.getPosition()); - fail("TODO(1.21.2) position packet change"); + p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true, false)); + p1.interpretPacketQueue(); + assertEquals(new Pos(0, 40, 0), p1.getPosition()); + // Confirmation + p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); + p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true, false)); + p1.interpretPacketQueue(); + assertEquals(new Pos(0.2, 40, 0), p1.getPosition()); } // FIXME //@Test public void singleTickMovementUpdate(Env env) { -// var instance = env.createFlatInstance(); -// var connection = env.createConnection(); -// var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); -// connection.connect(instance, new Pos(0, 40, 0)); -// -// p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); -// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); -// p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true)); -// var tracker = connection.trackIncoming(EntityPositionPacket.class); -// p1.interpretPacketQueue(); -// -// // Position update should only be sent once per tick independently of the number of packets -// tracker.assertSingle(); - fail("TODO(1.21.2) position packet change"); + var instance = env.createFlatInstance(); + var connection = env.createConnection(); + var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); + connection.connect(instance, new Pos(0, 40, 0)); + + p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); + p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true, false)); + p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true, false)); + var tracker = connection.trackIncoming(EntityPositionPacket.class); + p1.interpretPacketQueue(); + + // Position update should only be sent once per tick independently of the number of packets + tracker.assertSingle(); } @Test public void chunkUpdateDebounceTest(Env env) { -// final Instance flatInstance = env.createFlatInstance(); -// final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; -// // Preload all possible chunks to avoid issues due to async loading -// Set> chunks = new HashSet<>(); -// ChunkRange.chunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); -// CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); -// final TestConnection connection = env.createConnection(); -// Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// final Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); -// // Initial join -// chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); -// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertCount(viewDiameter); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertCount(viewDiameter); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertCount(viewDiameter); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertEmpty(); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertEmpty(); -// -// // Move to next chunk -// chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// // Abuse the fact that there is no delta check -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1); - fail("TODO(1.21.2) position packet change"); + final Instance flatInstance = env.createFlatInstance(); + final int viewDiameter = ServerFlag.CHUNK_VIEW_DISTANCE * 2 + 1; + // Preload all possible chunks to avoid issues due to async loading + Set> chunks = new HashSet<>(); + ChunkRange.chunksInRange(0, 0, viewDiameter + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); + final TestConnection connection = env.createConnection(); + Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + final Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); + // Initial join + chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); + player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertCount(viewDiameter); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertCount(viewDiameter); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertCount(viewDiameter); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertEmpty(); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertEmpty(); + + // Move to next chunk + chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + // Abuse the fact that there is no delta check + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1); } @Test public void testClientViewDistanceSettings(Env env) { -// int viewDistance = 4; -// final Instance flatInstance = env.createFlatInstance(); -// var connection = env.createConnection(); -// Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); -// // Preload all possible chunks to avoid issues due to async loading -// Set> chunks = new HashSet<>(); -// ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); -// CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); -// player.refreshSettings(new ClientSettings( -// Locale.US, (byte) viewDistance, -// ChatMessageType.FULL, true, -// (byte) 0, ClientSettings.MainHand.RIGHT, -// false, true -// )); -// -// Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); -// player.teleport(new Pos(160, 40, 160)); -// player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); -// player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(160.5, 40, 160.5), true)); -// player.interpretPacketQueue(); -// chunkDataPacketCollector.assertCount(MathUtils.square(viewDistance * 2 + 1)); - fail("TODO(1.21.2) position packet change"); + int viewDistance = 4; + final Instance flatInstance = env.createFlatInstance(); + var connection = env.createConnection(); + Player player = connection.connect(flatInstance, new Pos(0.5, 40, 0.5)); + // Preload all possible chunks to avoid issues due to async loading + Set> chunks = new HashSet<>(); + ChunkRange.chunksInRange(10, 10, viewDistance + 2, (x, z) -> chunks.add(flatInstance.loadChunk(x, z))); + CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); + player.refreshSettings(new ClientSettings( + Locale.US, (byte) viewDistance, + ChatMessageType.FULL, true, + (byte) 0, ClientSettings.MainHand.RIGHT, + false, true, + ClientSettings.ParticleSetting.ALL + )); + + Collector chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); + player.teleport(new Pos(160, 40, 160)); + player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); + player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(160.5, 40, 160.5), true, false)); + player.interpretPacketQueue(); + chunkDataPacketCollector.assertCount(MathUtils.square(viewDistance * 2 + 1)); } @Test public void testSettingsViewDistanceExpansionAndShrink(Env env) { -// int startingViewDistance = 8; -// byte endViewDistance = 12; -// byte finalViewDistance = 10; -// var instance = env.createFlatInstance(); -// var connection = env.createConnection(); -// Pos startingPlayerPos = new Pos(0, 42, 0); -// var player = connection.connect(instance, startingPlayerPos); -// -// int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); -// -// // Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread -// ChunkRange.chunksInRange(0, 0, endViewDistance, instance::loadChunk); -// -// var tracker = connection.trackIncoming(ChunkDataPacket.class); -// player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, -// ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); -// player.interpretPacketQueue(); -// tracker.assertCount(chunkDifference); -// -// var tracker1 = connection.trackIncoming(UnloadChunkPacket.class); -// player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, finalViewDistance, -// ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, false, true))); -// player.interpretPacketQueue(); -// -// int chunkDifference1 = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(finalViewDistance); -// tracker1.assertCount(chunkDifference1); - fail("TODO(1.21.2) position packet change"); + int startingViewDistance = 8; + byte endViewDistance = 12; + byte finalViewDistance = 10; + var instance = env.createFlatInstance(); + var connection = env.createConnection(); + Pos startingPlayerPos = new Pos(0, 42, 0); + var player = connection.connect(instance, startingPlayerPos); + + int chunkDifference = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(startingViewDistance); + + // Preload chunks, otherwise our first tracker.assertCount call will fail randomly due to chunks being loaded off the main thread + ChunkRange.chunksInRange(0, 0, endViewDistance, instance::loadChunk); + + var tracker = connection.trackIncoming(ChunkDataPacket.class); + player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, endViewDistance, + ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, + false, true, ClientSettings.ParticleSetting.ALL))); + player.interpretPacketQueue(); + tracker.assertCount(chunkDifference); + + var tracker1 = connection.trackIncoming(UnloadChunkPacket.class); + player.addPacketToQueue(new ClientSettingsPacket(new ClientSettings(Locale.US, finalViewDistance, + ChatMessageType.FULL, false, (byte) 0, ClientSettings.MainHand.RIGHT, + false, true, ClientSettings.ParticleSetting.ALL))); + player.interpretPacketQueue(); + + int chunkDifference1 = ChunkRange.chunksCount(endViewDistance) - ChunkRange.chunksCount(finalViewDistance); + tracker1.assertCount(chunkDifference1); + } + + @Test + public void testCancelledMove(Env env) { + var instance = env.createFlatInstance(); + var connection = env.createConnection(); + var p1 = connection.connect(instance, new Pos(0, 40, 0)); + p1.refreshReceivedTeleportId(p1.getLastSentTeleportId()); // Don't care about teleport confirm from spawn + + instance.eventNode().addListener(PlayerMoveEvent.class, event -> event.setCancelled(true)); + var collector = connection.trackIncoming(PlayerPositionAndLookPacket.class); + + p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true, false)); + p1.interpretPacketQueue(); + + assertEquals(new Pos(0, 40, 0), p1.getPosition()); + collector.assertSingle(packet -> { + assertEquals(0, packet.flags()); + assertEquals(new Vec(0, 40, 0), Vec.fromPoint(packet.position())); + // Must reset velocity or the player will keep moving and create a loop of teleport cancel teleport. + assertEquals(Vec.ZERO, packet.delta()); + }); } } diff --git a/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java b/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java index 7fcd6f7d5..0e3fcc970 100644 --- a/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java +++ b/src/test/java/net/minestom/server/listener/TestUseItemListenerIntegration.java @@ -5,13 +5,17 @@ import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.PlayerHand; import net.minestom.server.event.EventFilter; import net.minestom.server.event.player.PlayerUseItemEvent; +import net.minestom.server.item.ItemComponent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.component.Equippable; import net.minestom.server.network.packet.client.play.ClientUseItemPacket; import net.minestom.testing.Env; import net.minestom.testing.EnvTest; import org.junit.jupiter.api.Test; +import java.util.function.UnaryOperator; + import static org.junit.jupiter.api.Assertions.assertEquals; @EnvTest @@ -64,4 +68,34 @@ public class TestUseItemListenerIntegration { assertEquals(oldBoots, player.getItemInMainHand()); assertEquals(boots, player.getEquipment(EquipmentSlot.BOOTS)); } + + @Test + void testDoNotEquipNonEquippableArmor(Env env) { + var instance = env.createFlatInstance(); + var player = env.createPlayer(instance, new Pos(0, 41, 0)); + + var badBoots = ItemStack.of(Material.GOLDEN_BOOTS).without(ItemComponent.EQUIPPABLE); + player.setItemInMainHand(badBoots); + UseItemListener.useItemListener(new ClientUseItemPacket(PlayerHand.MAIN, 42, 0f, 0f), player); + + assertEquals(badBoots, player.getItemInMainHand()); + assertEquals(ItemStack.AIR, player.getEquipment(EquipmentSlot.BOOTS)); + } + + @Test + void testDoNotSwapNonSwappableArmor(Env env) { + var instance = env.createFlatInstance(); + var player = env.createPlayer(instance, new Pos(0, 41, 0)); + + var oldBoots = ItemStack.of(Material.GOLDEN_BOOTS); + player.setEquipment(EquipmentSlot.BOOTS, oldBoots); + + var boots = ItemStack.of(Material.DIAMOND_BOOTS).with(ItemComponent.EQUIPPABLE, + (UnaryOperator) (eq) -> eq.withSwappable(false)); + player.setItemInMainHand(boots); + UseItemListener.useItemListener(new ClientUseItemPacket(PlayerHand.MAIN, 42, 0f, 0f), player); + + assertEquals(boots, player.getItemInMainHand()); + assertEquals(oldBoots, player.getEquipment(EquipmentSlot.BOOTS)); + } } diff --git a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java index a43167a18..0d2541984 100644 --- a/src/test/java/net/minestom/server/network/PacketWriteReadTest.java +++ b/src/test/java/net/minestom/server/network/PacketWriteReadTest.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.Component; +import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.GameMode; @@ -22,6 +23,9 @@ import net.minestom.server.network.packet.server.login.SetCompressionPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.status.ResponsePacket; import net.minestom.server.network.player.GameProfile; +import net.minestom.server.recipe.Recipe; +import net.minestom.server.recipe.RecipeProperty; +import net.minestom.server.recipe.display.SlotDisplay; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -31,7 +35,6 @@ import java.util.Map; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; /** * Ensures that packet can be written and read correctly. @@ -45,6 +48,8 @@ public class PacketWriteReadTest { @BeforeAll public static void setupServer() { + MinecraftServer.init(); // Need some tags in here, pretty gross. + // Handshake SERVER_PACKETS.add(new ResponsePacket(new JsonObject().toString())); // Status @@ -77,48 +82,18 @@ public class PacketWriteReadTest { SERVER_PACKETS.add(new CollectItemPacket(5, 5, 5)); SERVER_PACKETS.add(new PlaceGhostRecipePacket((byte) 2, "recipe")); SERVER_PACKETS.add(new DeathCombatEventPacket(5, COMPONENT)); -// SERVER_PACKETS.add(new DeclareRecipesPacket( -// List.of(new Recipe( -// "minecraft:sticks", -// new Recipe.Shapeless("sticks", RecipeCategory.Crafting.MISC, -// List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.OAK_PLANKS)))), -// ItemStack.of(Material.STICK)) -// ), -// new Recipe( -// "minecraft:torch", -// new Recipe.Shaped("", -// RecipeCategory.Crafting.MISC, -// 1, -// 2, -// List.of(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), -// new Recipe.Ingredient(List.of(ItemStack.of(Material.STICK)))), -// ItemStack.of(Material.TORCH), -// true) -// ), -// new Recipe( -// "minecraft:coal", -// new Recipe.Blasting("forging", -// RecipeCategory.Cooking.MISC, -// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL))), -// ItemStack.of(Material.IRON_INGOT), -// 5, -// 5) -// ), -// new Recipe( -// "minecraft:iron_to_diamond", -// new Recipe.SmithingTransform(new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), -// new Recipe.Ingredient(List.of(ItemStack.of(Material.DIAMOND))), -// new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), -// ItemStack.of(Material.DIAMOND)) -// ), -// new Recipe( -// "minecraft:iron_to_coast", -// new Recipe.SmithingTrim(new Recipe.Ingredient(List.of(ItemStack.of(Material.IRON_INGOT))), -// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAST_ARMOR_TRIM_SMITHING_TEMPLATE))), -// new Recipe.Ingredient(List.of(ItemStack.of(Material.COAL)))) -// ) -// ))); - fail("TODO(1.21.2) recipe packet change"); + SERVER_PACKETS.add(new DeclareRecipesPacket(Map.of( + RecipeProperty.SMITHING_BASE, List.of(Material.STONE), + RecipeProperty.SMITHING_TEMPLATE, List.of(Material.STONE), + RecipeProperty.SMITHING_ADDITION, List.of(Material.STONE), + RecipeProperty.FURNACE_INPUT, List.of(Material.STONE), + RecipeProperty.BLAST_FURNACE_INPUT, List.of(Material.IRON_HOE, Material.DANDELION), + RecipeProperty.SMOKER_INPUT, List.of(Material.STONE), + RecipeProperty.CAMPFIRE_INPUT, List.of(Material.STONE)), + List.of(new DeclareRecipesPacket.StonecutterRecipe(new Recipe.Ingredient(Material.DIAMOND), + new SlotDisplay.ItemStack(ItemStack.of(Material.GOLD_BLOCK)))) + )); + // TODO(1.21.2) recipe book add/remove SERVER_PACKETS.add(new DestroyEntitiesPacket(List.of(5, 5, 5))); SERVER_PACKETS.add(new DisconnectPacket(COMPONENT)); @@ -150,7 +125,7 @@ public class PacketWriteReadTest { SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LISTED, new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), true, 0, GameMode.SURVIVAL, null, null, 0))); SERVER_PACKETS.add(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LIST_ORDER, - new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), true, 0, GameMode.SURVIVAL, null, null, 42))); + new PlayerInfoUpdatePacket.Entry(UUID.randomUUID(), "", List.of(), false, 0, GameMode.SURVIVAL, null, null, 42))); SERVER_PACKETS.add(new PlayerInfoRemovePacket(UUID.randomUUID())); } diff --git a/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java b/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java deleted file mode 100644 index f05d9f037..000000000 --- a/src/test/java/net/minestom/server/recipe/IngredientSerializationTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.minestom.server.recipe; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.network.NetworkBuffer; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class IngredientSerializationTest { - - @Test - public void cannotWriteAirIngredient() { - var ingredient = new Recipe.Ingredient(List.of(ItemStack.AIR)); - assertThrows(IllegalArgumentException.class, () -> - NetworkBuffer.makeArray(RecipeSerializers.INGREDIENT, ingredient)); - } -} diff --git a/src/test/java/net/minestom/server/recipe/IngredientTest.java b/src/test/java/net/minestom/server/recipe/IngredientTest.java new file mode 100644 index 000000000..50c493148 --- /dev/null +++ b/src/test/java/net/minestom/server/recipe/IngredientTest.java @@ -0,0 +1,21 @@ +package net.minestom.server.recipe; + +import net.minestom.server.item.Material; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class IngredientTest { + + @Test + public void cannotCreateAirIngredient() { + assertThrows(IllegalArgumentException.class, () -> new Recipe.Ingredient(Material.AIR)); + } + + @Test + public void cannotCreateEmptyIngredient() { + assertThrows(IllegalArgumentException.class, () -> new Recipe.Ingredient(List.of())); + } +} From 3f1841b66949bb2e3c0ab40ce17aa50b27ae0c23 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 22 Oct 2024 22:09:59 -0400 Subject: [PATCH 51/97] fix: add new customName field to potion contents --- .../java/net/minestom/demo/PlayerInit.java | 2 +- .../minestom/server/item/ItemComponent.java | 1 + .../server/item/component/PotionContents.java | 56 +++++++++---------- .../item/component/PotionContentsTest.java | 2 +- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 7b77abd76..d82c81a0b 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -147,7 +147,7 @@ public class PlayerInit { Enchantment.SHARPNESS, 10 ))) .build()); - +// player.getInventory().addItemStack(ItemStack.builder(Material.STONE_SWORD) .build()); diff --git a/src/main/java/net/minestom/server/item/ItemComponent.java b/src/main/java/net/minestom/server/item/ItemComponent.java index 02982ade9..4ecea7c68 100644 --- a/src/main/java/net/minestom/server/item/ItemComponent.java +++ b/src/main/java/net/minestom/server/item/ItemComponent.java @@ -95,6 +95,7 @@ public final class ItemComponent { public static final DataComponent> CONTAINER = register("container", ItemStack.NETWORK_TYPE.list(256), BinaryTagSerializer.ITEM.list()); public static final DataComponent BLOCK_STATE = register("block_state", ItemBlockState.NETWORK_TYPE, ItemBlockState.NBT_TYPE); public static final DataComponent> BEES = register("bees", Bee.NETWORK_TYPE.list(Short.MAX_VALUE), Bee.NBT_TYPE.list()); + // TODO(1.21.2) Updated NBT format > https://minecraft.wiki/w/Java_Edition_1.21.2#Data_components_3 public static final DataComponent LOCK = register("lock", null, BinaryTagSerializer.STRING); public static final DataComponent CONTAINER_LOOT = register("container_loot", null, SeededContainerLoot.NBT_TYPE); diff --git a/src/main/java/net/minestom/server/item/component/PotionContents.java b/src/main/java/net/minestom/server/item/component/PotionContents.java index 27679ef77..e4f45fa58 100644 --- a/src/main/java/net/minestom/server/item/component/PotionContents.java +++ b/src/main/java/net/minestom/server/item/component/PotionContents.java @@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.*; import net.kyori.adventure.util.RGBLike; import net.minestom.server.color.Color; import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.potion.CustomPotionEffect; import net.minestom.server.potion.PotionType; import net.minestom.server.utils.nbt.BinaryTagSerializer; @@ -16,30 +17,17 @@ import java.util.List; public record PotionContents( @Nullable PotionType potion, @Nullable RGBLike customColor, - @NotNull List customEffects + @NotNull List customEffects, + @Nullable String customName ) { - public static final int POTION_DRINK_TIME = 32; // 32 ticks, in ms - public static final PotionContents EMPTY = new PotionContents(null, null, List.of()); + public static final PotionContents EMPTY = new PotionContents(null, null, List.of(), null); - public static final NetworkBuffer.Type NETWORK_TYPE = new NetworkBuffer.Type<>() { - @Override - public void write(@NotNull NetworkBuffer buffer, PotionContents value) { - Integer typeId = value.potion == null ? null : value.potion.id(); - buffer.write(NetworkBuffer.VAR_INT.optional(), typeId); - buffer.write(Color.NETWORK_TYPE.optional(), value.customColor); - buffer.write(CustomPotionEffect.NETWORK_TYPE.list(), value.customEffects); - } - - @Override - public PotionContents read(@NotNull NetworkBuffer buffer) { - Integer typeId = buffer.read(NetworkBuffer.VAR_INT.optional()); - return new PotionContents( - typeId == null ? null : PotionType.fromId(typeId), - buffer.read(Color.NETWORK_TYPE.optional()), - buffer.read(CustomPotionEffect.NETWORK_TYPE.list(Short.MAX_VALUE)) - ); - } - }; + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBufferTemplate.template( + PotionType.NETWORK_TYPE.optional(), PotionContents::potion, + Color.NETWORK_TYPE.optional(), PotionContents::customColor, + CustomPotionEffect.NETWORK_TYPE.list(Short.MAX_VALUE), PotionContents::customEffects, + NetworkBuffer.STRING.optional(), PotionContents::customName, + PotionContents::new); public static final BinaryTagSerializer NBT_TYPE = new BinaryTagSerializer<>() { @Override @@ -62,6 +50,10 @@ public record PotionContents( builder.put("custom_effects", effectsBuilder.build()); } + if (value.customName != null) { + builder.putString("custom_name", value.customName); + } + return builder.build(); } @@ -69,7 +61,7 @@ public record PotionContents( public @NotNull PotionContents read(@NotNull BinaryTag tag) { // Can be a string with just a potion effect id if (tag instanceof StringBinaryTag string) { - return new PotionContents(PotionType.fromNamespaceId(string.value()), null, List.of()); + return new PotionContents(PotionType.fromNamespaceId(string.value()), null, List.of(), null); } // Otherwise must be a compound @@ -95,7 +87,11 @@ public record PotionContents( customEffects.add(CustomPotionEffect.NBT_TYPE.read(customEffectCompound)); } - return new PotionContents(potion, customColor, customEffects); + String customName = null; + if (compound.get("custom_name") instanceof StringBinaryTag customNameTag) + customName = customNameTag.value(); + + return new PotionContents(potion, customColor, customEffects, customName); } }; @@ -104,19 +100,23 @@ public record PotionContents( } public PotionContents(@NotNull PotionType potion) { - this(potion, null, List.of()); + this(potion, null, List.of(), null); } public PotionContents(@NotNull PotionType potion, @NotNull RGBLike customColor) { - this(potion, customColor, List.of()); + this(potion, customColor, List.of(), null); } public PotionContents(@NotNull List customEffects) { - this(null, null, customEffects); + this(null, null, customEffects, null); } public PotionContents(@NotNull CustomPotionEffect customEffect) { - this(null, null, List.of(customEffect)); + this(null, null, List.of(customEffect), null); + } + + public PotionContents(@Nullable PotionType potion, @Nullable RGBLike customColor, @NotNull List customEffects) { + this(potion, customColor, customEffects, null); } } diff --git a/src/test/java/net/minestom/server/item/component/PotionContentsTest.java b/src/test/java/net/minestom/server/item/component/PotionContentsTest.java index 4913fb118..3fedc7cfe 100644 --- a/src/test/java/net/minestom/server/item/component/PotionContentsTest.java +++ b/src/test/java/net/minestom/server/item/component/PotionContentsTest.java @@ -43,7 +43,7 @@ public class PotionContentsTest extends AbstractItemComponentTest Date: Tue, 22 Oct 2024 22:20:04 -0400 Subject: [PATCH 52/97] chore: rebase fixes --- .../net/minestom/server/instance/Instance.java | 2 +- .../packet/ClientPluginMessagePacketTest.java | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index f1c1cae2c..885f34a9e 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -444,7 +444,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, */ public void setWorldAge(long worldAge) { this.worldAge = worldAge; - PacketUtils.sendGroupedPacket(getPlayers(), createTimePacket()); + PacketSendingUtils.sendGroupedPacket(getPlayers(), createTimePacket()); } /** diff --git a/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java b/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java index d017b4a42..e49e71669 100644 --- a/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java +++ b/src/test/java/net/minestom/server/network/packet/ClientPluginMessagePacketTest.java @@ -4,8 +4,6 @@ import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket; import org.junit.jupiter.api.Test; -import java.nio.ByteBuffer; - import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -13,14 +11,12 @@ public class ClientPluginMessagePacketTest { @Test void testClientPluginMessagePacket() { - ByteBuffer buf = ByteBuffer.allocateDirect(1024); // The default from NetworkBuffer - NetworkBuffer networkBuffer = new NetworkBuffer(buf); - ClientPluginMessagePacket clientPluginMessagePacket = new ClientPluginMessagePacket("channel", new byte[0]); + var array = NetworkBuffer.makeArray( + ClientPluginMessagePacket.SERIALIZER, + new ClientPluginMessagePacket("channel", new byte[0])); - clientPluginMessagePacket.write(networkBuffer); - buf.limit(networkBuffer.writeIndex()); // Must set limit so that RAW_BYTES in plugin message packet has a len. - - var packet = new ClientPluginMessagePacket(networkBuffer); + var readBuffer = NetworkBuffer.wrap(array, 0, array.length); + var packet = readBuffer.read(ClientPluginMessagePacket.SERIALIZER); assertEquals("channel", packet.channel()); assertArrayEquals(new byte[0], packet.data()); From 102db50d052e5f86d2762b54dc4fa209ab197ac9 Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 23 Oct 2024 07:33:07 -0400 Subject: [PATCH 53/97] chore: test for parsing commands packet with 'unsupported' arg parser --- .../packet/DeclareCommandsPacketTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/java/net/minestom/server/network/packet/DeclareCommandsPacketTest.java diff --git a/src/test/java/net/minestom/server/network/packet/DeclareCommandsPacketTest.java b/src/test/java/net/minestom/server/network/packet/DeclareCommandsPacketTest.java new file mode 100644 index 000000000..9c67e0d09 --- /dev/null +++ b/src/test/java/net/minestom/server/network/packet/DeclareCommandsPacketTest.java @@ -0,0 +1,25 @@ +package net.minestom.server.network.packet; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.network.packet.server.play.DeclareCommandsPacket; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static net.minestom.server.network.packet.server.play.DeclareCommandsPacket.getFlag; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DeclareCommandsPacketTest { + + @Test + void testWriteGameProfileArg() { + var root = new DeclareCommandsPacket.Node(); + root.flags = getFlag(DeclareCommandsPacket.NodeType.ARGUMENT, false, false, false); + root.parser = "minecraft:game_profile"; + var packet = new DeclareCommandsPacket(List.of(root), 0); + + var array = NetworkBuffer.makeArray(DeclareCommandsPacket.SERIALIZER, packet); + var readPacket = NetworkBuffer.wrap(array, 0, array.length).read(DeclareCommandsPacket.SERIALIZER); + assertEquals("minecraft:game_profile", readPacket.nodes().getFirst().parser); + } +} From 5e17487155379174af7b4c7f045cb5608fe0e3c4 Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 23 Oct 2024 07:49:01 -0400 Subject: [PATCH 54/97] fix: allow custom player provider in env tests (fixes #2438) --- .../test/EnvTestPlayerProviderTest.java | 34 +++++++++++++++++++ .../java/net/minestom/testing/EnvImpl.java | 4 +++ .../minestom/testing/TestConnectionImpl.java | 4 +-- 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/test/java/net/minestom/server/test/EnvTestPlayerProviderTest.java diff --git a/src/test/java/net/minestom/server/test/EnvTestPlayerProviderTest.java b/src/test/java/net/minestom/server/test/EnvTestPlayerProviderTest.java new file mode 100644 index 000000000..afc575747 --- /dev/null +++ b/src/test/java/net/minestom/server/test/EnvTestPlayerProviderTest.java @@ -0,0 +1,34 @@ +package net.minestom.server.test; + +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Player; +import net.minestom.server.network.player.GameProfile; +import net.minestom.server.network.player.PlayerConnection; +import net.minestom.testing.Env; +import net.minestom.testing.EnvTest; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +@EnvTest +public class EnvTestPlayerProviderTest { + + public static class CustomPlayer extends Player { + public CustomPlayer(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) { + super(playerConnection, gameProfile); + } + } + + @Test + void testPlayerProviderUsedInEnvTest(Env env) { + // Note: By default the test environment will use a player provider of its own to bypass the queued chunk system + // overriding in a particular test will mean that chunk packets are not received consistently (they require the + // chunk queue interaction). However, this is not a problem for many tests, so we do support it. + + env.process().connection().setPlayerProvider(CustomPlayer::new); + var instance = env.createFlatInstance(); + var player = env.createPlayer(instance, new Pos(0, 42, 0)); + assertInstanceOf(CustomPlayer.class, player); + } +} diff --git a/testing/src/main/java/net/minestom/testing/EnvImpl.java b/testing/src/main/java/net/minestom/testing/EnvImpl.java index 89f1c9c7a..ec02253fb 100644 --- a/testing/src/main/java/net/minestom/testing/EnvImpl.java +++ b/testing/src/main/java/net/minestom/testing/EnvImpl.java @@ -19,6 +19,10 @@ final class EnvImpl implements Env { public EnvImpl(ServerProcess process) { this.process = process; + + // Use player provider to disable queued chunk sending. + // Set here to allow an individual test to override if they want. + process.connection().setPlayerProvider(TestConnectionImpl.TestPlayerImpl::new); } @Override diff --git a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java index 114adee4d..ae9877111 100644 --- a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java +++ b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java @@ -36,8 +36,6 @@ final class TestConnectionImpl implements TestConnection { TestConnectionImpl(Env env) { this.env = env; this.process = env.process(); - // Use player provider to disable queued chunk sending - env.process().connection().setPlayerProvider(TestPlayerImpl::new); } @Override @@ -133,7 +131,7 @@ final class TestConnectionImpl implements TestConnection { } } - final class TestPlayerImpl extends Player { + static final class TestPlayerImpl extends Player { public TestPlayerImpl(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) { super(playerConnection, gameProfile); } From 85ae6ea821826c41c14883853cf0e6e37ef4167c Mon Sep 17 00:00:00 2001 From: MelonHell <53826469+MelonHell@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:20:45 +0300 Subject: [PATCH 55/97] AsyncPlayerPreLoginEvent getConnection (#2446) * AsyncPlayerPreLoginEvent getConnection * reorder fields --- .../server/event/player/AsyncPlayerPreLoginEvent.java | 10 +++++++++- .../net/minestom/server/network/ConnectionManager.java | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java index 426af5644..035158cde 100644 --- a/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java +++ b/src/main/java/net/minestom/server/event/player/AsyncPlayerPreLoginEvent.java @@ -2,6 +2,7 @@ package net.minestom.server.event.player; import net.minestom.server.event.Event; import net.minestom.server.network.player.GameProfile; +import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.plugin.LoginPlugin; import net.minestom.server.network.plugin.LoginPluginMessageProcessor; import org.jetbrains.annotations.NotNull; @@ -15,15 +16,22 @@ import java.util.concurrent.CompletableFuture; */ public class AsyncPlayerPreLoginEvent implements Event { + private final PlayerConnection connection; private GameProfile gameProfile; private final LoginPluginMessageProcessor pluginMessageProcessor; - public AsyncPlayerPreLoginEvent(@NotNull GameProfile gameProfile, + public AsyncPlayerPreLoginEvent(@NotNull PlayerConnection connection, + @NotNull GameProfile gameProfile, @NotNull LoginPluginMessageProcessor pluginMessageProcessor) { + this.connection = connection; this.gameProfile = gameProfile; this.pluginMessageProcessor = pluginMessageProcessor; } + public @NotNull PlayerConnection getConnection() { + return connection; + } + public GameProfile getGameProfile() { return gameProfile; } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 624ece2ce..5e7fac680 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -189,7 +189,7 @@ public final class ConnectionManager { } // Call pre login event LoginPluginMessageProcessor pluginMessageProcessor = connection.loginPluginMessageProcessor(); - AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(gameProfile, pluginMessageProcessor); + AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(connection, gameProfile, pluginMessageProcessor); EventDispatcher.call(asyncPlayerPreLoginEvent); if (!connection.isOnline()) return gameProfile; // Player has been kicked // Change UUID/Username based on the event From 378c10a84f43b9c77c9a5dc5236228a9b354794f Mon Sep 17 00:00:00 2001 From: MelonHell <53826469+MelonHell@users.noreply.github.com> Date: Thu, 24 Oct 2024 04:53:00 +0300 Subject: [PATCH 56/97] Update RelativeFlags (#2447) --- .../net/minestom/server/entity/RelativeFlags.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/entity/RelativeFlags.java b/src/main/java/net/minestom/server/entity/RelativeFlags.java index 344dafad4..b4014b4ad 100644 --- a/src/main/java/net/minestom/server/entity/RelativeFlags.java +++ b/src/main/java/net/minestom/server/entity/RelativeFlags.java @@ -2,12 +2,21 @@ package net.minestom.server.entity; public class RelativeFlags { public static final int NONE = 0x00; + public static final int X = 0x01; public static final int Y = 0x02; public static final int Z = 0x04; + public static final int YAW = 0x08; public static final int PITCH = 0x10; + + public static final int DELTA_X = 0x20; + public static final int DELTA_Y = 0x40; + public static final int DELTA_Z = 0x80; + public static final int ROTATE_DELTA = 0x100; + public static final int COORD = X | Y | Z; public static final int VIEW = YAW | PITCH; - public static final int ALL = COORD | VIEW; + public static final int DELTA = DELTA_X | DELTA_Y | DELTA_Z | ROTATE_DELTA; + public static final int ALL = COORD | VIEW | DELTA; } \ No newline at end of file From 5c6fd7e8490e9008456c076e0b09d912870ab5b3 Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 23 Oct 2024 21:31:27 -0400 Subject: [PATCH 57/97] fix: switch connection back to config state on config ack --- .../java/net/minestom/server/network/packet/PacketVanilla.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/net/minestom/server/network/packet/PacketVanilla.java b/src/main/java/net/minestom/server/network/packet/PacketVanilla.java index f005c5797..61d4b30ef 100644 --- a/src/main/java/net/minestom/server/network/packet/PacketVanilla.java +++ b/src/main/java/net/minestom/server/network/packet/PacketVanilla.java @@ -8,6 +8,7 @@ import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; +import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; import net.minestom.server.network.packet.server.login.LoginSuccessPacket; @@ -39,6 +40,7 @@ public final class PacketVanilla { case LOGIN, TRANSFER -> ConnectionState.LOGIN; }; case ClientLoginAcknowledgedPacket ignored -> ConnectionState.CONFIGURATION; + case ClientConfigurationAckPacket ignored -> ConnectionState.CONFIGURATION; case ClientFinishConfigurationPacket ignored -> ConnectionState.PLAY; default -> currentState; }; From 0b24134dc4534a3d87abb6a59f27718969c29140 Mon Sep 17 00:00:00 2001 From: mworzala Date: Wed, 23 Oct 2024 21:52:37 -0400 Subject: [PATCH 58/97] feat: convert command parser string to generated enum --- .../java/net/minestom/codegen/Generators.java | 2 + .../codegen/MinestomCodeGenerator.java | 4 +- gradle/libs.versions.toml | 2 +- .../minestom/server/MinecraftConstants.java | 4 +- .../server/command/ArgumentParserType.java | 141 ++++++++++++++++++ .../command/builder/arguments/Argument.java | 21 +-- .../builder/arguments/ArgumentBoolean.java | 5 +- .../builder/arguments/ArgumentCommand.java | 4 +- .../builder/arguments/ArgumentEnum.java | 3 +- .../builder/arguments/ArgumentGroup.java | 3 +- .../builder/arguments/ArgumentLiteral.java | 3 +- .../builder/arguments/ArgumentLoop.java | 3 +- .../builder/arguments/ArgumentString.java | 5 +- .../arguments/ArgumentStringArray.java | 5 +- .../builder/arguments/ArgumentWord.java | 5 +- .../minecraft/ArgumentBlockState.java | 5 +- .../arguments/minecraft/ArgumentColor.java | 5 +- .../minecraft/ArgumentComponent.java | 5 +- .../arguments/minecraft/ArgumentEntity.java | 5 +- .../minecraft/ArgumentFloatRange.java | 5 +- .../arguments/minecraft/ArgumentIntRange.java | 5 +- .../minecraft/ArgumentItemStack.java | 5 +- .../minecraft/ArgumentNbtCompoundTag.java | 5 +- .../arguments/minecraft/ArgumentNbtTag.java | 5 +- .../arguments/minecraft/ArgumentResource.java | 5 +- .../minecraft/ArgumentResourceLocation.java | 5 +- .../minecraft/ArgumentResourceOrTag.java | 5 +- .../arguments/minecraft/ArgumentTime.java | 5 +- .../arguments/minecraft/ArgumentUUID.java | 5 +- .../registry/ArgumentEntityType.java | 5 +- .../minecraft/registry/ArgumentParticle.java | 5 +- .../arguments/number/ArgumentDouble.java | 3 +- .../arguments/number/ArgumentFloat.java | 3 +- .../arguments/number/ArgumentInteger.java | 3 +- .../arguments/number/ArgumentLong.java | 3 +- .../arguments/number/ArgumentNumber.java | 7 +- .../ArgumentRelativeBlockPosition.java | 5 +- .../relative/ArgumentRelativeVec2.java | 5 +- .../relative/ArgumentRelativeVec3.java | 5 +- .../server/play/DeclareCommandsPacket.java | 30 ++-- .../minestom/server/registry/Registry.java | 1 - .../server/command/CommandPacketTest.java | 19 ++- .../packet/DeclareCommandsPacketTest.java | 5 +- 43 files changed, 273 insertions(+), 106 deletions(-) create mode 100644 src/autogenerated/java/net/minestom/server/command/ArgumentParserType.java diff --git a/code-generators/src/main/java/net/minestom/codegen/Generators.java b/code-generators/src/main/java/net/minestom/codegen/Generators.java index cc8229009..1c0194a1c 100644 --- a/code-generators/src/main/java/net/minestom/codegen/Generators.java +++ b/code-generators/src/main/java/net/minestom/codegen/Generators.java @@ -34,6 +34,8 @@ public class Generators { resource("recipe_book_categories.json"), outputFolder).generate(); new GenericEnumGenerator("net.minestom.server.item.component", "ConsumeEffectType", resource("consume_effects.json"), outputFolder).packagePrivate().generate(); + new GenericEnumGenerator("net.minestom.server.command", "ArgumentParserType", + resource("command_arguments.json"), outputFolder).generate(); var generator = new CodeGenerator(outputFolder); diff --git a/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java b/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java index a56248de3..0ba176ded 100644 --- a/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java +++ b/code-generators/src/main/java/net/minestom/codegen/MinestomCodeGenerator.java @@ -29,6 +29,8 @@ public abstract class MinestomCodeGenerator { } protected static String toConstant(String namespace) { - return namespace.replace("minecraft:", "").toUpperCase(Locale.ROOT); + return namespace.replace("minecraft:", "") + .replace("brigadier:", "") + .toUpperCase(Locale.ROOT); } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7fb8ce7c..47ed88dfc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ metadata.format.version = "1.1" [versions] # Important dependencies -data = "1.21.2-rv1" +data = "1.21.3-dev" adventure = "4.17.0" jetbrainsAnnotations = "24.1.0" slf4j = "2.0.7" diff --git a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java index 193fb3bd3..3c9b0b8d0 100644 --- a/src/autogenerated/java/net/minestom/server/MinecraftConstants.java +++ b/src/autogenerated/java/net/minestom/server/MinecraftConstants.java @@ -4,11 +4,11 @@ package net.minestom.server; * AUTOGENERATED by ConstantsGenerator */ interface MinecraftConstants { - String VERSION_NAME = "1.21.2"; + String VERSION_NAME = "1.21.3"; int PROTOCOL_VERSION = 768; - int DATA_VERSION = 4080; + int DATA_VERSION = 4082; int RESOURCE_PACK_VERSION = 42; diff --git a/src/autogenerated/java/net/minestom/server/command/ArgumentParserType.java b/src/autogenerated/java/net/minestom/server/command/ArgumentParserType.java new file mode 100644 index 000000000..cd27b3e8b --- /dev/null +++ b/src/autogenerated/java/net/minestom/server/command/ArgumentParserType.java @@ -0,0 +1,141 @@ +package net.minestom.server.command; + +import net.minestom.server.network.NetworkBuffer; +import net.minestom.server.registry.StaticProtocolObject; +import net.minestom.server.utils.NamespaceID; +import net.minestom.server.utils.nbt.BinaryTagSerializer; +import org.jetbrains.annotations.NotNull; + +/** + * AUTOGENERATED by GenericEnumGenerator + */ +public enum ArgumentParserType implements StaticProtocolObject { + BOOL(NamespaceID.from("brigadier:bool")), + + FLOAT(NamespaceID.from("brigadier:float")), + + DOUBLE(NamespaceID.from("brigadier:double")), + + INTEGER(NamespaceID.from("brigadier:integer")), + + LONG(NamespaceID.from("brigadier:long")), + + STRING(NamespaceID.from("brigadier:string")), + + ENTITY(NamespaceID.from("minecraft:entity")), + + GAME_PROFILE(NamespaceID.from("minecraft:game_profile")), + + BLOCK_POS(NamespaceID.from("minecraft:block_pos")), + + COLUMN_POS(NamespaceID.from("minecraft:column_pos")), + + VEC3(NamespaceID.from("minecraft:vec3")), + + VEC2(NamespaceID.from("minecraft:vec2")), + + BLOCK_STATE(NamespaceID.from("minecraft:block_state")), + + BLOCK_PREDICATE(NamespaceID.from("minecraft:block_predicate")), + + ITEM_STACK(NamespaceID.from("minecraft:item_stack")), + + ITEM_PREDICATE(NamespaceID.from("minecraft:item_predicate")), + + COLOR(NamespaceID.from("minecraft:color")), + + COMPONENT(NamespaceID.from("minecraft:component")), + + STYLE(NamespaceID.from("minecraft:style")), + + MESSAGE(NamespaceID.from("minecraft:message")), + + NBT_COMPOUND_TAG(NamespaceID.from("minecraft:nbt_compound_tag")), + + NBT_TAG(NamespaceID.from("minecraft:nbt_tag")), + + NBT_PATH(NamespaceID.from("minecraft:nbt_path")), + + OBJECTIVE(NamespaceID.from("minecraft:objective")), + + OBJECTIVE_CRITERIA(NamespaceID.from("minecraft:objective_criteria")), + + OPERATION(NamespaceID.from("minecraft:operation")), + + PARTICLE(NamespaceID.from("minecraft:particle")), + + ANGLE(NamespaceID.from("minecraft:angle")), + + ROTATION(NamespaceID.from("minecraft:rotation")), + + SCOREBOARD_SLOT(NamespaceID.from("minecraft:scoreboard_slot")), + + SCORE_HOLDER(NamespaceID.from("minecraft:score_holder")), + + SWIZZLE(NamespaceID.from("minecraft:swizzle")), + + TEAM(NamespaceID.from("minecraft:team")), + + ITEM_SLOT(NamespaceID.from("minecraft:item_slot")), + + ITEM_SLOTS(NamespaceID.from("minecraft:item_slots")), + + RESOURCE_LOCATION(NamespaceID.from("minecraft:resource_location")), + + FUNCTION(NamespaceID.from("minecraft:function")), + + ENTITY_ANCHOR(NamespaceID.from("minecraft:entity_anchor")), + + INT_RANGE(NamespaceID.from("minecraft:int_range")), + + FLOAT_RANGE(NamespaceID.from("minecraft:float_range")), + + DIMENSION(NamespaceID.from("minecraft:dimension")), + + GAMEMODE(NamespaceID.from("minecraft:gamemode")), + + TIME(NamespaceID.from("minecraft:time")), + + RESOURCE_OR_TAG(NamespaceID.from("minecraft:resource_or_tag")), + + RESOURCE_OR_TAG_KEY(NamespaceID.from("minecraft:resource_or_tag_key")), + + RESOURCE(NamespaceID.from("minecraft:resource")), + + RESOURCE_KEY(NamespaceID.from("minecraft:resource_key")), + + TEMPLATE_MIRROR(NamespaceID.from("minecraft:template_mirror")), + + TEMPLATE_ROTATION(NamespaceID.from("minecraft:template_rotation")), + + HEIGHTMAP(NamespaceID.from("minecraft:heightmap")), + + LOOT_TABLE(NamespaceID.from("minecraft:loot_table")), + + LOOT_PREDICATE(NamespaceID.from("minecraft:loot_predicate")), + + LOOT_MODIFIER(NamespaceID.from("minecraft:loot_modifier")), + + UUID(NamespaceID.from("minecraft:uuid")); + + public static final NetworkBuffer.Type NETWORK_TYPE = NetworkBuffer.Enum(ArgumentParserType.class); + + public static final BinaryTagSerializer NBT_TYPE = BinaryTagSerializer.fromEnumKeyed(ArgumentParserType.class); + + private final NamespaceID namespace; + + ArgumentParserType(@NotNull NamespaceID namespace) { + this.namespace = namespace; + } + + @NotNull + @Override + public NamespaceID namespace() { + return this.namespace; + } + + @Override + public int id() { + return this.ordinal(); + } +} diff --git a/src/main/java/net/minestom/server/command/builder/arguments/Argument.java b/src/main/java/net/minestom/server/command/builder/arguments/Argument.java index 497924a2e..945508bf1 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/Argument.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/Argument.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.ArgumentCallback; import net.minestom.server.command.builder.Command; @@ -7,9 +8,6 @@ import net.minestom.server.command.builder.CommandExecutor; import net.minestom.server.command.builder.arguments.minecraft.SuggestionType; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.command.builder.suggestion.SuggestionCallback; -import net.minestom.server.registry.Registry; -import net.minestom.server.registry.StaticProtocolObject; -import net.minestom.server.utils.NamespaceID; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,17 +27,6 @@ import java.util.function.Supplier; * @param the type of this parsed argument */ public abstract class Argument { - @ApiStatus.Internal - public static final Registry.Container CONTAINER = Registry.createStaticContainer(Registry.Resource.COMMAND_ARGUMENTS, - (namespace, properties) -> new ArgumentImpl(NamespaceID.from(namespace), properties.getInt("id"))); - - record ArgumentImpl(NamespaceID namespace, int id) implements StaticProtocolObject { - @Override - public String toString() { - return name(); - } - } - private final String id; protected final boolean allowSpace; protected final boolean useRemaining; @@ -105,7 +92,7 @@ public abstract class Argument { */ public abstract @NotNull T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException; - public abstract String parser(); + public abstract ArgumentParserType parser(); public byte @Nullable [] nodeProperties() { return null; @@ -325,7 +312,7 @@ public abstract class Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return argument.parser(); } @@ -359,7 +346,7 @@ public abstract class Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return argument.parser(); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentBoolean.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentBoolean.java index 92f1d9f06..5e9dfc7d1 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentBoolean.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentBoolean.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import org.jetbrains.annotations.NotNull; @@ -29,8 +30,8 @@ public class ArgumentBoolean extends Argument { } @Override - public String parser() { - return "brigadier:bool"; + public ArgumentParserType parser() { + return ArgumentParserType.BOOL; } @Override public String toString() { diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java index 5ffe90d35..6f5608faa 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentCommand.java @@ -1,6 +1,7 @@ package net.minestom.server.command.builder.arguments; import net.minestom.server.MinecraftServer; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.CommandDispatcher; import net.minestom.server.command.builder.CommandResult; @@ -8,6 +9,7 @@ import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.utils.StringUtils; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class ArgumentCommand extends Argument { @@ -36,7 +38,7 @@ public class ArgumentCommand extends Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return null; } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java index da100c8c5..f88d49789 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentEnum.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import org.jetbrains.annotations.NotNull; @@ -41,7 +42,7 @@ public class ArgumentEnum extends Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return null; } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java index f65b28e5c..6a1c6c732 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentGroup.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.CommandContext; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; @@ -39,7 +40,7 @@ public class ArgumentGroup extends Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return null; } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLiteral.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLiteral.java index 7f45dadae..dd0ffcb13 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLiteral.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLiteral.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import org.jetbrains.annotations.NotNull; @@ -22,7 +23,7 @@ public class ArgumentLiteral extends Argument { } @Override - public String parser() { + public ArgumentParserType parser() { return null; } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java index aa5065da1..a7ac36b61 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentLoop.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.utils.StringUtils; @@ -62,7 +63,7 @@ public class ArgumentLoop extends Argument> { } @Override - public String parser() { + public ArgumentParserType parser() { return null; } } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java index d9b6b6aa9..0f408948e 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentString.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.NetworkBuffer; @@ -31,8 +32,8 @@ public class ArgumentString extends Argument { } @Override - public String parser() { - return "brigadier:string"; + public ArgumentParserType parser() { + return ArgumentParserType.STRING; } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java index f9e164b19..d02c31547 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentStringArray.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.network.NetworkBuffer; import net.minestom.server.utils.StringUtils; @@ -26,8 +27,8 @@ public class ArgumentStringArray extends Argument { } @Override - public String parser() { - return "brigadier:string"; + public ArgumentParserType parser() { + return ArgumentParserType.STRING; } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java index 59acab818..27f1e6633 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/ArgumentWord.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; import net.minestom.server.network.NetworkBuffer; @@ -69,8 +70,8 @@ public class ArgumentWord extends Argument { } @Override - public String parser() { - return "brigadier:string"; + public ArgumentParserType parser() { + return ArgumentParserType.STRING; } @Override diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentBlockState.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentBlockState.java index 94637ec97..6a5a2f59c 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentBlockState.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentBlockState.java @@ -1,5 +1,6 @@ package net.minestom.server.command.builder.arguments.minecraft; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; @@ -24,8 +25,8 @@ public class ArgumentBlockState extends Argument { } @Override - public String parser() { - return "minecraft:block_state"; + public @NotNull ArgumentParserType parser() { + return ArgumentParserType.BLOCK_STATE; } /** diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentColor.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentColor.java index 1163dc3fe..c38f7d51d 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentColor.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentColor.java @@ -2,6 +2,7 @@ package net.minestom.server.command.builder.arguments.minecraft; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; +import net.minestom.server.command.ArgumentParserType; import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; @@ -40,8 +41,8 @@ public class ArgumentColor extends Argument