Compare commits

...

26 Commits
1.2.1 ... 1.3.3

Author SHA1 Message Date
hyperdefined
63b3cb1d03 Update pom.xml 2022-02-23 19:57:41 -05:00
hyperdefined
7717b6b5a5 Update EntityDamage.java 2022-02-23 19:53:54 -05:00
hyperdefined
a421430fa8 only add damage to valid armor
closes #6
2022-02-23 19:52:58 -05:00
hyperdefined
7a89b31766 removed unused set 2022-02-22 19:05:00 -05:00
hyperdefined
0334681971 getFinalDamage() instead because of armor reductions 2022-02-22 17:33:48 -05:00
hyperdefined
df23f40d6b Update pom.xml 2022-02-22 15:08:38 -05:00
hyperdefined
0221ee40cf handle logic of lore reset better 2022-02-22 15:07:51 -05:00
hyperdefined
a01d07af4a fixed removing new tag for elytras
this fixes #5
2022-02-22 15:07:30 -05:00
hyperdefined
e402d3078a Merge pull request #4 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.10.0
Bump maven-compiler-plugin from 3.9.0 to 3.10.0
2022-02-14 21:07:02 -05:00
dependabot[bot]
4f44ca0777 Bump maven-compiler-plugin from 3.9.0 to 3.10.0
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.9.0...maven-compiler-plugin-3.10.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 11:38:14 +00:00
hyperdefined
53fd7f734c Update pom.xml 2022-02-12 20:47:52 -05:00
hyperdefined
75cd4fa17e fixed small typo 2022-02-12 20:47:32 -05:00
hyperdefined
e296c27a5b added comments to better explain what is going on 2022-02-11 19:19:05 -05:00
hyperdefined
adb1c637dc smh 2022-02-11 18:34:42 -05:00
hyperdefined
4b8f8061b4 Merge branch 'master' of https://github.com/hyperdefined/ToolStats 2022-02-11 15:09:49 -05:00
hyperdefined
464916e08b Update CommandToolStats.java 2022-02-11 15:09:32 -05:00
hyperdefined
6b6b65d1df Update README.md 2022-02-11 15:05:55 -05:00
hyperdefined
a1c39dffd0 Update pom.xml 2022-02-11 15:05:18 -05:00
hyperdefined
88eab81906 added tab completions to sub commands 2022-02-11 15:03:37 -05:00
hyperdefined
be233de90d fixed plugin.yml 2022-02-11 15:03:21 -05:00
hyperdefined
2437424e39 added reset lore command 2022-02-11 14:46:25 -05:00
hyperdefined
63b08062c8 Update CraftItem.java 2022-02-11 14:04:12 -05:00
hyperdefined
d23c2446dd fix fishing rods not updating lore correctly 2022-02-11 14:03:51 -05:00
hyperdefined
77b1be62d4 fixes 2022-02-10 21:41:23 -05:00
hyperdefined
29e6c998cf bump 2022-02-06 12:27:58 -05:00
hyperdefined
89951611fe changed api version to support more versions 2022-02-06 12:27:18 -05:00
16 changed files with 439 additions and 36 deletions

View File

@@ -1,7 +1,7 @@
<h1 align="center">ToolStats</h1> <h1 align="center">ToolStats</h1>
<p align="center"> <p align="center">
<img src="https://img.shields.io/badge/Minecraft-1.18+-orange" alt="Minecraft versions"> <img src="https://img.shields.io/badge/Minecraft-1.15+-orange" alt="Minecraft versions">
<img src="https://img.shields.io/github/v/release/hyperdefined/ToolStats" alt="GitHub release (latest by date)"> <img src="https://img.shields.io/github/v/release/hyperdefined/ToolStats" alt="GitHub release (latest by date)">
<a href="https://github.com/hyperdefined/ToolStats/releases"><img src="https://img.shields.io/github/downloads/hyperdefined/ToolStats/total?logo=github" alt="Downloads"></a> <a href="https://github.com/hyperdefined/ToolStats/releases"><img src="https://img.shields.io/github/downloads/hyperdefined/ToolStats/total?logo=github" alt="Downloads"></a>
<a href="https://en.cryptobadges.io/donate/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL"><img src="https://en.cryptobadges.io/badge/micro/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL" alt="Donate with Bitcoin"></a> <a href="https://en.cryptobadges.io/donate/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL"><img src="https://en.cryptobadges.io/badge/micro/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL" alt="Donate with Bitcoin"></a>
@@ -23,6 +23,8 @@ Here is everything it tracks:
The best part is, this data is stored on the item itself. You can also change how the lore is displayed on the items! The best part is, this data is stored on the item itself. You can also change how the lore is displayed on the items!
If item lore is ever incorrect, you can run `/toolstats reset` to reset the item lore so it's correct.
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image.png) ![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image2.png) ![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image2.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image3.png) ![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image3.png)

View File

@@ -23,7 +23,7 @@
<groupId>lol.hyper</groupId> <groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId> <artifactId>toolstats</artifactId>
<version>1.2.1</version> <version>1.3.3</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>ToolStats</name> <name>ToolStats</name>
@@ -51,7 +51,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version> <version>3.10.0</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>

View File

@@ -57,8 +57,6 @@ public final class ToolStats extends JavaPlugin {
// used for tracking new elytras // used for tracking new elytras
public final NamespacedKey newElytra = new NamespacedKey(this, "new"); public final NamespacedKey newElytra = new NamespacedKey(this, "new");
public final Set<NamespacedKey> keys = new HashSet<>();
public BlocksMined blocksMined; public BlocksMined blocksMined;
public ChunkPopulate chunkPopulate; public ChunkPopulate chunkPopulate;
public CraftItem craftItem; public CraftItem craftItem;
@@ -74,7 +72,7 @@ public final class ToolStats extends JavaPlugin {
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 FileConfiguration config; public FileConfiguration config;
public final int CONFIG_VERSION = 2; public final int CONFIG_VERSION = 3;
@Override @Override
public void onEnable() { public void onEnable() {
@@ -111,15 +109,6 @@ public final class ToolStats extends JavaPlugin {
new Metrics(this, 14110); new Metrics(this, 14110);
Bukkit.getScheduler().runTaskAsynchronously(this, this::checkForUpdates); Bukkit.getScheduler().runTaskAsynchronously(this, this::checkForUpdates);
keys.add(genericOwner);
keys.add(timeCreated);
keys.add(swordPlayerKills);
keys.add(swordMobKills);
keys.add(genericMined);
keys.add(fishingRodCaught);
keys.add(shearsSheared);
keys.add(armorDamage);
} }
public void loadConfig() { public void loadConfig() {
@@ -152,6 +141,12 @@ public final class ToolStats extends JavaPlugin {
} }
} }
/**
* Checks the config to see if we want to show lore on certain items.
* @param itemStack The item to check.
* @param configName The config we are checking under.
* @return If we want to allow lore or not.
*/
public boolean checkConfig(ItemStack itemStack, String configName) { public boolean checkConfig(ItemStack itemStack, String configName) {
String itemName = itemStack.getType().toString().toLowerCase(); String itemName = itemStack.getType().toString().toLowerCase();
String itemType = null; String itemType = null;
@@ -202,6 +197,12 @@ public final class ToolStats extends JavaPlugin {
return false; return false;
} }
/**
* Gets the lore message from the config.
* @param configName The config name, "messages." is already in front.
* @param raw If you want the raw message with the formatting codes and placeholders.
* @return The lore message.
*/
public String getLoreFromConfig(String configName, boolean raw) { public String getLoreFromConfig(String configName, boolean raw) {
String lore = config.getString("messages." + configName); String lore = config.getString("messages." + configName);
if (lore == null) { if (lore == null) {
@@ -235,6 +236,9 @@ public final class ToolStats extends JavaPlugin {
if (lore.contains("{damage}")) { if (lore.contains("{damage}")) {
lore = lore.replace("{damage}", ""); lore = lore.replace("{damage}", "");
} }
if (lore.contains("{fish}")) {
lore = lore.replace("{fish}", "");
}
} }
return lore; return lore;
} }

View File

@@ -18,36 +18,255 @@
package lol.hyper.toolstats.commands; package lol.hyper.toolstats.commands;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.ChatColor; import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.*;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CommandToolStats implements CommandExecutor { import java.text.SimpleDateFormat;
import java.util.*;
public class CommandToolStats implements TabExecutor {
private final ToolStats toolStats; private final ToolStats toolStats;
public CommandToolStats(ToolStats toolStats) { public CommandToolStats(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
@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[] args) {
if (!sender.hasPermission("toolstats.use")) {
sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
return true;
}
if (args.length == 0) { if (args.length == 0) {
sender.sendMessage(ChatColor.GREEN + "ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined."); sender.sendMessage(ChatColor.GREEN + "ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.");
} else if (args.length == 1) { }
if (args[0].equalsIgnoreCase("reload")) { switch (args[0]) {
case "reload": {
if (sender.isOp() || sender.hasPermission("toolstats.reload")) { if (sender.isOp() || sender.hasPermission("toolstats.reload")) {
toolStats.loadConfig(); toolStats.loadConfig();
sender.sendMessage(ChatColor.GREEN + "Configuration reloaded!"); sender.sendMessage(ChatColor.GREEN + "Configuration reloaded!");
} else { } else {
sender.sendMessage(ChatColor.RED + "You do not have permission for this command."); sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
} }
} else { return true;
}
case "reset": {
if (args.length == 2 && args[1].equalsIgnoreCase("confirm")) {
Player player = (Player) sender;
ItemStack heldItem = player.getInventory().getItemInMainHand();
if (heldItem.getType() == Material.AIR) {
sender.sendMessage(ChatColor.RED + "You must hold an item!");
return true;
}
fixItemLore(heldItem, player);
sender.sendMessage(ChatColor.GREEN + "The lore was reset!");
return true;
}
sender.sendMessage(ChatColor.GREEN + "This will remove ALL current lore from the held item and replace it with the correct lore.");
sender.sendMessage(ChatColor.GREEN + "The item owner will be who ever is currently running this command.");
sender.sendMessage(ChatColor.GREEN + "Only use this if the tags on the tool are incorrect.");
sender.sendMessage(ChatColor.GREEN + "Type /toolstats reset confirm to confirm this.");
return true;
}
default: {
sender.sendMessage(ChatColor.RED + "Invalid sub-command."); sender.sendMessage(ChatColor.RED + "Invalid sub-command.");
} }
} }
return true; return true;
} }
/**
* Fixes lore on a given item. This will wipe all lore and reapply our custom ones.
* @param original The item we are fixing.
* @param player The player running the command.
*/
private void fixItemLore(ItemStack original, Player player) {
ItemStack finalItem = original.clone();
ItemMeta finalMeta = finalItem.getItemMeta();
if (finalMeta == null) {
return;
}
PersistentDataContainer container = finalMeta.getPersistentDataContainer();
List<String> lore = new ArrayList<>();
String caughtByLore = toolStats.getLoreFromConfig("fished.caught-by", false);
String lootedByLore = toolStats.getLoreFromConfig("looted.found-by", false);
String tradedByLore = toolStats.getLoreFromConfig("traded.traded-by", false);
// make sure the config messages are not null
if (caughtByLore == null || lootedByLore == null || tradedByLore == null) {
return;
}
// determine how the item was originally created
// this doesn't get saved, so we just rely on the lore
// if there isn't a tag, default to crafted
String type = "DEFAULT";
if (finalMeta.hasLore()) {
if (finalMeta.getLore() != null) {
for (String line : finalMeta.getLore()) {
if (line.contains(caughtByLore)) {
type = "CAUGHT";
}
if (line.contains(lootedByLore)) {
type = "LOOTED";
}
if (line.contains(tradedByLore)) {
type = "TRADED";
}
}
}
}
// hard code elytras
if (finalItem.getType() == Material.ELYTRA) {
if (toolStats.config.getBoolean("enabled.elytra-tag")) {
lore.add(toolStats.getLoreFromConfig("looted.found-by", true).replace("{player}", player.getName()));
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) {
lore.add(toolStats.getLoreFromConfig("looted.found-on", true).replace("{date}", format.format(new Date(time))));
}
}
finalMeta.setLore(lore);
finalItem.setItemMeta(finalMeta);
int slot = player.getInventory().getHeldItemSlot();
player.getInventory().setItem(slot, finalItem);
return;
}
}
if (toolStats.checkConfig(original, "created-by")) {
if (container.has(toolStats.genericOwner, new UUIDDataType())) {
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
// show how the item was created based on the previous lore
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", player.getName()));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName()));
break;
}
case "LOOTED": {
lore.add(toolStats.getLoreFromConfig("looted.found-by", true).replace("{player}", player.getName()));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName()));
break;
}
}
}
}
if (toolStats.checkConfig(original, "created-date")) {
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) {
// show how when the item was created based on the previous lore
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-on", true).replace("{date}", format.format(new Date(time))));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", format.format(new Date(time))));
break;
}
case "LOOTED": {
lore.add(toolStats.getLoreFromConfig("looted.foundon", true).replace("{date}", format.format(new Date(time))));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-on", true).replace("{date}", format.format(new Date(time))));
break;
}
}
}
}
}
if (toolStats.checkConfig(original, "player-kills")) {
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
if (kills != null) {
lore.add(toolStats.getLoreFromConfig("kills.player", true).replace("{kills}", Integer.toString(kills)));
}
}
}
if (toolStats.checkConfig(original, "mob-kills")) {
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
if (kills != null) {
lore.add(toolStats.getLoreFromConfig("kills.mob", true).replace("{kills}", Integer.toString(kills)));
}
}
}
if (toolStats.checkConfig(original, "blocks-mined")) {
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
if (blocksMined != null) {
lore.add(toolStats.getLoreFromConfig("blocks-mined", true).replace("{blocks}", Integer.toString(blocksMined)));
}
}
}
if (toolStats.config.getBoolean("enabled.fish-caught")) {
if (container.has(toolStats.fishingRodCaught, PersistentDataType.INTEGER)) {
Integer fish = container.get(toolStats.fishingRodCaught, PersistentDataType.INTEGER);
if (fish != null) {
lore.add(toolStats.getLoreFromConfig("fished.fish-caught", true).replace("{fish}", Integer.toString(fish)));
}
}
}
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
if (container.has(toolStats.shearsSheared, PersistentDataType.INTEGER)) {
Integer sheep = container.get(toolStats.shearsSheared, PersistentDataType.INTEGER);
if (sheep != null) {
lore.add(toolStats.getLoreFromConfig("sheep-sheared", true).replace("{sheep}", Integer.toString(sheep)));
}
}
}
if (toolStats.config.getBoolean("enabled.armor-damage")) {
if (container.has(toolStats.armorDamage, PersistentDataType.INTEGER)) {
Integer damage = container.get(toolStats.armorDamage, PersistentDataType.INTEGER);
if (damage != null) {
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", Integer.toString(damage)));
}
}
}
finalMeta.setLore(lore);
finalItem.setItemMeta(finalMeta);
int slot = player.getInventory().getHeldItemSlot();
player.getInventory().setItem(slot, finalItem);
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
if (args.length == 1) {
if (sender.hasPermission("toolstats.reload")) {
return Arrays.asList("reset", "reload");
} else {
return Collections.singletonList("reset");
}
}
if (args.length == 2) {
if (args[0].equalsIgnoreCase("reset")) {
return Collections.singletonList("confirm");
}
}
return null;
}
} }

View File

@@ -44,18 +44,25 @@ public class BlocksMined implements Listener {
@EventHandler @EventHandler
public void onBreak(BlockBreakEvent event) { public void onBreak(BlockBreakEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
// ignore creative mode
if (player.getGameMode() != GameMode.SURVIVAL) { if (player.getGameMode() != GameMode.SURVIVAL) {
return; return;
} }
// if the player mines something with their fist
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot()); ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) { if (heldItem == null || heldItem.getType() == Material.AIR) {
return; return;
} }
// only check certain items
String itemName = heldItem.getType().toString().toLowerCase(); String itemName = heldItem.getType().toString().toLowerCase();
if (Arrays.stream(validTools).noneMatch(itemName::contains)) { if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
return; return;
} }
// if it's an item we want, update the stats
updateBlocksMined(heldItem); updateBlocksMined(heldItem);
} }
@@ -64,6 +71,8 @@ public class BlocksMined implements Listener {
if (meta == null) { if (meta == null) {
return; return;
} }
// read the current stats from the item
// if they don't exist, then start from 0
Integer blocksMined = 0; Integer blocksMined = 0;
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) { if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
@@ -79,6 +88,11 @@ public class BlocksMined implements Listener {
String configLore = toolStats.getLoreFromConfig("blocks-mined", false); String configLore = toolStats.getLoreFromConfig("blocks-mined", false);
String configLoreRaw = toolStats.getLoreFromConfig("blocks-mined", true); String configLoreRaw = toolStats.getLoreFromConfig("blocks-mined", true);
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
return;
}
List<String> lore; List<String> lore;
if (meta.hasLore()) { if (meta.hasLore()) {
lore = meta.getLore(); lore = meta.getLore();
@@ -86,10 +100,6 @@ public class BlocksMined implements Listener {
boolean hasLore = false; boolean hasLore = false;
// we do a for loop like this, we can keep track of index // we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items // this doesn't mess the lore up of existing items
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
return;
}
for (int x = 0; x < lore.size(); x++) { for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(configLore)) { if (lore.get(x).contains(configLore)) {
hasLore = true; hasLore = true;
@@ -106,6 +116,7 @@ public class BlocksMined implements Listener {
lore = new ArrayList<>(); lore = new ArrayList<>();
lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined))); lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
} }
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "blocks-mined")) { if (toolStats.checkConfig(itemStack, "blocks-mined")) {
meta.setLore(lore); meta.setLore(lore);
} }

View File

@@ -53,14 +53,17 @@ public class ChunkPopulate implements Listener {
Bukkit.getScheduler().runTaskLater(toolStats, () -> { Bukkit.getScheduler().runTaskLater(toolStats, () -> {
Chunk chunk = event.getChunk(); Chunk chunk = event.getChunk();
for (Entity entity : chunk.getEntities()) { for (Entity entity : chunk.getEntities()) {
// if there is a new item frame
if (entity instanceof ItemFrame) { if (entity instanceof ItemFrame) {
ItemFrame itemFrame = (ItemFrame) entity; ItemFrame itemFrame = (ItemFrame) entity;
// if the item frame has an elytra
if (itemFrame.getItem().getType() == Material.ELYTRA) { if (itemFrame.getItem().getType() == Material.ELYTRA) {
ItemStack elytraCopy = itemFrame.getItem(); ItemStack elytraCopy = itemFrame.getItem();
ItemMeta meta = elytraCopy.getItemMeta(); ItemMeta meta = elytraCopy.getItemMeta();
if (meta == null) { if (meta == null) {
return; return;
} }
// add the new tag so we know it's new
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(toolStats.newElytra, PersistentDataType.INTEGER, 1); container.set(toolStats.newElytra, PersistentDataType.INTEGER, 1);
elytraCopy.setItemMeta(meta); elytraCopy.setItemMeta(meta);

View File

@@ -19,6 +19,7 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType; import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -46,31 +47,61 @@ public class CraftItem implements Listener {
@EventHandler @EventHandler
public void onCraft(CraftItemEvent event) { public void onCraft(CraftItemEvent event) {
if (event.isCancelled()) {
return;
}
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
ItemStack itemStack = event.getCurrentItem(); ItemStack itemStack = event.getCurrentItem();
if (itemStack == null || itemStack.getType() == Material.AIR) { if (itemStack == null || itemStack.getType() == Material.AIR) {
return; return;
} }
String name = itemStack.getType().toString().toLowerCase(Locale.ROOT); String name = itemStack.getType().toString().toLowerCase(Locale.ROOT);
// only check for items we want
for (String x : validItems) { for (String x : validItems) {
if (name.contains(x)) { if (name.contains(x)) {
// if the player shift clicks, send them this warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.crafting");
if (configMessage != null) {
if (configMessage.length() != 0) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
}
// test the item before setting it
if (addLore(itemStack, player) == null) { if (addLore(itemStack, player) == null) {
return; return;
} }
// set the result
event.setCurrentItem(addLore(itemStack, player)); event.setCurrentItem(addLore(itemStack, player));
} }
} }
} }
/**
* Adds crafted tags to item.
* @param itemStack The item add item to.
* @param owner The player crafting.
* @return A copy of the item with the tags + lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) { private ItemStack addLore(ItemStack itemStack, Player owner) {
// clone the item
ItemStack newItem = itemStack.clone(); ItemStack newItem = itemStack.clone();
ItemMeta meta = newItem.getItemMeta(); ItemMeta meta = newItem.getItemMeta();
if (meta == null) { if (meta == null) {
return null; return null;
} }
// get the current time
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag
// this is to prevent duplicate tags
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return null;
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
@@ -87,12 +118,14 @@ public class CraftItem implements Listener {
} }
List<String> lore; List<String> lore;
// get the current lore the item
if (meta.hasLore()) { if (meta.hasLore()) {
lore = meta.getLore(); lore = meta.getLore();
assert lore != null; assert lore != null;
} else { } else {
lore = new ArrayList<>(); lore = new ArrayList<>();
} }
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "created-date")) { if (toolStats.checkConfig(itemStack, "created-date")) {
lore.add(createdOnRaw.replace("{date}", format.format(finalDate))); lore.add(createdOnRaw.replace("{date}", format.format(finalDate)));
} }

View File

@@ -49,6 +49,9 @@ public class EntityDamage implements Listener {
@EventHandler @EventHandler
public void onDamage(EntityDamageByEntityEvent event) { public void onDamage(EntityDamageByEntityEvent event) {
if (event.isCancelled()) {
return;
}
if (!(event.getEntity() instanceof LivingEntity)) { if (!(event.getEntity() instanceof LivingEntity)) {
return; return;
} }
@@ -61,10 +64,12 @@ public class EntityDamage implements Listener {
if (player.getGameMode() != GameMode.SURVIVAL) { if (player.getGameMode() != GameMode.SURVIVAL) {
return; return;
} }
// a player killed something with their fist
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot()); ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) { if (heldItem == null || heldItem.getType() == Material.AIR) {
return; return;
} }
// check items we want
String itemName = heldItem.getType().toString().toLowerCase(); String itemName = heldItem.getType().toString().toLowerCase();
if (Arrays.stream(validTools).noneMatch(itemName::contains)) { if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
return; return;
@@ -78,9 +83,11 @@ public class EntityDamage implements Listener {
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updateMobKills(heldItem)); player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updateMobKills(heldItem));
trackedMobs.add(livingEntity.getUniqueId()); trackedMobs.add(livingEntity.getUniqueId());
} }
// trident is being thrown at something
if (event.getDamager() instanceof Trident) { if (event.getDamager() instanceof Trident) {
Trident trident = (Trident) event.getDamager(); Trident trident = (Trident) event.getDamager();
ItemStack clone; ItemStack clone;
// trident is killing player
if (livingEntity instanceof Player) { if (livingEntity instanceof Player) {
clone = updatePlayerKills(trident.getItem()); clone = updatePlayerKills(trident.getItem());
} else { } else {
@@ -91,14 +98,18 @@ public class EntityDamage implements Listener {
} }
trident.setItem(clone); trident.setItem(clone);
} }
// arrow is being shot
if (event.getDamager() instanceof Arrow) { if (event.getDamager() instanceof Arrow) {
Arrow arrow = (Arrow) event.getDamager(); Arrow arrow = (Arrow) event.getDamager();
// if the shooter is a player
if (arrow.getShooter() instanceof Player) { if (arrow.getShooter() instanceof Player) {
Player player = (Player) arrow.getShooter(); Player player = (Player) arrow.getShooter();
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot()); ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null) { if (heldItem == null) {
return; return;
} }
// if the player is holding the bow/crossbow
// if they switch then oh well
if (heldItem.getType() == Material.BOW || heldItem.getType() == Material.CROSSBOW) { if (heldItem.getType() == Material.BOW || heldItem.getType() == Material.CROSSBOW) {
if (livingEntity instanceof Player) { if (livingEntity instanceof Player) {
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updatePlayerKills(heldItem)); player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updatePlayerKills(heldItem));
@@ -115,7 +126,9 @@ public class EntityDamage implements Listener {
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) { for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) { if (armor != null) {
updateArmorDamage(armor, event.getDamage()); if (isArmor(armor.getType().toString().toLowerCase(Locale.ROOT))) {
updateArmorDamage(armor, event.getFinalDamage());
}
} }
} }
} }
@@ -127,12 +140,15 @@ public class EntityDamage implements Listener {
return; return;
} }
LivingEntity livingEntity = (LivingEntity) event.getEntity(); LivingEntity livingEntity = (LivingEntity) event.getEntity();
// player is taken damage but not being killed
if (livingEntity instanceof Player) { if (livingEntity instanceof Player) {
Player player = (Player) livingEntity; Player player = (Player) livingEntity;
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) { for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) { if (armor != null) {
updateArmorDamage(armor, event.getDamage()); if (isArmor(armor.getType().toString().toLowerCase(Locale.ROOT))) {
updateArmorDamage(armor, event.getFinalDamage());
}
} }
} }
} }
@@ -144,17 +160,25 @@ public class EntityDamage implements Listener {
return; return;
} }
LivingEntity livingEntity = (LivingEntity) event.getEntity(); LivingEntity livingEntity = (LivingEntity) event.getEntity();
// player is taken damage but not being killed
if (livingEntity instanceof Player) { if (livingEntity instanceof Player) {
Player player = (Player) livingEntity; Player player = (Player) livingEntity;
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) { for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) { if (armor != null) {
updateArmorDamage(armor, event.getDamage()); if (isArmor(armor.getType().toString().toLowerCase(Locale.ROOT))) {
updateArmorDamage(armor, event.getFinalDamage());
}
} }
} }
} }
} }
/**
* Updates a weapon's player kills.
* @param itemStack The item to update.
* @return A copy of the item.
*/
private ItemStack updatePlayerKills(ItemStack itemStack) { private ItemStack updatePlayerKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone(); ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta(); ItemMeta meta = finalItem.getItemMeta();
@@ -204,6 +228,7 @@ public class EntityDamage implements Listener {
lore = new ArrayList<>(); lore = new ArrayList<>();
lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills))); lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
} }
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "player-kills")) { if (toolStats.checkConfig(itemStack, "player-kills")) {
meta.setLore(lore); meta.setLore(lore);
} }
@@ -211,6 +236,11 @@ public class EntityDamage implements Listener {
return finalItem; return finalItem;
} }
/**
* Updates a weapon's mob kills.
* @param itemStack The item to update.
* @return A copy of the item.
*/
private ItemStack updateMobKills(ItemStack itemStack) { private ItemStack updateMobKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone(); ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta(); ItemMeta meta = finalItem.getItemMeta();
@@ -260,6 +290,7 @@ public class EntityDamage implements Listener {
lore = new ArrayList<>(); lore = new ArrayList<>();
lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills))); lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
} }
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "mob-kills")) { if (toolStats.checkConfig(itemStack, "mob-kills")) {
meta.setLore(lore); meta.setLore(lore);
} }
@@ -267,6 +298,11 @@ public class EntityDamage implements Listener {
return finalItem; return finalItem;
} }
/**
* Updates a player's armor damage stats.
* @param itemStack The armor piece.
* @param damage How much damage is being added.
*/
private void updateArmorDamage(ItemStack itemStack, double damage) { private void updateArmorDamage(ItemStack itemStack, double damage) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -321,4 +357,13 @@ public class EntityDamage implements Listener {
} }
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
} }
/**
* Check if item is an armor piece.
* @param itemType The item type, not name.
* @return If the item is an armor piece.
*/
private boolean isArmor(String itemType) {
return itemType.endsWith("_helmet") || itemType.endsWith("_chestplate") || itemType.endsWith("_leggings") || itemType.endsWith("_boots");
}
} }

View File

@@ -43,6 +43,7 @@ public class EntityDeath implements Listener {
return; return;
} }
UUID livingEntityUUID = event.getEntity().getUniqueId(); UUID livingEntityUUID = event.getEntity().getUniqueId();
// if it's a mob we are tracking that matters
if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) { if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) {
for (ItemStack current : event.getDrops()) { for (ItemStack current : event.getDrops()) {
String name = current.getType().toString().toLowerCase(Locale.ROOT); String name = current.getType().toString().toLowerCase(Locale.ROOT);
@@ -56,6 +57,11 @@ public class EntityDeath implements Listener {
} }
} }
/**
* Adds "drop by" tag to item.
* @param itemStack The item to add lore to.
* @param mob The mob or player name.
*/
private void addLore(ItemStack itemStack, String mob) { private void addLore(ItemStack itemStack, String mob) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -87,7 +93,7 @@ public class EntityDeath implements Listener {
lore = new ArrayList<>(); lore = new ArrayList<>();
} }
if (!hasTag) { if (!hasTag) {
lore.add(droppedByLoreRaw.replace("X", mob)); lore.add(droppedByLoreRaw.replace("{name}", mob));
} }
if (toolStats.config.getBoolean("enabled.dropped-by")) { if (toolStats.config.getBoolean("enabled.dropped-by")) {
meta.setLore(lore); meta.setLore(lore);

View File

@@ -57,10 +57,13 @@ public class GenerateLoot implements Listener {
return; return;
} }
Inventory chest = inventoryHolder.getInventory(); Inventory chest = inventoryHolder.getInventory();
// run task later since if it runs on the same tick it breaks idk
Bukkit.getScheduler().runTaskLater(toolStats, () -> { Bukkit.getScheduler().runTaskLater(toolStats, () -> {
Player player = (Player) chest.getViewers().get(0); Player player = (Player) chest.getViewers().get(0);
// do a classic for loot so we keep track of chest index of item
for (int i = 0; i < chest.getContents().length; i++) { for (int i = 0; i < chest.getContents().length; i++) {
ItemStack itemStack = chest.getItem(i); ItemStack itemStack = chest.getItem(i);
// ignore air
if (itemStack == null || itemStack.getType() == Material.AIR) { if (itemStack == null || itemStack.getType() == Material.AIR) {
continue; continue;
} }
@@ -75,6 +78,12 @@ public class GenerateLoot implements Listener {
},1); },1);
} }
/**
* Adds lore to newly generated items.
* @param itemStack The item to add lore to.
* @param owner The player that found the item.
* @return The item with the lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) { private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemStack newItem = itemStack.clone(); ItemStack newItem = itemStack.clone();
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
@@ -84,6 +93,11 @@ public class GenerateLoot implements Listener {
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return null;
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());

View File

@@ -47,6 +47,9 @@ public class PickupItem implements Listener {
@EventHandler @EventHandler
public void onPickup(EntityPickupItemEvent event) { public void onPickup(EntityPickupItemEvent event) {
if (event.isCancelled()) {
return;
}
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if (entity instanceof Player) { if (entity instanceof Player) {
ItemStack itemStack = event.getItem().getItemStack(); ItemStack itemStack = event.getItem().getItemStack();
@@ -58,13 +61,17 @@ public class PickupItem implements Listener {
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// the elytra has the new key, set the lore to it // the elytra has the new key, set the lore to it
if (container.has(toolStats.newElytra, PersistentDataType.INTEGER)) { if (container.has(toolStats.newElytra, PersistentDataType.INTEGER)) {
container.remove(toolStats.newElytra);
addLore(itemStack, (Player) event.getEntity()); addLore(itemStack, (Player) event.getEntity());
} }
} }
} }
} }
/**
* Adds "looted by" tags for elytras.
* @param itemStack The elytra to add lore to.
* @param owner The player who found it.
*/
private void addLore(ItemStack itemStack, Player owner) { private void addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -75,6 +82,7 @@ public class PickupItem implements Listener {
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.remove(toolStats.newElytra);
String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true); String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true);
String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true); String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true);

View File

@@ -50,6 +50,9 @@ public class PlayerFish implements Listener {
@EventHandler @EventHandler
public void onFish(PlayerFishEvent event) { public void onFish(PlayerFishEvent event) {
if (event.isCancelled()) {
return;
}
// only listen to when a player catches a fish // only listen to when a player catches a fish
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) { if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) {
return; return;
@@ -72,6 +75,10 @@ public class PlayerFish implements Listener {
} }
} }
/**
* Updates a fishing rod's count.
* @param itemStack The fishing rod to update.
*/
private void updateFishCount(ItemStack itemStack) { private void updateFishCount(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -126,6 +133,11 @@ public class PlayerFish implements Listener {
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
} }
/**
* Adds "caught by" tags to newly fished items.
* @param itemStack The item to add lore to.
* @param owner The player who caught the item.
*/
private void addNewLore(ItemStack itemStack, Player owner) { private void addNewLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -134,6 +146,11 @@ public class PlayerFish implements Listener {
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return;
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());

View File

@@ -43,22 +43,31 @@ public class SheepShear implements Listener {
@EventHandler @EventHandler
public void onShear(PlayerInteractEntityEvent event) { public void onShear(PlayerInteractEntityEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer(); Player player = event.getPlayer();
Entity entity = event.getRightClicked(); Entity entity = event.getRightClicked();
if (!(entity instanceof Sheep)) { if (!(entity instanceof Sheep)) {
return; return;
} }
// check if the player is right-clicking with shears only
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot()); ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.SHEARS) { if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.SHEARS) {
return; return;
} }
Sheep sheep = (Sheep) entity; Sheep sheep = (Sheep) entity;
// make sure the sheep is not sheared
if (!sheep.isSheared()) { if (!sheep.isSheared()) {
addLore(heldItem); addLore(heldItem);
} }
} }
/**
* Adds tags to shears.
* @param itemStack The shears.
*/
private void addLore(ItemStack itemStack) { private void addLore(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {

View File

@@ -20,6 +20,7 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType; import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; 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;
@@ -56,15 +57,27 @@ public class VillagerTrade implements Listener {
return; return;
} }
Inventory inventory = event.getClickedInventory(); Inventory inventory = event.getClickedInventory();
// only check villager inventories
if (inventory instanceof MerchantInventory) { if (inventory instanceof MerchantInventory) {
// only check the result slot (the item you receive)
if (event.getSlotType() == InventoryType.SlotType.RESULT) { if (event.getSlotType() == InventoryType.SlotType.RESULT) {
ItemStack item = event.getCurrentItem(); ItemStack item = event.getCurrentItem();
// only check items we want
for (String x : validItems) { for (String x : validItems) {
if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) { if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
// if the player shift clicks show the warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.trading");
if (configMessage != null) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
ItemStack newItem = addLore(item, (Player) event.getWhoClicked()); ItemStack newItem = addLore(item, (Player) event.getWhoClicked());
if (newItem == null) { if (newItem == null) {
return; return;
} }
// this gets delayed since villager inventories suck for no reason
// if you don't delay this it doesn't work idk
Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5); Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5);
} }
} }
@@ -72,6 +85,12 @@ public class VillagerTrade implements Listener {
} }
} }
/**
* Adds "traded by" tags to item.
* @param itemStack The item to add lore.
* @param owner The player who traded.
* @return The item with lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) { private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
if (meta == null) { if (meta == null) {
@@ -80,6 +99,11 @@ public class VillagerTrade implements Listener {
long timeCreated = System.currentTimeMillis(); long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated); Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return null;
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId()); container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());

View File

@@ -92,5 +92,10 @@ messages:
sheep-sheared: "&7Sheep sheared: &8{sheep}" sheep-sheared: "&7Sheep sheared: &8{sheep}"
dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name
damage-taken: "&7Damage taken: &8{damage}" damage-taken: "&7Damage taken: &8{damage}"
# Display this message if the player shift click trades/crafts items. It's not really easy to get every single item
# that is crafted. The tag will only be added to the first item. If you don't want this message, simply replace them both with ""
shift-click-warning:
crafting: "&cCrafting items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
trading: "&cTrading items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
config-version: 2 config-version: 3

View File

@@ -1,15 +1,18 @@
name: ToolStats name: ToolStats
version: '${project.version}' version: '${project.version}'
main: lol.hyper.toolstats.ToolStats main: lol.hyper.toolstats.ToolStats
api-version: 1.18 api-version: 1.15
author: hyperdefined author: hyperdefined
description: Track various tool stats! description: Track various tool stats!
commands: commands:
toolstats: toolstats:
usage: /toolstats usage: /toolstats
description: Main command. description: Main command.
permission: randomenchant.reload permission: toolstats.main
permissions: permissions:
randomenchant.reload: toolstats.main:
description: Allows the usage of /randomenchant reload description: Allows the usage of /toolstats
default: op default: true
toolstats.reload:
description: Allows the usage of /toolstats reload
default: op