Compare commits

...

32 Commits

Author SHA1 Message Date
hyperdefined
67d141c452 Update README.md 2025-05-07 18:10:52 -04:00
hyperdefined
c1300e916f Update pom.xml 2025-05-07 18:01:03 -04:00
hyperdefined
6d6f1aab8a add allow-creative 2025-05-07 17:58:44 -04:00
hyperdefined
b2ef154cc6 add dropped-by 2025-05-07 17:51:54 -04:00
hyperdefined
bc8f4948fe add normalize-time-creation 2025-05-06 20:29:27 -04:00
hyperdefined
70e19269ee rename many config things 2025-05-06 20:05:13 -04:00
hyperdefined
5373792480 new perms and suggestions 2025-05-06 18:42:52 -04:00
hyperdefined
f71d079e23 add remove ability 2025-05-06 18:36:17 -04:00
hyperdefined
bcb85c7a28 add edit ability 2025-05-06 17:07:57 -04:00
hyperdefined
1e4e963fe1 remove debug 2025-04-07 11:00:55 -04:00
hyperdefined
298a8dd592 Update pom.xml 2025-04-07 10:57:27 -04:00
hyperdefined
49a3c03f94 typing with paws is hard 2025-04-07 10:56:51 -04:00
hyperdefined
ecd241ac52 fix #99 2025-04-07 10:56:25 -04:00
hyperdefined
5a1be37339 remove token if stat is disabled
this was missing prior
2025-04-07 10:56:13 -04:00
hyperdefined
a07782df5b added missing stat for reset command 2025-04-07 10:55:17 -04:00
hyperdefined
31123fdfd5 woops 2025-04-07 10:04:20 -04:00
hyperdefined
e310f1cb18 fix #98 2025-04-05 18:24:23 -04:00
hyperdefined
3d850ef00c Create FUNDING.yml 2025-03-31 19:39:35 -04:00
hyperdefined
dfd2ef7d7b added missing entries 2025-03-31 19:27:03 -04:00
hyperdefined
957d4d95cb Create damage-done.png 2025-03-31 19:24:57 -04:00
hyperdefined
2143daa133 cleanup 2025-03-31 19:21:09 -04:00
hyperdefined
be8fcc2d57 Update TokenCrafting.java 2025-03-31 19:20:24 -04:00
hyperdefined
ed9afc1812 backwards compatibility with old flight time format 2025-03-31 19:06:43 -04:00
hyperdefined
706175a13a Merge pull request #97 from sebampuero/impr-flighttime-fmt
Elytra flight time as human readable format
2025-03-31 18:44:50 -04:00
sebampuero
256581fa08 fix: use char instead of str 2025-03-31 18:42:47 -04:00
sebampuero
818f2e7a39 feat: update lore formatting 2025-03-31 18:41:33 -04:00
sebampuero
d83bc55eec feat: fix function for several placeholders. It was appending wrongly. Use version11 class for updater. 2025-03-31 18:41:33 -04:00
sebampuero
3196223d30 docs: javadoc fix 2025-03-31 18:39:09 -04:00
sebampuero
02d5d1c17e feat: adding updater for config version 11 2025-03-31 18:39:05 -04:00
sebampuero
d675549209 feat: add format lore that replaces several placeholders with a map 2025-03-31 18:14:51 -04:00
sebampuero
d5324b5db6 feat: some first changes
Add placeholders for time values, new formatting function and call for new function.
2025-03-31 18:13:45 -04:00
hyperdefined
4fe4c2be25 fix #94 2025-03-31 18:03:07 -04:00
31 changed files with 1563 additions and 304 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
buy_me_a_coffee: hyperdefined

View File

@@ -12,14 +12,15 @@
ToolStats is a Paper plugin that display various stats about tools. This plugin is inspired off of [GearStats](https://www.spigotmc.org/resources/gearstats.12960/). You can either track all statistics by default, or a use a token system to add statistics to tool/armor. You can configure how each statistic is shown on the item, or disable it! ToolStats is a Paper plugin that display various stats about tools. This plugin is inspired off of [GearStats](https://www.spigotmc.org/resources/gearstats.12960/). You can either track all statistics by default, or a use a token system to add statistics to tool/armor. You can configure how each statistic is shown on the item, or disable it!
Here is everything it tracks: Here is everything it tracks:
* Blocks mined (pickaxes, shovels, axes, hoes, shears) * Blocks mined (pickaxes, shovels, axes, hoes, shears).
* Crops mined (hoes) * Crops mined (hoes).
* Player/mob kills (swords, axes, tridents, bows/crossbows, mace) * Player/mob kills (swords, axes, tridents, bows/crossbows, mace).
* Ownership of items when crafted, looted (from chests), traded, spawned via creative, and caught from fishing. * Ownership of items when crafted, looted (from chests), traded, spawned via creative, and caught from fishing.
* Armor damage taken. * Armor damage taken.
* Damage done with weapons.
* Fish caught. * Fish caught.
* Sheep sheared. * Sheep sheared.
* Arrows shot (bows/crossbows) * Arrows shot (bows/crossbows).
* Flight time with elytras. * Flight time with elytras.
The best part is, this data is stored on the item itself. The best part is, this data is stored on the item itself.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

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

View File

@@ -93,6 +93,10 @@ public final class ToolStats extends JavaPlugin {
* Key for arrows shot. * Key for arrows shot.
*/ */
public final NamespacedKey arrowsShot = new NamespacedKey(this, "arrows-shot"); public final NamespacedKey arrowsShot = new NamespacedKey(this, "arrows-shot");
/**
* Key for arrows shot.
*/
public final NamespacedKey droppedBy = new NamespacedKey(this, "dropped-by");
/** /**
* Key for tracking flight time. * Key for tracking flight time.
*/ */
@@ -117,7 +121,7 @@ public final class ToolStats extends JavaPlugin {
*/ */
public final NamespacedKey originType = new NamespacedKey(this, "origin"); public final NamespacedKey originType = new NamespacedKey(this, "origin");
public final int CONFIG_VERSION = 11; public final int CONFIG_VERSION = 12;
public final Logger logger = this.getLogger(); public final Logger logger = this.getLogger();
public final File configFile = new File(this.getDataFolder(), "config.yml"); public final File configFile = new File(this.getDataFolder(), "config.yml");
public boolean tokens = false; public boolean tokens = false;

View File

@@ -30,6 +30,7 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
@@ -38,6 +39,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
public class CommandToolStats implements TabExecutor { public class CommandToolStats implements TabExecutor {
@@ -48,7 +50,7 @@ public class CommandToolStats implements TabExecutor {
} }
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) {
if (!sender.hasPermission("toolstats.command")) { if (!sender.hasPermission("toolstats.command")) {
sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true; return true;
@@ -89,6 +91,41 @@ public class CommandToolStats implements TabExecutor {
} }
return true; return true;
} }
// /toolstats edit stat value
case "edit": {
if (!sender.hasPermission("toolstats.edit")) {
sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true;
}
if (sender instanceof ConsoleCommandSender) {
sender.sendMessage(Component.text("You must be a player for this command.", NamedTextColor.RED));
return true;
}
if (args.length < 3) {
sender.sendMessage(Component.text("Invalid syntax. Usage: /toolstats edit <stat> <value>", NamedTextColor.RED));
return true;
}
handleEdit(args[1], args[2], (Player) sender);
return true;
}
// /toolstats remove stat
case "remove": {
if (!sender.hasPermission("toolstats.remove")) {
sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true;
}
if (sender instanceof ConsoleCommandSender) {
sender.sendMessage(Component.text("You must be a player for this command.", NamedTextColor.RED));
return true;
}
if (args.length < 2) {
sender.sendMessage(Component.text("Invalid syntax. Usage: /toolstats remove <stat>", NamedTextColor.RED));
return true;
}
handleRemove(args[1], (Player) sender);
return true;
}
case "reset": { case "reset": {
if (!sender.hasPermission("toolstats.reset")) { if (!sender.hasPermission("toolstats.reset")) {
sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED)); sender.sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
@@ -210,7 +247,8 @@ public class CommandToolStats implements TabExecutor {
if (flightTime != null) { if (flightTime != null) {
if (toolStats.config.getBoolean("enabled.flight-time")) { if (toolStats.config.getBoolean("enabled.flight-time")) {
Component line = toolStats.configTools.formatLore("flight-time", "{time}", toolStats.numberFormat.formatDouble((double) flightTime / 1000)); Map<String, String> flightTimeFormatted = toolStats.numberFormat.formatTime(flightTime);
Component line = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", flightTimeFormatted);
lore.add(line); lore.add(line);
} }
} }
@@ -228,84 +266,109 @@ public class CommandToolStats implements TabExecutor {
player.getInventory().setItem(slot, finalItem); player.getInventory().setItem(slot, finalItem);
} }
if (toolStats.configTools.checkConfig(original.getType(), "created-by")) { if (container.has(toolStats.droppedBy, PersistentDataType.STRING)) {
if (container.has(toolStats.itemOwner, new UUIDDataType())) { if (toolStats.config.getBoolean("enabled.dropped-by")) {
UUID owner = container.get(toolStats.itemOwner, new UUIDDataType()); if (container.has(toolStats.droppedBy)) {
String ownerName = null; String droppedBy = container.get(toolStats.droppedBy, PersistentDataType.STRING);
// if we can read the current owner lore.add(toolStats.configTools.formatLore("dropped-by", "{name}", droppedBy));
if (owner != null) { } else {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner); player.sendMessage(Component.text("Unable to set 'dropped-by', as this item has no record of it."));
ownerName = offlinePlayer.getName();
}
// if the owner's name is null for whatever reason, set the new owner
// to the current player running the command
if (ownerName == null) {
player.sendMessage(Component.text("The owner of this item is null. Setting to " + player.getName() + ".", NamedTextColor.RED));
ownerName = player.getName();
container.set(toolStats.itemOwner, new UUIDDataType(), player.getUniqueId());
}
// show how the item was created based on the previous lore
switch (origin) {
case 0: {
lore.add(toolStats.configTools.formatLore("created.created-by", "{player}", ownerName));
break;
}
case 2: {
lore.add(toolStats.configTools.formatLore("looted.looted-by", "{player}", ownerName));
break;
}
case 3: {
lore.add(toolStats.configTools.formatLore("traded.traded-by", "{player}", ownerName));
break;
}
case 4: {
lore.add(toolStats.configTools.formatLore("looted.found-by", "{player}", ownerName));
break;
}
case 5: {
lore.add(toolStats.configTools.formatLore("fished.caught-by", "{player}", ownerName));
break;
}
case 6: {
lore.add(toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", ownerName));
break;
}
} }
} }
} }
if (toolStats.configTools.checkConfig(original.getType(), "created-date")) {
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) { if (container.has(toolStats.itemOwner, new UUIDDataType())) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG); UUID owner = container.get(toolStats.itemOwner, new UUIDDataType());
if (time != null) { String ownerName = null;
String date = toolStats.numberFormat.formatDate(new Date(time)); // if we can read the current owner
// show how when the item was created based on the previous lore if (owner != null) {
switch (origin) { OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner);
case 0: { ownerName = offlinePlayer.getName();
lore.add(toolStats.configTools.formatLore("created.created-on", "{date}", date)); }
break;
// if the owner's name is null for whatever reason, set the new owner
// to the current player running the command
if (ownerName == null) {
player.sendMessage(Component.text("The owner of this item is null. Setting to " + player.getName() + ".", NamedTextColor.RED));
ownerName = player.getName();
container.set(toolStats.itemOwner, new UUIDDataType(), player.getUniqueId());
}
// show how the item was created based on the previous lore
switch (origin) {
case 0: {
if (toolStats.configTools.checkConfig(original.getType(), "crafted-by")) {
lore.add(toolStats.configTools.formatLore("crafted.crafted-by", "{player}", ownerName));
}
break;
}
case 2: {
if (toolStats.configTools.checkConfig(original.getType(), "looted-by")) {
lore.add(toolStats.configTools.formatLore("looted.looted-by", "{player}", ownerName));
}
break;
}
case 3: {
if (toolStats.configTools.checkConfig(original.getType(), "traded-by")) {
lore.add(toolStats.configTools.formatLore("traded.traded-by", "{player}", ownerName));
}
break;
}
case 5: {
if (toolStats.configTools.checkConfig(original.getType(), "fished-by")) {
lore.add(toolStats.configTools.formatLore("fished.caught-by", "{player}", ownerName));
}
break;
}
case 6: {
if (toolStats.configTools.checkConfig(original.getType(), "spawned-in-by")) {
lore.add(toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", ownerName));
}
break;
}
}
}
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) {
String date = toolStats.numberFormat.formatDate(new Date(time));
// show how when the item was created based on the previous lore
switch (origin) {
case 0: {
if (toolStats.configTools.checkConfig(original.getType(), "crafted-on")) {
lore.add(toolStats.configTools.formatLore("crafted.crafted-on", "{date}", date));
} }
case 2: { break;
}
case 1: {
if (toolStats.config.getBoolean("enabled.dropped-on")) {
lore.add(toolStats.configTools.formatLore("dropped-on", "{date}", date));
}
break;
}
case 2: {
if (toolStats.configTools.checkConfig(original.getType(), "looted-on")) {
lore.add(toolStats.configTools.formatLore("looted.looted-on", "{date}", date)); lore.add(toolStats.configTools.formatLore("looted.looted-on", "{date}", date));
break;
} }
case 3: { break;
}
case 3: {
if (toolStats.configTools.checkConfig(original.getType(), "traded-on")) {
lore.add(toolStats.configTools.formatLore("traded.traded-on", "{date}", date)); lore.add(toolStats.configTools.formatLore("traded.traded-on", "{date}", date));
break;
} }
case 4: { break;
lore.add(toolStats.configTools.formatLore("looted.found-on", "{date}", date)); }
break; case 5: {
} if (toolStats.configTools.checkConfig(original.getType(), "fished-on")) {
case 5: {
lore.add(toolStats.configTools.formatLore("fished.caught-on", "{date}", date)); lore.add(toolStats.configTools.formatLore("fished.caught-on", "{date}", date));
break;
} }
case 6: { break;
}
case 6: {
if (toolStats.configTools.checkConfig(original.getType(), "spawned-in-on")) {
lore.add(toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", date)); lore.add(toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", date));
break;
} }
break;
} }
} }
} }
@@ -366,6 +429,14 @@ public class CommandToolStats implements TabExecutor {
} }
} }
} }
if (toolStats.configTools.checkConfig(original.getType(), "damage-done")) {
if (container.has(toolStats.damageDone, PersistentDataType.DOUBLE)) {
Double damage = container.get(toolStats.damageDone, PersistentDataType.DOUBLE);
if (damage != null) {
lore.add(toolStats.configTools.formatLore("damage-done", "{damage}", toolStats.numberFormat.formatDouble(damage)));
}
}
}
if (toolStats.config.getBoolean("enabled.arrows-shot")) { if (toolStats.config.getBoolean("enabled.arrows-shot")) {
if (container.has(toolStats.arrowsShot, PersistentDataType.INTEGER)) { if (container.has(toolStats.arrowsShot, PersistentDataType.INTEGER)) {
Integer arrows = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER); Integer arrows = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER);
@@ -406,6 +477,12 @@ public class CommandToolStats implements TabExecutor {
target.getInventory().addItem(itemStack); target.getInventory().addItem(itemStack);
break; break;
} }
case "damage-done": {
ItemStack itemStack = toolStats.tokenItems.damageDone();
itemStack.setAmount(amount);
target.getInventory().addItem(itemStack);
break;
}
case "mob-kills": { case "mob-kills": {
ItemStack itemStack = toolStats.tokenItems.mobKills(); ItemStack itemStack = toolStats.tokenItems.mobKills();
itemStack.setAmount(amount); itemStack.setAmount(amount);
@@ -457,9 +534,601 @@ public class CommandToolStats implements TabExecutor {
} }
} }
/**
* Handle edit subcommand.
*
* @param stat The stat to edit.
* @param userValue The value the user entered.
* @param player The player using the command.
*/
private void handleEdit(String stat, Object userValue, Player player) {
ItemStack editedItem = player.getInventory().getItemInMainHand().clone();
if (!toolStats.itemChecker.isValidItem(editedItem.getType())) {
player.sendMessage(Component.text("This is not a valid item.", NamedTextColor.RED));
return;
}
ItemMeta editedItemMeta = editedItem.getItemMeta();
PersistentDataContainer container = editedItemMeta.getPersistentDataContainer();
switch (stat) {
case "crops-harvested": {
if (!toolStats.config.getBoolean("enabled.crops-harvested")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.cropsHarvested)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateCropsMined(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "blocks-mined": {
if (!toolStats.configTools.checkConfig(editedItem.getType(), "blocks-mined")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.blocksMined)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.blocksMined, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateBlocksMined(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "damage-taken": {
if (!toolStats.config.getBoolean("enabled.armor-damage")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.armorDamage)) {
double value;
try {
value = Double.parseDouble((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Double statValue = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
double difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateArmorDamage(editedItem, difference, false);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "damage-done": {
if (!toolStats.configTools.checkConfig(editedItem.getType(), "damage-done")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.damageDone)) {
double value;
try {
value = Double.parseDouble((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Double statValue = container.get(toolStats.damageDone, PersistentDataType.DOUBLE);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
double difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateWeaponDamage(editedItem, difference, false);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "mob-kills": {
if (!toolStats.configTools.checkConfig(editedItem.getType(), "mob-kills")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.mobKills)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.mobKills, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateMobKills(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "player-kills": {
if (!toolStats.configTools.checkConfig(editedItem.getType(), "player-kills")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.playerKills)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.playerKills, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updatePlayerKills(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "arrows-shot": {
if (!toolStats.config.getBoolean("enabled.arrows-shot")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.arrowsShot)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateArrowsShot(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "sheep-sheared": {
if (!toolStats.config.getBoolean("enabled.sheep-sheared")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.sheepSheared)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.sheepSheared, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateSheepSheared(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "flight-time": {
if (!toolStats.config.getBoolean("enabled.flight-time")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.flightTime)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Long statValue = container.get(toolStats.flightTime, PersistentDataType.LONG);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
long difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateFlightTime(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "fight-caught": {
if (!toolStats.config.getBoolean("enabled.fight-caught")) {
player.sendMessage(Component.text("This stat is disabled.", NamedTextColor.RED));
return;
}
if (container.has(toolStats.fishCaught)) {
int value;
try {
value = Integer.parseInt((String) userValue);
} catch (NumberFormatException exception) {
player.sendMessage(Component.text("That is not a valid number.", NamedTextColor.RED));
return;
}
if (value < 0) {
player.sendMessage(Component.text("Number must be positive.", NamedTextColor.RED));
return;
}
Integer statValue = container.get(toolStats.fishCaught, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
int difference = value - statValue;
editedItemMeta = toolStats.itemLore.updateFishCaught(editedItem, difference);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
default: {
player.sendMessage(Component.text("That is not a valid stat to update.", NamedTextColor.RED));
return;
}
}
editedItem.setItemMeta(editedItemMeta);
player.getInventory().setItemInMainHand(editedItem);
}
/**
* Handle remove subcommand.
*
* @param stat The stat to remove.
* @param player The player using the command.
*/
private void handleRemove(String stat, Player player) {
ItemStack editedItem = player.getInventory().getItemInMainHand().clone();
if (!toolStats.itemChecker.isValidItem(editedItem.getType())) {
player.sendMessage(Component.text("This is not a valid item.", NamedTextColor.RED));
return;
}
ItemMeta editedItemMeta = editedItem.getItemMeta();
PersistentDataContainer container = editedItemMeta.getPersistentDataContainer();
switch (stat) {
case "crops-harvested": {
if (container.has(toolStats.cropsHarvested)) {
Integer statValue = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.cropsHarvested);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "crops-mined");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("crops-harvested", "{crops}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "blocks-mined": {
if (container.has(toolStats.blocksMined)) {
Integer statValue = container.get(toolStats.blocksMined, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.blocksMined);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "blocks-mined");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("blocks-mined", "{blocks}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "damage-taken": {
if (container.has(toolStats.armorDamage)) {
Double statValue = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.armorDamage);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "damage-taken");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("damage-taken", "{damage}", toolStats.numberFormat.formatDouble(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "damage-done": {
if (container.has(toolStats.damageDone)) {
Double statValue = container.get(toolStats.damageDone, PersistentDataType.DOUBLE);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.damageDone);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "damage-done");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("damage-done", "{damage}", toolStats.numberFormat.formatDouble(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "mob-kills": {
if (container.has(toolStats.mobKills)) {
Integer statValue = container.get(toolStats.mobKills, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.mobKills);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "mob-kills");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("kills.mob", "{kills}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "player-kills": {
if (container.has(toolStats.playerKills)) {
Integer statValue = container.get(toolStats.playerKills, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.playerKills);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "player-kills");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("kills.player", "{kills}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "sheep-sheared": {
if (container.has(toolStats.sheepSheared)) {
Integer statValue = container.get(toolStats.sheepSheared, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.sheepSheared);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "sheep-sheared");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("sheep-sheared", "{sheep}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "flight-time": {
if (container.has(toolStats.flightTime)) {
Long statValue = container.get(toolStats.flightTime, PersistentDataType.LONG);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.flightTime);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "flight-time");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Map<String, String> timeFormatted = toolStats.numberFormat.formatTime(statValue);
Component oldLine = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", timeFormatted);
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
case "fight-caught": {
if (container.has(toolStats.fishCaught)) {
Integer statValue = container.get(toolStats.fishCaught, PersistentDataType.INTEGER);
if (statValue == null) {
player.sendMessage(Component.text("Unable to get stat from item.", NamedTextColor.RED));
return;
}
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (tokens == null) {
player.sendMessage(Component.text("Unable to get tokens from item.", NamedTextColor.RED));
return;
}
container.remove(toolStats.fishCaught);
List<String> newTokens = toolStats.itemChecker.removeToken(tokens, "fight-caught");
if (newTokens.isEmpty()) {
container.remove(toolStats.tokenApplied);
} else {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
}
Component oldLine = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", toolStats.numberFormat.formatInt(statValue));
List<Component> newLore = toolStats.itemLore.removeLore(editedItemMeta.lore(), oldLine);
editedItemMeta.lore(newLore);
} else {
player.sendMessage(Component.text("This item does not have that stat.", NamedTextColor.RED));
}
break;
}
default: {
player.sendMessage(Component.text("That is not a valid stat to update.", NamedTextColor.RED));
return;
}
}
editedItem.setItemMeta(editedItemMeta);
player.getInventory().setItemInMainHand(editedItem);
}
@Nullable @Nullable
@Override @Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String @NotNull [] args) {
if (args.length == 1) { if (args.length == 1) {
List<String> suggestions = new ArrayList<>(); List<String> suggestions = new ArrayList<>();
if (sender.hasPermission("toolstats.reload")) { if (sender.hasPermission("toolstats.reload")) {
@@ -471,12 +1140,32 @@ public class CommandToolStats implements TabExecutor {
if (sender.hasPermission("toolstats.givetokens")) { if (sender.hasPermission("toolstats.givetokens")) {
suggestions.add("givetokens"); suggestions.add("givetokens");
} }
if (sender.hasPermission("toolstats.edit")) {
suggestions.add("edit");
}
if (sender.hasPermission("toolstats.remove")) {
suggestions.add("remove");
}
return suggestions.isEmpty() ? null : suggestions; return suggestions.isEmpty() ? null : suggestions;
} }
if (args.length == 2 && args[0].equalsIgnoreCase("reset") && sender.hasPermission("toolstats.reset.confirm")) { if (args.length == 2 && args[0].equalsIgnoreCase("reset") && sender.hasPermission("toolstats.reset.confirm")) {
return Collections.singletonList("confirm"); return Collections.singletonList("confirm");
} }
if (args.length == 2 && args[0].equalsIgnoreCase("edit") && sender.hasPermission("toolstats.edit")) {
// yes I am lazy
return toolStats.tokenCrafting.getTokenTypes().stream()
.filter(s -> !s.equals("remove") && !s.equals("reset"))
.map(s -> s.equals("crops-mined") ? "crops-harvested" : s)
.collect(Collectors.toList());
}
if (args.length == 2 && args[0].equalsIgnoreCase("remove") && sender.hasPermission("toolstats.remove")) {
// yes I am lazy
return toolStats.tokenCrafting.getTokenTypes().stream()
.filter(s -> !s.equals("remove") && !s.equals("reset"))
.map(s -> s.equals("crops-mined") ? "crops-harvested" : s)
.collect(Collectors.toList());
}
if (args.length == 3 && args[0].equalsIgnoreCase("givetokens") && sender.hasPermission("toolstats.givetokens")) { if (args.length == 3 && args[0].equalsIgnoreCase("givetokens") && sender.hasPermission("toolstats.givetokens")) {
return toolStats.tokenCrafting.getTokenTypes(); return toolStats.tokenCrafting.getTokenTypes();
} }

View File

@@ -48,7 +48,7 @@ public class BlockBreak implements Listener {
return; return;
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();

View File

@@ -50,7 +50,7 @@ public class CraftItem implements Listener {
return; return;
} }
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
ItemStack craftedItem = event.getCurrentItem(); ItemStack craftedItem = event.getCurrentItem();
@@ -121,7 +121,13 @@ public class CraftItem implements Listener {
} }
// get the current time // get the current time
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
} else {
finalDate = new Date(timeCreated);
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag // if the item already has the tag
@@ -139,12 +145,12 @@ public class CraftItem implements Listener {
} }
// if creation date is enabled, add it // if creation date is enabled, add it
if (toolStats.configTools.checkConfig(itemStack.getType(), "created-date")) { if (toolStats.configTools.checkConfig(itemStack.getType(), "crafted-on")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.originType, PersistentDataType.INTEGER, 0); container.set(toolStats.originType, PersistentDataType.INTEGER, 0);
String date = toolStats.numberFormat.formatDate(finalDate); String date = toolStats.numberFormat.formatDate(finalDate);
Component newLine = toolStats.configTools.formatLore("created.created-on", "{date}", date); Component newLine = toolStats.configTools.formatLore("crafted.crafted-on", "{date}", date);
if (newLine == null) { if (newLine == null) {
return null; return null;
} }
@@ -153,11 +159,11 @@ public class CraftItem implements Listener {
} }
// if creation owner is enabled, add it // if creation owner is enabled, add it
if (toolStats.configTools.checkConfig(itemStack.getType(), "created-by")) { if (toolStats.configTools.checkConfig(itemStack.getType(), "crafted-by")) {
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 0); container.set(toolStats.originType, PersistentDataType.INTEGER, 0);
Component newLine = toolStats.configTools.formatLore("created.created-by", "{player}", owner.getName()); Component newLine = toolStats.configTools.formatLore("crafted.crafted-by", "{player}", owner.getName());
if (newLine == null) { if (newLine == null) {
return null; return null;
} }

View File

@@ -30,6 +30,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -87,7 +88,13 @@ public class CreativeEvent implements Listener {
} }
// get the current time // get the current time
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
} else {
finalDate = new Date(timeCreated);
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag // if the item already has the tag
@@ -96,22 +103,45 @@ public class CreativeEvent implements Listener {
return null; return null;
} }
// get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
if (toolStats.configTools.checkConfig(itemStack.getType(), "spawned-in-on")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.originType, PersistentDataType.INTEGER, 6);
String date = toolStats.numberFormat.formatDate(finalDate);
Component newLine = toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
if (toolStats.configTools.checkConfig(itemStack.getType(), "spawned-in-by")) {
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 6);
Component newLine = toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", owner.getName());
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
// if hash is enabled, add it // if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newSpawnedItem.getType(), owner.getUniqueId(), timeCreated); String hash = toolStats.hashMaker.makeHash(newSpawnedItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
// if spawned in is enabled, add it
if (toolStats.configTools.checkConfig(newSpawnedItem.getType(), "spawned-in")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 6);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.lore(newLore);
}
newSpawnedItem.setItemMeta(meta); newSpawnedItem.setItemMeta(meta);
return newSpawnedItem; return newSpawnedItem;
} }

View File

@@ -25,7 +25,6 @@ import org.bukkit.entity.*;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -157,7 +156,7 @@ public class EntityDamage implements Listener {
// player is taking damage // player is taking damage
if (mobBeingAttacked instanceof Player playerTakingDamage) { if (mobBeingAttacked instanceof Player playerTakingDamage) {
if (playerTakingDamage.getGameMode() == GameMode.CREATIVE || playerTakingDamage.getGameMode() == GameMode.SPECTATOR) { if (playerTakingDamage.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
updateArmorDamage(playerTakingDamage.getInventory(), event.getFinalDamage()); updateArmorDamage(playerTakingDamage.getInventory(), event.getFinalDamage());
@@ -188,7 +187,7 @@ public class EntityDamage implements Listener {
boolean isMain = playerInventory.getItemInMainHand().getType() == Material.BOW || playerInventory.getItemInMainHand().getType() == Material.CROSSBOW; boolean isMain = playerInventory.getItemInMainHand().getType() == Material.BOW || playerInventory.getItemInMainHand().getType() == Material.CROSSBOW;
boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.BOW || playerInventory.getItemInOffHand().getType() == Material.CROSSBOW; boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.BOW || playerInventory.getItemInOffHand().getType() == Material.CROSSBOW;
ItemMeta newBowDamage = toolStats.itemLore.updateWeaponDamage(playerInventory.getItemInMainHand(), damage, false); ItemMeta newBowDamage = toolStats.itemLore.updateWeaponDamage(heldBow, damage, false);
//toolStats.logger.info(newBowDamage.toString()); //toolStats.logger.info(newBowDamage.toString());
// player is shooting another player // player is shooting another player

View File

@@ -30,6 +30,8 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -84,19 +86,44 @@ public class EntityDeath implements Listener {
return null; return null;
} }
if (!toolStats.config.getBoolean("enabled.dropped-by")) { long timeCreated = System.currentTimeMillis();
return null; Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
} else {
finalDate = new Date(timeCreated);
} }
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(toolStats.originType, PersistentDataType.INTEGER, 1);
String mobName = toolStats.config.getString("messages.mob." + entity.getType()); String mobName = toolStats.config.getString("messages.mob." + entity.getType());
if (mobName == null) { if (mobName == null) {
mobName = entity.getName(); mobName = entity.getName();
} }
Component newLine = toolStats.configTools.formatLore("dropped-by", "{name}", mobName);
List<Component> newLore = toolStats.itemLore.addItemLore(meta, newLine); List<Component> lore;
meta.lore(newLore); if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
if (toolStats.config.getBoolean("enabled.dropped-on")) {
container.set(toolStats.originType, PersistentDataType.INTEGER, 1);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
String date = toolStats.numberFormat.formatDate(finalDate);
Component droppedOn = toolStats.configTools.formatLore("dropped-on", "{date}", date);
lore.add(droppedOn);
}
if (toolStats.config.getBoolean("enabled.dropped-by")) {
container.set(toolStats.originType, PersistentDataType.INTEGER, 1);
container.set(toolStats.droppedBy, PersistentDataType.STRING, mobName);
Component droppedBy = toolStats.configTools.formatLore("dropped-by", "{name}", mobName);
lore.add(droppedBy);
}
meta.lore(lore);
newItem.setItemMeta(meta); newItem.setItemMeta(meta);
return newItem; return newItem;
} }

View File

@@ -36,6 +36,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -99,29 +100,58 @@ public class GenerateLoot implements Listener {
return null; return null;
} }
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
PersistentDataContainer container = meta.getPersistentDataContainer(); if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
if (!toolStats.configTools.checkConfig(newItem.getType(), "looted-tag")) { timeCreated = finalDate.getTime();
return null; } else {
finalDate = new Date(timeCreated);
} }
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) {
return null; return null;
} }
// only make the hash if it's enabled // get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
if (toolStats.configTools.checkConfig(newItem.getType(), "looted-on")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
String date = toolStats.numberFormat.formatDate(finalDate);
Component newLine = toolStats.configTools.formatLore("looted.looted-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
if (toolStats.configTools.checkConfig(newItem.getType(), "looted-by")) {
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
Component newLine = toolStats.configTools.formatLore("looted.looted-by", "{player}", owner.getName());
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
// if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated); String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.lore(newLore);
newItem.setItemMeta(meta); newItem.setItemMeta(meta);
return newItem; return newItem;
} }

View File

@@ -23,6 +23,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
@@ -46,6 +47,11 @@ public class InventoryOpen implements Listener {
} }
Inventory inventory = event.getInventory(); Inventory inventory = event.getInventory();
// only check these
if (inventory.getType() != InventoryType.CHEST || inventory.getType() != InventoryType.BARREL || inventory.getType() != InventoryType.SHULKER_BOX || inventory.getType() != InventoryType.ENDER_CHEST) {
return;
}
Player player = (Player) event.getPlayer(); Player player = (Player) event.getPlayer();
for (ItemStack itemStack : inventory) { for (ItemStack itemStack : inventory) {
if (itemStack == null) { if (itemStack == null) {

View File

@@ -35,6 +35,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -53,7 +54,7 @@ public class PickupItem implements Listener {
} }
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if (entity instanceof Player player) { if (entity instanceof Player player) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
Item item = event.getItem(); Item item = event.getItem();
@@ -90,7 +91,13 @@ public class PickupItem implements Listener {
return null; return null;
} }
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
} else {
finalDate = new Date(timeCreated);
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (!toolStats.config.getBoolean("enabled.elytra-tag")) { if (!toolStats.config.getBoolean("enabled.elytra-tag")) {
@@ -103,13 +110,25 @@ public class PickupItem implements Listener {
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
// get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 4); container.set(toolStats.originType, PersistentDataType.INTEGER, 4);
container.remove(toolStats.newElytra); container.remove(toolStats.newElytra);
String formattedDate = toolStats.numberFormat.formatDate(finalDate); String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate); Component dateCreatedLore = toolStats.configTools.formatLore("looted.found-on", "{date}", formattedDate);
meta.lore(newLore); Component itemOwnerLore = toolStats.configTools.formatLore("looted.found-by", "{player}", owner.getName());
lore.add(dateCreatedLore);
lore.add(itemOwnerLore);
meta.lore(lore);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
return finalItem; return finalItem;
} }

View File

@@ -34,6 +34,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -56,7 +57,7 @@ public class PlayerFish implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
@@ -88,7 +89,7 @@ public class PlayerFish implements Listener {
ItemStack caughtItem = ((Item) event.getCaught()).getItemStack(); ItemStack caughtItem = ((Item) event.getCaught()).getItemStack();
Item caughtItemEntity = (Item) event.getCaught(); Item caughtItemEntity = (Item) event.getCaught();
if (toolStats.itemChecker.isValidItem(caughtItem.getType())) { if (toolStats.itemChecker.isValidItem(caughtItem.getType())) {
ItemStack newItem = addNewLore(caughtItem, player); ItemStack newItem = addFishedOrigin(caughtItem, player);
if (newItem != null) { if (newItem != null) {
caughtItemEntity.setItemStack(newItem); caughtItemEntity.setItemStack(newItem);
} }
@@ -102,36 +103,65 @@ public class PlayerFish implements Listener {
* @param owner The player who caught it. * @param owner The player who caught it.
* @return A copy of the new item with lore. * @return A copy of the new item with lore.
*/ */
private ItemStack addNewLore(ItemStack originalItem, Player owner) { private ItemStack addFishedOrigin(ItemStack originalItem, Player owner) {
ItemStack newItem = originalItem.clone(); ItemStack newItem = originalItem.clone();
ItemMeta meta = originalItem.getItemMeta(); ItemMeta meta = originalItem.getItemMeta();
if (meta == null) { if (meta == null) {
return null; return null;
} }
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
PersistentDataContainer container = meta.getPersistentDataContainer(); if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
if (!toolStats.configTools.checkConfig(newItem.getType(), "fished-tag")) { timeCreated = finalDate.getTime();
return null; } else {
finalDate = new Date(timeCreated);
} }
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) {
return null; return null;
} }
// only make the hash if it's enabled // get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
if (toolStats.configTools.checkConfig(newItem.getType(), "fished-on")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.originType, PersistentDataType.INTEGER, 5);
String date = toolStats.numberFormat.formatDate(finalDate);
Component newLine = toolStats.configTools.formatLore("fished.caught-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
if (toolStats.configTools.checkConfig(newItem.getType(), "fished-by")) {
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 5);
Component newLine = toolStats.configTools.formatLore("fished.caught-by", "{player}", owner.getName());
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
// if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated); String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 5);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.lore(newLore);
newItem.setItemMeta(meta); newItem.setItemMeta(meta);
return newItem; return newItem;
} }

View File

@@ -58,7 +58,7 @@ public class PlayerInteract implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
// store when a player opens a chest // store when a player opens a chest
@@ -72,7 +72,7 @@ public class PlayerInteract implements Listener {
public void onInteract(PlayerInteractEntityEvent event) { public void onInteract(PlayerInteractEntityEvent event) {
Entity clicked = event.getRightClicked(); Entity clicked = event.getRightClicked();
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
// store when a player opens a minecart // store when a player opens a minecart

View File

@@ -41,7 +41,7 @@ public class PlayerMove implements Listener {
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onCraft(PlayerMoveEvent event) { public void onMove(PlayerMoveEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
// player starts to fly // player starts to fly
if (player.isGliding()) { if (player.isGliding()) {

View File

@@ -45,7 +45,7 @@ public class SheepShear implements Listener {
return; return;
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
Entity entity = event.getRightClicked(); Entity entity = event.getRightClicked();

View File

@@ -46,7 +46,7 @@ public class ShootBow implements Listener {
return; return;
} }
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.ADVENTURE) { if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }

View File

@@ -35,6 +35,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -126,29 +127,58 @@ public class VillagerTrade implements Listener {
return null; return null;
} }
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
} else {
finalDate = new Date(timeCreated);
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) {
return null; return null;
} }
if (!toolStats.configTools.checkConfig(newItem.getType(), "traded-tag")) { // get the current lore the item
return null; List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
} }
// only make the hash if it's enabled if (toolStats.configTools.checkConfig(newItem.getType(), "traded-on")) {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.originType, PersistentDataType.INTEGER, 3);
String date = toolStats.numberFormat.formatDate(finalDate);
Component newLine = toolStats.configTools.formatLore("traded.traded-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
if (toolStats.configTools.checkConfig(newItem.getType(), "traded-by")) {
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 3);
Component newLine = toolStats.configTools.formatLore("traded.traded-by", "{player}", owner.getName());
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore);
}
// if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated); String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.hash, PersistentDataType.STRING, hash);
} }
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 3);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.lore(newLore);
newItem.setItemMeta(meta); newItem.setItemMeta(meta);
return newItem; return newItem;
} }

View File

@@ -27,10 +27,7 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class ItemChecker { public class ItemChecker {
@@ -343,6 +340,26 @@ public class ItemChecker {
return String.join(",", tokens); return String.join(",", tokens);
} }
/**
* Remove a given token from a list of tokens.
*
* @param appliedTokens The tokens on the item.
* @param toRemove The token to remove.
* @return The list of tokens.
*/
public List<String> removeToken(String appliedTokens, String toRemove) {
// remove the tokens if they exist
List<String> tokenList = new ArrayList<>(Arrays.asList(appliedTokens.split(",")));
tokenList.remove(toRemove);
if (tokenList.isEmpty()) {
return Collections.emptyList();
} else {
return tokenList;
}
}
/** /**
* Check to see if a given container has our keys for stats. * Check to see if a given container has our keys for stats.
* *

View File

@@ -27,6 +27,7 @@ import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
public class ItemLore { public class ItemLore {
@@ -101,131 +102,6 @@ public class ItemLore {
return newLore; return newLore;
} }
/**
* Adds new ownership to an item.
*
* @param itemMeta The item meta.
* @param playerName The new owner of item.
* @param formattedDate The date of the ownership.
* @return The item's new lore.
*/
public List<Component> addNewOwner(ItemMeta itemMeta, String playerName, String formattedDate) {
Component dateCreatedLore;
Component itemOwnerLore;
Integer origin = null;
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
origin = container.get(toolStats.originType, PersistentDataType.INTEGER);
}
// if the origin is broken, don't try to set the lore
if (origin == null) {
toolStats.logger.info("Unable to determine origin for item " + itemMeta.getAsString());
toolStats.logger.info("This IS a bug, please report this to the GitHub.");
return itemMeta.lore();
}
// set the lore based on the origin
switch (origin) {
case 2: {
dateCreatedLore = toolStats.configTools.formatLore("looted.looted-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("looted.looted-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.looted.looted-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.looted.looted-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
break;
}
case 3: {
dateCreatedLore = toolStats.configTools.formatLore("traded.traded-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("traded.traded-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.traded.traded-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.traded.traded-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
break;
}
case 4: {
dateCreatedLore = toolStats.configTools.formatLore("looted.found-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("looted.found-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.looted.found-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.looted.found-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
break;
}
case 5: {
dateCreatedLore = toolStats.configTools.formatLore("fished.caught-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("fished.caught-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.fished.caught-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.fished.caught-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
break;
}
case 6: {
dateCreatedLore = toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.spawned-in.spawned-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.spawned-in.spawned-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.lore();
}
break;
}
default: {
toolStats.logger.warning("Origin " + origin + " was found. Data was modified OR something REALLY broke.");
toolStats.logger.warning(itemMeta.getAsString());
return itemMeta.lore();
}
}
List<Component> newLore;
if (itemMeta.hasLore()) {
newLore = itemMeta.lore();
} else {
newLore = new ArrayList<>();
}
newLore.add(dateCreatedLore);
newLore.add(itemOwnerLore);
return newLore;
}
/** /**
* Add x to the crops mined stat. * Add x to the crops mined stat.
* *
@@ -251,6 +127,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.cropsHarvested); container.remove(toolStats.cropsHarvested);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "crops-mined");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldCropsMinedFormatted = toolStats.numberFormat.formatInt(cropsMined); String oldCropsMinedFormatted = toolStats.numberFormat.formatInt(cropsMined);
Component lineToRemove = toolStats.configTools.formatLore("crops-harvested", "{crops}", oldCropsMinedFormatted); Component lineToRemove = toolStats.configTools.formatLore("crops-harvested", "{crops}", oldCropsMinedFormatted);
@@ -334,6 +225,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.blocksMined); container.remove(toolStats.blocksMined);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "blocks-mined");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldBlocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined); String oldBlocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined);
Component lineToRemove = toolStats.configTools.formatLore("blocks-mined", "{blocks}", oldBlocksMinedFormatted); Component lineToRemove = toolStats.configTools.formatLore("blocks-mined", "{blocks}", oldBlocksMinedFormatted);
@@ -418,6 +324,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.playerKills); container.remove(toolStats.playerKills);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "player-kills");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldPlayerKillsFormatted = toolStats.numberFormat.formatInt(playerKills); String oldPlayerKillsFormatted = toolStats.numberFormat.formatInt(playerKills);
Component lineToRemove = toolStats.configTools.formatLore("player-kills", "{kills}", oldPlayerKillsFormatted); Component lineToRemove = toolStats.configTools.formatLore("player-kills", "{kills}", oldPlayerKillsFormatted);
@@ -501,6 +422,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.mobKills); container.remove(toolStats.mobKills);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "mob-kills");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldMobKillsFormatted = toolStats.numberFormat.formatInt(mobKills); String oldMobKillsFormatted = toolStats.numberFormat.formatInt(mobKills);
Component lineToRemove = toolStats.configTools.formatLore("mob-kills", "{kills}", oldMobKillsFormatted); Component lineToRemove = toolStats.configTools.formatLore("mob-kills", "{kills}", oldMobKillsFormatted);
@@ -592,6 +528,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.armorDamage); container.remove(toolStats.armorDamage);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "damage-taken");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldDamageTakenFormatted = toolStats.numberFormat.formatDouble(armorDamage); String oldDamageTakenFormatted = toolStats.numberFormat.formatDouble(armorDamage);
Component lineToRemove = toolStats.configTools.formatLore("damage-taken", "{damage}", oldDamageTakenFormatted); Component lineToRemove = toolStats.configTools.formatLore("damage-taken", "{damage}", oldDamageTakenFormatted);
@@ -683,6 +634,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.damageDone); container.remove(toolStats.damageDone);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "damage-done");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldDamageDoneFormatted = toolStats.numberFormat.formatDouble(damageDone); String oldDamageDoneFormatted = toolStats.numberFormat.formatDouble(damageDone);
Component lineToRemove = toolStats.configTools.formatLore("damage-done", "{damage}", oldDamageDoneFormatted); Component lineToRemove = toolStats.configTools.formatLore("damage-done", "{damage}", oldDamageDoneFormatted);
@@ -766,9 +732,32 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.flightTime); container.remove(toolStats.flightTime);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "flight-time");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldFlightTimeFormatted = toolStats.numberFormat.formatDouble(flightTime); // if the old format is in the config, check to see if the old format is on the elytra
Component lineToRemove = toolStats.configTools.formatLore("flight-time", "{time}", oldFlightTimeFormatted); if (toolStats.config.getString("messages.flight-time-old") != null) {
String oldFormatFormatted = toolStats.numberFormat.formatDouble((double) flightTime / 1000);
Component oldFormat = toolStats.configTools.formatLore("flight-time-old", "{time}", oldFormatFormatted);
List<Component> newLore = removeLore(meta.lore(), oldFormat);
meta.lore(newLore);
}
Map<String, String> oldFlightTimeFormatted = toolStats.numberFormat.formatTime(flightTime);
Component lineToRemove = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", oldFlightTimeFormatted);
List<Component> newLore = removeLore(meta.lore(), lineToRemove); List<Component> newLore = removeLore(meta.lore(), lineToRemove);
meta.lore(newLore); meta.lore(newLore);
} }
@@ -815,10 +804,18 @@ public class ItemLore {
} }
container.set(toolStats.flightTime, PersistentDataType.LONG, flightTime + duration); container.set(toolStats.flightTime, PersistentDataType.LONG, flightTime + duration);
String oldFlightFormatted = toolStats.numberFormat.formatDouble((double) flightTime / 1000); Map<String, String> oldFlightFormatted = toolStats.numberFormat.formatTime(flightTime);
String newFlightFormatted = toolStats.numberFormat.formatDouble((double) (flightTime + duration) / 1000); Map<String, String> newFlightFormatted = toolStats.numberFormat.formatTime(flightTime + duration);
Component oldLine = toolStats.configTools.formatLore("flight-time", "{time}", oldFlightFormatted); // if the old format is in the config, check to see if the old format is on the elytra
Component newLine = toolStats.configTools.formatLore("flight-time", "{time}", newFlightFormatted); if (toolStats.config.getString("messages.flight-time-old") != null) {
if (meta.hasLore()) {
String oldFormatFormatted = toolStats.numberFormat.formatDouble((double) flightTime / 1000);
Component oldFormat = toolStats.configTools.formatLore("flight-time-old", "{time}", oldFormatFormatted);
meta.lore(removeLore(meta.lore(), oldFormat));
}
}
Component oldLine = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", oldFlightFormatted);
Component newLine = toolStats.configTools.formatLoreMultiplePlaceholders("flight-time", newFlightFormatted);
if (oldLine == null || newLine == null) { if (oldLine == null || newLine == null) {
return null; return null;
} }
@@ -851,6 +848,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.sheepSheared); container.remove(toolStats.sheepSheared);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "sheep-sheared");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldSheepShearedFormatted = toolStats.numberFormat.formatDouble(sheepSheared); String oldSheepShearedFormatted = toolStats.numberFormat.formatDouble(sheepSheared);
Component lineToRemove = toolStats.configTools.formatLore("sheep-sheared", "{sheep}", oldSheepShearedFormatted); Component lineToRemove = toolStats.configTools.formatLore("sheep-sheared", "{sheep}", oldSheepShearedFormatted);
@@ -934,6 +946,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.arrowsShot); container.remove(toolStats.arrowsShot);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "arrows-shot");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldArrowsShotFormatted = toolStats.numberFormat.formatDouble(arrowsShot); String oldArrowsShotFormatted = toolStats.numberFormat.formatDouble(arrowsShot);
Component lineToRemove = toolStats.configTools.formatLore("arrows-shot", "{arrows}", oldArrowsShotFormatted); Component lineToRemove = toolStats.configTools.formatLore("arrows-shot", "{arrows}", oldArrowsShotFormatted);
@@ -1019,6 +1046,21 @@ public class ItemLore {
return null; return null;
} }
container.remove(toolStats.fishCaught); container.remove(toolStats.fishCaught);
// remove the applied token if this stat is disabled
if (container.has(toolStats.tokenApplied)) {
String appliedTokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING);
if (appliedTokens != null) {
// remove the token from the list
// if the list is empty, remove the PDC
// otherwise set the PDC back with the new list
List<String> newTokens = toolStats.itemChecker.removeToken(appliedTokens, "fish-caught");
if (!newTokens.isEmpty()) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens));
} else {
container.remove(toolStats.tokenApplied);
}
}
}
if (meta.hasLore()) { if (meta.hasLore()) {
String oldFishCaught = toolStats.numberFormat.formatDouble(fishCaught); String oldFishCaught = toolStats.numberFormat.formatDouble(fishCaught);
Component lineToRemove = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", oldFishCaught); Component lineToRemove = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", oldFishCaught);

View File

@@ -22,8 +22,14 @@ import lol.hyper.toolstats.ToolStats;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
public class NumberFormat { public class NumberFormat {
@@ -33,6 +39,7 @@ public class NumberFormat {
/** /**
* Utility class to format different numbers * Utility class to format different numbers
*
* @param toolStats Plugin instance. * @param toolStats Plugin instance.
*/ */
public NumberFormat(ToolStats toolStats) { public NumberFormat(ToolStats toolStats) {
@@ -136,4 +143,69 @@ public class NumberFormat {
public String formatDate(Date date) { public String formatDate(Date date) {
return DATE_FORMAT.format(date); return DATE_FORMAT.format(date);
} }
/**
* Returns a human-readable form of time in milliseconds.
* E.g. given 3752348000L outputs 1 year, 5 months, 3 days, 14 hours, 12 minutes, 28 seconds.
*
* @param time The time in ms.
* @return Map with units as keys and time value, e.g. "years" (key) -> 1 (value)
*/
public Map<String, String> formatTime(Long time) {
final int SECONDS_PER_MINUTE = 60;
final int MINUTES_PER_HOUR = 60;
final int HOURS_PER_DAY = 24;
final int DAYS_PER_MONTH = 30; // Approximation
final int DAYS_PER_YEAR = 365; // Approximation
long totalSeconds = time / 1000;
Map<String, String> timeUnits = new HashMap<>();
long years = totalSeconds / (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
if (years > 0) {
timeUnits.put("years", Long.toString(years));
}
totalSeconds %= (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
long months = totalSeconds / (DAYS_PER_MONTH * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
if (months > 0) {
timeUnits.put("months", Long.toString(months));
}
totalSeconds %= (DAYS_PER_MONTH * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
long days = totalSeconds / (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
if (days > 0) {
timeUnits.put("days", Long.toString(days));
}
totalSeconds %= (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
long hours = totalSeconds / (MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
if (hours > 0) {
timeUnits.put("hours", Long.toString(hours));
}
totalSeconds %= (MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
long minutes = totalSeconds / SECONDS_PER_MINUTE;
if (minutes > 0) {
timeUnits.put("minutes", Long.toString(minutes));
}
totalSeconds %= SECONDS_PER_MINUTE;
long seconds = totalSeconds;
if (seconds > 0 || timeUnits.isEmpty()) { // Always include seconds if everything else is zero
timeUnits.put("seconds", Long.toString(seconds));
}
return timeUnits;
}
public Date normalizeTime(Long time) {
Instant instant = Instant.ofEpochMilli(time);
ZoneId zone = ZoneId.systemDefault();
LocalDate localDate = instant.atZone(zone).toLocalDate();
ZonedDateTime midnight = localDate.atStartOfDay(zone);
return Date.from(midnight.toInstant());
}
} }

View File

@@ -115,13 +115,14 @@ public class TokenCrafting {
NamespacedKey removeKey = new NamespacedKey(toolStats, "remove-token"); NamespacedKey removeKey = new NamespacedKey(toolStats, "remove-token");
ShapedRecipe removeRecipe = new ShapedRecipe(removeKey, toolStats.tokenItems.removeToken()); ShapedRecipe removeRecipe = new ShapedRecipe(removeKey, toolStats.tokenItems.removeToken());
resetRecipe.shape(" P ", "P P", " P "); removeRecipe.shape(" P ", "P P", " P ");
resetRecipe.setIngredient('P', Material.PAPER); removeRecipe.setIngredient('P', Material.PAPER);
recipes.add(removeRecipe); recipes.add(removeRecipe);
tokenTypes.add("crops-mined"); tokenTypes.add("crops-mined");
tokenTypes.add("blocks-mined"); tokenTypes.add("blocks-mined");
tokenTypes.add("damage-taken"); tokenTypes.add("damage-taken");
tokenTypes.add("damage-done");
tokenTypes.add("mob-kills"); tokenTypes.add("mob-kills");
tokenTypes.add("player-kills"); tokenTypes.add("player-kills");
tokenTypes.add("arrows-shot"); tokenTypes.add("arrows-shot");

View File

@@ -27,6 +27,7 @@ import org.bukkit.Material;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -48,6 +49,11 @@ public class ConfigTools {
* @return If we want to add data or not. * @return If we want to add data or not.
*/ */
public boolean checkConfig(Material material, String configName) { public boolean checkConfig(Material material, String configName) {
if (toolStats.config.getConfigurationSection("enabled." + configName) == null) {
toolStats.logger.warning("Missing config section for enabled" + configName);
return false;
}
String itemName = material.toString().toLowerCase(); String itemName = material.toString().toLowerCase();
String itemType = null; String itemType = null;
// hardcode these // hardcode these
@@ -74,7 +80,6 @@ public class ConfigTools {
} else { } else {
itemType = itemName.substring(itemName.indexOf('_') + 1); itemType = itemName.substring(itemName.indexOf('_') + 1);
} }
return switch (itemType) { return switch (itemType) {
case "pickaxe" -> toolStats.config.getBoolean("enabled." + configName + ".pickaxe"); case "pickaxe" -> toolStats.config.getBoolean("enabled." + configName + ".pickaxe");
case "sword" -> toolStats.config.getBoolean("enabled." + configName + ".sword"); case "sword" -> toolStats.config.getBoolean("enabled." + configName + ".sword");
@@ -133,6 +138,65 @@ public class ConfigTools {
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE); return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
} }
/**
* Format a string with several placeholders to be ready for lore usage.
*
* @param configName The message to use.
* @param placeHoldersValues Map containing placeholders names as keys and values.
* @return Formatted string, null if the configName doesn't exist.
*/
public Component formatLoreMultiplePlaceholders(String configName, Map<String, String> placeHoldersValues) {
String lore = toolStats.config.getString("messages." + configName);
if (lore == null) {
toolStats.logger.warning("Unable to find config message for: messages." + configName);
return null;
}
// if the config message is empty, don't send it
if (lore.isEmpty()) {
return null;
}
Pattern pattern = Pattern.compile("\\{([^}]+)\\}(\\S*)\\s*");
Matcher matcher = pattern.matcher(lore);
StringBuilder result = new StringBuilder();
int lastEnd = 0;
while (matcher.find()) {
String placeholder = matcher.group(1);
String unit = matcher.group(2);
result.append(lore, lastEnd, matcher.start());
if (placeHoldersValues.containsKey(placeholder)) {
result.append(placeHoldersValues.get(placeholder)).append(unit).append(" ");
}
// Update lastEnd to end of the match
lastEnd = matcher.end();
}
if (lastEnd < lore.length()) {
result.append(lore.substring(lastEnd));
}
Component component;
// Clean output text
String outputText = result.toString().replaceAll("\\s+", " ").trim();
// if we match the old color codes, then format them as so
Matcher hexMatcher = CONFIG_HEX_PATTERN.matcher(outputText);
Matcher colorMatcher = COLOR_CODES.matcher(outputText);
if (hexMatcher.find() || colorMatcher.find()) {
component = LegacyComponentSerializer.legacyAmpersand().deserialize(outputText);
} else {
// otherwise format them normally
component = MiniMessage.miniMessage().deserialize(outputText);
}
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
}
/** /**
* Format a string from the config. * Format a string from the config.
* *

View File

@@ -61,5 +61,10 @@ public class ConfigUpdater {
Version11 version11 = new Version11(toolStats); Version11 version11 = new Version11(toolStats);
version11.update(); version11.update();
} }
// Version 11 to 12
if (version == 11) {
Version12 version12 = new Version12(toolStats);
version12.update();
}
} }
} }

View File

@@ -25,7 +25,6 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class TokenItems { public class TokenItems {

View File

@@ -86,6 +86,11 @@ public class Version11 {
toolStats.logger.info("Adding enabled.damage-done.bow to config.yml"); toolStats.logger.info("Adding enabled.damage-done.bow to config.yml");
toolStats.logger.info("Adding enabled.damage-done.mace to config.yml"); toolStats.logger.info("Adding enabled.damage-done.mace to config.yml");
toolStats.logger.info("Updating entry for messages.flight-time");
String oldFlightTime = toolStats.config.getString("messages.flight-time");
toolStats.config.set("messages.flight-time-old", oldFlightTime);
toolStats.config.set("messages.flight-time", "&7Flight time: &8{years}y {months}m {days}d {hours}h {minutes}m {seconds}s");
// save the config and reload it // save the config and reload it
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");

View File

@@ -0,0 +1,122 @@
/*
* This file is part of ToolStats.
*
* ToolStats is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ToolStats is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ToolStats. If not, see <https://www.gnu.org/licenses/>.
*/
package lol.hyper.toolstats.tools.config.versions;
import it.unimi.dsi.fastutil.Pair;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
public class Version12 {
private final ToolStats toolStats;
/**
* Used for updating from version 11 to 12.
*
* @param toolStats ToolStats instance.
*/
public Version12(ToolStats toolStats) {
this.toolStats = toolStats;
}
/**
* Perform the config update.
*/
public void update() {
// save the old config first
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-11.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config-11.yml!");
throw new RuntimeException(exception);
}
toolStats.logger.info("Updating config.yml to version 12.");
toolStats.config.set("config-version", 12);
transfer("enabled.created-by", "enabled.crafted-by");
transfer("enabled.created-date", "enabled.crafted-on");
transfer("enabled.fished-tag", "enabled.fished-by");
transfer("enabled.fished-tag", "enabled.fished-on");
transfer("enabled.looted-tag", "enabled.looted-by");
transfer("enabled.looted-tag", "enabled.looted-on");
transfer("enabled.traded-tag", "enabled.traded-by");
transfer("enabled.traded-tag", "enabled.traded-on");
transfer("enabled.spawned-in", "enabled.spawned-in-by");
transfer("enabled.spawned-in", "enabled.spawned-in-on");
transfer("messages.created", "messages.crafted");
toolStats.config.set("enabled.created-by", null);
toolStats.config.set("enabled.created-date", null);
toolStats.config.set("enabled.fished-tag", null);
toolStats.config.set("enabled.looted-tag", null);
toolStats.config.set("enabled.traded-tag", null);
toolStats.config.set("enabled.spawned-in", null);
toolStats.logger.info("Adding enabled.dropped-on");
boolean droppedBy = toolStats.config.getBoolean("enabled.dropped-by");
toolStats.config.set("enabled.dropped-on", droppedBy);
toolStats.logger.info("Adding messages.dropped-on");
toolStats.config.set("messages.dropped-on", "&7Dropped on: &8{date}");
// rename crafted to crafted here
// copy the old ones first
String craftedByMessage = toolStats.config.getString("messages.created.created-by");
String craftedOnMessage = toolStats.config.getString("messages.created.created-on");
toolStats.config.set("messages.created", null);
toolStats.config.set("messages.crafted.created-by", null);
toolStats.config.set("messages.crafted.created-on", null);
toolStats.config.set("messages.crafted.crafted-by", craftedByMessage);
toolStats.config.set("messages.crafted.crafted-on", craftedOnMessage);
toolStats.logger.info("Adding normalize-time-creation");
toolStats.config.set("normalize-time-creation", false);
// save the config and reload it
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!");
throw new RuntimeException(exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 12. A copy of version 11 has been saved as config-11.yml");
}
private void transfer(String oldSection, String newSection) {
toolStats.logger.info("Moving " + oldSection + " to " + newSection);
ConfigurationSection old = toolStats.config.getConfigurationSection(oldSection);
toolStats.config.set(newSection, old);
}
}

View File

@@ -66,8 +66,8 @@ tokens:
levels: 1 levels: 1
enabled: enabled:
# Will show ownership of items when they are created/found. # Will show "Crafted by <player>"
created-by: crafted-by:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -78,8 +78,8 @@ enabled:
armor: true armor: true
mace: true mace: true
fishing-rod: true fishing-rod: true
# Will show time the item is created # Will show "Crafted on <date>"
created-date: crafted-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -91,7 +91,18 @@ enabled:
mace: true mace: true
fishing-rod: true fishing-rod: true
# Will show "Fished by <player>" # Will show "Fished by <player>"
fished-tag: fished-by:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fishing-rod: true
# Will show "Fished on <date>"
fished-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -102,7 +113,7 @@ enabled:
armor: true armor: true
fishing-rod: true fishing-rod: true
# Will show "Found by <player>" # Will show "Found by <player>"
looted-tag: looted-by:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -112,8 +123,30 @@ enabled:
bow: true bow: true
armor: true armor: true
fishing-rod: true fishing-rod: true
# Will show "Trade by <player>" # Will show "Found on <date>"
traded-tag: looted-on:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fishing-rod: true
# Will show "Traded by <player>"
traded-by:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fishing-rod: true
# Will show "Traded on <date>"
traded-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -148,7 +181,19 @@ enabled:
hoe: true hoe: true
shears: true shears: true
# Will show "Spawned in by <player>" # Will show "Spawned in by <player>"
spawned-in: spawned-in-by:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
mace: true
fishing-rod: true
# Will show "Spawned in on <date>"
spawned-in-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -163,15 +208,16 @@ enabled:
sheep-sheared: true sheep-sheared: true
armor-damage: true armor-damage: true
dropped-by: true dropped-by: true
dropped-on: true
elytra-tag: true elytra-tag: true
arrows-shot: true arrows-shot: true
flight-time: true flight-time: true
crops-harvested: true crops-harvested: true
messages: messages:
created: crafted:
created-by: "&7Crafted by: &8{player}" crafted-by: "&7Crafted by: &8{player}"
created-on: "&7Crafted on: &8{date}" crafted-on: "&7Crafted on: &8{date}"
fished: fished:
caught-by: "&7Caught by: &8{player}" caught-by: "&7Caught by: &8{player}"
caught-on: "&7Caught on: &8{date}" caught-on: "&7Caught on: &8{date}"
@@ -193,10 +239,11 @@ messages:
blocks-mined: "&7Blocks mined: &8{blocks}" blocks-mined: "&7Blocks mined: &8{blocks}"
crops-harvested: "&7Crops harvested: &8{crops}" crops-harvested: "&7Crops harvested: &8{crops}"
sheep-sheared: "&7Sheep sheared: &8{sheep}" sheep-sheared: "&7Sheep sheared: &8{sheep}"
dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name dropped-by: "&7Dropped by: &8{name}" # name will be mob name
dropped-on: "&7Dropped on: &8{date}"
damage-taken: "&7Damage taken: &8{damage}" damage-taken: "&7Damage taken: &8{damage}"
arrows-shot: "&7Arrows shot: &8{arrows}" arrows-shot: "&7Arrows shot: &8{arrows}"
flight-time: "&7Flight time: &8{time}" flight-time: "&7Flight time: &8{years}y {months}m {days}d {hours}h {minutes}m {seconds}s"
damage-done: "&7Damage done: &8{damage}" damage-done: "&7Damage done: &8{damage}"
# Set display name for mobs. See: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html # Set display name for mobs. See: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html
mobs: mobs:
@@ -220,4 +267,11 @@ number-formats:
# This has no use currently, but can be used for future features for dupe detection. # This has no use currently, but can be used for future features for dupe detection.
generate-hash-for-items: false generate-hash-for-items: false
config-version: 11 # Make when items are created at midnight on the date.
# This makes dates for items more "normalized" instead of being at different times.
normalize-time-creation: false
# Allows stats and origins to be tracked if the player is in creative mode.
allow-creative: false
config-version: 12

View File

@@ -26,3 +26,9 @@ permissions:
toolstats.givetokens: toolstats.givetokens:
description: Allows the usage of /toolstats givetoken. description: Allows the usage of /toolstats givetoken.
default: op default: op
toolstats.edit:
description: Allows the usage of /toolstats edit.
default: op
toolstats.remove:
description: Allows the usage of /toolstats remove.
default: op