From 58ea3b7ca55a44f21e81560ba07ade06ec8af60f Mon Sep 17 00:00:00 2001 From: Racci <90304606+DaRacci@users.noreply.github.com> Date: Mon, 27 Dec 2021 08:39:11 +1100 Subject: [PATCH] Add Potion NamespacedKey Patches (#783) --- patches/api/0042-Potion-NamespacedKey.patch | 213 +++++++++++++ .../server/0246-Potion-NamespacedKey.patch | 298 ++++++++++++++++++ 2 files changed, 511 insertions(+) create mode 100644 patches/api/0042-Potion-NamespacedKey.patch create mode 100644 patches/server/0246-Potion-NamespacedKey.patch diff --git a/patches/api/0042-Potion-NamespacedKey.patch b/patches/api/0042-Potion-NamespacedKey.patch new file mode 100644 index 000000000..97873f4d0 --- /dev/null +++ b/patches/api/0042-Potion-NamespacedKey.patch @@ -0,0 +1,213 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Racci +Date: Fri, 3 Dec 2021 23:48:26 +1100 +Subject: [PATCH] Potion NamespacedKey + + +diff --git a/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java +index 74767751199bce03d63f2a9524712656193f850c..52a31aa6d77e6c9afac78e76829d0265e903b029 100644 +--- a/src/main/java/org/bukkit/potion/PotionEffect.java ++++ b/src/main/java/org/bukkit/potion/PotionEffect.java +@@ -5,6 +5,7 @@ import java.util.Map; + import java.util.NoSuchElementException; + import org.apache.commons.lang.Validate; + import org.bukkit.Color; ++import org.bukkit.NamespacedKey; + import org.bukkit.configuration.serialization.ConfigurationSerializable; + import org.bukkit.configuration.serialization.SerializableAs; + import org.bukkit.entity.LivingEntity; +@@ -26,12 +27,14 @@ public class PotionEffect implements ConfigurationSerializable { + private static final String AMBIENT = "ambient"; + private static final String PARTICLES = "has-particles"; + private static final String ICON = "has-icon"; ++ private static final String KEY = "namespacedKey"; // Purpur + private final int amplifier; + private final int duration; + private final PotionEffectType type; + private final boolean ambient; + private final boolean particles; + private final boolean icon; ++ @Nullable private final NamespacedKey key; // Purpur + + /** + * Creates a potion effect. +@@ -44,6 +47,36 @@ public class PotionEffect implements ConfigurationSerializable { + * @param icon the icon status, see {@link PotionEffect#hasIcon()} + */ + public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon) { ++ // Purpur start ++ this(type, duration, amplifier, ambient, particles, icon, null); ++ } ++ ++ /** ++ * Create a potion effect. ++ * @param duration measured in ticks, see {@link ++ * PotionEffect#getDuration()} ++ * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} ++ * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} ++ * @param particles the particle status, see {@link PotionEffect#hasParticles()} ++ * @param key the namespacedKey, see {@link PotionEffect#getKey()} ++ */ ++ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, @Nullable NamespacedKey key) { ++ this(type, duration, amplifier, ambient, particles, particles, key); ++ } ++ ++ /** ++ * Creates a potion effect. ++ * @param type effect type ++ * @param duration measured in ticks, see {@link ++ * PotionEffect#getDuration()} ++ * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} ++ * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} ++ * @param particles the particle status, see {@link PotionEffect#hasParticles()} ++ * @param icon the icon status, see {@link PotionEffect#hasIcon()} ++ * @param key the namespacedKey, see {@link PotionEffect#getKey()} ++ */ ++ public PotionEffect(@NotNull PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles, boolean icon, @Nullable NamespacedKey key) { ++ // Purpur end + Validate.notNull(type, "effect type cannot be null"); + this.type = type; + this.duration = duration; +@@ -51,6 +84,7 @@ public class PotionEffect implements ConfigurationSerializable { + this.ambient = ambient; + this.particles = particles; + this.icon = icon; ++ this.key = key; // Purpur - add key + } + + /** +@@ -98,36 +132,43 @@ public class PotionEffect implements ConfigurationSerializable { + * @param map the map to deserialize from + */ + public PotionEffect(@NotNull Map map) { +- this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true))); ++ this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT, false), getBool(map, PARTICLES, true), getBool(map, ICON, getBool(map, PARTICLES, true)), getKey(map)); // Purpur - getKey + } + + // Paper start + @NotNull + public PotionEffect withType(@NotNull PotionEffectType type) { +- return new PotionEffect(type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + @NotNull + public PotionEffect withDuration(int duration) { +- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + @NotNull + public PotionEffect withAmplifier(int amplifier) { +- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + @NotNull + public PotionEffect withAmbient(boolean ambient) { +- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + @NotNull + public PotionEffect withParticles(boolean particles) { +- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + @NotNull + public PotionEffect withIcon(boolean icon) { +- return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon); ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); // Purpur - add key + } + // Paper end + ++ // Purpur start ++ @NotNull ++ public PotionEffect withKey(@Nullable NamespacedKey key) { ++ return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon, key); ++ } ++ // Purpur end ++ + @NotNull + private static PotionEffectType getEffectType(@NotNull Map map) { + int type = getInt(map, TYPE); +@@ -154,17 +195,33 @@ public class PotionEffect implements ConfigurationSerializable { + return def; + } + ++ // Purpur start ++ @Nullable ++ private static NamespacedKey getKey(@NotNull Map map) { ++ Object key = map.get(KEY); ++ if (key instanceof String stringKey) { ++ return NamespacedKey.fromString(stringKey); ++ } ++ return null; ++ } ++ // Purpur end ++ + @Override + @NotNull + public Map serialize() { +- return ImmutableMap.builder() +- .put(TYPE, type.getId()) +- .put(DURATION, duration) +- .put(AMPLIFIER, amplifier) +- .put(AMBIENT, ambient) +- .put(PARTICLES, particles) +- .put(ICON, icon) +- .build(); ++ // Purpur start - add key, don't serialize if null. ++ ImmutableMap.Builder builder = ImmutableMap.builder() ++ .put(TYPE, type.getId()) ++ .put(DURATION, duration) ++ .put(AMPLIFIER, amplifier) ++ .put(AMBIENT, ambient) ++ .put(PARTICLES, particles) ++ .put(ICON, icon); ++ if(key != null) { ++ builder.put(KEY, key.toString()); ++ } ++ return builder.build(); ++ // Purpur end + } + + /** +@@ -188,7 +245,7 @@ public class PotionEffect implements ConfigurationSerializable { + return false; + } + PotionEffect that = (PotionEffect) obj; +- return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon; ++ return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration && this.particles == that.particles && this.icon == that.icon && this.key == that.key; // Purpur - add key + } + + /** +@@ -256,6 +313,24 @@ public class PotionEffect implements ConfigurationSerializable { + return icon; + } + ++ ++ // Purpur start ++ /** ++ * @return if the key isn't the default namespacedKey ++ */ ++ public boolean hasKey() { ++ return key != null; ++ } ++ ++ /** ++ * @return the key attached to the potion ++ */ ++ @Nullable ++ public NamespacedKey getKey() { ++ return key; ++ } ++ // Purpur end ++ + @Override + public int hashCode() { + int hash = 1; +@@ -270,6 +345,6 @@ public class PotionEffect implements ConfigurationSerializable { + + @Override + public String toString() { +- return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : ""); ++ return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : "") + (hasKey() ? "(" + key + ")" : ""); // Purpur - add key if not null + } + } diff --git a/patches/server/0246-Potion-NamespacedKey.patch b/patches/server/0246-Potion-NamespacedKey.patch new file mode 100644 index 000000000..9df879bff --- /dev/null +++ b/patches/server/0246-Potion-NamespacedKey.patch @@ -0,0 +1,298 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Racci +Date: Sat, 4 Dec 2021 00:07:05 +1100 +Subject: [PATCH] Potion NamespacedKey + + +diff --git a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java +index 0dadea0c9559d99c7de04dbda68b3e743c9eeecb..6827d71965aa122c1f30bc49c04e0b0065c1d8ec 100644 +--- a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java ++++ b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java +@@ -6,6 +6,7 @@ import net.minecraft.nbt.CompoundTag; + import net.minecraft.world.entity.LivingEntity; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; ++import org.bukkit.NamespacedKey; + + public class MobEffectInstance implements Comparable { + private static final Logger LOGGER = LogManager.getLogger(); +@@ -17,6 +18,7 @@ public class MobEffectInstance implements Comparable { + private boolean visible; + private boolean showIcon; + @Nullable ++ private NamespacedKey key; // Purpur - add key + private MobEffectInstance hiddenEffect; + + public MobEffectInstance(MobEffect type) { +@@ -40,12 +42,27 @@ public class MobEffectInstance implements Comparable { + } + + public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon, @Nullable MobEffectInstance hiddenEffect) { ++ // Purpur start ++ this(type, duration, amplifier, ambient, showParticles, showIcon, (NamespacedKey)null, hiddenEffect); ++ } ++ ++ public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, @Nullable NamespacedKey key) { ++ this(type, duration, amplifier, ambient, showParticles, showParticles, key, (MobEffectInstance)null); ++ } ++ ++ public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon, @Nullable NamespacedKey key) { ++ this(type, duration, amplifier, ambient, showParticles, showIcon, key, (MobEffectInstance)null); ++ } ++ ++ public MobEffectInstance(MobEffect type, int duration, int amplifier, boolean ambient, boolean showParticles, boolean showIcon, @Nullable NamespacedKey key, @Nullable MobEffectInstance hiddenEffect) { // Purpur - add key ++ // Purpur end + this.effect = type; + this.duration = duration; + this.amplifier = amplifier; + this.ambient = ambient; + this.visible = showParticles; + this.showIcon = showIcon; ++ this.key = key; // Purpur - add key + this.hiddenEffect = hiddenEffect; + } + +@@ -60,6 +77,7 @@ public class MobEffectInstance implements Comparable { + this.ambient = that.ambient; + this.visible = that.visible; + this.showIcon = that.showIcon; ++ this.key = that.key; // Purpur - add key + } + + public boolean update(MobEffectInstance that) { +@@ -104,6 +122,13 @@ public class MobEffectInstance implements Comparable { + bl = true; + } + ++ // Purpur start ++ if (that.key != this.key) { ++ this.key = that.key; ++ bl = true; ++ } ++ // Purpur end ++ + return bl; + } + +@@ -131,6 +156,17 @@ public class MobEffectInstance implements Comparable { + return this.showIcon; + } + ++ // Purpur start ++ public boolean hasKey() { ++ return this.key != null; ++ } ++ ++ @Nullable ++ public NamespacedKey getKey() { ++ return this.key; ++ } ++ // Purpur end ++ + public boolean tick(LivingEntity entity, Runnable overwriteCallback) { + if (this.duration > 0) { + if (this.effect.isDurationEffectTick(this.duration, this.amplifier)) { +@@ -184,6 +220,12 @@ public class MobEffectInstance implements Comparable { + string = string + ", Show Icon: false"; + } + ++ // Purpur start ++ if (this.hasKey()) { ++ string = string + ", Key: " + this.key; ++ } ++ // Purpur end ++ + return string; + } + +@@ -195,7 +237,7 @@ public class MobEffectInstance implements Comparable { + return false; + } else { + MobEffectInstance mobEffectInstance = (MobEffectInstance)object; +- return this.duration == mobEffectInstance.duration && this.amplifier == mobEffectInstance.amplifier && this.ambient == mobEffectInstance.ambient && this.effect.equals(mobEffectInstance.effect); ++ return this.duration == mobEffectInstance.duration && this.amplifier == mobEffectInstance.amplifier && this.ambient == mobEffectInstance.ambient && this.effect.equals(mobEffectInstance.effect) && this.key == mobEffectInstance.key; // Purpur - add key + } + } + +@@ -219,6 +261,11 @@ public class MobEffectInstance implements Comparable { + nbt.putBoolean("Ambient", this.isAmbient()); + nbt.putBoolean("ShowParticles", this.isVisible()); + nbt.putBoolean("ShowIcon", this.showIcon()); ++ // Purpur start ++ if (this.key != null) { ++ nbt.putString("Key", this.key.toString()); ++ } ++ // Purpur end + if (this.hiddenEffect != null) { + CompoundTag compoundTag = new CompoundTag(); + this.hiddenEffect.save(compoundTag); +@@ -248,12 +295,19 @@ public class MobEffectInstance implements Comparable { + bl3 = nbt.getBoolean("ShowIcon"); + } + ++ // Purpur start ++ NamespacedKey key = null; ++ if (nbt.contains("Key")) { ++ key = NamespacedKey.fromString(nbt.getString("Key")); ++ } ++ // Purpur end ++ + MobEffectInstance mobEffectInstance = null; + if (nbt.contains("HiddenEffect", 10)) { + mobEffectInstance = loadSpecifiedEffect(type, nbt.getCompound("HiddenEffect")); + } + +- return new MobEffectInstance(type, j, i < 0 ? 0 : i, bl, bl2, bl3, mobEffectInstance); ++ return new MobEffectInstance(type, j, i < 0 ? 0 : i, bl, bl2, bl3, key, mobEffectInstance); // Purpur - add key + } + + public void setNoCounter(boolean permanent) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 92a08935e7b1c936e8aa379b118c345b89dc23d7..d2439ebab74c53e01f27fe9a9fe9366b99974dea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -436,7 +436,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + + @Override + public boolean addPotionEffect(PotionEffect effect, boolean force) { +- this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon ++ this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon(), effect.getKey()), EntityPotionEffectEvent.Cause.PLUGIN); // Purpur - add key // Paper - Don't ignore icon + return true; + } + +@@ -457,7 +457,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + @Override + public PotionEffect getPotionEffect(PotionEffectType type) { + MobEffectInstance handle = this.getHandle().getEffect(MobEffect.byId(type.getId())); +- return (handle == null) ? null : new PotionEffect(PotionEffectType.getById(MobEffect.getId(handle.getEffect())), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible()); ++ return (handle == null) ? null : new PotionEffect(PotionEffectType.getById(MobEffect.getId(handle.getEffect())), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible(), handle.getKey()); // Purpur - add key + } + + @Override +@@ -469,7 +469,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + public Collection getActivePotionEffects() { + List effects = new ArrayList(); + for (MobEffectInstance handle : this.getHandle().activeEffects.values()) { +- effects.add(new PotionEffect(PotionEffectType.getById(MobEffect.getId(handle.getEffect())), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible())); ++ effects.add(new PotionEffect(PotionEffectType.getById(MobEffect.getId(handle.getEffect())), handle.getDuration(), handle.getAmplifier(), handle.isAmbient(), handle.isVisible(), handle.getKey())); // Purpur - add key + } + return effects; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +index 4d325f61e9171b9e1a069ae69a87ec397735da79..056de387d0971f0b994e562c0b638442875b3a71 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +@@ -11,6 +11,7 @@ import net.minecraft.nbt.ListTag; + import org.apache.commons.lang.Validate; + import org.bukkit.Color; + import org.bukkit.Material; ++import org.bukkit.NamespacedKey; + import org.bukkit.configuration.serialization.DelegateDeserialization; + import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey; + import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta; +@@ -33,6 +34,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + static final ItemMetaKey POTION_COLOR = new ItemMetaKey("CustomPotionColor", "custom-color"); + static final ItemMetaKey ID = new ItemMetaKey("Id", "potion-id"); + static final ItemMetaKey DEFAULT_POTION = new ItemMetaKey("Potion", "potion-type"); ++ static final ItemMetaKey KEY = new ItemMetaKey("Key", "namespacedkey"); // Purpur - add key + + // Having an initial "state" in ItemMeta seems bit dirty but the UNCRAFTABLE potion type + // is treated as the empty form of the meta because it represents an empty potion with no effect +@@ -83,7 +85,13 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + boolean ambient = effect.getBoolean(AMBIENT.NBT); + boolean particles = tag.contains(SHOW_PARTICLES.NBT, CraftMagicNumbers.NBT.TAG_BYTE) ? effect.getBoolean(SHOW_PARTICLES.NBT) : true; + boolean icon = tag.contains(SHOW_ICON.NBT, CraftMagicNumbers.NBT.TAG_BYTE) ? effect.getBoolean(SHOW_ICON.NBT) : particles; +- this.customEffects.add(new PotionEffect(type, duration, amp, ambient, particles, icon)); ++ // Purpur start ++ NamespacedKey key = null; ++ if (tag.contains(KEY.NBT)) { ++ key = NamespacedKey.fromString(effect.getString(KEY.NBT)); ++ } ++ this.customEffects.add(new PotionEffect(type, duration, amp, ambient, particles, icon, key)); ++ // Purpur end + } + } + } +@@ -132,6 +140,11 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + effectData.putBoolean(AMBIENT.NBT, effect.isAmbient()); + effectData.putBoolean(SHOW_PARTICLES.NBT, effect.hasParticles()); + effectData.putBoolean(SHOW_ICON.NBT, effect.hasIcon()); ++ // Purpur start ++ if (effect.hasKey()) { ++ effectData.putString(KEY.NBT, effect.getKey().toString()); ++ } ++ // Purpur end + effectList.add(effectData); + } + } +@@ -201,7 +214,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + if (index != -1) { + if (overwrite) { + PotionEffect old = this.customEffects.get(index); +- if (old.getAmplifier() == effect.getAmplifier() && old.getDuration() == effect.getDuration() && old.isAmbient() == effect.isAmbient()) { ++ if (old.getAmplifier() == effect.getAmplifier() && old.getDuration() == effect.getDuration() && old.isAmbient() == effect.isAmbient() && old.getKey() == effect.getKey()) { // Purpur - add key + return false; + } + this.customEffects.set(index, effect); +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +index acb69821a99aa69bce6d127e10976089c85be223..c5abd73981c5f4b41605eba0d44e6573dfd2a77a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java +@@ -101,7 +101,7 @@ public class CraftPotionUtil { + + public static MobEffectInstance fromBukkit(PotionEffect effect) { + MobEffect type = MobEffect.byId(effect.getType().getId()); +- return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()); ++ return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.getKey()); // Purpur - add key + } + + public static PotionEffect toBukkit(MobEffectInstance effect) { +@@ -110,7 +110,7 @@ public class CraftPotionUtil { + int duration = effect.getDuration(); + boolean ambient = effect.isAmbient(); + boolean particles = effect.isVisible(); +- return new PotionEffect(type, duration, amp, ambient, particles); ++ return new PotionEffect(type, duration, amp, ambient, particles, effect.getKey()); // Purpur - add key + } + + public static boolean equals(MobEffect mobEffect, PotionEffectType type) { +diff --git a/src/test/java/org/bukkit/potion/PotionTest.java b/src/test/java/org/bukkit/potion/PotionTest.java +index 7ea3cc4f8e35b61b3eba717ed58ee98cf835168c..48aa077ab2e2b708fb3d3287e636b4dc1c969925 100644 +--- a/src/test/java/org/bukkit/potion/PotionTest.java ++++ b/src/test/java/org/bukkit/potion/PotionTest.java +@@ -9,6 +9,7 @@ import net.minecraft.resources.ResourceLocation; + import net.minecraft.world.effect.MobEffect; + import net.minecraft.world.effect.MobEffectInstance; + import net.minecraft.world.item.alchemy.Potion; ++import org.bukkit.NamespacedKey; + import org.bukkit.support.AbstractTestingBase; + import org.junit.Test; + +@@ -47,4 +48,27 @@ public class PotionTest extends AbstractTestingBase { + assertEquals("Same type not returned by name " + key, bukkit, byName); + } + } ++ ++ // Purpur start ++ @Test ++ public void testNamespacedKey() { ++ NamespacedKey key = new NamespacedKey("testnamespace", "testkey"); ++ PotionEffect namedSpacedEffect = new PotionEffect(PotionEffectType.DOLPHINS_GRACE, 20, 0, true, true, true, key); ++ assertNotNull(namedSpacedEffect.getKey()); ++ assertTrue(namedSpacedEffect.hasKey()); ++ assertFalse(namedSpacedEffect.withKey(null).hasKey()); ++ ++ PotionEffect effect = new PotionEffect(PotionEffectType.DOLPHINS_GRACE, 20, 0, true, true, true); ++ assertNull(effect.getKey()); ++ assertFalse(effect.hasKey()); ++ assertTrue(namedSpacedEffect.withKey(key).hasKey()); ++ ++ Map s1 = namedSpacedEffect.serialize(); ++ Map s2 = effect.serialize(); ++ assertTrue(s1.containsKey("namespacedKey")); ++ assertFalse(s2.containsKey("namespacedKey")); ++ assertNotNull(new PotionEffect(s1).getKey()); ++ assertNull(new PotionEffect(s2).getKey()); ++ } ++ // Purpur end + }