Fix item nbt being reset when dragging (#206)

This commit is contained in:
IzzelAliz 2021-04-03 15:28:30 +08:00
parent c6c38b09e7
commit 9319dbc00f
3 changed files with 82 additions and 3 deletions

View File

@ -0,0 +1,8 @@
package io.izzel.arclight.common.bridge.bukkit;
import net.minecraft.item.ItemStack;
public interface CraftItemStackBridge {
ItemStack bridge$getHandle();
}

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.bukkit; package io.izzel.arclight.common.mixin.bukkit;
import io.izzel.arclight.common.bridge.bukkit.CraftItemStackBridge;
import io.izzel.arclight.common.bridge.bukkit.ItemMetaBridge; import io.izzel.arclight.common.bridge.bukkit.ItemMetaBridge;
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge; import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
import io.izzel.arclight.common.bridge.item.ItemStackBridge; import io.izzel.arclight.common.bridge.item.ItemStackBridge;
@ -10,19 +11,27 @@ import org.bukkit.Material;
import org.bukkit.craftbukkit.v.inventory.CraftItemFactory; import org.bukkit.craftbukkit.v.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v.inventory.CraftItemStack; import org.bukkit.craftbukkit.v.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v.inventory.CraftMetaItem; import org.bukkit.craftbukkit.v.inventory.CraftMetaItem;
import org.bukkit.craftbukkit.v.legacy.CraftLegacy;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
@Mixin(value = CraftItemStack.class, remap = false) @Mixin(value = CraftItemStack.class, remap = false)
public abstract class CraftItemStackMixin { public abstract class CraftItemStackMixin implements CraftItemStackBridge {
// @formatter:off // @formatter:off
@Shadow static Material getType(ItemStack item) { return null; } @Shadow static Material getType(ItemStack item) { return null; }
@Shadow static boolean hasItemMeta(ItemStack item) { return false; } @Shadow static boolean hasItemMeta(ItemStack item) { return false; }
@Shadow ItemStack handle;
@Shadow public abstract Material getType();
@Shadow public abstract short getDurability();
@Shadow public abstract boolean hasItemMeta();
// @formatter:on // @formatter:on
@Inject(method = "getItemMeta(Lnet/minecraft/item/ItemStack;)Lorg/bukkit/inventory/meta/ItemMeta;", @Inject(method = "getItemMeta(Lnet/minecraft/item/ItemStack;)Lorg/bukkit/inventory/meta/ItemMeta;",
@ -31,8 +40,14 @@ public abstract class CraftItemStackMixin {
Material type = getType(item); Material type = getType(item);
if (((MaterialBridge) (Object) type).bridge$getType() != MaterialPropertySpec.MaterialType.VANILLA) { if (((MaterialBridge) (Object) type).bridge$getType() != MaterialPropertySpec.MaterialType.VANILLA) {
if (hasItemMeta(item)) { if (hasItemMeta(item)) {
CraftMetaItem metaItem = new CraftMetaItem(item.getTag()); CompoundNBT tag = item.getTag();
((ItemMetaBridge) metaItem).bridge$offerUnhandledTags(item.getTag()); CraftMetaItem metaItem;
if (tag != null) {
metaItem = new CraftMetaItem(tag);
((ItemMetaBridge) metaItem).bridge$offerUnhandledTags(tag);
} else {
metaItem = new CraftMetaItem(new CompoundNBT());
}
((ItemMetaBridge) metaItem).bridge$setForgeCaps(((ItemStackBridge) (Object) item).bridge$getForgeCaps()); ((ItemMetaBridge) metaItem).bridge$setForgeCaps(((ItemStackBridge) (Object) item).bridge$getForgeCaps());
cir.setReturnValue(metaItem); cir.setReturnValue(metaItem);
} else { } else {
@ -49,4 +64,53 @@ public abstract class CraftItemStackMixin {
((ItemStackBridge)(Object) item).bridge$setForgeCaps(forgeCaps.copy()); ((ItemStackBridge)(Object) item).bridge$setForgeCaps(forgeCaps.copy());
} }
} }
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public boolean isSimilar(org.bukkit.inventory.ItemStack stack) {
if (stack == null) {
return false;
}
if (stack == (Object) this) {
return true;
}
if (!(stack instanceof CraftItemStack)) {
return stack.getClass() == org.bukkit.inventory.ItemStack.class && stack.isSimilar((org.bukkit.inventory.ItemStack) (Object) this);
}
CraftItemStack that = (CraftItemStack) stack;
if (handle == ((CraftItemStackBridge) (Object) that).bridge$getHandle()) {
return true;
}
if (handle == null || ((CraftItemStackBridge) (Object) that).bridge$getHandle() == null) {
return false;
}
Material comparisonType = CraftLegacy.fromLegacy(that.getType()); // This may be called from legacy item stacks, try to get the right material
if (!(comparisonType == this.getType() && getDurability() == that.getDurability())) {
return false;
}
return hasItemMeta()
? (that.hasItemMeta()
&& Objects.equals(handle.getTag(), ((CraftItemStackBridge) (Object) that).bridge$getHandle().getTag())
&& Objects.equals(((ItemStackBridge) (Object) handle).bridge$getForgeCaps(), ((ItemStackBridge) (Object) ((CraftItemStackBridge) (Object) that).bridge$getHandle()).bridge$getForgeCaps()))
: !that.hasItemMeta();
}
@Inject(method = "hasItemMeta(Lnet/minecraft/item/ItemStack;)Z", cancellable = true, at = @At("HEAD"))
private static void arclight$hasMeta(ItemStack item, CallbackInfoReturnable<Boolean> cir) {
if (item != null) {
CompoundNBT forgeCaps = ((ItemStackBridge) (Object) item).bridge$getForgeCaps();
if (forgeCaps != null && !forgeCaps.isEmpty()) {
cir.setReturnValue(true);
}
}
}
@Override
public ItemStack bridge$getHandle() {
return handle;
}
} }

View File

@ -116,6 +116,13 @@ public class CraftMetaItemMixin implements ItemMetaBridge {
return 61 * hash + (this.forgeCaps != null ? this.forgeCaps.hashCode() : 0); return 61 * hash + (this.forgeCaps != null ? this.forgeCaps.hashCode() : 0);
} }
@Inject(method = "isEmpty", cancellable = true,at = @At("HEAD"))
private void arclight$forgeCapsEmpty(CallbackInfoReturnable<Boolean> cir) {
if (this.forgeCaps != null && !this.forgeCaps.isEmpty()) {
cir.setReturnValue(false);
}
}
@Inject(method = "equalsCommon", cancellable = true, at = @At("HEAD")) @Inject(method = "equalsCommon", cancellable = true, at = @At("HEAD"))
private void arclight$forgeCapsEquals(CraftMetaItem that, CallbackInfoReturnable<Boolean> cir) { private void arclight$forgeCapsEquals(CraftMetaItem that, CallbackInfoReturnable<Boolean> cir) {
CompoundNBT forgeCaps = ((ItemMetaBridge) that).bridge$getForgeCaps(); CompoundNBT forgeCaps = ((ItemMetaBridge) that).bridge$getForgeCaps();