diff --git a/pom.xml b/pom.xml
index 0139a8f..64f6e8a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,7 +105,7 @@
io.papermc.paper
paper-api
- 1.21.9-R0.1-SNAPSHOT
+ 1.21.10-R0.1-SNAPSHOT
provided
diff --git a/src/main/java/lol/hyper/toolstats/ToolStats.java b/src/main/java/lol/hyper/toolstats/ToolStats.java
index 77e20ba..2c37b94 100644
--- a/src/main/java/lol/hyper/toolstats/ToolStats.java
+++ b/src/main/java/lol/hyper/toolstats/ToolStats.java
@@ -151,6 +151,7 @@ public final class ToolStats extends JavaPlugin {
public TokenData tokenData;
public AnvilEvent anvilEvent;
public PrepareCraft prepareCraft;
+ public BlockDispenseEvent blockDispenseEvent;
public HyperLib hyperLib;
public TextUtils textUtils;
@@ -201,6 +202,7 @@ public final class ToolStats extends JavaPlugin {
shootBow = new ShootBow(this);
anvilEvent = new AnvilEvent(this);
prepareCraft = new PrepareCraft(this);
+ blockDispenseEvent = new BlockDispenseEvent(this);
// save which stat can be used by a reset token
tokenKeys.add(blocksMined);
@@ -231,6 +233,7 @@ public final class ToolStats extends JavaPlugin {
Bukkit.getServer().getPluginManager().registerEvents(playerMove, this);
Bukkit.getServer().getPluginManager().registerEvents(anvilEvent, this);
Bukkit.getServer().getPluginManager().registerEvents(prepareCraft, this);
+ Bukkit.getServer().getPluginManager().registerEvents(blockDispenseEvent, this);
this.getCommand("toolstats").setExecutor(commandToolStats);
diff --git a/src/main/java/lol/hyper/toolstats/events/BlockDispenseEvent.java b/src/main/java/lol/hyper/toolstats/events/BlockDispenseEvent.java
new file mode 100644
index 0000000..f68daa6
--- /dev/null
+++ b/src/main/java/lol/hyper/toolstats/events/BlockDispenseEvent.java
@@ -0,0 +1,136 @@
+/*
+ * This file is part of ToolStats.
+ *
+ * ToolStats is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ToolStats is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ToolStats. If not, see .
+ */
+
+package lol.hyper.toolstats.events;
+
+import lol.hyper.hyperlib.datatypes.UUIDDataType;
+import lol.hyper.toolstats.ToolStats;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockDispenseLootEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+public class BlockDispenseEvent implements Listener {
+
+ private final ToolStats toolStats;
+
+ public BlockDispenseEvent(ToolStats toolStats) {
+ this.toolStats = toolStats;
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onDispense(BlockDispenseLootEvent event) {
+ Player player = event.getPlayer();
+
+ if (player == null) {
+ return;
+ }
+
+ List loot = event.getDispensedLoot();
+ // probably won't ever happen
+ if (loot.isEmpty()) {
+ return;
+ }
+
+ List newLoot = new ArrayList<>();
+ for (ItemStack lootItem : loot) {
+ ItemStack newLootItem = lootItem.clone();
+ Material lootItemMaterial = newLootItem.getType();
+ // if the item is one we want, do stuff
+ if (toolStats.itemChecker.isValidItem(lootItemMaterial)) {
+ newLootItem = addLootedOrigin(newLootItem, player);
+ }
+
+ // if the item returned null, add the original item
+ newLoot.add(Objects.requireNonNullElse(newLootItem, lootItem));
+ }
+ event.setDispensedLoot(newLoot);
+ }
+
+ /**
+ * Adds lore to newly generated items.
+ *
+ * @param itemStack The item to add lore to.
+ * @param owner The player that found the item.
+ * @return The item with the lore.
+ */
+ private ItemStack addLootedOrigin(ItemStack itemStack, Player owner) {
+ ItemStack newItem = itemStack.clone();
+ ItemMeta meta = itemStack.getItemMeta();
+ if (meta == null) {
+ return null;
+ }
+ long timeCreated = System.currentTimeMillis();
+ Date finalDate;
+ if (toolStats.config.getBoolean("normalize-time-creation")) {
+ finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
+ timeCreated = finalDate.getTime();
+ }
+ PersistentDataContainer container = meta.getPersistentDataContainer();
+
+ if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) {
+ return null;
+ }
+
+ // get the current lore the item
+ List lore;
+ if (meta.hasLore()) {
+ lore = meta.lore();
+ } else {
+ lore = new ArrayList<>();
+ }
+
+ // if creation date is enabled, add it
+ Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 2, newItem);
+ if (creationDate != null) {
+ container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
+ container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
+ lore.add(creationDate);
+ meta.lore(lore);
+ }
+
+ // if ownership is enabled, add it
+ Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 2, newItem);
+ if (itemOwner != null) {
+ container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
+ container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
+ lore.add(itemOwner);
+ meta.lore(lore);
+ }
+
+ // if hash is enabled, add it
+ if (toolStats.config.getBoolean("generate-hash-for-items")) {
+ String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
+ container.set(toolStats.hash, PersistentDataType.STRING, hash);
+ }
+
+ newItem.setItemMeta(meta);
+ return newItem;
+ }
+}
diff --git a/src/main/java/lol/hyper/toolstats/events/PlayerInteract.java b/src/main/java/lol/hyper/toolstats/events/PlayerInteract.java
index 7ca538b..da4bdb0 100644
--- a/src/main/java/lol/hyper/toolstats/events/PlayerInteract.java
+++ b/src/main/java/lol/hyper/toolstats/events/PlayerInteract.java
@@ -20,8 +20,8 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
-import org.bukkit.Material;
import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@@ -31,6 +31,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.InventoryHolder;
import java.util.HashMap;
import java.util.Map;
@@ -62,7 +63,8 @@ public class PlayerInteract implements Listener {
return;
}
// store when a player opens a chest
- if (block.getType() != Material.AIR && block.getType() == Material.CHEST) {
+ BlockState state = block.getState();
+ if (state instanceof InventoryHolder) {
openedChests.put(block, player);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedChests.remove(block), 20);
}