diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index d58b647a9..77bf0c3b9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -54,11 +54,15 @@ public class BukkitCustomItem extends AbstractCustomItem { } public Object clientItem() { - return clientItem; + return this.clientItem; } public Object item() { - return item; + return this.item; + } + + public boolean hasClientboundMaterial() { + return this.clientItem != this.item; } public static Builder builder(Object item, Object clientBoundItem) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 096c64683..94a1834bb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -125,23 +125,23 @@ public class BukkitItemManager extends AbstractItemManager { @Override public Item s2c(Item item, Player player) { if (item.isEmpty()) return item; - return this.networkItemHandler.s2c(item, player); + return this.networkItemHandler.s2c(item, player).orElse(item); } @Override public Item c2s(Item item) { if (item.isEmpty()) return item; - return this.networkItemHandler.c2s(item); + return this.networkItemHandler.c2s(item).orElse(item); } - public ItemStack s2c(ItemStack item, Player player) { - if (item.isEmpty()) return item; - return s2c(wrap(item), player).getItem(); + public Optional s2c(ItemStack item, Player player) { + if (item.isEmpty()) return Optional.empty(); + return this.networkItemHandler.s2c(wrap(item), player).map(Item::getItem); } - public ItemStack c2s(ItemStack item) { - if (item.isEmpty()) return item; - return c2s(wrap(item)).getItem(); + public Optional c2s(ItemStack item) { + if (item.isEmpty()) return Optional.empty(); + return this.networkItemHandler.c2s(wrap(item)).map(Item::getItem); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 6a5d6bab2..93cc71caa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -23,6 +23,11 @@ public class ComponentItemWrapper implements ItemWrapper { private final ItemStack item; private final Object handle; + public ComponentItemWrapper(final Object handle) { + this.handle = handle; + this.item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(handle); + } + public ComponentItemWrapper(final ItemStack item) { this.item = ItemStackUtils.ensureCraftItemStack(item); this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index 97dacdc3f..b02cb2e84 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -32,54 +32,70 @@ import java.util.function.BiConsumer; public final class LegacyNetworkItemHandler implements NetworkItemHandler { @Override - public Item c2s(Item wrapped) { + public Optional> c2s(Item wrapped) { + boolean forceReturn = false; + Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isPresent()) { BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); if (customItem.item() != FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) { wrapped = wrapped.unsafeTransmuteCopy(customItem.item(), wrapped.count()); + forceReturn = true; } } + CompoundTag networkData = (CompoundTag) wrapped.getTag(NETWORK_ITEM_TAG); - if (networkData == null) return wrapped; - wrapped.removeTag(NETWORK_ITEM_TAG); - for (Map.Entry entry : networkData.entrySet()) { - if (entry.getValue() instanceof CompoundTag tag) { - NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + if (networkData != null) { + forceReturn = true; + // 移除tag + wrapped.removeTag(NETWORK_ITEM_TAG); + // 恢复物品 + for (Map.Entry entry : networkData.entrySet()) { + if (entry.getValue() instanceof CompoundTag tag) { + NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + } } } - return wrapped; + + return forceReturn ? Optional.empty() : Optional.of(wrapped); } @Override - public Item s2c(Item wrapped, Player player) { - // todo 处理bundle和container + public Optional> s2c(Item wrapped, Player player) { + boolean forceReturn = false; + // todo 处理bundle + + // todo 处理container // todo 处理book Optional> optionalCustomItem = wrapped.getCustomItem(); // 不是自定义物品或修改过的原版物品 if (optionalCustomItem.isEmpty()) { - if (!Config.interceptItem()) return wrapped; - return new OtherItem(wrapped).process(NetworkTextReplaceContext.of(player)); + if (!Config.interceptItem()) { + return forceReturn ? Optional.of(wrapped) : Optional.empty(); + } + return new OtherItem(wrapped, forceReturn).process(NetworkTextReplaceContext.of(player)); } - // 应用client-bound-material + // 应用 client-bound-material BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); - Object serverItem = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()); - boolean hasDifferentMaterial = serverItem == customItem.item() && serverItem != customItem.clientItem(); - if (hasDifferentMaterial) { + if (customItem.hasClientboundMaterial() && FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem()) { wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count()); + forceReturn = true; } // 没有客户端侧组件 if (!customItem.hasClientBoundDataModifier()) { - if (!Config.interceptItem()) return wrapped; - return new OtherItem(wrapped).process(NetworkTextReplaceContext.of(player)); + if (!Config.interceptItem()) { + return forceReturn ? Optional.of(wrapped) : Optional.empty(); + } + return new OtherItem(wrapped, forceReturn).process(NetworkTextReplaceContext.of(player)); } // 应用client-bound-data CompoundTag tag = new CompoundTag(); + // 创建context Tag argumentTag = wrapped.getTag(ArgumentsModifier.ARGUMENTS_TAG); ItemBuildContext context; if (argumentTag instanceof CompoundTag arguments) { @@ -91,12 +107,15 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler modifier : customItem.clientBoundDataModifiers()) { modifier.prepareNetworkItem(wrapped, context, tag); } + // 应用阶段 for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.apply(wrapped, context); } + // 如果拦截物品的描述名称等 if (Config.interceptItem()) { if (!tag.containsKey("display.Name")) { processCustomName(wrapped, tag::put, context); @@ -105,10 +124,12 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler item, BiConsumer callback, Context context) { @@ -157,12 +178,14 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler item; private boolean globalChanged = false; private CompoundTag networkTag; + private final boolean forceReturn; - public OtherItem(Item item) { + public OtherItem(Item item, boolean forceReturn) { this.item = item; + this.forceReturn = forceReturn; } - public Item process(Context context) { + public Optional> process(Context context) { if (processLore(this.item, (s, c) -> networkTag().put(s, c), context)) { this.globalChanged = true; } @@ -171,8 +194,12 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler { @Override - public Item c2s(Item wrapped) { + public Optional> c2s(Item wrapped) { + boolean forceReturn = false; + + // 处理收纳袋 if (wrapped.hasComponent(ComponentTypes.BUNDLE_CONTENTS)) { Object bundleContents = wrapped.getExactComponent(ComponentTypes.BUNDLE_CONTENTS); List newItems = new ArrayList<>(); + boolean changed = false; for (Object previousItem : FastNMS.INSTANCE.method$BundleContents$items(bundleContents)) { - ItemStack itemStack = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem)); - newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack)); + Optional itemStack = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem)); + if (itemStack.isPresent()) { + newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack.get())); + changed = true; + } else { + newItems.add(previousItem); + } + } + if (changed) { + wrapped.setExactComponent(ComponentTypes.BUNDLE_CONTENTS, FastNMS.INSTANCE.constructor$BundleContents(newItems)); + forceReturn = true; } - wrapped.setExactComponent(ComponentTypes.BUNDLE_CONTENTS, FastNMS.INSTANCE.constructor$BundleContents(newItems)); } + // 处理潜影盒等 if (wrapped.hasComponent(ComponentTypes.CONTAINER)) { Object containerContents = wrapped.getExactComponent(ComponentTypes.CONTAINER); List newItems = new ArrayList<>(); + boolean changed = false; for (Object previousItem : FastNMS.INSTANCE.field$ItemContainerContents$items(containerContents)) { - ItemStack itemStack = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem)); - newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack)); + Optional itemStack = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem)); + if (itemStack.isPresent()) { + newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack.get())); + changed = true; + } else { + newItems.add(previousItem); + } + } + if (changed) { + wrapped.setExactComponent(ComponentTypes.CONTAINER, FastNMS.INSTANCE.method$ItemContainerContents$fromItems(newItems)); + forceReturn = true; } - wrapped.setExactComponent(ComponentTypes.CONTAINER, FastNMS.INSTANCE.method$ItemContainerContents$fromItems(newItems)); } // 先尝试恢复client-bound-material @@ -57,79 +79,112 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler entry : networkData.entrySet()) { + if (entry.getValue() instanceof CompoundTag tag) { + NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + } + } - // 移除此tag - compoundTag.remove(NETWORK_ITEM_TAG); - for (Map.Entry entry : networkData.entrySet()) { - if (entry.getValue() instanceof CompoundTag tag) { - NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + // 如果清空了,则直接移除这个组件 + if (compoundTag.isEmpty()) wrapped.resetComponent(ComponentTypes.CUSTOM_DATA); + // 否则设置为新的 + else wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, compoundTag); } } - if (compoundTag.isEmpty()) wrapped.resetComponent(ComponentTypes.CUSTOM_DATA); - else wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, compoundTag); - return wrapped; + return forceReturn ? Optional.of(wrapped) : Optional.empty(); } @Override - public Item s2c(Item wrapped, Player player) { + public Optional> s2c(Item wrapped, Player player) { + boolean forceReturn = false; + + // 处理收纳袋 if (wrapped.hasComponent(ComponentTypes.BUNDLE_CONTENTS)) { Object bundleContents = wrapped.getExactComponent(ComponentTypes.BUNDLE_CONTENTS); List newItems = new ArrayList<>(); + boolean changed = false; for (Object previousItem : FastNMS.INSTANCE.method$BundleContents$items(bundleContents)) { - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem), player); - newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack)); + Optional itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem), player); + if (itemStack.isPresent()) { + newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack.get())); + changed = true; + } else { + newItems.add(previousItem); + } + } + if (changed) { + wrapped.setExactComponent(ComponentTypes.BUNDLE_CONTENTS, FastNMS.INSTANCE.constructor$BundleContents(newItems)); + forceReturn = true; } - wrapped.setExactComponent(ComponentTypes.BUNDLE_CONTENTS, FastNMS.INSTANCE.constructor$BundleContents(newItems)); } + // 处理潜影盒等 if (wrapped.hasComponent(ComponentTypes.CONTAINER)) { Object containerContents = wrapped.getExactComponent(ComponentTypes.CONTAINER); List newItems = new ArrayList<>(); for (Object previousItem : FastNMS.INSTANCE.field$ItemContainerContents$items(containerContents)) { - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem), player); - newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack)); + boolean changed = false; + Optional itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(previousItem), player); + if (itemStack.isPresent()) { + newItems.add(FastNMS.INSTANCE.field$CraftItemStack$handle(itemStack.get())); + changed = true; + } else { + newItems.add(previousItem); + } + if (changed) { + wrapped.setExactComponent(ComponentTypes.CONTAINER, FastNMS.INSTANCE.method$ItemContainerContents$fromItems(newItems)); + forceReturn = true; + } } - wrapped.setExactComponent(ComponentTypes.CONTAINER, FastNMS.INSTANCE.method$ItemContainerContents$fromItems(newItems)); } // todo 处理book // 不是自定义物品或修改过的原版物品 - Item original = wrapped; Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { - if (!Config.interceptItem()) return wrapped; - return new OtherItem(wrapped).process(NetworkTextReplaceContext.of(player)); + if (!Config.interceptItem()) { + return forceReturn ? Optional.of(wrapped) : Optional.empty(); + } + return new OtherItem(wrapped, forceReturn).process(NetworkTextReplaceContext.of(player)); } - // 应用 client-bound-data BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); - Object serverItem = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()); - boolean hasDifferentMaterial = serverItem == customItem.item() && serverItem != customItem.clientItem(); - if (hasDifferentMaterial) { + // 提前复制,这和物品类型相关 + Item original = wrapped; + // 应用 client-bound-material前提是服务端侧物品类型和客户端侧的不同 + if (customItem.hasClientboundMaterial() && FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem()) { wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count()); + forceReturn = true; } + // 没有 client-bound-data if (!customItem.hasClientBoundDataModifier()) { - if (!Config.interceptItem()) return wrapped; - return new OtherItem(wrapped).process(NetworkTextReplaceContext.of(player)); + if (!Config.interceptItem()) { + return forceReturn ? Optional.of(wrapped) : Optional.empty(); + } + return new OtherItem(wrapped, forceReturn).process(NetworkTextReplaceContext.of(player)); } - CompoundTag customData = Optional.ofNullable(wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); + // 获取custom data + CompoundTag customData = Optional.ofNullable(wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)) + .map(CompoundTag.class::cast) + .orElseGet(CompoundTag::new); CompoundTag arguments = customData.getCompound(ArgumentsModifier.ARGUMENTS_TAG); + // 创建context ItemBuildContext context; if (arguments == null) { context = ItemBuildContext.of(player); @@ -140,13 +195,16 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler modifier : customItem.clientBoundDataModifiers()) { modifier.prepareNetworkItem(original, context, tag); } + // 应用阶段 for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.apply(wrapped, context); } + // 如果拦截物品的描述名称等 if (Config.interceptItem()) { if (!tag.containsKey(ComponentIds.ITEM_NAME)) { if (VersionHelper.isOrAbove1_21_5()) processModernItemName(wrapped, () -> tag, context); @@ -161,11 +219,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler tag, context); } } + // 如果tag不空,则需要返回 if (!tag.isEmpty()) { customData.put(NETWORK_ITEM_TAG, tag); wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData); + forceReturn = true; } - return wrapped; + return forceReturn ? Optional.of(wrapped) : Optional.empty(); } public static boolean processLegacyLore(Item item, Supplier tag, Context context) { @@ -274,14 +334,16 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler item; + private final boolean forceReturn; private boolean globalChanged = false; private CompoundTag tag; - public OtherItem(Item item) { + public OtherItem(Item item, boolean forceReturn) { this.item = item; + this.forceReturn = forceReturn; } - public Item process(Context context) { + public Optional> process(Context context) { if (VersionHelper.isOrAbove1_21_5()) { if (processModernLore(this.item, this::getOrCreateTag, context)) this.globalChanged = true; @@ -298,11 +360,17 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler items = new ArrayList<>(listSize); + boolean changed = false; Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); for (int i = 0; i < listSize; i++) { - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf), serverPlayer); - items.add(itemStack); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + items.add(optional.get()); + changed = true; + } else { + items.add(itemStack); + } } - ItemStack carriedItem = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf), serverPlayer); + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack newCarriedItem = carriedItem; + Optional optional = BukkitItemManager.instance().s2c(carriedItem, serverPlayer); + if (optional.isPresent()) { + changed = true; + newCarriedItem = optional.get(); + } + if (!changed) return; event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); @@ -3216,7 +3230,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes for (ItemStack itemStack : items) { FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); } - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); } } @@ -3235,18 +3249,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes try { itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); } catch (Exception e) { - // 其他插件干的,比如某ty*****er,不要赖到ce头上 + // 其他插件干的,发送了非法的物品 return; } - itemStack = BukkitItemManager.instance().s2c(itemStack, serverPlayer); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); } } @@ -3258,12 +3273,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes if (!(user instanceof BukkitServerPlayer serverPlayer)) return; FriendlyByteBuf buf = event.getBuffer(); Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf), serverPlayer); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); } } @@ -3274,7 +3291,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes if (Config.disableItemOperations()) return; if (!(user instanceof BukkitServerPlayer serverPlayer)) return; FriendlyByteBuf buf = event.getBuffer(); - + boolean changed = false; Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); int entity = buf.readVarInt(); List> slots = Lists.newArrayList(); @@ -3282,23 +3299,29 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes do { slotMask = buf.readByte(); Object equipmentSlot = CoreReflections.instance$EquipmentSlot$values[slotMask & 127]; - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf), serverPlayer); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); } while ((slotMask & -128) != 0); - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(entity); - int i = slots.size(); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (int j = 0; j < i; ++j) { - com.mojang.datafixers.util.Pair pair = slots.get(j); - Enum equipmentSlot = (Enum) pair.getFirst(); - boolean bl = j != i - 1; - int k = equipmentSlot.ordinal(); - buf.writeByte(bl ? k | -128 : k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(entity); + int i = slots.size(); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int j = 0; j < i; ++j) { + com.mojang.datafixers.util.Pair pair = slots.get(j); + Enum equipmentSlot = (Enum) pair.getFirst(); + boolean bl = j != i - 1; + int k = equipmentSlot.ordinal(); + buf.writeByte(bl ? k | -128 : k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + } } } } @@ -3312,14 +3335,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes FriendlyByteBuf buf = event.getBuffer(); int slot = buf.readVarInt(); Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf), serverPlayer); - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); } } @@ -3340,18 +3364,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } catch (Exception e) { return; } - itemStack = BukkitItemManager.instance().c2s(itemStack); - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeShort(slotNum); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - if (VersionHelper.isOrAbove1_20_5()) { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, itemStack); - } else { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); - } + BukkitItemManager.instance().c2s(itemStack).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeShort(slotNum); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + if (VersionHelper.isOrAbove1_20_5()) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); + } else { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + } + }); } } @@ -3361,7 +3385,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { if (Config.disableItemOperations()) return; FriendlyByteBuf buf = event.getBuffer(); - + boolean changed = false; Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); int containerId = buf.readContainerId(); int stateId = buf.readVarInt(); @@ -3372,27 +3396,37 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); for (int j = 0; j < i; ++j) { int k = buf.readShort(); - ItemStack itemStack = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf)); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(itemStack); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } changedSlots.put(k, itemStack); } - ItemStack carriedItem = BukkitItemManager.instance().c2s(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf)); - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slotNum); - buf.writeByte(buttonNum); - buf.writeVarInt(clickType); - buf.writeVarInt(changedSlots.size()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - changedSlots.forEach((k, v) -> { - buf.writeShort(k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); - }); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); - + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(carriedItem); + if (optional.isPresent()) { + changed = true; + carriedItem = optional.get(); + } + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slotNum); + buf.writeByte(buttonNum); + buf.writeVarInt(clickType); + buf.writeVarInt(changedSlots.size()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + changedSlots.forEach((k, v) -> { + buf.writeShort(k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); + }); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java index e1dd5d5f4..f9b57d6d3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.util.FriendlyByteBuf; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Optional; public class CommonItemPacketHandler implements EntityPacketHandler { public static final CommonItemPacketHandler INSTANCE = new CommonItemPacketHandler(); @@ -24,7 +25,7 @@ public class CommonItemPacketHandler implements EntityPacketHandler { if (Config.disableItemOperations()) return; FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); - + boolean changed = false; List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); @@ -41,16 +42,21 @@ public class CommonItemPacketHandler implements EntityPacketHandler { } continue; } - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack), user); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, user); + if (optional.isEmpty()) continue; + changed = true; + itemStack = optional.get(); Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack))); break; } - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java index bc2e99f8a..52bf764e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.util.FriendlyByteBuf; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Optional; public class ItemDisplayPacketHandler implements EntityPacketHandler { public static final ItemDisplayPacketHandler INSTANCE = new ItemDisplayPacketHandler(); @@ -20,24 +21,28 @@ public class ItemDisplayPacketHandler implements EntityPacketHandler { if (Config.disableItemOperations()) return; FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); + boolean changed = false; List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); if (entityDataId != ItemDisplayEntityData.DisplayedItem.id()) continue; Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack), user); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, user); + if (optional.isEmpty()) continue; + changed = true; + itemStack = optional.get(); Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) - )); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack))); break; } - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java index 623a11785..b413c087b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java @@ -14,16 +14,18 @@ import net.momirealms.craftengine.core.util.FriendlyByteBuf; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Optional; public class ItemFramePacketHandler implements EntityPacketHandler { public static final ItemFramePacketHandler INSTANCE = new ItemFramePacketHandler(); - private static long lastWarningTime = 0; + private static long LAST_WARN_TIME = 0; @Override public void handleSetEntityData(Player user, ByteBufPacketEvent event) { if (Config.disableItemOperations()) return; FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); + boolean changed = false; List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); @@ -32,26 +34,29 @@ public class ItemFramePacketHandler implements EntityPacketHandler { Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { long time = System.currentTimeMillis(); - if (time - lastWarningTime > 5000) { + if (time - LAST_WARN_TIME > 5000) { BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; CraftEngine.instance().logger().severe("An issue was detected while applying item-related entity data for '" + serverPlayer.name() + "'. Please execute the command '/ce debug entity-id " + serverPlayer.world().name() + " " + id + "' and provide a screenshot for further investigation."); - lastWarningTime = time; + LAST_WARN_TIME = time; } continue; } - ItemStack itemStack = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack), user); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, user); + if (optional.isEmpty()) continue; + changed = true; + itemStack = optional.get(); Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) - )); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack))); break; } - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java index 49e362233..529bd293e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java @@ -10,6 +10,7 @@ import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.Optional; public interface NetworkItemHandler { Operation[] BY_INDEX = new Operation[] {Operation.ADD, Operation.REMOVE, Operation.RESET}; @@ -17,9 +18,9 @@ public interface NetworkItemHandler { String NETWORK_OPERATION = "type"; String NETWORK_VALUE = "value"; - Item s2c(Item itemStack, Player player); + Optional> s2c(Item itemStack, Player player); - Item c2s(Item itemStack); + Optional> c2s(Item itemStack); static CompoundTag pack(Operation operation, @Nullable Tag value) { if (value == null) {