From a404f4b9abdcc26eff21d1844d7e5f8c7390800b Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 25 Apr 2024 16:24:08 -0700
Subject: [PATCH] address my own comments

---
 patches/server/Adventure.patch                | 22 ++++++++++++++-----
 .../Implement-enchantWithLevels-API.patch     |  2 +-
 ...able-API-and-replenishable-lootables.patch |  5 ++---
 ...he-changed-item-from-dispense-events.patch |  2 +-
 4 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch
index aa85206011..ab998b46d1 100644
--- a/patches/server/Adventure.patch
+++ b/patches/server/Adventure.patch
@@ -1219,6 +1219,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
 +import org.bukkit.craftbukkit.entity.CraftEntity;
 +import org.intellij.lang.annotations.Subst;
++import org.jetbrains.annotations.Contract;
 +import org.jetbrains.annotations.NotNull;
 +import org.jetbrains.annotations.Nullable;
 +
@@ -1337,7 +1338,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        return jsons;
 +    }
 +
-+    public static net.minecraft.network.chat.Component asVanilla(@Nullable final Component component) {
++    public static net.minecraft.network.chat.@NotNull Component asVanillaNullToEmpty(final @Nullable Component component) {
++        if (component == null) return net.minecraft.network.chat.CommonComponents.EMPTY;
++        return asVanilla(component);
++    }
++
++    @Contract("null -> null; !null -> !null")
++    public static net.minecraft.network.chat.Component asVanilla(final @Nullable Component component) {
 +        if (component == null) return null;
 +        if (true) return new AdventureComponent(component);
 +        return WRAPPER_AWARE_SERIALIZER.serialize(component);
@@ -4159,7 +4166,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          if (this.getHandle().connection == null) return;
  
 -        ClientboundTabListPacket packet = new ClientboundTabListPacket((this.playerListHeader == null) ? Component.empty() : this.playerListHeader, (this.playerListFooter == null) ? Component.empty() : this.playerListFooter);
-+        ClientboundTabListPacket packet = new ClientboundTabListPacket((this.playerListHeader == null) ? Component.empty() : io.papermc.paper.adventure.PaperAdventure.asVanilla(this.playerListHeader), (this.playerListFooter == null) ? Component.empty() : io.papermc.paper.adventure.PaperAdventure.asVanilla(this.playerListFooter)); // Paper - adventure
++        ClientboundTabListPacket packet = new ClientboundTabListPacket(io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(this.playerListHeader), io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(this.playerListFooter)); // Paper - adventure
          this.getHandle().connection.send(packet);
      }
  
@@ -4421,8 +4428,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        final ServerGamePacketListenerImpl connection = this.getHandle().connection;
 +        if (connection == null) return;
 +        final ClientboundTabListPacket packet = new ClientboundTabListPacket(
-+            io.papermc.paper.adventure.PaperAdventure.asVanilla((this.playerListHeader == null) ? net.kyori.adventure.text.Component.empty() : this.playerListHeader),
-+            io.papermc.paper.adventure.PaperAdventure.asVanilla((this.playerListFooter == null) ? net.kyori.adventure.text.Component.empty() : this.playerListFooter)
++            io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(this.playerListHeader),
++            io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(this.playerListFooter)
 +        );
 +        connection.send(packet);
 +    }
@@ -4744,7 +4751,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    // Paper start - Adventure
 +    @Override
 +    public net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowItem> asHoverEvent(final ItemStack item, final java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowItem> op) {
-+        return net.kyori.adventure.text.event.HoverEvent.showItem(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowItem.showItem(item.getType().getKey(), item.getAmount(), io.papermc.paper.adventure.PaperAdventure.asAdventure(CraftItemStack.asNMSCopy(item).getComponentsPatch()))));
++        return net.kyori.adventure.text.event.HoverEvent.showItem(op.apply(
++            net.kyori.adventure.text.event.HoverEvent.ShowItem.showItem(
++                item.getType().getKey(),
++                item.getAmount(),
++                io.papermc.paper.adventure.PaperAdventure.asAdventure(CraftItemStack.unwrap(item).getComponentsPatch())) // unwrap is fine here because the components patch will be safely copied
++        ));
 +    }
 +
 +    @Override
diff --git a/patches/server/Implement-enchantWithLevels-API.patch b/patches/server/Implement-enchantWithLevels-API.patch
index c2207edfba..188b11267f 100644
--- a/patches/server/Implement-enchantWithLevels-API.patch
+++ b/patches/server/Implement-enchantWithLevels-API.patch
@@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        Preconditions.checkArgument(random != null, "Argument 'random' must not be null");
 +        final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack);
 +        if (internalStack.isEnchanted()) {
-+            internalStack.applyComponents(net.minecraft.core.component.DataComponentPatch.builder().remove(net.minecraft.core.component.DataComponents.ENCHANTMENTS).build());
++            internalStack.set(net.minecraft.core.component.DataComponents.ENCHANTMENTS, null);
 +        }
 +        final net.minecraft.world.item.ItemStack enchanted = net.minecraft.world.item.enchantment.EnchantmentHelper.enchantItem(
 +            MinecraftServer.getServer().getWorldData().enabledFeatures(),
diff --git a/patches/server/LootTable-API-and-replenishable-lootables.patch b/patches/server/LootTable-API-and-replenishable-lootables.patch
index 50780be420..7fae07f171 100644
--- a/patches/server/LootTable-API-and-replenishable-lootables.patch
+++ b/patches/server/LootTable-API-and-replenishable-lootables.patch
@@ -673,9 +673,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        // Copied from super with changes, always check the original method
 +        this.lootableData.loadNbt(nbt); // Paper
 +        if (nbt.contains("LootTable", 8)) {
-+            final var loc = new net.minecraft.resources.ResourceLocation(nbt.getString("LootTable"));
-+            this.setLootTable(ResourceKey.create(net.minecraft.core.registries.Registries.LOOT_TABLE, loc));
-+            try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable.location()); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
++            this.setLootTable(net.minecraft.Optionull.map(net.minecraft.resources.ResourceLocation.tryParse(nbt.getString("LootTable")), rl -> ResourceKey.create(net.minecraft.core.registries.Registries.LOOT_TABLE, rl)));
++            try { if (this.lootTable != null) org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable.location()); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
 +            if (nbt.contains("LootTableSeed", 4)) {
 +                this.setLootTableSeed(nbt.getLong("LootTableSeed"));
 +            } else {
diff --git a/patches/server/Properly-track-the-changed-item-from-dispense-events.patch b/patches/server/Properly-track-the-changed-item-from-dispense-events.patch
index 0b58597ca9..23580b9633 100644
--- a/patches/server/Properly-track-the-changed-item-from-dispense-events.patch
+++ b/patches/server/Properly-track-the-changed-item-from-dispense-events.patch
@@ -79,7 +79,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              }
          }
  
-+        Projectile iprojectile = this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); // Paper - move from above and track changed items in the dispense event
++        Projectile iprojectile = this.projectileItem.asProjectile(worldserver, iposition, CraftItemStack.unwrap(event.getItem()), enumdirection); // Paper - move from above and track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies
          this.projectileItem.shoot(iprojectile, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty());
          ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(pointer.blockEntity());
          // CraftBukkit end