lots of updates

- add hash to items when created
- added "crops harvested" for hoes
This commit is contained in:
hyperdefined
2023-09-30 20:05:31 -04:00
parent 0a3f46fc6e
commit 5551c24202
14 changed files with 238 additions and 57 deletions

View File

@@ -21,6 +21,7 @@ import lol.hyper.githubreleaseapi.GitHubRelease;
import lol.hyper.githubreleaseapi.GitHubReleaseAPI; import lol.hyper.githubreleaseapi.GitHubReleaseAPI;
import lol.hyper.toolstats.commands.CommandToolStats; import lol.hyper.toolstats.commands.CommandToolStats;
import lol.hyper.toolstats.events.*; import lol.hyper.toolstats.events.*;
import lol.hyper.toolstats.tools.HashMaker;
import lol.hyper.toolstats.tools.ItemLore; import lol.hyper.toolstats.tools.ItemLore;
import lol.hyper.toolstats.tools.NumberFormat; import lol.hyper.toolstats.tools.NumberFormat;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
@@ -29,7 +30,6 @@ import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import space.arim.morepaperlib.MorePaperLib; import space.arim.morepaperlib.MorePaperLib;
@@ -60,6 +60,10 @@ public final class ToolStats extends JavaPlugin {
* Stores how many blocks were mined. * Stores how many blocks were mined.
*/ */
public final NamespacedKey genericMined = new NamespacedKey(this, "generic-mined"); public final NamespacedKey genericMined = new NamespacedKey(this, "generic-mined");
/**
* Stores how many crops were harvested.
*/
public final NamespacedKey cropsHarvested = new NamespacedKey(this, "crops-mined");
/** /**
* Stores how many fish were caught. * Stores how many fish were caught.
*/ */
@@ -80,6 +84,10 @@ public final class ToolStats extends JavaPlugin {
* Key for tracking new elytras that spawn. * Key for tracking new elytras that spawn.
*/ */
public final NamespacedKey newElytra = new NamespacedKey(this, "new"); public final NamespacedKey newElytra = new NamespacedKey(this, "new");
/**
* Key for item has.
*/
public final NamespacedKey hash = new NamespacedKey(this, "hash");
/** /**
* Stores how an item was created. * Stores how an item was created.
* 0 = crafted. * 0 = crafted.
@@ -115,6 +123,7 @@ public final class ToolStats extends JavaPlugin {
private BukkitAudiences adventure; private BukkitAudiences adventure;
public MorePaperLib morePaperLib; public MorePaperLib morePaperLib;
public HashMaker hashMaker;
@Override @Override
@@ -126,6 +135,7 @@ public final class ToolStats extends JavaPlugin {
logger.info("Copying default config!"); logger.info("Copying default config!");
} }
loadConfig(); loadConfig();
hashMaker = new HashMaker(this);
blocksMined = new BlocksMined(this); blocksMined = new BlocksMined(this);
craftItem = new CraftItem(this); craftItem = new CraftItem(this);
chunkPopulate = new ChunkPopulate(this); chunkPopulate = new ChunkPopulate(this);
@@ -198,12 +208,12 @@ public final class ToolStats extends JavaPlugin {
/** /**
* Checks the config to see if we want to show lore on certain items. * Checks the config to see if we want to show lore on certain items.
* *
* @param itemStack The item to check. * @param material The item type to check.
* @param configName The config we are checking under. * @param configName The config we are checking under.
* @return If we want to allow lore or not. * @return If we want to allow lore or not.
*/ */
public boolean checkConfig(ItemStack itemStack, String configName) { public boolean checkConfig(Material material, String configName) {
String itemName = itemStack.getType().toString().toLowerCase(); String itemName = material.toString().toLowerCase();
String itemType = null; String itemType = null;
if (itemName.contains("bow") || itemName.contains("shears") || itemName.contains("trident")) { if (itemName.contains("bow") || itemName.contains("shears") || itemName.contains("trident")) {
if (itemName.contains("bow")) { if (itemName.contains("bow")) {
@@ -301,6 +311,9 @@ public final class ToolStats extends JavaPlugin {
if (lore.contains("{fish}")) { if (lore.contains("{fish}")) {
lore = lore.replace("{fish}", ""); lore = lore.replace("{fish}", "");
} }
if (lore.contains("{crops}")) {
lore = lore.replace("{crops}", "");
}
} }
return lore; return lore;
} }

View File

@@ -158,7 +158,7 @@ public class CommandToolStats implements TabExecutor {
} }
} }
if (toolStats.checkConfig(original, "created-by")) { if (toolStats.checkConfig(original.getType(), "created-by")) {
if (container.has(toolStats.genericOwner, new UUIDDataType())) { if (container.has(toolStats.genericOwner, new UUIDDataType())) {
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
// show how the item was created based on the previous lore // show how the item was created based on the previous lore
@@ -186,7 +186,7 @@ public class CommandToolStats implements TabExecutor {
} }
} }
} }
if (toolStats.checkConfig(original, "created-date")) { if (toolStats.checkConfig(original.getType(), "created-date")) {
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) { if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG); Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) { if (time != null) {
@@ -216,7 +216,7 @@ public class CommandToolStats implements TabExecutor {
} }
} }
} }
if (toolStats.checkConfig(original, "player-kills")) { if (toolStats.checkConfig(original.getType(), "player-kills")) {
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) { if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER); Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
if (kills != null) { if (kills != null) {
@@ -224,7 +224,7 @@ public class CommandToolStats implements TabExecutor {
} }
} }
} }
if (toolStats.checkConfig(original, "mob-kills")) { if (toolStats.checkConfig(original.getType(), "mob-kills")) {
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) { if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER); Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
if (kills != null) { if (kills != null) {
@@ -232,7 +232,15 @@ public class CommandToolStats implements TabExecutor {
} }
} }
} }
if (toolStats.checkConfig(original, "blocks-mined")) { if (toolStats.checkConfig(original.getType(), "blocks-mined")) {
if (original.getType().toString().toLowerCase(Locale.ROOT).contains("hoe")) {
if (container.has(toolStats.cropsHarvested, PersistentDataType.INTEGER)) {
Integer crops = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
if (crops != null) {
lore.add(toolStats.getLoreFromConfig("crops-harvested", true).replace("{crops}", toolStats.numberFormat.formatInt(crops)));
}
}
}
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) { if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER); Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
if (blocksMined != null) { if (blocksMined != null) {

View File

@@ -19,7 +19,10 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker; import lol.hyper.toolstats.tools.ItemChecker;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -32,6 +35,8 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.UUID;
public class BlocksMined implements Listener { public class BlocksMined implements Listener {
@@ -50,15 +55,23 @@ public class BlocksMined implements Listener {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return; return;
} }
// if the player mines something with their fist
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
ItemStack heldItem = inventory.getItemInMainHand(); ItemStack heldItem = inventory.getItemInMainHand();
Block block = event.getBlock();
// only check certain items // only check certain items
if (!ItemChecker.isMineTool(heldItem.getType())) { if (!ItemChecker.isMineTool(heldItem.getType())) {
return; return;
} }
// update the blocks mined
updateBlocksMined(heldItem); if (heldItem.getType().toString().toLowerCase(Locale.ROOT).contains("hoe")) {
// player is breaking crops with a hoe
if (block.getBlockData() instanceof Ageable) {
updateCropsMined(heldItem, (Ageable) block.getBlockData());
}
} else {
// update the blocks mined
updateBlocksMined(heldItem);
}
} }
private void updateBlocksMined(ItemStack playerTool) { private void updateBlocksMined(ItemStack playerTool) {
@@ -87,7 +100,44 @@ public class BlocksMined implements Listener {
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{blocks}", blocksMinedFormatted, "blocks-mined"); List<String> newLore = toolStats.itemLore.addItemLore(meta, "{blocks}", blocksMinedFormatted, "blocks-mined");
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(playerTool, "blocks-mined")) { if (toolStats.checkConfig(playerTool.getType(), "blocks-mined")) {
meta.setLore(newLore);
}
playerTool.setItemMeta(meta);
}
private void updateCropsMined(ItemStack playerTool, Ageable block) {
// ignore crops that are not fully grown
if (block.getAge() != block.getMaximumAge()) {
return;
}
ItemMeta meta = playerTool.getItemMeta();
if (meta == null) {
toolStats.logger.warning(playerTool + " does NOT have any meta! Unable to update stats.");
return;
}
// read the current stats from the item
// if they don't exist, then start from 0
Integer cropsMined = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.cropsHarvested, PersistentDataType.INTEGER)) {
cropsMined = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
}
if (cropsMined == null) {
cropsMined = 0;
toolStats.logger.warning(playerTool + " does not have valid crops-mined set! Resting to zero. This should NEVER happen.");
}
cropsMined++;
container.set(toolStats.cropsHarvested, PersistentDataType.INTEGER, cropsMined);
String cropsMinedFormatted = toolStats.numberFormat.formatInt(cropsMined);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{crops}", cropsMinedFormatted, "crops-harvested");
// do we add the lore based on the config?
if (toolStats.checkConfig(playerTool.getType(), "blocks-mined")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
playerTool.setItemMeta(meta); playerTool.setItemMeta(meta);

View File

@@ -104,6 +104,9 @@ public class CraftItem implements Listener {
return null; return null;
} }
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 0); container.set(toolStats.originType, PersistentDataType.INTEGER, 0);
@@ -128,10 +131,10 @@ public class CraftItem implements Listener {
lore = new ArrayList<>(); lore = new ArrayList<>();
} }
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "created-date")) { if (toolStats.checkConfig(itemStack.getType(), "created-date")) {
lore.add(createdOnRaw.replace("{date}", toolStats.numberFormat.formatDate(finalDate))); lore.add(createdOnRaw.replace("{date}", toolStats.numberFormat.formatDate(finalDate)));
} }
if (toolStats.checkConfig(itemStack, "created-by")) { if (toolStats.checkConfig(itemStack.getType(), "created-by")) {
lore.add(createdByRaw.replace("{player}", owner.getName())); lore.add(createdByRaw.replace("{player}", owner.getName()));
} }
meta.setLore(lore); meta.setLore(lore);

View File

@@ -249,7 +249,7 @@ public class EntityDamage implements Listener {
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player"); List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player");
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "player-kills")) { if (toolStats.checkConfig(itemStack.getType(), "player-kills")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
@@ -284,7 +284,7 @@ public class EntityDamage implements Listener {
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob"); List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob");
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "mob-kills")) { if (toolStats.checkConfig(itemStack.getType(), "mob-kills")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
@@ -356,7 +356,7 @@ public class EntityDamage implements Listener {
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob"); List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob");
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(newTrident, "mob-kills")) { if (toolStats.checkConfig(newTrident.getType(), "mob-kills")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
newTrident.setItemMeta(meta); newTrident.setItemMeta(meta);
@@ -393,7 +393,7 @@ public class EntityDamage implements Listener {
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player"); List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player");
// do we add the lore based on the config? // do we add the lore based on the config?
if (toolStats.checkConfig(newTrident, "player-kills")) { if (toolStats.checkConfig(newTrident.getType(), "player-kills")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
newTrident.setItemMeta(meta); newTrident.setItemMeta(meta);

View File

@@ -144,6 +144,9 @@ public class GenerateLoot implements Listener {
return null; return null;
} }
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 2); container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
@@ -151,7 +154,7 @@ public class GenerateLoot implements Listener {
String formattedDate = toolStats.numberFormat.formatDate(finalDate); String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate); List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (toolStats.checkConfig(newItem, "looted-tag")) { if (toolStats.checkConfig(newItem.getType(), "looted-tag")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
newItem.setItemMeta(meta); newItem.setItemMeta(meta);

View File

@@ -19,6 +19,7 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker; import lol.hyper.toolstats.tools.ItemChecker;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -32,7 +33,7 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import java.util.List; import java.util.UUID;
public class InventoryOpen implements Listener { public class InventoryOpen implements Listener {
@@ -49,36 +50,54 @@ public class InventoryOpen implements Listener {
} }
Inventory inventory = event.getInventory(); Inventory inventory = event.getInventory();
Location location = event.getInventory().getLocation();
for (ItemStack itemStack : inventory) { for (ItemStack itemStack : inventory) {
if (itemStack == null) { if (itemStack == null) {
continue; continue;
} }
// ignore items that are not the right type
if (!ItemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta itemMeta = itemStack.getItemMeta(); ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) { if (itemMeta == null) {
continue; continue;
} }
PersistentDataContainer container = itemMeta.getPersistentDataContainer(); PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// ignore any items that already have the origin tag
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) { // generate a hash if the item doesn't have one
continue; if (!container.has(toolStats.hash, PersistentDataType.STRING)) {
} // make sure the item has an owner
// ignore items that are not the right type if (!container.has(toolStats.genericOwner, new UUIDDataType())) {
if (!ItemChecker.isValidItem(itemStack.getType())) { continue;
continue; }
UUID owner = container.get(toolStats.genericOwner, new UUIDDataType());
if (owner == null) {
continue;
}
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (timestamp == null) {
continue;
}
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
toolStats.logger.info(hash);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
ItemMeta newMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA); // add origin tag
if (newMeta == null) { if (!container.has(toolStats.originType, PersistentDataType.INTEGER)) {
continue; itemMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA);
if (itemMeta == null) {
continue;
}
} }
ItemMeta clone = itemMeta.clone();
BukkitRunnable runnable = new BukkitRunnable() { BukkitRunnable runnable = new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
itemStack.setItemMeta(newMeta); itemStack.setItemMeta(clone);
} }
}; };
Location location = inventory.getLocation();
// only run for actual inventories
if (location != null) { if (location != null) {
toolStats.scheduleRegion(runnable, location.getWorld(), location.getChunk(), 1); toolStats.scheduleRegion(runnable, location.getWorld(), location.getChunk(), 1);
} }

View File

@@ -155,6 +155,9 @@ public class PlayerFish implements Listener {
return null; return null;
} }
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 5); container.set(toolStats.originType, PersistentDataType.INTEGER, 5);
@@ -162,7 +165,7 @@ public class PlayerFish implements Listener {
String formattedDate = toolStats.numberFormat.formatDate(finalDate); String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate); List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (toolStats.checkConfig(newItem, "fished-tag")) { if (toolStats.checkConfig(newItem.getType(), "fished-tag")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
newItem.setItemMeta(meta); newItem.setItemMeta(meta);

View File

@@ -19,7 +19,7 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker; import lol.hyper.toolstats.tools.ItemChecker;
import org.bukkit.Location; import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -32,6 +32,8 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
public class PlayerJoin implements Listener { public class PlayerJoin implements Listener {
private final ToolStats toolStats; private final ToolStats toolStats;
@@ -49,35 +51,50 @@ public class PlayerJoin implements Listener {
if (itemStack == null) { if (itemStack == null) {
continue; continue;
} }
// ignore items that are not the right type
if (!ItemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta itemMeta = itemStack.getItemMeta(); ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) { if (itemMeta == null) {
continue; continue;
} }
PersistentDataContainer container = itemMeta.getPersistentDataContainer(); PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// ignore any items that already have the origin tag
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) { // generate a hash if the item doesn't have one
continue; if (!container.has(toolStats.hash, PersistentDataType.STRING)) {
} // make sure the item has an owner
// ignore items that are not the right type if (!container.has(toolStats.genericOwner, new UUIDDataType())) {
if (!ItemChecker.isValidItem(itemStack.getType())) { continue;
continue; }
UUID owner = container.get(toolStats.genericOwner, new UUIDDataType());
if (owner == null) {
continue;
}
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (timestamp == null) {
continue;
}
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
toolStats.logger.info(hash);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
ItemMeta newMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA); // add origin tag
if (newMeta == null) { if (!container.has(toolStats.originType, PersistentDataType.INTEGER)) {
continue; itemMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA);
if (itemMeta == null) {
continue;
}
} }
ItemMeta clone = itemMeta.clone();
BukkitRunnable runnable = new BukkitRunnable() { BukkitRunnable runnable = new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
itemStack.setItemMeta(newMeta); itemStack.setItemMeta(clone);
} }
}; };
Location location = inventory.getLocation(); toolStats.scheduleEntity(runnable, player, 1);
// only run for actual inventories
if (location != null) {
toolStats.scheduleRegion(runnable, location.getWorld(), location.getChunk(), 1);
}
} }
} }
} }

View File

@@ -106,6 +106,9 @@ public class VillagerTrade implements Listener {
return null; return null;
} }
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 3); container.set(toolStats.originType, PersistentDataType.INTEGER, 3);
@@ -113,7 +116,7 @@ public class VillagerTrade implements Listener {
String formattedDate = toolStats.numberFormat.formatDate(finalDate); String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate); List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (toolStats.checkConfig(newItem, "traded-tag")) { if (toolStats.checkConfig(newItem.getType(), "traded-tag")) {
meta.setLore(newLore); meta.setLore(newLore);
} }
newItem.setItemMeta(meta); newItem.setItemMeta(meta);

View File

@@ -0,0 +1,60 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package lol.hyper.toolstats.tools;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.Material;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
public class HashMaker {
private final ToolStats toolStats;
public HashMaker(ToolStats toolStats) {
this.toolStats = toolStats;
}
public String makeHash(Material itemType, UUID player, long timestamp) {
String input = itemType.toString() + player.toString() + timestamp;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : hashBytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException exception) {
toolStats.logger.warning("Unable to generate hash for " + player.toString() + "!");
toolStats.logger.warning("Generating a random UUID instead.");
exception.printStackTrace();
return java.util.UUID.randomUUID().toString();
}
}
}

View File

@@ -24,10 +24,10 @@ import java.util.Locale;
public class ItemChecker { public class ItemChecker {
private static final String[] validItems = { "pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing", "elytra" }; private static final String[] validItems = {"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing", "elytra"};
private static final String[] validArmor = { "helmet", "chestplate", "leggings", "boots" }; private static final String[] validArmor = {"helmet", "chestplate", "leggings", "boots"};
private static final String[] validMelee = {"sword", "trident", "axe"}; private static final String[] validMelee = {"sword", "trident", "axe"};
private static final String[] validMine = { "pickaxe", "axe", "hoe", "shovel", "shear" }; private static final String[] validMine = {"pickaxe", "axe", "hoe", "shovel", "shear", "hoe"};
/** /**
* Check if item is an armor piece. * Check if item is an armor piece.

View File

@@ -63,7 +63,8 @@ public class ItemLore {
for (int x = 0; x < newLore.size(); x++) { for (int x = 0; x < newLore.size(); x++) {
// check to see if the line matches the config value // check to see if the line matches the config value
// this means we update this line only! // this means we update this line only!
if (newLore.get(x).contains(configLore)) { String line = newLore.get(x);
if (line.contains(configLore)) {
newLore.set(x, newLine); newLore.set(x, newLine);
return newLore; return newLore;
} }

View File

@@ -91,6 +91,7 @@ messages:
mob: "&7Mob kills: &8{kills}" mob: "&7Mob kills: &8{kills}"
player: "&7Player kills: &8{kills}" player: "&7Player kills: &8{kills}"
blocks-mined: "&7Blocks mined: &8{blocks}" blocks-mined: "&7Blocks mined: &8{blocks}"
crops-harvested: "&7Crops harvested: &8{crops}"
sheep-sheared: "&7Sheep sheared: &8{sheep}" sheep-sheared: "&7Sheep sheared: &8{sheep}"
dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name
damage-taken: "&7Damage taken: &8{damage}" damage-taken: "&7Damage taken: &8{damage}"