Compare commits

...

111 Commits

Author SHA1 Message Date
hyperdefined
11d6a5bf91 add new stuff to readme 2026-04-06 14:27:57 -04:00
hyperdefined
df4fadb1f0 remove dupe comment 2026-04-06 12:20:09 -04:00
hyperdefined
c5deb0f7fd config updater 17 2026-04-06 12:19:11 -04:00
hyperdefined
27427c9ee6 RS multikill support
still experimental
2026-04-05 21:07:54 -04:00
hyperdefined
7cd5e8f0d0 make sure we check for canceled events 2026-04-05 20:22:30 -04:00
hyperdefined
6a13c7fef7 add logs stripped 2026-04-05 20:18:43 -04:00
hyperdefined
a785e331b3 git change 2026-04-05 01:30:33 -04:00
hyperdefined
16462d8d81 change api version 2026-04-05 01:07:15 -04:00
hyperdefined
d06cad1c5f Merge pull request #122 from hyperdefined/dependabot/gradle/gradle-wrapper-9.4.1
Bump gradle-wrapper from 9.4.0 to 9.4.1
2026-04-05 00:56:32 -04:00
hyperdefined
7360e4ac2f finally 2026-04-05 00:55:11 -04:00
hyperdefined
4513804c40 random things 2026-04-04 23:54:52 -04:00
hyperdefined
1d56d77bdb add wrapper 2026-04-04 23:51:23 -04:00
hyperdefined
906b13f91e maybe work now... 2026-04-04 23:50:41 -04:00
hyperdefined
c801ce18ec try this 2026-04-04 23:48:12 -04:00
dependabot[bot]
75692f0a05 Bump gradle-wrapper from 9.4.0 to 9.4.1
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.4.0 to 9.4.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.4.0...v9.4.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-05 03:47:31 +00:00
hyperdefined
018b7fee9b update dependabot 2026-04-04 23:46:06 -04:00
hyperdefined
3a2b18907e change workflow 2026-04-04 23:45:31 -04:00
hyperdefined
6217015862 convert to gradle 2026-04-04 23:44:23 -04:00
hyperdefined
46db1af915 add missing creating mode checks here 2026-04-03 19:04:40 -04:00
hyperdefined
772acf4332 mc 26 update 2026-04-03 19:01:24 -04:00
hyperdefined
1cd38294cc bump 2026-04-03 18:52:38 -04:00
hyperdefined
9e01726b84 experimental RS support
does not support multikill
2026-04-03 18:52:16 -04:00
hyperdefined
1176b57886 update java 2026-04-02 16:24:48 -04:00
hyperdefined
5c54182301 check for baby sheep here 2026-04-02 16:23:57 -04:00
hyperdefined
47846df0e4 Merge pull request #121 from hyperdefined/dependabot/maven/com.github.hyperdefined-hyperlib-1.0.10
Bump com.github.hyperdefined:hyperlib from 1.0.9 to 1.0.10
2026-04-02 07:25:17 -04:00
dependabot[bot]
b666323c4a Bump com.github.hyperdefined:hyperlib from 1.0.9 to 1.0.10
Bumps [com.github.hyperdefined:hyperlib](https://github.com/hyperdefined/hyperlib) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/hyperdefined/hyperlib/releases)
- [Commits](https://github.com/hyperdefined/hyperlib/compare/1.0.9...1.0.10)

---
updated-dependencies:
- dependency-name: com.github.hyperdefined:hyperlib
  dependency-version: 1.0.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-02 11:05:22 +00:00
hyperdefined
b484b772cb bump config 2026-03-06 21:04:52 -05:00
hyperdefined
d56eda6512 added more missing config values 2026-03-06 20:59:17 -05:00
hyperdefined
c7a784920d 2.0.2 2026-03-06 20:51:17 -05:00
hyperdefined
e029c1af3b fix #119 2026-03-06 20:50:32 -05:00
hyperdefined
a0282e67c1 improvements to main command
* fix logic with the edit command
* improved command suggestions
2026-03-06 17:03:29 -05:00
hyperdefined
bb33f4031a 2.0.1 2026-03-06 16:42:19 -05:00
hyperdefined
91331965f1 fix typo on fish-caught edit 2026-03-05 18:10:41 -05:00
hyperdefined
7e9a62a8f1 fix OpenInv compatibility
closes #116
2026-03-04 18:15:07 -05:00
hyperdefined
bf4e2af631 fix pom for paper plugin 2026-03-04 17:47:57 -05:00
hyperdefined
870b086a94 migrate into paper plugin 2026-03-04 17:45:57 -05:00
hyperdefined
58042980eb Merge pull request #117 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.15.0
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.14.1 to 3.15.0
2026-02-02 16:33:04 -05:00
dependabot[bot]
1157a4312f 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.1 to 3.15.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.1...maven-compiler-plugin-3.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-02 12:16:23 +00:00
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
hyperdefined
1e4e963fe1 remove debug 2025-04-07 11:00:55 -04:00
hyperdefined
298a8dd592 Update pom.xml 2025-04-07 10:57:27 -04:00
hyperdefined
49a3c03f94 typing with paws is hard 2025-04-07 10:56:51 -04:00
hyperdefined
ecd241ac52 fix #99 2025-04-07 10:56:25 -04:00
hyperdefined
5a1be37339 remove token if stat is disabled
this was missing prior
2025-04-07 10:56:13 -04:00
hyperdefined
a07782df5b added missing stat for reset command 2025-04-07 10:55:17 -04:00
hyperdefined
31123fdfd5 woops 2025-04-07 10:04:20 -04:00
hyperdefined
e310f1cb18 fix #98 2025-04-05 18:24:23 -04:00
hyperdefined
3d850ef00c Create FUNDING.yml 2025-03-31 19:39:35 -04:00
97 changed files with 5600 additions and 1941 deletions

0
.deepsource.toml Normal file → Executable file
View File

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

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

2
.github/dependabot.yml vendored Normal file → Executable file
View File

@@ -1,6 +1,6 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: maven - package-ecosystem: gradle
directory: "/" directory: "/"
schedule: schedule:
interval: daily interval: daily

24
.github/workflows/build.yml vendored Executable file
View File

@@ -0,0 +1,24 @@
name: Build with Gradle
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 25
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
- name: Build with Gradle
run: ./gradlew build

0
.github/workflows/hangar.yml vendored Normal file → Executable file
View File

View File

@@ -1,25 +0,0 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Build with Maven
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Build with Maven
run: mvn -B package --file pom.xml

0
.github/workflows/modrinth.yml vendored Normal file → Executable file
View File

17
.gitignore vendored Normal file → Executable file
View File

@@ -18,7 +18,6 @@ out/
*.ctxt *.ctxt
# Package Files # # Package Files #
*.jar
*.war *.war
*.nar *.nar
*.ear *.ear
@@ -95,19 +94,9 @@ $RECYCLE.BIN/
# Windows shortcuts # Windows shortcuts
*.lnk *.lnk
target/ # Gradle
.gradle/
pom.xml.tag build/
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml
# Common working directory # Common working directory
run/ run/

0
LICENSE Normal file → Executable file
View File

52
README.md Normal file → Executable file
View File

@@ -4,45 +4,53 @@
<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.
* Logs stripped.
The best part is, this data is stored on the item itself. The best part is, this data is stored on the item itself.
This plugin also has compatibility for:
* [RoseStacker](https://modrinth.com/plugin/rosestacker)
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).

46
build.gradle.kts Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file was generated by the Gradle 'init' task.
*/
plugins {
`java-library`
}
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.rosewooddev.io/repository/public/")
mavenCentral()
maven("https://jitpack.io")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:26.1.1.build.+")
compileOnly("dev.rosewood:rosestacker:1.5.39")
compileOnly("com.github.hyperdefined:hyperlib:1.0.14:all")
}
group = "lol.hyper"
version = "2.0.3"
description = "ToolStats"
java.sourceCompatibility = JavaVersion.VERSION_25
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
val pluginVersion = version.toString()
tasks.processResources {
filteringCharset = "UTF-8"
val props = mapOf("version" to pluginVersion)
inputs.properties(props)
filesMatching("paper-plugin.yml") {
expand(props)
}
}

5
gradle.properties Normal file
View File

@@ -0,0 +1,5 @@
# This file was generated by the Gradle 'init' task.
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
org.gradle.configuration-cache=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

248
gradlew vendored Executable file
View File

@@ -0,0 +1,248 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

93
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

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

124
pom.xml
View File

@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId>
<version>1.9.3</version>
<packaging>jar</packaging>
<name>ToolStats</name>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>auto-clean</id>
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>lol.hyper.toolstats.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>lol.hyper.githubreleaseapi</pattern>
<shadedPattern>lol.hyper.toolstats.updater</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>lol.hyper</groupId>
<artifactId>github-release-api</artifactId>
<version>1.0.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

5
settings.gradle.kts Normal file
View File

@@ -0,0 +1,5 @@
/*
* This file was generated by the Gradle 'init' task.
*/
rootProject.name = "toolstats"

View File

@@ -17,111 +17,30 @@
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.support.rosestacker.RoseStacker;
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 = 17;
* 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 +65,28 @@ 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;
public RoseStacker roseStacker = null;
@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 +94,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 +126,14 @@ 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); if (Bukkit.getPluginManager().isPluginEnabled("RoseStacker")) {
tokenKeys.add(cropsHarvested); logger.info("RoseStacker has been detected, adding support!");
tokenKeys.add(sheepSheared); roseStacker = new RoseStacker(this);
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 +153,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); registerCommand("toolstats", 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 +185,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

@@ -0,0 +1,37 @@
/*
* 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;
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
import io.papermc.paper.plugin.loader.PluginLoader;
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.repository.RemoteRepository;
public class ToolStatsLoader implements PluginLoader {
@Override
public void classloader(PluginClasspathBuilder classpathBuilder) {
MavenLibraryResolver resolver = new MavenLibraryResolver();
resolver.addRepository(new RemoteRepository.Builder("jitpack", "default", "https://jitpack.io").build());
resolver.addDependency(new Dependency(new DefaultArtifact("com.github.hyperdefined:hyperlib:jar:all:1.0.14"), null));
classpathBuilder.addLibrary(resolver);
}
}

340
src/main/java/lol/hyper/toolstats/events/AnvilEvent.java Normal file → Executable file
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;
@@ -40,7 +39,7 @@ public class AnvilEvent implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onAnvilEvent(PrepareAnvilEvent event) { public void onAnvilEvent(PrepareAnvilEvent event) {
// only listen if the token system is enabled // only listen if the token system is enabled
if (!toolStats.config.getBoolean("tokens.enabled")) { if (!toolStats.config.getBoolean("tokens.enabled")) {
@@ -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,9 +123,33 @@ 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;
}
if (tokenType.equalsIgnoreCase("logs-stripped")) {
addToken(event, tokenType, "logs-stripped", clone);
return;
}
} }
return; return;
} }
if (toolStats.itemChecker.canGlide(clone)) {
addToken(event, tokenType, "flight-time", clone);
return;
}
if (toolStats.itemChecker.isArmor(firstSlotMaterial)) { if (toolStats.itemChecker.isArmor(firstSlotMaterial)) {
addToken(event, tokenType, "damage-taken", clone); addToken(event, tokenType, "damage-taken", clone);
return; return;
@@ -143,6 +167,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 +202,14 @@ public class AnvilEvent implements Listener {
addToken(event, tokenType, "damage-done", clone); addToken(event, tokenType, "damage-done", clone);
return; return;
} }
return; if (tokenType.equalsIgnoreCase("wither-kills")) {
} addToken(event, tokenType, "wither-kills", clone);
if (firstSlotMaterial == Material.ELYTRA) { return;
addToken(event, tokenType, "flight-time", clone); }
if (tokenType.equalsIgnoreCase("enderdragon-kills")) {
addToken(event, tokenType, "enderdragon-kills", clone);
return;
}
return; return;
} }
if (firstSlotMaterial == Material.FISHING_ROD) { if (firstSlotMaterial == Material.FISHING_ROD) {
@@ -287,6 +331,51 @@ 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;
}
case "logs-stripped": {
if (toolStats.config.getBoolean("enabled.logs-stripped")) {
newItem.setItemMeta(toolStats.itemLore.updateLogsStripped(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 +397,127 @@ 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);
}
if (container.has(toolStats.toolStatsKeys.getLogsStripped())) {
Integer logsStripped = container.get(toolStats.toolStatsKeys.getLogsStripped(), PersistentDataType.INTEGER);
if (logsStripped == null) {
return;
}
meta = toolStats.itemLore.updateLogsStripped(finalItem, -logsStripped);
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,46 +18,49 @@
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 final List<Block> brokenContainers = new ArrayList<>();
public BlockBreak(ToolStats toolStats) { public BlockBreak(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBreak(BlockBreakEvent event) { public void onBreak(BlockBreakEvent event) {
if (event.isCancelled()) { Player player = event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return; return;
} }
Player player = event.getPlayer(); if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
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 +99,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,166 @@
/*
* 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, ignoreCancelled = true)
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<>();
}
// by request
if (newItem.getType() == Material.ELYTRA) {
if (!toolStats.config.getBoolean("enabled.elytra-tag")) {
return null;
}
Component creationDate = toolStats.itemLore.formatCreationTime(timeCreated, 4, newItem);
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, newItem);
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);
}
}
// 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

@@ -44,16 +44,19 @@ public class ChunkPopulate implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPopulate(ChunkPopulateEvent event) { public void onPopulate(ChunkPopulateEvent event) {
if (event.getChunk().getWorld().getEnvironment() != World.Environment.THE_END) { if (event.getChunk().getWorld().getEnvironment() != World.Environment.THE_END) {
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();
Bukkit.getRegionScheduler().runDelayed(toolStats, world, chunk.getX(), chunk.getZ(), scheduledTask -> { Bukkit.getRegionScheduler().runDelayed(toolStats, world, chunk.getX(), chunk.getZ(), _ -> {
for (Entity entity : chunk.getEntities()) { for (Entity entity : chunk.getEntities()) {
// if there is a new item frame // if there is a new item frame
if (!(entity instanceof ItemFrame itemFrame)) { if (!(entity instanceof ItemFrame itemFrame)) {
@@ -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);
} }

53
src/main/java/lol/hyper/toolstats/events/CraftItem.java Normal file → Executable file
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;
@@ -44,13 +44,13 @@ public class CraftItem implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onCraft(CraftItemEvent event) { public void onCraft(CraftItemEvent event) {
if (event.isCancelled()) { Player player = (Player) event.getWhoClicked();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return; return;
} }
Player player = (Player) event.getWhoClicked(); if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return; return;
} }
ItemStack craftedItem = event.getCurrentItem(); ItemStack craftedItem = event.getCurrentItem();
@@ -116,17 +116,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 +143,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,12 +17,13 @@
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;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCreativeEvent; import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -30,6 +31,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;
@@ -41,9 +43,12 @@ public class CreativeEvent implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
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 +65,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 +87,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;
@@ -45,13 +46,13 @@ public class EntityDamage implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onDamage(EntityDamageByEntityEvent event) { public void onDamage(EntityDamageByEntityEvent event) {
if (event.isCancelled()) { if (!(event.getEntity() instanceof LivingEntity mobBeingAttacked)) {
return; return;
} }
if (!(event.getEntity() instanceof LivingEntity mobBeingAttacked)) { if (!toolStats.configTools.checkWorld(mobBeingAttacked.getWorld().getName())) {
return; return;
} }
@@ -66,10 +67,27 @@ 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.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return;
}
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;
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return;
}
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,14 +96,25 @@ 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
if (playerBeingAttacked) { if (playerBeingAttacked) {
updateWeaponKills(playerAttackingInventory, "player"); updateWeaponKills(playerAttackingInventory, "player", null);
} else { } else {
// player kills a regular mob // player kills a regular mob
updateWeaponKills(playerAttackingInventory, "mob"); updateWeaponKills(playerAttackingInventory, "mob", mobBeingAttacked);
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilled(playerAttackingInventory, "wither", mobBeingAttacked);
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilled(playerAttackingInventory, "enderdragon", mobBeingAttacked);
}
} }
} }
@@ -96,7 +125,10 @@ 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) {
if (player.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return;
}
// update the trident's tracked damage // update the trident's tracked damage
updateTridentDamage(trident, finalDamage); updateTridentDamage(trident, finalDamage);
@@ -104,10 +136,16 @@ public class EntityDamage implements Listener {
if (modDied) { if (modDied) {
// if the trident killed a player, update the kills // if the trident killed a player, update the kills
if (playerBeingAttacked) { if (playerBeingAttacked) {
updateTridentKills(trident, "player"); updateTridentKills(trident, "player", null);
} else { } else {
// the trident killed a mob, update the kills // the trident killed a mob, update the kills
updateTridentKills(trident, "mob"); updateTridentKills(trident, "mob", mobBeingAttacked);
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilled(player.getInventory(), "wither", mobBeingAttacked);
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilled(player.getInventory(), "enderdragon", mobBeingAttacked);
}
} }
} }
@@ -122,6 +160,9 @@ public class EntityDamage implements Listener {
// a player shot the arrow // a player shot the arrow
if (source instanceof Player shootingPlayer) { if (source instanceof Player shootingPlayer) {
if (shootingPlayer.getGameMode() == GameMode.CREATIVE && !toolStats.config.getBoolean("allow-creative")) {
return;
}
// update the player's bow damage // update the player's bow damage
updateBowDamage(shootingPlayer.getInventory(), finalDamage); updateBowDamage(shootingPlayer.getInventory(), finalDamage);
@@ -129,10 +170,16 @@ public class EntityDamage implements Listener {
if (modDied) { if (modDied) {
if (playerBeingAttacked) { if (playerBeingAttacked) {
// player killed another player with an arrow // player killed another player with an arrow
updateBowKills(shootingPlayer.getInventory(), "player"); updateBowKills(shootingPlayer.getInventory(), "player", null);
} else { } else {
// player killed mob with an arrow // player killed mob with an arrow
updateBowKills(shootingPlayer.getInventory(), "mob"); updateBowKills(shootingPlayer.getInventory(), "mob", mobBeingAttacked);
if (mobAttackedType == EntityType.WITHER) {
updateBossesKilledByBow(shootingPlayer.getInventory(), "wither", mobBeingAttacked);
}
if (mobAttackedType == EntityType.ENDER_DRAGON) {
updateBossesKilledByBow(shootingPlayer.getInventory(), "enderdragon", mobBeingAttacked);
}
} }
} }
@@ -156,7 +203,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());
@@ -187,8 +234,7 @@ public class EntityDamage implements Listener {
boolean isMain = playerInventory.getItemInMainHand().getType() == Material.BOW || playerInventory.getItemInMainHand().getType() == Material.CROSSBOW; boolean isMain = playerInventory.getItemInMainHand().getType() == Material.BOW || playerInventory.getItemInMainHand().getType() == Material.CROSSBOW;
boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.BOW || playerInventory.getItemInOffHand().getType() == Material.CROSSBOW; boolean isOffHand = playerInventory.getItemInOffHand().getType() == Material.BOW || playerInventory.getItemInOffHand().getType() == Material.CROSSBOW;
ItemMeta newBowDamage = toolStats.itemLore.updateWeaponDamage(playerInventory.getItemInMainHand(), damage, false); ItemMeta newBowDamage = toolStats.itemLore.updateWeaponDamage(heldBow, damage, false);
//toolStats.logger.info(newBowDamage.toString());
// player is shooting another player // player is shooting another player
if (newBowDamage != null) { if (newBowDamage != null) {
@@ -202,7 +248,7 @@ public class EntityDamage implements Listener {
} }
} }
private void updateBowKills(PlayerInventory playerInventory, String type) { private void updateBowKills(PlayerInventory playerInventory, String type, LivingEntity entity) {
ItemStack heldBow = toolStats.itemChecker.getBow(playerInventory); ItemStack heldBow = toolStats.itemChecker.getBow(playerInventory);
if (heldBow == null) { if (heldBow == null) {
return; return;
@@ -213,6 +259,21 @@ public class EntityDamage implements Listener {
if (type.equalsIgnoreCase("mob")) { if (type.equalsIgnoreCase("mob")) {
// player is shooting a mob // player is shooting a mob
if (toolStats.roseStacker != null) {
toolStats.roseStacker.countMobs(entity, count -> {
ItemMeta newBow = toolStats.itemLore.updateMobKills(heldBow, count);
if (newBow != null) {
if (isMain && isOffHand) {
playerInventory.getItemInMainHand().setItemMeta(newBow);
} else if (isMain) {
playerInventory.getItemInMainHand().setItemMeta(newBow);
} else if (isOffHand) {
playerInventory.getItemInOffHand().setItemMeta(newBow);
}
}
});
return;
}
ItemMeta newBow = toolStats.itemLore.updateMobKills(heldBow, 1); ItemMeta newBow = toolStats.itemLore.updateMobKills(heldBow, 1);
if (newBow != null) { if (newBow != null) {
if (isMain && isOffHand) { if (isMain && isOffHand) {
@@ -239,17 +300,32 @@ public class EntityDamage implements Listener {
} }
} }
private void updateTridentKills(Trident trident, String type) { private void updateTridentKills(Trident trident, String type, LivingEntity entity) {
ItemStack newTrident = trident.getItemStack(); ItemStack newTrident = trident.getItemStack();
ItemMeta newKills;
if (type.equalsIgnoreCase("player")) { if (type.equalsIgnoreCase("player")) {
newKills = toolStats.itemLore.updatePlayerKills(trident.getItemStack(), 1); ItemMeta newTridentMeta = toolStats.itemLore.updatePlayerKills(trident.getItemStack(), 1);
} else { if (newTridentMeta != null) {
newKills = toolStats.itemLore.updateMobKills(trident.getItemStack(), 1); newTrident.setItemMeta(newTridentMeta);
trident.setItemStack(newTrident);
}
return;
} }
if (newKills != null) { if (type.equalsIgnoreCase("mob")) {
newTrident.setItemMeta(newKills); if (toolStats.roseStacker != null) {
trident.setItemStack(newTrident); toolStats.roseStacker.countMobs(entity, count -> {
ItemMeta newTridentMeta = toolStats.itemLore.updateMobKills(newTrident, count);
if (newTridentMeta != null) {
newTrident.setItemMeta(newTridentMeta);
trident.setItemStack(newTrident);
}
});
return;
}
ItemMeta newTridentMeta = toolStats.itemLore.updateMobKills(trident.getItemStack(), 1);
if (newTridentMeta != null) {
newTrident.setItemMeta(newTridentMeta);
trident.setItemStack(newTrident);
}
} }
} }
@@ -270,17 +346,128 @@ public class EntityDamage implements Listener {
} }
} }
private void updateWeaponKills(PlayerInventory playerInventory, String type) { private void updateWeaponKills(PlayerInventory playerInventory, String type, LivingEntity entity) {
ItemStack heldWeapon = playerInventory.getItemInMainHand(); ItemStack heldWeapon = playerInventory.getItemInMainHand();
ItemMeta newHeldWeaponMeta = null;
if (type.equalsIgnoreCase("player")) { if (type.equalsIgnoreCase("player")) {
newHeldWeaponMeta = toolStats.itemLore.updatePlayerKills(heldWeapon, 1); ItemMeta newHeldWeaponMeta = toolStats.itemLore.updatePlayerKills(heldWeapon, 1);
if (newHeldWeaponMeta != null) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
}
return;
} }
if (type.equalsIgnoreCase("mob")) { if (type.equalsIgnoreCase("mob")) {
newHeldWeaponMeta = toolStats.itemLore.updateMobKills(heldWeapon, 1); if (toolStats.roseStacker != null) {
toolStats.roseStacker.countMobs(entity, count -> {
ItemStack currentHeldWeapon = playerInventory.getItemInMainHand();
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateMobKills(currentHeldWeapon, count);
if (newHeldWeaponMeta != null) {
currentHeldWeapon.setItemMeta(newHeldWeaponMeta);
}
});
} else {
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateMobKills(heldWeapon, 1);
if (newHeldWeaponMeta != null) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
}
}
} }
}
private void updateBossesKilled(PlayerInventory playerInventory, String boss, LivingEntity entity) {
ItemStack heldWeapon = playerInventory.getItemInMainHand();
int count = 1;
if (toolStats.roseStacker != null) {
//count = toolStats.roseStacker.countMobs(entity);
}
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateBossesKilled(heldWeapon, count, boss);
if (newHeldWeaponMeta != null) { if (newHeldWeaponMeta != null) {
playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta); playerInventory.getItemInMainHand().setItemMeta(newHeldWeaponMeta);
} }
} }
private void updateBossesKilledByBow(PlayerInventory playerInventory, String boss, LivingEntity entity) {
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;
if (toolStats.roseStacker != null) {
toolStats.roseStacker.countMobs(entity, count -> {
ItemMeta newHeldWeaponMeta = toolStats.itemLore.updateBossesKilled(heldBow, count, 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);
}
}
});
return;
}
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;
@@ -41,12 +43,15 @@ public class EntityDeath implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onDeath(EntityDeathEvent event) { public void onDeath(EntityDeathEvent event) {
LivingEntity livingEntity = event.getEntity(); LivingEntity livingEntity = event.getEntity();
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,133 +18,82 @@
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 final Map<Inventory, Location> generatedInventory = new HashMap<>();
public final List<Location> droppedLootLocations = new ArrayList<>();
public GenerateLoot(ToolStats toolStats) { public GenerateLoot(ToolStats toolStats) {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onGenerateLoot(LootGenerateEvent event) { public void onGenerateLoot(LootGenerateEvent event) {
InventoryHolder inventoryHolder = event.getInventoryHolder(); InventoryHolder inventoryHolder = event.getInventoryHolder();
if (inventoryHolder == null) { if (inventoryHolder == null) {
return; return;
} }
Location lootLocation = event.getLootContext().getLocation(); Location lootLocation = event.getLootContext().getLocation();
if (!toolStats.configTools.checkWorld(lootLocation.getWorld().getName())) {
if (inventoryHolder instanceof Chest) { return;
Block openedChest = null; }
// look at the current list of opened chest and get the distance Chunk lootChunk = lootLocation.getChunk();
// between the LootContext location and chest location Bukkit.getRegionScheduler().runDelayed(toolStats, lootLocation.getWorld(), lootChunk.getX(), lootChunk.getZ(), scheduledTask -> {
// if the distance is less than 1, it's the same chest if (inventoryHolder instanceof Container) {
for (Block chest : toolStats.playerInteract.openedChests.keySet()) { Block openedChest = null;
Location chestLocation = chest.getLocation(); Location chestLocation = null;
if (chest.getWorld() == lootLocation.getWorld()) { // look at the current list of opened chest and get the distance
double distance = lootLocation.distance(chestLocation); // between the LootContext location and chest location
if (distance <= 1.0) { // if the distance is less than 1, it's the same chest
openedChest = chest; for (Block chest : toolStats.playerInteract.openedChests) {
chestLocation = chest.getLocation();
if (chest.getWorld() == lootLocation.getWorld()) {
double distance = lootLocation.distance(chestLocation);
if (distance <= 1.0) {
openedChest = chest;
}
} }
} }
} for (Block brokenChest : toolStats.blockBreak.brokenContainers) {
// ignore if the chest is not in the same location Location brokenChestLocation = brokenChest.getLocation();
if (openedChest == null) { if (brokenChestLocation.getWorld() == lootLocation.getWorld()) {
return; double distance = lootLocation.distance(brokenChestLocation);
} if (distance <= 1.0) {
droppedLootLocations.add(brokenChestLocation);
Player player = toolStats.playerInteract.openedChests.get(openedChest); Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask2 -> droppedLootLocations.remove(brokenChestLocation), 20);
setLoot(event.getLoot(), player); }
} }
if (inventoryHolder instanceof StorageMinecart mineCart) { }
if (toolStats.playerInteract.openedMineCarts.containsKey(mineCart)) { // ignore if the chest is not in the same location
Player player = toolStats.playerInteract.openedMineCarts.get(mineCart); if (openedChest != null) {
setLoot(event.getLoot(), player); generatedInventory.put(inventoryHolder.getInventory(), chestLocation);
}
}
}
/**
* 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);
} }
} }
} if (inventoryHolder instanceof StorageMinecart mineCart) {
if (toolStats.playerInteract.openedMineCarts.contains(mineCart)) {
Inventory mineCartInventory = mineCart.getInventory();
generatedInventory.put(mineCartInventory, mineCart.getLocation());
}
}
}, 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(ignoreCancelled = true)
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) {
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,14 +17,16 @@
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.block.DoubleChest;
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;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.BlockInventoryHolder;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
@@ -40,19 +42,20 @@ public class InventoryOpen implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler @EventHandler(ignoreCancelled = true)
public void onOpen(InventoryOpenEvent event) { public void onOpen(InventoryOpenEvent event) {
if (event.isCancelled()) {
return;
}
Inventory inventory = event.getInventory(); Inventory inventory = event.getInventory();
// only check these InventoryHolder holder = inventory.getHolder();
if (inventory.getType() != InventoryType.CHEST || inventory.getType() != InventoryType.BARREL || inventory.getType() != InventoryType.SHULKER_BOX || inventory.getType() != InventoryType.ENDER_CHEST) { boolean isBlockInventory = holder instanceof BlockInventoryHolder || holder instanceof DoubleChest;
if (!(inventory.getHolder() instanceof BlockInventoryHolder)) {
// ignore not real inventories
return; return;
} }
Player player = (Player) event.getPlayer(); Player player = (Player) event.getPlayer();
if (!toolStats.configTools.checkWorld(player.getWorld().getName())) {
return;
}
for (ItemStack itemStack : inventory) { for (ItemStack itemStack : inventory) {
if (itemStack == null) { if (itemStack == null) {
continue; continue;
@@ -69,13 +72,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 +86,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;
@@ -46,14 +47,14 @@ public class PickupItem implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPickup(EntityPickupItemEvent event) { public void onPickup(EntityPickupItemEvent event) {
if (event.isCancelled()) {
return;
}
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if (entity instanceof Player 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 +67,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 +91,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 +105,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(ignoreCancelled = true)
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;
@@ -45,18 +46,18 @@ public class PlayerFish implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onFish(PlayerFishEvent event) { public void onFish(PlayerFishEvent event) {
if (event.isCancelled()) {
return;
}
// only listen to when a player catches a fish // only listen to when a player catches a fish
if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) { if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) {
return; return;
} }
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 +89,7 @@ public class PlayerFish implements Listener {
ItemStack caughtItem = ((Item) event.getCaught()).getItemStack(); ItemStack caughtItem = ((Item) event.getCaught()).getItemStack();
Item caughtItemEntity = (Item) event.getCaught(); Item caughtItemEntity = (Item) event.getCaught();
if (toolStats.itemChecker.isValidItem(caughtItem.getType())) { if (toolStats.itemChecker.isValidItem(caughtItem.getType())) {
ItemStack newItem = addNewLore(caughtItem, player); ItemStack newItem = addFishedOrigin(caughtItem, player);
if (newItem != null) { if (newItem != null) {
caughtItemEntity.setItemStack(newItem); caughtItemEntity.setItemStack(newItem);
} }
@@ -102,36 +103,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,22 +31,30 @@ 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 org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.HashMap; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import java.util.Locale;
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;
} }
@EventHandler @EventHandler(ignoreCancelled = true)
public void onInteract(PlayerInteractEvent event) { public void onInteract(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return; return;
@@ -58,28 +66,60 @@ 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) {
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedChests.remove(block), 20); Inventory holderInventory = holder.getInventory();
openedChests.add(block);
chestInventories.add(holderInventory);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, _ -> openedChests.remove(block), 20);
}
// player right-clicked a log
String blockType = block.getType().toString().toLowerCase(Locale.ROOT);
if (blockType.endsWith("_log") && !blockType.contains("stripped")) {
PlayerInventory playerInventory = player.getInventory();
ItemStack axe = toolStats.itemChecker.getAxe(playerInventory);
// not holding an axe
if (axe == null) {
return;
}
ItemMeta newAxe = toolStats.itemLore.updateLogsStripped(axe, 1);
if (newAxe != null) {
boolean isMain = playerInventory.getItemInMainHand().getType().toString().endsWith("_AXE");
boolean isOffHand = playerInventory.getItemInOffHand().getType().toString().endsWith("_AXE");
if (isMain && isOffHand) {
playerInventory.getItemInMainHand().setItemMeta(newAxe);
} else if (isMain) {
playerInventory.getItemInMainHand().setItemMeta(newAxe);
} else if (isOffHand) {
playerInventory.getItemInOffHand().setItemMeta(newAxe);
}
}
} }
} }
@EventHandler @EventHandler(ignoreCancelled = true)
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();
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, scheduledTask -> openedMineCarts.remove(storageMinecart), 20); mineCartChestInventories.add(mineCartInventory);
openedMineCarts.add(storageMinecart);
Bukkit.getGlobalRegionScheduler().runDelayed(toolStats, _ -> 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;
@@ -40,9 +39,12 @@ public class PlayerMove implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onCraft(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) {
long duration = (System.currentTimeMillis() - playerStartFlight.get(player)); // skip missing slots
ItemMeta newItem = toolStats.itemLore.updateFlightTime(chest, duration); if (armorPiece == null) {
if (newItem != null) { continue;
inventory.getChestplate().setItemMeta(newItem); }
// if the armor piece can glide, track the flight time
if (toolStats.itemChecker.canGlide(armorPiece)) {
long duration = (System.currentTimeMillis() - playerStartFlight.get(player));
ItemMeta newMeta = toolStats.itemLore.updateFlightTime(armorPiece, duration);
if (newMeta != null) {
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,58 @@
/*
* 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

@@ -39,13 +39,16 @@ public class SheepShear implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onShear(PlayerInteractEntityEvent event) { public void onShear(PlayerInteractEntityEvent event) {
if (event.isCancelled()) { if (event.isCancelled()) {
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();
@@ -59,6 +62,11 @@ public class SheepShear implements Listener {
return; return;
} }
// make sure they are not a baby
if (!sheep.isAdult()) {
return;
}
// make sure the sheep is not sheared // make sure the sheep is not sheared
if (sheep.isSheared()) { if (sheep.isSheared()) {
return; return;

7
src/main/java/lol/hyper/toolstats/events/ShootBow.java Normal file → Executable file
View File

@@ -38,7 +38,7 @@ public class ShootBow implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onShoot(EntityShootBowEvent event) { public void onShoot(EntityShootBowEvent event) {
Entity shooter = event.getEntity(); Entity shooter = event.getEntity();
// only listen for players // only listen for players
@@ -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;
@@ -46,15 +47,18 @@ public class VillagerTrade implements Listener {
this.toolStats = toolStats; this.toolStats = toolStats;
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onTrade(InventoryClickEvent event) { public void onTrade(InventoryClickEvent event) {
if (event.isCancelled() || event.getCurrentItem() == null) { if (event.getCurrentItem() == null) {
return; return;
} }
Inventory inventory = event.getClickedInventory(); Inventory inventory = event.getClickedInventory();
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

@@ -0,0 +1,79 @@
/*
* 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.support.rosestacker;
import dev.rosewood.rosestacker.api.RoseStackerAPI;
import dev.rosewood.rosestacker.stack.StackedEntity;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import java.util.function.Consumer;
public class RoseStacker {
private final ToolStats toolStats;
private final RoseStackerAPI rsAPI;
public RoseStacker(ToolStats toolStats) {
this.toolStats = toolStats;
this.rsAPI = RoseStackerAPI.getInstance();
}
public void countMobs(LivingEntity entity, Consumer<Integer> callback) {
if (!rsAPI.isEntityStacked(entity)) {
// if the entity is not stacked, ignore
callback.accept(1);
return;
}
StackedEntity stackedEntity = rsAPI.getStackedEntity(entity);
if (stackedEntity == null) {
callback.accept(1);
return;
}
int before = stackedEntity.getStackSize();
boolean killAll = stackedEntity.getStackSettings().shouldKillEntireStackOnDeath();
// if we kill the entire stack, add the entire stack to the count
if (killAll) {
callback.accept(before);
return;
}
Location stackedLocation = stackedEntity.getLocation();
Chunk stackedChunk = stackedEntity.getLocation().getChunk();
// check the stack size after a tick to see the difference
Bukkit.getRegionScheduler().runDelayed(toolStats, stackedLocation.getWorld(), stackedChunk.getX(), stackedChunk.getZ(), _ -> {
int after = stackedEntity.getStackSize();
int difference = before - after;
// if the diff goes negative, we killed more than the stack
// we killed the entire stack, so return the size
if (difference <= 0) {
difference = before;
}
toolStats.logger.info("before: {}", before);
toolStats.logger.info("after: {}", after);
toolStats.logger.info("difference: {}", difference);
callback.accept(difference);
}, 1);
}
}

6
src/main/java/lol/hyper/toolstats/tools/HashMaker.java Normal file → Executable file
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();
} }
} }

123
src/main/java/lol/hyper/toolstats/tools/ItemChecker.java Normal file → Executable file
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;
@@ -27,10 +28,7 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class ItemChecker { public class ItemChecker {
@@ -54,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);
} }
@@ -72,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);
@@ -119,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.
* *
@@ -128,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;
} }
@@ -154,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];
} }
@@ -183,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;
@@ -291,6 +306,35 @@ public class ItemChecker {
return null; return null;
} }
/**
* Get the player's axe.
*
* @param inventory Their inventory.
* @return Their axe, either main or offhand.
*/
public @Nullable ItemStack getAxe(PlayerInventory inventory) {
ItemStack main = inventory.getItemInMainHand();
ItemStack offHand = inventory.getItemInOffHand();
boolean isMain = main.getType().toString().endsWith("_AXE");
boolean isOffHand = offHand.getType().toString().endsWith("_AXE");
// if the player is holding an axe in their main hand, use that one
// if the axe is in their offhand instead, use that one after checking main hand
// Minecraft prioritizes main hand if the player holds in both hands
if (isMain && isOffHand) {
return main;
}
if (isMain) {
return main;
}
if (isOffHand) {
return offHand;
}
return null;
}
/** /**
* Checks the keys of the item and returns the tokens we should add. * Checks the keys of the item and returns the tokens we should add.
* If the server swaps token systems this should allow compatability. * If the server swaps token systems this should allow compatability.
@@ -306,36 +350,51 @@ 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 (container.has(toolStats.toolStatsKeys.getLogsStripped())) {
tokens.add("logs-stripped");
}
if (tokens.isEmpty()) { if (tokens.isEmpty()) {
return null; return null;
} }
@@ -343,6 +402,26 @@ public class ItemChecker {
return String.join(",", tokens); return String.join(",", tokens);
} }
/**
* Remove a given token from a list of tokens.
*
* @param appliedTokens The tokens on the item.
* @param toRemove The token to remove.
* @return The list of tokens.
*/
public List<String> removeToken(String appliedTokens, String toRemove) {
// remove the tokens if they exist
List<String> tokenList = new ArrayList<>(Arrays.asList(appliedTokens.split(",")));
tokenList.remove(toRemove);
if (tokenList.isEmpty()) {
return Collections.emptyList();
} else {
return tokenList;
}
}
/** /**
* Check to see if a given container has our keys for stats. * Check to see if a given container has our keys for stats.
* *
@@ -352,6 +431,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)));
} }
} }

1277
src/main/java/lol/hyper/toolstats/tools/ItemLore.java Normal file → Executable file

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)
*/ */
@@ -155,7 +161,7 @@ public class NumberFormat {
long totalSeconds = time / 1000; long totalSeconds = time / 1000;
Map<String, String> timeUnits = new HashMap<>(); Map<String, String> timeUnits = new HashMap<>();
long years = totalSeconds / (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE); long years = totalSeconds / (DAYS_PER_YEAR * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
if (years > 0) { if (years > 0) {
timeUnits.put("years", Long.toString(years)); timeUnits.put("years", Long.toString(years));
@@ -190,7 +196,16 @@ public class NumberFormat {
if (seconds > 0 || timeUnits.isEmpty()) { // Always include seconds if everything else is zero if (seconds > 0 || timeUnits.isEmpty()) { // Always include seconds if everything else is zero
timeUnits.put("seconds", Long.toString(seconds)); timeUnits.put("seconds", Long.toString(seconds));
} }
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,265 @@
/*
* 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);
NamespacedKey logsStrippedKey = new NamespacedKey(toolStats, "logs-stripped-token");
ShapedRecipe logsStrippedRecipe = new ShapedRecipe(logsStrippedKey, createToken("logs-stripped"));
logsStrippedRecipe.shape(" P ", "PSP", " P ");
logsStrippedRecipe.setIngredient('P', Material.PAPER);
logsStrippedRecipe.setIngredient('S', Material.WOODEN_AXE);
recipes.add(logsStrippedRecipe);
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");
tokenTypes.add("logs-stripped");
}
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,189 @@
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;
private NamespacedKey logsStripped;
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");
logsStripped = new NamespacedKey(toolStats, "logs-stripped");
// 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);
tokenKeys.add(logsStripped);
}
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;
}
public NamespacedKey getLogsStripped() {
return logsStripped;
}
/**
* 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,10 +45,15 @@ 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
if (material == Material.BOW || material == Material.CROSSBOW || material == Material.SHEARS || material == Material.TRIDENT || material == Material.FISHING_ROD) { if (material == Material.BOW || material == Material.CROSSBOW || material == Material.SHEARS || material == Material.TRIDENT || material == Material.FISHING_ROD || material == Material.SHIELD) {
switch (material) { switch (material) {
case CROSSBOW: case CROSSBOW:
case BOW: { case BOW: {
@@ -71,11 +72,14 @@ public class ConfigTools {
itemType = "fishing-rod"; itemType = "fishing-rod";
break; break;
} }
case SHIELD: {
itemType = "shield";
break;
}
} }
} 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 +91,55 @@ 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 "shield" -> toolStats.config.getBoolean("enabled." + configName + ".shield");
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 +151,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 +168,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 +182,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 +217,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 +236,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,19 @@ 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) { case 15 -> new Version16(toolStats).update(); // 15 to 16
Version8 version8 = new Version8(toolStats); case 16 -> new Version17(toolStats).update(); // 16 to 17
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,146 @@
/*
* 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;
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

@@ -0,0 +1,77 @@
/*
* 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 Version16 {
private final ToolStats toolStats;
/**
* Used for updating from version 15 to 16.
*
* @param toolStats ToolStats instance.
*/
public Version16(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-15.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config-15.yml!", exception);
}
// we make this super verbose so that admins can see what's being added
toolStats.logger.info("Updating config.yml to version 16.");
toolStats.config.set("config-version", 16);
toolStats.logger.info("Adding enabled.crafted-on.shield to config.yml.");
toolStats.config.set("enabled.crafted-on.shield", true);
toolStats.logger.info("Adding enabled.crafted-by.shield to config.yml.");
toolStats.config.set("enabled.crafted-by.shield", true);
toolStats.logger.info("Adding enabled.traded-on.shield to config.yml.");
toolStats.config.set("enabled.traded-on.shield", true);
toolStats.logger.info("Adding enabled.traded-by.shield to config.yml.");
toolStats.config.set("enabled.traded-by.shield", true);
toolStats.logger.info("Adding enabled.looted-on.shield to config.yml.");
toolStats.config.set("enabled.looted-on.shield", true);
toolStats.logger.info("Adding enabled.looted-by.shield to config.yml.");
toolStats.config.set("enabled.looted-by.shield", true);
// 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 16. A copy of version 6 has been saved as config-15.yml");
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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;
import java.util.List;
public class Version17 {
private final ToolStats toolStats;
/**
* Used for updating from version 16 to 17.
*
* @param toolStats ToolStats instance.
*/
public Version17(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-16.yml");
} catch (IOException exception) {
toolStats.logger.error("Unable to save config-16.yml!", exception);
}
toolStats.logger.info("Updating config.yml to version 17.");
toolStats.config.set("config-version", 17);
toolStats.logger.info("Adding new token to config: logs-stripped");
toolStats.config.set("tokens.data.logs-stripped.title", "&7ToolStats: &8Logs Stripped Token");
toolStats.config.set("tokens.data.logs-stripped.lore", List.of(
"&8Combine with an axe in an anvil to track logs stripped.",
"&8Uses &7{levels} &8level."
));
toolStats.config.set("tokens.data.logs-stripped.levels", 1);
toolStats.config.set("tokens.data.logs-stripped.material", "PAPER");
toolStats.config.set("tokens.data.logs-stripped.custom-model-data.enabled", false);
toolStats.config.set("tokens.data.logs-stripped.custom-model-data.type", "float");
toolStats.config.set("tokens.data.logs-stripped.custom-model-data.value", 1001);
toolStats.logger.info("Adding enabled.logs-stripped");
toolStats.config.set("enabled.logs-stripped", true);
toolStats.logger.info("Adding messages.logs-stripped");
toolStats.config.set("messages.logs-stripped", "&7Logs stripped: &8{logs}");
// 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 17. A copy of version 16 has been saved as config-16.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);

245
src/main/resources/config.yml Normal file → Executable file
View File

@@ -8,66 +8,193 @@ 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
logs-stripped:
title: "&7ToolStats: &8Logs Stripped Token"
lore:
- "&8Combine with an axe in an anvil to track logs stripped."
- "&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 +205,10 @@ 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: shield: true
# Will show "Crafted on <date>"
crafted-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -90,8 +219,21 @@ enabled:
armor: true armor: true
mace: true mace: true
fishing-rod: true fishing-rod: true
spear: true
shield: 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 +244,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 +254,10 @@ enabled:
bow: true bow: true
armor: true armor: true
fishing-rod: true fishing-rod: true
# Will show "Trade by <player>" spear: true
traded-tag: shield: true
# Will show "Found on <date>"
looted-on:
pickaxe: true pickaxe: true
sword: true sword: true
shovel: true shovel: true
@@ -123,24 +267,53 @@ enabled:
bow: true bow: true
armor: true armor: true
fishing-rod: true fishing-rod: true
spear: true
shield: 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
shield: true
# Will show "Traded on <date>"
traded-on:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fishing-rod: true
shield: true
damage-done: damage-done:
sword: true sword: true
axe: true axe: true
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 +321,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 +332,40 @@ 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
logs-stripped: 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 +384,21 @@ 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}"
logs-stripped: "&7Logs stripped: &8{logs}"
# 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 +421,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: 17

View File

@@ -0,0 +1,38 @@
name: ToolStats
version: ${version}
main: lol.hyper.toolstats.ToolStats
api-version: '26.1.1'
folia-supported: true
author: hyperdefined
description: Track various tool stats!
website: https://github.com/hyperdefined/ToolStats
loader: lol.hyper.toolstats.ToolStatsLoader
permissions:
toolstats.command:
description: Allows the usage of /toolstats.
default: true
children:
toolstats.reset: true
toolstats.reset.confirm: true
toolstats.purge: true
toolstats.purge.confirm: true
toolstats.reload:
description: Allows the usage of /toolstats reload.
default: op
toolstats.givetokens:
description: Allows the usage of /toolstats givetoken.
default: op
toolstats.edit:
description: Allows the usage of /toolstats edit.
default: op
toolstats.remove:
description: Allows the usage of /toolstats remove.
default: op
dependencies:
server:
RoseStacker:
load: BEFORE
required: false

View File

@@ -1,28 +0,0 @@
name: ToolStats
version: '${project.version}'
main: lol.hyper.toolstats.ToolStats
api-version: 1.21
author: hyperdefined
description: Track various tool stats!
website: https://github.com/hyperdefined/ToolStats
folia-supported: true
commands:
toolstats:
usage: /toolstats
permission: toolstats.command
permissions:
toolstats.command:
description: Allows the usage of /toolstats.
default: true
toolstats.reload:
description: Allows the usage of /toolstats reload.
default: op
toolstats.reset:
description: Allows the usage of /toolstats reset.
default: true
toolstats.reset.confirm:
description: Allows the usage of /toolstats reset confirm.
default: true
toolstats.givetokens:
description: Allows the usage of /toolstats givetoken.
default: op