Closed CalenXwX closed 9 months ago
参考net.minecraft.world.item.ItemStack类的 copy() 方法:
... ItemStack itemstack = new ItemStack(this.getItem(), this.count, this.serializeCaps()); ...
在创建新ItemStack对象时,调用 this.serializeCaps() 获取了带有ForgeCaps的完整NBT,而在ItemStack的serializeCaps()方法(继承自 net.minecraftforge.common.capabilities.CapabilityProvider )中,
CapabilityDispatcher disp = this.getCapabilities(); return disp != null ? disp.serializeNBT() : null;
使用 getCapabilities() 方法获取到当前ItemStack的capabilities。 在getCapabilities()方法中,若当前ItemStack未被初始化,则下调用了 this.doGatherCapabilities 方法生成 this.capabilities 属性: this.capabilities = ForgeEventFactory.gatherCapabilities(this.baseClass, this.getProvider(), parent); CatServer-1.18.2-6c3f5965版本中,CatForgeItemCap::setItemCap方法直接读取 nmsItemStack 的 capabilities 属性:
this.capabilities = ForgeEventFactory.gatherCapabilities(this.baseClass, this.getProvider(), parent);
... if (nmsItemStack != null && nmsItemStack.capabilities != null) { CompoundTag capNBT = nmsItemStack.capabilities.serializeNBT(); ...
若nmsItemStack未被初始化,则获取到的capabilities为null,会导致ForgeCaps无法被写入bukkitItemStack。 当玩家打开背包、取出物品并放回时,在某些情况下会调用AbstractContainerMenu类中的m_150430_方法(doClick),在执行其中CatServer插入的代码 org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack3); 时触发这一问题,并在随后向客户端发送更新整个背包所有物品的数据包,导致玩家拿起的物品的所有ForgeCaps丢失,拔刀剑的属性被重置,变为ForgeCaps中多个关键Tag为空的“无名”。
org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack3);
DispenseItemBehavior dispenseitembehavior = this.m_7216_(itemstack);
dispenserblockentity.m_6836_(i, dispenseitembehavior.m_6115_(blocksourceimpl, itemstack));
ItemStack itemstack = this.m_7498_(p_123391_, p_123392_);
+ p_123562_.setItem(Items.f_42446_);
+ // CraftBukkit start + @Deprecated + public void setItem(Item item) { + this.f_41589_ = item; + } + // CraftBukkit end
此方法只修改了this.item属性(f41589),没有修改this.delegate属性,此水桶仍可放出水。 参考ItemStack类的构造方法: this.delegate = p_41604_ == null ? null : p_41604_.m_5456_().delegate; 按照ItemLike的delegate属性设置了ItemStack的delegate属性。 ItemStack类的getItem()方法: return !this.f_41591_ && this.delegate != null ? (Item)this.delegate.get() : Items.f_41852_; 获取的是delegate的物品。
this.delegate = p_41604_ == null ? null : p_41604_.m_5456_().delegate;
return !this.f_41591_ && this.delegate != null ? (Item)this.delegate.get() : Items.f_41852_;
很棒!看起来这修复了一个历史性遗留问题。
ItemStack#setItem方法中delegate赋值需要换行以保持代码可读性 这看起来可以被合并。
参考net.minecraft.world.item.ItemStack类的 copy() 方法:
在创建新ItemStack对象时,调用 this.serializeCaps() 获取了带有ForgeCaps的完整NBT,而在ItemStack的serializeCaps()方法(继承自 net.minecraftforge.common.capabilities.CapabilityProvider )中,
使用 getCapabilities() 方法获取到当前ItemStack的capabilities。 在getCapabilities()方法中,若当前ItemStack未被初始化,则下调用了 this.doGatherCapabilities 方法生成 this.capabilities 属性:
this.capabilities = ForgeEventFactory.gatherCapabilities(this.baseClass, this.getProvider(), parent);
CatServer-1.18.2-6c3f5965版本中,CatForgeItemCap::setItemCap方法直接读取 nmsItemStack 的 capabilities 属性:若nmsItemStack未被初始化,则获取到的capabilities为null,会导致ForgeCaps无法被写入bukkitItemStack。 当玩家打开背包、取出物品并放回时,在某些情况下会调用AbstractContainerMenu类中的m_150430_方法(doClick),在执行其中CatServer插入的代码
org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack3);
时触发这一问题,并在随后向客户端发送更新整个背包所有物品的数据包,导致玩家拿起的物品的所有ForgeCaps丢失,拔刀剑的属性被重置,变为ForgeCaps中多个关键Tag为空的“无名”。DispenseItemBehavior dispenseitembehavior = this.m_7216_(itemstack);
获取了水桶的DispenseItemBehavior,并在dispenserblockentity.m_6836_(i, dispenseitembehavior.m_6115_(blocksourceimpl, itemstack));
执行了DefaultDispenseItemBehavior类的的dispense(...)方法(m6115),在dispense(...)方法中ItemStack itemstack = this.m_7498_(p_123391_, p_123392_);
调用了水桶的DispenseItemBehavior类(net.minecraft.core.dispenser.DispenseItemBehavior$16)的m7498(...)方法(execute),执行此方法时出现了问题。 DispenseItemBehavior$16定义在DispenseItemBehavior.java.patch文件的第350行起的部分。 其中第394行+ p_123562_.setItem(Items.f_42446_);
调用CatServer在ItemStack类中插入的setItem方法修改了ItemStack中的物品此方法只修改了this.item属性(f41589),没有修改this.delegate属性,此水桶仍可放出水。 参考ItemStack类的构造方法:
this.delegate = p_41604_ == null ? null : p_41604_.m_5456_().delegate;
按照ItemLike的delegate属性设置了ItemStack的delegate属性。 ItemStack类的getItem()方法:return !this.f_41591_ && this.delegate != null ? (Item)this.delegate.get() : Items.f_41852_;
获取的是delegate的物品。