Handle forge caps in items properly (#143)
Maybe not covering all cases
This commit is contained in:
parent
3964235b8f
commit
41a70332a4
|
@ -27,3 +27,4 @@ public org/bukkit/craftbukkit/v/inventory/CraftMetaTropicalFishBucket/<init>(Lor
|
||||||
public org/bukkit/craftbukkit/v/inventory/CraftMetaCrossbow/<init>(Lorg/bukkit/craftbukkit/v/inventory/CraftMetaItem;)V
|
public org/bukkit/craftbukkit/v/inventory/CraftMetaCrossbow/<init>(Lorg/bukkit/craftbukkit/v/inventory/CraftMetaItem;)V
|
||||||
public org/bukkit/craftbukkit/v/inventory/CraftMetaSuspiciousStew/<init>(Lorg/bukkit/craftbukkit/v/inventory/CraftMetaItem;)V
|
public org/bukkit/craftbukkit/v/inventory/CraftMetaSuspiciousStew/<init>(Lorg/bukkit/craftbukkit/v/inventory/CraftMetaItem;)V
|
||||||
public org/spigotmc/ActivationRange$ActivationType/boundingBox
|
public org/spigotmc/ActivationRange$ActivationType/boundingBox
|
||||||
|
public org/bukkit/craftbukkit/v/inventory/CraftMetaItem/<init>(Lnet/minecraft/nbt/CompoundNBT;)V
|
|
@ -0,0 +1,19 @@
|
||||||
|
package io.izzel.arclight.common.bridge.bukkit;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.INBT;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ItemMetaBridge {
|
||||||
|
|
||||||
|
CompoundNBT bridge$getForgeCaps();
|
||||||
|
|
||||||
|
void bridge$setForgeCaps(CompoundNBT nbt);
|
||||||
|
|
||||||
|
void bridge$offerUnhandledTags(CompoundNBT nbt);
|
||||||
|
|
||||||
|
Map<String, INBT> bridge$getUnhandledTags();
|
||||||
|
|
||||||
|
void bridge$setUnhandledTags(Map<String, INBT> tags);
|
||||||
|
}
|
|
@ -1,6 +1,12 @@
|
||||||
package io.izzel.arclight.common.bridge.item;
|
package io.izzel.arclight.common.bridge.item;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
|
||||||
public interface ItemStackBridge {
|
public interface ItemStackBridge {
|
||||||
|
|
||||||
void bridge$convertStack(int version);
|
void bridge$convertStack(int version);
|
||||||
|
|
||||||
|
CompoundNBT bridge$getForgeCaps();
|
||||||
|
|
||||||
|
void bridge$setForgeCaps(CompoundNBT caps);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package io.izzel.arclight.common.mixin.bukkit;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.bridge.bukkit.ItemMetaBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.item.ItemStackBridge;
|
||||||
|
import io.izzel.arclight.i18n.conf.MaterialPropertySpec;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.craftbukkit.v.inventory.CraftItemFactory;
|
||||||
|
import org.bukkit.craftbukkit.v.inventory.CraftItemStack;
|
||||||
|
import org.bukkit.craftbukkit.v.inventory.CraftMetaItem;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(value = CraftItemStack.class, remap = false)
|
||||||
|
public abstract class CraftItemStackMixin {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Shadow static Material getType(ItemStack item) { return null; }
|
||||||
|
@Shadow static boolean hasItemMeta(ItemStack item) { return false; }
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Inject(method = "getItemMeta(Lnet/minecraft/item/ItemStack;)Lorg/bukkit/inventory/meta/ItemMeta;",
|
||||||
|
cancellable = true, at = @At("HEAD"))
|
||||||
|
private static void arclight$offerCaps(ItemStack item, CallbackInfoReturnable<ItemMeta> cir) {
|
||||||
|
Material type = getType(item);
|
||||||
|
if (((MaterialBridge) (Object) type).bridge$getType() != MaterialPropertySpec.MaterialType.VANILLA) {
|
||||||
|
if (hasItemMeta(item)) {
|
||||||
|
CraftMetaItem metaItem = new CraftMetaItem(item.getTag());
|
||||||
|
((ItemMetaBridge) metaItem).bridge$offerUnhandledTags(item.getTag());
|
||||||
|
((ItemMetaBridge) metaItem).bridge$setForgeCaps(((ItemStackBridge) (Object) item).bridge$getForgeCaps());
|
||||||
|
cir.setReturnValue(metaItem);
|
||||||
|
} else {
|
||||||
|
cir.setReturnValue(CraftItemFactory.instance().getItemMeta(getType(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "setItemMeta(Lnet/minecraft/item/ItemStack;Lorg/bukkit/inventory/meta/ItemMeta;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ItemStack;convertStack(I)V"))
|
||||||
|
private static void arclight$setCaps(ItemStack item, ItemMeta itemMeta, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
CompoundNBT forgeCaps = ((ItemMetaBridge) itemMeta).bridge$getForgeCaps();
|
||||||
|
if (forgeCaps != null) {
|
||||||
|
((ItemStackBridge)(Object) item).bridge$setForgeCaps(forgeCaps.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
package io.izzel.arclight.common.mixin.bukkit;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import io.izzel.arclight.common.bridge.bukkit.ItemMetaBridge;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.CompressedStreamTools;
|
||||||
|
import net.minecraft.nbt.INBT;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.bukkit.craftbukkit.v.inventory.CraftMetaItem;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mixin(value = CraftMetaItem.class, remap = false)
|
||||||
|
public class CraftMetaItemMixin implements ItemMetaBridge {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Shadow(remap = false) @Final private Map<String, INBT> unhandledTags;
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
private static final Set<String> EXTEND_TAGS = ImmutableSet.of(
|
||||||
|
"map_is_scaling",
|
||||||
|
"map",
|
||||||
|
"CustomPotionEffects",
|
||||||
|
"Potion",
|
||||||
|
"CustomPotionColor",
|
||||||
|
"SkullOwner",
|
||||||
|
"SkullProfile",
|
||||||
|
"EntityTag",
|
||||||
|
"BlockEntityTag",
|
||||||
|
"title",
|
||||||
|
"author",
|
||||||
|
"pages",
|
||||||
|
"resolved",
|
||||||
|
"generation",
|
||||||
|
"Fireworks",
|
||||||
|
"StoredEnchantments",
|
||||||
|
"Explosion",
|
||||||
|
"Recipes",
|
||||||
|
"BucketVariantTag",
|
||||||
|
"Charged",
|
||||||
|
"ChargedProjectiles",
|
||||||
|
"Effects",
|
||||||
|
"LodestoneDimension",
|
||||||
|
"LodestonePos",
|
||||||
|
"LodestoneTracked"
|
||||||
|
);
|
||||||
|
private CompoundNBT forgeCaps;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundNBT bridge$getForgeCaps() {
|
||||||
|
return this.forgeCaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setForgeCaps(CompoundNBT nbt) {
|
||||||
|
this.forgeCaps = nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$offerUnhandledTags(CompoundNBT nbt) {
|
||||||
|
if (getClass().equals(CraftMetaItem.class)) {
|
||||||
|
for (String s : nbt.keySet()) {
|
||||||
|
if (EXTEND_TAGS.contains(s)) {
|
||||||
|
this.unhandledTags.put(s, nbt.get(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, INBT> bridge$getUnhandledTags() {
|
||||||
|
return this.unhandledTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setUnhandledTags(Map<String, INBT> tags) {
|
||||||
|
this.unhandledTags.putAll(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "serialize(Lcom/google/common/collect/ImmutableMap$Builder;)Lcom/google/common/collect/ImmutableMap$Builder;", at = @At("RETURN"))
|
||||||
|
private void arclight$serializeForgeCaps(ImmutableMap.Builder<String, Object> builder, CallbackInfoReturnable<ImmutableMap.Builder<String, Object>> cir) throws IOException {
|
||||||
|
if (this.forgeCaps != null) {
|
||||||
|
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||||
|
CompressedStreamTools.writeCompressed(this.forgeCaps, buf);
|
||||||
|
builder.put("forgeCaps", Base64.encodeBase64String(buf.toByteArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "clone", locals = LocalCapture.CAPTURE_FAILHARD, at = @At("RETURN"))
|
||||||
|
private void arclight$cloneTags(CallbackInfoReturnable<CraftMetaItem> cir, CraftMetaItem clone) {
|
||||||
|
if (this.unhandledTags != null) {
|
||||||
|
((ItemMetaBridge) clone).bridge$getUnhandledTags().putAll(this.unhandledTags);
|
||||||
|
}
|
||||||
|
if (this.forgeCaps != null) {
|
||||||
|
((ItemMetaBridge) clone).bridge$setForgeCaps(this.forgeCaps.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModifyVariable(method = "applyHash", index = 1, at = @At("RETURN"))
|
||||||
|
private int arclight$applyForgeCapsHash(int hash) {
|
||||||
|
return 61 * hash + (this.forgeCaps != null ? this.forgeCaps.hashCode() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "equalsCommon", cancellable = true, at = @At("HEAD"))
|
||||||
|
private void arclight$forgeCapsEquals(CraftMetaItem that, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
CompoundNBT forgeCaps = ((ItemMetaBridge) that).bridge$getForgeCaps();
|
||||||
|
boolean ret;
|
||||||
|
if (this.forgeCaps == null) {
|
||||||
|
ret = forgeCaps != null && forgeCaps.size() != 0;
|
||||||
|
} else {
|
||||||
|
ret = forgeCaps == null ? this.forgeCaps.size() != 0 : !this.forgeCaps.equals(forgeCaps);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "<init>(Ljava/util/Map;)V", at = @At("RETURN"))
|
||||||
|
private void arclight$extractForgeCaps(Map<String, Object> map, CallbackInfo ci) {
|
||||||
|
if (map.containsKey("forgeCaps")) {
|
||||||
|
Object forgeCaps = map.get("forgeCaps");
|
||||||
|
try {
|
||||||
|
ByteArrayInputStream buf = new ByteArrayInputStream(Base64.decodeBase64(forgeCaps.toString()));
|
||||||
|
this.forgeCaps = CompressedStreamTools.readCompressed(buf);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogManager.getLogger(getClass()).error("Reading forge caps", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "<init>*", locals = LocalCapture.CAPTURE_FAILSOFT, at = @At("RETURN"))
|
||||||
|
private void arclight$copyForgeCaps(CallbackInfo ci, CraftMetaItem meta) {
|
||||||
|
CompoundNBT forgeCaps = ((ItemMetaBridge) meta).bridge$getForgeCaps();
|
||||||
|
if (forgeCaps != null) {
|
||||||
|
this.forgeCaps = forgeCaps.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import org.bukkit.event.player.PlayerCommandSendEvent;
|
||||||
import org.spigotmc.SpigotConfig;
|
import org.spigotmc.SpigotConfig;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
@ -28,12 +29,10 @@ public abstract class CommandsMixin {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@Shadow public abstract int handleCommand(CommandSource source, String command);
|
@Shadow public abstract int handleCommand(CommandSource source, String command);
|
||||||
@Shadow @Final private CommandDispatcher<CommandSource> dispatcher;
|
@Mutable @Shadow @Final private CommandDispatcher<CommandSource> dispatcher;
|
||||||
|
@Shadow protected abstract void commandSourceNodesToSuggestionNodes(CommandNode<CommandSource> rootCommandSource, CommandNode<ISuggestionProvider> rootSuggestion, CommandSource source, Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> commandNodeToSuggestionNode);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
@Shadow
|
|
||||||
protected abstract void commandSourceNodesToSuggestionNodes(CommandNode<CommandSource> rootCommandSource, CommandNode<ISuggestionProvider> rootSuggestion, CommandSource source, Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> commandNodeToSuggestionNode);
|
|
||||||
|
|
||||||
public void arclight$constructor() {
|
public void arclight$constructor() {
|
||||||
this.dispatcher = new CommandDispatcher<>();
|
this.dispatcher = new CommandDispatcher<>();
|
||||||
this.dispatcher.setConsumer((context, b, i) -> context.getSource().onCommandComplete(context, b, i));
|
this.dispatcher.setConsumer((context, b, i) -> context.getSource().onCommandComplete(context, b, i));
|
||||||
|
|
|
@ -7,6 +7,8 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityProvider;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
|
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
|
||||||
|
@ -25,13 +27,31 @@ import java.util.Random;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Mixin(ItemStack.class)
|
@Mixin(ItemStack.class)
|
||||||
public abstract class ItemStackMixin implements ItemStackBridge {
|
public abstract class ItemStackMixin extends CapabilityProvider<ItemStack> implements ItemStackBridge {
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@Shadow @Deprecated private Item item;
|
@Shadow @Deprecated private Item item;
|
||||||
@Shadow private int count;
|
@Shadow private int count;
|
||||||
|
@Shadow(remap = false) private CompoundNBT capNBT;
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
|
protected ItemStackMixin(Class<ItemStack> baseClass) {
|
||||||
|
super(baseClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundNBT bridge$getForgeCaps() {
|
||||||
|
return this.serializeCaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setForgeCaps(CompoundNBT caps) {
|
||||||
|
this.capNBT = caps;
|
||||||
|
if (caps != null) {
|
||||||
|
this.deserializeCaps(caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final Logger LOG = LogManager.getLogger("Arclight");
|
private static final Logger LOG = LogManager.getLogger("Arclight");
|
||||||
|
|
||||||
public void convertStack(int version) {
|
public void convertStack(int version) {
|
||||||
|
|
|
@ -19,9 +19,11 @@
|
||||||
"CraftHumanEntityMixin",
|
"CraftHumanEntityMixin",
|
||||||
"CraftInventoryMixin",
|
"CraftInventoryMixin",
|
||||||
"CraftItemFactoryMixin",
|
"CraftItemFactoryMixin",
|
||||||
|
"CraftItemStackMixin",
|
||||||
"CraftLegacyLegacyMixin",
|
"CraftLegacyLegacyMixin",
|
||||||
"CraftLegacyUtilMixin",
|
"CraftLegacyUtilMixin",
|
||||||
"CraftMagicNumbersMixin",
|
"CraftMagicNumbersMixin",
|
||||||
|
"CraftMetaItemMixin",
|
||||||
"CraftServerMixin",
|
"CraftServerMixin",
|
||||||
"CraftVillagerMixin",
|
"CraftVillagerMixin",
|
||||||
"CraftWorldMixin",
|
"CraftWorldMixin",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user