From 7e4c8504db2e4edf27aba3bd27c933e838efbc73 Mon Sep 17 00:00:00 2001 From: acrylic-style Date: Sun, 3 Nov 2024 20:51:25 +0900 Subject: [PATCH] bug fix --- .../loreeditor/api/util/ReflectionUtil.java | 10 +++++ build.gradle.kts | 2 +- .../common/network/PacketPreHandler.java | 29 +++++++------ .../network/packet/ClientboundSetSlot.java | 6 +++ .../packet/ClientboundWindowItems.java | 2 + .../packet/ClientboundSetSlotImpl.java | 5 +++ .../packet/ClientboundWindowItemsImpl.java | 9 ++++ .../packet/ClientboundSetSlotImpl.java | 5 +++ .../packet/ClientboundWindowItemsImpl.java | 9 ++++ .../packet/ClientboundSetSlotImpl.java | 6 +++ .../packet/ClientboundWindowItemsImpl.java | 10 ++++- .../packet/ClientboundSetSlotImpl.java | 6 +++ .../packet/ClientboundWindowItemsImpl.java | 10 ++++- .../v1_21_1/chat/ComponentImpl.java | 2 +- .../v1_21_1/item/ItemStackImpl.java | 43 +++++++++++++++++-- .../packet/ClientboundSetSlotImpl.java | 6 +++ .../packet/ClientboundWindowItemsImpl.java | 7 +++ 17 files changed, 145 insertions(+), 22 deletions(-) diff --git a/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java b/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java index e032e74..7261f40 100644 --- a/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java +++ b/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java @@ -87,4 +87,14 @@ public static boolean isModernNMS() { throw new RuntimeException(e); } } + + public static void setField(@NotNull Object o, @NotNull String fieldName, @NotNull Object value) { + try { + Field field = o.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(o, value); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } } diff --git a/build.gradle.kts b/build.gradle.kts index 8991296..a644f03 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { allprojects { group = "net.azisaba.loreeditor" - version = "1.2.0" + version = "1.2.1" apply { plugin("java") diff --git a/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java b/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java index ab6a59e..b69b9b7 100644 --- a/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java +++ b/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java @@ -50,13 +50,13 @@ public PacketPreHandler(@NotNull Plugin plugin, @NotNull Player player) { public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception { // client -> server try { - if (msg.getClass().getSimpleName().contains("SetCreativeSlot")) { + if (msg.getClass().getSimpleName().contains("SetCreative")) { ServerboundSetCreativeSlot packet = ServerboundSetCreativeSlot.getInstance(msg); reverseProcessItemStack(packet.getItem()); - } else if (msg.getClass().getSimpleName().contains("WindowClick")) { + } else if (msg.getClass().getSimpleName().contains("WindowClick") || msg.getClass().getSimpleName().contains("ContainerClick")) { ServerboundClickContainerSlot packet = ServerboundClickContainerSlot.getInstance(msg); reverseProcessItemStack(packet.getItem()); - } else if (msg.getClass().getSimpleName().contains("CloseWindow")) { + } else if (msg.getClass().getSimpleName().contains("ContainerClose") || msg.getClass().getSimpleName().contains("WindowClose")) { if (player.getOpenInventory().getType() == InventoryType.MERCHANT) { // re-add lore after trading Bukkit.getScheduler().runTask(plugin, player::updateInventory); @@ -75,23 +75,28 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) if (msg.getClass().getSimpleName().contains("WindowItems") || msg.getClass().getSimpleName().contains("ContainerSetContent")) { if (player.getOpenInventory().getType() != InventoryType.MERCHANT) { ClientboundWindowItems packet = ClientboundWindowItems.getInstance(msg); - packet.getItems().forEach(i -> { + packet.setItems(packet.getItems().stream().map(ItemStack::copy).peek(i -> { PROCESS_ITEM_PERF_COUNTER.recordStart(); try { processItemStack(i); } finally { PROCESS_ITEM_PERF_COUNTER.recordEnd(); } - }); + }).collect(Collectors.toList())); } } else if (msg.getClass().getSimpleName().contains("SetSlot")) { if (player.getOpenInventory().getType() != InventoryType.MERCHANT) { ClientboundSetSlot packet = ClientboundSetSlot.getInstance(msg); - PROCESS_ITEM_PERF_COUNTER.recordStart(); - try { - processItemStack(packet.getItem()); - } finally { - PROCESS_ITEM_PERF_COUNTER.recordEnd(); + ItemStack item = packet.getItem(); + if (item != null) { + item = item.copy(); + PROCESS_ITEM_PERF_COUNTER.recordStart(); + try { + processItemStack(item); + } finally { + PROCESS_ITEM_PERF_COUNTER.recordEnd(); + } + packet.replaceItem(item); } } } @@ -102,14 +107,14 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) } public void processItemStack(@Nullable ItemStack item) { - if (item == null) return; + if (item == null || item.getCount() == 0) return; CompoundTag tag = item.getTag(); boolean hadTag = tag != null; if (tag == null) { tag = CompoundTag.getInstance(null).constructor(); } if (tag.hasKeyOfType("lore_editor", 10)) { - reverseProcessItemStack(item); + return; } CompoundTag loreEditorTag = CompoundTag.getInstance(null).constructor(); AtomicReference displayTag = new AtomicReference<>(tag.getCompound("display")); diff --git a/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundSetSlot.java b/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundSetSlot.java index 4019518..04452d4 100644 --- a/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundSetSlot.java +++ b/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundSetSlot.java @@ -12,4 +12,10 @@ public interface ClientboundSetSlot { @Nullable ItemStack getItem(); + + /** + * Replaces the item tag/component. Other properties of the item stack are not guaranteed to be preserved. + * @param item new item tag/component + */ + void replaceItem(@NotNull ItemStack item); } diff --git a/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundWindowItems.java b/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundWindowItems.java index dcee47f..0243fcb 100644 --- a/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundWindowItems.java +++ b/common/src/main/java/net/azisaba/loreeditor/common/network/packet/ClientboundWindowItems.java @@ -19,4 +19,6 @@ public interface ClientboundWindowItems { */ @NotNull List getItems(); + + void setItems(@NotNull List items); } diff --git a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundSetSlotImpl.java b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundSetSlotImpl.java index ad51a09..0a556f6 100644 --- a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundSetSlotImpl.java +++ b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundSetSlotImpl.java @@ -29,4 +29,9 @@ public ClientboundSetSlotImpl(PacketPlayOutSetSlot handle) { public @Nullable ItemStack getItem() { return ItemStackImpl.getInstance(ReflectionUtil.getField(handle, "c")); } + + @Override + public void replaceItem(@NotNull ItemStack item) { + ReflectionUtil.setField(handle, "c", ((ItemStackImpl) item).getHandle()); + } } diff --git a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundWindowItemsImpl.java b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundWindowItemsImpl.java index 53b9045..41a52ec 100644 --- a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundWindowItemsImpl.java +++ b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/network/packet/ClientboundWindowItemsImpl.java @@ -35,4 +35,13 @@ public ClientboundWindowItemsImpl(@NotNull PacketPlayOutWindowItems handle) { } return items; } + + @Override + public void setItems(@NotNull List items) { + List list = new ArrayList<>(); + for (ItemStack item : items) { + list.add(((ItemStackImpl) item).getHandle()); + } + ReflectionUtil.setField(getHandle(), "b", list); + } } diff --git a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundSetSlotImpl.java b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundSetSlotImpl.java index a6d93bc..1d1675c 100644 --- a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundSetSlotImpl.java +++ b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundSetSlotImpl.java @@ -29,4 +29,9 @@ public ClientboundSetSlotImpl(PacketPlayOutSetSlot handle) { public @Nullable ItemStack getItem() { return ItemStackImpl.getInstance(ReflectionUtil.getField(handle, "c")); } + + @Override + public void replaceItem(@NotNull ItemStack item) { + ReflectionUtil.setField(handle, "c", ((ItemStackImpl) item).getHandle()); + } } diff --git a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundWindowItemsImpl.java b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundWindowItemsImpl.java index 0f5dcf1..c7a0201 100644 --- a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundWindowItemsImpl.java +++ b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/network/packet/ClientboundWindowItemsImpl.java @@ -35,4 +35,13 @@ public ClientboundWindowItemsImpl(@NotNull PacketPlayOutWindowItems handle) { } return items; } + + @Override + public void setItems(@NotNull List items) { + List list = new ArrayList<>(); + for (ItemStack item : items) { + list.add(((ItemStackImpl) item).getHandle()); + } + ReflectionUtil.setField(getHandle(), "b", list); + } } diff --git a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundSetSlotImpl.java b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundSetSlotImpl.java index ae84233..962b940 100644 --- a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundSetSlotImpl.java +++ b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundSetSlotImpl.java @@ -29,4 +29,10 @@ public ClientboundSetSlotImpl(PacketPlayOutSetSlot handle) { public @Nullable ItemStack getItem() { return ItemStackImpl.getInstance(ReflectionUtil.getField(handle, "f")); } + + @Override + public void replaceItem(@NotNull ItemStack item) { + if (getItem() == null) throw new IllegalStateException("Cannot replace null item (for now)"); + getItem().setTag(item.getTag()); + } } diff --git a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundWindowItemsImpl.java b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundWindowItemsImpl.java index 0729ca1..b74161c 100644 --- a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundWindowItemsImpl.java +++ b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/network/packet/ClientboundWindowItemsImpl.java @@ -2,7 +2,6 @@ import net.azisaba.loreeditor.api.item.ItemStack; import net.azisaba.loreeditor.common.network.packet.ClientboundWindowItems; -import net.azisaba.loreeditor.api.util.ReflectionUtil; import net.azisaba.loreeditor.v1_19_R3.item.ItemStackImpl; import net.minecraft.network.protocol.game.PacketPlayOutWindowItems; import org.jetbrains.annotations.Contract; @@ -30,9 +29,16 @@ public ClientboundWindowItemsImpl(@NotNull PacketPlayOutWindowItems handle) { @Override public @NotNull List getItems() { List items = new ArrayList<>(); - for (Object o : ((List) ReflectionUtil.getField(getHandle(), "c"))) { + for (Object o : handle.c()) { items.add(ItemStackImpl.getInstance(o)); } return items; } + + @Override + public void setItems(@NotNull List items) { + for (int i = 0; i < items.size(); i++) { + handle.c().set(i, ((ItemStackImpl) items.get(i)).getHandle()); + } + } } diff --git a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundSetSlotImpl.java b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundSetSlotImpl.java index d1df6ea..9b0d130 100644 --- a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundSetSlotImpl.java +++ b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundSetSlotImpl.java @@ -29,4 +29,10 @@ public ClientboundSetSlotImpl(PacketPlayOutSetSlot handle) { public @Nullable ItemStack getItem() { return ItemStackImpl.getInstance(ReflectionUtil.getField(handle, "f")); } + + @Override + public void replaceItem(@NotNull ItemStack item) { + if (getItem() == null) throw new IllegalStateException("Cannot replace null item (for now)"); + getItem().setTag(item.getTag()); + } } diff --git a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundWindowItemsImpl.java b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundWindowItemsImpl.java index 181d5f4..eec9389 100644 --- a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundWindowItemsImpl.java +++ b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/packet/ClientboundWindowItemsImpl.java @@ -1,7 +1,6 @@ package net.azisaba.loreeditor.v1_20.network.packet; import net.azisaba.loreeditor.api.item.ItemStack; -import net.azisaba.loreeditor.api.util.ReflectionUtil; import net.azisaba.loreeditor.common.network.packet.ClientboundWindowItems; import net.azisaba.loreeditor.v1_20.item.ItemStackImpl; import net.minecraft.network.protocol.game.PacketPlayOutWindowItems; @@ -30,9 +29,16 @@ public ClientboundWindowItemsImpl(@NotNull PacketPlayOutWindowItems handle) { @Override public @NotNull List getItems() { List items = new ArrayList<>(); - for (Object o : ((List) ReflectionUtil.getField(getHandle(), "c"))) { + for (Object o : handle.d()) { items.add(ItemStackImpl.getInstance(o)); } return items; } + + @Override + public void setItems(@NotNull List items) { + for (int i = 0; i < items.size(); i++) { + handle.d().set(i, ((ItemStackImpl) items.get(i)).handle()); + } + } } diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java index 62e88d1..400e017 100644 --- a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java @@ -38,7 +38,7 @@ public static MutableComponent deserializeFromJson(@NotNull String input) { return net.minecraft.network.chat.Component.Serializer.fromJson(input, registries); } - public static String serializeToJson(@NotNull MutableComponent component) { + public static String serializeToJson(@NotNull net.minecraft.network.chat.Component component) { RegistryAccess registries = ((CraftServer) Bukkit.getServer()).getServer().registryAccess(); return net.minecraft.network.chat.Component.Serializer.toJson(component, registries); } diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java index 2764a90..c138f2d 100644 --- a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java @@ -7,11 +7,14 @@ import net.azisaba.loreeditor.v1_21_1.chat.ComponentImpl; import net.azisaba.loreeditor.v1_21_1.item.tag.CompoundTagImpl; import net.azisaba.loreeditor.v1_21_1.item.tag.ListTagImpl; +import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ItemLore; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,7 +48,7 @@ public ItemStackImpl(net.minecraft.world.item.ItemStack handle) { customData = CustomData.of(new net.minecraft.nbt.CompoundTag()); handle.set(DataComponents.CUSTOM_DATA, customData); } - return new CompoundTagImpl(customData.getUnsafe()); + return handleLore(new CompoundTagImpl(customData.getUnsafe())); } @SuppressWarnings("deprecation") @@ -53,9 +56,30 @@ public ItemStackImpl(net.minecraft.world.item.ItemStack handle) { public @Nullable CompoundTag getTag() { CustomData customData = handle.get(DataComponents.CUSTOM_DATA); if (customData == null) { - return null; + return handleLore(null); } - return new CompoundTagImpl(customData.getUnsafe()); + return handleLore(new CompoundTagImpl(customData.getUnsafe())); + } + + private CompoundTag handleLore(@Nullable CompoundTag base) { + var handle = new net.minecraft.nbt.ListTag(); + ListTag listTag = new ListTagImpl(handle); + if (handle().has(DataComponents.LORE)) { + Objects.requireNonNull(handle().get(DataComponents.LORE)).lines() + .forEach(component -> handle.add(StringTag.valueOf(ComponentImpl.serializeToJson(component)))); + } else { + return base; + } + if (handle.isEmpty()) { + return base; + } + if (base == null) { + base = new CompoundTagImpl(new net.minecraft.nbt.CompoundTag()); + } + CompoundTag displayTag = base.getCompound("display"); + displayTag.set("Lore", listTag); + base.set("display", displayTag); + return base; } @Override @@ -75,6 +99,8 @@ public void setTag(@Nullable CompoundTag tag) { .map(ComponentImpl::deserializeFromJson) .collect(Collectors.toUnmodifiableList()); handle.set(DataComponents.LORE, new ItemLore(lore)); + } else { + handle.remove(DataComponents.LORE); } } } @@ -86,6 +112,15 @@ public int getCount() { @Override public @NotNull ItemStack copy() { - return new ItemStackImpl(handle.copy()); + org.bukkit.inventory.ItemStack originalStack = handle.getBukkitStack(); + org.bukkit.inventory.ItemStack stack = new org.bukkit.inventory.ItemStack(originalStack.getType(), handle.getCount()); + if (originalStack.hasItemMeta()) { + stack.setItemMeta(originalStack.getItemMeta().clone()); + } + return new ItemStackImpl(CraftItemStack.asNMSCopy(stack)); + } + + public DataComponentMap getComponents() { + return handle.getComponents(); } } diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java index 02f58b2..ed8f208 100644 --- a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java @@ -28,4 +28,10 @@ public ClientboundSetSlotImpl(ClientboundContainerSetSlotPacket handle) { public @Nullable ItemStack getItem() { return ItemStackImpl.getInstance(handle.getItem()); } + + @Override + public void replaceItem(@NotNull ItemStack item) { + if (getItem() == null) throw new IllegalStateException("Cannot replace null item (for now)"); + ((ItemStackImpl) getItem()).handle().restorePatch(((ItemStackImpl) item).handle().getComponentsPatch()); + } } diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java index 4036b80..e82a059 100644 --- a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java @@ -34,4 +34,11 @@ public ClientboundWindowItemsImpl(@NotNull ClientboundContainerSetContentPacket } return items; } + + @Override + public void setItems(@NotNull List items) { + for (int i = 0; i < items.size(); i++) { + handle.getItems().set(i, ((ItemStackImpl) items.get(i)).handle()); + } + } }