diff --git a/eco-api/src/main/java/com/willfp/eco/core/packet/Packet.java b/eco-api/src/main/java/com/willfp/eco/core/packet/Packet.java index 9a69382f..e6f9eefe 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/packet/Packet.java +++ b/eco-api/src/main/java/com/willfp/eco/core/packet/Packet.java @@ -6,10 +6,51 @@ import org.jetbrains.annotations.NotNull; /** * Represents a packet. - * - * @param handle The NMS handle. */ -public record Packet(@NotNull Object handle) { +public class Packet { + /** + * The packet handle. + */ + private Object handle; + + /** + * Create a new packet. + * + * @param handle The packet handle. + */ + public Packet(@NotNull final Object handle) { + this.handle = handle; + } + + /** + * Get the packet handle. + * + * @return The packet handle. + */ + public Object getHandle() { + return handle; + } + + /** + * Set the packet handle. + * + * @param handle The packet handle. + */ + public void setHandle(@NotNull final Object handle) { + this.handle = handle; + } + + /** + * Get the packet handle, compatible with the old record-based packet system. + * + * @return The packet handle. + * @deprecated Use {@link #getHandle()} instead. + */ + @Deprecated + public Object handle() { + return handle; + } + /** * Send to a player. * diff --git a/eco-core/core-nms/common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/packet/EcoChannelDuplexHandler.kt b/eco-core/core-nms/common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/packet/EcoChannelDuplexHandler.kt index cf59063c..e6826d5a 100644 --- a/eco-core/core-nms/common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/packet/EcoChannelDuplexHandler.kt +++ b/eco-core/core-nms/common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/packet/EcoChannelDuplexHandler.kt @@ -23,7 +23,7 @@ class EcoChannelDuplexHandler( event.handleReceive() if (!event.isCancelled) { - super.channelRead(ctx, msg) + super.channelRead(ctx, event.packet.handle) } } else { super.channelRead(ctx, msg) @@ -39,7 +39,7 @@ class EcoChannelDuplexHandler( event.handleSend() if (!event.isCancelled) { - super.write(ctx, msg, promise) + super.write(ctx, event.packet.handle, promise) } } else { super.write(ctx, msg, promise) diff --git a/eco-core/core-nms/modern/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/modern/NewEcoFastItemStack.kt b/eco-core/core-nms/modern/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/modern/NewEcoFastItemStack.kt index fb023ad4..cd47848f 100644 --- a/eco-core/core-nms/modern/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/modern/NewEcoFastItemStack.kt +++ b/eco-core/core-nms/modern/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/modern/NewEcoFastItemStack.kt @@ -144,7 +144,7 @@ open class NewEcoFastItemStack( override fun getDisplayName(): String = displayNameComponent.toLegacy() - private fun net.minecraft.world.item.ItemStack.modifyComponent( + protected fun net.minecraft.world.item.ItemStack.modifyComponent( component: DataComponentType, modifier: (T) -> T ) { diff --git a/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_4/packet/NewItemsPacketSetCreativeSlot.kt b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_4/packet/NewItemsPacketSetCreativeSlot.kt index c1b491a0..766f7677 100644 --- a/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_4/packet/NewItemsPacketSetCreativeSlot.kt +++ b/eco-core/core-nms/v1_21_4/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_4/packet/NewItemsPacketSetCreativeSlot.kt @@ -6,6 +6,7 @@ import com.willfp.eco.core.packet.PacketListener import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket object NewItemsPacketSetCreativeSlot : PacketListener { diff --git a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/FastItemStackFactory.kt b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/FastItemStackFactory.kt index 61af4731..d02c5132 100644 --- a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/FastItemStackFactory.kt +++ b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/FastItemStackFactory.kt @@ -3,10 +3,11 @@ package com.willfp.eco.internal.spigot.proxy.v1_21_5 import com.willfp.eco.core.fast.FastItemStack import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.common.modern.NewEcoFastItemStack +import com.willfp.eco.internal.spigot.proxy.v1_21_5.item.NewerEcoFastItemStack import org.bukkit.inventory.ItemStack class FastItemStackFactory : FastItemStackFactoryProxy { override fun create(itemStack: ItemStack): FastItemStack { - return NewEcoFastItemStack(itemStack) + return NewerEcoFastItemStack(itemStack) } } diff --git a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/PacketHandler.kt b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/PacketHandler.kt index 794b278d..5da5c273 100644 --- a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/PacketHandler.kt +++ b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/PacketHandler.kt @@ -5,10 +5,10 @@ import com.willfp.eco.core.packet.PacketListener import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot -import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames import com.willfp.eco.internal.spigot.proxy.v1_21_5.packet.NewItemsPacketOpenWindowMerchant import com.willfp.eco.internal.spigot.proxy.v1_21_5.packet.NewItemsPacketSetCreativeSlot +import com.willfp.eco.internal.spigot.proxy.v1_21_5.packet.NewItemsPacketWindowItems import net.minecraft.network.protocol.Packet import org.bukkit.craftbukkit.entity.CraftPlayer import org.bukkit.entity.Player @@ -40,7 +40,7 @@ class PacketHandler : PacketHandlerProxy { NewItemsPacketOpenWindowMerchant, NewItemsPacketSetCreativeSlot, PacketSetSlot, - PacketWindowItems(plugin) + NewItemsPacketWindowItems(plugin) ) } } diff --git a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/item/NewerEcoFastItemStack.kt b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/item/NewerEcoFastItemStack.kt new file mode 100644 index 00000000..e2d946c0 --- /dev/null +++ b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/item/NewerEcoFastItemStack.kt @@ -0,0 +1,185 @@ +package com.willfp.eco.internal.spigot.proxy.v1_21_5.item + +import com.willfp.eco.internal.spigot.proxy.common.modern.NewEcoFastItemStack +import net.minecraft.core.component.DataComponents +import net.minecraft.world.item.component.TooltipDisplay +import org.bukkit.inventory.ItemFlag +import org.bukkit.inventory.ItemStack + + +open class NewerEcoFastItemStack( + bukkit: ItemStack, +) : NewEcoFastItemStack(bukkit) { + override fun addItemFlags(vararg hideFlags: ItemFlag) { + for (flag in hideFlags) { + when (flag) { + ItemFlag.HIDE_ENCHANTS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.ENCHANTMENTS, true) + } + } + + ItemFlag.HIDE_ATTRIBUTES -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.ATTRIBUTE_MODIFIERS, true) + } + } + + ItemFlag.HIDE_UNBREAKABLE -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.UNBREAKABLE, true) + } + } + + ItemFlag.HIDE_DESTROYS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.CAN_BREAK, true) + } + } + + ItemFlag.HIDE_PLACED_ON -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.CAN_PLACE_ON, true) + } + } + + ItemFlag.HIDE_ADDITIONAL_TOOLTIP -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + TooltipDisplay(true, tooltip.hiddenComponents) + } + } + + ItemFlag.HIDE_DYE -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.DYED_COLOR, true) + } + } + + ItemFlag.HIDE_ARMOR_TRIM -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.TRIM, true) + } + } + + ItemFlag.HIDE_STORED_ENCHANTS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.STORED_ENCHANTMENTS, true) + } + } + } + } + + apply() + } + + override fun removeItemFlags(vararg hideFlags: ItemFlag) { + for (flag in hideFlags) { + when (flag) { + ItemFlag.HIDE_ENCHANTS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.ENCHANTMENTS, false) + } + } + + ItemFlag.HIDE_ATTRIBUTES -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.ATTRIBUTE_MODIFIERS, false) + } + } + + ItemFlag.HIDE_UNBREAKABLE -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.UNBREAKABLE, false) + } + } + + ItemFlag.HIDE_DESTROYS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.CAN_BREAK, false) + } + } + + ItemFlag.HIDE_PLACED_ON -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.CAN_PLACE_ON, false) + } + } + + ItemFlag.HIDE_ADDITIONAL_TOOLTIP -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + TooltipDisplay(false, tooltip.hiddenComponents) + } + } + + ItemFlag.HIDE_DYE -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.DYED_COLOR, false) + } + } + + ItemFlag.HIDE_ARMOR_TRIM -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.TRIM, false) + } + } + + ItemFlag.HIDE_STORED_ENCHANTS -> { + handle.modifyComponent(DataComponents.TOOLTIP_DISPLAY) { tooltip -> + tooltip.withHidden(DataComponents.STORED_ENCHANTMENTS, false) + } + } + } + } + + apply() + } + + override fun hasItemFlag(flag: ItemFlag): Boolean { + return when (flag) { + ItemFlag.HIDE_ENCHANTS -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.ENCHANTMENTS) + } + + ItemFlag.HIDE_ATTRIBUTES -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.ATTRIBUTE_MODIFIERS) + } + + ItemFlag.HIDE_UNBREAKABLE -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.UNBREAKABLE) + } + + ItemFlag.HIDE_DESTROYS -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.CAN_BREAK) + } + + ItemFlag.HIDE_PLACED_ON -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.CAN_PLACE_ON) + } + + ItemFlag.HIDE_ADDITIONAL_TOOLTIP -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + tooltip.hideTooltip + } + + ItemFlag.HIDE_DYE -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.DYED_COLOR) + } + + ItemFlag.HIDE_ARMOR_TRIM -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.TRIM) + } + + ItemFlag.HIDE_STORED_ENCHANTS -> { + val tooltip = handle.get(DataComponents.TOOLTIP_DISPLAY) ?: return false + !tooltip.shows(DataComponents.STORED_ENCHANTMENTS) + } + } + } +} diff --git a/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/packet/NewItemsPacketWindowItems.kt b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/packet/NewItemsPacketWindowItems.kt new file mode 100644 index 00000000..56def880 --- /dev/null +++ b/eco-core/core-nms/v1_21_5/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_21_5/packet/NewItemsPacketWindowItems.kt @@ -0,0 +1,90 @@ +package com.willfp.eco.internal.spigot.proxy.v1_21_5.packet + +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.display.Display +import com.willfp.eco.core.items.HashedItem +import com.willfp.eco.core.packet.PacketEvent +import com.willfp.eco.core.packet.PacketListener +import com.willfp.eco.internal.spigot.proxy.common.asBukkitStack +import com.willfp.eco.internal.spigot.proxy.common.asNMSStack +import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.DisplayFrame +import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.lastDisplayFrame +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import java.util.UUID +import java.util.concurrent.ConcurrentHashMap + +class NewItemsPacketWindowItems( + private val plugin: EcoPlugin +) : PacketListener { + private val lastKnownWindowIDs = ConcurrentHashMap() + + + override fun onSend(event: PacketEvent) { + val packet = event.packet.handle as? ClientboundContainerSetContentPacket ?: return + val player = event.player + + Display.display(packet.carriedItem.asBukkitStack(), player) + + val windowId = packet.containerId + + val lastKnownID = lastKnownWindowIDs[player.uniqueId] + lastKnownWindowIDs[player.uniqueId] = windowId + + // If there is any change in window ID at any point, + // Remove the last display frame to prevent any potential conflicts. + // If the window ID is not zero (not a player inventory), then remove too, + // as GUIs are not player inventories. + if (lastKnownID != windowId || windowId != 0) { + player.lastDisplayFrame = DisplayFrame.EMPTY + } + + val itemStacks = packet.items.map { it.asBukkitStack() } + + val newItems = modifyWindowItems(itemStacks.toMutableList(), windowId, player) + + val newPacket = ClientboundContainerSetContentPacket( + packet.containerId, + packet.stateId, + newItems.map { it.asNMSStack() }, + packet.carriedItem, + ) + + event.packet.handle = newPacket + } + + private fun modifyWindowItems( + itemStacks: MutableList, + windowId: Int, + player: Player + ): MutableList { + if (plugin.configYml.getBool("use-display-frame") && windowId == 0) { + val frameMap = mutableMapOf() + + for (index in itemStacks.indices) { + frameMap[index.toByte()] = HashedItem.of(itemStacks[index]) + } + + val newFrame = DisplayFrame(frameMap) + + val lastFrame = player.lastDisplayFrame + + player.lastDisplayFrame = newFrame + + val changes = lastFrame.getChangedSlots(newFrame) + + for (index in changes) { + Display.display(itemStacks[index.toInt()], player) + } + + for (index in (itemStacks.indices subtract changes.toSet())) { + itemStacks[index.toInt()] = lastFrame.getItem(index.toByte()) ?: itemStacks[index.toInt()] + } + } else { + itemStacks.forEach { Display.display(it, player) } + } + + return itemStacks + } +}