mirror of
https://github.com/hyperdefined/ToolStats.git
synced 2025-12-06 06:41:44 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53fd7f734c | ||
|
|
75cd4fa17e | ||
|
|
e296c27a5b | ||
|
|
adb1c637dc | ||
|
|
4b8f8061b4 | ||
|
|
464916e08b | ||
|
|
6b6b65d1df | ||
|
|
a1c39dffd0 | ||
|
|
88eab81906 | ||
|
|
be233de90d | ||
|
|
2437424e39 | ||
|
|
63b08062c8 | ||
|
|
d23c2446dd | ||
|
|
77b1be62d4 | ||
|
|
29e6c998cf | ||
|
|
89951611fe | ||
|
|
1c18a1a90c | ||
|
|
f0ec409ef4 | ||
|
|
0f9d75db06 | ||
|
|
975445b8f3 |
@@ -1,7 +1,7 @@
|
||||
<h1 align="center">ToolStats</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Minecraft-1.18+-orange" alt="Minecraft versions">
|
||||
<img src="https://img.shields.io/badge/Minecraft-1.15+-orange" alt="Minecraft versions">
|
||||
<img src="https://img.shields.io/github/v/release/hyperdefined/ToolStats" alt="GitHub release (latest by date)">
|
||||
<a href="https://github.com/hyperdefined/ToolStats/releases"><img src="https://img.shields.io/github/downloads/hyperdefined/ToolStats/total?logo=github" alt="Downloads"></a>
|
||||
<a href="https://en.cryptobadges.io/donate/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL"><img src="https://en.cryptobadges.io/badge/micro/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL" alt="Donate with Bitcoin"></a>
|
||||
@@ -21,7 +21,9 @@ Here is everything it tracks:
|
||||
* Fish caught.
|
||||
* Sheep sheared.
|
||||
|
||||
The best part is, this data is stored on the item itself.
|
||||
The best part is, this data is stored on the item itself. You can also change how the lore is displayed on the items!
|
||||
|
||||
If item lore is ever incorrect, you can run `/toolstats reset` to reset the item lore so it's correct.
|
||||
|
||||

|
||||

|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -23,7 +23,7 @@
|
||||
|
||||
<groupId>lol.hyper</groupId>
|
||||
<artifactId>toolstats</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.3.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ToolStats</name>
|
||||
|
||||
@@ -23,6 +23,7 @@ import lol.hyper.toolstats.commands.CommandToolStats;
|
||||
import lol.hyper.toolstats.events.*;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@@ -73,7 +74,7 @@ public final class ToolStats extends JavaPlugin {
|
||||
public final Logger logger = this.getLogger();
|
||||
public final File configFile = new File(this.getDataFolder(), "config.yml");
|
||||
public FileConfiguration config;
|
||||
public final int CONFIG_VERSION = 2;
|
||||
public final int CONFIG_VERSION = 3;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@@ -151,6 +152,12 @@ public final class ToolStats extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the config to see if we want to show lore on certain items.
|
||||
* @param itemStack The item to check.
|
||||
* @param configName The config we are checking under.
|
||||
* @return If we want to allow lore or not.
|
||||
*/
|
||||
public boolean checkConfig(ItemStack itemStack, String configName) {
|
||||
String itemName = itemStack.getType().toString().toLowerCase();
|
||||
String itemType = null;
|
||||
@@ -200,4 +207,50 @@ public final class ToolStats extends JavaPlugin {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lore message from the config.
|
||||
* @param configName The config name, "messages." is already in front.
|
||||
* @param raw If you want the raw message with the formatting codes and placeholders.
|
||||
* @return The lore message.
|
||||
*/
|
||||
public String getLoreFromConfig(String configName, boolean raw) {
|
||||
String lore = config.getString("messages." + configName);
|
||||
if (lore == null) {
|
||||
return null;
|
||||
}
|
||||
if (raw) {
|
||||
return ChatColor.translateAlternateColorCodes('&', lore);
|
||||
} else {
|
||||
// we basically add the color codes then remove them
|
||||
// this is a dirty trick to remove color codes
|
||||
lore = ChatColor.translateAlternateColorCodes('&', lore);
|
||||
lore = ChatColor.stripColor(lore);
|
||||
if (lore.contains("{player}")) {
|
||||
lore = lore.replace("{player}", "");
|
||||
}
|
||||
if (lore.contains("{date}")) {
|
||||
lore = lore.replace("{date}", "");
|
||||
}
|
||||
if (lore.contains("{name}")) {
|
||||
lore = lore.replace("{name}", "");
|
||||
}
|
||||
if (lore.contains("{kills}")) {
|
||||
lore = lore.replace("{kills}", "");
|
||||
}
|
||||
if (lore.contains("{blocks}")) {
|
||||
lore = lore.replace("{blocks}", "");
|
||||
}
|
||||
if (lore.contains("{sheep}")) {
|
||||
lore = lore.replace("{sheep}", "");
|
||||
}
|
||||
if (lore.contains("{damage}")) {
|
||||
lore = lore.replace("{damage}", "");
|
||||
}
|
||||
if (lore.contains("{fish}")) {
|
||||
lore = lore.replace("{fish}", "");
|
||||
}
|
||||
}
|
||||
return lore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,36 +18,241 @@
|
||||
package lol.hyper.toolstats.commands;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import org.bukkit.ChatColor;
|
||||
import lol.hyper.toolstats.UUIDDataType;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CommandToolStats implements CommandExecutor {
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
public class CommandToolStats implements TabExecutor {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
|
||||
public CommandToolStats(ToolStats toolStats) {
|
||||
this.toolStats = toolStats;
|
||||
}
|
||||
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!sender.hasPermission("toolstats.use")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
|
||||
return true;
|
||||
}
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage(ChatColor.GREEN + "ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.");
|
||||
} else if (args.length == 1) {
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
}
|
||||
switch (args[0]) {
|
||||
case "reload": {
|
||||
if (sender.isOp() || sender.hasPermission("toolstats.reload")) {
|
||||
toolStats.loadConfig();
|
||||
sender.sendMessage(ChatColor.GREEN + "Configuration reloaded!");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
case "reset": {
|
||||
if (args.length == 2 && args[1].equalsIgnoreCase("confirm")) {
|
||||
Player player = (Player) sender;
|
||||
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
||||
if (heldItem.getType() == Material.AIR) {
|
||||
sender.sendMessage(ChatColor.RED + "You must hold an item!");
|
||||
return true;
|
||||
}
|
||||
fixItemLore(heldItem, player);
|
||||
sender.sendMessage(ChatColor.GREEN + "The lore was reset!");
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage(ChatColor.GREEN + "This will remove ALL current lore from the held item and replace it with the correct lore.");
|
||||
sender.sendMessage(ChatColor.GREEN + "The item owner will be who ever is currently running this command.");
|
||||
sender.sendMessage(ChatColor.GREEN + "Only use this if the tags on the tool are incorrect.");
|
||||
sender.sendMessage(ChatColor.GREEN + "Type /toolstats reset confirm to confirm this.");
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
sender.sendMessage(ChatColor.RED + "Invalid sub-command.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes lore on a given item. This will wipe all lore and reapply our custom ones.
|
||||
* @param original The item we are fixing.
|
||||
* @param player The player running the command.
|
||||
*/
|
||||
private void fixItemLore(ItemStack original, Player player) {
|
||||
ItemStack finalItem = original.clone();
|
||||
ItemMeta finalMeta = finalItem.getItemMeta();
|
||||
if (finalMeta == null) {
|
||||
return;
|
||||
}
|
||||
PersistentDataContainer container = finalMeta.getPersistentDataContainer();
|
||||
List<String> lore = new ArrayList<>();
|
||||
|
||||
String caughtByLore = toolStats.getLoreFromConfig("fished.caught-by", false);
|
||||
String lootedByLore = toolStats.getLoreFromConfig("looted.found-by", false);
|
||||
String tradedByLore = toolStats.getLoreFromConfig("traded.traded-by", false);
|
||||
|
||||
// make sure the config messages are not null
|
||||
if (caughtByLore == null || lootedByLore == null || tradedByLore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// determine how the item was originally created
|
||||
// this doesn't get saved, so we just rely on the lore
|
||||
// if there isn't a tag, default to crafted
|
||||
String type = "DEFAULT";
|
||||
if (finalMeta.hasLore()) {
|
||||
if (finalMeta.getLore() != null) {
|
||||
for (String line : finalMeta.getLore()) {
|
||||
if (line.contains(caughtByLore)) {
|
||||
type = "CAUGHT";
|
||||
}
|
||||
if (line.contains(lootedByLore)) {
|
||||
type = "LOOTED";
|
||||
}
|
||||
if (line.contains(tradedByLore)) {
|
||||
type = "TRADED";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toolStats.checkConfig(original, "created-by")) {
|
||||
if (container.has(toolStats.genericOwner, new UUIDDataType())) {
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
|
||||
// show how the item was created based on the previous lore
|
||||
switch (type) {
|
||||
case "DEFAULT": {
|
||||
lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", player.getName()));
|
||||
break;
|
||||
}
|
||||
case "CAUGHT": {
|
||||
lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName()));
|
||||
break;
|
||||
}
|
||||
case "LOOTED": {
|
||||
lore.add(toolStats.getLoreFromConfig("looted.looted-by", true).replace("{player}", player.getName()));
|
||||
break;
|
||||
}
|
||||
case "TRADED": {
|
||||
lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toolStats.checkConfig(original, "created-date")) {
|
||||
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
|
||||
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
|
||||
if (time == null) {
|
||||
return;
|
||||
}
|
||||
// show how when the item was created based on the previous lore
|
||||
switch (type) {
|
||||
case "DEFAULT": {
|
||||
lore.add(toolStats.getLoreFromConfig("created.created-on", true).replace("{date}", format.format(new Date(time))));
|
||||
break;
|
||||
}
|
||||
case "CAUGHT": {
|
||||
lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", format.format(new Date(time))));
|
||||
break;
|
||||
}
|
||||
case "LOOTED": {
|
||||
lore.add(toolStats.getLoreFromConfig("looted.looted-on", true).replace("{date}", format.format(new Date(time))));
|
||||
break;
|
||||
}
|
||||
case "TRADED": {
|
||||
lore.add(toolStats.getLoreFromConfig("traded.traded-on", true).replace("{date}", format.format(new Date(time))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toolStats.checkConfig(original, "player-kills")) {
|
||||
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
|
||||
Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
|
||||
if (kills == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("kills.player", true).replace("{kills}", Integer.toString(kills)));
|
||||
}
|
||||
}
|
||||
if (toolStats.checkConfig(original, "mob-kills")) {
|
||||
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
|
||||
Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
|
||||
if (kills == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("kills.mob", true).replace("{kills}", Integer.toString(kills)));
|
||||
}
|
||||
}
|
||||
if (toolStats.checkConfig(original, "blocks-mined")) {
|
||||
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
|
||||
Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
|
||||
if (blocksMined == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("blocks-mined", true).replace("{blocks}", Integer.toString(blocksMined)));
|
||||
}
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.fish-caught")) {
|
||||
if (container.has(toolStats.fishingRodCaught, PersistentDataType.INTEGER)) {
|
||||
Integer fish = container.get(toolStats.fishingRodCaught, PersistentDataType.INTEGER);
|
||||
if (fish == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("fished.fish-caught", true).replace("{fish}", Integer.toString(fish)));
|
||||
}
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
|
||||
if (container.has(toolStats.shearsSheared, PersistentDataType.INTEGER)) {
|
||||
Integer sheep = container.get(toolStats.shearsSheared, PersistentDataType.INTEGER);
|
||||
if (sheep == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("sheep-sheared", true).replace("{sheep}", Integer.toString(sheep)));
|
||||
}
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.armor-damage")) {
|
||||
if (container.has(toolStats.armorDamage, PersistentDataType.INTEGER)) {
|
||||
Integer damage = container.get(toolStats.armorDamage, PersistentDataType.INTEGER);
|
||||
if (damage == null) {
|
||||
return;
|
||||
}
|
||||
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", Integer.toString(damage)));
|
||||
}
|
||||
}
|
||||
finalMeta.setLore(lore);
|
||||
finalItem.setItemMeta(finalMeta);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
if (sender.hasPermission("toolstats.reload")) {
|
||||
return Arrays.asList("reset", "reload");
|
||||
} else {
|
||||
return Collections.singletonList("reset");
|
||||
}
|
||||
}
|
||||
if (args.length == 2) {
|
||||
if (args[0].equalsIgnoreCase("reset")) {
|
||||
return Collections.singletonList("confirm");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -38,7 +37,6 @@ public class BlocksMined implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String[] validTools = {"pickaxe", "axe", "hoe", "shovel", "shear"};
|
||||
private final String blocksMinedLore = ChatColor.GRAY + "Blocks mined: " + ChatColor.DARK_GRAY + "X";
|
||||
|
||||
public BlocksMined(ToolStats toolStats) {
|
||||
this.toolStats = toolStats;
|
||||
@@ -46,18 +44,25 @@ public class BlocksMined implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onBreak(BlockBreakEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Player player = event.getPlayer();
|
||||
// ignore creative mode
|
||||
if (player.getGameMode() != GameMode.SURVIVAL) {
|
||||
return;
|
||||
}
|
||||
// if the player mines something with their fist
|
||||
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
|
||||
if (heldItem == null || heldItem.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
// only check certain items
|
||||
String itemName = heldItem.getType().toString().toLowerCase();
|
||||
if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
|
||||
return;
|
||||
}
|
||||
// if it's an item we want, update the stats
|
||||
updateBlocksMined(heldItem);
|
||||
}
|
||||
|
||||
@@ -66,6 +71,8 @@ public class BlocksMined implements Listener {
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
// read the current stats from the item
|
||||
// if they don't exist, then start from 0
|
||||
Integer blocksMined = 0;
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
|
||||
@@ -78,6 +85,14 @@ public class BlocksMined implements Listener {
|
||||
}
|
||||
container.set(toolStats.genericMined, PersistentDataType.INTEGER, blocksMined);
|
||||
|
||||
String configLore = toolStats.getLoreFromConfig("blocks-mined", false);
|
||||
String configLoreRaw = toolStats.getLoreFromConfig("blocks-mined", true);
|
||||
|
||||
if (configLore == null || configLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -86,21 +101,22 @@ public class BlocksMined implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Blocks mined")) {
|
||||
if (lore.get(x).contains(configLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, blocksMinedLore.replace("X", Integer.toString(blocksMined)));
|
||||
lore.set(x, configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(blocksMinedLore.replace("X", Integer.toString(blocksMined)));
|
||||
lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(blocksMinedLore.replace("X", Integer.toString(blocksMined)));
|
||||
lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
|
||||
}
|
||||
// do we add the lore based on the config?
|
||||
if (toolStats.checkConfig(itemStack, "blocks-mined")) {
|
||||
meta.setLore(lore);
|
||||
}
|
||||
|
||||
@@ -53,14 +53,17 @@ public class ChunkPopulate implements Listener {
|
||||
Bukkit.getScheduler().runTaskLater(toolStats, () -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
// if there is a new item frame
|
||||
if (entity instanceof ItemFrame) {
|
||||
ItemFrame itemFrame = (ItemFrame) entity;
|
||||
// if the item frame has an elytra
|
||||
if (itemFrame.getItem().getType() == Material.ELYTRA) {
|
||||
ItemStack elytraCopy = itemFrame.getItem();
|
||||
ItemMeta meta = elytraCopy.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
// add the new tag so we know it's new
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
container.set(toolStats.newElytra, PersistentDataType.INTEGER, 1);
|
||||
elytraCopy.setItemMeta(meta);
|
||||
|
||||
@@ -39,8 +39,6 @@ public class CraftItem implements Listener {
|
||||
public final String[] validItems = {
|
||||
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
|
||||
};
|
||||
private final String timeCreatedLore = ChatColor.GRAY + "Crafted on: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String ownerLore = ChatColor.GRAY + "Crafted by: " + ChatColor.DARK_GRAY + "X";
|
||||
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
|
||||
|
||||
public CraftItem(ToolStats toolStats) {
|
||||
@@ -49,42 +47,90 @@ public class CraftItem implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onCraft(CraftItemEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
ItemStack itemStack = event.getCurrentItem();
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
String name = itemStack.getType().toString().toLowerCase(Locale.ROOT);
|
||||
// only check for items we want
|
||||
for (String x : validItems) {
|
||||
if (name.contains(x)) {
|
||||
// if the player shift clicks, send them this warning
|
||||
if (event.isShiftClick()) {
|
||||
String configMessage = toolStats.config.getString("messages.shift-click-warning.crafting");
|
||||
if (configMessage != null) {
|
||||
if (configMessage.length() != 0) {
|
||||
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
// test the item before setting it
|
||||
if (addLore(itemStack, player) == null) {
|
||||
return;
|
||||
}
|
||||
// set the result
|
||||
event.setCurrentItem(addLore(itemStack, player));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds crafted tags to item.
|
||||
* @param itemStack The item add item to.
|
||||
* @param owner The player crafting.
|
||||
* @return A copy of the item with the tags + lore.
|
||||
*/
|
||||
private ItemStack addLore(ItemStack itemStack, Player owner) {
|
||||
// clone the item
|
||||
ItemStack newItem = itemStack.clone();
|
||||
ItemMeta meta = newItem.getItemMeta();
|
||||
if (meta == null) {
|
||||
return null;
|
||||
}
|
||||
// get the current time
|
||||
long timeCreated = System.currentTimeMillis();
|
||||
Date finalDate = new Date(timeCreated);
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
|
||||
// if the item already has the tag
|
||||
// this is to prevent duplicate tags
|
||||
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
|
||||
|
||||
String createdByRaw = toolStats.getLoreFromConfig("created.created-by", true);
|
||||
String createdOnRaw = toolStats.getLoreFromConfig("created.created-on", true);
|
||||
|
||||
if (createdOnRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.created.created-on!");
|
||||
return null;
|
||||
}
|
||||
if (createdByRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.created.created-by!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
// get the current lore the item
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
assert lore != null;
|
||||
} else {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
// do we add the lore based on the config?
|
||||
if (toolStats.checkConfig(itemStack, "created-date")) {
|
||||
lore.add(timeCreatedLore.replace("X", format.format(finalDate)));
|
||||
lore.add(createdOnRaw.replace("{date}", format.format(finalDate)));
|
||||
}
|
||||
if (toolStats.checkConfig(itemStack, "created-by")) {
|
||||
lore.add(ownerLore.replace("X", owner.getName()));
|
||||
lore.add(createdByRaw.replace("{player}", owner.getName()));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
newItem.setItemMeta(meta);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.*;
|
||||
@@ -41,9 +40,6 @@ public class EntityDamage implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String[] validTools = {"sword", "trident", "axe"};
|
||||
private final String playerKillsLore = ChatColor.GRAY + "Player kills: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String mobKillsLore = ChatColor.GRAY + "Mob kills: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String damageTakenLore = ChatColor.GRAY + "Damage taken: " + ChatColor.DARK_GRAY + "X";
|
||||
private final DecimalFormat decimalFormat = new DecimalFormat("0.00");
|
||||
public final Set<UUID> trackedMobs = new HashSet<>();
|
||||
|
||||
@@ -53,6 +49,9 @@ public class EntityDamage implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageByEntityEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getEntity() instanceof LivingEntity)) {
|
||||
return;
|
||||
}
|
||||
@@ -65,10 +64,12 @@ public class EntityDamage implements Listener {
|
||||
if (player.getGameMode() != GameMode.SURVIVAL) {
|
||||
return;
|
||||
}
|
||||
// a player killed something with their fist
|
||||
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
|
||||
if (heldItem == null || heldItem.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
// check items we want
|
||||
String itemName = heldItem.getType().toString().toLowerCase();
|
||||
if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
|
||||
return;
|
||||
@@ -82,9 +83,11 @@ public class EntityDamage implements Listener {
|
||||
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updateMobKills(heldItem));
|
||||
trackedMobs.add(livingEntity.getUniqueId());
|
||||
}
|
||||
// trident is being thrown at something
|
||||
if (event.getDamager() instanceof Trident) {
|
||||
Trident trident = (Trident) event.getDamager();
|
||||
ItemStack clone;
|
||||
// trident is killing player
|
||||
if (livingEntity instanceof Player) {
|
||||
clone = updatePlayerKills(trident.getItem());
|
||||
} else {
|
||||
@@ -95,14 +98,18 @@ public class EntityDamage implements Listener {
|
||||
}
|
||||
trident.setItem(clone);
|
||||
}
|
||||
// arrow is being shot
|
||||
if (event.getDamager() instanceof Arrow) {
|
||||
Arrow arrow = (Arrow) event.getDamager();
|
||||
// if the shooter is a player
|
||||
if (arrow.getShooter() instanceof Player) {
|
||||
Player player = (Player) arrow.getShooter();
|
||||
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
|
||||
if (heldItem == null) {
|
||||
return;
|
||||
}
|
||||
// if the player is holding the bow/crossbow
|
||||
// if they switch then oh well
|
||||
if (heldItem.getType() == Material.BOW || heldItem.getType() == Material.CROSSBOW) {
|
||||
if (livingEntity instanceof Player) {
|
||||
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updatePlayerKills(heldItem));
|
||||
@@ -131,6 +138,7 @@ public class EntityDamage implements Listener {
|
||||
return;
|
||||
}
|
||||
LivingEntity livingEntity = (LivingEntity) event.getEntity();
|
||||
// player is taken damage but not being killed
|
||||
if (livingEntity instanceof Player) {
|
||||
Player player = (Player) livingEntity;
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
@@ -144,7 +152,11 @@ public class EntityDamage implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageByBlockEvent event) {
|
||||
if (!(event.getEntity() instanceof LivingEntity)) {
|
||||
return;
|
||||
}
|
||||
LivingEntity livingEntity = (LivingEntity) event.getEntity();
|
||||
// player is taken damage but not being killed
|
||||
if (livingEntity instanceof Player) {
|
||||
Player player = (Player) livingEntity;
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
@@ -156,6 +168,11 @@ public class EntityDamage implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a weapon's player kills.
|
||||
* @param itemStack The item to update.
|
||||
* @return A copy of the item.
|
||||
*/
|
||||
private ItemStack updatePlayerKills(ItemStack itemStack) {
|
||||
ItemStack finalItem = itemStack.clone();
|
||||
ItemMeta meta = finalItem.getItemMeta();
|
||||
@@ -174,6 +191,14 @@ public class EntityDamage implements Listener {
|
||||
}
|
||||
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills);
|
||||
|
||||
String playerKillsLore = toolStats.getLoreFromConfig("kills.player", false);
|
||||
String playerKillsLoreRaw = toolStats.getLoreFromConfig("kills.player", true);
|
||||
|
||||
if (playerKillsLore == null || playerKillsLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.kills.player!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -182,21 +207,22 @@ public class EntityDamage implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Player kills")) {
|
||||
if (lore.get(x).contains(playerKillsLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, playerKillsLore.replace("X", Integer.toString(playerKills)));
|
||||
lore.set(x, playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(playerKillsLore.replace("X", Integer.toString(playerKills)));
|
||||
lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(playerKillsLore.replace("X", Integer.toString(playerKills)));
|
||||
lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
|
||||
}
|
||||
// do we add the lore based on the config?
|
||||
if (toolStats.checkConfig(itemStack, "player-kills")) {
|
||||
meta.setLore(lore);
|
||||
}
|
||||
@@ -204,6 +230,11 @@ public class EntityDamage implements Listener {
|
||||
return finalItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a weapon's mob kills.
|
||||
* @param itemStack The item to update.
|
||||
* @return A copy of the item.
|
||||
*/
|
||||
private ItemStack updateMobKills(ItemStack itemStack) {
|
||||
ItemStack finalItem = itemStack.clone();
|
||||
ItemMeta meta = finalItem.getItemMeta();
|
||||
@@ -222,6 +253,14 @@ public class EntityDamage implements Listener {
|
||||
}
|
||||
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills);
|
||||
|
||||
String mobKillsLore = toolStats.getLoreFromConfig("kills.mob", false);
|
||||
String mobKillsLoreRaw = toolStats.getLoreFromConfig("kills.mob", true);
|
||||
|
||||
if (mobKillsLore == null || mobKillsLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.kills.mob!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -230,21 +269,22 @@ public class EntityDamage implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Mob kills")) {
|
||||
if (lore.get(x).contains(mobKillsLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, mobKillsLore.replace("X", Integer.toString(mobKills)));
|
||||
lore.set(x, mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(mobKillsLore.replace("X", Integer.toString(mobKills)));
|
||||
lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(mobKillsLore.replace("X", Integer.toString(mobKills)));
|
||||
lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
|
||||
}
|
||||
// do we add the lore based on the config?
|
||||
if (toolStats.checkConfig(itemStack, "mob-kills")) {
|
||||
meta.setLore(lore);
|
||||
}
|
||||
@@ -252,6 +292,11 @@ public class EntityDamage implements Listener {
|
||||
return finalItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a player's armor damage stats.
|
||||
* @param itemStack The armor piece.
|
||||
* @param damage How much damage is being added.
|
||||
*/
|
||||
private void updateArmorDamage(ItemStack itemStack, double damage) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -270,6 +315,14 @@ public class EntityDamage implements Listener {
|
||||
decimalFormat.setRoundingMode(RoundingMode.DOWN);
|
||||
container.set(toolStats.armorDamage, PersistentDataType.DOUBLE, damageTaken);
|
||||
|
||||
String damageTakenLore = toolStats.getLoreFromConfig("damage-taken", false);
|
||||
String damageTakenLoreRaw = toolStats.getLoreFromConfig("damage-taken", true);
|
||||
|
||||
if (damageTakenLore == null || damageTakenLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.damage-taken!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -278,20 +331,20 @@ public class EntityDamage implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Damage taken")) {
|
||||
if (lore.get(x).contains(damageTakenLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, damageTakenLore.replace("X", decimalFormat.format(damageTaken)));
|
||||
lore.set(x, damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(damageTakenLore.replace("X", decimalFormat.format(damageTaken)));
|
||||
lore.add(damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(damageTakenLore.replace("X", decimalFormat.format(damageTaken)));
|
||||
lore.add(damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.armor-damage")) {
|
||||
meta.setLore(lore);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -32,7 +31,6 @@ import java.util.*;
|
||||
public class EntityDeath implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String droppedLore = ChatColor.GRAY + "Dropped by: " + ChatColor.DARK_GRAY + "X";
|
||||
|
||||
public EntityDeath(ToolStats toolStats) {
|
||||
this.toolStats = toolStats;
|
||||
@@ -45,6 +43,7 @@ public class EntityDeath implements Listener {
|
||||
return;
|
||||
}
|
||||
UUID livingEntityUUID = event.getEntity().getUniqueId();
|
||||
// if it's a mob we are tracking that matters
|
||||
if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) {
|
||||
for (ItemStack current : event.getDrops()) {
|
||||
String name = current.getType().toString().toLowerCase(Locale.ROOT);
|
||||
@@ -58,20 +57,34 @@ public class EntityDeath implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds "drop by" tag to item.
|
||||
* @param itemStack The item to add lore to.
|
||||
* @param mob The mob or player name.
|
||||
*/
|
||||
private void addLore(ItemStack itemStack, String mob) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
boolean hasTag = false;
|
||||
|
||||
String droppedByLore = toolStats.getLoreFromConfig("dropped-by", false);
|
||||
String droppedByLoreRaw = toolStats.getLoreFromConfig("dropped-by", true);
|
||||
|
||||
if (droppedByLore == null || droppedByLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.dropped-by!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
assert lore != null;
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Dropped by")) {
|
||||
if (lore.get(x).contains(droppedByLore)) {
|
||||
// replace existing tag
|
||||
lore.set(x, droppedLore.replace("X", mob));
|
||||
lore.set(x, droppedByLoreRaw.replace("{name}", mob));
|
||||
hasTag = true;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +93,7 @@ public class EntityDeath implements Listener {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
if (!hasTag) {
|
||||
lore.add(droppedLore.replace("X", mob));
|
||||
lore.add(droppedByLoreRaw.replace("{name}", mob));
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.dropped-by")) {
|
||||
meta.setLore(lore);
|
||||
|
||||
@@ -20,7 +20,6 @@ package lol.hyper.toolstats.events;
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import lol.hyper.toolstats.UUIDDataType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -42,8 +41,6 @@ import java.util.Locale;
|
||||
public class GenerateLoot implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String LOOT_OWNER = ChatColor.GRAY + "Looted by: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String LOOT_TIME = ChatColor.GRAY + "Looted on: " + ChatColor.DARK_GRAY + "X";
|
||||
public final String[] validItems = {
|
||||
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
|
||||
};
|
||||
@@ -60,10 +57,13 @@ public class GenerateLoot implements Listener {
|
||||
return;
|
||||
}
|
||||
Inventory chest = inventoryHolder.getInventory();
|
||||
// run task later since if it runs on the same tick it breaks idk
|
||||
Bukkit.getScheduler().runTaskLater(toolStats, () -> {
|
||||
Player player = (Player) chest.getViewers().get(0);
|
||||
// do a classic for loot so we keep track of chest index of item
|
||||
for (int i = 0; i < chest.getContents().length; i++) {
|
||||
ItemStack itemStack = chest.getItem(i);
|
||||
// ignore air
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR) {
|
||||
continue;
|
||||
}
|
||||
@@ -78,6 +78,12 @@ public class GenerateLoot implements Listener {
|
||||
},1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 addLore(ItemStack itemStack, Player owner) {
|
||||
ItemStack newItem = itemStack.clone();
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
@@ -87,8 +93,22 @@ public class GenerateLoot implements Listener {
|
||||
long timeCreated = System.currentTimeMillis();
|
||||
Date finalDate = new Date(timeCreated);
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
|
||||
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
|
||||
|
||||
String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true);
|
||||
String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true);
|
||||
|
||||
if (foundByLoreRaw == null || foundOnLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.looted!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -97,8 +117,8 @@ public class GenerateLoot implements Listener {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
if (toolStats.checkConfig(newItem, "looted-tag")) {
|
||||
lore.add(LOOT_TIME.replace("X", format.format(finalDate)));
|
||||
lore.add(LOOT_OWNER.replace("X", owner.getName()));
|
||||
lore.add(foundOnLoreRaw.replace("{date}", format.format(finalDate)));
|
||||
lore.add(foundByLoreRaw.replace("{player}", owner.getName()));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
newItem.setItemMeta(meta);
|
||||
|
||||
@@ -19,7 +19,6 @@ package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import lol.hyper.toolstats.UUIDDataType;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -40,8 +39,6 @@ import java.util.Locale;
|
||||
public class PickupItem implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String FOUND_BY = ChatColor.GRAY + "Found by: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String FOUND_ON = ChatColor.GRAY + "Found on: " + ChatColor.DARK_GRAY + "X";
|
||||
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
|
||||
|
||||
public PickupItem(ToolStats toolStats) {
|
||||
@@ -50,6 +47,9 @@ public class PickupItem implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPickup(EntityPickupItemEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Entity entity = event.getEntity();
|
||||
if (entity instanceof Player) {
|
||||
ItemStack itemStack = event.getItem().getItemStack();
|
||||
@@ -68,6 +68,11 @@ public class PickupItem implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds "looted by" tags for elytras.
|
||||
* @param itemStack The elytra to add lore to.
|
||||
* @param owner The player who found it.
|
||||
*/
|
||||
private void addLore(ItemStack itemStack, Player owner) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -78,6 +83,15 @@ public class PickupItem implements Listener {
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
|
||||
|
||||
String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true);
|
||||
String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true);
|
||||
|
||||
if (foundByLoreRaw == null || foundOnLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.looted!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -86,8 +100,8 @@ public class PickupItem implements Listener {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.elytra-tag")) {
|
||||
lore.add(FOUND_ON.replace("X", format.format(finalDate)));
|
||||
lore.add(FOUND_BY.replace("X", owner.getName()));
|
||||
lore.add(foundOnLoreRaw.replace("{date}", format.format(finalDate)));
|
||||
lore.add(foundByLoreRaw.replace("{player}", owner.getName()));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
@@ -19,7 +19,6 @@ package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import lol.hyper.toolstats.UUIDDataType;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -40,9 +39,6 @@ import java.util.Locale;
|
||||
public class PlayerFish implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String fishCaughtLore = ChatColor.GRAY + "Fish caught: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String FISH_OWNER = ChatColor.GRAY + "Caught by: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String FISH_TIME = ChatColor.GRAY + "Caught on: " + ChatColor.DARK_GRAY + "X";
|
||||
public final String[] validItems = {
|
||||
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
|
||||
};
|
||||
@@ -54,6 +50,9 @@ public class PlayerFish implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onFish(PlayerFishEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
// only listen to when a player catches a fish
|
||||
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) {
|
||||
return;
|
||||
@@ -76,6 +75,10 @@ public class PlayerFish implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a fishing rod's count.
|
||||
* @param itemStack The fishing rod to update.
|
||||
*/
|
||||
private void updateFishCount(ItemStack itemStack) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -92,6 +95,15 @@ public class PlayerFish implements Listener {
|
||||
fishCaught++;
|
||||
}
|
||||
container.set(toolStats.fishingRodCaught, PersistentDataType.INTEGER, fishCaught);
|
||||
|
||||
String fishCaughtLore = toolStats.getLoreFromConfig("fished.fish-caught", false);
|
||||
String fishCaughtLoreRaw = toolStats.getLoreFromConfig("fished.fish-caught", true);
|
||||
|
||||
if (fishCaughtLore == null || fishCaughtLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.fish-caught!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -100,20 +112,20 @@ public class PlayerFish implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Fish caught")) {
|
||||
if (lore.get(x).contains(fishCaughtLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, fishCaughtLore.replace("X", Integer.toString(fishCaught)));
|
||||
lore.set(x, fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(fishCaughtLore.replace("X", Integer.toString(fishCaught)));
|
||||
lore.add(fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(fishCaughtLore.replace("X", Integer.toString(fishCaught)));
|
||||
lore.add(fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.fish-caught")) {
|
||||
meta.setLore(lore);
|
||||
@@ -121,6 +133,11 @@ public class PlayerFish implements Listener {
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds "caught by" tags to newly fished items.
|
||||
* @param itemStack The item to add lore to.
|
||||
* @param owner The player who caught the item.
|
||||
*/
|
||||
private void addNewLore(ItemStack itemStack, Player owner) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -129,8 +146,22 @@ public class PlayerFish implements Listener {
|
||||
long timeCreated = System.currentTimeMillis();
|
||||
Date finalDate = new Date(timeCreated);
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
|
||||
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
|
||||
|
||||
String caughtByLoreRaw = toolStats.getLoreFromConfig("fished.caught-by", true);
|
||||
String caughtOnLoreRaw = toolStats.getLoreFromConfig("fished.caught-on", true);
|
||||
|
||||
if (caughtByLoreRaw == null || caughtOnLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.fished!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -139,8 +170,8 @@ public class PlayerFish implements Listener {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
if (toolStats.checkConfig(itemStack, "fished-tag")) {
|
||||
lore.add(FISH_TIME.replace("X", format.format(finalDate)));
|
||||
lore.add(FISH_OWNER.replace("X", owner.getName()));
|
||||
lore.add(caughtOnLoreRaw.replace("{date}", format.format(finalDate)));
|
||||
lore.add(caughtByLoreRaw.replace("{player}", owner.getName()));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -37,7 +36,6 @@ import java.util.List;
|
||||
public class SheepShear implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String sheepShearLore = ChatColor.GRAY + "Sheep sheared: " + ChatColor.DARK_GRAY + "X";
|
||||
|
||||
public SheepShear(ToolStats toolStats) {
|
||||
this.toolStats = toolStats;
|
||||
@@ -45,22 +43,31 @@ public class SheepShear implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onShear(PlayerInteractEntityEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Player player = event.getPlayer();
|
||||
Entity entity = event.getRightClicked();
|
||||
if (!(entity instanceof Sheep)) {
|
||||
return;
|
||||
}
|
||||
// check if the player is right-clicking with shears only
|
||||
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
|
||||
if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.SHEARS) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sheep sheep = (Sheep) entity;
|
||||
// make sure the sheep is not sheared
|
||||
if (!sheep.isSheared()) {
|
||||
addLore(heldItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tags to shears.
|
||||
* @param itemStack The shears.
|
||||
*/
|
||||
private void addLore(ItemStack itemStack) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -77,6 +84,15 @@ public class SheepShear implements Listener {
|
||||
sheepSheared++;
|
||||
}
|
||||
container.set(toolStats.shearsSheared, PersistentDataType.INTEGER, sheepSheared);
|
||||
|
||||
String sheepShearedLore = toolStats.getLoreFromConfig("sheep-sheared", false);
|
||||
String sheepShearedLoreRaw = toolStats.getLoreFromConfig("sheep-sheared", true);
|
||||
|
||||
if (sheepShearedLore == null || sheepShearedLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.sheep-sheared!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -85,20 +101,20 @@ public class SheepShear implements Listener {
|
||||
// we do a for loop like this, we can keep track of index
|
||||
// this doesn't mess the lore up of existing items
|
||||
for (int x = 0; x < lore.size(); x++) {
|
||||
if (lore.get(x).contains("Sheep sheared")) {
|
||||
if (lore.get(x).contains(sheepShearedLore)) {
|
||||
hasLore = true;
|
||||
lore.set(x, sheepShearLore.replace("X", Integer.toString(sheepSheared)));
|
||||
lore.set(x, sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the item has lore but doesn't have the tag, add it
|
||||
if (!hasLore) {
|
||||
lore.add(sheepShearLore.replace("X", Integer.toString(sheepSheared)));
|
||||
lore.add(sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
|
||||
}
|
||||
} else {
|
||||
// if the item has no lore, create a new list and add the string
|
||||
lore = new ArrayList<>();
|
||||
lore.add(sheepShearLore.replace("X", Integer.toString(sheepSheared)));
|
||||
lore.add(sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
|
||||
}
|
||||
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
|
||||
meta.setLore(lore);
|
||||
|
||||
@@ -19,6 +19,7 @@ package lol.hyper.toolstats.events;
|
||||
|
||||
import lol.hyper.toolstats.ToolStats;
|
||||
import lol.hyper.toolstats.UUIDDataType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -41,8 +42,6 @@ import java.util.Locale;
|
||||
public class VillagerTrade implements Listener {
|
||||
|
||||
private final ToolStats toolStats;
|
||||
private final String TRADED_OWNER = ChatColor.GRAY + "Traded by: " + ChatColor.DARK_GRAY + "X";
|
||||
private final String TRADED_TIME = ChatColor.GRAY + "Traded on: " + ChatColor.DARK_GRAY + "X";
|
||||
public final String[] validItems = {
|
||||
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
|
||||
};
|
||||
@@ -58,19 +57,40 @@ public class VillagerTrade implements Listener {
|
||||
return;
|
||||
}
|
||||
Inventory inventory = event.getClickedInventory();
|
||||
// only check villager inventories
|
||||
if (inventory instanceof MerchantInventory) {
|
||||
// only check the result slot (the item you receive)
|
||||
if (event.getSlotType() == InventoryType.SlotType.RESULT) {
|
||||
ItemStack item = event.getCurrentItem();
|
||||
// only check items we want
|
||||
for (String x : validItems) {
|
||||
if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
|
||||
// if the player shift clicks show the warning
|
||||
if (event.isShiftClick()) {
|
||||
String configMessage = toolStats.config.getString("messages.shift-click-warning.trading");
|
||||
if (configMessage != null) {
|
||||
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
|
||||
}
|
||||
}
|
||||
ItemStack newItem = addLore(item, (Player) event.getWhoClicked());
|
||||
event.getView().setCursor(newItem);
|
||||
if (newItem == null) {
|
||||
return;
|
||||
}
|
||||
// this gets delayed since villager inventories suck for no reason
|
||||
// if you don't delay this it doesn't work idk
|
||||
Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds "traded by" tags to item.
|
||||
* @param itemStack The item to add lore.
|
||||
* @param owner The player who traded.
|
||||
* @return The item with lore.
|
||||
*/
|
||||
private ItemStack addLore(ItemStack itemStack, Player owner) {
|
||||
ItemMeta meta = itemStack.getItemMeta();
|
||||
if (meta == null) {
|
||||
@@ -79,8 +99,22 @@ public class VillagerTrade implements Listener {
|
||||
long timeCreated = System.currentTimeMillis();
|
||||
Date finalDate = new Date(timeCreated);
|
||||
PersistentDataContainer container = meta.getPersistentDataContainer();
|
||||
|
||||
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
|
||||
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
|
||||
|
||||
String tradedByLoreRaw = toolStats.getLoreFromConfig("traded.traded-by", true);
|
||||
String tradedOnLoreRaw = toolStats.getLoreFromConfig("traded.traded-on", true);
|
||||
|
||||
if (tradedByLoreRaw == null || tradedOnLoreRaw == null) {
|
||||
toolStats.logger.warning("There is no lore message for messages.traded!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> lore;
|
||||
if (meta.hasLore()) {
|
||||
lore = meta.getLore();
|
||||
@@ -89,8 +123,8 @@ public class VillagerTrade implements Listener {
|
||||
lore = new ArrayList<>();
|
||||
}
|
||||
if (toolStats.checkConfig(itemStack, "traded-tag")) {
|
||||
lore.add(TRADED_TIME.replace("X", format.format(finalDate)));
|
||||
lore.add(TRADED_OWNER.replace("X", owner.getName()));
|
||||
lore.add(tradedOnLoreRaw.replace("{date}", format.format(finalDate)));
|
||||
lore.add(tradedByLoreRaw.replace("{player}", owner.getName()));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
@@ -71,4 +71,31 @@ enabled:
|
||||
dropped-by: true
|
||||
elytra-tag: true
|
||||
|
||||
config-version: 2
|
||||
messages:
|
||||
created:
|
||||
created-by: "&7Crafted by: &8{player}"
|
||||
created-on: "&7Crafted on: &8{date}"
|
||||
fished:
|
||||
caught-by: "&7Caught by: &8{player}"
|
||||
caught-on: "&7Caught on: &8{date}"
|
||||
fish-caught: "&7Fish caught: &8{fish}"
|
||||
looted:
|
||||
found-by: "&7Found by: &8{player}"
|
||||
found-on: "&7Found on: &8{date}"
|
||||
traded:
|
||||
traded-by: "&7Traded by: &8{player}"
|
||||
traded-on: "&7Traded on: &8{date}"
|
||||
kills:
|
||||
mob: "&7Mob kills: &8{kills}"
|
||||
player: "&7Player kills: &8{kills}"
|
||||
blocks-mined: "&7Blocks mined: &8{blocks}"
|
||||
sheep-sheared: "&7Sheep sheared: &8{sheep}"
|
||||
dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name
|
||||
damage-taken: "&7Damage taken: &8{damage}"
|
||||
# Display this message if the player shift click trades/crafts items. It's not really easy to get every single item
|
||||
# that is crafted. The tag will only be added to the first item. If you don't want this message, simply replace them both with ""
|
||||
shift-click-warning:
|
||||
crafting: "&cCrafting items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
|
||||
trading: "&cTrading items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
|
||||
|
||||
config-version: 3
|
||||
@@ -1,15 +1,18 @@
|
||||
name: ToolStats
|
||||
version: '${project.version}'
|
||||
main: lol.hyper.toolstats.ToolStats
|
||||
api-version: 1.18
|
||||
api-version: 1.15
|
||||
author: hyperdefined
|
||||
description: Track various tool stats!
|
||||
commands:
|
||||
toolstats:
|
||||
usage: /toolstats
|
||||
description: Main command.
|
||||
permission: randomenchant.reload
|
||||
permission: toolstats.main
|
||||
permissions:
|
||||
randomenchant.reload:
|
||||
description: Allows the usage of /randomenchant reload
|
||||
toolstats.main:
|
||||
description: Allows the usage of /toolstats
|
||||
default: true
|
||||
toolstats.reload:
|
||||
description: Allows the usage of /toolstats reload
|
||||
default: op
|
||||
Reference in New Issue
Block a user