diff --git a/build.gradle.kts b/build.gradle.kts index cd147f6..a4022bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "me.lojosho" -version = "0.6.5${getGitCommitHash()}" +version = "0.7.0${getGitCommitHash()}" allprojects { apply(plugin = "java") @@ -33,7 +33,7 @@ allprojects { maven("https://repo.nexomc.com/snapshots/") maven("https://repo.nexomc.com/releases/") - // Geary & Backup ProtocolLib repo + // Geary repo maven("https://repo.mineinabyss.com/releases/") maven("https://repo.mineinabyss.com/snapshots/") @@ -55,9 +55,6 @@ allprojects { // PlaceholderAPI maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") - // ProtocolLib - maven("https://repo.dmulloy2.net/repository/public/") - // Oraxen maven("https://repo.oraxen.com/releases") @@ -83,7 +80,7 @@ allprojects { compileOnly("com.mojang:authlib:3.13.56") compileOnly("org.jetbrains:annotations:26.0.1") compileOnly("io.th0rgal:oraxen:1.182.0") - compileOnly("com.nexomc:nexo:1.0.0") + compileOnly("com.nexomc:nexo:1.4.0") compileOnly("com.github.LoneDev6:API-ItemsAdder:3.6.3-beta-14") compileOnly("com.mineinabyss:geary-papermc:0.31.0-dev.4") compileOnly("it.unimi.dsi:fastutil:8.5.15") @@ -98,7 +95,6 @@ allprojects { } compileOnly("com.github.Xiao-MoMi:Custom-Fishing:2.3.3") compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.2") - compileOnly("com.comphenix.protocol:ProtocolLib:5.3.0") compileOnly("org.joml:joml:1.10.8") compileOnly("com.google.guava:guava:33.4.0-jre") // Sometimes just not included in compile time??? compileOnly("com.github.Gecolay.GSit:core:2.0.0") @@ -148,12 +144,11 @@ tasks { runServer { dependsOn(shadowJar) dependsOn(jar) - minecraftVersion("1.21.5") + minecraftVersion("1.21.6") downloadPlugins { hangar("PlaceholderAPI", "2.11.6") - url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar") - url("https://download.luckperms.net/1567/bukkit/loader/LuckPerms-Bukkit-5.4.150.jar") + url("https://download.luckperms.net/1593/bukkit/loader/LuckPerms-Bukkit-5.5.8.jar") } } @@ -205,7 +200,6 @@ bukkit { main = "me.lojosho.hibiscuscommons.HibiscusCommonsPlugin" apiVersion = "1.20" authors = listOf("LoJoSho") - depend = listOf("ProtocolLib") softDepend = listOf( "ModelEngine", "Oraxen", @@ -252,12 +246,6 @@ hangarPublish { val versions: List = listOf("1.18.2-1.20.4") platformVersions.set(versions) - - dependencies { - hangar("ProtocolLib") { - required.set(true) - } - } } } } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java index 6713406..c233775 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java @@ -2,6 +2,7 @@ package me.lojosho.hibiscuscommons; import lombok.Getter; import me.lojosho.hibiscuscommons.hooks.Hooks; +import me.lojosho.hibiscuscommons.listener.PlayerConnectionEvent; import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.util.ServerUtils; import org.jetbrains.annotations.ApiStatus; @@ -42,6 +43,8 @@ public final class HibiscusCommonsPlugin extends HibiscusPlugin { return; } + getServer().getPluginManager().registerEvents(new PlayerConnectionEvent(), this); + // Plugin startup logic Hooks.setup(); } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java index f56c3cc..3d11590 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java @@ -3,6 +3,10 @@ package me.lojosho.hibiscuscommons; import com.jeff_media.updatechecker.UpdateCheckSource; import com.jeff_media.updatechecker.UpdateChecker; import lombok.Getter; +import lombok.Setter; +import me.lojosho.hibiscuscommons.packets.DefaultPacketInterface; +import me.lojosho.hibiscuscommons.packets.PacketInterface; +import me.lojosho.hibiscuscommons.plugins.SubPlugins; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @@ -20,6 +24,8 @@ public abstract class HibiscusPlugin extends JavaPlugin { private boolean onLatestVersion = true; @Getter private boolean disabled = false; + @Getter @Setter + private PacketInterface packetInterface = new DefaultPacketInterface(); protected HibiscusPlugin() { this(-1); @@ -47,6 +53,8 @@ public abstract class HibiscusPlugin extends JavaPlugin { return; } + SubPlugins.addSubPlugin(this); + if (bstats > 0) { Metrics metrics = new Metrics(this, bstats); } @@ -88,6 +96,7 @@ public abstract class HibiscusPlugin extends JavaPlugin { @Override public final void onDisable() { disabled = true; + SubPlugins.removeSubPlugin(this); onEnd(); } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java b/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java new file mode 100644 index 0000000..cdc5636 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java @@ -0,0 +1,15 @@ +package me.lojosho.hibiscuscommons.listener; + +import me.lojosho.hibiscuscommons.nms.NMSHandlers; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerConnectionEvent implements Listener { + + @EventHandler(ignoreCancelled = false, priority = EventPriority.LOW) + public void onPlayerJoin(PlayerJoinEvent event) { + NMSHandlers.getHandler().getUtilHandler().handleChannelOpen(event.getPlayer()); + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSPackets.java b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSPackets.java index 06b7e47..5ae2311 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSPackets.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSPackets.java @@ -1,29 +1,48 @@ package me.lojosho.hibiscuscommons.nms; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; +import org.bukkit.GameMode; import org.bukkit.Location; -import org.bukkit.entity.Display; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; public interface NMSPackets { static int POSITION_INTERPOLATION_DURATION = 2; + static int SHARED_ENTITY_METADATA = 0; - void sendSlotUpdate( - Player player, - int slot - ); + void sendSharedEntityData(int entityId, Map dataValues, List sendTo); + + void sendFakePlayerInfoPacket(final Player skinnedPlayer, final int entityId, final UUID uuid, final String npcName, final List sendTo); + + void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo); + + void sendMovePacket(final int entityId, final @NotNull Location from, final @NotNull Location to, final boolean onGround, @NotNull List sendTo); + + void sendGamemodeChange(Player player, GameMode gameMode); + + void sendRotateHeadPacket(int entityId, Location location, List sendTo); + + void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo); + + void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo); + + void sendSlotUpdate(Player player, int slot); + + default void sendLookAtPacket(int entityId, Location location, List sendTo) { + + } void sendEquipmentSlotUpdate( int entityId, @@ -58,8 +77,6 @@ public interface NMSPackets { List sendTo ); - void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo); - void sendCameraPacket(int entityId, List sendTo); void sendSpawnEntityPacket(int entityId, UUID uuid, EntityType entityType, Location location, List sendTo); @@ -77,4 +94,6 @@ public interface NMSPackets { List sendTo); void sendToastPacket(Player player, ItemStack icon, Component title, Component description); + + Object createMountPacket(int entityId, int[] passengerIds); } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java index 833f0b8..d21a566 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java @@ -19,4 +19,8 @@ public interface NMSUtils { ItemStack setColor(@NotNull ItemStack itemStack, Color color); + default void handleChannelOpen(@NotNull Player player) { + + } + } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java new file mode 100644 index 0000000..a63f9b2 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java @@ -0,0 +1,5 @@ +package me.lojosho.hibiscuscommons.packets; + +public class DefaultPacketInterface implements PacketInterface { + // Overrides nothing +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java new file mode 100644 index 0000000..3ec1098 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java @@ -0,0 +1,7 @@ +package me.lojosho.hibiscuscommons.packets; + +public enum PacketAction { + NOTHING, + CHANGED, + CANCELLED, +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java new file mode 100644 index 0000000..df61dd4 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java @@ -0,0 +1,44 @@ +package me.lojosho.hibiscuscommons.packets; + +import me.lojosho.hibiscuscommons.packets.wrapper.*; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public interface PacketInterface { + + default PacketAction writeContainerContent(@NotNull Player player, @NotNull ContainerContentWrapper wrapper) { + return PacketAction.NOTHING; + } + + default PacketAction writeSlotContent(@NotNull Player player, @NotNull SlotContentWrapper wrapper) { + return PacketAction.NOTHING; + } + + default PacketAction writeEquipmentContent(@NotNull Player player, @NotNull EntityEquipmentWrapper wrapper) { + return PacketAction.NOTHING; + } + + default PacketAction writePassengerContent(@NotNull Player player, @NotNull PassengerWrapper wrapper) { + return PacketAction.NOTHING; + } + + default PacketAction readInventoryClick(@NotNull Player player, @NotNull InventoryClickWrapper wrapper) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readPlayerAction(@NotNull Player player, @NotNull PlayerActionWrapper wrapper) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readPlayerArm(@NotNull Player player) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readEntityHandle(@NotNull Player player) { + return PacketAction.NOTHING; + // Override + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/ContainerContentWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/ContainerContentWrapper.java new file mode 100644 index 0000000..65f54ad --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/ContainerContentWrapper.java @@ -0,0 +1,20 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@Getter @Setter +public class ContainerContentWrapper { + + private Integer windowId; + private List slotData; + + public ContainerContentWrapper(@NotNull Integer windowId, @NotNull List slotData) { + this.windowId = windowId; + this.slotData = slotData; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/EntityEquipmentWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/EntityEquipmentWrapper.java new file mode 100644 index 0000000..0c8667d --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/EntityEquipmentWrapper.java @@ -0,0 +1,21 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +@Getter @Setter +public class EntityEquipmentWrapper { + + private int entityId; + private Map armor; + + public EntityEquipmentWrapper(int entityId, @NotNull Map armor) { + this.entityId = entityId; + this.armor = armor; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/InventoryClickWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/InventoryClickWrapper.java new file mode 100644 index 0000000..7eded2f --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/InventoryClickWrapper.java @@ -0,0 +1,17 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +@Getter @Setter +public class InventoryClickWrapper { + + private int clickType; + private int slotNumber; + + public InventoryClickWrapper(@NotNull Integer clickType, @NotNull Integer slotNumber) { + this.clickType = clickType; + this.slotNumber = slotNumber; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PassengerWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PassengerWrapper.java new file mode 100644 index 0000000..b36fa12 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PassengerWrapper.java @@ -0,0 +1,19 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@Getter @Setter +public class PassengerWrapper { + + private int owner; + private List passengers; + + public PassengerWrapper(@NotNull Integer owner, @NotNull List passengers) { + this.owner = owner; + this.passengers = passengers; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PlayerActionWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PlayerActionWrapper.java new file mode 100644 index 0000000..b3475fe --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/PlayerActionWrapper.java @@ -0,0 +1,14 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class PlayerActionWrapper { + + private String actionType; + + public PlayerActionWrapper(String actionType) { + this.actionType = actionType; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/SlotContentWrapper.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/SlotContentWrapper.java new file mode 100644 index 0000000..588e5a7 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/wrapper/SlotContentWrapper.java @@ -0,0 +1,20 @@ +package me.lojosho.hibiscuscommons.packets.wrapper; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +@Setter @Getter +public class SlotContentWrapper { + + private Integer windowId; + private int slot; + private ItemStack itemStack; + + public SlotContentWrapper(Integer windowId, Integer slot, @NotNull ItemStack itemStack) { + this.windowId = windowId; + this.slot = slot; + this.itemStack = itemStack; + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java b/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java new file mode 100644 index 0000000..a4ca256 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java @@ -0,0 +1,29 @@ +package me.lojosho.hibiscuscommons.plugins; + +import com.google.common.collect.ImmutableList; +import me.lojosho.hibiscuscommons.HibiscusPlugin; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class SubPlugins { + + private static final List SUB_PLUGINS = new ArrayList<>(); + + @NotNull + public static List getSubPlugins() { + return ImmutableList.copyOf(SUB_PLUGINS); + } + + @ApiStatus.Internal + public static void addSubPlugin(@NotNull HibiscusPlugin plugin) { + SUB_PLUGINS.add(plugin); + } + + @ApiStatus.Internal + public static void removeSubPlugin(@NotNull HibiscusPlugin plugin) { + SUB_PLUGINS.remove(plugin); + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/util/ServerUtils.java b/common/src/main/java/me/lojosho/hibiscuscommons/util/ServerUtils.java index 4d6ffaf..38aa218 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/util/ServerUtils.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/util/ServerUtils.java @@ -1,12 +1,12 @@ package me.lojosho.hibiscuscommons.util; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.comphenix.protocol.wrappers.WrappedSignedProperty; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; import me.lojosho.hibiscuscommons.nms.NMSHandlers; import org.bukkit.Color; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.profile.PlayerProfile; +import org.bukkit.profile.PlayerTextures; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,14 +21,8 @@ public class ServerUtils { } @Nullable - public static WrappedSignedProperty getSkin(Player player) { - WrappedSignedProperty skinData = WrappedGameProfile.fromPlayer(player).getProperties() - .get("textures").stream().findAny().orElse(null); - - if (skinData == null) { - return null; - } - return new WrappedSignedProperty("textures", skinData.getValue(), skinData.getSignature()); + public static PlayerTextures getSkin(Player player) { + return player.getPlayerProfile().getTextures(); } /** diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/util/packets/PacketManager.java b/common/src/main/java/me/lojosho/hibiscuscommons/util/packets/PacketManager.java index 07e8fad..fe9e60c 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/util/packets/PacketManager.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/util/packets/PacketManager.java @@ -1,12 +1,10 @@ package me.lojosho.hibiscuscommons.util.packets; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketContainer; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.util.MessagesUtil; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -34,14 +32,9 @@ public class PacketManager { public static void gamemodeChangePacket( Player player, - int gamemode + GameMode gamemode ) { - PacketContainer packet = new PacketContainer(PacketType.Play.Server.GAME_STATE_CHANGE); - packet.getGameStateIDs().write(0, 3); - // Tells what event this is. This is a change gamemode event. - packet.getFloat().write(0, (float) gamemode); - sendPacket(player, packet); - MessagesUtil.sendDebugMessages("Gamemode Change sent to " + player + " to be " + gamemode); + NMSHandlers.getHandler().getPacketHandler().sendGamemodeChange(player, gamemode); } public static void ridingMountPacket( @@ -52,15 +45,12 @@ public class PacketManager { NMSHandlers.getHandler().getPacketHandler().sendMountPacket(mountId, new int[]{passengerId}, sendTo); } - public static void sendLookPacket( + public static void sendRotateHeadPacket( int entityId, @NotNull Location location, @NotNull List sendTo ) { - PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_HEAD_ROTATION); - packet.getIntegers().write(0, entityId); - packet.getBytes().write(0, (byte) (location.getYaw() * 256.0F / 360.0F)); - for (Player p : sendTo) sendPacket(p, packet); + NMSHandlers.getHandler().getPacketHandler().sendRotateHeadPacket(entityId, location, sendTo); } public static void sendRotationPacket( @@ -69,29 +59,7 @@ public class PacketManager { boolean onGround, @NotNull List sendTo ) { - float ROTATION_FACTOR = 256.0F / 360.0F; - float yaw = location.getYaw() * ROTATION_FACTOR; - float pitch = location.getPitch() * ROTATION_FACTOR; - PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_LOOK); - packet.getIntegers().write(0, entityId); - packet.getBytes().write(0, (byte) yaw); - packet.getBytes().write(1, (byte) pitch); - - //Bukkit.getLogger().info("DEBUG: Yaw: " + (location.getYaw() * ROTATION_FACTOR) + " | Original Yaw: " + location.getYaw()); - packet.getBooleans().write(0, onGround); - for (Player p : sendTo) sendPacket(p, packet); - } - - public static void sendRotationPacket( - int entityId, - int yaw, - boolean onGround, - @NotNull List sendTo - ) { - float ROTATION_FACTOR = 256.0F / 360.0F; - float yaw2 = yaw * ROTATION_FACTOR; - - NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw2, onGround, sendTo); + NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, location, onGround, sendTo); } public static void sendRidingPacket( @@ -213,9 +181,4 @@ public class PacketManager { return players; } - public static void sendPacket(Player player, PacketContainer packet) { - if (player == null) return; - ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet, null,false); - } - } diff --git a/v1_20_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R3/NMSPackets.java b/v1_20_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R3/NMSPackets.java index d3501df..751d51f 100644 --- a/v1_20_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R3/NMSPackets.java +++ b/v1_20_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R3/NMSPackets.java @@ -1,30 +1,31 @@ package me.lojosho.hibiscuscommons.nms.v1_20_R3; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonObject; +import com.google.common.collect.ImmutableList; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_20_R3.CraftEquipmentSlot; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntityType; @@ -36,52 +37,113 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; -import java.nio.ByteBuffer; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor teleportConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - teleportConstructor = ClientboundTeleportEntityPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - teleportConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -177,28 +239,28 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -212,47 +274,20 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. boolean onGround, List sendTo ) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeDouble(x); - byteBuf.writeDouble(y); - byteBuf.writeDouble(z); - byteBuf.writeByte((byte) (yaw * 256.0F / 360.0F)); - byteBuf.writeByte((byte) (pitch * 256.0F / 360.0F)); - byteBuf.writeBoolean(onGround); + fakeNmsEntity.setId(entityId); + fakeNmsEntity.setRot((yaw * 256.0F / 360.0F), (pitch * 256.0F / 360.0F)); + fakeNmsEntity.setOnGround(onGround); - try { - ClientboundTeleportEntityPacket packet = teleportConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + ClientboundTeleportEntityPacket packet = new ClientboundTeleportEntityPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -311,4 +346,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. public void sendToastPacket(Player player, ItemStack icon, Component title, Component description) { throw new UnsupportedOperationException("Not implemented in this version."); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_20_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R4/NMSPackets.java b/v1_20_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R4/NMSPackets.java index afe43fb..a343988 100644 --- a/v1_20_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R4/NMSPackets.java +++ b/v1_20_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_20_R4/NMSPackets.java @@ -1,29 +1,37 @@ package me.lojosho.hibiscuscommons.nms.v1_20_R4; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; @@ -36,51 +44,113 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; -import java.nio.ByteBuffer; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor teleportConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - teleportConstructor = ClientboundTeleportEntityPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - teleportConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -175,28 +245,28 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -210,47 +280,20 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. boolean onGround, List sendTo ) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeDouble(x); - byteBuf.writeDouble(y); - byteBuf.writeDouble(z); - byteBuf.writeByte((byte) (yaw * 256.0F / 360.0F)); - byteBuf.writeByte((byte) (pitch * 256.0F / 360.0F)); - byteBuf.writeBoolean(onGround); + fakeNmsEntity.setId(entityId); + fakeNmsEntity.setRot((yaw * 256.0F / 360.0F), (pitch * 256.0F / 360.0F)); + fakeNmsEntity.setOnGround(onGround); - try { - ClientboundTeleportEntityPacket packet = teleportConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + ClientboundTeleportEntityPacket packet = new ClientboundTeleportEntityPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -372,4 +415,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R1/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R1/NMSPackets.java b/v1_21_R1/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R1/NMSPackets.java index 0433390..ce9122b 100644 --- a/v1_21_R1/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R1/NMSPackets.java +++ b/v1_21_R1/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R1/NMSPackets.java @@ -1,30 +1,37 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R1; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonObject; -import com.mojang.datafixers.kinds.Const; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; @@ -37,61 +44,114 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor teleportConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; - static Constructor rotationConstructor; - static Constructor spawnConstructor; + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - teleportConstructor = ClientboundTeleportEntityPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - teleportConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - rotationConstructor = ClientboundRotateHeadPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - rotationConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); } + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } @Override public void sendEquipmentSlotUpdate( @@ -185,28 +245,28 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -220,47 +280,20 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. boolean onGround, List sendTo ) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeDouble(x); - byteBuf.writeDouble(y); - byteBuf.writeDouble(z); - byteBuf.writeByte((byte) (yaw * 256.0F / 360.0F)); - byteBuf.writeByte((byte) (pitch * 256.0F / 360.0F)); - byteBuf.writeBoolean(onGround); + fakeNmsEntity.setId(entityId); + fakeNmsEntity.setRot((yaw * 256.0F / 360.0F), (pitch * 256.0F / 360.0F)); + fakeNmsEntity.setOnGround(onGround); - try { - ClientboundTeleportEntityPacket packet = teleportConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + ClientboundTeleportEntityPacket packet = new ClientboundTeleportEntityPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -381,4 +414,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R2/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R2/NMSPackets.java b/v1_21_R2/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R2/NMSPackets.java index 6170489..50e6abc 100644 --- a/v1_21_R2/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R2/NMSPackets.java +++ b/v1_21_R2/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R2/NMSPackets.java @@ -1,31 +1,38 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R2; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; @@ -36,47 +43,115 @@ import org.bukkit.entity.Display; import org.bukkit.entity.EntityType; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; -import java.nio.ByteBuffer; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, player.listOrder, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -172,28 +247,28 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -215,30 +290,12 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. } } - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -360,4 +417,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R3/NMSPackets.java b/v1_21_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R3/NMSPackets.java index 5349455..eade0a1 100644 --- a/v1_21_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R3/NMSPackets.java +++ b/v1_21_R3/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R3/NMSPackets.java @@ -1,33 +1,40 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R3; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; -import net.minecraft.advancements.*; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; import org.bukkit.Color; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; @@ -38,49 +45,116 @@ import org.bukkit.entity.Display; import org.bukkit.entity.EntityType; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; -import java.nio.ByteBuffer; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, true, player.listOrder, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -176,28 +250,29 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.setId(mountId); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -219,30 +294,12 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. } } - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -398,4 +455,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R4/NMSPackets.java b/v1_21_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R4/NMSPackets.java index 81056db..4b2c139 100644 --- a/v1_21_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R4/NMSPackets.java +++ b/v1_21_R4/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R4/NMSPackets.java @@ -1,85 +1,162 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R4; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.AdventureComponent; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.json.JSONComponentSerializer; -import net.minecraft.advancements.*; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; +import org.apache.commons.lang3.tuple.Triple; import org.bukkit.Bukkit; import org.bukkit.Color; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.scoreboard.CraftScoreboard; -import org.bukkit.entity.Display; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, true, player.listOrder, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -175,28 +252,28 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -211,21 +288,7 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. List sendTo ) { try { - ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), java.util.Set.of(), onGround); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); + ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), Set.of(), onGround); for (Player p : sendTo) sendPacket(p, packet); } catch (Exception e) { e.printStackTrace(); @@ -234,14 +297,10 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -394,4 +453,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java index 0043389..124c5a5 100644 --- a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java @@ -13,5 +13,4 @@ public class NMSCommon { ServerPlayerConnection connection = serverPlayer.connection; connection.send(packet); } - } diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java new file mode 100644 index 0000000..3f6b626 --- /dev/null +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java @@ -0,0 +1,226 @@ +package me.lojosho.hibiscuscommons.nms.v1_21_R5; + +import com.mojang.datafixers.util.Pair; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import lombok.Getter; +import me.lojosho.hibiscuscommons.nms.NMSHandlers; +import me.lojosho.hibiscuscommons.packets.PacketAction; +import me.lojosho.hibiscuscommons.packets.wrapper.*; +import me.lojosho.hibiscuscommons.plugins.SubPlugins; +import me.lojosho.hibiscuscommons.util.MessagesUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.CraftEquipmentSlot; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +public class NMSPacketChannel extends ChannelDuplexHandler { + + @Getter + private final Player player; + + public NMSPacketChannel(Player player) { + this.player = player; + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (!(msg instanceof Packet packet)) { + super.write(ctx, msg, promise); + return; + } + + switch (packet) { + case ClientboundContainerSetContentPacket setContentPacket -> msg = handleMenuChange(setContentPacket); + case ClientboundContainerSetSlotPacket setSlotPacket -> msg = handleSlotChange(setSlotPacket); + case ClientboundSetEquipmentPacket equipmentPacket -> msg = handlePlayerEquipment(equipmentPacket); + case ClientboundSetPassengersPacket passengerPacket -> msg = handlePassengerSet(passengerPacket); + default -> {} + } + + if (msg == null) return; + else super.write(ctx, msg, promise); + } + + private Packet handleMenuChange(@NotNull ClientboundContainerSetContentPacket packet) { + MessagesUtil.sendDebugMessages("Menu Initial "); + + Integer windowId = packet.containerId(); + NonNullList slotData = NonNullList.create(); + slotData.addAll(packet.items()); + + List bukkitItems = slotData.stream().map(CraftItemStack::asBukkitCopy).toList(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + ContainerContentWrapper wrapper = new ContainerContentWrapper(windowId, bukkitItems); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().writeContainerContent(player, wrapper); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + List nmsItems = wrapper.getSlotData().stream().map(CraftItemStack::asNMSCopy).toList(); + return new ClientboundContainerSetContentPacket(0, packet.stateId(), nmsItems, packet.carriedItem()); + } + + private Packet handleSlotChange(@NotNull ClientboundContainerSetSlotPacket packet) { + MessagesUtil.sendDebugMessages("SetSlot Initial "); + + final int windowId = packet.getContainerId(); + final int slot = packet.getSlot(); + final ItemStack item = packet.getItem(); + + org.bukkit.inventory.ItemStack bukkitItem = CraftItemStack.asBukkitCopy(item); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SlotContentWrapper wrapper = new SlotContentWrapper(windowId, slot, bukkitItem); + + SubPlugins.getSubPlugins().forEach(plugin -> { + PacketAction pluginAction = plugin.getPacketInterface().writeSlotContent(player, wrapper); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + + final ItemStack nmsItem = CraftItemStack.asNMSCopy(wrapper.getItemStack()); + + return new ClientboundContainerSetSlotPacket(0, packet.getStateId(), wrapper.getSlot(), nmsItem); + } + + private Packet handlePlayerEquipment(@NotNull ClientboundSetEquipmentPacket packet) { + final List> nmsArmor = packet.getSlots(); + final int entity = packet.getEntity(); + HashMap bukkitArmor = new HashMap<>(); + for (Pair piece : nmsArmor) { + EquipmentSlot slot = CraftEquipmentSlot.getSlot(piece.getFirst()); + org.bukkit.inventory.ItemStack itemStack = CraftItemStack.asBukkitCopy(piece.getSecond()); + bukkitArmor.put(slot, itemStack); + } + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + EntityEquipmentWrapper wrapper = new EntityEquipmentWrapper(entity, bukkitArmor); + + SubPlugins.getSubPlugins().forEach(plugin -> { + PacketAction pluginAction = plugin.getPacketInterface().writeEquipmentContent(player, wrapper); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + + + List> newArmor = new ArrayList<>(); + for (Map.Entry entry : wrapper.getArmor().entrySet()) { + net.minecraft.world.entity.EquipmentSlot slot = CraftEquipmentSlot.getNMS(entry.getKey()); + ItemStack itemStack = CraftItemStack.asNMSCopy(entry.getValue()); + newArmor.add(new Pair<>(slot, itemStack)); + } + + return new ClientboundSetEquipmentPacket(packet.getEntity(), newArmor); + } + + private Packet handlePassengerSet(@NotNull ClientboundSetPassengersPacket packet) { + int ownerId = packet.getVehicle(); + List passengers = Arrays.stream(packet.getPassengers()).boxed().collect(Collectors.toList()); + MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + PassengerWrapper wrapper = new PassengerWrapper(ownerId, passengers); + SubPlugins.getSubPlugins().forEach(plugin -> { + PacketAction pluginAction = plugin.getPacketInterface().writePassengerContent(player, wrapper); + if (pluginAction != PacketAction.NOTHING) { + action.set(pluginAction); + } + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + return (Packet) NMSHandlers.getHandler().getPacketHandler().createMountPacket(ownerId, passengers.stream().mapToInt(Integer::intValue).toArray()); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (!(msg instanceof Packet packet)) { + super.channelRead(ctx, msg); + return; + } + + switch (packet) { + case ServerboundContainerClickPacket clickPacket -> msg = handleInventoryClick(clickPacket); + case ServerboundPlayerActionPacket playerActionPacket -> msg = handlePlayerAction(playerActionPacket); + case ServerboundSwingPacket swingPacket -> msg = handlePlayerArm(swingPacket); + case ServerboundInteractPacket interactPacket -> msg = handleInteract(interactPacket); + default -> {} + } + + if (msg == null) return; + else super.channelRead(ctx, msg); + } + + private Packet handleInventoryClick(@NotNull ServerboundContainerClickPacket packet) { + ClickType clickType = packet.clickType(); + int slotClicked = packet.slotNum(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readInventoryClick(player, new InventoryClickWrapper(clickType.id(), slotClicked)); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handlePlayerAction(ServerboundPlayerActionPacket packet) { + ServerboundPlayerActionPacket.Action playerAction = packet.getAction(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readPlayerAction(player, new PlayerActionWrapper(playerAction.name())); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handlePlayerArm(ServerboundSwingPacket packet) { + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readPlayerArm(player); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handleInteract(ServerboundInteractPacket packet) { + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readEntityHandle(player); + if (pluginAction != PacketAction.NOTHING) action.set(pluginAction); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } +} \ No newline at end of file diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java index 5a43ee4..8c3cc00 100644 --- a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java @@ -1,84 +1,165 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R5; +import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.JsonOps; -import io.netty.buffer.Unpooled; +import io.papermc.paper.adventure.PaperAdventure; import it.unimi.dsi.fastutil.ints.IntList; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import me.lojosho.hibiscuscommons.util.AdventureUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minecraft.advancements.*; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.level.GameType; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.bukkit.Bukkit; import org.bukkit.Color; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.scoreboard.CraftScoreboard; -import org.bukkit.entity.Display; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.lang.reflect.Constructor; import java.util.*; +import java.util.stream.Collectors; public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { - static Constructor passengerConstructor; - static Constructor linkConstructor; - static Constructor cameraConstructor; - static Constructor lookAtConstructor; + private static ServerLevel level = MinecraftServer.getServer().overworld(); + private static Entity fakeNmsEntity = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); - static { - try { - passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - passengerConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - linkConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - cameraConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - try { - lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); - lookAtConstructor.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } + @Override @SuppressWarnings("unchecked") + public void sendSharedEntityData(int entityId, Map dataValues, List sendTo) { + List> nmsDataValues = dataValues.entrySet().stream().map(entry -> { + int index = entry.getKey(); + Number value = entry.getValue(); + return switch (value) { + case Byte byteVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.BYTE, byteVal); + case Float floatVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.FLOAT, floatVal); + case Integer intVal -> new SynchedEntityData.DataValue<>(index, EntityDataSerializers.INT, intVal); + default -> + throw new IllegalArgumentException("Unsupported data value type: " + value.getClass().getSimpleName()); + }; + }).collect(Collectors.toList()); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, nmsDataValues); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendFakePlayerInfoPacket( + final Player skinnedPlayer, + final int entityId, + final UUID uuid, + final String npcName, + final List sendTo + ) { + ServerPlayer player = ((CraftPlayer) skinnedPlayer).getHandle(); + String name = npcName.substring(0, 15); + GameProfile profile = new GameProfile(uuid, name); + + Component component = AdventureUtils.MINI_MESSAGE.deserialize(name); + net.minecraft.network.chat.Component nmsComponent = HibiscusCommonsPlugin.isOnPaper() ? PaperAdventure.asVanilla(component) : net.minecraft.network.chat.Component.literal(name); + + ClientboundPlayerInfoUpdatePacket.Entry entry = new ClientboundPlayerInfoUpdatePacket.Entry(uuid, profile, false, 0, GameType.CREATIVE, nmsComponent, true, player.listOrder, player.getChatSession().asData()); + EnumSet actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER); + ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(actions, entry); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendPlayerInfoRemovePacket(final UUID uuid, final List sendTo) { + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(uuid)); + for (Player player : sendTo) sendPacket(player, packet); + } + + @Override + public void sendMovePacket( + final int entityId, + final @NotNull Location from, + final @NotNull Location to, + final boolean onGround, + @NotNull List sendTo + ) { + byte dx = (byte) (to.getX() - from.getX()); + byte dy = (byte) (to.getY() - from.getY()); + byte dz = (byte) (to.getZ() - from.getZ()); + + ClientboundMoveEntityPacket.Pos packet = new ClientboundMoveEntityPacket.Pos(entityId, dx, dy, dz, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendGamemodeChange(Player player, GameMode gameMode) { + ClientboundGameEventPacket.Type type = ClientboundGameEventPacket.CHANGE_GAME_MODE; + float param = gameMode.ordinal(); + + ClientboundGameEventPacket packet = new ClientboundGameEventPacket(type, param); + sendPacket(player, packet); + } + + @Override + public void sendLookAtPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + fakeNmsEntity.getBukkitEntity().teleport(location); + ClientboundPlayerLookAtPacket packet = new ClientboundPlayerLookAtPacket(EntityAnchorArgument.Anchor.EYES, fakeNmsEntity, EntityAnchorArgument.Anchor.EYES); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotateHeadPacket(int entityId, Location location, List sendTo) { + fakeNmsEntity.setId(entityId); + byte headRot = (byte) (location.getYaw() * 256.0F / 360.0F); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(fakeNmsEntity, headRot); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, float yaw, float pitch, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + yaw = (byte) (yaw * ROTATION_FACTOR); + pitch = (byte) (pitch * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, (byte) yaw, (byte) pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendRotationPacket(int entityId, Location location, boolean onGround, List sendTo) { + float ROTATION_FACTOR = 256.0F / 360.0F; + byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR); + byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR); + ClientboundMoveEntityPacket.Rot packet = new ClientboundMoveEntityPacket.Rot(entityId, yaw, pitch, onGround); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -174,28 +255,29 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(mountId); - byteBuf.writeVarIntArray(passengerIds); - try { - ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.setId(mountId); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + for (Player p : sendTo) sendPacket(p, packet); } @Override public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeInt(leashEntity); - byteBuf.writeInt(entityId); - try { - ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + // Fake entities just to avoid reflection + ServerLevel level = MinecraftServer.getServer().overworld(); + Entity entity1 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + Entity entity2 = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + entity1.setId(leashEntity); + entity2.setId(entityId); + + ClientboundSetEntityLinkPacket packet = new ClientboundSetEntityLinkPacket(entity1, entity2); + for (Player p : sendTo) sendPacket(p, packet); } @Override @@ -210,21 +292,7 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. List sendTo ) { try { - ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), java.util.Set.of(), onGround); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Override - public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - byteBuf.writeFloat(yaw); - byteBuf.writeBoolean(onGround); - try { - ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); + ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), Set.of(), onGround); for (Player p : sendTo) sendPacket(p, packet); } catch (Exception e) { e.printStackTrace(); @@ -233,14 +301,10 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. @Override public void sendCameraPacket(int entityId, List sendTo) { - FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); - byteBuf.writeVarInt(entityId); - try { - ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); - for (Player p : sendTo) sendPacket(p, packet); - } catch (Exception e) { - e.printStackTrace(); - } + fakeNmsEntity.setId(entityId); + + ClientboundSetCameraPacket packet = new ClientboundSetCameraPacket(fakeNmsEntity); + for (Player p : sendTo) sendPacket(p, packet); } @@ -393,4 +457,18 @@ public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons. sendPacket(player, removePacket); }, 2L); } + + @Override + public Object createMountPacket(int entityId, int[] passengerIds) { + fakeNmsEntity.setId(entityId); + List passengers = Arrays.stream(passengerIds).mapToObj(id -> { + Entity passenger = new ArmorStand(net.minecraft.world.entity.EntityType.ARMOR_STAND, level); + passenger.setId(id); + return passenger; + }).toList(); + fakeNmsEntity.passengers = ImmutableList.copyOf(passengers); + ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(fakeNmsEntity); + fakeNmsEntity.passengers = ImmutableList.of(); + return packet; + } } diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java index c7bdce4..ac20859 100644 --- a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java @@ -1,12 +1,17 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R5; +import io.netty.channel.Channel; +import io.netty.channel.ChannelPipeline; import net.minecraft.core.component.DataComponents; +import net.minecraft.network.Connection; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.component.DyedItemColor; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,4 +56,16 @@ public class NMSUtils extends NMSCommon implements me.lojosho.hibiscuscommons.nm } return null; } + + @Override + public void handleChannelOpen(@NotNull Player player) { + Channel channel = ((CraftPlayer) player).getHandle().connection.connection.channel; + ChannelPipeline pipeline = channel.pipeline(); + + NMSPacketChannel channelHandler = new NMSPacketChannel(player); + for (String key : pipeline.toMap().keySet()) { + if (!(pipeline.get(key) instanceof Connection)) continue; + pipeline.addBefore(key, "hibiscus_channel_handler", channelHandler); + } + } }