Compare commits

..

17 Commits
1.1 ... 1.3

Author SHA1 Message Date
hyperdefined
adb1c637dc smh 2022-02-11 18:34:42 -05:00
hyperdefined
4b8f8061b4 Merge branch 'master' of https://github.com/hyperdefined/ToolStats 2022-02-11 15:09:49 -05:00
hyperdefined
464916e08b Update CommandToolStats.java 2022-02-11 15:09:32 -05:00
hyperdefined
6b6b65d1df Update README.md 2022-02-11 15:05:55 -05:00
hyperdefined
a1c39dffd0 Update pom.xml 2022-02-11 15:05:18 -05:00
hyperdefined
88eab81906 added tab completions to sub commands 2022-02-11 15:03:37 -05:00
hyperdefined
be233de90d fixed plugin.yml 2022-02-11 15:03:21 -05:00
hyperdefined
2437424e39 added reset lore command 2022-02-11 14:46:25 -05:00
hyperdefined
63b08062c8 Update CraftItem.java 2022-02-11 14:04:12 -05:00
hyperdefined
d23c2446dd fix fishing rods not updating lore correctly 2022-02-11 14:03:51 -05:00
hyperdefined
77b1be62d4 fixes 2022-02-10 21:41:23 -05:00
hyperdefined
29e6c998cf bump 2022-02-06 12:27:58 -05:00
hyperdefined
89951611fe changed api version to support more versions 2022-02-06 12:27:18 -05:00
hyperdefined
1c18a1a90c added missing check (fixes #2) 2022-02-05 16:42:42 -05:00
hyperdefined
f0ec409ef4 Update README.md 2022-01-31 17:40:51 -05:00
hyperdefined
0f9d75db06 Update pom.xml 2022-01-31 17:40:32 -05:00
hyperdefined
975445b8f3 support for custom lore messages 2022-01-31 17:40:10 -05:00
15 changed files with 491 additions and 77 deletions

View File

@@ -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.
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image2.png)

View File

@@ -23,7 +23,7 @@
<groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId>
<version>1.1</version>
<version>1.3</version>
<packaging>jar</packaging>
<name>ToolStats</name>

View File

@@ -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() {
@@ -200,4 +201,44 @@ public final class ToolStats extends JavaPlugin {
}
return false;
}
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;
}
}

View File

@@ -18,36 +18,232 @@
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;
}
private ItemStack fixItemLore(ItemStack original, Player player) {
ItemStack finalItem = original.clone();
ItemMeta finalMeta = finalItem.getItemMeta();
if (finalMeta == null) {
return null;
}
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);
if (caughtByLore == null || lootedByLore == null || tradedByLore == null) {
return null;
}
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());
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 null;
}
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-by", 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 null;
}
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 null;
}
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 null;
}
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 null;
}
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 null;
}
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 null;
}
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", Integer.toString(damage)));
}
}
finalMeta.setLore(lore);
finalItem.setItemMeta(finalMeta);
return finalItem;
}
@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;
}
}

View File

@@ -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,6 +44,9 @@ public class BlocksMined implements Listener {
@EventHandler
public void onBreak(BlockBreakEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer();
if (player.getGameMode() != GameMode.SURVIVAL) {
return;
@@ -78,6 +79,9 @@ 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);
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
@@ -85,21 +89,25 @@ public class BlocksMined implements Listener {
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
return;
}
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)));
}
if (toolStats.checkConfig(itemStack, "blocks-mined")) {
meta.setLore(lore);

View File

@@ -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,6 +47,9 @@ 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) {
@@ -57,6 +58,17 @@ public class CraftItem implements Listener {
String name = itemStack.getType().toString().toLowerCase(Locale.ROOT);
for (String x : validItems) {
if (name.contains(x)) {
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));
}
}
}
if (addLore(itemStack, player) == null) {
return;
}
event.setCurrentItem(addLore(itemStack, player));
}
}
@@ -71,8 +83,26 @@ public class CraftItem 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 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;
if (meta.hasLore()) {
lore = meta.getLore();
@@ -81,10 +111,10 @@ public class CraftItem implements Listener {
lore = new ArrayList<>();
}
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);

View File

@@ -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;
}
@@ -144,6 +143,9 @@ public class EntityDamage implements Listener {
@EventHandler
public void onDamage(EntityDamageByBlockEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity livingEntity = (LivingEntity) event.getEntity();
if (livingEntity instanceof Player) {
Player player = (Player) livingEntity;
@@ -174,6 +176,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,20 +192,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("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)));
}
if (toolStats.checkConfig(itemStack, "player-kills")) {
meta.setLore(lore);
@@ -222,6 +232,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,20 +248,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("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)));
}
if (toolStats.checkConfig(itemStack, "mob-kills")) {
meta.setLore(lore);
@@ -270,6 +288,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 +304,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);

View File

@@ -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;
@@ -64,14 +62,23 @@ public class EntityDeath implements Listener {
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 +87,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);

View File

@@ -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"
};
@@ -87,8 +84,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 +108,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);

View File

@@ -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();
@@ -78,6 +78,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 +95,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);

View File

@@ -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;
@@ -92,6 +91,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 +108,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);
@@ -129,8 +137,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 +161,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);

View File

@@ -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,6 +43,9 @@ 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)) {
@@ -77,6 +78,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 +95,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);

View File

@@ -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"
};
@@ -63,8 +62,17 @@ public class VillagerTrade implements Listener {
ItemStack item = event.getCurrentItem();
for (String x : validItems) {
if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
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;
}
Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5);
}
}
}
@@ -79,8 +87,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 +111,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);

View File

@@ -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

View File

@@ -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