diff --git a/src/main/java/lol/hyper/toolstats/ToolStats.java b/src/main/java/lol/hyper/toolstats/ToolStats.java index be213b7..58de4b3 100644 --- a/src/main/java/lol/hyper/toolstats/ToolStats.java +++ b/src/main/java/lol/hyper/toolstats/ToolStats.java @@ -96,6 +96,7 @@ public final class ToolStats extends JavaPlugin { * 3 = traded. * 4 = founded (for elytras). * 5 = fished. + * 6 = spawned in (creative). */ public final NamespacedKey originType = new NamespacedKey(this, "origin"); @@ -124,7 +125,7 @@ public final class ToolStats extends JavaPlugin { private BukkitAudiences adventure; public MorePaperLib morePaperLib; public HashMaker hashMaker; - + public CreativeEvent creativeEvent; @Override public void onEnable() { @@ -151,6 +152,7 @@ public final class ToolStats extends JavaPlugin { itemLore = new ItemLore(this); inventoryOpen = new InventoryOpen(this); playerJoin = new PlayerJoin(this); + creativeEvent = new CreativeEvent(this); Bukkit.getServer().getPluginManager().registerEvents(blocksMined, this); Bukkit.getServer().getPluginManager().registerEvents(chunkPopulate, this); @@ -165,6 +167,7 @@ public final class ToolStats extends JavaPlugin { Bukkit.getServer().getPluginManager().registerEvents(villagerTrade, this); Bukkit.getServer().getPluginManager().registerEvents(inventoryOpen, this); Bukkit.getServer().getPluginManager().registerEvents(playerJoin, this); + Bukkit.getServer().getPluginManager().registerEvents(creativeEvent, this); this.getCommand("toolstats").setExecutor(commandToolStats); diff --git a/src/main/java/lol/hyper/toolstats/commands/CommandToolStats.java b/src/main/java/lol/hyper/toolstats/commands/CommandToolStats.java index 2d25178..448accb 100644 --- a/src/main/java/lol/hyper/toolstats/commands/CommandToolStats.java +++ b/src/main/java/lol/hyper/toolstats/commands/CommandToolStats.java @@ -23,7 +23,9 @@ import lol.hyper.toolstats.tools.UUIDDataType; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; @@ -51,55 +53,55 @@ public class CommandToolStats implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (!sender.hasPermission("toolstats.command")) { - audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); return true; } if (args.length == 0) { - audiences.sender(sender).sendMessage(Component.text("ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.").color(NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.", NamedTextColor.GREEN)); return true; } switch (args[0]) { case "reload": { if (sender.hasPermission("toolstats.reload")) { toolStats.loadConfig(); - audiences.sender(sender).sendMessage(Component.text("Configuration reloaded!").color(NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("Configuration reloaded!", NamedTextColor.GREEN)); } else { - audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); } return true; } case "reset": { if (!sender.hasPermission("toolstats.reset")) { - audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); return true; } if (sender instanceof ConsoleCommandSender) { - audiences.sender(sender).sendMessage(Component.text("You must be a player for this command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You must be a player for this command.", NamedTextColor.RED)); return true; } if (args.length == 2 && args[1].equalsIgnoreCase("confirm")) { if (!sender.hasPermission("toolstats.reset.confirm")) { - audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); return true; } Player player = (Player) sender; ItemStack heldItem = player.getInventory().getItemInMainHand(); if (!ItemChecker.isValidItem(heldItem.getType())) { - audiences.sender(sender).sendMessage(Component.text("You must hold a valid item.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("You must hold a valid item.", NamedTextColor.RED)); return true; } fixItemLore(heldItem, player); - audiences.sender(sender).sendMessage(Component.text("The lore was reset!").color(NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("The lore was reset!", NamedTextColor.GREEN)); return true; } - audiences.sender(sender).sendMessage(Component.text("This will remove ALL current lore from the held item and replace it with the correct lore.").color(NamedTextColor.GREEN)); - audiences.sender(sender).sendMessage(Component.text("The item owner will be who ever is currently running this command.").color(NamedTextColor.GREEN)); - audiences.sender(sender).sendMessage(Component.text("Only use this if the tags on the tool are incorrect.").color(NamedTextColor.GREEN)); - audiences.sender(sender).sendMessage(Component.text("Type /toolstats reset confirm to confirm this.").color(NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("This will remove ALL current lore from the held item and replace it with the correct lore.", NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("If the owner of the item is broken, it will reset to the person holding it.", NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("Only use this if the tags on the tool are incorrect.", NamedTextColor.GREEN)); + audiences.sender(sender).sendMessage(Component.text("Type /toolstats reset confirm to confirm this.", NamedTextColor.GREEN)); return true; } default: { - audiences.sender(sender).sendMessage(Component.text("Invalid sub-command.").color(NamedTextColor.RED)); + audiences.sender(sender).sendMessage(Component.text("Invalid sub-command.", NamedTextColor.RED)); } } return true; @@ -123,9 +125,10 @@ public class CommandToolStats implements TabExecutor { String caughtByLore = toolStats.getLoreFromConfig("fished.caught-by", false); String lootedByLore = toolStats.getLoreFromConfig("looted.found-by", false); String tradedByLore = toolStats.getLoreFromConfig("traded.traded-by", false); + String spawnedByLore = toolStats.getLoreFromConfig("spawned.spawned-by", false); // make sure the config messages are not null - if (caughtByLore == null || lootedByLore == null || tradedByLore == null) { + if (caughtByLore == null || lootedByLore == null || tradedByLore == null || spawnedByLore == null) { return; } @@ -160,27 +163,46 @@ public class CommandToolStats implements TabExecutor { if (toolStats.checkConfig(original.getType(), "created-by")) { if (container.has(toolStats.genericOwner, new UUIDDataType())) { - container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId()); + UUID owner = container.get(toolStats.genericOwner, new UUIDDataType()); + String ownerName = null; + // if we can read the current owner + if (owner != null) { + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner); + ownerName = offlinePlayer.getName(); + } + + // if the owner's name is null for whatever reason, set the new owner + // to the current player running the command + if (ownerName == null) { + audiences.player(player).sendMessage(Component.text("The owner of this item is null. Setting to " + player.getName() + ".", NamedTextColor.RED)); + ownerName = player.getName(); + container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId()); + } + // show how the item was created based on the previous lore switch (origin) { case 0: { - lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", player.getName())); + lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", ownerName)); break; } case 2: { - lore.add(toolStats.getLoreFromConfig("looted.looted-by", true).replace("{player}", player.getName())); + lore.add(toolStats.getLoreFromConfig("looted.looted-by", true).replace("{player}", ownerName)); break; } case 3: { - lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName())); + lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", ownerName)); break; } case 4: { - lore.add(toolStats.getLoreFromConfig("looted.found-by", true).replace("{player}", player.getName())); + lore.add(toolStats.getLoreFromConfig("looted.found-by", true).replace("{player}", ownerName)); break; } case 5: { - lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName())); + lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", ownerName)); + break; + } + case 6: { + lore.add(toolStats.getLoreFromConfig("spawned.spawned-by", true).replace("{player}", ownerName)); break; } } @@ -212,6 +234,10 @@ public class CommandToolStats implements TabExecutor { lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time)))); break; } + case 6: { + lore.add(toolStats.getLoreFromConfig("spawned.spawned-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time)))); + break; + } } } } diff --git a/src/main/java/lol/hyper/toolstats/events/CreativeEvent.java b/src/main/java/lol/hyper/toolstats/events/CreativeEvent.java new file mode 100644 index 0000000..756dc57 --- /dev/null +++ b/src/main/java/lol/hyper/toolstats/events/CreativeEvent.java @@ -0,0 +1,111 @@ +/* + * 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.toolstats.ToolStats; +import lol.hyper.toolstats.tools.ItemChecker; +import lol.hyper.toolstats.tools.UUIDDataType; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryCreativeEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.util.Date; +import java.util.List; + +public class CreativeEvent implements Listener { + + private final ToolStats toolStats; + + public CreativeEvent(ToolStats toolStats) { + this.toolStats = toolStats; + } + + @EventHandler + public void onCreativeEvent(InventoryCreativeEvent event) { + Player player = (Player) event.getWhoClicked(); + // make sure they are in creative mode + if (player.getGameMode() != GameMode.CREATIVE) { + return; + } + ItemStack spawnedItem = event.getCursor(); + if (!ItemChecker.isValidItem(spawnedItem.getType())) { + return; + } + + ItemMeta spawnedItemMeta = spawnedItem.getItemMeta(); + if (spawnedItemMeta == null) { + return; + } + // if the item already has an origin set, don't add it again + // this is needed since you can spam click an item and the event will fire again + PersistentDataContainer container = spawnedItemMeta.getPersistentDataContainer(); + if (container.has(toolStats.originType, PersistentDataType.INTEGER)) { + return; + } + + // add the tags to the item + ItemStack newItem = addLore(spawnedItem, player); + if (newItem != null) { + event.setCursor(newItem); + } + } + + /** + * Adds tags to newly spawned items in creative. + * + * @param spawnedItem The item. + */ + private ItemStack addLore(ItemStack spawnedItem, Player owner) { + ItemStack newSpawnedItem = spawnedItem.clone(); + ItemMeta meta = newSpawnedItem.getItemMeta(); + if (meta == null) { + toolStats.logger.warning(newSpawnedItem + " does NOT have any meta! Unable to update stats."); + return null; + } + + long timeCreated = System.currentTimeMillis(); + Date finalDate = new Date(timeCreated); + PersistentDataContainer container = meta.getPersistentDataContainer(); + + // only make the hash if it's enabled + if (toolStats.config.getBoolean("generate-hash-for-items")) { + String hash = toolStats.hashMaker.makeHash(spawnedItem.getType(), owner.getUniqueId(), timeCreated); + container.set(toolStats.hash, PersistentDataType.STRING, hash); + } + + container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); + container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); + container.set(toolStats.originType, PersistentDataType.INTEGER, 6); + + String formattedDate = toolStats.numberFormat.formatDate(finalDate); + List newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate); + + if (toolStats.checkConfig(newSpawnedItem.getType(), "spawned-in")) { + meta.setLore(newLore); + } + + newSpawnedItem.setItemMeta(meta); + return newSpawnedItem; + } +} diff --git a/src/main/java/lol/hyper/toolstats/tools/ItemLore.java b/src/main/java/lol/hyper/toolstats/tools/ItemLore.java index 6923c1d..954a977 100644 --- a/src/main/java/lol/hyper/toolstats/tools/ItemLore.java +++ b/src/main/java/lol/hyper/toolstats/tools/ItemLore.java @@ -121,6 +121,11 @@ public class ItemLore { itemOwner = toolStats.getLoreFromConfig("fished.caught-by", true); break; } + case 6: { + dateCreated = toolStats.getLoreFromConfig("spawned.spawned-on", true); + itemOwner = toolStats.getLoreFromConfig("spawned.spawned-by", true); + break; + } } if (dateCreated == null || itemOwner == null) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e07987b..be66ed6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -65,6 +65,16 @@ enabled: axe: true hoe: true shears: true + # Will show "Spawned in by " + spawned-in: + pickaxe: true + sword: true + shovel: true + axe: true + hoe: true + shears: true + bow: true + armor: true fish-caught: true sheep-sheared: true armor-damage: true @@ -90,6 +100,9 @@ messages: kills: mob: "&7Mob kills: &8{kills}" player: "&7Player kills: &8{kills}" + spawned: + spawned-by: "&7Spawned in by: &8{player}" + spawned-on: "&7Spawned on: &8{date}" blocks-mined: "&7Blocks mined: &8{blocks}" crops-harvested: "&7Crops harvested: &8{crops}" sheep-sheared: "&7Sheep sheared: &8{sheep}"