Compare commits

..

64 Commits
1.9.5 ... 2.0

Author SHA1 Message Date
hyperdefined
5c4b212390 forgot to update 2026-01-26 16:33:30 -05:00
hyperdefined
e321e9066c omg???? 2026-01-26 16:31:24 -05:00
hyperdefined
a0b64e0499 handle edge case
player drops new item from a looted chest onto ground, add origin to it
2026-01-26 16:29:17 -05:00
hyperdefined
6204a3e22b properly handle breaking chest gen 2026-01-26 16:19:00 -05:00
hyperdefined
9e9482067d typo in updater 2026-01-26 15:36:32 -05:00
hyperdefined
58a74a0cdd properly do black/whitelist feature based on feedback 2026-01-26 15:23:20 -05:00
hyperdefined
9755ac2035 check all inventories 2026-01-26 13:38:17 -05:00
hyperdefined
06232f1dc4 sigh I am dumb 2026-01-26 13:32:28 -05:00
hyperdefined
a21fbf7a95 add blacklist-worlds feature 2026-01-26 13:23:28 -05:00
hyperdefined
96dd3ccd89 Update README.md 2026-01-25 17:51:55 -05:00
hyperdefined
fb1901085c config updater for 14 -> 15 2026-01-25 17:50:18 -05:00
hyperdefined
e537286785 improve compatibility with ValhallaMMO
fuck this plugin holy fuck
2026-01-20 20:14:18 -05:00
hyperdefined
6a994e4a82 move keys to own class
this took forever
2026-01-20 17:39:08 -05:00
hyperdefined
8a4da8ad56 add trident throws 2026-01-14 17:44:33 -05:00
hyperdefined
25e5a13095 support shields for damage taken 2026-01-14 16:57:49 -05:00
hyperdefined
72a5de5ee8 im a brick sometimes 2026-01-14 14:14:33 -05:00
hyperdefined
43b811db4e Update TokenData.java 2026-01-14 14:13:44 -05:00
hyperdefined
bd4ab50dc7 add critical strikes 2026-01-14 14:12:04 -05:00
hyperdefined
3087e3adcb more missing things 2026-01-14 13:58:02 -05:00
hyperdefined
588f413484 more misc things for bosses killed 2026-01-14 13:44:38 -05:00
hyperdefined
7beaa151c1 add bosses killed stat 2026-01-14 13:24:51 -05:00
hyperdefined
b5040a4636 1.9.11 (spear support) 2025-12-22 19:09:14 -05:00
hyperdefined
c28ee0fb8c check for creative mode here 2025-11-05 17:21:53 -05:00
hyperdefined
8fe7292505 1.9.10 2025-11-05 17:20:57 -05:00
hyperdefined
3da74fe656 close #113
added all types of containers to loot checking. also added trial chamber stuff
2025-11-05 17:19:45 -05:00
hyperdefined
ab0d2a1ca1 Update pom.xml 2025-09-30 17:44:01 -04:00
hyperdefined
857ce5b631 Merge pull request #111 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.6.1
Bump org.apache.maven.plugins:maven-shade-plugin from 3.6.0 to 3.6.1
2025-09-26 13:43:24 -04:00
hyperdefined
b14fb30212 Merge pull request #112 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.14.1
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.14.0 to 3.14.1
2025-09-26 13:40:47 -04:00
dependabot[bot]
a9bb876b38 Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.14.0 to 3.14.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.0...maven-compiler-plugin-3.14.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-23 11:04:12 +00:00
dependabot[bot]
e819fadd50 Bump org.apache.maven.plugins:maven-shade-plugin from 3.6.0 to 3.6.1
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.6.0 to 3.6.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.6.0...v3.6.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-version: 3.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-15 12:04:39 +00:00
hyperdefined
c22c36f0a4 Update README.md 2025-08-08 22:24:09 -04:00
hyperdefined
e38ffdef07 forgot these 2025-08-06 19:43:24 -04:00
hyperdefined
c7540244bc update things 2025-08-06 19:34:59 -04:00
hyperdefined
613957fadf hyperlib updates 2025-08-06 19:09:13 -04:00
hyperdefined
e48be6ba20 hyperlib demo 2025-08-04 13:29:26 -04:00
hyperdefined
c0d79fd740 Update pom.xml 2025-07-23 12:31:06 -04:00
hyperdefined
b056972d30 swap order of anvil checking to account 2025-07-23 12:30:46 -04:00
hyperdefined
525df4bcf6 use the new GLIDER DataComponent 2025-07-23 12:19:40 -04:00
hyperdefined
86cbdd58ff new purge command 2025-07-23 11:29:20 -04:00
hyperdefined
27a89fd67c unify owner and timestamp creation 2025-07-23 10:53:22 -04:00
hyperdefined
70ed50ce9e 1.9.8
closes #109
2025-07-15 10:49:19 -04:00
hyperdefined
84c1f8313a Merge pull request #108 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-clean-plugin-3.5.0
Bump org.apache.maven.plugins:maven-clean-plugin from 3.4.1 to 3.5.0
2025-06-08 20:07:25 -04:00
dependabot[bot]
f7ec488396 Bump org.apache.maven.plugins:maven-clean-plugin from 3.4.1 to 3.5.0
Bumps [org.apache.maven.plugins:maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-clean-plugin/releases)
- [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.4.1...maven-clean-plugin-3.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 11:58:28 +00:00
hyperdefined
df014fd888 docs update 2025-05-21 15:12:54 -04:00
hyperdefined
1d617706a6 Update pom.xml 2025-05-15 18:56:27 -04:00
hyperdefined
49e1acc66a imports 2025-05-15 18:52:00 -04:00
hyperdefined
eddaec1543 remove hard coded paper material 2025-05-15 18:51:17 -04:00
hyperdefined
57ec36d5a7 oops lol 2025-05-15 18:49:35 -04:00
hyperdefined
a617875975 Update CommandToolStats.java 2025-05-15 18:47:38 -04:00
hyperdefined
3ee53e0cf7 config updater for 13 2025-05-15 18:44:48 -04:00
hyperdefined
364859bc0a few fixes 2025-05-15 18:33:27 -04:00
hyperdefined
0efc07b12b Update TokenData.java 2025-05-15 18:15:27 -04:00
hyperdefined
e73ba5376c Update config.yml 2025-05-15 18:14:00 -04:00
hyperdefined
68318e3af2 {levels} placeholder 2025-05-15 18:13:47 -04:00
hyperdefined
c7cd25e866 custom model data & massive cleanup
closes #105
2025-05-15 17:59:44 -04:00
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
76 changed files with 4206 additions and 1711 deletions

View File

@@ -4,45 +4,49 @@
<a href="https://modrinth.com/plugin/ToolStats"><img alt="modrinth" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/modrinth_vector.svg"></a> <a href="https://modrinth.com/plugin/ToolStats"><img alt="modrinth" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/modrinth_vector.svg"></a>
<a href="https://hangar.papermc.io/hyperdefined/ToolStats"><img alt="hangar" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/hangar_vector.svg"></a> <a href="https://hangar.papermc.io/hyperdefined/ToolStats"><img alt="hangar" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/hangar_vector.svg"></a>
<a href="https://papermc.io"><img alt="paper" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg"></a> <a href="https://papermc.io"><img alt="paper" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg"></a>
<a href="https://github.com/hyperdefined/ToolStats/wiki"><img alt="ghpages" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/ghpages_vector.svg"></a> <a href="https://docs.hyper.lol/plugins/toolstats/about/"><img alt="ghpages" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/ghpages_vector.svg"></a>
<a href="https://discord.gg/rJuQXVcJz8"><img alt="discord-singular" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg"></a> <a href="https://discord.gg/rJuQXVcJz8"><img alt="discord-singular" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg"></a>
<a href="https://buymeacoffee.com/hyperdefined"><img alt="buymeacoffee-singular" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/donate/buymeacoffee-singular_vector.svg"></a> <a href="https://buymeacoffee.com/hyperdefined"><img alt="buymeacoffee-singular" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/donate/buymeacoffee-singular_vector.svg"></a>
<a href="https://patreon.com/hyperdefined"><img alt="patreon-singular" height="40" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/donate/patreon-singular_vector.svg"></a>
</p> </p>
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/vaults/barrels), traded, spawned via creative, and caught from fishing.
* Armor damage taken. * Armor damage taken (shields too).
* 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.
* Critical strikes for melee weapons.
* Times trident thrown.
The best part is, this data is stored on the item itself. The best part is, this data is stored on the item itself.
If item lore is ever incorrect/missing, you can run `/toolstats reset`. This command fixes the lore on whatever item you are holding. If item lore is ever incorrect/missing, you can run `/toolstats reset`. This command fixes the lore on whatever item you are holding.
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image2.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image2.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image3.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image3.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image4.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image4.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image5.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image5.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image6.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image6.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image7.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image7.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image8.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image8.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image9.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image9.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image10.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image10.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image11.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image11.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image13.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image13.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image14.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image14.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image12.png) ![Image](https://docs.hyper.lol/plugins/toolstats/assets/image12.png)
## Documentation ## Documentation
Visit the [wiki](https://github.com/hyperdefined/ToolStats/wiki) for help. Visit the [wiki](https://docs.hyper.lol/plugins/toolstats/about/) for help.
## License ## License
This plugin is released under GNU General Public License v3. See [LICENSE](https://github.com/hyperdefined/ToolStats/blob/master/LICENSE). This plugin is released under GNU General Public License v3. See [LICENSE](https://github.com/hyperdefined/ToolStats/blob/master/LICENSE).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

34
pom.xml
View File

@@ -23,7 +23,7 @@
<groupId>lol.hyper</groupId> <groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId> <artifactId>toolstats</artifactId>
<version>1.9.5</version> <version>2.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>ToolStats</name> <name>ToolStats</name>
@@ -37,7 +37,7 @@
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-clean-plugin</artifactId> <artifactId>maven-clean-plugin</artifactId>
<version>3.4.1</version> <version>3.5.0</version>
<executions> <executions>
<execution> <execution>
<id>auto-clean</id> <id>auto-clean</id>
@@ -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.14.0</version> <version>3.14.1</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>
@@ -60,16 +60,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version> <version>3.6.1</version>
<configuration> <configuration>
<relocations> <relocations>
<relocation> <relocation>
<pattern>org.bstats</pattern> <pattern>lol.hyper.hyperlib</pattern>
<shadedPattern>lol.hyper.toolstats.bstats</shadedPattern> <shadedPattern>lol.hyper.toolstats.hyperlib</shadedPattern>
</relocation>
<relocation>
<pattern>lol.hyper.githubreleaseapi</pattern>
<shadedPattern>lol.hyper.toolstats.updater</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>
@@ -99,25 +95,23 @@
<id>papermc</id> <id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url> <url>https://repo.papermc.io/repository/maven-public/</url>
</repository> </repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>io.papermc.paper</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId> <artifactId>paper-api</artifactId>
<version>1.21.5-R0.1-SNAPSHOT</version> <version>1.21.11-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.bstats</groupId> <groupId>com.github.hyperdefined</groupId>
<artifactId>bstats-bukkit</artifactId> <artifactId>hyperlib</artifactId>
<version>3.1.0</version> <version>1.0.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>lol.hyper</groupId>
<artifactId>github-release-api</artifactId>
<version>1.0.5</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -17,111 +17,29 @@
package lol.hyper.toolstats; package lol.hyper.toolstats;
import lol.hyper.githubreleaseapi.GitHubRelease; import lol.hyper.hyperlib.HyperLib;
import lol.hyper.githubreleaseapi.GitHubReleaseAPI; import lol.hyper.hyperlib.bstats.HyperStats;
import lol.hyper.githubreleaseapi.ReleaseNotFoundException; import lol.hyper.hyperlib.releases.HyperUpdater;
import lol.hyper.hyperlib.utils.TextUtils;
import lol.hyper.toolstats.commands.CommandToolStats; import lol.hyper.toolstats.commands.CommandToolStats;
import lol.hyper.toolstats.events.*; import lol.hyper.toolstats.events.*;
import lol.hyper.toolstats.tools.*; import lol.hyper.toolstats.tools.*;
import lol.hyper.toolstats.tools.config.ConfigTools; import lol.hyper.toolstats.tools.config.ConfigTools;
import lol.hyper.toolstats.tools.config.ConfigUpdater; import lol.hyper.toolstats.tools.config.ConfigUpdater;
import lol.hyper.toolstats.tools.config.TokenItems; import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
public final class ToolStats extends JavaPlugin { public final class ToolStats extends JavaPlugin {
/** public final int CONFIG_VERSION = 15;
* Stores who created an item. public final ComponentLogger logger = this.getComponentLogger();
*/
public final NamespacedKey itemOwner = new NamespacedKey(this, "owner");
/**
* Stores when the item was created.
*/
public final NamespacedKey timeCreated = new NamespacedKey(this, "time-created");
/**
* Stores how many player kills.
*/
public final NamespacedKey playerKills = new NamespacedKey(this, "player-kills");
/**
* Stores how many mob kills.
*/
public final NamespacedKey mobKills = new NamespacedKey(this, "mob-kills");
/**
* Stores how many blocks were mined.
*/
public final NamespacedKey blocksMined = new NamespacedKey(this, "generic-mined");
/**
* Stores how many crops were harvested.
*/
public final NamespacedKey cropsHarvested = new NamespacedKey(this, "crops-mined");
/**
* Stores how many fish were caught.
*/
public final NamespacedKey fishCaught = new NamespacedKey(this, "fish-caught");
/**
* Stores how many sheep were sheared.
*/
public final NamespacedKey sheepSheared = new NamespacedKey(this, "sheared");
/**
* Stores how much damage an armor piece has taken.
*/
public final NamespacedKey armorDamage = new NamespacedKey(this, "damage-taken");
/**
* Stores how much damage a weapon has done.
*/
public final NamespacedKey damageDone = new NamespacedKey(this, "damage-done");
/**
* Key for tracking new elytras that spawn.
*/
public final NamespacedKey newElytra = new NamespacedKey(this, "new");
/**
* Key for item has.
*/
public final NamespacedKey hash = new NamespacedKey(this, "hash");
/**
* Key for arrows shot.
*/
public final NamespacedKey arrowsShot = new NamespacedKey(this, "arrows-shot");
/**
* Key for tracking flight time.
*/
public final NamespacedKey flightTime = new NamespacedKey(this, "flightTime");
/**
* Key for token type. This is for the token itself.
*/
public final NamespacedKey tokenType = new NamespacedKey(this, "token-type");
/**
* Key for applied token. This is what goes onto the tool/armor to record the type.
*/
public final NamespacedKey tokenApplied = new NamespacedKey(this, "token-applied");
/**
* Stores how an item was created.
* 0 = crafted.
* 1 = dropped.
* 2 = looted.
* 3 = traded.
* 4 = founded (for elytras).
* 5 = fished.
* 6 = spawned in (creative).
*/
public final NamespacedKey originType = new NamespacedKey(this, "origin");
public final int CONFIG_VERSION = 11;
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;
public final Set<NamespacedKey> tokenKeys = new HashSet<>();
public BlockBreak blockBreak; public BlockBreak blockBreak;
public ChunkPopulate chunkPopulate; public ChunkPopulate chunkPopulate;
@@ -146,13 +64,27 @@ public final class ToolStats extends JavaPlugin {
public ItemChecker itemChecker; public ItemChecker itemChecker;
public ShootBow shootBow; public ShootBow shootBow;
public ConfigTools configTools; public ConfigTools configTools;
public TokenItems tokenItems; public TokenData tokenData;
public TokenCrafting tokenCrafting;
public AnvilEvent anvilEvent; public AnvilEvent anvilEvent;
public PrepareCraft prepareCraft; public PrepareCraft prepareCraft;
public BlockDispenseEvent blockDispenseEvent;
public HyperLib hyperLib;
public TextUtils textUtils;
public ProjectileShoot projectileShoot;
public ToolStatsKeys toolStatsKeys;
public InventoryClose inventoryClose;
public PlayerDrop playerDrop;
@Override @Override
public void onEnable() { public void onEnable() {
hyperLib = new HyperLib(this);
hyperLib.setup();
HyperStats stats = new HyperStats(hyperLib, 14110);
stats.setup();
textUtils = new TextUtils(hyperLib);
if (!configFile.exists()) { if (!configFile.exists()) {
this.saveResource("config.yml", true); this.saveResource("config.yml", true);
logger.info("Copying default config!"); logger.info("Copying default config!");
@@ -160,10 +92,11 @@ public final class ToolStats extends JavaPlugin {
loadConfig(); loadConfig();
configTools = new ConfigTools(this); configTools = new ConfigTools(this);
tokenItems = new TokenItems(this); toolStatsKeys = new ToolStatsKeys(this);
tokenCrafting = new TokenCrafting(this); toolStatsKeys.make();
tokenCrafting.setup(); tokenData = new TokenData(this);
for (ShapedRecipe recipe : tokenCrafting.getRecipes()) { tokenData.setup();
for (ShapedRecipe recipe : tokenData.getRecipes()) {
if (tokens && config.getBoolean("tokens.craft-tokens")) { if (tokens && config.getBoolean("tokens.craft-tokens")) {
Bukkit.addRecipe(recipe); Bukkit.addRecipe(recipe);
} }
@@ -191,17 +124,10 @@ public final class ToolStats extends JavaPlugin {
shootBow = new ShootBow(this); shootBow = new ShootBow(this);
anvilEvent = new AnvilEvent(this); anvilEvent = new AnvilEvent(this);
prepareCraft = new PrepareCraft(this); prepareCraft = new PrepareCraft(this);
blockDispenseEvent = new BlockDispenseEvent(this);
// save which stat can be used by a reset token projectileShoot = new ProjectileShoot(this);
tokenKeys.add(blocksMined); inventoryClose = new InventoryClose(this);
tokenKeys.add(playerKills); playerDrop = new PlayerDrop(this);
tokenKeys.add(mobKills);
tokenKeys.add(cropsHarvested);
tokenKeys.add(sheepSheared);
tokenKeys.add(fishCaught);
tokenKeys.add(flightTime);
tokenKeys.add(arrowsShot);
tokenKeys.add(armorDamage);
Bukkit.getServer().getPluginManager().registerEvents(blockBreak, this); Bukkit.getServer().getPluginManager().registerEvents(blockBreak, this);
Bukkit.getServer().getPluginManager().registerEvents(chunkPopulate, this); Bukkit.getServer().getPluginManager().registerEvents(chunkPopulate, this);
@@ -221,17 +147,24 @@ public final class ToolStats extends JavaPlugin {
Bukkit.getServer().getPluginManager().registerEvents(playerMove, this); Bukkit.getServer().getPluginManager().registerEvents(playerMove, this);
Bukkit.getServer().getPluginManager().registerEvents(anvilEvent, this); Bukkit.getServer().getPluginManager().registerEvents(anvilEvent, this);
Bukkit.getServer().getPluginManager().registerEvents(prepareCraft, this); Bukkit.getServer().getPluginManager().registerEvents(prepareCraft, this);
Bukkit.getServer().getPluginManager().registerEvents(blockDispenseEvent, this);
Bukkit.getServer().getPluginManager().registerEvents(projectileShoot, this);
Bukkit.getServer().getPluginManager().registerEvents(inventoryClose, this);
Bukkit.getServer().getPluginManager().registerEvents(playerDrop, this);
this.getCommand("toolstats").setExecutor(commandToolStats); this.getCommand("toolstats").setExecutor(commandToolStats);
new Metrics(this, 14110); HyperUpdater updater = new HyperUpdater(hyperLib);
Bukkit.getAsyncScheduler().runNow(this, scheduledTask -> checkForUpdates()); updater.setGitHub("hyperdefined", "ToolStats");
updater.setModrinth("oBZj9E15");
updater.setHangar("ToolStats", "paper");
updater.check();
} }
public void loadConfig() { public void loadConfig() {
config = YamlConfiguration.loadConfiguration(configFile); config = YamlConfiguration.loadConfiguration(configFile);
if (config.getInt("config-version") != CONFIG_VERSION) { if (config.getInt("config-version") != CONFIG_VERSION) {
logger.warning("Your config file is outdated! We will try to update it, but you should regenerate it!"); logger.warn("Your config file is outdated! We will try to update it, but you should regenerate it!");
ConfigUpdater configUpdater = new ConfigUpdater(this); ConfigUpdater configUpdater = new ConfigUpdater(this);
configUpdater.updateConfig(); configUpdater.updateConfig();
} }
@@ -246,29 +179,4 @@ public final class ToolStats extends JavaPlugin {
numberFormat = new NumberFormat(this); numberFormat = new NumberFormat(this);
} }
public void checkForUpdates() {
GitHubReleaseAPI api;
try {
api = new GitHubReleaseAPI("ToolStats", "hyperdefined");
} catch (IOException e) {
logger.warning("Unable to check updates!");
e.printStackTrace();
return;
}
GitHubRelease current;
try {
current = api.getReleaseByTag(this.getPluginMeta().getVersion());
} catch (ReleaseNotFoundException e) {
logger.warning("You are running a version that does not exist on GitHub. If you are in a dev environment, you can ignore this. Otherwise, this is a bug!");
return;
}
GitHubRelease latest = api.getLatestVersion();
int buildsBehind = api.getBuildsBehind(current);
if (buildsBehind == 0) {
logger.info("You are running the latest version.");
} else {
logger.warning("A new version is available (" + latest.getTagVersion() + ")! You are running version " + current.getTagVersion() + ". You are " + buildsBehind + " version(s) behind.");
}
}
} }

View File

@@ -18,7 +18,6 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -57,7 +56,6 @@ public class AnvilEvent implements Listener {
} }
Material firstSlotMaterial = firstSlot.getType(); Material firstSlotMaterial = firstSlot.getType();
Material secondSlotMaterial = secondSlot.getType();
// make sure the first item is a valid item // make sure the first item is a valid item
if (!toolStats.itemChecker.isValidItem(firstSlotMaterial)) { if (!toolStats.itemChecker.isValidItem(firstSlotMaterial)) {
@@ -67,12 +65,12 @@ public class AnvilEvent implements Listener {
PersistentDataContainer secondSlotContainer = secondSlot.getItemMeta().getPersistentDataContainer(); PersistentDataContainer secondSlotContainer = secondSlot.getItemMeta().getPersistentDataContainer();
// make sure the 2nd item is one of ours // make sure the 2nd item is one of ours
if (secondSlotMaterial != Material.PAPER || !secondSlotContainer.has(toolStats.tokenType, PersistentDataType.STRING)) { if (!secondSlotContainer.has(toolStats.toolStatsKeys.getTokenType(), PersistentDataType.STRING)) {
return; return;
} }
// get the type from the token // get the type from the token
String tokenType = secondSlotContainer.get(toolStats.tokenType, PersistentDataType.STRING); String tokenType = secondSlotContainer.get(toolStats.toolStatsKeys.getTokenType(), PersistentDataType.STRING);
if (tokenType == null) { if (tokenType == null) {
return; return;
} }
@@ -91,7 +89,9 @@ public class AnvilEvent implements Listener {
} }
if (tokenType.equalsIgnoreCase("remove")) { if (tokenType.equalsIgnoreCase("remove")) {
remove(event, clone); ItemStack removedStats = toolStats.itemLore.removeAll(clone, false);
event.setResult(removedStats);
event.getView().setRepairCost(toolStats.itemChecker.getCost("remove"));
return; return;
} }
@@ -123,7 +123,27 @@ public class AnvilEvent implements Listener {
addToken(event, tokenType, "mob-kills", clone); addToken(event, tokenType, "mob-kills", clone);
return; return;
} }
if (tokenType.equalsIgnoreCase("damage-done")) {
addToken(event, tokenType, "damage-done", clone);
return;
} }
if (tokenType.equalsIgnoreCase("wither-kills")) {
addToken(event, tokenType, "wither-kills", clone);
return;
}
if (tokenType.equalsIgnoreCase("enderdragon-kills")) {
addToken(event, tokenType, "enderdragon-kills", clone);
return;
}
if (tokenType.equalsIgnoreCase("critical-strikes")) {
addToken(event, tokenType, "critical-strikes", clone);
return;
}
}
return;
}
if (toolStats.itemChecker.canGlide(clone)) {
addToken(event, tokenType, "flight-time", clone);
return; return;
} }
if (toolStats.itemChecker.isArmor(firstSlotMaterial)) { if (toolStats.itemChecker.isArmor(firstSlotMaterial)) {
@@ -143,6 +163,22 @@ public class AnvilEvent implements Listener {
addToken(event, tokenType, "damage-done", clone); addToken(event, tokenType, "damage-done", clone);
return; return;
} }
if (tokenType.equalsIgnoreCase("wither-kills")) {
addToken(event, tokenType, "wither-kills", clone);
return;
}
if (tokenType.equalsIgnoreCase("enderdragon-kills")) {
addToken(event, tokenType, "enderdragon-kills", clone);
return;
}
if (tokenType.equalsIgnoreCase("critical-strikes")) {
addToken(event, tokenType, "critical-strikes", clone);
return;
}
if (tokenType.equalsIgnoreCase("trident-throws")) {
addToken(event, tokenType, "trident-throws", clone);
return;
}
return; return;
} }
if (firstSlotMaterial == Material.BOW || firstSlotMaterial == Material.CROSSBOW) { if (firstSlotMaterial == Material.BOW || firstSlotMaterial == Material.CROSSBOW) {
@@ -162,10 +198,14 @@ public class AnvilEvent implements Listener {
addToken(event, tokenType, "damage-done", clone); addToken(event, tokenType, "damage-done", clone);
return; return;
} }
if (tokenType.equalsIgnoreCase("wither-kills")) {
addToken(event, tokenType, "wither-kills", clone);
return;
}
if (tokenType.equalsIgnoreCase("enderdragon-kills")) {
addToken(event, tokenType, "enderdragon-kills", clone);
return; return;
} }
if (firstSlotMaterial == Material.ELYTRA) {
addToken(event, tokenType, "flight-time", clone);
return; return;
} }
if (firstSlotMaterial == Material.FISHING_ROD) { if (firstSlotMaterial == Material.FISHING_ROD) {
@@ -287,6 +327,42 @@ public class AnvilEvent implements Listener {
} }
break; break;
} }
case "wither-kills": {
if (toolStats.config.getBoolean("enabled.bosses-killed.wither")) {
newItem.setItemMeta(toolStats.itemLore.updateBossesKilled(newItem, 0, "wither"));
} else {
event.setResult(null);
return;
}
break;
}
case "enderdragon-kills": {
if (toolStats.config.getBoolean("enabled.bosses-killed.enderdragon")) {
newItem.setItemMeta(toolStats.itemLore.updateBossesKilled(newItem, 0, "enderdragon"));
} else {
event.setResult(null);
return;
}
break;
}
case "critical-strikes": {
if (toolStats.config.getBoolean("enabled.critical-strikes")) {
newItem.setItemMeta(toolStats.itemLore.updateCriticalStrikes(newItem, 0));
} else {
event.setResult(null);
return;
}
break;
}
case "trident-throws": {
if (toolStats.config.getBoolean("enabled.trident-throws")) {
newItem.setItemMeta(toolStats.itemLore.updateTridentThrows(newItem, 0));
} else {
event.setResult(null);
return;
}
break;
}
} }
event.setResult(newItem); event.setResult(newItem);
event.getView().setRepairCost(toolStats.itemChecker.getCost(targetToken)); event.getView().setRepairCost(toolStats.itemChecker.getCost(targetToken));
@@ -308,238 +384,119 @@ public class AnvilEvent implements Listener {
ItemMeta meta = finalItem.getItemMeta(); ItemMeta meta = finalItem.getItemMeta();
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.playerKills)) { if (container.has(toolStats.toolStatsKeys.getPlayerKills())) {
Integer playerKills = container.get(toolStats.playerKills, PersistentDataType.INTEGER); Integer playerKills = container.get(toolStats.toolStatsKeys.getPlayerKills(), PersistentDataType.INTEGER);
if (playerKills == null) { if (playerKills == null) {
return; return;
} }
meta = toolStats.itemLore.updatePlayerKills(finalItem, -playerKills); meta = toolStats.itemLore.updatePlayerKills(finalItem, -playerKills);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.mobKills)) { if (container.has(toolStats.toolStatsKeys.getMobKills())) {
Integer mobKills = container.get(toolStats.mobKills, PersistentDataType.INTEGER); Integer mobKills = container.get(toolStats.toolStatsKeys.getMobKills(), PersistentDataType.INTEGER);
if (mobKills == null) { if (mobKills == null) {
return; return;
} }
meta = toolStats.itemLore.updateMobKills(finalItem, -mobKills); meta = toolStats.itemLore.updateMobKills(finalItem, -mobKills);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.blocksMined)) { if (container.has(toolStats.toolStatsKeys.getBlocksMined())) {
Integer blocksMined = container.get(toolStats.blocksMined, PersistentDataType.INTEGER); Integer blocksMined = container.get(toolStats.toolStatsKeys.getBlocksMined(), PersistentDataType.INTEGER);
if (blocksMined == null) { if (blocksMined == null) {
return; return;
} }
meta = toolStats.itemLore.updateBlocksMined(finalItem, -blocksMined); meta = toolStats.itemLore.updateBlocksMined(finalItem, -blocksMined);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.cropsHarvested)) { if (container.has(toolStats.toolStatsKeys.getCropsHarvested())) {
Integer cropsHarvested = container.get(toolStats.playerKills, PersistentDataType.INTEGER); Integer cropsHarvested = container.get(toolStats.toolStatsKeys.getCropsHarvested(), PersistentDataType.INTEGER);
if (cropsHarvested == null) { if (cropsHarvested == null) {
return; return;
} }
meta = toolStats.itemLore.updateCropsMined(finalItem, -cropsHarvested); meta = toolStats.itemLore.updateCropsMined(finalItem, -cropsHarvested);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.fishCaught)) { if (container.has(toolStats.toolStatsKeys.getFishCaught())) {
Integer fishCaught = container.get(toolStats.fishCaught, PersistentDataType.INTEGER); Integer fishCaught = container.get(toolStats.toolStatsKeys.getFishCaught(), PersistentDataType.INTEGER);
if (fishCaught == null) { if (fishCaught == null) {
return; return;
} }
meta = toolStats.itemLore.updateFishCaught(finalItem, -fishCaught); meta = toolStats.itemLore.updateFishCaught(finalItem, -fishCaught);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.sheepSheared)) { if (container.has(toolStats.toolStatsKeys.getSheepSheared())) {
Integer sheepSheared = container.get(toolStats.sheepSheared, PersistentDataType.INTEGER); Integer sheepSheared = container.get(toolStats.toolStatsKeys.getSheepSheared(), PersistentDataType.INTEGER);
if (sheepSheared == null) { if (sheepSheared == null) {
return; return;
} }
meta = toolStats.itemLore.updateSheepSheared(finalItem, -sheepSheared); meta = toolStats.itemLore.updateSheepSheared(finalItem, -sheepSheared);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.armorDamage)) { if (container.has(toolStats.toolStatsKeys.getArmorDamage())) {
Double armorDamage = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE); Double armorDamage = container.get(toolStats.toolStatsKeys.getArmorDamage(), PersistentDataType.DOUBLE);
if (armorDamage == null) { if (armorDamage == null) {
return; return;
} }
meta = toolStats.itemLore.updateArmorDamage(finalItem, -armorDamage, true); meta = toolStats.itemLore.updateArmorDamage(finalItem, -armorDamage, true);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.damageDone)) { if (container.has(toolStats.toolStatsKeys.getDamageDone())) {
Double damageDone = container.get(toolStats.damageDone, PersistentDataType.DOUBLE); Double damageDone = container.get(toolStats.toolStatsKeys.getDamageDone(), PersistentDataType.DOUBLE);
if (damageDone == null) { if (damageDone == null) {
return; return;
} }
meta = toolStats.itemLore.updateArmorDamage(finalItem, -damageDone, true); meta = toolStats.itemLore.updateArmorDamage(finalItem, -damageDone, true);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.arrowsShot)) { if (container.has(toolStats.toolStatsKeys.getArrowsShot())) {
Integer arrowsShot = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER); Integer arrowsShot = container.get(toolStats.toolStatsKeys.getArrowsShot(), PersistentDataType.INTEGER);
if (arrowsShot == null) { if (arrowsShot == null) {
return; return;
} }
meta = toolStats.itemLore.updateArrowsShot(finalItem, -arrowsShot); meta = toolStats.itemLore.updateArrowsShot(finalItem, -arrowsShot);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.flightTime)) { if (container.has(toolStats.toolStatsKeys.getFlightTime())) {
Long flightTime = container.get(toolStats.flightTime, PersistentDataType.LONG); Long flightTime = container.get(toolStats.toolStatsKeys.getFlightTime(), PersistentDataType.LONG);
if (flightTime == null) { if (flightTime == null) {
return; return;
} }
meta = toolStats.itemLore.updateFlightTime(finalItem, -flightTime); meta = toolStats.itemLore.updateFlightTime(finalItem, -flightTime);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
} }
if (container.has(toolStats.toolStatsKeys.getWitherKills())) {
Integer witherKills = container.get(toolStats.toolStatsKeys.getWitherKills(), PersistentDataType.INTEGER);
if (witherKills == null) {
return;
}
meta = toolStats.itemLore.updateBossesKilled(finalItem, -witherKills, "wither");
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.toolStatsKeys.getEnderDragonKills())) {
Integer enderDragonKills = container.get(toolStats.toolStatsKeys.getEnderDragonKills(), PersistentDataType.INTEGER);
if (enderDragonKills == null) {
return;
}
meta = toolStats.itemLore.updateBossesKilled(finalItem, -enderDragonKills, "enderdragon");
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.toolStatsKeys.getCriticalStrikes())) {
Integer criticalStrikes = container.get(toolStats.toolStatsKeys.getCriticalStrikes(), PersistentDataType.INTEGER);
if (criticalStrikes == null) {
return;
}
meta = toolStats.itemLore.updateCriticalStrikes(finalItem, -criticalStrikes);
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.toolStatsKeys.getTridentThrows())) {
Integer tridentThrows = container.get(toolStats.toolStatsKeys.getTridentThrows(), PersistentDataType.INTEGER);
if (tridentThrows == null) {
return;
}
meta = toolStats.itemLore.updateTridentThrows(finalItem, -tridentThrows);
finalItem.setItemMeta(meta);
}
event.setResult(finalItem); event.setResult(finalItem);
event.getView().setRepairCost(toolStats.itemChecker.getCost("reset")); event.getView().setRepairCost(toolStats.itemChecker.getCost("reset"));
} }
/**
* Remove all stats from an item.
*
* @param event The PrepareAnvilEvent event.
* @param inputItem The input item to remove stats from.
*/
private void remove(PrepareAnvilEvent event, ItemStack inputItem) {
ItemStack finalItem = inputItem.clone();
ItemMeta meta = finalItem.getItemMeta();
PersistentDataContainer container = meta.getPersistentDataContainer();
// remove the applied tokens
if (container.has(toolStats.tokenApplied)) {
container.remove(toolStats.tokenApplied);
}
if (container.has(toolStats.playerKills)) {
Integer playerKills = container.get(toolStats.playerKills, PersistentDataType.INTEGER);
if (playerKills == null) {
return;
}
container.remove(toolStats.playerKills);
String playerKillsFormatted = toolStats.numberFormat.formatInt(playerKills);
Component lineToRemove = toolStats.configTools.formatLore("kills.player", "{kills}", playerKillsFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.mobKills)) {
Integer mobKills = container.get(toolStats.mobKills, PersistentDataType.INTEGER);
if (mobKills == null) {
return;
}
container.remove(toolStats.mobKills);
String mobKillsFormatted = toolStats.numberFormat.formatInt(mobKills);
Component lineToRemove = toolStats.configTools.formatLore("kills.mob", "{kills}", mobKillsFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.blocksMined)) {
Integer blocksMined = container.get(toolStats.blocksMined, PersistentDataType.INTEGER);
if (blocksMined == null) {
return;
}
container.remove(toolStats.blocksMined);
String blocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined);
Component lineToRemove = toolStats.configTools.formatLore("blocks-mined", "{blocks}", blocksMinedFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.cropsHarvested)) {
Integer cropsHarvested = container.get(toolStats.playerKills, PersistentDataType.INTEGER);
if (cropsHarvested == null) {
return;
}
container.remove(toolStats.cropsHarvested);
String cropsHarvestedFormatted = toolStats.numberFormat.formatInt(cropsHarvested);
Component lineToRemove = toolStats.configTools.formatLore("crops-harvested", "{crops}", cropsHarvestedFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.fishCaught)) {
Integer fishCaught = container.get(toolStats.fishCaught, PersistentDataType.INTEGER);
if (fishCaught == null) {
return;
}
container.remove(toolStats.fishCaught);
String fishCaughtFormatted = toolStats.numberFormat.formatInt(fishCaught);
Component lineToRemove = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", fishCaughtFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.sheepSheared)) {
Integer sheepSheared = container.get(toolStats.sheepSheared, PersistentDataType.INTEGER);
if (sheepSheared == null) {
return;
}
container.remove(toolStats.sheepSheared);
String sheepShearedFormatted = toolStats.numberFormat.formatInt(sheepSheared);
Component lineToRemove = toolStats.configTools.formatLore("sheep.sheared", "{sheep}", sheepShearedFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.armorDamage)) {
Double armorDamage = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
if (armorDamage == null) {
return;
}
container.remove(toolStats.armorDamage);
String armorDamageFormatted = toolStats.numberFormat.formatDouble(armorDamage);
Component lineToRemove = toolStats.configTools.formatLore("damage-taken", "{damage}", armorDamageFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.damageDone)) {
Double damageDone = container.get(toolStats.damageDone, PersistentDataType.DOUBLE);
if (damageDone == null) {
return;
}
container.remove(toolStats.damageDone);
String damageDoneFormatted = toolStats.numberFormat.formatDouble(damageDone);
Component lineToRemove = toolStats.configTools.formatLore("damage-done", "{damage}", damageDoneFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.arrowsShot)) {
Integer arrowsShot = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER);
if (arrowsShot == null) {
return;
}
container.remove(toolStats.arrowsShot);
String arrowsShotFormatted = toolStats.numberFormat.formatInt(arrowsShot);
Component lineToRemove = toolStats.configTools.formatLore("arrows-shot", "{arrows}", arrowsShotFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
if (container.has(toolStats.flightTime)) {
Long flightTime = container.get(toolStats.flightTime, PersistentDataType.LONG);
if (flightTime == null) {
return;
}
container.remove(toolStats.flightTime);
String flightTimeFormatted = toolStats.numberFormat.formatDouble(flightTime);
Component lineToRemove = toolStats.configTools.formatLore("flight-time", "{time}", flightTimeFormatted);
meta.lore(toolStats.itemLore.removeLore(meta.lore(), lineToRemove));
finalItem.setItemMeta(meta);
}
event.setResult(finalItem);
event.getView().setRepairCost(toolStats.itemChecker.getCost("remove"));
}
} }

View File

@@ -18,25 +18,28 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.Bukkit; import org.bukkit.*;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable; import org.bukkit.block.data.Ageable;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
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.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
public class BlockBreak implements Listener { public class BlockBreak implements Listener {
private final ToolStats toolStats; private final ToolStats toolStats;
public List<Block> brokenContainers = new ArrayList<>();
public BlockBreak(ToolStats toolStats) { public BlockBreak(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
@@ -48,16 +51,19 @@ 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 (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
ItemStack heldItem = inventory.getItemInMainHand(); ItemStack heldItem = inventory.getItemInMainHand();
Block block = event.getBlock(); Block block = event.getBlock();
if (block.getType() == Material.CHEST) { if (block.getType() == Material.CHEST || block.getType() == Material.BARREL) {
toolStats.playerInteract.openedChests.put(block, player); brokenContainers.add(block);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> toolStats.playerInteract.openedChests.remove(block), 20); Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> brokenContainers.remove(block), 20);
} }
// only check certain items // only check certain items
@@ -96,4 +102,41 @@ public class BlockBreak implements Listener {
} }
} }
} }
@EventHandler(priority = EventPriority.HIGHEST)
public void onBreak(BlockDropItemEvent event) {
Player player = event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
Location eventLocation = event.getBlock().getLocation();
Chunk eventChunk = eventLocation.getChunk();
Bukkit.getRegionScheduler().runDelayed(toolStats, eventLocation.getWorld(), eventChunk.getX(), eventChunk.getZ(), scheduledTask -> {
boolean validLootDrops = false;
for (Location droppedLootLocation : toolStats.generateLoot.droppedLootLocations) {
if (eventLocation.getWorld() == droppedLootLocation.getWorld()) {
double distance = droppedLootLocation.distance(eventLocation);
if (distance <= 1.0) {
validLootDrops = true;
}
}
}
if (validLootDrops) {
toolStats.generateLoot.droppedLootLocations.remove(eventLocation);
for (Item droppedItemEntity : event.getItems()) {
ItemStack droppedItem = droppedItemEntity.getItemStack();
if (!toolStats.itemChecker.isValidItem(droppedItem.getType())) {
continue;
}
ItemStack newItem = toolStats.inventoryClose.addLootedOrigin(droppedItem, player);
if (newItem != null) {
droppedItemEntity.setItemStack(newItem);
}
}
}
}, 1);
}
} }

View File

@@ -0,0 +1,143 @@
/*
* 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.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockDispenseLootEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class BlockDispenseEvent implements Listener {
private final ToolStats toolStats;
public BlockDispenseEvent(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onDispense(BlockDispenseLootEvent event) {
Player player = event.getPlayer();
if (player == null) {
return;
}
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return;
}
List<ItemStack> loot = event.getDispensedLoot();
// probably won't ever happen
if (loot.isEmpty()) {
return;
}
List<ItemStack> newLoot = new ArrayList<>();
for (ItemStack lootItem : loot) {
ItemStack newLootItem = lootItem.clone();
Material lootItemMaterial = newLootItem.getType();
// if the item is one we want, do stuff
if (toolStats.itemChecker.isValidItem(lootItemMaterial)) {
newLootItem = addLootedOrigin(newLootItem, player);
}
// if the item returned null, add the original item
newLoot.add(Objects.requireNonNullElse(newLootItem, lootItem));
}
event.setDispensedLoot(newLoot);
}
/**
* 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 addLootedOrigin(ItemStack itemStack, Player owner) {
ItemStack newItem = itemStack.clone();
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
}
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
return null;
}
// get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
// if creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 2, newItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 2);
lore.add(creationDate);
meta.lore(lore);
}
// if ownership is enabled, add it
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 2, newItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 2);
lore.add(itemOwner);
meta.lore(lore);
}
// if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING, hash);
}
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -50,6 +50,9 @@ public class ChunkPopulate implements Listener {
return; return;
} }
World world = event.getChunk().getWorld(); World world = event.getChunk().getWorld();
if (!toolStats.configTools.checkWorld(world.getName())) {
return;
}
// this is delayed because entities are not loaded instantly // this is delayed because entities are not loaded instantly
// we just check 1 second later // we just check 1 second later
Chunk chunk = event.getChunk(); Chunk chunk = event.getChunk();
@@ -68,7 +71,7 @@ public class ChunkPopulate implements Listener {
} }
// add the new tag so we know it's new // 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.toolStatsKeys.getElytraKey(), PersistentDataType.INTEGER, 1);
elytraCopy.setItemMeta(meta); elytraCopy.setItemMeta(meta);
itemFrame.setItem(elytraCopy); itemFrame.setItem(elytraCopy);
} }

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@@ -50,7 +50,10 @@ 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 (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
ItemStack craftedItem = event.getCurrentItem(); ItemStack craftedItem = event.getCurrentItem();
@@ -116,17 +119,21 @@ public class CraftItem implements Listener {
ItemStack newItem = itemStack.clone(); ItemStack newItem = itemStack.clone();
ItemMeta meta = newItem.getItemMeta(); ItemMeta meta = newItem.getItemMeta();
if (meta == null) { if (meta == null) {
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats."); toolStats.logger.warn("{} does NOT have any meta! Unable to update stats.", itemStack);
return null; return null;
} }
// 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();
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag // if the item already has the tag
// this is to prevent duplicate tags // this is to prevent duplicate tags
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { if (container.has(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
return null; return null;
} }
@@ -139,36 +146,27 @@ 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")) { Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 0, newItem);
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated); if (creationDate != null) {
container.set(toolStats.originType, PersistentDataType.INTEGER, 0); container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 0);
String date = toolStats.numberFormat.formatDate(finalDate); lore.add(creationDate);
Component newLine = toolStats.configTools.formatLore("created.created-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore); meta.lore(lore);
} }
// if creation owner is enabled, add it // if ownership is enabled, add it
if (toolStats.configTools.checkConfig(itemStack.getType(), "created-by")) { Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 0, newItem);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId()); if (itemOwner != null) {
container.set(toolStats.originType, PersistentDataType.INTEGER, 0); container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 0);
Component newLine = toolStats.configTools.formatLore("created.created-by", "{player}", owner.getName()); lore.add(itemOwner);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.lore(lore); 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(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.toolStatsKeys.getHash(), PersistentDataType.STRING, hash);
} }
newItem.setItemMeta(meta); newItem.setItemMeta(meta);
return newItem; return newItem;

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -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;
@@ -44,6 +45,9 @@ public class CreativeEvent implements Listener {
@EventHandler @EventHandler
public void onCreativeEvent(InventoryCreativeEvent event) { public void onCreativeEvent(InventoryCreativeEvent event) {
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
// make sure they are in creative mode // make sure they are in creative mode
if (player.getGameMode() != GameMode.CREATIVE) { if (player.getGameMode() != GameMode.CREATIVE) {
return; return;
@@ -60,7 +64,7 @@ public class CreativeEvent implements Listener {
// if the item already has an origin set, don't add it again // if the item already has an origin set, don't add it again
// this is needed since you can spam click an item and the event will fire again // this is needed since you can spam click an item and the event will fire again
PersistentDataContainer container = spawnedItemMeta.getPersistentDataContainer(); PersistentDataContainer container = spawnedItemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) { if (container.has(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER)) {
return; return;
} }
@@ -82,36 +86,56 @@ public class CreativeEvent implements Listener {
ItemStack newSpawnedItem = itemStack.clone(); ItemStack newSpawnedItem = itemStack.clone();
ItemMeta meta = newSpawnedItem.getItemMeta(); ItemMeta meta = newSpawnedItem.getItemMeta();
if (meta == null) { if (meta == null) {
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats."); toolStats.logger.warn("{} does NOT have any meta! Unable to update stats.", itemStack);
return null; return null;
} }
// 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();
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag // if the item already has the tag
// this is to prevent duplicate tags // this is to prevent duplicate tags
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { if (container.has(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
return null; return null;
} }
// get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
// if creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 6, newSpawnedItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 6);
lore.add(creationDate);
meta.lore(lore);
}
// if ownership is enabled, add it
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 6, newSpawnedItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 6);
lore.add(itemOwner);
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.toolStatsKeys.getHash(), 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

@@ -29,6 +29,7 @@ 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;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
@@ -55,6 +56,10 @@ public class EntityDamage implements Listener {
return; return;
} }
if (!toolStats.configTools.checkWorld(mobBeingAttacked.getWorld().getName())) {
return;
}
// ignore void and /kill damage // ignore void and /kill damage
EntityDamageEvent.DamageCause cause = event.getCause(); EntityDamageEvent.DamageCause cause = event.getCause();
if (ignoredCauses.contains(cause)) { if (ignoredCauses.contains(cause)) {
@@ -66,10 +71,21 @@ public class EntityDamage implements Listener {
boolean playerBeingAttacked = mobBeingAttacked instanceof Player; boolean playerBeingAttacked = mobBeingAttacked instanceof Player;
double finalDamage = event.getFinalDamage(); double finalDamage = event.getFinalDamage();
boolean modDied = mobBeingAttacked.getHealth() - finalDamage <= 0; boolean modDied = mobBeingAttacked.getHealth() - finalDamage <= 0;
EntityType mobAttackedType = event.getEntityType();
boolean critical = event.isCritical();
if (playerBeingAttacked) {
Player player = (Player) event.getEntity();
if (player.isBlocking()) {
double blockedDamage = -event.getDamage(EntityDamageEvent.DamageModifier.BLOCKING);
updateShieldDamage(player.getInventory(), blockedDamage);
}
}
// player attacks something // player attacks something
if (playerAttacking) { if (playerAttacking) {
PlayerInventory playerAttackingInventory = ((Player) damager).getInventory(); Player player = (Player) damager;
PlayerInventory playerAttackingInventory = player.getInventory();
// make sure the item the player used is an item we want // make sure the item the player used is an item we want
if (!toolStats.itemChecker.isMeleeWeapon(playerAttackingInventory.getItemInMainHand().getType())) { if (!toolStats.itemChecker.isMeleeWeapon(playerAttackingInventory.getItemInMainHand().getType())) {
return; return;
@@ -78,6 +94,11 @@ public class EntityDamage implements Listener {
// update their weapon's damage // update their weapon's damage
updateWeaponDamage(playerAttackingInventory, event.getFinalDamage()); updateWeaponDamage(playerAttackingInventory, event.getFinalDamage());
// if the player crit
if (critical) {
updateCriticalStrikes(playerAttackingInventory);
}
// the mob the player attacked died // the mob the player attacked died
if (modDied) { if (modDied) {
// player killed another player // player killed another player
@@ -86,6 +107,12 @@ public class EntityDamage implements Listener {
} else { } else {
// player kills a regular mob // player kills a regular mob
updateWeaponKills(playerAttackingInventory, "mob"); updateWeaponKills(playerAttackingInventory, "mob");
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilled(playerAttackingInventory, "wither");
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilled(playerAttackingInventory, "enderdragon");
}
} }
} }
@@ -96,7 +123,7 @@ public class EntityDamage implements Listener {
// something was hit by a trident // something was hit by a trident
if (damager instanceof Trident trident) { if (damager instanceof Trident trident) {
ProjectileSource source = trident.getShooter(); ProjectileSource source = trident.getShooter();
if (source instanceof Player) { if (source instanceof Player player) {
// update the trident's tracked damage // update the trident's tracked damage
updateTridentDamage(trident, finalDamage); updateTridentDamage(trident, finalDamage);
@@ -108,6 +135,12 @@ public class EntityDamage implements Listener {
} else { } else {
// the trident killed a mob, update the kills // the trident killed a mob, update the kills
updateTridentKills(trident, "mob"); updateTridentKills(trident, "mob");
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilled(player.getInventory(), "wither");
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilled(player.getInventory(), "enderdragon");
}
} }
} }
@@ -133,6 +166,12 @@ public class EntityDamage implements Listener {
} else { } else {
// player killed mob with an arrow // player killed mob with an arrow
updateBowKills(shootingPlayer.getInventory(), "mob"); updateBowKills(shootingPlayer.getInventory(), "mob");
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilledByBow(shootingPlayer.getInventory(), "wither");
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilledByBow(shootingPlayer.getInventory(), "enderdragon");
}
} }
} }
@@ -156,7 +195,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 +227,6 @@ 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(heldBow, damage, false); ItemMeta newBowDamage = toolStats.itemLore.updateWeaponDamage(heldBow, damage, false);
//toolStats.logger.info(newBowDamage.toString());
// player is shooting another player // player is shooting another player
if (newBowDamage != null) { if (newBowDamage != null) {
@@ -283,4 +321,82 @@ public class EntityDamage implements Listener {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta); playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
} }
} }
private void updateBossesKilled(PlayerInventory playerInventory, String boss) {
ItemStack heldWeapon = playerInventory.getItemInMainHand();
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateBossesKilled(heldWeapon, 1, boss);
if (newHeldWeaponMeta != null) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
}
}
private void updateBossesKilledByBow(PlayerInventory playerInventory, String boss) {
ItemStack heldBow = toolStats.itemChecker.getBow(playerInventory);
if (heldBow == null) {
return;
}
boolean isMain = playerInventory.getItemInMainHand().getType() == Material.BOW || playerInventory.getItemInMainHand().getType() == Material.CROSSBOW;
boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.BOW || playerInventory.getItemInOffHand().getType() == Material.CROSSBOW;
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateBossesKilled(heldBow, 1, boss);
if (newHeldWeaponMeta != null) {
if (isMain && isOffHand) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
} else if (isMain) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
} else if (isOffHand) {
playerInventory.getItemInOffHand().setItemMeta(newHeldWeaponMeta);
}
}
}
private void updateCriticalStrikes(PlayerInventory playerInventory) {
ItemStack heldWeapon = playerInventory.getItemInMainHand();
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateCriticalStrikes(heldWeapon, 1);
if (newHeldWeaponMeta != null) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
}
}
private void updateShieldDamage(PlayerInventory playerInventory, double damage) {
boolean isMain = playerInventory.getItemInMainHand().getType() == Material.SHIELD;
boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.SHIELD;
ItemStack heldShield;
if (isMain && isOffHand) {
heldShield = playerInventory.getItemInMainHand();
int shieldDamage = (heldShield.getItemMeta() instanceof Damageable d) ? d.getDamage() : 0;
ItemMeta newShieldMeta = toolStats.itemLore.updateArmorDamage(heldShield, damage, false);
if (newShieldMeta != null) {
if (newShieldMeta instanceof Damageable dNew) {
dNew.setDamage(shieldDamage);
}
playerInventory.getItemInMainHand().setItemMeta(newShieldMeta);
}
} else if (isMain) {
heldShield = playerInventory.getItemInMainHand();
int shieldDamage = (heldShield.getItemMeta() instanceof Damageable d) ? d.getDamage() : 0;
ItemMeta newShieldMeta = toolStats.itemLore.updateArmorDamage(heldShield, damage, false);
if (newShieldMeta != null) {
if (newShieldMeta instanceof Damageable dNew) {
dNew.setDamage(shieldDamage);
}
playerInventory.getItemInMainHand().setItemMeta(newShieldMeta);
}
} else if (isOffHand) {
heldShield = playerInventory.getItemInOffHand();
int shieldDamage = (heldShield.getItemMeta() instanceof Damageable d) ? d.getDamage() : 0;
ItemMeta newShieldMeta = toolStats.itemLore.updateArmorDamage(heldShield, damage, false);
if (newShieldMeta != null) {
if (newShieldMeta instanceof Damageable dNew) {
dNew.setDamage(shieldDamage);
}
playerInventory.getItemInOffHand().setItemMeta(newShieldMeta);
}
}
}
} }

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;
@@ -47,6 +49,9 @@ public class EntityDeath implements Listener {
if (livingEntity instanceof Player) { if (livingEntity instanceof Player) {
return; return;
} }
if (!toolStats.configTools.checkWorld(livingEntity.getWorld().getName())) {
return;
}
UUID livingEntityUUID = event.getEntity().getUniqueId(); UUID livingEntityUUID = event.getEntity().getUniqueId();
// if it's a mob we are tracking that matters // if it's a mob we are tracking that matters
if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) { if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) {
@@ -55,7 +60,7 @@ public class EntityDeath implements Listener {
ItemMeta droppedItemMeta = droppedItem.getItemMeta(); ItemMeta droppedItemMeta = droppedItem.getItemMeta();
if (droppedItemMeta != null) { if (droppedItemMeta != null) {
PersistentDataContainer container = droppedItemMeta.getPersistentDataContainer(); PersistentDataContainer container = droppedItemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) { if (container.has(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER)) {
continue; // ignore any items that have our tags continue; // ignore any items that have our tags
} }
@@ -84,19 +89,43 @@ 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();
} }
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 creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 1, newItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 1);
lore.add(creationDate);
meta.lore(lore);
}
if (toolStats.config.getBoolean("enabled.dropped-by")) {
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 1);
container.set(toolStats.toolStatsKeys.getDroppedBy(), 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

@@ -18,30 +18,29 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType; import org.bukkit.Bukkit;
import net.kyori.adventure.text.Component; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.Chest; import org.bukkit.block.Container;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.StorageMinecart; import org.bukkit.entity.minecart.StorageMinecart;
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.world.LootGenerateEvent; import org.bukkit.event.world.LootGenerateEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.Date; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class GenerateLoot implements Listener { public class GenerateLoot implements Listener {
private final ToolStats toolStats; private final ToolStats toolStats;
public Map<Inventory, Location> generatedInventory = new HashMap<>();
public List<Location> droppedLootLocations = new ArrayList<>();
public GenerateLoot(ToolStats toolStats) { public GenerateLoot(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
@@ -54,14 +53,19 @@ public class GenerateLoot implements Listener {
return; return;
} }
Location lootLocation = event.getLootContext().getLocation(); Location lootLocation = event.getLootContext().getLocation();
if (!toolStats.configTools.checkWorld(lootLocation.getWorld().getName())) {
if (inventoryHolder instanceof Chest) { return;
}
Chunk lootChunk = lootLocation.getChunk();
Bukkit.getRegionScheduler().runDelayed(toolStats, lootLocation.getWorld(), lootChunk.getX(), lootChunk.getZ(), scheduledTask -> {
if (inventoryHolder instanceof Container) {
Block openedChest = null; Block openedChest = null;
Location chestLocation = null;
// look at the current list of opened chest and get the distance // look at the current list of opened chest and get the distance
// between the LootContext location and chest location // between the LootContext location and chest location
// if the distance is less than 1, it's the same chest // if the distance is less than 1, it's the same chest
for (Block chest : toolStats.playerInteract.openedChests.keySet()) { for (Block chest : toolStats.playerInteract.openedChests) {
Location chestLocation = chest.getLocation(); chestLocation = chest.getLocation();
if (chest.getWorld() == lootLocation.getWorld()) { if (chest.getWorld() == lootLocation.getWorld()) {
double distance = lootLocation.distance(chestLocation); double distance = lootLocation.distance(chestLocation);
if (distance <= 1.0) { if (distance <= 1.0) {
@@ -69,82 +73,27 @@ public class GenerateLoot implements Listener {
} }
} }
} }
// ignore if the chest is not in the same location for (Block brokenChest : toolStats.blockBreak.brokenContainers) {
if (openedChest == null) { Location brokenChestLocation = brokenChest.getLocation();
return; if (brokenChestLocation.getWorld() == lootLocation.getWorld()) {
double distance = lootLocation.distance(brokenChestLocation);
if (distance <= 1.0) {
droppedLootLocations.add(brokenChestLocation);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask2 -> droppedLootLocations.remove(brokenChestLocation), 20);
}
}
}
// ignore if the chest is not in the same location
if (openedChest != null) {
generatedInventory.put(inventoryHolder.getInventory(), chestLocation);
} }
Player player = toolStats.playerInteract.openedChests.get(openedChest);
setLoot(event.getLoot(), player);
} }
if (inventoryHolder instanceof StorageMinecart mineCart) { if (inventoryHolder instanceof StorageMinecart mineCart) {
if (toolStats.playerInteract.openedMineCarts.containsKey(mineCart)) { if (toolStats.playerInteract.openedMineCarts.contains(mineCart)) {
Player player = toolStats.playerInteract.openedMineCarts.get(mineCart); Inventory mineCartInventory = mineCart.getInventory();
setLoot(event.getLoot(), player); generatedInventory.put(mineCartInventory, mineCart.getLocation());
}
}
}
/**
* 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 addLootedOrigin(ItemStack itemStack, Player owner) {
ItemStack newItem = itemStack.clone();
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer();
if (!toolStats.configTools.checkConfig(newItem.getType(), "looted-tag")) {
return null;
}
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) {
return null;
}
// only make the hash if it's enabled
if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
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);
return newItem;
}
/**
* Add tags to the generated loot.
*
* @param loot The loot from the event.
* @param player The player triggering the event.
*/
private void setLoot(List<ItemStack> loot, Player player) {
for (int i = 0; i < loot.size(); i++) {
ItemStack itemStack = loot.get(i);
// ignore air
if (itemStack == null || itemStack.getType() == Material.AIR) {
continue;
}
if (toolStats.itemChecker.isValidItem(itemStack.getType())) {
ItemStack newItem = addLootedOrigin(itemStack, player);
if (newItem != null) {
loot.set(i, newItem);
}
} }
} }
}, 1);
} }
} }

View File

@@ -0,0 +1,196 @@
/*
* 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.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class InventoryClose implements Listener {
private final ToolStats toolStats;
public InventoryClose(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onClose(InventoryCloseEvent event) {
if (toolStats.generateLoot.generatedInventory.isEmpty()) {
return;
}
Player player = (Player) event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
Inventory closedInventory = event.getInventory();
InventoryHolder holder = closedInventory.getHolder();
if (toolStats.generateLoot.generatedInventory.containsKey(closedInventory)) {
Location chestLocation = toolStats.generateLoot.generatedInventory.get(closedInventory);
toolStats.generateLoot.generatedInventory.remove(closedInventory);
player.getScheduler().runDelayed(toolStats, scheduledTask -> {
PlayerInventory playerInventory = player.getInventory();
for (int i = 0; i < playerInventory.getContents().length; i++) {
ItemStack item = playerInventory.getItem(i);
if (item == null) {
continue;
}
if (!toolStats.itemChecker.isValidItem(item.getType())) {
continue;
}
ItemStack newItem = addLootedOrigin(item, player);
if (newItem != null) {
playerInventory.setItem(i, newItem);
}
}
}, null, 1);
if (holder instanceof StorageMinecart mineCart) {
mineCart.getScheduler().runDelayed(toolStats, scheduledTask -> {
Inventory chestInventory = mineCart.getInventory();
for (int i = 0; i < chestInventory.getContents().length; i++) {
ItemStack item = chestInventory.getItem(i);
if (item == null) {
continue;
}
if (!toolStats.itemChecker.isValidItem(item.getType())) {
continue;
}
ItemStack newItem = addLootedOrigin(item, player);
if (newItem != null) {
chestInventory.setItem(i, newItem);
}
}
}, null, 1);
}
if (holder instanceof Container container) {
Chunk chestChunk = chestLocation.getChunk();
Bukkit.getRegionScheduler().runDelayed(toolStats, chestLocation.getWorld(), chestChunk.getX(), chestChunk.getZ(), scheduledTask -> {
BlockState blockState = chestLocation.getWorld().getBlockAt(chestLocation).getState();
if (blockState instanceof InventoryHolder chest) {
Inventory chestInventory = chest.getInventory();
for (int i = 0; i < chestInventory.getContents().length; i++) {
ItemStack item = chestInventory.getItem(i);
if (item == null) {
continue;
}
if (!toolStats.itemChecker.isValidItem(item.getType())) {
continue;
}
ItemStack newItem = addLootedOrigin(item, player);
if (newItem != null) {
chestInventory.setItem(i, newItem);
}
}
}
}, 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.
*/
public ItemStack addLootedOrigin(ItemStack itemStack, Player owner) {
ItemStack newItem = itemStack.clone();
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
}
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER) || container.has(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
return null;
}
// get the current lore the item
List<Component> lore;
if (meta.hasLore()) {
lore = meta.lore();
} else {
lore = new ArrayList<>();
}
// if creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 2, newItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 2);
lore.add(creationDate);
meta.lore(lore);
}
// if ownership is enabled, add it
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 2, newItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 2);
lore.add(itemOwner);
meta.lore(lore);
}
// if hash is enabled, add it
if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(newItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING, hash);
}
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
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;
@@ -47,12 +47,10 @@ public class InventoryOpen implements Listener {
} }
Inventory inventory = event.getInventory(); Inventory inventory = event.getInventory();
// only check these Player player = (Player) event.getPlayer();
if (inventory.getType() != InventoryType.CHEST || inventory.getType() != InventoryType.BARREL || inventory.getType() != InventoryType.SHULKER_BOX || inventory.getType() != InventoryType.ENDER_CHEST) { if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return; return;
} }
Player player = (Player) event.getPlayer();
for (ItemStack itemStack : inventory) { for (ItemStack itemStack : inventory) {
if (itemStack == null) { if (itemStack == null) {
continue; continue;
@@ -69,13 +67,13 @@ public class InventoryOpen implements Listener {
if (toolStats.config.getBoolean("tokens.enabled")) { if (toolStats.config.getBoolean("tokens.enabled")) {
// if the token system is on and the item doesn't have stat keys // if the token system is on and the item doesn't have stat keys
if (toolStats.itemChecker.keyCheck(container) && !container.has(toolStats.tokenType)) { if (toolStats.itemChecker.keyCheck(container) && !container.has(toolStats.toolStatsKeys.getTokenType())) {
// add the tokens // add the tokens
String newTokens = toolStats.itemChecker.addTokensToExisting(itemStack); String newTokens = toolStats.itemChecker.addTokensToExisting(itemStack);
if (newTokens == null) { if (newTokens == null) {
return; return;
} }
container.set(toolStats.tokenApplied, PersistentDataType.STRING, newTokens); container.set(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING, newTokens);
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} }
@@ -83,29 +81,29 @@ public class InventoryOpen implements Listener {
// generate a hash if the item doesn't have one (and enabled) // generate a hash if the item doesn't have one (and enabled)
// if hashes are disabled and the item has one, remove it. // if hashes are disabled and the item has one, remove it.
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
if (!container.has(toolStats.hash, PersistentDataType.STRING)) { if (!container.has(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING)) {
UUID owner = null; UUID owner = null;
// get the current owner if there is one. // get the current owner if there is one.
if (container.has(toolStats.itemOwner, new UUIDDataType())) { if (container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
owner = container.get(toolStats.itemOwner, new UUIDDataType()); owner = container.get(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType());
} }
// if there is no owner, use the player holding it // if there is no owner, use the player holding it
if (owner == null) { if (owner == null) {
owner = player.getUniqueId(); owner = player.getUniqueId();
} }
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG); Long timestamp = container.get(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG);
if (timestamp == null) { if (timestamp == null) {
// if there is no time created, use now // if there is no time created, use now
timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis();
} }
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp); String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING, hash);
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} else { } else {
// if hashes are disabled but the item has one, remove it. // if hashes are disabled but the item has one, remove it.
if (container.has(toolStats.hash, PersistentDataType.STRING)) { if (container.has(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING)) {
container.remove(toolStats.hash); container.remove(toolStats.toolStatsKeys.getHash());
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} }

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@@ -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,10 @@ 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 (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
Item item = event.getItem(); Item item = event.getItem();
@@ -66,7 +70,7 @@ public class PickupItem implements Listener {
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (itemStack.getType() == Material.ELYTRA) { if (itemStack.getType() == Material.ELYTRA) {
// 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.toolStatsKeys.getElytraKey(), PersistentDataType.INTEGER)) {
ItemStack newElytra = addElytraOrigin(itemStack, (Player) event.getEntity()); ItemStack newElytra = addElytraOrigin(itemStack, (Player) event.getEntity());
if (newElytra != null) { if (newElytra != null) {
item.setItemStack(newElytra); item.setItemStack(newElytra);
@@ -90,7 +94,11 @@ 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();
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (!toolStats.config.getBoolean("enabled.elytra-tag")) { if (!toolStats.config.getBoolean("enabled.elytra-tag")) {
@@ -100,16 +108,38 @@ public class PickupItem implements Listener {
// only make the hash if it's enabled // only make the hash if it's enabled
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(finalItem.getType(), owner.getUniqueId(), timeCreated); String hash = toolStats.hashMaker.makeHash(finalItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.toolStatsKeys.getHash(), 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.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 4);
container.remove(toolStats.toolStatsKeys.getElytraKey());
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 4, finalItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 4);
lore.add(creationDate);
meta.lore(lore);
}
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 4, finalItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 4);
lore.add(itemOwner);
meta.lore(lore);
} }
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.itemOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 4);
container.remove(toolStats.newElytra);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<Component> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.lore(newLore);
finalItem.setItemMeta(meta); finalItem.setItemMeta(meta);
return finalItem; return finalItem;
} }

View File

@@ -0,0 +1,65 @@
/*
* 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.events;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class PlayerDrop implements Listener {
private final ToolStats toolStats;
public PlayerDrop(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onDrop(PlayerDropItemEvent event) {
Player player = event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (toolStats.generateLoot.generatedInventory.isEmpty()) {
return;
}
player.getScheduler().runDelayed(toolStats, scheduledTask -> {
Inventory opened = player.getOpenInventory().getTopInventory();
if (toolStats.generateLoot.generatedInventory.containsKey(opened)) {
Item droppedItemEntity = event.getItemDrop();
ItemStack droppedItem = droppedItemEntity.getItemStack();
if (!toolStats.itemChecker.isValidItem(droppedItem.getType())) {
return;
}
ItemStack newItem = toolStats.inventoryClose.addLootedOrigin(droppedItem, player);
if (newItem != null) {
droppedItemEntity.setItemStack(newItem);
}
}
}, null, 1);
}
}

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@@ -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,10 @@ public class PlayerFish implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }
@@ -88,7 +92,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 +106,56 @@ 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;
if (toolStats.config.getBoolean("normalize-time-creation")) {
finalDate = toolStats.numberFormat.normalizeTime(timeCreated);
timeCreated = finalDate.getTime();
}
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (!toolStats.configTools.checkConfig(newItem.getType(), "fished-tag")) { if (container.has(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
return null; return null;
} }
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.itemOwner, PersistentDataType.LONG)) { // 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 creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 5, newItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 5);
lore.add(creationDate);
meta.lore(lore);
}
// if ownership is enabled, add it
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 5, newItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 5);
lore.add(itemOwner);
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.toolStatsKeys.getHash(), 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

@@ -20,8 +20,8 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -31,16 +31,20 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action; import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import java.util.HashMap; import java.util.ArrayList;
import java.util.Map; import java.util.List;
public class PlayerInteract implements Listener { public class PlayerInteract implements Listener {
private final ToolStats toolStats; private final ToolStats toolStats;
public final Map<Block, Player> openedChests = new HashMap<>(); public final List<Block> openedChests = new ArrayList<>();
public final Map<StorageMinecart, Player> openedMineCarts = new HashMap<>(); public final List<StorageMinecart> openedMineCarts = new ArrayList<>();
public final List<Inventory> chestInventories = new ArrayList<>();
public final List<Inventory> mineCartChestInventories = new ArrayList<>();
public PlayerInteract(ToolStats toolStats) { public PlayerInteract(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
@@ -58,12 +62,18 @@ public class PlayerInteract implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
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
if (block.getType() != Material.AIR && block.getType() == Material.CHEST) { BlockState state = block.getState();
openedChests.put(block, player); if (state instanceof InventoryHolder holder) {
Inventory holderInventory = holder.getInventory();
openedChests.add(block);
chestInventories.add(holderInventory);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedChests.remove(block), 20); Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedChests.remove(block), 20);
} }
} }
@@ -72,13 +82,15 @@ 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
if (clicked.getType() == EntityType.CHEST_MINECART) { if (clicked.getType() == EntityType.CHEST_MINECART) {
StorageMinecart storageMinecart = (StorageMinecart) clicked; StorageMinecart storageMinecart = (StorageMinecart) clicked;
openedMineCarts.put(storageMinecart, player); Inventory mineCartInventory = storageMinecart.getInventory();
mineCartChestInventories.add(mineCartInventory);
openedMineCarts.add(storageMinecart);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedMineCarts.remove(storageMinecart), 20); Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedMineCarts.remove(storageMinecart), 20);
} }
} }

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
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;
@@ -42,6 +42,9 @@ public class PlayerJoin implements Listener {
@EventHandler @EventHandler
public void onJoin(PlayerJoinEvent event) { public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
Inventory inventory = player.getInventory(); Inventory inventory = player.getInventory();
for (ItemStack itemStack : inventory) { for (ItemStack itemStack : inventory) {
@@ -60,42 +63,42 @@ public class PlayerJoin implements Listener {
if (toolStats.config.getBoolean("tokens.enabled")) { if (toolStats.config.getBoolean("tokens.enabled")) {
// if the token system is on and the item doesn't have stat keys // if the token system is on and the item doesn't have stat keys
if (toolStats.itemChecker.keyCheck(container) && !container.has(toolStats.tokenType)) { if (toolStats.itemChecker.keyCheck(container) && !container.has(toolStats.toolStatsKeys.getTokenType())) {
// add the tokens // add the tokens
String newTokens = toolStats.itemChecker.addTokensToExisting(itemStack); String newTokens = toolStats.itemChecker.addTokensToExisting(itemStack);
if (newTokens == null) { if (newTokens == null) {
return; return;
} }
container.set(toolStats.tokenApplied, PersistentDataType.STRING, newTokens); container.set(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING, newTokens);
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} }
// generate a hash if the item doesn't have one // generate a hash if the item doesn't have one
if (toolStats.config.getBoolean("generate-hash-for-items")) { if (toolStats.config.getBoolean("generate-hash-for-items")) {
if (!container.has(toolStats.hash, PersistentDataType.STRING)) { if (!container.has(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING)) {
UUID owner = null; UUID owner = null;
// get the current owner if there is one. // get the current owner if there is one.
if (container.has(toolStats.itemOwner, new UUIDDataType())) { if (container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
owner = container.get(toolStats.itemOwner, new UUIDDataType()); owner = container.get(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType());
} }
// if there is no owner, use the player holding it // if there is no owner, use the player holding it
if (owner == null) { if (owner == null) {
owner = player.getUniqueId(); owner = player.getUniqueId();
} }
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG); Long timestamp = container.get(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG);
if (timestamp == null) { if (timestamp == null) {
// if there is no time created, use now // if there is no time created, use now
timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis();
} }
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp); String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
container.set(toolStats.hash, PersistentDataType.STRING, hash); container.set(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING, hash);
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} else { } else {
// if hashes are disabled but the item has one, remove it. // if hashes are disabled but the item has one, remove it.
if (container.has(toolStats.hash, PersistentDataType.STRING)) { if (container.has(toolStats.toolStatsKeys.getHash(), PersistentDataType.STRING)) {
container.remove(toolStats.hash); container.remove(toolStats.toolStatsKeys.getHash());
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }
} }

View File

@@ -18,7 +18,6 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -43,6 +42,9 @@ public class PlayerMove implements Listener {
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onMove(PlayerMoveEvent event) { public void onMove(PlayerMoveEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
// player starts to fly // player starts to fly
if (player.isGliding()) { if (player.isGliding()) {
// if they are flying, and we don't have them tracked, add them // if they are flying, and we don't have them tracked, add them
@@ -53,15 +55,23 @@ public class PlayerMove implements Listener {
// player is not flying // player is not flying
if (playerStartFlight.containsKey(player)) { if (playerStartFlight.containsKey(player)) {
PlayerInventory inventory = player.getInventory(); PlayerInventory inventory = player.getInventory();
ItemStack chest = inventory.getChestplate(); // copy their current armor
// make sure the player is wearing an elytra ItemStack[] armor = inventory.getArmorContents().clone();
if (chest != null && chest.getType() == Material.ELYTRA) { for (ItemStack armorPiece : armor) {
// skip missing slots
if (armorPiece == null) {
continue;
}
// if the armor piece can glide, track the flight time
if (toolStats.itemChecker.canGlide(armorPiece)) {
long duration = (System.currentTimeMillis() - playerStartFlight.get(player)); long duration = (System.currentTimeMillis() - playerStartFlight.get(player));
ItemMeta newItem = toolStats.itemLore.updateFlightTime(chest, duration); ItemMeta newMeta = toolStats.itemLore.updateFlightTime(armorPiece, duration);
if (newItem != null) { if (newMeta != null) {
inventory.getChestplate().setItemMeta(newItem); armorPiece.setItemMeta(newMeta);
} }
} }
}
inventory.setArmorContents(armor);
playerStartFlight.remove(player); playerStartFlight.remove(player);
} }
} }

View File

@@ -18,7 +18,6 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.Material;
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;
@@ -40,7 +39,7 @@ public class PrepareCraft implements Listener {
// get the items in the crafting grid // get the items in the crafting grid
ItemStack[] grid = event.getInventory().getMatrix(); ItemStack[] grid = event.getInventory().getMatrix();
for (ItemStack item : grid) { for (ItemStack item : grid) {
if (item == null || item.getType() != Material.PAPER) { if (item == null) {
continue; continue;
} }
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
@@ -49,7 +48,7 @@ public class PrepareCraft implements Listener {
} }
// if the paper item has our PDC, cancel it // if the paper item has our PDC, cancel it
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.tokenType)) { if (container.has(toolStats.toolStatsKeys.getTokenType())) {
event.getInventory().setResult(null); event.getInventory().setResult(null);
} }
} }

View File

@@ -0,0 +1,59 @@
/*
* 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.events;
import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.entity.Trident;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
;
public class ProjectileShoot implements Listener {
private final ToolStats toolStats;
public ProjectileShoot(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onProjectileLaunch(PlayerLaunchProjectileEvent event) {
if (!(event.getProjectile() instanceof Trident tridentEntity)) {
return;
}
if (!toolStats.configTools.checkWorld(tridentEntity.getWorld().getName())) {
return;
}
tridentEntity.getScheduler().runDelayed(toolStats, scheduledTask -> {
ItemStack tridentStack = tridentEntity.getItemStack();
ItemMeta newTridentMeta = toolStats.itemLore.updateTridentThrows(tridentStack, 1);
if (newTridentMeta == null) {
return;
}
tridentStack.setItemMeta(newTridentMeta);
tridentEntity.setItemStack(tridentStack);
}, null, 1);
}
}

View File

@@ -45,7 +45,10 @@ 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 (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
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,10 @@ public class ShootBow implements Listener {
return; return;
} }
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.ADVENTURE) { if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return; return;
} }

View File

@@ -17,8 +17,8 @@
package lol.hyper.toolstats.events; package lol.hyper.toolstats.events;
import lol.hyper.hyperlib.datatypes.UUIDDataType;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@@ -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;
@@ -55,6 +56,9 @@ public class VillagerTrade implements Listener {
if (!(event.getWhoClicked() instanceof Player player)) { if (!(event.getWhoClicked() instanceof Player player)) {
return; return;
} }
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) { if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return; return;
} }
@@ -122,33 +126,54 @@ public class VillagerTrade implements Listener {
ItemStack newItem = oldItem.clone(); ItemStack newItem = oldItem.clone();
ItemMeta meta = newItem.getItemMeta(); ItemMeta meta = newItem.getItemMeta();
if (meta == null) { if (meta == null) {
toolStats.logger.warning(newItem + " does NOT have any meta! Unable to update stats."); toolStats.logger.warn("{} does NOT have any meta! Unable to update stats.", newItem);
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();
}
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.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG) || container.has(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType())) {
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 creation date is enabled, add it
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 3, newItem);
if (creationDate != null) {
container.set(toolStats.toolStatsKeys.getTimeCreated(), PersistentDataType.LONG, timeCreated);
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 3);
lore.add(creationDate);
meta.lore(lore);
}
// if ownership is enabled, add it
Component itemOwner = toolStats.itemLore.formatOwner(owner.getName(), 3, newItem);
if (itemOwner != null) {
container.set(toolStats.toolStatsKeys.getItemOwner(), new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.toolStatsKeys.getOriginType(), PersistentDataType.INTEGER, 3);
lore.add(itemOwner);
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.toolStatsKeys.getHash(), 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

@@ -51,9 +51,9 @@ public class HashMaker {
return hexString.toString(); return hexString.toString();
} catch (NoSuchAlgorithmException exception) { } catch (NoSuchAlgorithmException exception) {
toolStats.logger.warning("Unable to generate hash for " + player + "!"); toolStats.logger.error("Unable to generate hash", exception);
toolStats.logger.warning("Generating a random UUID instead."); toolStats.logger.warn("Unable to generate hash for {}!", player);
exception.printStackTrace(); toolStats.logger.warn("Generating a random UUID instead.");
return java.util.UUID.randomUUID().toString(); return java.util.UUID.randomUUID().toString();
} }
} }

View File

@@ -17,6 +17,7 @@
package lol.hyper.toolstats.tools; package lol.hyper.toolstats.tools;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
@@ -51,7 +52,7 @@ public class ItemChecker {
mineItems.add(material); mineItems.add(material);
} }
if (lowerCase.contains("_sword") || lowerCase.contains("_axe")) { if (lowerCase.contains("_sword") || lowerCase.contains("_axe") || lowerCase.contains("_spear")) {
meleeItems.add(material); meleeItems.add(material);
} }
@@ -69,6 +70,7 @@ public class ItemChecker {
validItems.add(Material.CROSSBOW); validItems.add(Material.CROSSBOW);
validItems.add(Material.FISHING_ROD); validItems.add(Material.FISHING_ROD);
validItems.add(Material.ELYTRA); validItems.add(Material.ELYTRA);
validItems.add(Material.SHIELD);
// combine the lists // combine the lists
validItems.addAll(armorItems); validItems.addAll(armorItems);
@@ -116,6 +118,22 @@ public class ItemChecker {
return mineItems.contains(itemType); return mineItems.contains(itemType);
} }
/**
* In newer versions of Minecraft, you can make items glide, which works
* like an Elytra.
*
* @param itemStack The item to check.
* @return True/false if the item can glide like an Elytra.
*/
public boolean canGlide(ItemStack itemStack) {
// if it's an elytra, we are good
if (itemStack.getType() == Material.ELYTRA) {
return true;
}
// otherwise if it has the GLIDER data
return itemStack.hasData(DataComponentTypes.GLIDER);
}
/** /**
* Check a given item for a target token. * Check a given item for a target token.
* *
@@ -125,12 +143,12 @@ public class ItemChecker {
*/ */
public boolean checkTokens(PersistentDataContainer container, String targetToken) { public boolean checkTokens(PersistentDataContainer container, String targetToken) {
// make sure the item has tokens // make sure the item has tokens
if (!container.has(toolStats.tokenApplied, PersistentDataType.STRING)) { if (!container.has(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING)) {
return false; return false;
} }
// get the tokens for this item // get the tokens for this item
String tokens = container.get(toolStats.tokenApplied, PersistentDataType.STRING); String tokens = container.get(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING);
if (tokens == null) { if (tokens == null) {
return false; return false;
} }
@@ -151,12 +169,12 @@ public class ItemChecker {
return new String[0]; return new String[0];
} }
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
if (!container.has(toolStats.tokenApplied, PersistentDataType.STRING)) { if (!container.has(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING)) {
return new String[0]; return new String[0];
} }
// get the tokens for this item // get the tokens for this item
String tokensRaw = container.get(toolStats.tokenApplied, PersistentDataType.STRING); String tokensRaw = container.get(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING);
if (tokensRaw == null) { if (tokensRaw == null) {
return new String[0]; return new String[0];
} }
@@ -180,12 +198,12 @@ public class ItemChecker {
String[] tokens = getTokens(item); String[] tokens = getTokens(item);
// there are no tokens // there are no tokens
if (tokens.length == 0) { if (tokens.length == 0) {
container.set(toolStats.tokenApplied, PersistentDataType.STRING, token); container.set(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING, token);
} else { } else {
// other tokens exist, so add // other tokens exist, so add
String[] newTokens = Arrays.copyOf(tokens, tokens.length + 1); String[] newTokens = Arrays.copyOf(tokens, tokens.length + 1);
newTokens[tokens.length] = token; newTokens[tokens.length] = token;
container.set(toolStats.tokenApplied, PersistentDataType.STRING, String.join(",", newTokens)); container.set(toolStats.toolStatsKeys.getTokenApplied(), PersistentDataType.STRING, String.join(",", newTokens));
} }
item.setItemMeta(meta); item.setItemMeta(meta);
return item; return item;
@@ -303,36 +321,48 @@ public class ItemChecker {
} }
PersistentDataContainer container = meta.getPersistentDataContainer(); PersistentDataContainer container = meta.getPersistentDataContainer();
ArrayList<String> tokens = new ArrayList<>(); ArrayList<String> tokens = new ArrayList<>();
if (container.has(toolStats.playerKills)) { if (container.has(toolStats.toolStatsKeys.getPlayerKills())) {
tokens.add("player-kills"); tokens.add("player-kills");
} }
if (container.has(toolStats.mobKills)) { if (container.has(toolStats.toolStatsKeys.getMobKills())) {
tokens.add("mob-kills"); tokens.add("mob-kills");
} }
if (container.has(toolStats.blocksMined)) { if (container.has(toolStats.toolStatsKeys.getBlocksMined())) {
tokens.add("blocks-mined"); tokens.add("blocks-mined");
} }
if (container.has(toolStats.cropsHarvested)) { if (container.has(toolStats.toolStatsKeys.getCropsHarvested())) {
tokens.add("crops-mined"); tokens.add("crops-mined");
} }
if (container.has(toolStats.fishCaught)) { if (container.has(toolStats.toolStatsKeys.getFishCaught())) {
tokens.add("fish-caught"); tokens.add("fish-caught");
} }
if (container.has(toolStats.sheepSheared)) { if (container.has(toolStats.toolStatsKeys.getSheepSheared())) {
tokens.add("sheep-sheared"); tokens.add("sheep-sheared");
} }
if (container.has(toolStats.armorDamage)) { if (container.has(toolStats.toolStatsKeys.getArmorDamage())) {
tokens.add("damage-taken"); tokens.add("damage-taken");
} }
if (container.has(toolStats.arrowsShot)) { if (container.has(toolStats.toolStatsKeys.getArrowsShot())) {
tokens.add("arrows-shot"); tokens.add("arrows-shot");
} }
if (container.has(toolStats.flightTime)) { if (container.has(toolStats.toolStatsKeys.getFlightTime())) {
tokens.add("flight-time"); tokens.add("flight-time");
} }
if (container.has(toolStats.damageDone)) { if (container.has(toolStats.toolStatsKeys.getDamageDone())) {
tokens.add("damage-done"); tokens.add("damage-done");
} }
if (container.has(toolStats.toolStatsKeys.getWitherKills())) {
tokens.add("wither-kills");
}
if (container.has(toolStats.toolStatsKeys.getEnderDragonKills())) {
tokens.add("enderdragon-kills");
}
if (container.has(toolStats.toolStatsKeys.getCriticalStrikes())) {
tokens.add("critical-strikes");
}
if (container.has(toolStats.toolStatsKeys.getTridentThrows())) {
tokens.add("trident-throws");
}
if (tokens.isEmpty()) { if (tokens.isEmpty()) {
return null; return null;
} }
@@ -369,6 +399,6 @@ public class ItemChecker {
public boolean keyCheck(PersistentDataContainer container) { public boolean keyCheck(PersistentDataContainer container) {
return container.getKeys().stream() return container.getKeys().stream()
.map(NamespacedKey::getKey) .map(NamespacedKey::getKey)
.anyMatch(key -> toolStats.tokenKeys.stream().anyMatch(tokenKey -> tokenKey.getKey().equalsIgnoreCase(key))); .anyMatch(key -> toolStats.toolStatsKeys.getTokenKeys().stream().anyMatch(tokenKey -> tokenKey.getKey().equalsIgnoreCase(key)));
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,10 @@ 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.HashMap;
import java.util.Locale; import java.util.Locale;
@@ -35,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) {
@@ -48,35 +53,35 @@ public class NumberFormat {
// if these config values are missing, use the default ones // if these config values are missing, use the default ones
if (dateFormat == null) { if (dateFormat == null) {
dateFormat = "M/dd/yyyy"; dateFormat = "M/dd/yyyy";
toolStats.logger.warning("date-format is missing! Using default American English format."); toolStats.logger.warn("date-format is missing! Using default American English format.");
} }
if (decimalSeparator == null) { if (decimalSeparator == null) {
decimalSeparator = "."; decimalSeparator = ".";
toolStats.logger.warning("number-formats.decimal-separator is missing! Using default \".\" instead."); toolStats.logger.warn("number-formats.decimal-separator is missing! Using default \".\" instead.");
} }
if (commaSeparator == null) { if (commaSeparator == null) {
commaSeparator = ","; commaSeparator = ",";
toolStats.logger.warning("number-formats.comma-separator is missing! Using default \",\" instead."); toolStats.logger.warn("number-formats.comma-separator is missing! Using default \",\" instead.");
} }
if (commaFormat == null) { if (commaFormat == null) {
commaFormat = "#,###"; commaFormat = "#,###";
toolStats.logger.warning("number-formats.comma-format is missing! Using default #,### instead."); toolStats.logger.warn("number-formats.comma-format is missing! Using default #,### instead.");
} }
if (decimalFormat == null) { if (decimalFormat == null) {
decimalFormat = "#,##0.00"; decimalFormat = "#,##0.00";
toolStats.logger.warning("number-formats.comma-separator is missing! Using default #,###.00 instead."); toolStats.logger.warn("number-formats.comma-separator is missing! Using default #,###.00 instead.");
} }
// test the date format // test the date format
try { try {
DATE_FORMAT = new SimpleDateFormat(dateFormat, Locale.getDefault()); DATE_FORMAT = new SimpleDateFormat(dateFormat, Locale.getDefault());
} catch (NullPointerException | IllegalArgumentException exception) { } catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("date-format is NOT a valid format! Using default American English format."); toolStats.logger.error("Invalid format or missing format", exception);
exception.printStackTrace(); toolStats.logger.warn("date-format is NOT a valid format! Using default American English format.");
DATE_FORMAT = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH); DATE_FORMAT = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
} }
@@ -90,8 +95,8 @@ public class NumberFormat {
try { try {
COMMA_FORMAT = new DecimalFormat(commaFormat, formatSymbols); COMMA_FORMAT = new DecimalFormat(commaFormat, formatSymbols);
} catch (NullPointerException | IllegalArgumentException exception) { } catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("number-formats.comma-format is NOT a valid format! Using default #,### instead."); toolStats.logger.error("Invalid comma or missing format", exception);
exception.printStackTrace(); toolStats.logger.warn("number-formats.comma-format is NOT a valid format! Using default #,### instead.");
COMMA_FORMAT = new DecimalFormat("#,###", formatSymbols); COMMA_FORMAT = new DecimalFormat("#,###", formatSymbols);
} }
@@ -99,8 +104,8 @@ public class NumberFormat {
try { try {
DECIMAL_FORMAT = new DecimalFormat(decimalFormat, formatSymbols); DECIMAL_FORMAT = new DecimalFormat(decimalFormat, formatSymbols);
} catch (NullPointerException | IllegalArgumentException exception) { } catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("number-formats.decimal-format is NOT a valid format! Using default #,###.00 instead."); toolStats.logger.error("Invalid decimal or missing format", exception);
exception.printStackTrace(); toolStats.logger.warn("number-formats.decimal-format is NOT a valid format! Using default #,###.00 instead.");
DECIMAL_FORMAT = new DecimalFormat("#,###.00", formatSymbols); DECIMAL_FORMAT = new DecimalFormat("#,###.00", formatSymbols);
} }
} }
@@ -140,8 +145,9 @@ public class NumberFormat {
} }
/** /**
* Returns a human readable form of time in milliseconds. * Returns a human-readable form of time in milliseconds.
* E.g. given 3752348000L outputs 1 years, 5 months, 3 days, 14 hours, 12 minutes, 28 seconds. * E.g. given 3752348000L outputs 1 year, 5 months, 3 days, 14 hours, 12 minutes, 28 seconds.
*
* @param time The time in ms. * @param time The time in ms.
* @return Map with units as keys and time value, e.g. "years" (key) -> 1 (value) * @return Map with units as keys and time value, e.g. "years" (key) -> 1 (value)
*/ */
@@ -193,4 +199,13 @@ public class NumberFormat {
return timeUnits; 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

@@ -1,143 +0,0 @@
/*
* 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;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ShapedRecipe;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class TokenCrafting {
private final ToolStats toolStats;
private final Set<ShapedRecipe> recipes = new HashSet<>();
private final ArrayList<String> tokenTypes = new ArrayList<>();
public TokenCrafting(ToolStats toolStats) {
this.toolStats = toolStats;
}
public void setup() {
NamespacedKey playerKillsKey = new NamespacedKey(toolStats, "player-kills-token");
ShapedRecipe playerKillRecipe = new ShapedRecipe(playerKillsKey, toolStats.tokenItems.playerKills());
playerKillRecipe.shape(" P ", "PSP", " P ");
playerKillRecipe.setIngredient('P', Material.PAPER);
playerKillRecipe.setIngredient('S', Material.WOODEN_SWORD);
recipes.add(playerKillRecipe);
NamespacedKey mobKillsKey = new NamespacedKey(toolStats, "mob-kills-token");
ShapedRecipe mobKillsRecipe = new ShapedRecipe(mobKillsKey, toolStats.tokenItems.mobKills());
mobKillsRecipe.shape(" P ", "PRP", " P ");
mobKillsRecipe.setIngredient('P', Material.PAPER);
mobKillsRecipe.setIngredient('R', Material.ROTTEN_FLESH);
recipes.add(mobKillsRecipe);
NamespacedKey blocksMinedKey = new NamespacedKey(toolStats, "blocks-mined-token");
ShapedRecipe blocksMinedRecipe = new ShapedRecipe(blocksMinedKey, toolStats.tokenItems.blocksMined());
blocksMinedRecipe.shape(" P ", "PSP", " P ");
blocksMinedRecipe.setIngredient('P', Material.PAPER);
blocksMinedRecipe.setIngredient('S', Material.WOODEN_PICKAXE);
recipes.add(blocksMinedRecipe);
NamespacedKey cropsMinedKey = new NamespacedKey(toolStats, "crops-mined-token");
ShapedRecipe cropsMinedRecipe = new ShapedRecipe(cropsMinedKey, toolStats.tokenItems.cropsMined());
cropsMinedRecipe.shape(" P ", "PHP", " P ");
cropsMinedRecipe.setIngredient('P', Material.PAPER);
cropsMinedRecipe.setIngredient('H', Material.WOODEN_HOE);
recipes.add(cropsMinedRecipe);
NamespacedKey fishCaughtKey = new NamespacedKey(toolStats, "fish-caught-token");
ShapedRecipe fishCaughtRecipe = new ShapedRecipe(fishCaughtKey, toolStats.tokenItems.fishCaught());
fishCaughtRecipe.shape(" P ", "PCP", " P ");
fishCaughtRecipe.setIngredient('P', Material.PAPER);
fishCaughtRecipe.setIngredient('C', Material.COD);
recipes.add(fishCaughtRecipe);
NamespacedKey sheepShearedKey = new NamespacedKey(toolStats, "sheep-sheared-token");
ShapedRecipe sheepShearedRecipe = new ShapedRecipe(sheepShearedKey, toolStats.tokenItems.sheepSheared());
sheepShearedRecipe.shape(" P ", "PWP", " P ");
sheepShearedRecipe.setIngredient('P', Material.PAPER);
sheepShearedRecipe.setIngredient('W', Material.WHITE_WOOL);
recipes.add(sheepShearedRecipe);
NamespacedKey armorDamageKey = new NamespacedKey(toolStats, "damage-taken-token");
ShapedRecipe armorDamageRecipe = new ShapedRecipe(armorDamageKey, toolStats.tokenItems.damageTaken());
armorDamageRecipe.shape(" P ", "PCP", " P ");
armorDamageRecipe.setIngredient('P', Material.PAPER);
armorDamageRecipe.setIngredient('C', Material.LEATHER_CHESTPLATE);
recipes.add(armorDamageRecipe);
NamespacedKey damageDoneKey = new NamespacedKey(toolStats, "damage-done-token");
ShapedRecipe damageDoneRecipe = new ShapedRecipe(damageDoneKey, toolStats.tokenItems.damageDone());
damageDoneRecipe.shape(" P ", "PSP", " P ");
damageDoneRecipe.setIngredient('P', Material.PAPER);
damageDoneRecipe.setIngredient('S', Material.SHIELD);
recipes.add(damageDoneRecipe);
NamespacedKey arrowsShotKey = new NamespacedKey(toolStats, "arrows-shot-token");
ShapedRecipe arrowsShotRecipe = new ShapedRecipe(arrowsShotKey, toolStats.tokenItems.arrowsShot());
arrowsShotRecipe.shape(" P ", "PAP", " P ");
arrowsShotRecipe.setIngredient('P', Material.PAPER);
arrowsShotRecipe.setIngredient('A', Material.ARROW);
recipes.add(arrowsShotRecipe);
NamespacedKey flightTimeKey = new NamespacedKey(toolStats, "flight-time-token");
ShapedRecipe flightTimeRecipe = new ShapedRecipe(flightTimeKey, toolStats.tokenItems.flightTime());
flightTimeRecipe.shape(" P ", "PFP", " P ");
flightTimeRecipe.setIngredient('P', Material.PAPER);
flightTimeRecipe.setIngredient('F', Material.FEATHER);
recipes.add(flightTimeRecipe);
NamespacedKey resetKey = new NamespacedKey(toolStats, "reset-token");
ShapedRecipe resetRecipe = new ShapedRecipe(resetKey, toolStats.tokenItems.resetToken());
resetRecipe.shape(" P ", "PPP", " P ");
resetRecipe.setIngredient('P', Material.PAPER);
recipes.add(resetRecipe);
NamespacedKey removeKey = new NamespacedKey(toolStats, "remove-token");
ShapedRecipe removeRecipe = new ShapedRecipe(removeKey, toolStats.tokenItems.removeToken());
removeRecipe.shape(" P ", "P P", " P ");
removeRecipe.setIngredient('P', Material.PAPER);
recipes.add(removeRecipe);
tokenTypes.add("crops-mined");
tokenTypes.add("blocks-mined");
tokenTypes.add("damage-taken");
tokenTypes.add("damage-done");
tokenTypes.add("mob-kills");
tokenTypes.add("player-kills");
tokenTypes.add("arrows-shot");
tokenTypes.add("sheep-sheared");
tokenTypes.add("flight-time");
tokenTypes.add("fish-caught");
tokenTypes.add("reset");
tokenTypes.add("remove");
}
public Set<ShapedRecipe> getRecipes() {
return recipes;
}
public ArrayList<String> getTokenTypes() {
return tokenTypes;
}
}

View File

@@ -0,0 +1,257 @@
/*
* 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;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.CustomModelData;
import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.*;
public class TokenData {
private final ToolStats toolStats;
private final Set<ShapedRecipe> recipes = new HashSet<>();
private final ArrayList<String> tokenTypes = new ArrayList<>();
public TokenData(ToolStats toolStats) {
this.toolStats = toolStats;
}
public void setup() {
NamespacedKey playerKillsKey = new NamespacedKey(toolStats, "player-kills-token");
ShapedRecipe playerKillRecipe = new ShapedRecipe(playerKillsKey, createToken("player-kills"));
playerKillRecipe.shape(" P ", "PSP", " P ");
playerKillRecipe.setIngredient('P', Material.PAPER);
playerKillRecipe.setIngredient('S', Material.WOODEN_SWORD);
recipes.add(playerKillRecipe);
NamespacedKey mobKillsKey = new NamespacedKey(toolStats, "mob-kills-token");
ShapedRecipe mobKillsRecipe = new ShapedRecipe(mobKillsKey, createToken("mob-kills"));
mobKillsRecipe.shape(" P ", "PRP", " P ");
mobKillsRecipe.setIngredient('P', Material.PAPER);
mobKillsRecipe.setIngredient('R', Material.ROTTEN_FLESH);
recipes.add(mobKillsRecipe);
NamespacedKey blocksMinedKey = new NamespacedKey(toolStats, "blocks-mined-token");
ShapedRecipe blocksMinedRecipe = new ShapedRecipe(blocksMinedKey, createToken("blocks-mined"));
blocksMinedRecipe.shape(" P ", "PSP", " P ");
blocksMinedRecipe.setIngredient('P', Material.PAPER);
blocksMinedRecipe.setIngredient('S', Material.WOODEN_PICKAXE);
recipes.add(blocksMinedRecipe);
NamespacedKey cropsMinedKey = new NamespacedKey(toolStats, "crops-mined-token");
ShapedRecipe cropsMinedRecipe = new ShapedRecipe(cropsMinedKey, createToken("crops-mined"));
cropsMinedRecipe.shape(" P ", "PHP", " P ");
cropsMinedRecipe.setIngredient('P', Material.PAPER);
cropsMinedRecipe.setIngredient('H', Material.WOODEN_HOE);
recipes.add(cropsMinedRecipe);
NamespacedKey fishCaughtKey = new NamespacedKey(toolStats, "fish-caught-token");
ShapedRecipe fishCaughtRecipe = new ShapedRecipe(fishCaughtKey, createToken("fish-caught"));
fishCaughtRecipe.shape(" P ", "PCP", " P ");
fishCaughtRecipe.setIngredient('P', Material.PAPER);
fishCaughtRecipe.setIngredient('C', Material.COD);
recipes.add(fishCaughtRecipe);
NamespacedKey sheepShearedKey = new NamespacedKey(toolStats, "sheep-sheared-token");
ShapedRecipe sheepShearedRecipe = new ShapedRecipe(sheepShearedKey, createToken("sheep-sheared"));
sheepShearedRecipe.shape(" P ", "PWP", " P ");
sheepShearedRecipe.setIngredient('P', Material.PAPER);
sheepShearedRecipe.setIngredient('W', Material.WHITE_WOOL);
recipes.add(sheepShearedRecipe);
NamespacedKey armorDamageKey = new NamespacedKey(toolStats, "damage-taken-token");
ShapedRecipe armorDamageRecipe = new ShapedRecipe(armorDamageKey, createToken("damage-taken"));
armorDamageRecipe.shape(" P ", "PCP", " P ");
armorDamageRecipe.setIngredient('P', Material.PAPER);
armorDamageRecipe.setIngredient('C', Material.LEATHER_CHESTPLATE);
recipes.add(armorDamageRecipe);
NamespacedKey damageDoneKey = new NamespacedKey(toolStats, "damage-done-token");
ShapedRecipe damageDoneRecipe = new ShapedRecipe(damageDoneKey, createToken("damage-done"));
damageDoneRecipe.shape(" P ", "PSP", " P ");
damageDoneRecipe.setIngredient('P', Material.PAPER);
damageDoneRecipe.setIngredient('S', Material.SHIELD);
recipes.add(damageDoneRecipe);
NamespacedKey arrowsShotKey = new NamespacedKey(toolStats, "arrows-shot-token");
ShapedRecipe arrowsShotRecipe = new ShapedRecipe(arrowsShotKey, createToken("arrows-shot"));
arrowsShotRecipe.shape(" P ", "PAP", " P ");
arrowsShotRecipe.setIngredient('P', Material.PAPER);
arrowsShotRecipe.setIngredient('A', Material.ARROW);
recipes.add(arrowsShotRecipe);
NamespacedKey flightTimeKey = new NamespacedKey(toolStats, "flight-time-token");
ShapedRecipe flightTimeRecipe = new ShapedRecipe(flightTimeKey, createToken("flight-time"));
flightTimeRecipe.shape(" P ", "PFP", " P ");
flightTimeRecipe.setIngredient('P', Material.PAPER);
flightTimeRecipe.setIngredient('F', Material.FEATHER);
recipes.add(flightTimeRecipe);
NamespacedKey resetKey = new NamespacedKey(toolStats, "reset-token");
ShapedRecipe resetRecipe = new ShapedRecipe(resetKey, createToken("reset"));
resetRecipe.shape(" P ", "PPP", " P ");
resetRecipe.setIngredient('P', Material.PAPER);
recipes.add(resetRecipe);
NamespacedKey removeKey = new NamespacedKey(toolStats, "remove-token");
ShapedRecipe removeRecipe = new ShapedRecipe(removeKey, createToken("remove"));
removeRecipe.shape(" P ", "P P", " P ");
removeRecipe.setIngredient('P', Material.PAPER);
recipes.add(removeRecipe);
NamespacedKey witherKillsKey = new NamespacedKey(toolStats, "wither-kills-token");
ShapedRecipe witherKillsRecipe = new ShapedRecipe(witherKillsKey, createToken("wither-kills"));
witherKillsRecipe.shape(" P ", "PWP", " P ");
witherKillsRecipe.setIngredient('P', Material.PAPER);
witherKillsRecipe.setIngredient('W', Material.WITHER_ROSE);
recipes.add(witherKillsRecipe);
NamespacedKey enderDragonKillsKey = new NamespacedKey(toolStats, "enderdragon-kills-token");
ShapedRecipe enderDragonKillsRecipe = new ShapedRecipe(enderDragonKillsKey, createToken("enderdragon-kills"));
enderDragonKillsRecipe.shape(" P ", "PEP", " P ");
enderDragonKillsRecipe.setIngredient('P', Material.PAPER);
enderDragonKillsRecipe.setIngredient('E', Material.ENDER_PEARL);
recipes.add(enderDragonKillsRecipe);
NamespacedKey criticalStrikesKey = new NamespacedKey(toolStats, "critical-strikes-token");
ShapedRecipe criticalStrikesRecipe = new ShapedRecipe(criticalStrikesKey, createToken("critical-strikes"));
criticalStrikesRecipe.shape(" P ", "PSP", " P ");
criticalStrikesRecipe.setIngredient('P', Material.PAPER);
criticalStrikesRecipe.setIngredient('S', Material.GOLDEN_SWORD);
recipes.add(criticalStrikesRecipe);
NamespacedKey tridentThrowsKey = new NamespacedKey(toolStats, "trident-throws-token");
ShapedRecipe tridentThrowsRecipe = new ShapedRecipe(tridentThrowsKey, createToken("trident-throws"));
tridentThrowsRecipe.shape(" P ", "PSP", " P ");
tridentThrowsRecipe.setIngredient('P', Material.PAPER);
tridentThrowsRecipe.setIngredient('S', Material.PRISMARINE_SHARD);
recipes.add(tridentThrowsRecipe);
tokenTypes.add("crops-mined");
tokenTypes.add("blocks-mined");
tokenTypes.add("damage-taken");
tokenTypes.add("damage-done");
tokenTypes.add("mob-kills");
tokenTypes.add("player-kills");
tokenTypes.add("arrows-shot");
tokenTypes.add("sheep-sheared");
tokenTypes.add("flight-time");
tokenTypes.add("fish-caught");
tokenTypes.add("reset");
tokenTypes.add("remove");
tokenTypes.add("wither-kills");
tokenTypes.add("enderdragon-kills");
tokenTypes.add("critical-strikes");
tokenTypes.add("trident-throws");
}
public Set<ShapedRecipe> getRecipes() {
return recipes;
}
public ArrayList<String> getTokenTypes() {
return tokenTypes;
}
public ItemStack createToken(String tokenType) {
// we don't have to check if the token exists
// we do that prior
ConfigurationSection tokenConfig = toolStats.config.getConfigurationSection("tokens.data." + tokenType);
String materialFromConfig = tokenConfig.getString("material");
if (materialFromConfig == null) {
toolStats.logger.warn("Could not find material config for token {}", tokenType);
toolStats.logger.warn("Using PAPER as default.");
materialFromConfig = "PAPER";
}
Material material = Material.getMaterial(materialFromConfig);
if (material == null) {
toolStats.logger.warn("Material {} is not a valid Minecraft material.", materialFromConfig);
toolStats.logger.warn("Using PAPER as default.");
material = Material.PAPER;
}
ItemStack token = new ItemStack(material);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
String titleFromConfig = toolStats.config.getString("tokens.data." + tokenType + ".title");
Component title = toolStats.textUtils.format(titleFromConfig);
List<Component> lore = toolStats.configTools.getTokenLore(tokenType);
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.toolStatsKeys.getTokenType(), PersistentDataType.STRING, tokenType);
token.setItemMeta(tokenMeta);
// set the custom model data
if (tokenConfig.getBoolean("custom-model-data.enabled")) {
String type = tokenConfig.getString("custom-model-data.type");
Object value = tokenConfig.get("custom-model-data.value");
if (type == null || value == null) {
toolStats.logger.info("Could not find custom model data for token {}", tokenType);
toolStats.logger.info("Type: {}", type);
toolStats.logger.info("Value: {}", value);
return null;
}
CustomModelData data = setData(type, value);
if (data != null) {
token.setData(DataComponentTypes.CUSTOM_MODEL_DATA, data);
} else {
return null;
}
}
return token;
}
private CustomModelData setData(String type, Object data) {
switch (type.toLowerCase(Locale.ROOT)) {
case "float": {
float f;
try {
f = Float.parseFloat(data.toString());
} catch (NumberFormatException e) {
toolStats.logger.info("{} is not a valid float!", data);
return null;
}
return CustomModelData.customModelData().addFloat(f).build();
}
case "string": {
return CustomModelData.customModelData().addString(data.toString()).build();
}
default: {
toolStats.logger.info("{} is not a valid data type!", data);
return null;
}
}
}
}

View File

@@ -0,0 +1,182 @@
package lol.hyper.toolstats.tools;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.NamespacedKey;
import java.util.HashSet;
import java.util.Set;
public class ToolStatsKeys {
private final ToolStats toolStats;
private final Set<NamespacedKey> tokenKeys = new HashSet<>();
public ToolStatsKeys(ToolStats toolStats) {
this.toolStats = toolStats;
}
private NamespacedKey itemOwner;
private NamespacedKey timeCreated;
private NamespacedKey playerKills;
private NamespacedKey mobKills;
private NamespacedKey blocksMined;
private NamespacedKey cropsHarvested;
private NamespacedKey fishCaught;
private NamespacedKey sheepSheared;
private NamespacedKey armorDamage;
private NamespacedKey damageDone;
private NamespacedKey newElytra;
private NamespacedKey hash;
private NamespacedKey arrowsShot;
private NamespacedKey droppedBy;
private NamespacedKey flightTime;
private NamespacedKey tokenType;
private NamespacedKey tokenApplied;
private NamespacedKey witherKills;
private NamespacedKey enderDragonKills;
private NamespacedKey criticalStrikes;
private NamespacedKey tridentThrows;
private NamespacedKey originType;
public void make() {
itemOwner = new NamespacedKey(toolStats, "owner");
timeCreated = new NamespacedKey(toolStats, "time-created");
playerKills = new NamespacedKey(toolStats, "player-kills");
mobKills = new NamespacedKey(toolStats, "mob-kills");
blocksMined = new NamespacedKey(toolStats, "generic-mined");
cropsHarvested = new NamespacedKey(toolStats, "crops-mined");
fishCaught = new NamespacedKey(toolStats, "fish-caught");
sheepSheared = new NamespacedKey(toolStats, "sheared");
armorDamage = new NamespacedKey(toolStats, "damage-taken");
damageDone = new NamespacedKey(toolStats, "damage-done");
newElytra = new NamespacedKey(toolStats, "new");
hash = new NamespacedKey(toolStats, "hash");
arrowsShot = new NamespacedKey(toolStats, "arrows-shot");
droppedBy = new NamespacedKey(toolStats, "dropped-by");
flightTime = new NamespacedKey(toolStats, "flightTime");
tokenType = new NamespacedKey(toolStats, "token-type");
tokenApplied = new NamespacedKey(toolStats, "token-applied");
witherKills = new NamespacedKey(toolStats, "wither-kills");
enderDragonKills = new NamespacedKey(toolStats, "enderdragon-kills");
criticalStrikes = new NamespacedKey(toolStats, "critical-strikes");
tridentThrows = new NamespacedKey(toolStats, "trident-throws");
originType = new NamespacedKey(toolStats, "origin");
// save which stat can be used by a reset token
tokenKeys.add(blocksMined);
tokenKeys.add(playerKills);
tokenKeys.add(mobKills);
tokenKeys.add(cropsHarvested);
tokenKeys.add(sheepSheared);
tokenKeys.add(fishCaught);
tokenKeys.add(flightTime);
tokenKeys.add(arrowsShot);
tokenKeys.add(armorDamage);
tokenKeys.add(witherKills);
tokenKeys.add(enderDragonKills);
tokenKeys.add(criticalStrikes);
tokenKeys.add(tridentThrows);
}
public NamespacedKey getItemOwner() {
return itemOwner;
}
public NamespacedKey getTimeCreated() {
return timeCreated;
}
public NamespacedKey getPlayerKills() {
return playerKills;
}
public NamespacedKey getMobKills() {
return mobKills;
}
public NamespacedKey getBlocksMined() {
return blocksMined;
}
public NamespacedKey getCropsHarvested() {
return cropsHarvested;
}
public NamespacedKey getFishCaught() {
return fishCaught;
}
public NamespacedKey getSheepSheared() {
return sheepSheared;
}
public NamespacedKey getArmorDamage() {
return armorDamage;
}
public NamespacedKey getDamageDone() {
return damageDone;
}
public NamespacedKey getElytraKey() {
return newElytra;
}
public NamespacedKey getHash() {
return hash;
}
public NamespacedKey getArrowsShot() {
return arrowsShot;
}
public NamespacedKey getDroppedBy() {
return droppedBy;
}
public NamespacedKey getFlightTime() {
return flightTime;
}
public NamespacedKey getTokenType() {
return tokenType;
}
public NamespacedKey getTokenApplied() {
return tokenApplied;
}
public NamespacedKey getWitherKills() {
return witherKills;
}
public NamespacedKey getEnderDragonKills() {
return enderDragonKills;
}
public NamespacedKey getCriticalStrikes() {
return criticalStrikes;
}
public NamespacedKey getTridentThrows() {
return tridentThrows;
}
/**
* Stores how an item was created.
* 0 = crafted.
* 1 = dropped.
* 2 = looted.
* 3 = traded.
* 4 = founded (for elytras).
* 5 = fished.
* 6 = spawned in (creative).
*/
public NamespacedKey getOriginType() {
return originType;
}
public Set<NamespacedKey> getTokenKeys() {
return tokenKeys;
}
}

View File

@@ -1,54 +0,0 @@
/*
* 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;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.nio.ByteBuffer;
import java.util.UUID;
public class UUIDDataType implements PersistentDataType<byte[], UUID> {
@Override
public @NotNull Class<byte[]> getPrimitiveType() {
return byte[].class;
}
@Override
public @NotNull Class<UUID> getComplexType() {
return UUID.class;
}
@Override
public byte @NotNull [] toPrimitive(UUID complex, @NotNull PersistentDataAdapterContext context) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(complex.getMostSignificantBits());
bb.putLong(complex.getLeastSignificantBits());
return bb.array();
}
@Override
public @NotNull UUID fromPrimitive(byte @NotNull [] primitive, @NotNull PersistentDataAdapterContext context) {
ByteBuffer bb = ByteBuffer.wrap(primitive);
long firstLong = bb.getLong();
long secondLong = bb.getLong();
return new UUID(firstLong, secondLong);
}
}

View File

@@ -20,8 +20,6 @@ package lol.hyper.toolstats.tools.config;
import lol.hyper.toolstats.ToolStats; import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Material; import org.bukkit.Material;
import java.util.ArrayList; import java.util.ArrayList;
@@ -34,8 +32,6 @@ import java.util.regex.Pattern;
public class ConfigTools { public class ConfigTools {
private final ToolStats toolStats; private final ToolStats toolStats;
public static final Pattern COLOR_CODES = Pattern.compile("[&§]([0-9a-fk-or])");
public static final Pattern CONFIG_HEX_PATTERN = Pattern.compile("[&§]#([A-Fa-f0-9]{6})");
public ConfigTools(ToolStats toolStats) { public ConfigTools(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
@@ -49,6 +45,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.warn("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
@@ -75,7 +76,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");
@@ -87,12 +87,54 @@ public class ConfigTools {
case "trident" -> toolStats.config.getBoolean("enabled." + configName + ".trident"); case "trident" -> toolStats.config.getBoolean("enabled." + configName + ".trident");
case "fishing-rod" -> toolStats.config.getBoolean("enabled." + configName + ".fishing-rod"); case "fishing-rod" -> toolStats.config.getBoolean("enabled." + configName + ".fishing-rod");
case "mace" -> toolStats.config.getBoolean("enabled." + configName + ".mace"); case "mace" -> toolStats.config.getBoolean("enabled." + configName + ".mace");
case "spear" -> toolStats.config.getBoolean("enabled." + configName + ".spear");
case "helmet", "chestplate", "leggings", "boots" -> case "helmet", "chestplate", "leggings", "boots" ->
toolStats.config.getBoolean("enabled." + configName + ".armor"); toolStats.config.getBoolean("enabled." + configName + ".armor");
default -> false; default -> false;
}; };
} }
/**
* Check the status of a world from the config.
*
* @param worldName The world to check.
* @return True if we can work in this world, false if not.
*/
public boolean checkWorld(String worldName) {
boolean enabled = toolStats.config.getBoolean("world-limit.enabled");
// if the system is disabled, all worlds are allowed
if (!enabled) {
return true;
}
String mode = toolStats.config.getString("world-limit.mode");
if (mode == null) {
toolStats.logger.info("world-limit.mode is not set, not allowing any worlds by default.");
return false;
}
List<String> worlds = toolStats.config.getStringList("world-limit.worlds");
// if no worlds are defined, deny them
if (worlds.isEmpty()) {
return false;
}
if (mode.equalsIgnoreCase("blacklist")) {
// this world is on list and mode = blacklisted
// don't allow this world, allow others not on list
return !worlds.contains(worldName);
}
if (mode.equalsIgnoreCase("whitelist")) {
// this world is on list and mode = whitelisted
// allow it. if the world is not on list, don't allow it
return worlds.contains(worldName);
}
toolStats.logger.warn("Unknown worlds.mode '{}', denying by default.", mode);
return false;
}
/** /**
* Format a string to be ready for lore usage. * Format a string to be ready for lore usage.
* *
@@ -104,7 +146,7 @@ public class ConfigTools {
public Component formatLore(String configName, String placeHolder, Object value) { public Component formatLore(String configName, String placeHolder, Object value) {
String lore = toolStats.config.getString("messages." + configName); String lore = toolStats.config.getString("messages." + configName);
if (lore == null) { if (lore == null) {
toolStats.logger.warning("Unable to find config message for: messages." + configName); toolStats.logger.warn("Unable to find config message for: messages.{}", configName);
return null; return null;
} }
@@ -121,16 +163,7 @@ public class ConfigTools {
lore = lore.replace(placeHolder, String.valueOf(value)); lore = lore.replace(placeHolder, String.valueOf(value));
} }
// if we match the old color codes, then format them as so component = toolStats.textUtils.format(lore);
Matcher hexMatcher = CONFIG_HEX_PATTERN.matcher(lore);
Matcher colorMatcher = COLOR_CODES.matcher(lore);
if (hexMatcher.find() || colorMatcher.find()) {
component = LegacyComponentSerializer.legacyAmpersand().deserialize(lore);
} else {
// otherwise format them normally
component = MiniMessage.miniMessage().deserialize(lore);
}
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE); return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
} }
@@ -144,7 +177,7 @@ public class ConfigTools {
public Component formatLoreMultiplePlaceholders(String configName, Map<String, String> placeHoldersValues) { public Component formatLoreMultiplePlaceholders(String configName, Map<String, String> placeHoldersValues) {
String lore = toolStats.config.getString("messages." + configName); String lore = toolStats.config.getString("messages." + configName);
if (lore == null) { if (lore == null) {
toolStats.logger.warning("Unable to find config message for: messages." + configName); toolStats.logger.warn("Unable to find config message for: messages.{}", configName);
return null; return null;
} }
@@ -179,49 +212,7 @@ public class ConfigTools {
Component component; Component component;
// Clean output text // Clean output text
String outputText = result.toString().replaceAll("\\s+", " ").trim(); String outputText = result.toString().replaceAll("\\s+", " ").trim();
component = toolStats.textUtils.format(outputText);
// 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.
*
* @param configName The config to format.
* @return Formatted string, null if the configName doesn't exist.
*/
public Component format(String configName) {
String message = toolStats.config.getString(configName);
if (message == null) {
toolStats.logger.warning("Unable to find config message for: " + configName);
return null;
}
// if the config message is empty, don't send it
if (message.isEmpty()) {
return null;
}
// the final component for this lore
Component component;
// if we match the old color codes, then format them as so
Matcher hexMatcher = CONFIG_HEX_PATTERN.matcher(message);
Matcher colorMatcher = COLOR_CODES.matcher(message);
if (hexMatcher.find() || colorMatcher.find()) {
component = LegacyComponentSerializer.legacyAmpersand().deserialize(message);
} else {
// otherwise format them normally
component = MiniMessage.miniMessage().deserialize(message);
}
return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE); return component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
} }
@@ -240,16 +231,14 @@ public class ConfigTools {
List<Component> finalLore = new ArrayList<>(); List<Component> finalLore = new ArrayList<>();
for (String line : raw) { for (String line : raw) {
Component component; if (line.contains("{levels}")) {
// if we match the old color codes, then format them as so Integer levels = toolStats.config.getInt("tokens.data." + tokenType + ".levels");
Matcher hexMatcher = CONFIG_HEX_PATTERN.matcher(line); // will return 0 if it doesn't exist
Matcher colorMatcher = COLOR_CODES.matcher(line); if (levels != 0) {
if (hexMatcher.find() || colorMatcher.find()) { line = line.replace("{levels}", String.valueOf(levels));
component = LegacyComponentSerializer.legacyAmpersand().deserialize(line);
} else {
// otherwise format them normally
component = MiniMessage.miniMessage().deserialize(line);
} }
}
Component component = toolStats.textUtils.format(line);
component = component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE); component = component.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE);
finalLore.add(component); finalLore.add(component);
} }

View File

@@ -31,35 +31,17 @@ public class ConfigUpdater {
public void updateConfig() { public void updateConfig() {
int version = toolStats.config.getInt("config-version"); int version = toolStats.config.getInt("config-version");
// Version 5 to 6 switch (version) {
if (version == 5) { case 5 -> new Version6(toolStats).update(); // 5 to 6
Version6 version6 = new Version6(toolStats); case 6 -> new Version7(toolStats).update(); // 6 to 7
version6.update(); case 7 -> new Version8(toolStats).update(); // 7 to 8
} case 8 -> new Version9(toolStats).update(); // 8 to 9
// Version 6 to 7 case 9 -> new Version10(toolStats).update(); // 9 to 10
if (version == 6) { case 10 -> new Version11(toolStats).update(); // 10 to 11
Version7 version7 = new Version7(toolStats); case 11 -> new Version12(toolStats).update(); // 11 to 12
version7.update(); case 12 -> new Version13(toolStats).update(); // 12 to 13
} case 13 -> new Version14(toolStats).update(); // 13 to 14
// Version 7 to 8 case 14 -> new Version15(toolStats).update(); // 14 to 15
if (version == 7) {
Version8 version8 = new Version8(toolStats);
version8.update();
}
// Version 8 to 9
if (version == 8) {
Version9 version9 = new Version9(toolStats);
version9.update();
}
// Version 9 to 10
if (version == 9) {
Version10 version10 = new Version10(toolStats);
version10.update();
}
// Version 10 to 11
if (version == 10) {
Version11 version11 = new Version11(toolStats);
version11.update();
} }
} }
} }

View File

@@ -1,253 +0,0 @@
/*
* 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;
import lol.hyper.toolstats.ToolStats;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.List;
public class TokenItems {
private final ToolStats toolStats;
public TokenItems(ToolStats toolStats) {
this.toolStats = toolStats;
}
public ItemStack playerKills() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.player-kills.title");
List<Component> lore = toolStats.configTools.getTokenLore("player-kills");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "player-kills");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack mobKills() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.mob-kills.title");
List<Component> lore = toolStats.configTools.getTokenLore("mob-kills");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "mob-kills");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack blocksMined() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.blocks-mined.title");
List<Component> lore = toolStats.configTools.getTokenLore("blocks-mined");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "blocks-mined");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack cropsMined() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.crops-mined.title");
List<Component> lore = toolStats.configTools.getTokenLore("crops-mined");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "crops-mined");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack fishCaught() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.fish-caught.title");
List<Component> lore = toolStats.configTools.getTokenLore("fight-caught");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "fish-caught");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack sheepSheared() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.sheep-sheared.title");
List<Component> lore = toolStats.configTools.getTokenLore("sheep-sheared");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "sheep-sheared");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack damageTaken() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.damage-taken.title");
List<Component> lore = toolStats.configTools.getTokenLore("damage-taken");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "damage-taken");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack damageDone() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.damage-done.title");
List<Component> lore = toolStats.configTools.getTokenLore("damage-done");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "damage-done");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack arrowsShot() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.arrows-shot.title");
List<Component> lore = toolStats.configTools.getTokenLore("arrows-shot");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "arrows-shot");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack flightTime() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.flight-time.title");
List<Component> lore = toolStats.configTools.getTokenLore("flight-time");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "flight-time");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack resetToken() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.reset.title");
List<Component> lore = toolStats.configTools.getTokenLore("reset");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "reset");
token.setItemMeta(tokenMeta);
return token;
}
public ItemStack removeToken() {
// set up the item
ItemStack token = new ItemStack(Material.PAPER);
ItemMeta tokenMeta = token.getItemMeta();
PersistentDataContainer tokenData = tokenMeta.getPersistentDataContainer();
// set the title and lore
Component title = toolStats.configTools.format("tokens.data.remove.title");
List<Component> lore = toolStats.configTools.getTokenLore("remove");
tokenMeta.displayName(title);
tokenMeta.lore(lore);
// set the PDC
tokenData.set(toolStats.tokenType, PersistentDataType.STRING, "remove");
token.setItemMeta(tokenMeta);
return token;
}
}

View File

@@ -43,8 +43,7 @@ public class Version10 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-9.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-9.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-9.yml!"); toolStats.logger.error("Unable to save config-9.yml!", exception);
throw new RuntimeException(exception);
} }
// we make this super verbose so that admins can see what's being added // we make this super verbose so that admins can see what's being added
@@ -72,8 +71,7 @@ public class Version10 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 10. A copy of version 9 has been saved as config-9.yml"); toolStats.logger.info("Config has been updated to version 10. A copy of version 9 has been saved as config-9.yml");

View File

@@ -45,8 +45,7 @@ public class Version11 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-10.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-10.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-10.yml!"); toolStats.logger.error("Unable to save config-10.yml!", exception);
throw new RuntimeException(exception);
} }
// we make this super verbose so that admins can see what's being added // we make this super verbose so that admins can see what's being added
@@ -95,8 +94,7 @@ public class Version11 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 11. A copy of version 10 has been saved as config-10.yml"); toolStats.logger.info("Config has been updated to version 11. A copy of version 10 has been saved as config-10.yml");

View File

@@ -0,0 +1,115 @@
/*
* 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 lol.hyper.toolstats.ToolStats;
import org.bukkit.configuration.ConfigurationSection;
import java.io.File;
import java.io.IOException;
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.error("Unable to save config-11.yml!", 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.error("Unable to save config.yml!", 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 {} to {}", oldSection, newSection);
ConfigurationSection old = toolStats.config.getConfigurationSection(oldSection);
toolStats.config.set(newSection, old);
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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 lol.hyper.toolstats.ToolStats;
import java.io.File;
import java.io.IOException;
public class Version13 {
private final ToolStats toolStats;
/**
* Used for updating from version 12 to 13.
*
* @param toolStats ToolStats instance.
*/
public Version13(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-12.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config-12.yml!", exception);
}
toolStats.logger.info("Updating config.yml to version 13.");
toolStats.config.set("config-version", 13);
for (String key : toolStats.config.getConfigurationSection("tokens.data").getKeys(false)) {
toolStats.logger.info("Adding tokens.data.{}.material", key);
toolStats.config.set("tokens.data." + key + ".material", "PAPER");
toolStats.logger.info("Adding tokens.data.{}.custom-model-data.enabled", key);
toolStats.config.set("tokens.data." + key + ".custom-model-data.enabled", false);
toolStats.logger.info("Adding tokens.data.{}.custom-model-data.type", key);
toolStats.config.set("tokens.data." + key + ".custom-model-data.type", "float");
toolStats.logger.info("Adding tokens.data.{}.custom-model-data.value", key);
toolStats.config.set("tokens.data." + key + ".custom-model-data.value", 1001);
}
// save the config and reload it
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config.yml!", exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 13. A copy of version 12 has been saved as config-12.yml");
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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 lol.hyper.toolstats.ToolStats;
import java.io.File;
import java.io.IOException;
public class Version14 {
private final ToolStats toolStats;
/**
* Used for updating from version 13 to 14.
*
* @param toolStats ToolStats instance.
*/
public Version14(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-13.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config-13.yml!", exception);
}
toolStats.logger.info("Updating config.yml to version 14.");
toolStats.config.set("config-version", 14);
// add spear to sections to be a toggle
toolStats.config.set("enabled.crafted-by.spear", true);
toolStats.logger.info("Adding enabled.crafted-by.spear");
toolStats.config.set("enabled.crafted-on.spear", true);
toolStats.logger.info("Adding enabled.crafted-on.spear");
toolStats.config.set("enabled.looted-by.spear", true);
toolStats.logger.info("Adding enabled.looted-by.spear");
toolStats.config.set("enabled.looted-on.spear", true);
toolStats.logger.info("Adding enabled.looted-on.spear");
toolStats.config.set("enabled.damage-done.spear", true);
toolStats.logger.info("Adding enabled.damage-done.spear");
toolStats.config.set("enabled.player-kills.spear", true);
toolStats.logger.info("Adding enabled.player-kills.spear");
toolStats.config.set("enabled.mob-kills.spear", true);
toolStats.logger.info("Adding enabled.mob-kills.spear");
toolStats.config.set("enabled.spawned-in-by.spear", true);
toolStats.logger.info("Adding enabled.spawned-in-by.spear");
toolStats.config.set("enabled.spawned-in-on.spear", true);
toolStats.logger.info("Adding enabled.spawned-in-on.spear");
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config.yml!", exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 14. A copy of version 13 has been saved as config-13.yml");
}
}

View File

@@ -0,0 +1,147 @@
/*
* 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 lol.hyper.toolstats.ToolStats;
import org.bukkit.configuration.ConfigurationSection;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class Version15 {
private final ToolStats toolStats;
/**
* Used for updating from version 14 to 15.
*
* @param toolStats ToolStats instance.
*/
public Version15(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-14.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config-14.yml!", exception);
}
toolStats.logger.info("Updating config.yml to version 15.");
toolStats.config.set("config-version", 15);
// wither kills token
toolStats.logger.info("Adding new token to config: wither-kills");
toolStats.config.set("tokens.data.wither-kills.title", "&7ToolStats: &8Wither Kills Token");
toolStats.config.set("tokens.data.wither-kills.lore", List.of(
"&8Combine with a melee or ranged weapon in an anvil to track wither kills.",
"&8Uses &7{levels} &8level."
));
toolStats.config.set("tokens.data.wither-kills.levels", 1);
toolStats.config.set("tokens.data.wither-kills.material", "PAPER");
toolStats.config.set("tokens.data.wither-kills.custom-model-data.enabled", false);
toolStats.config.set("tokens.data.wither-kills.custom-model-data.type", "float");
toolStats.config.set("tokens.data.wither-kills.custom-model-data.value", 1001);
// ender dragon kills token
toolStats.logger.info("Adding new token to config: enderdragon-kills");
toolStats.config.set("tokens.data.enderdragon-kills.title", "&7ToolStats: &8Ender Dragon Kills Token");
toolStats.config.set("tokens.data.enderdragon-kills.lore", List.of(
"&8Combine with a melee or ranged weapon in an anvil to track Ender Dragon kills.",
"&8Uses &7{levels} &8level."
));
toolStats.config.set("tokens.data.enderdragon-kills.levels", 1);
toolStats.config.set("tokens.data.enderdragon-kills.material", "PAPER");
toolStats.config.set("tokens.data.enderdragon-kills.custom-model-data.enabled", false);
toolStats.config.set("tokens.data.enderdragon-kills.custom-model-data.type", "float");
toolStats.config.set("tokens.data.enderdragon-kills.custom-model-data.value", 1001);
// critical strikes token
toolStats.logger.info("Adding new token to config: critical-strikes");
toolStats.config.set("tokens.data.critical-strikes.title", "&7ToolStats: &8Critical Strikes Token");
toolStats.config.set("tokens.data.critical-strikes.lore", List.of(
"&8Combine with a melee or ranged weapon in an anvil to track critical strikes.",
"&8Uses &7{levels} &8level."
));
toolStats.config.set("tokens.data.critical-strikes.levels", 1);
toolStats.config.set("tokens.data.critical-strikes.material", "PAPER");
toolStats.config.set("tokens.data.critical-strikes.custom-model-data.enabled", false);
toolStats.config.set("tokens.data.critical-strikes.custom-model-data.type", "float");
toolStats.config.set("tokens.data.critical-strikes.custom-model-data.value", 1001);
// trident throws token
toolStats.logger.info("Adding new token to config: trident-throws");
toolStats.config.set("tokens.data.trident-throws.title", "&7ToolStats: &8Trident Throws Token");
toolStats.config.set("tokens.data.trident-throws.lore", List.of(
"&8Combine with a trident in an anvil to track times thrown.",
"&8Uses &7{levels} &8level."
));
toolStats.config.set("tokens.data.trident-throws.levels", 1);
toolStats.config.set("tokens.data.trident-throws.material", "PAPER");
toolStats.config.set("tokens.data.trident-throws.custom-model-data.enabled", false);
toolStats.config.set("tokens.data.trident-throws.custom-model-data.type", "float");
toolStats.config.set("tokens.data.trident-throws.custom-model-data.value", 1001);
// bosses-killed stuff
toolStats.logger.info("Adding enabled.bosses-killed.wither");
toolStats.config.set("enabled.bosses-killed.wither", true);
toolStats.logger.info("Adding enabled.bosses-killed.enderdragon");
toolStats.config.set("enabled.bosses-killed.enderdragon", true);
// critical strikes
toolStats.config.set("enabled.critical-strikes", true);
toolStats.logger.info("Adding enabled.critical-strikes");
//trident throws
toolStats.config.set("enabled.trident-throws", true);
toolStats.logger.info("Adding enabled.trident-throws");
// default for new stats
toolStats.logger.info("Adding new default messages");
toolStats.config.set("messages.bosses-killed.wither", "&7Withers killed: &8{kills}");
toolStats.config.set("messages.bosses-killed.enderdragon", "&7Ender Dragons killed: &8{kills}");
toolStats.config.set("messages.critical-strikes", "&7Critical strikes: &8{strikes}");
toolStats.config.set("messages.trident-throws", "&7Times thrown: &8{times}");
// blacklist feature
toolStats.logger.info("Adding new world-limit feature, which is disabled by default");
List<String> worlds = Arrays.asList("world_1", "world_2");
toolStats.config.set("world-limit.enabled", false);
toolStats.config.set("world-limit.mode", "blacklist");
toolStats.config.set("world-limit.worlds", worlds);
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config.yml!", exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 15. A copy of version 14 has been saved as config-14.yml");
}
}

View File

@@ -46,8 +46,7 @@ public class Version6 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-5.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-5.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-5.yml!"); toolStats.logger.error("Unable to save config-5.yml!", exception);
throw new RuntimeException(exception);
} }
// we make this super verbose so that admins can see what's being added // we make this super verbose so that admins can see what's being added
@@ -107,8 +106,7 @@ public class Version6 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 6. A copy of version 5 has been saved as config-5.yml"); toolStats.logger.info("Config has been updated to version 6. A copy of version 5 has been saved as config-5.yml");

View File

@@ -43,8 +43,7 @@ public class Version7 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-6.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-6.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-6.yml!"); toolStats.logger.error("Unable to save config-6.yml!", exception);
throw new RuntimeException(exception);
} }
// we make this super verbose so that admins can see what's being added // we make this super verbose so that admins can see what's being added
@@ -61,8 +60,7 @@ public class Version7 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 7. A copy of version 6 has been saved as config-6.yml"); toolStats.logger.info("Config has been updated to version 7. A copy of version 6 has been saved as config-6.yml");

View File

@@ -45,8 +45,7 @@ public class Version8 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-7.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-7.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-7.yml!"); toolStats.logger.error("Unable to save config-7.yml!", exception);
throw new RuntimeException(exception);
} }
// we make this super verbose so that admins can see what's being added // we make this super verbose so that admins can see what's being added
@@ -78,8 +77,7 @@ public class Version8 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 8. A copy of version 7 has been saved as config-7.yml"); toolStats.logger.info("Config has been updated to version 8. A copy of version 7 has been saved as config-7.yml");

View File

@@ -45,8 +45,7 @@ public class Version9 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-8.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config-8.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config-8.yml!"); toolStats.logger.error("Unable to save config-8.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.logger.info("Updating config.yml to version 9."); toolStats.logger.info("Updating config.yml to version 9.");
@@ -78,8 +77,7 @@ public class Version9 {
try { try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml"); toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) { } catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!"); toolStats.logger.error("Unable to save config.yml!", exception);
throw new RuntimeException(exception);
} }
toolStats.loadConfig(); toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 9. A copy of version 8 has been saved as config-8.yml"); toolStats.logger.info("Config has been updated to version 9. A copy of version 8 has been saved as config-8.yml");
@@ -93,7 +91,7 @@ public class Version9 {
* @param lore The lore of the item. * @param lore The lore of the item.
*/ */
private void addToken(String tokenType, String title, String lore) { private void addToken(String tokenType, String title, String lore) {
toolStats.logger.info("Adding token type configuration for " + tokenType); toolStats.logger.info("Adding token type configuration for {}", tokenType);
toolStats.config.set("tokens.data." + tokenType + ".title", title); toolStats.config.set("tokens.data." + tokenType + ".title", title);
List<String> loreList = new ArrayList<>(); List<String> loreList = new ArrayList<>();
loreList.add(lore); loreList.add(lore);

View File

@@ -8,66 +8,182 @@ tokens:
title: "&7ToolStats: &8Player Kills Token" title: "&7ToolStats: &8Player Kills Token"
lore: lore:
- "&8Combine with a melee or ranged weapon in an anvil to track player kills." - "&8Combine with a melee or ranged weapon in an anvil to track player kills."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
mob-kills: mob-kills:
title: "&7ToolStats: &8Mob Kills Token" title: "&7ToolStats: &8Mob Kills Token"
lore: lore:
- "&8Combine with a melee or ranged weapon in an anvil to track mob kills." - "&8Combine with a melee or ranged weapon in an anvil to track mob kills."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
blocks-mined: blocks-mined:
title: "&7ToolStats: &8Blocks Mined Token" title: "&7ToolStats: &8Blocks Mined Token"
lore: lore:
- "&8Combine with a pickaxe, axe, shovel, or shears in an anvil to track blocks mined." - "&8Combine with a pickaxe, axe, shovel, or shears in an anvil to track blocks mined."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
crops-mined: crops-mined:
title: "&7ToolStats: &8Crops Mined Token" title: "&7ToolStats: &8Crops Mined Token"
lore: lore:
- "&8Combine with a hoe in an anvil to track crops broken." - "&8Combine with a hoe in an anvil to track crops broken."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
fish-caught: fish-caught:
title: "&7ToolStats: &8Fish Caught Token" title: "&7ToolStats: &8Fish Caught Token"
lore: lore:
- "&8Combine with a fishing rod in an anvil to track fish caught." - "&8Combine with a fishing rod in an anvil to track fish caught."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
sheep-sheared: sheep-sheared:
title: "&7ToolStats: &8Sheep Sheared Token" title: "&7ToolStats: &8Sheep Sheared Token"
lore: lore:
- "&8Combine with shears in an anvil to track sheep sheared." - "&8Combine with shears in an anvil to track sheep sheared."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
damage-taken: damage-taken:
title: "&7ToolStats: &8Damage Taken Token" title: "&7ToolStats: &8Damage Taken Token"
lore: lore:
- "&8Combine with an armor piece in an anvil to track damage taken." - "&8Combine with an armor piece in an anvil to track damage taken."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
damage-done: damage-done:
title: "&7ToolStats: &8Damage Done Token" title: "&7ToolStats: &8Damage Done Token"
lore: lore:
- "&8Combine with a melee or ranged weapon in an anvil to track damage done." - "&8Combine with a melee or ranged weapon in an anvil to track damage done."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
arrows-shot: arrows-shot:
title: "&7ToolStats: &8Arrows Shot Token" title: "&7ToolStats: &8Arrows Shot Token"
lore: lore:
- "&8Combine with a bow or crossbow in an anvil to track arrows shot." - "&8Combine with a bow or crossbow in an anvil to track arrows shot."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
flight-time: flight-time:
title: "&7ToolStats: &8Flight Time Token" title: "&7ToolStats: &8Flight Time Token"
lore: lore:
- "&8Combine with an elytra in an anvil to track flight time." - "&8Combine with an elytra in an anvil to track flight time."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
reset: reset:
title: "&7ToolStats: &8Reset Token" title: "&7ToolStats: &8Reset Token"
lore: lore:
- "&8Combine in an anvil with to reset ALL stats for this item. Tokens on this item stay." - "&8Combine in an anvil with to reset ALL stats for this item. Tokens on this item stay."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
remove: remove:
title: "&7ToolStats: &8Remove Token" title: "&7ToolStats: &8Remove Token"
lore: lore:
- "&8Combine in an anvil with to REMOVE ALL stats and tokens for this item." - "&8Combine in an anvil with to REMOVE ALL stats and tokens for this item."
- "&8Uses &7{levels} &8level."
levels: 1 levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
wither-kills:
title: "&7ToolStats: &8Wither Kills Token"
lore:
- "&8Combine with a melee or ranged weapon in an anvil to track wither kills."
- "&8Uses &7{levels} &8level."
levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
enderdragon-kills:
title: "&7ToolStats: &8Ender Dragon Kills Token"
lore:
- "&8Combine with a melee or ranged weapon in an anvil to track Ender Dragon kills."
- "&8Uses &7{levels} &8level."
levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
critical-strikes:
title: "&7ToolStats: &8Critical Strikes Token"
lore:
- "&8Combine with a melee or ranged weapon in an anvil to track critical strikes."
- "&8Uses &7{levels} &8level."
levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
trident-throws:
title: "&7ToolStats: &8Trident Throws Token"
lore:
- "&8Combine with a trident in an anvil to track times thrown."
- "&8Uses &7{levels} &8level."
levels: 1
material: PAPER
custom-model-data:
enabled: false
type: float
value: 1001
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 +194,9 @@ enabled:
armor: true armor: true
mace: true mace: true
fishing-rod: true fishing-rod: true
# Will show time the item is created spear: true
created-date: # Will show "Crafted on <date>"
crafted-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -90,8 +207,20 @@ enabled:
armor: true armor: true
mace: true mace: true
fishing-rod: true fishing-rod: true
spear: 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 +231,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 +241,32 @@ enabled:
bow: true bow: true
armor: true armor: true
fishing-rod: true fishing-rod: true
# Will show "Trade by <player>" spear: true
traded-tag: # Will show "Found on <date>"
looted-on:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fishing-rod: true
spear: 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
@@ -129,18 +282,21 @@ enabled:
trident: true trident: true
bow: true bow: true
mace: true mace: true
spear: true
player-kills: player-kills:
sword: true sword: true
axe: true axe: true
trident: true trident: true
bow: true bow: true
mace: true mace: true
spear: true
mob-kills: mob-kills:
sword: true sword: true
axe: true axe: true
trident: true trident: true
bow: true bow: true
mace: true mace: true
spear: true
blocks-mined: blocks-mined:
pickaxe: true pickaxe: true
shovel: true shovel: true
@@ -148,7 +304,7 @@ 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 pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -159,19 +315,39 @@ enabled:
armor: true armor: true
mace: true mace: true
fishing-rod: true fishing-rod: true
spear: true
# Will show "Spawned in on <date>"
spawned-in-on:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
mace: true
fishing-rod: true
spear: true
bosses-killed:
wither: true
enderdragon: true
fish-caught: true fish-caught: true
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
critical-strikes: true
trident-throws: 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}"
@@ -190,14 +366,20 @@ messages:
spawned-in: spawned-in:
spawned-by: "&7Spawned in by: &8{player}" spawned-by: "&7Spawned in by: &8{player}"
spawned-on: "&7Spawned on: &8{date}" spawned-on: "&7Spawned on: &8{date}"
bosses-killed:
wither: "&7Withers killed: &8{kills}"
enderdragon: "&7Ender Dragons killed: &8{kills}"
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{years}y {months}m {days}d {hours}h {minutes}m {seconds}s" 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}"
critical-strikes: "&7Critical strikes: &8{strikes}"
trident-throws: "&7Times thrown: &8{times}"
# 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:
ZOMBIE: "Zombie" ZOMBIE: "Zombie"
@@ -220,4 +402,20 @@ 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
# Allows you to change what worlds ToolStats works in.
# Mode is blacklist or whitelist.
world-limit:
enabled: false
mode: "blacklist"
worlds:
- world_1
- world_2
config-version: 15

View File

@@ -23,6 +23,18 @@ permissions:
toolstats.reset.confirm: toolstats.reset.confirm:
description: Allows the usage of /toolstats reset confirm. description: Allows the usage of /toolstats reset confirm.
default: true default: true
toolstats.purge:
description: Allows the usage of /toolstats purge.
default: true
toolstats.purge.confirm:
description: Allows the usage of /toolstats purge confirm.
default: true
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