24package com.dreamfirestudios.dreamcore.DreamInventory;
26import net.kyori.adventure.text.Component;
27import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
28import org.bukkit.entity.LivingEntity;
29import org.bukkit.entity.Player;
30import org.bukkit.inventory.Inventory;
31import org.bukkit.inventory.ItemStack;
32import org.bukkit.inventory.PlayerInventory;
33import org.bukkit.inventory.meta.Damageable;
34import org.bukkit.inventory.meta.ItemMeta;
35import org.jetbrains.annotations.NotNull;
36import org.jetbrains.annotations.Nullable;
38import java.util.ArrayList;
40import java.util.Objects;
41import java.util.function.Predicate;
85 public static @NotNull List<ItemRef>
scan(@Nullable LivingEntity entity) {
86 final List<ItemRef> out =
new ArrayList<>();
87 if (entity ==
null || entity.getEquipment() ==
null)
return out;
90 final ItemStack[] armor = entity.getEquipment().getArmorContents();
91 for (
int i = 0; i < armor.length; i++) {
92 final ItemStack s = armor[i];
97 final ItemStack main = entity.getEquipment().getItemInMainHand();
98 final ItemStack off = entity.getEquipment().getItemInOffHand();
111 public static @NotNull List<ItemRef>
scan(@Nullable PlayerInventory inv) {
112 final List<ItemRef> out =
new ArrayList<>();
113 if (inv ==
null)
return out;
116 final ItemStack[] contents = inv.getContents();
117 for (
int slot = 0; slot < contents.length; slot++) {
118 final ItemStack s = contents[slot];
123 final ItemStack[] armor = inv.getArmorContents();
124 for (
int i = 0; i < armor.length; i++) {
125 final ItemStack s = armor[i];
130 final ItemStack main = inv.getItemInMainHand();
131 final ItemStack off = inv.getItemInOffHand();
148 public static int totalCount(@NotNull PlayerInventory inv, @NotNull ItemStack probe) {
149 Objects.requireNonNull(inv,
"inventory");
150 Objects.requireNonNull(probe,
"itemStack");
152 for (ItemStack s : inv.getContents()) {
153 if (s !=
null && s.isSimilar(probe)) total += s.getAmount();
164 public static boolean isBroken(@Nullable ItemStack item) {
165 if (item ==
null)
return false;
166 final int max = item.getType().getMaxDurability();
167 if (max <= 0)
return false;
168 final ItemMeta meta = item.getItemMeta();
169 if (!(meta instanceof Damageable dmg))
return false;
170 return dmg.getDamage() >= max;
180 public static @Nullable ItemStack
findByDisplayName(@NotNull PlayerInventory inv, @NotNull String plainName) {
181 Objects.requireNonNull(inv,
"inventory");
182 Objects.requireNonNull(plainName,
"plainName");
183 final String target = plainName.trim();
184 for (ItemStack s : inv.getContents()) {
185 if (s ==
null)
continue;
186 final ItemMeta meta = s.getItemMeta();
187 if (meta ==
null || !meta.hasDisplayName())
continue;
188 final Component name = meta.displayName();
189 if (name ==
null)
continue;
190 final String plain = PlainTextComponentSerializer.plainText().serialize(name);
191 if (plain.equalsIgnoreCase(target))
return s;
202 public static @Nullable ItemStack
findByDisplayName(@NotNull PlayerInventory inv, @NotNull Component nameComponent) {
203 final String plain = PlainTextComponentSerializer.plainText().serialize(nameComponent);
214 public static boolean hasAtLeast(@NotNull PlayerInventory inv, @NotNull ItemStack probe,
int amount) {
215 return totalCount(inv, probe) >= Math.max(0, amount);
229 public static int removeAmount(@NotNull PlayerInventory inv, @NotNull ItemStack probe,
int amount) {
230 Objects.requireNonNull(inv,
"inventory");
231 Objects.requireNonNull(probe,
"itemStack");
232 int toRemove = Math.max(0, amount);
233 if (toRemove == 0)
return 0;
235 ItemStack[] contents = inv.getContents();
236 for (
int slot = 0; slot < contents.length && toRemove > 0; slot++) {
237 ItemStack s = contents[slot];
238 if (s ==
null || !s.isSimilar(probe))
continue;
240 int take = Math.min(s.getAmount(), toRemove);
241 s.setAmount(s.getAmount() - take);
244 if (s.getAmount() <= 0) contents[slot] =
null;
246 inv.setContents(contents);
247 return amount - toRemove;
256 public static int removeAllSimilar(@NotNull PlayerInventory inv, @NotNull ItemStack probe) {
257 Objects.requireNonNull(inv,
"inventory");
258 Objects.requireNonNull(probe,
"itemStack");
260 ItemStack[] contents = inv.getContents();
261 for (
int slot = 0; slot < contents.length; slot++) {
262 ItemStack s = contents[slot];
263 if (s !=
null && s.isSimilar(probe)) {
264 removed += s.getAmount();
265 contents[slot] =
null;
268 inv.setContents(contents);
278 public static boolean addItem(@NotNull PlayerInventory inv, @NotNull ItemStack stack) {
279 Objects.requireNonNull(inv,
"inventory");
280 Objects.requireNonNull(stack,
"itemStack");
281 return inv.addItem(stack).isEmpty();
291 public static void swap(@NotNull Inventory inv,
int slot1,
int slot2) {
292 Objects.requireNonNull(inv,
"inventory");
293 final int size = inv.getSize();
294 if (slot1 < 0 || slot1 >= size || slot2 < 0 || slot2 >= size) {
295 throw new IllegalArgumentException(
"Invalid slot(s): " + slot1 +
", " + slot2 +
" (size=" + size +
")");
297 ItemStack a = inv.getItem(slot1);
298 ItemStack b = inv.getItem(slot2);
299 inv.setItem(slot1, b);
300 inv.setItem(slot2, a);
308 public static void ensureMainHand(@NotNull Player player, @NotNull ItemStack stack) {
309 Objects.requireNonNull(player,
"player");
310 Objects.requireNonNull(stack,
"itemStack");
311 ItemStack current = player.getInventory().getItemInMainHand();
312 if (current !=
null && current.isSimilar(stack))
return;
313 player.getInventory().setItemInMainHand(stack);
332 public static @Nullable ItemStack
findFirst(@NotNull PlayerInventory inv, @NotNull Predicate<ItemStack> predicate) {
333 Objects.requireNonNull(inv,
"inventory");
334 Objects.requireNonNull(predicate,
"predicate");
335 for (ItemStack s : inv.getContents()) {
336 if (s !=
null && predicate.test(s))
return s;
Utility class providing safe and Paper-friendly inventory manipulation helpers.
static int totalCount(@NotNull PlayerInventory inv, @NotNull ItemStack probe)
Counts total items similar to the probe across a player’s inventory.
static void swap(@NotNull Inventory inv, int slot1, int slot2)
Swaps two slots in an inventory.
static int removeAmount(@NotNull PlayerInventory inv, @NotNull ItemStack probe, int amount)
Removes up to a certain amount of matching items from the inventory.
static int removeAllSimilar(@NotNull PlayerInventory inv, @NotNull ItemStack probe)
Removes all stacks similar to the probe.
static boolean hasAtLeast(@NotNull PlayerInventory inv, @NotNull ItemStack probe, int amount)
Checks if the inventory has at least amount of the probe item.
static List< ItemRef > scan(@Nullable LivingEntity entity)
Scans a living entity’s equipment (armor + hands) and returns logical item references.
static ItemStack findByDisplayName(@NotNull PlayerInventory inv, @NotNull String plainName)
Finds the first item whose display name matches the given plain text.
static boolean addItem(@NotNull PlayerInventory inv, @NotNull ItemStack stack)
Attempts to add an item to inventory.
static ItemStack findFirst(@NotNull PlayerInventory inv, @NotNull Predicate< ItemStack > predicate)
Finds the first item in an inventory matching a predicate.
static final int SLOT_MAIN_HAND
Reserved slot index for main hand references in ItemRef.
static boolean isBroken(@Nullable ItemStack item)
Determines whether the item is fully broken (at max durability).
static void ensureMainHand(@NotNull Player player, @NotNull ItemStack stack)
Ensures the player’s main hand contains the given stack (if not already similar).
static ItemStack findByDisplayName(@NotNull PlayerInventory inv, @NotNull Component nameComponent)
Finds the first item matching the given component display name.
static final int SLOT_OFF_HAND
Reserved slot index for off hand references in ItemRef.
static List< ItemRef > scan(@Nullable PlayerInventory inv)
Scans a player’s full inventory (backpack + armor + hands).
Logical locations for items when scanning entities or players.
ENTITY_INVENTORY
Any backpack/hotbar slot.
ENTITY_OFF_HAND
Entity’s off hand (slot = DreamInventory.SLOT_OFF_HAND).
ENTITY_ARMOR
Any armor slot (see slot index for which).
ENTITY_MAIN_HAND
Entity’s main hand (slot = DreamInventory.SLOT_MAIN_HAND).
record ItemRef(ItemLocation location, int slot, ItemStack stack)
Immutable reference to an item found during an inventory scan.