From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yannick Lamprecht <yannicklamprecht@live.de>
Date: Mon, 22 Jan 2024 13:27:18 +0100
Subject: [PATCH] ItemStack Tooltip API


diff --git a/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e16f2645e956cbac8d0fc75ba8209f67fd1835c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContext.java
@@ -0,0 +1,76 @@
+package io.papermc.paper.inventory.tooltip;
+
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.Contract;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Context for computing itemstack tooltips via
+ * {@link org.bukkit.inventory.ItemStack#computeTooltipLines(TooltipContext, Player)}
+ */
+@NullMarked
+public interface TooltipContext {
+
+    /**
+     * Creates a new context with the given advanced and creative
+     * mode settings.
+     *
+     * @param advanced whether the context is for advanced tooltips
+     * @param creative whether the context is for the creative inventory
+     * @return a new context
+     */
+    @Contract("_, _ -> new")
+    static TooltipContext create(final boolean advanced, final boolean creative) {
+        return new TooltipContextImpl(advanced, creative);
+    }
+
+    /**
+     * Creates a new context that is neither advanced nor creative.
+     *
+     * @return a new context
+     */
+    @Contract("-> new")
+    static TooltipContext create() {
+        return new TooltipContextImpl(false, false);
+    }
+
+    /**
+     * Returns whether the context is for advanced
+     * tooltips.
+     * <p>
+     * Advanced tooltips are shown by default
+     * when a player has {@code F3+H} enabled.
+     *
+     * @return true if for advanced tooltips
+     */
+    boolean isAdvanced();
+
+    /**
+     * Returns whether the context is for the creative
+     * mode inventory.
+     * <p>
+     * Creative tooltips are shown by default when a player is
+     * in the creative inventory.
+     *
+     * @return true if for creative mode inventory
+     */
+    boolean isCreative();
+
+    /**
+     * Returns a new context with {@link #isAdvanced()}
+     * set to true.
+     *
+     * @return a new context
+     */
+    @Contract("-> new")
+    TooltipContext asAdvanced();
+
+    /**
+     * Returns a new context with {@link #isCreative()}
+     * set to true.
+     *
+     * @return a new context
+     */
+    @Contract("-> new")
+    TooltipContext asCreative();
+}
diff --git a/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a649b90dfac6000c01579a48234a11383c731439
--- /dev/null
+++ b/src/main/java/io/papermc/paper/inventory/tooltip/TooltipContextImpl.java
@@ -0,0 +1,17 @@
+package io.papermc.paper.inventory.tooltip;
+
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+record TooltipContextImpl(boolean isAdvanced, boolean isCreative) implements TooltipContext {
+
+    @Override
+    public TooltipContext asCreative() {
+        return new TooltipContextImpl(this.isAdvanced, true);
+    }
+
+    @Override
+    public TooltipContext asAdvanced() {
+        return new TooltipContextImpl(true, this.isCreative);
+    }
+}
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
index 159e96b1eedb0c97b624c338fefa1783336483e3..ff155bd22a6ea7f59dbf91c9280a653917b5010f 100644
--- a/src/main/java/org/bukkit/UnsafeValues.java
+++ b/src/main/java/org/bukkit/UnsafeValues.java
@@ -279,4 +279,6 @@ public interface UnsafeValues {
     @org.jetbrains.annotations.ApiStatus.Internal
     io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck);
     // Paper end - lifecycle event API
+
+    @NotNull java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines
 }
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
index c3ae09dc66119cb2873201fb2975ad5e0f8237d2..0e6103628673130139363b53d23d3432deff5c50 100644
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
@@ -1124,4 +1124,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
         return type.isAir() || amount <= 0;
     }
     // Paper end
+    // Paper start - expose itemstack tooltip lines
+    /**
+     * Computes the tooltip lines for this stack.
+     * <p>
+     * <b>Disclaimer:</b>
+     * Tooltip contents are not guaranteed to be consistent across different
+     * Minecraft versions.
+     *
+     * @param tooltipContext the tooltip context
+     * @param player a player for player-specific tooltip lines
+     * @return an immutable list of components (can be empty)
+     */
+    @SuppressWarnings("deprecation") // abusing unsafe as a bridge
+    public java.util.@NotNull @org.jetbrains.annotations.Unmodifiable List<net.kyori.adventure.text.Component> computeTooltipLines(final @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, final @Nullable org.bukkit.entity.Player player) {
+        return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player);
+    }
+    // Paper end - expose itemstack tooltip lines
 }