From 788cdc2c4538b15d338d2ca66c73ead553141147 Mon Sep 17 00:00:00 2001 From: filoghost Date: Mon, 12 Dec 2022 20:38:48 +0100 Subject: [PATCH] Add support for Minecraft 1.19.3 --- core/pom.xml | 5 + .../core/HolographicDisplaysCore.java | 2 +- .../holographicdisplays/core/NMSVersion.java | 3 +- nms/pom.xml | 1 + nms/v1_19_r2/pom.xml | 29 +++++ .../nms/v1_19_R2/DataWatcherKey.java | 56 +++++++++ .../v1_19_R2/DataWatcherPacketBuilder.java | 70 +++++++++++ .../nms/v1_19_R2/EntityDestroyNMSPacket.java | 37 ++++++ .../nms/v1_19_R2/EntityMetadataNMSPacket.java | 45 +++++++ .../nms/v1_19_R2/EntityMountNMSPacket.java | 30 +++++ .../nms/v1_19_R2/EntitySpawnNMSPacket.java | 53 ++++++++ .../nms/v1_19_R2/EntityTeleportNMSPacket.java | 42 +++++++ .../nms/v1_19_R2/EntityTypeID.java | 14 +++ .../nms/v1_19_R2/InboundPacketHandler.java | 46 +++++++ .../nms/v1_19_R2/PacketByteBuffer.java | 55 +++++++++ .../VersionClickableNMSPacketEntity.java | 47 +++++++ .../v1_19_R2/VersionItemNMSPacketEntity.java | 56 +++++++++ .../nms/v1_19_R2/VersionNMSManager.java | 115 ++++++++++++++++++ .../nms/v1_19_R2/VersionNMSPacket.java | 22 ++++ .../v1_19_R2/VersionTextNMSPacketEntity.java | 70 +++++++++++ pom.xml | 6 + 21 files changed, 802 insertions(+), 2 deletions(-) create mode 100644 nms/v1_19_r2/pom.xml create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherKey.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherPacketBuilder.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityDestroyNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMetadataNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMountNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntitySpawnNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTeleportNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTypeID.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/InboundPacketHandler.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/PacketByteBuffer.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionClickableNMSPacketEntity.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionItemNMSPacketEntity.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSManager.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSPacket.java create mode 100644 nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionTextNMSPacketEntity.java diff --git a/core/pom.xml b/core/pom.xml index 6a9f4f1f..04866e8d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -109,6 +109,11 @@ holographicdisplays-nms-v1_19_r1 + + ${project.groupId} + holographicdisplays-nms-v1_19_r2 + + org.spigotmc spigot-api diff --git a/core/src/main/java/me/filoghost/holographicdisplays/core/HolographicDisplaysCore.java b/core/src/main/java/me/filoghost/holographicdisplays/core/HolographicDisplaysCore.java index abece00f..493fed11 100644 --- a/core/src/main/java/me/filoghost/holographicdisplays/core/HolographicDisplaysCore.java +++ b/core/src/main/java/me/filoghost/holographicdisplays/core/HolographicDisplaysCore.java @@ -40,7 +40,7 @@ public class HolographicDisplaysCore { try { nmsManager = NMSVersion.getCurrent().createNMSManager(errorCollector); } catch (UnknownVersionException e) { - throw new PluginEnableException("Holographic Displays only supports Spigot from 1.8 to 1.18.2."); + throw new PluginEnableException("Holographic Displays only supports Spigot from 1.8 to 1.19.3."); } catch (OutdatedVersionException e) { throw new PluginEnableException("Holographic Displays only supports " + e.getMinimumSupportedVersion() + " and above."); } catch (Throwable t) { diff --git a/core/src/main/java/me/filoghost/holographicdisplays/core/NMSVersion.java b/core/src/main/java/me/filoghost/holographicdisplays/core/NMSVersion.java index bbecaaab..c26d1434 100644 --- a/core/src/main/java/me/filoghost/holographicdisplays/core/NMSVersion.java +++ b/core/src/main/java/me/filoghost/holographicdisplays/core/NMSVersion.java @@ -38,7 +38,8 @@ public enum NMSVersion { /* 1.17 */ v1_17_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_17_R1.VersionNMSManager(errorCollector)), /* 1.18 - 1.18.1 */ v1_18_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_18_R1.VersionNMSManager(errorCollector)), /* 1.18.2 */ v1_18_R2(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_18_R2.VersionNMSManager(errorCollector)), - /* 1.19 - ? */ v1_19_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R1.VersionNMSManager(errorCollector)), + /* 1.19 - 1.19.2 */ v1_19_R1(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R1.VersionNMSManager(errorCollector)), + /* 1.19.3 - ? */ v1_19_R2(errorCollector -> new me.filoghost.holographicdisplays.nms.v1_19_R2.VersionNMSManager(errorCollector)), /* Other versions */ UNKNOWN(NMSManagerFactory.unknownVersion()); private static final NMSVersion CURRENT_VERSION = detectCurrentVersion(); diff --git a/nms/pom.xml b/nms/pom.xml index 1b821b4d..09bdbc69 100644 --- a/nms/pom.xml +++ b/nms/pom.xml @@ -30,6 +30,7 @@ v1_18_r1 v1_18_r2 v1_19_r1 + v1_19_r2 diff --git a/nms/v1_19_r2/pom.xml b/nms/v1_19_r2/pom.xml new file mode 100644 index 00000000..1c745d6e --- /dev/null +++ b/nms/v1_19_r2/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + me.filoghost.holographicdisplays + holographicdisplays-nms + 3.0.1-SNAPSHOT + + + holographicdisplays-nms-v1_19_r2 + HolographicDisplays NMS v1_19_R2 + + + + ${project.groupId} + holographicdisplays-nms-common + + + + org.spigotmc + spigot + 1.19.3-R0.1-SNAPSHOT + provided + + + + diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherKey.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherKey.java new file mode 100644 index 00000000..dc6ce221 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherKey.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import io.netty.handler.codec.EncoderException; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.network.syncher.DataWatcherRegistry; +import net.minecraft.network.syncher.DataWatcherSerializer; +import net.minecraft.world.item.ItemStack; + +import java.util.Optional; + +class DataWatcherKey { + + private static final DataWatcherSerializer BYTE_SERIALIZER = DataWatcherRegistry.a; + private static final DataWatcherSerializer INT_SERIALIZER = DataWatcherRegistry.b; + private static final DataWatcherSerializer BOOLEAN_SERIALIZER = DataWatcherRegistry.j; + private static final DataWatcherSerializer ITEM_STACK_SERIALIZER = DataWatcherRegistry.h; + private static final DataWatcherSerializer> OPTIONAL_CHAT_COMPONENT_SERIALIZER = DataWatcherRegistry.g; + + static final DataWatcherKey ENTITY_STATUS = new DataWatcherKey<>(0, BYTE_SERIALIZER); + static final DataWatcherKey> CUSTOM_NAME = new DataWatcherKey<>(2, OPTIONAL_CHAT_COMPONENT_SERIALIZER); + static final DataWatcherKey CUSTOM_NAME_VISIBILITY = new DataWatcherKey<>(3, BOOLEAN_SERIALIZER); + static final DataWatcherKey ITEM_STACK = new DataWatcherKey<>(8, ITEM_STACK_SERIALIZER); + static final DataWatcherKey ARMOR_STAND_STATUS = new DataWatcherKey<>(15, BYTE_SERIALIZER); + static final DataWatcherKey SLIME_SIZE = new DataWatcherKey<>(16, INT_SERIALIZER); + + private final int index; + private final DataWatcherSerializer serializer; + private final int serializerTypeID; + + private DataWatcherKey(int index, DataWatcherSerializer serializer) { + this.index = index; + this.serializer = serializer; + this.serializerTypeID = DataWatcherRegistry.b(serializer); + if (serializerTypeID < 0) { + throw new EncoderException("Could not find serializer ID of " + serializer); + } + } + + int getIndex() { + return index; + } + + DataWatcherSerializer getSerializer() { + return serializer; + } + + int getSerializerTypeID() { + return serializerTypeID; + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherPacketBuilder.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherPacketBuilder.java new file mode 100644 index 00000000..a8ae4b56 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/DataWatcherPacketBuilder.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.fcommons.Strings; +import net.minecraft.network.chat.IChatBaseComponent; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_19_R2.util.CraftChatMessage; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +abstract class DataWatcherPacketBuilder { + + private static final int MAX_CUSTOM_NAME_LENGTH = 5000; + + private final PacketByteBuffer packetByteBuffer; + + DataWatcherPacketBuilder(PacketByteBuffer packetByteBuffer) { + this.packetByteBuffer = packetByteBuffer; + } + + DataWatcherPacketBuilder setInvisible() { + packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.ENTITY_STATUS, (byte) 0x20); // Invisible + return this; + } + + DataWatcherPacketBuilder setArmorStandMarker() { + setInvisible(); + packetByteBuffer.writeDataWatcherEntry( + DataWatcherKey.ARMOR_STAND_STATUS, (byte) (0x01 | 0x02 | 0x08 | 0x10)); // Small, no gravity, no base plate, marker + return this; + } + + DataWatcherPacketBuilder setCustomName(String customName) { + packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.CUSTOM_NAME, getCustomNameDataWatcherValue(customName)); + packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.CUSTOM_NAME_VISIBILITY, !Strings.isEmpty(customName)); + return this; + } + + private Optional getCustomNameDataWatcherValue(String customName) { + customName = Strings.truncate(customName, MAX_CUSTOM_NAME_LENGTH); + if (!Strings.isEmpty(customName)) { + return Optional.of(CraftChatMessage.fromString(customName, false, true)[0]); + } else { + return Optional.empty(); + } + } + + DataWatcherPacketBuilder setItemStack(ItemStack itemStack) { + packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.ITEM_STACK, CraftItemStack.asNMSCopy(itemStack)); + return this; + } + + DataWatcherPacketBuilder setSlimeSmall() { + packetByteBuffer.writeDataWatcherEntry(DataWatcherKey.SLIME_SIZE, 1); + return this; + } + + T build() { + packetByteBuffer.writeDataWatcherEntriesEnd(); + return createPacket(packetByteBuffer); + } + + abstract T createPacket(PacketByteBuffer packetByteBuffer); + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityDestroyNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityDestroyNMSPacket.java new file mode 100644 index 00000000..92bad83e --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityDestroyNMSPacket.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.nms.common.EntityID; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy; + +class EntityDestroyNMSPacket extends VersionNMSPacket { + + private final Packet rawPacket; + + EntityDestroyNMSPacket(EntityID entityID) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + + packetByteBuffer.writeVarIntArray(entityID.getNumericID()); + + this.rawPacket = new PacketPlayOutEntityDestroy(packetByteBuffer); + } + + EntityDestroyNMSPacket(EntityID entityID1, EntityID entityID2) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + + packetByteBuffer.writeVarIntArray(entityID1.getNumericID(), entityID2.getNumericID()); + + this.rawPacket = new PacketPlayOutEntityDestroy(packetByteBuffer); + } + + @Override + Packet getRawPacket() { + return rawPacket; + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMetadataNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMetadataNMSPacket.java new file mode 100644 index 00000000..fbc2d047 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMetadataNMSPacket.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.nms.common.EntityID; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; + +class EntityMetadataNMSPacket extends VersionNMSPacket { + + private final Packet rawPacket; + + private EntityMetadataNMSPacket(PacketByteBuffer packetByteBuffer) { + this.rawPacket = new PacketPlayOutEntityMetadata(packetByteBuffer); + } + + @Override + Packet getRawPacket() { + return rawPacket; + } + + public static DataWatcherPacketBuilder builder(EntityID entityID) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + packetByteBuffer.writeVarInt(entityID.getNumericID()); + return new Builder(packetByteBuffer); + } + + + private static class Builder extends DataWatcherPacketBuilder { + + private Builder(PacketByteBuffer packetByteBuffer) { + super(packetByteBuffer); + } + + @Override + EntityMetadataNMSPacket createPacket(PacketByteBuffer packetByteBuffer) { + return new EntityMetadataNMSPacket(packetByteBuffer); + } + + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMountNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMountNMSPacket.java new file mode 100644 index 00000000..9ef243d5 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityMountNMSPacket.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.nms.common.EntityID; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutMount; + +class EntityMountNMSPacket extends VersionNMSPacket { + + private final Packet rawPacket; + + EntityMountNMSPacket(EntityID vehicleEntityID, EntityID passengerEntityID) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + + packetByteBuffer.writeVarInt(vehicleEntityID.getNumericID()); + packetByteBuffer.writeVarIntArray(passengerEntityID.getNumericID()); + + this.rawPacket = new PacketPlayOutMount(packetByteBuffer); + } + + @Override + Packet getRawPacket() { + return rawPacket; + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntitySpawnNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntitySpawnNMSPacket.java new file mode 100644 index 00000000..09f53cb4 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntitySpawnNMSPacket.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.common.PositionCoordinates; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity; + +class EntitySpawnNMSPacket extends VersionNMSPacket { + + private final Packet rawPacket; + + EntitySpawnNMSPacket(EntityID entityID, int entityTypeID, PositionCoordinates position, double positionOffsetY) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + + packetByteBuffer.writeVarInt(entityID.getNumericID()); + packetByteBuffer.writeUUID(entityID.getUUID()); + packetByteBuffer.writeVarInt(entityTypeID); + + // Position + packetByteBuffer.writeDouble(position.getX()); + packetByteBuffer.writeDouble(position.getY() + positionOffsetY); + packetByteBuffer.writeDouble(position.getZ()); + + // Rotation + packetByteBuffer.writeByte(0); + packetByteBuffer.writeByte(0); + + // Object data + if (entityTypeID == EntityTypeID.ITEM) { + packetByteBuffer.writeInt(1); // Velocity is present and zero (otherwise by default a random velocity is applied) + } else { + packetByteBuffer.writeInt(0); + } + + // Velocity + packetByteBuffer.writeShort(0); + packetByteBuffer.writeShort(0); + packetByteBuffer.writeShort(0); + + this.rawPacket = new PacketPlayOutSpawnEntity(packetByteBuffer); + } + + @Override + Packet getRawPacket() { + return rawPacket; + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTeleportNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTeleportNMSPacket.java new file mode 100644 index 00000000..d54931b0 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTeleportNMSPacket.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.common.PositionCoordinates; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport; + +class EntityTeleportNMSPacket extends VersionNMSPacket { + + private final Packet rawPacket; + + EntityTeleportNMSPacket(EntityID entityID, PositionCoordinates position, double positionOffsetY) { + PacketByteBuffer packetByteBuffer = PacketByteBuffer.get(); + + packetByteBuffer.writeVarInt(entityID.getNumericID()); + + // Position + packetByteBuffer.writeDouble(position.getX()); + packetByteBuffer.writeDouble(position.getY() + positionOffsetY); + packetByteBuffer.writeDouble(position.getZ()); + + // Rotation + packetByteBuffer.writeByte(0); + packetByteBuffer.writeByte(0); + + // On ground + packetByteBuffer.writeBoolean(false); + + this.rawPacket = new PacketPlayOutEntityTeleport(packetByteBuffer); + } + + @Override + Packet getRawPacket() { + return rawPacket; + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTypeID.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTypeID.java new file mode 100644 index 00000000..6511754f --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/EntityTypeID.java @@ -0,0 +1,14 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +class EntityTypeID { + + static final int ARMOR_STAND = 2; + static final int ITEM = 45; + static final int SLIME = 84; + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/InboundPacketHandler.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/InboundPacketHandler.java new file mode 100644 index 00000000..3b0cebf1 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/InboundPacketHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import me.filoghost.fcommons.logging.Log; +import me.filoghost.fcommons.reflection.ReflectField; +import me.filoghost.holographicdisplays.nms.common.NMSErrors; +import me.filoghost.holographicdisplays.nms.common.PacketListener; +import net.minecraft.network.protocol.game.PacketPlayInUseEntity; +import org.bukkit.entity.Player; + +class InboundPacketHandler extends ChannelInboundHandlerAdapter { + + public static final String HANDLER_NAME = "holographic_displays_listener"; + private static final ReflectField ENTITY_ID_FIELD = ReflectField.lookup(int.class, PacketPlayInUseEntity.class, "a"); + + private final Player player; + private final PacketListener packetListener; + + InboundPacketHandler(Player player, PacketListener packetListener) { + this.player = player; + this.packetListener = packetListener; + } + + @Override + public void channelRead(ChannelHandlerContext context, Object packet) throws Exception { + try { + if (packet instanceof PacketPlayInUseEntity) { + int entityID = ENTITY_ID_FIELD.get(packet); + boolean cancel = packetListener.onAsyncEntityInteract(player, entityID); + if (cancel) { + return; + } + } + } catch (Throwable t) { + Log.warning(NMSErrors.EXCEPTION_ON_PACKET_READ, t); + } + super.channelRead(context, packet); + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/PacketByteBuffer.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/PacketByteBuffer.java new file mode 100644 index 00000000..65009fb9 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/PacketByteBuffer.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import io.netty.buffer.Unpooled; +import net.minecraft.network.PacketDataSerializer; + +import java.util.UUID; + +class PacketByteBuffer extends PacketDataSerializer { + + private static final PacketByteBuffer INSTANCE = new PacketByteBuffer(); + + static PacketByteBuffer get() { + INSTANCE.clear(); + return INSTANCE; + } + + private PacketByteBuffer() { + super(Unpooled.buffer()); + } + + void writeVarInt(int i) { + super.d(i); + } + + void writeVarIntArray(int i1) { + writeVarInt(1); + writeVarInt(i1); + } + + void writeVarIntArray(int i1, int i2) { + writeVarInt(2); + writeVarInt(i1); + writeVarInt(i2); + } + + void writeUUID(UUID uuid) { + super.a(uuid); + } + + void writeDataWatcherEntry(DataWatcherKey key, T value) { + writeByte(key.getIndex()); + writeVarInt(key.getSerializerTypeID()); + key.getSerializer().a(this, value); + } + + void writeDataWatcherEntriesEnd() { + writeByte(0xFF); + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionClickableNMSPacketEntity.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionClickableNMSPacketEntity.java new file mode 100644 index 00000000..5905aab3 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionClickableNMSPacketEntity.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.common.PositionCoordinates; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import me.filoghost.holographicdisplays.nms.common.PacketGroup; +import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity; + +class VersionClickableNMSPacketEntity implements ClickableNMSPacketEntity { + + private final EntityID slimeID; + + VersionClickableNMSPacketEntity(EntityID slimeID) { + this.slimeID = slimeID; + } + + @Override + public EntityID getID() { + return slimeID; + } + + @Override + public PacketGroup newSpawnPackets(PositionCoordinates position) { + return PacketGroup.of( + new EntitySpawnNMSPacket(slimeID, EntityTypeID.SLIME, position, SLIME_Y_OFFSET), + EntityMetadataNMSPacket.builder(slimeID) + .setInvisible() + .setSlimeSmall() // Required for a correct client-side collision box + .build() + ); + } + + @Override + public PacketGroup newTeleportPackets(PositionCoordinates position) { + return new EntityTeleportNMSPacket(slimeID, position, SLIME_Y_OFFSET); + } + + @Override + public PacketGroup newDestroyPackets() { + return new EntityDestroyNMSPacket(slimeID); + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionItemNMSPacketEntity.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionItemNMSPacketEntity.java new file mode 100644 index 00000000..93580224 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionItemNMSPacketEntity.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.common.PositionCoordinates; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import me.filoghost.holographicdisplays.nms.common.PacketGroup; +import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity; +import org.bukkit.inventory.ItemStack; + +class VersionItemNMSPacketEntity implements ItemNMSPacketEntity { + + private final EntityID itemID; + private final EntityID vehicleID; + + VersionItemNMSPacketEntity(EntityID itemID, EntityID vehicleID) { + this.itemID = itemID; + this.vehicleID = vehicleID; + } + + @Override + public PacketGroup newSpawnPackets(PositionCoordinates position, ItemStack itemStack) { + return PacketGroup.of( + new EntitySpawnNMSPacket(vehicleID, EntityTypeID.ARMOR_STAND, position, ITEM_Y_OFFSET), + EntityMetadataNMSPacket.builder(vehicleID) + .setArmorStandMarker() + .build(), + new EntitySpawnNMSPacket(itemID, EntityTypeID.ITEM, position, ITEM_Y_OFFSET), + EntityMetadataNMSPacket.builder(itemID) + .setItemStack(itemStack) + .build(), + new EntityMountNMSPacket(vehicleID, itemID) + ); + } + + @Override + public PacketGroup newChangePackets(ItemStack itemStack) { + return EntityMetadataNMSPacket.builder(itemID) + .setItemStack(itemStack) + .build(); + } + + @Override + public PacketGroup newTeleportPackets(PositionCoordinates position) { + return new EntityTeleportNMSPacket(vehicleID, position, ITEM_Y_OFFSET); + } + + @Override + public PacketGroup newDestroyPackets() { + return new EntityDestroyNMSPacket(itemID, vehicleID); + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSManager.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSManager.java new file mode 100644 index 00000000..a230a91a --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSManager.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelPipeline; +import me.filoghost.fcommons.logging.ErrorCollector; +import me.filoghost.fcommons.logging.Log; +import me.filoghost.fcommons.reflection.ReflectField; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import me.filoghost.holographicdisplays.nms.common.FallbackEntityIDGenerator; +import me.filoghost.holographicdisplays.nms.common.NMSErrors; +import me.filoghost.holographicdisplays.nms.common.NMSManager; +import me.filoghost.holographicdisplays.nms.common.PacketListener; +import me.filoghost.holographicdisplays.nms.common.entity.ClickableNMSPacketEntity; +import me.filoghost.holographicdisplays.nms.common.entity.ItemNMSPacketEntity; +import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity; +import net.minecraft.network.NetworkManager; +import net.minecraft.server.network.PlayerConnection; +import net.minecraft.world.entity.Entity; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class VersionNMSManager implements NMSManager { + + private static final ReflectField ENTITY_ID_COUNTER_FIELD = ReflectField.lookup(AtomicInteger.class, Entity.class, "c"); + private final Supplier entityIDGenerator; + + public VersionNMSManager(ErrorCollector errorCollector) { + this.entityIDGenerator = getEntityIDGenerator(errorCollector); + + // Force initialization of class to eventually throw exceptions early + DataWatcherKey.ENTITY_STATUS.getIndex(); + } + + private Supplier getEntityIDGenerator(ErrorCollector errorCollector) { + try { + AtomicInteger nmsEntityIDCounter = ENTITY_ID_COUNTER_FIELD.getStatic(); + return nmsEntityIDCounter::incrementAndGet; + } catch (ReflectiveOperationException e) { + errorCollector.add(e, NMSErrors.EXCEPTION_GETTING_ENTITY_ID_GENERATOR); + return new FallbackEntityIDGenerator(); + } + } + + private EntityID newEntityID() { + return new EntityID(entityIDGenerator); + } + + @Override + public TextNMSPacketEntity newTextPacketEntity() { + return new VersionTextNMSPacketEntity(newEntityID()); + } + + @Override + public ItemNMSPacketEntity newItemPacketEntity() { + return new VersionItemNMSPacketEntity(newEntityID(), newEntityID()); + } + + @Override + public ClickableNMSPacketEntity newClickablePacketEntity() { + return new VersionClickableNMSPacketEntity(newEntityID()); + } + + @Override + public void injectPacketListener(Player player, PacketListener packetListener) { + modifyPipeline(player, (ChannelPipeline pipeline) -> { + ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME); + if (currentListener != null) { + pipeline.remove(InboundPacketHandler.HANDLER_NAME); + } + pipeline.addBefore("packet_handler", InboundPacketHandler.HANDLER_NAME, new InboundPacketHandler(player, packetListener)); + }); + } + + @Override + public void uninjectPacketListener(Player player) { + modifyPipeline(player, (ChannelPipeline pipeline) -> { + ChannelHandler currentListener = pipeline.get(InboundPacketHandler.HANDLER_NAME); + if (currentListener != null) { + pipeline.remove(InboundPacketHandler.HANDLER_NAME); + } + }); + } + + /* + * Modifying the pipeline in the main thread can cause deadlocks, delays and other concurrency issues, + * which can be avoided by using the event loop. Thanks to ProtocolLib for this insight. + */ + private void modifyPipeline(Player player, Consumer pipelineModifierTask) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().b; + NetworkManager networkManager = playerConnection.a(); + Channel channel = networkManager.m; + + channel.eventLoop().execute(() -> { + if (!player.isOnline()) { + return; + } + try { + pipelineModifierTask.accept(channel.pipeline()); + } catch (Exception e) { + Log.warning(NMSErrors.EXCEPTION_MODIFYING_CHANNEL_PIPELINE, e); + } + }); + } + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSPacket.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSPacket.java new file mode 100644 index 00000000..fed0d8f7 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionNMSPacket.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.nms.common.PacketGroup; +import net.minecraft.network.protocol.Packet; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +abstract class VersionNMSPacket implements PacketGroup { + + @Override + public void sendTo(Player player) { + ((CraftPlayer) player).getHandle().b.a(getRawPacket()); + } + + abstract Packet getRawPacket(); + +} diff --git a/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionTextNMSPacketEntity.java b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionTextNMSPacketEntity.java new file mode 100644 index 00000000..c0ec5c29 --- /dev/null +++ b/nms/v1_19_r2/src/main/java/me/filoghost/holographicdisplays/nms/v1_19_R2/VersionTextNMSPacketEntity.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) filoghost and contributors + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package me.filoghost.holographicdisplays.nms.v1_19_R2; + +import me.filoghost.holographicdisplays.common.PositionCoordinates; +import me.filoghost.holographicdisplays.nms.common.EntityID; +import me.filoghost.holographicdisplays.nms.common.IndividualTextPacketGroup; +import me.filoghost.holographicdisplays.nms.common.PacketGroup; +import me.filoghost.holographicdisplays.nms.common.entity.TextNMSPacketEntity; + +class VersionTextNMSPacketEntity implements TextNMSPacketEntity { + + private final EntityID armorStandID; + + VersionTextNMSPacketEntity(EntityID armorStandID) { + this.armorStandID = armorStandID; + } + + @Override + public PacketGroup newSpawnPackets(PositionCoordinates position, String text) { + return PacketGroup.of( + new EntitySpawnNMSPacket(armorStandID, EntityTypeID.ARMOR_STAND, position, ARMOR_STAND_Y_OFFSET), + EntityMetadataNMSPacket.builder(armorStandID) + .setArmorStandMarker() + .setCustomName(text) + .build() + ); + } + + @Override + public IndividualTextPacketGroup newSpawnPackets(PositionCoordinates position) { + return IndividualTextPacketGroup.of( + new EntitySpawnNMSPacket(armorStandID, EntityTypeID.ARMOR_STAND, position, ARMOR_STAND_Y_OFFSET), + (String text) -> EntityMetadataNMSPacket.builder(armorStandID) + .setArmorStandMarker() + .setCustomName(text) + .build() + ); + } + + @Override + public PacketGroup newChangePackets(String text) { + return EntityMetadataNMSPacket.builder(armorStandID) + .setCustomName(text) + .build(); + } + + @Override + public IndividualTextPacketGroup newChangePackets() { + return IndividualTextPacketGroup.of( + (String text) -> EntityMetadataNMSPacket.builder(armorStandID) + .setCustomName(text) + .build() + ); + } + + @Override + public PacketGroup newTeleportPackets(PositionCoordinates position) { + return new EntityTeleportNMSPacket(armorStandID, position, ARMOR_STAND_Y_OFFSET); + } + + @Override + public PacketGroup newDestroyPackets() { + return new EntityDestroyNMSPacket(armorStandID); + } + +} diff --git a/pom.xml b/pom.xml index 0075755d..0430f068 100644 --- a/pom.xml +++ b/pom.xml @@ -201,6 +201,12 @@ ${project.version} + + ${project.groupId} + holographicdisplays-nms-v1_19_r2 + ${project.version} + + org.spigotmc spigot-api