31699ae9a8
* Updated Upstream (Bukkit/CraftBukkit) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: a6a9d2a4 Remove some old ApiStatus.Experimental annotations be72314c SPIGOT-7300, PR-829: Add new DamageSource API providing enhanced information about entity damage b252cf05 SPIGOT-7576, PR-970: Add methods in MushroomCow to change stew effects b1c689bd PR-902: Add Server#isLoggingIPs to get log-ips configuration 08f86d1c PR-971: Add Player methods for client-side potion effects 2e3024a9 PR-963: Add API for in-world structures a23292a7 SPIGOT-7530, PR-948: Improve Resource Pack API with new 1.20.3 functionality 1851857b SPIGOT-3071, PR-969: Add entity spawn method with spawn reason cde4c52a SPIGOT-5553, PR-964: Add EntityKnockbackEvent CraftBukkit Changes: 38fd4bd50 Fix accidentally renamed internal damage method 80f0ce4be SPIGOT-7300, PR-1180: Add new DamageSource API providing enhanced information about entity damage 7e43f3b16 SPIGOT-7581: Fix typo in BlockMushroom ea14b7d90 SPIGOT-7576, PR-1347: Add methods in MushroomCow to change stew effects 4c687f243 PR-1259: Add Server#isLoggingIPs to get log-ips configuration 22a541a29 Improve support for per-world game rules cb7dccce2 PR-1348: Add Player methods for client-side potion effects b8d6109f0 PR-1335: Add API for in-world structures 4398a1b5b SPIGOT-7577: Make CraftWindCharge#explode discard the entity e74107678 Fix Crafter maximum stack size 0bb0f4f6a SPIGOT-7530, PR-1314: Improve Resource Pack API with new 1.20.3 functionality 4949f556d SPIGOT-3071, PR-1345: Add entity spawn method with spawn reason 20ac73ca2 PR-1353: Fix Structure#place not working as documented with 0 palette 3c1b77871 SPIGOT-6911, PR-1349: Change max book length in CraftMetaBook 333701839 SPIGOT-7572: Bee nests generated without bees f48f4174c SPIGOT-5553, PR-1336: Add EntityKnockbackEvent
307 Zeilen
14 KiB
Diff
307 Zeilen
14 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Thu, 28 May 2015 23:00:19 -0400
|
|
Subject: [PATCH] Handle Item Meta Inconsistencies
|
|
|
|
First, Enchantment order would blow away seeing 2 items as the same,
|
|
however the Client forces enchantment list in a certain order, as well
|
|
as does the /enchant command. Anvils can insert it into forced order,
|
|
causing 2 same items to be considered different.
|
|
|
|
This change makes unhandled NBT Tags and Enchantments use a sorted tree map,
|
|
so they will always be in a consistent order.
|
|
|
|
Additionally, the old enchantment API was never updated when ItemMeta
|
|
was added, resulting in 2 different ways to modify an items enchantments.
|
|
|
|
For consistency, the old API methods now forward to use the
|
|
ItemMeta API equivalents, and should deprecate the old API's.
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
index 6291265ae4691bf7dffe196d20571c1c30e8d906..70511628eefc28163d07f50f18d9cc55dd93d68b 100644
|
|
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
|
@@ -181,6 +181,23 @@ public final class ItemStack {
|
|
return this.getItem().getTooltipImage(this);
|
|
}
|
|
|
|
+ // Paper start
|
|
+ private static final java.util.Comparator<? super CompoundTag> enchantSorter = java.util.Comparator.comparing(o -> o.getString("id"));
|
|
+ private void processEnchantOrder(@Nullable CompoundTag tag) {
|
|
+ if (tag == null || !tag.contains("Enchantments", net.minecraft.nbt.Tag.TAG_LIST)) {
|
|
+ return;
|
|
+ }
|
|
+ ListTag list = tag.getList("Enchantments", net.minecraft.nbt.Tag.TAG_COMPOUND);
|
|
+ if (list.size() < 2) {
|
|
+ return;
|
|
+ }
|
|
+ try {
|
|
+ //noinspection unchecked
|
|
+ list.sort((java.util.Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
|
|
+ } catch (Exception ignored) {}
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
public ItemStack(ItemLike item) {
|
|
this(item, 1);
|
|
}
|
|
@@ -227,6 +244,7 @@ public final class ItemStack {
|
|
this.count = nbttagcompound.getByte("Count");
|
|
if (nbttagcompound.contains("tag", 10)) {
|
|
this.tag = nbttagcompound.getCompound("tag").copy();
|
|
+ this.processEnchantOrder(this.tag); // Paper
|
|
this.getItem().verifyTagAfterLoad(this.tag);
|
|
}
|
|
|
|
@@ -846,6 +864,7 @@ public final class ItemStack {
|
|
|
|
public void setTag(@Nullable CompoundTag nbt) {
|
|
this.tag = nbt;
|
|
+ this.processEnchantOrder(this.tag); // Paper
|
|
if (this.getItem().canBeDepleted()) {
|
|
this.setDamageValue(this.getDamageValue());
|
|
}
|
|
@@ -1143,6 +1162,7 @@ public final class ItemStack {
|
|
ListTag nbttaglist = this.tag.getList("Enchantments", 10);
|
|
|
|
nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) level));
|
|
+ processEnchantOrder(this.tag); // Paper
|
|
}
|
|
|
|
public boolean isEnchanted() {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
index 23b83f8e98d681895b4e23cda4f3d50f85c12dd9..c72a1a503f6e71228a1f82b37068ff7a83e983dc 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
|
|
@@ -188,28 +188,11 @@ public final class CraftItemStack extends ItemStack {
|
|
public void addUnsafeEnchantment(Enchantment ench, int level) {
|
|
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
|
|
|
- if (!CraftItemStack.makeTag(this.handle)) {
|
|
- return;
|
|
- }
|
|
- ListTag list = CraftItemStack.getEnchantmentList(this.handle);
|
|
- if (list == null) {
|
|
- list = new ListTag();
|
|
- this.handle.getTag().put(ENCHANTMENTS.NBT, list);
|
|
- }
|
|
- int size = list.size();
|
|
-
|
|
- for (int i = 0; i < size; i++) {
|
|
- CompoundTag tag = (CompoundTag) list.get(i);
|
|
- String id = tag.getString(ENCHANTMENTS_ID.NBT);
|
|
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
|
|
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
|
|
- return;
|
|
- }
|
|
- }
|
|
- CompoundTag tag = new CompoundTag();
|
|
- tag.putString(ENCHANTMENTS_ID.NBT, ench.getKey().toString());
|
|
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
|
|
- list.add(tag);
|
|
+ // Paper start - Replace whole method
|
|
+ final ItemMeta itemMeta = this.getItemMeta();
|
|
+ itemMeta.addEnchant(ench, level, true);
|
|
+ this.setItemMeta(itemMeta);
|
|
+ // Paper end
|
|
}
|
|
|
|
static boolean makeTag(net.minecraft.world.item.ItemStack item) {
|
|
@@ -242,43 +225,15 @@ public final class CraftItemStack extends ItemStack {
|
|
public int removeEnchantment(Enchantment ench) {
|
|
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
|
|
|
- ListTag list = CraftItemStack.getEnchantmentList(this.handle), listCopy;
|
|
- if (list == null) {
|
|
- return 0;
|
|
- }
|
|
- int index = Integer.MIN_VALUE;
|
|
- int level = Integer.MIN_VALUE;
|
|
- int size = list.size();
|
|
-
|
|
- for (int i = 0; i < size; i++) {
|
|
- CompoundTag enchantment = (CompoundTag) list.get(i);
|
|
- String id = enchantment.getString(ENCHANTMENTS_ID.NBT);
|
|
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
|
|
- index = i;
|
|
- level = 0xffff & enchantment.getShort(ENCHANTMENTS_LVL.NBT);
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (index == Integer.MIN_VALUE) {
|
|
- return 0;
|
|
- }
|
|
- if (size == 1) {
|
|
- this.handle.getTag().remove(ENCHANTMENTS.NBT);
|
|
- if (this.handle.getTag().isEmpty()) {
|
|
- this.handle.setTag(null);
|
|
- }
|
|
- return level;
|
|
- }
|
|
-
|
|
- // This is workaround for not having an index removal
|
|
- listCopy = new ListTag();
|
|
- for (int i = 0; i < size; i++) {
|
|
- if (i != index) {
|
|
- listCopy.add(list.get(i));
|
|
- }
|
|
+ // Paper start - replace entire method
|
|
+ int level = getEnchantmentLevel(ench);
|
|
+ if (level > 0) {
|
|
+ final ItemMeta itemMeta = this.getItemMeta();
|
|
+ if (itemMeta == null) return 0;
|
|
+ itemMeta.removeEnchant(ench);
|
|
+ this.setItemMeta(itemMeta);
|
|
}
|
|
- this.handle.getTag().put(ENCHANTMENTS.NBT, listCopy);
|
|
+ // Paper end
|
|
|
|
return level;
|
|
}
|
|
@@ -290,7 +245,7 @@ public final class CraftItemStack extends ItemStack {
|
|
|
|
@Override
|
|
public Map<Enchantment, Integer> getEnchantments() {
|
|
- return CraftItemStack.getEnchantments(this.handle);
|
|
+ return this.hasItemMeta() ? this.getItemMeta().getEnchants() : ImmutableMap.<Enchantment, Integer>of(); // Paper - use Item Meta
|
|
}
|
|
|
|
static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
|
index ffdea312f93d00289364ef4d41a820cd1338f3bd..361268bcc0197c2f9f4bd065d8f7b51771d562a9 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
|
@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.ImmutableMultimap;
|
|
import com.google.common.collect.LinkedHashMultimap;
|
|
+import com.google.common.collect.ImmutableSortedMap; // Paper
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Multimap;
|
|
import com.google.common.collect.SetMultimap;
|
|
@@ -23,6 +24,7 @@ import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Base64;
|
|
import java.util.Collection;
|
|
+import java.util.Comparator; // Paper
|
|
import java.util.EnumSet;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
@@ -33,6 +35,7 @@ import java.util.Map;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
+import java.util.TreeMap; // Paper
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.annotation.Nonnull;
|
|
@@ -277,7 +280,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
private List<String> lore; // null and empty are two different states internally
|
|
private Integer customModelData;
|
|
private CompoundTag blockData;
|
|
- private Map<Enchantment, Integer> enchantments;
|
|
+ private EnchantmentMap enchantments; // Paper
|
|
private Multimap<Attribute, AttributeModifier> attributeModifiers;
|
|
private int repairCost;
|
|
private int hideFlag;
|
|
@@ -288,7 +291,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
|
|
|
private CompoundTag internalTag;
|
|
- final Map<String, Tag> unhandledTags = new HashMap<String, Tag>(); // Visible for testing only
|
|
+ final Map<String, Tag> unhandledTags = new TreeMap<String, Tag>(); // Visible for testing only // Paper
|
|
private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftMetaItem.DATA_TYPE_REGISTRY);
|
|
|
|
private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only
|
|
@@ -309,7 +312,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
this.blockData = meta.blockData;
|
|
|
|
if (meta.enchantments != null) {
|
|
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(meta.enchantments);
|
|
+ this.enchantments = new EnchantmentMap(meta.enchantments); // Paper
|
|
}
|
|
|
|
if (meta.hasAttributeModifiers()) {
|
|
@@ -392,13 +395,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
}
|
|
}
|
|
|
|
- static Map<Enchantment, Integer> buildEnchantments(CompoundTag tag, ItemMetaKey key) {
|
|
+ static EnchantmentMap buildEnchantments(CompoundTag tag, ItemMetaKey key) { // Paper
|
|
if (!tag.contains(key.NBT)) {
|
|
return null;
|
|
}
|
|
|
|
ListTag ench = tag.getList(key.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND);
|
|
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
|
|
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
|
|
|
for (int i = 0; i < ench.size(); i++) {
|
|
String id = ((CompoundTag) ench.get(i)).getString(CraftMetaItem.ENCHANTMENTS_ID.NBT);
|
|
@@ -551,13 +554,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
}
|
|
}
|
|
|
|
- static Map<Enchantment, Integer> buildEnchantments(Map<String, Object> map, ItemMetaKey key) {
|
|
+ static EnchantmentMap buildEnchantments(Map<String, Object> map, ItemMetaKey key) { // Paper
|
|
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true);
|
|
if (ench == null) {
|
|
return null;
|
|
}
|
|
|
|
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
|
|
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
|
|
for (Map.Entry<?, ?> entry : ench.entrySet()) {
|
|
// Doctor older enchants
|
|
String enchantKey = entry.getKey().toString();
|
|
@@ -845,14 +848,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
|
|
@Override
|
|
public Map<Enchantment, Integer> getEnchants() {
|
|
- return this.hasEnchants() ? ImmutableMap.copyOf(this.enchantments) : ImmutableMap.<Enchantment, Integer>of();
|
|
+ return this.hasEnchants() ? ImmutableSortedMap.copyOfSorted(this.enchantments) : ImmutableMap.<Enchantment, Integer>of(); // Paper
|
|
}
|
|
|
|
@Override
|
|
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
|
|
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
|
|
if (this.enchantments == null) {
|
|
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(4);
|
|
+ this.enchantments = new EnchantmentMap(); // Paper
|
|
}
|
|
|
|
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
|
|
@@ -1269,7 +1272,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
clone.customModelData = this.customModelData;
|
|
clone.blockData = this.blockData;
|
|
if (this.enchantments != null) {
|
|
- clone.enchantments = new LinkedHashMap<Enchantment, Integer>(this.enchantments);
|
|
+ clone.enchantments = new EnchantmentMap(this.enchantments); // Paper
|
|
}
|
|
if (this.hasAttributeModifiers()) {
|
|
clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers);
|
|
@@ -1516,4 +1519,22 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
|
return CraftMetaItem.HANDLED_TAGS;
|
|
}
|
|
}
|
|
+
|
|
+ // Paper start
|
|
+ private static class EnchantmentMap extends TreeMap<Enchantment, Integer> {
|
|
+ private EnchantmentMap(Map<Enchantment, Integer> enchantments) {
|
|
+ this();
|
|
+ putAll(enchantments);
|
|
+ }
|
|
+
|
|
+ private EnchantmentMap() {
|
|
+ super(Comparator.comparing(o -> o.getKey().toString()));
|
|
+ }
|
|
+
|
|
+ public EnchantmentMap clone() {
|
|
+ return (EnchantmentMap) super.clone();
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
}
|