Compare commits

..

218 Commits
1.3 ... 1.8.1

Author SHA1 Message Date
hyperdefined
a43155b0c5 Fix armor damage + arrows on reset command 2024-09-08 22:57:41 -04:00
hyperdefined
e327d132e2 Update pom.xml 2024-09-08 22:52:55 -04:00
hyperdefined
f09f2d3703 Fix armor damage breaking (#70) 2024-09-08 22:51:49 -04:00
hyperdefined
e9782c2985 bump to 1.8 instead 2024-09-07 15:50:27 -04:00
hyperdefined
b596310bfe redo lore replacement
Instead of partially matching the old lore, build the old lore and match it instead.
2024-09-06 17:47:07 -04:00
hyperdefined
6d1f0fe561 update config from 6 to 7 2024-08-29 00:16:22 -04:00
hyperdefined
fb0d179d37 add flight time (#62) 2024-08-29 00:10:01 -04:00
hyperdefined
e8ab578eef Update pom.xml 2024-08-28 23:23:20 -04:00
hyperdefined
57be2371e1 Merge pull request #67 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.3.4
Bump net.kyori:adventure-platform-bukkit from 4.3.3 to 4.3.4
2024-08-28 23:20:43 -04:00
hyperdefined
f3732a4eea Merge pull request #69 from hyperdefined/dependabot/maven/org.bstats-bstats-bukkit-3.0.3
Bump org.bstats:bstats-bukkit from 3.0.2 to 3.0.3
2024-08-28 23:20:33 -04:00
hyperdefined
7e13159056 support hex colors in lore (#68) 2024-08-28 23:20:16 -04:00
dependabot[bot]
7cdb8d55b5 Bump org.bstats:bstats-bukkit from 3.0.2 to 3.0.3
Bumps [org.bstats:bstats-bukkit](https://github.com/Bastian/bStats-Metrics) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/Bastian/bStats-Metrics/releases)
- [Commits](https://github.com/Bastian/bStats-Metrics/compare/v3.0.2...v3.0.3)

---
updated-dependencies:
- dependency-name: org.bstats:bstats-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-19 11:27:39 +00:00
dependabot[bot]
368e59b1e1 Bump net.kyori:adventure-platform-bukkit from 4.3.3 to 4.3.4
Bumps [net.kyori:adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.3.3 to 4.3.4.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.3...v4.3.4)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-07 11:04:11 +00:00
hyperdefined
9412dc02d7 Update README.md 2024-07-24 21:32:03 -04:00
hyperdefined
0765c49622 Update pom.xml 2024-07-24 21:29:12 -04:00
hyperdefined
91959c223e new damage cause, fix #64 #65 2024-07-19 20:12:50 -04:00
hyperdefined
a53cebc589 Merge pull request #63 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-clean-plugin-3.4.0
Bump org.apache.maven.plugins:maven-clean-plugin from 3.3.2 to 3.4.0
2024-06-24 21:45:02 -04:00
dependabot[bot]
7f7c1d4656 Bump org.apache.maven.plugins:maven-clean-plugin from 3.3.2 to 3.4.0
Bumps [org.apache.maven.plugins:maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.3.2 to 3.4.0.
- [Release notes](https://github.com/apache/maven-clean-plugin/releases)
- [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.3.2...maven-clean-plugin-3.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-20 11:04:51 +00:00
hyperdefined
1e99fa5076 Merge pull request #60 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.6.0
Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.3 to 3.6.0
2024-06-18 12:06:21 -04:00
hyperdefined
d50ee82a98 Merge pull request #61 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.3.3
Bump net.kyori:adventure-platform-bukkit from 4.3.2 to 4.3.3
2024-06-18 12:04:11 -04:00
dependabot[bot]
2a2c9a7376 Bump net.kyori:adventure-platform-bukkit from 4.3.2 to 4.3.3
Bumps [net.kyori:adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.2...v4.3.3)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 11:19:58 +00:00
dependabot[bot]
813648e330 Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.3 to 3.6.0
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.3...maven-shade-plugin-3.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-31 11:33:03 +00:00
hyperdefined
330001e6de Update README.md 2024-05-25 15:53:34 -04:00
hyperdefined
75b1a95cb5 Merge pull request #56 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.5.3
Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.2 to 3.5.3
2024-05-25 15:52:46 -04:00
hyperdefined
ca37021e5a Merge pull request #57 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.17.0
Bump net.kyori:adventure-text-minimessage from 4.16.0 to 4.17.0
2024-05-25 15:52:39 -04:00
hyperdefined
f72ea3dbfa Update pom.xml 2024-05-25 15:41:49 -04:00
hyperdefined
03077d5e2f possibly fix #59 2024-05-25 15:41:16 -04:00
hyperdefined
608c870667 possibly fix #44 2024-05-25 15:38:44 -04:00
hyperdefined
ea27e4f4ab remove color codes when comparing 2024-05-25 15:37:52 -04:00
dependabot[bot]
8a7c6c720a Bump net.kyori:adventure-text-minimessage from 4.16.0 to 4.17.0
Bumps [net.kyori:adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.16.0 to 4.17.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.16.0...v4.17.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-08 11:41:03 +00:00
dependabot[bot]
12e2758ffd Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.2 to 3.5.3
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.2...maven-shade-plugin-3.5.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-24 11:09:18 +00:00
hyperdefined
5939b8f944 Merge pull request #54 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.13.0
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.12.1 to 3.13.0
2024-03-26 18:12:54 -04:00
hyperdefined
021d67e505 Merge pull request #55 from hyperdefined/dependabot/maven/space.arim.morepaperlib-morepaperlib-0.4.4
Bump space.arim.morepaperlib:morepaperlib from 0.4.3 to 0.4.4
2024-03-26 18:10:25 -04:00
dependabot[bot]
c0ee457c4d Bump space.arim.morepaperlib:morepaperlib from 0.4.3 to 0.4.4
Bumps space.arim.morepaperlib:morepaperlib from 0.4.3 to 0.4.4.

---
updated-dependencies:
- dependency-name: space.arim.morepaperlib:morepaperlib
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-25 11:28:14 +00:00
dependabot[bot]
4f4e4a961a 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.12.1 to 3.13.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.1...maven-compiler-plugin-3.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-19 11:15:00 +00:00
hyperdefined
3412094f93 Merge pull request #51 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.16.0
Bump net.kyori:adventure-text-minimessage from 4.15.0 to 4.16.0
2024-02-23 17:29:35 -05:00
hyperdefined
cdc46a1f5f Merge pull request #52 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.5.2 2024-02-22 09:33:56 -05:00
dependabot[bot]
d4c7770352 Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.1 to 3.5.2
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.1...maven-shade-plugin-3.5.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-21 11:22:24 +00:00
dependabot[bot]
85db07877d Bump net.kyori:adventure-text-minimessage from 4.15.0 to 4.16.0
Bumps [net.kyori:adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.15.0 to 4.16.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.15.0...v4.16.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-20 11:46:47 +00:00
hyperdefined
1e37fcd3cb Merge pull request #49 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.3.2
Bump net.kyori:adventure-platform-bukkit from 4.3.1 to 4.3.2
2023-12-26 12:06:21 -05:00
hyperdefined
10f9b9404e Merge pull request #50 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.12.1
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.12.0 to 3.12.1
2023-12-26 12:05:43 -05:00
dependabot[bot]
c350536ab6 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.12.0 to 3.12.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.0...maven-compiler-plugin-3.12.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-25 11:07:40 +00:00
dependabot[bot]
e12a0a80f5 Bump net.kyori:adventure-platform-bukkit from 4.3.1 to 4.3.2
Bumps [net.kyori:adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.3.1 to 4.3.2.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.1...v4.3.2)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-22 11:57:41 +00:00
hyperdefined
44a3fc7d63 Merge pull request #46 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.15.0
Bump net.kyori:adventure-text-minimessage from 4.14.0 to 4.15.0
2023-12-19 17:21:21 -05:00
hyperdefined
6a5bb994cc Merge pull request #48 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.12.0
Bump org.apache.maven.plugins:maven-compiler-plugin from 3.11.0 to 3.12.0
2023-12-19 17:18:53 -05:00
dependabot[bot]
1c52664935 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.11.0 to 3.12.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-19 12:01:49 +00:00
dependabot[bot]
4d18020065 Bump net.kyori:adventure-text-minimessage from 4.14.0 to 4.15.0
Bumps [net.kyori:adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.14.0 to 4.15.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.14.0...v4.15.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 11:40:53 +00:00
hyperdefined
ee5ebff614 Merge pull request #43 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-clean-plugin-3.3.2
Bump org.apache.maven.plugins:maven-clean-plugin from 3.3.1 to 3.3.2
2023-10-27 13:35:41 -04:00
dependabot[bot]
fa7b19e3fc Bump org.apache.maven.plugins:maven-clean-plugin from 3.3.1 to 3.3.2
Bumps [org.apache.maven.plugins:maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/apache/maven-clean-plugin/releases)
- [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.3.1...maven-clean-plugin-3.3.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-27 11:06:37 +00:00
hyperdefined
cc4176cfbe awrf :3 2023-10-22 20:05:44 -04:00
hyperdefined
bd30b05246 Update README.md 2023-10-22 19:52:34 -04:00
hyperdefined
2ace1c4f16 bump version 2023-10-22 19:46:59 -04:00
hyperdefined
c3f47707c4 remove all "config" things into it's own thing 2023-10-22 19:43:22 -04:00
hyperdefined
ee1c197d72 more config updater changes 2023-10-22 19:35:41 -04:00
hyperdefined
74b529ba4f Update CommandToolStats.java 2023-10-22 19:23:30 -04:00
hyperdefined
c328b9e019 add "arrows shot" + fix jank 2023-10-22 19:13:44 -04:00
hyperdefined
38c37ea601 new images 2023-10-22 18:54:51 -04:00
hyperdefined
700e7bca2c more config changes
* fixed typo on config updater
* handle missing config messages a lot better
* only try to update lore if it's enabled, don't try then check if it's enabled
2023-10-21 18:52:58 -04:00
hyperdefined
59bfdf69ca improve various config things 2023-10-21 18:11:28 -04:00
hyperdefined
68aed25834 Update README.md 2023-10-19 18:04:57 -04:00
hyperdefined
0968497fc0 added a config updater 2023-10-19 17:59:53 -04:00
hyperdefined
c7a5aef9ee make item checking better
fixes #42
2023-10-19 17:05:15 -04:00
hyperdefined
e40e16c273 Update modrinth.yml 2023-10-19 12:25:22 -04:00
hyperdefined
fc9ef05afd Update modrinth.yml 2023-10-19 12:24:30 -04:00
hyperdefined
26ae28dcd8 Update README.md 2023-10-19 12:23:12 -04:00
hyperdefined
02a7920ad2 Create modrinth.yml 2023-10-19 12:22:08 -04:00
hyperdefined
68c9685477 added "spawned by" for creative items
closes #41
2023-10-17 14:17:41 -04:00
hyperdefined
9f81cb1f74 Merge pull request #40 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.3.1 2023-10-02 09:10:39 -04:00
hyperdefined
e068aeb9f4 never ending battle with deepsource 2023-09-30 20:52:30 -04:00
hyperdefined
b0733935ae handle loot generation better
edit the loot itself, not the contents of chest

also handle breaking chest instead of opening it
2023-09-30 20:43:54 -04:00
hyperdefined
664eddeab0 more hash work 2023-09-30 20:22:33 -04:00
hyperdefined
cda8d94199 ok 2023-09-30 20:07:46 -04:00
hyperdefined
5551c24202 lots of updates
- add hash to items when created
- added "crops harvested" for hoes
2023-09-30 20:05:31 -04:00
dependabot[bot]
951106177b Bump net.kyori:adventure-platform-bukkit from 4.3.0 to 4.3.1
Bumps [net.kyori:adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.0...v4.3.1)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-29 11:18:32 +00:00
hyperdefined
0a3f46fc6e Merge pull request #39 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.5.1
Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1
2023-09-27 22:00:23 -04:00
dependabot[bot]
2894e2021a Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.0...maven-shade-plugin-3.5.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 11:47:01 +00:00
hyperdefined
2e34cb812a Merge pull request #38 from hyperdefined/dependabot/maven/lol.hyper-github-release-api-1.0.5
Bump lol.hyper:github-release-api from 1.0.4 to 1.0.5
2023-09-18 12:01:07 -04:00
dependabot[bot]
a38c148b80 Bump lol.hyper:github-release-api from 1.0.4 to 1.0.5
Bumps [lol.hyper:github-release-api](https://github.com/hyperdefined/GitHubReleaseAPI) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/hyperdefined/GitHubReleaseAPI/releases)
- [Commits](https://github.com/hyperdefined/GitHubReleaseAPI/compare/1.0.4...1.0.5)

---
updated-dependencies:
- dependency-name: lol.hyper:github-release-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 11:35:07 +00:00
hyperdefined
a55cea4b5d more work 2023-08-30 17:02:50 -04:00
hyperdefined
d0fcd4fc61 Update pom.xml 2023-08-30 16:38:13 -04:00
hyperdefined
f14b9bc474 imports 2023-08-30 16:37:36 -04:00
hyperdefined
366a54052a basic folia support 2023-08-29 10:41:08 -04:00
hyperdefined
fe96235ed1 removed unused function 2023-07-17 19:24:45 -04:00
hyperdefined
fe8052f9d6 add origin tag to existing items 2023-07-17 19:23:04 -04:00
hyperdefined
884bdef444 add missing elytra to item list 2023-07-17 19:22:32 -04:00
hyperdefined
be31202f65 config changes 2023-07-17 15:29:33 -04:00
hyperdefined
39d8a42110 clean this up a bit 2023-07-17 15:29:26 -04:00
hyperdefined
91090dd6cc fix this 2023-07-17 15:28:56 -04:00
hyperdefined
29a2a5150c update various things for origin NBT 2023-07-13 19:16:02 -04:00
hyperdefined
b38d2825cb added NBT for origins of items 2023-07-13 19:04:29 -04:00
hyperdefined
fd6c120a58 Merge pull request #36 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-clean-plugin-3.3.1
Bump maven-clean-plugin from 3.2.0 to 3.3.1
2023-06-20 18:50:48 -04:00
dependabot[bot]
459569a1dc Bump maven-clean-plugin from 3.2.0 to 3.3.1
Bumps [maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.2.0 to 3.3.1.
- [Release notes](https://github.com/apache/maven-clean-plugin/releases)
- [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.2.0...maven-clean-plugin-3.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-20 11:59:37 +00:00
hyperdefined
9ba6200415 Merge pull request #35 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.5.0
Bump maven-shade-plugin from 3.4.1 to 3.5.0
2023-06-19 13:24:21 -04:00
dependabot[bot]
b94e0e8c36 Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-16 11:59:30 +00:00
hyperdefined
a42c526198 Merge pull request #34 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.14.0
Bump adventure-text-minimessage from 4.13.1 to 4.14.0
2023-06-07 12:35:33 -04:00
dependabot[bot]
851a494935 Bump adventure-text-minimessage from 4.13.1 to 4.14.0
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.13.1 to 4.14.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.13.1...v4.14.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-07 11:59:12 +00:00
hyperdefined
72e869d5e2 Update pom.xml 2023-05-22 20:22:02 -04:00
hyperdefined
300fe56c5a use continue here, not return
closes #33
2023-05-22 20:21:16 -04:00
hyperdefined
fe5e55d746 Update pom.xml 2023-05-22 00:05:00 -04:00
hyperdefined
0574fb61a6 fix traded-by tags :3333 2023-05-22 00:03:42 -04:00
hyperdefined
433ab547cb minor adjustments 2023-05-21 23:49:07 -04:00
hyperdefined
9746789f2b added int damage value 2023-04-21 15:31:54 -04:00
hyperdefined
fd3c3ca8ed Merge pull request #31 from hyperdefined/dependabot/maven/org.bstats-bstats-bukkit-3.0.2
Bump bstats-bukkit from 3.0.1 to 3.0.2
2023-04-10 16:38:20 -04:00
hyperdefined
c6dc2c3368 Merge pull request #32 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.13.1
Bump adventure-text-minimessage from 4.13.0 to 4.13.1
2023-04-10 16:36:01 -04:00
dependabot[bot]
d11211b1c7 Bump adventure-text-minimessage from 4.13.0 to 4.13.1
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.13.0 to 4.13.1.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.13.0...v4.13.1)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-10 12:02:00 +00:00
dependabot[bot]
e8c2296bd7 Bump bstats-bukkit from 3.0.1 to 3.0.2
Bumps [bstats-bukkit](https://github.com/Bastian/bStats-Metrics) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/Bastian/bStats-Metrics/releases)
- [Commits](https://github.com/Bastian/bStats-Metrics/compare/v3.0.1...v3.0.2)

---
updated-dependencies:
- dependency-name: org.bstats:bstats-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-29 12:00:34 +00:00
hyperdefined
d8f296a085 Merge pull request #29 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.13.0
Bump adventure-text-minimessage from 4.12.0 to 4.13.0
2023-03-16 10:42:18 -04:00
hyperdefined
58dee809f3 Merge pull request #30 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.3.0
Bump adventure-platform-bukkit from 4.2.0 to 4.3.0
2023-03-16 10:40:21 -04:00
dependabot[bot]
590cf6e8b0 Bump adventure-platform-bukkit from 4.2.0 to 4.3.0
Bumps [adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-16 12:00:42 +00:00
dependabot[bot]
a7cc8671bd Bump adventure-text-minimessage from 4.12.0 to 4.13.0
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.12.0 to 4.13.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.12.0...v4.13.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-14 12:00:26 +00:00
hyperdefined
37a7c642d3 Merge pull request #28 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.11.0
Bump maven-compiler-plugin from 3.10.1 to 3.11.0
2023-02-27 18:57:28 -05:00
dependabot[bot]
31acdd9527 Bump maven-compiler-plugin from 3.10.1 to 3.11.0
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.10.1 to 3.11.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.10.1...maven-compiler-plugin-3.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 12:10:48 +00:00
hyperdefined
9b0ac2d912 stfu deepsource 2023-02-20 22:28:33 -05:00
hyperdefined
4ea9e1600b return item lore back rather than nulling it 2023-02-20 22:02:48 -05:00
hyperdefined
72b8b31779 Merge pull request #27 from hyperdefined/dependabot/maven/org.bstats-bstats-bukkit-3.0.1
Bump bstats-bukkit from 3.0.0 to 3.0.1
2023-02-16 17:43:01 -05:00
dependabot[bot]
fce135f2f8 Bump bstats-bukkit from 3.0.0 to 3.0.1
Bumps [bstats-bukkit](https://github.com/Bastian/bStats-Metrics) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/Bastian/bStats-Metrics/releases)
- [Commits](https://github.com/Bastian/bStats-Metrics/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: org.bstats:bstats-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 12:09:50 +00:00
hyperdefined
425b315104 Revert "Update ToolStats.java"
This reverts commit f2739cf433.
2023-01-16 13:41:50 -05:00
hyperdefined
50a0bc800c small command changes 2022-12-12 17:05:46 -05:00
hyperdefined
583cd824f4 Update EntityDamage.java 2022-12-12 12:06:06 -05:00
hyperdefined
d63f00166d Update NumberFormat.java 2022-12-12 11:30:26 -05:00
hyperdefined
0bcb0c7370 added missing tracking for mobs 2022-12-12 11:21:06 -05:00
hyperdefined
e4859de614 Merge pull request #26 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.2.0
Bump adventure-platform-bukkit from 4.1.2 to 4.2.0
2022-12-11 23:41:50 -05:00
dependabot[bot]
f7c1af153f Bump adventure-platform-bukkit from 4.1.2 to 4.2.0
Bumps [adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.1.2 to 4.2.0.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.1.2...v4.2.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 11:05:50 +00:00
hyperdefined
946dc591f5 Update pom.xml 2022-12-08 13:40:27 -05:00
hyperdefined
d279569199 Update EntityDamage.java 2022-12-08 13:40:12 -05:00
hyperdefined
f2739cf433 Update ToolStats.java 2022-12-07 16:21:14 -05:00
hyperdefined
bef854be14 removed logging 2022-12-07 15:19:32 -05:00
hyperdefined
2c971da1b9 unify lore management 2022-12-07 14:56:57 -05:00
hyperdefined
2e0ee18594 more possible plugin compatibility? 2022-12-01 17:56:41 -05:00
hyperdefined
98a5f20a86 better offhand/main hand detection 2022-11-30 14:41:34 -05:00
hyperdefined
dd8a0db3b6 fix using rods in offhand 2022-11-30 14:22:35 -05:00
hyperdefined
fee7d5cd99 Merge pull request #25 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.12.0
Bump adventure-text-minimessage from 4.11.0 to 4.12.0
2022-11-29 23:21:12 -05:00
hyperdefined
70ebf49958 Merge branch 'master' of https://github.com/hyperdefined/ToolStats 2022-11-29 20:06:40 -05:00
dependabot[bot]
50d2ec0507 Bump adventure-text-minimessage from 4.11.0 to 4.12.0
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.11.0 to 4.12.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.11.0...v4.12.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-28 11:09:14 +00:00
hyperdefined
6428925e40 support for complete customization of numbers
closes #24
2022-11-24 00:44:59 -05:00
hyperdefined
1d4faa89a1 Merge branch 'master' of https://github.com/hyperdefined/ToolStats 2022-11-23 02:22:46 -05:00
hyperdefined
1ad650f42b Merge pull request #23 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.4.0 to 3.4.1
2022-11-06 19:20:20 -05:00
hyperdefined
fdb6626c42 update all items 1 tick later
this should fix #18
2022-11-04 20:26:55 -04:00
dependabot[bot]
cd80e6a675 Bump maven-shade-plugin from 3.4.0 to 3.4.1
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-27 11:23:52 +00:00
hyperdefined
03d45ea8f7 Update pom.xml 2022-10-26 18:10:22 -04:00
hyperdefined
91a98cf664 fix the symbols regardless of Locale 2022-10-26 18:08:00 -04:00
hyperdefined
72b00e96f6 fix example date format in config 2022-10-24 21:27:40 -04:00
hyperdefined
07458bfc11 ignore mob drops with our tags
fixes #22
2022-10-24 21:21:45 -04:00
hyperdefined
24d30f6059 fix deepsource problems 2022-10-13 18:09:19 -04:00
hyperdefined
bea7e52347 Update pom.xml 2022-10-13 18:05:00 -04:00
hyperdefined
1b1b45ef6d even BETTER number formatting?!?!
closes #19
2022-10-13 17:58:40 -04:00
hyperdefined
2de2ae82a7 config for date formatting
closes #20
2022-10-12 13:21:54 -04:00
hyperdefined
7639943fea better formatting for numbers 2022-10-12 13:04:35 -04:00
hyperdefined
2b75ea094d maybe not do this? 2022-10-09 16:51:26 -04:00
hyperdefined
bc8496fad4 changed event priorities 2022-10-05 20:46:19 -04:00
hyperdefined
1cef74311e big cleanup 2022-10-05 16:20:36 -04:00
hyperdefined
cbbdb4e9c4 remove dumb stuff 2022-10-04 12:59:16 -04:00
hyperdefined
f6d35c459c Merge pull request #17 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0
2022-09-19 22:32:43 -04:00
dependabot[bot]
4624d7a847 Bump maven-shade-plugin from 3.3.0 to 3.4.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-15 11:29:08 +00:00
hyperdefined
3766db3454 Merge branch 'master' of https://github.com/hyperdefined/ToolStats 2022-09-12 16:57:35 -04:00
hyperdefined
5a5e29c5e2 ignore CUSTOM damage causes 2022-09-12 16:57:19 -04:00
hyperdefined
d188877f18 Update README.md 2022-08-30 10:28:29 -04:00
hyperdefined
05200f075b Update pom.xml 2022-08-19 18:27:57 -04:00
hyperdefined
9973d743a5 better handling of /kill
apparently minecraft:kill runs in multiple entity damage events?
2022-08-19 18:27:34 -04:00
hyperdefined
a89b9d6f6a Update CommandToolStats.java 2022-08-19 17:39:25 -04:00
hyperdefined
082f529c32 hopefully fixed long standing bug 2022-08-18 11:59:20 -04:00
hyperdefined
05f940026f ignore void and /kill damage 2022-08-18 10:27:43 -04:00
hyperdefined
59d0295b18 permission stuff 2022-08-15 11:51:23 -04:00
hyperdefined
af908f2eb6 Merge pull request #16 from hyperdefined/dependabot/maven/lol.hyper-github-release-api-1.0.4
Bump github-release-api from 1.0.3 to 1.0.4
2022-08-15 11:45:05 -04:00
dependabot[bot]
c86e96e200 Bump github-release-api from 1.0.3 to 1.0.4
Bumps [github-release-api](https://github.com/hyperdefined/GitHubReleaseAPI) from 1.0.3 to 1.0.4.
- [Release notes](https://github.com/hyperdefined/GitHubReleaseAPI/releases)
- [Commits](https://github.com/hyperdefined/GitHubReleaseAPI/compare/1.0.3...1.0.4)

---
updated-dependencies:
- dependency-name: lol.hyper:github-release-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-11 13:32:36 +00:00
hyperdefined
8061293810 Merge pull request #15 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.1.2
Bump adventure-platform-bukkit from 4.1.1 to 4.1.2
2022-08-04 12:25:29 -04:00
dependabot[bot]
656e265006 Bump adventure-platform-bukkit from 4.1.1 to 4.1.2
Bumps [adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.1.1 to 4.1.2.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.1.1...v4.1.2)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 11:30:53 +00:00
hyperdefined
507813f106 Update pom.xml 2022-06-27 20:22:13 -04:00
hyperdefined
e3e1c6a690 Update pom.xml 2022-06-18 17:09:25 -04:00
hyperdefined
5eebcb9ff4 make sure chests are in the same world
fixes #14
2022-06-18 17:09:12 -04:00
hyperdefined
63d508fded fixed typo 2022-06-16 00:04:23 -04:00
hyperdefined
59a8079ba2 Update pom.xml 2022-06-16 00:00:19 -04:00
hyperdefined
3767ee2f63 fixed reseting lore for armor 2022-06-16 00:00:04 -04:00
hyperdefined
7d5f73ae96 better number formatting 2022-06-15 23:59:19 -04:00
hyperdefined
b581d9d178 much better item checking 2022-06-15 23:48:39 -04:00
hyperdefined
d355b7a429 moved class 2022-06-15 23:26:20 -04:00
hyperdefined
d06a1c4a40 support for adding lore to minecart items 2022-06-15 23:25:21 -04:00
hyperdefined
e22fc7b530 Merge pull request #13 from hyperdefined/dependabot/maven/net.kyori-adventure-platform-bukkit-4.1.1
Bump adventure-platform-bukkit from 4.1.0 to 4.1.1
2022-06-13 18:32:54 -04:00
dependabot[bot]
8478411b8f Bump adventure-platform-bukkit from 4.1.0 to 4.1.1
Bumps [adventure-platform-bukkit](https://github.com/KyoriPowered/adventure-platform) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-13 11:38:33 +00:00
hyperdefined
85d072667a Update CommandToolStats.java 2022-06-13 03:10:39 -04:00
hyperdefined
010ca54144 gamemode check 2022-06-13 03:07:37 -04:00
hyperdefined
6af49d6c30 better null handling 2022-06-13 02:55:11 -04:00
hyperdefined
c4e4ce01fd removed debug message 2022-06-13 02:21:32 -04:00
hyperdefined
983a35bd0b Update README.md 2022-06-08 21:01:15 -04:00
hyperdefined
d9ad7ebcad shade stuff 2022-06-07 17:58:46 -04:00
hyperdefined
995f80e159 Update plugin.yml 2022-06-06 13:26:05 -04:00
hyperdefined
56850c40d1 Merge pull request #11 from hyperdefined/dependabot/maven/net.kyori-adventure-text-minimessage-4.11.0
Bump adventure-text-minimessage from 4.10.1 to 4.11.0
2022-06-06 13:25:15 -04:00
dependabot[bot]
b9e4bbd1e8 Bump adventure-text-minimessage from 4.10.1 to 4.11.0
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.10.1 to 4.11.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.10.1...v4.11.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 11:28:36 +00:00
hyperdefined
6a23c7a724 version bump 2022-05-10 15:31:52 -04:00
hyperdefined
cd6cb999c0 handle item pickup better 2022-05-10 15:29:53 -04:00
hyperdefined
f9cff275b5 fixed trident lore not being added 2022-05-10 15:27:51 -04:00
hyperdefined
ba1ae01801 use minimessage for various messages 2022-05-10 14:41:01 -04:00
hyperdefined
fd35cf6e9c Update README.md 2022-04-19 18:55:48 -04:00
hyperdefined
5971ecc919 Merge pull request #10 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-clean-plugin-3.2.0
Bump maven-clean-plugin from 3.1.0 to 3.2.0
2022-04-06 11:38:22 -04:00
dependabot[bot]
4c4ca0c31e Bump maven-clean-plugin from 3.1.0 to 3.2.0
Bumps [maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/apache/maven-clean-plugin/releases)
- [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.1.0...maven-clean-plugin-3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-05 11:24:12 +00:00
hyperdefined
294b753430 Merge pull request #9 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.3.0
Bump maven-shade-plugin from 3.2.4 to 3.3.0
2022-03-30 15:11:18 -04:00
dependabot[bot]
adf6a3149b Bump maven-shade-plugin from 3.2.4 to 3.3.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.4 to 3.3.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.4...maven-shade-plugin-3.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-30 11:32:46 +00:00
hyperdefined
ea68650038 Merge pull request #8 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.10.1
Bump maven-compiler-plugin from 3.10.0 to 3.10.1
2022-03-11 16:47:40 -05:00
dependabot[bot]
114a27e9b5 Bump maven-compiler-plugin from 3.10.0 to 3.10.1
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.10.0...maven-compiler-plugin-3.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-11 11:26:04 +00:00
hyperdefined
7cdb71df50 cleanup 2022-03-01 23:33:55 -05:00
hyperdefined
bd80d6718c Update CommandToolStats.java 2022-03-01 23:33:26 -05:00
hyperdefined
b9907eedec unify item arrays & date formats 2022-03-01 23:32:30 -05:00
hyperdefined
61cf44a407 handle finding who opens a newly spawned chest better 2022-03-01 23:21:09 -05:00
hyperdefined
337f88ce36 Update pom.xml 2022-02-24 11:46:50 -05:00
hyperdefined
42f100f0b0 added missing return (fixes #7) 2022-02-24 11:46:08 -05:00
hyperdefined
63b3cb1d03 Update pom.xml 2022-02-23 19:57:41 -05:00
hyperdefined
7717b6b5a5 Update EntityDamage.java 2022-02-23 19:53:54 -05:00
hyperdefined
a421430fa8 only add damage to valid armor
closes #6
2022-02-23 19:52:58 -05:00
hyperdefined
7a89b31766 removed unused set 2022-02-22 19:05:00 -05:00
hyperdefined
0334681971 getFinalDamage() instead because of armor reductions 2022-02-22 17:33:48 -05:00
hyperdefined
df23f40d6b Update pom.xml 2022-02-22 15:08:38 -05:00
hyperdefined
0221ee40cf handle logic of lore reset better 2022-02-22 15:07:51 -05:00
hyperdefined
a01d07af4a fixed removing new tag for elytras
this fixes #5
2022-02-22 15:07:30 -05:00
hyperdefined
e402d3078a Merge pull request #4 from hyperdefined/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.10.0
Bump maven-compiler-plugin from 3.9.0 to 3.10.0
2022-02-14 21:07:02 -05:00
dependabot[bot]
4f44ca0777 Bump maven-compiler-plugin from 3.9.0 to 3.10.0
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.9.0...maven-compiler-plugin-3.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 11:38:14 +00:00
hyperdefined
53fd7f734c Update pom.xml 2022-02-12 20:47:52 -05:00
hyperdefined
75cd4fa17e fixed small typo 2022-02-12 20:47:32 -05:00
hyperdefined
e296c27a5b added comments to better explain what is going on 2022-02-11 19:19:05 -05:00
34 changed files with 2797 additions and 798 deletions

12
.github/workflows/modrinth.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
on:
push:
branches: [ master ]
jobs:
modrinth-desc:
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v3
- uses: funnyboy-roks/modrinth-auto-desc@v1.6
with:
auth-token: ${{ secrets.MODRINTH }}
slug: 'oBZj9E15'

View File

@@ -1,11 +1,10 @@
<h1 align="center">ToolStats</h1>
<p align="center">
<img src="https://img.shields.io/badge/Minecraft-1.15+-orange" alt="Minecraft versions">
<img src="https://img.shields.io/badge/Minecraft-1.15--1.21-orange" alt="Minecraft versions">
<img src="https://img.shields.io/github/v/release/hyperdefined/ToolStats" alt="GitHub release (latest by date)">
<a href="https://github.com/hyperdefined/ToolStats/releases"><img src="https://img.shields.io/github/downloads/hyperdefined/ToolStats/total?logo=github" alt="Downloads"></a>
<a href="https://en.cryptobadges.io/donate/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL"><img src="https://en.cryptobadges.io/badge/micro/1F29aNKQzci3ga5LDcHHawYzFPXvELTFoL" alt="Donate with Bitcoin"></a>
<a href="https://en.cryptobadges.io/donate/0xF3b4e87E4c11f586949ca8740eD33A1e473F924c"><img src="https://en.cryptobadges.io/badge/micro/0xF3b4e87E4c11f586949ca8740eD33A1e473F924c" alt="Donate with Ethereum"></a>
<img src="https://img.shields.io/badge/made%20with-love%20&%20fluff-red" alt="Made with love & fluff">
<a href="https://ko-fi.com/hyperdefined"><img src="https://img.shields.io/badge/Donate-Ko--fi-red" alt="Donate via Ko-fi"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0"><img src="https://img.shields.io/badge/License-GPLv3-blue.svg" alt="License: GPL v3"></a>
<a href="https://wakatime.com/badge/user/992a7647-176a-477c-8086-e1abfba87ff4/project/0200f07a-f303-4103-a5f2-34b38c9c1fa4"><img src="https://wakatime.com/badge/user/992a7647-176a-477c-8086-e1abfba87ff4/project/0200f07a-f303-4103-a5f2-34b38c9c1fa4.svg" alt="wakatime"></a>
@@ -15,15 +14,17 @@ ToolStats is a small plugin that display various stats about tools. This plugin
Here is everything it tracks:
* Blocks mined (pickaxes, shovels, axes, hoes, shears)
* Crops mined (hoes)
* Player/mob kills (swords, axes, tridents, bows/crossbows)
* Ownership of items when crafted, looted (from chests), traded, and caught from fishing.
* Ownership of items when crafted, looted (from chests), traded, spawned via creative, and caught from fishing.
* Armor damage taken.
* Fish caught.
* Sheep sheared.
* Arrows shot (bows/crossbows)
The best part is, this data is stored on the item itself. You can also change how the lore is displayed on the items!
If item lore is ever incorrect, you can run `/toolstats reset` to reset the item lore so it's correct.
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://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image2.png)
@@ -35,6 +36,11 @@ If item lore is ever incorrect, you can run `/toolstats reset` to reset the item
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image8.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image9.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image10.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image11.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image12.png)
## Documentation
Visit the [wiki](https://github.com/hyperdefined/ToolStats/wiki) for help.
## License
This plugin is released under GNU General Public License v3. See [LICENSE](https://github.com/hyperdefined/ToolStats/blob/master/LICENSE).

BIN
images/image11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
images/image12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

61
pom.xml
View File

@@ -23,7 +23,7 @@
<groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId>
<version>1.3</version>
<version>1.8.1</version>
<packaging>jar</packaging>
<name>ToolStats</name>
@@ -37,7 +37,7 @@
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<version>3.4.0</version>
<executions>
<execution>
<id>auto-clean</id>
@@ -51,7 +51,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
@@ -60,13 +60,25 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<version>3.6.0</version>
<configuration>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>lol.hyper.toolstats.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori.adventure</pattern>
<shadedPattern>lol.hyper.toolstats.adventure</shadedPattern>
</relocation>
<relocation>
<pattern>lol.hyper.githubreleaseapi</pattern>
<shadedPattern>lol.hyper.toolstats.updater</shadedPattern>
</relocation>
<relocation>
<pattern>space.arim.morepaperlib</pattern>
<shadedPattern>lol.hyper.toolstats.morepaperlib</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
@@ -95,31 +107,54 @@
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>arim-mvn-lgpl3</id>
<url>https://mvn-repo.arim.space/lesser-gpl3/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.18.1-R0.1-SNAPSHOT</version>
<version>1.20.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.0</version>
<version>3.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>lol.hyper</groupId>
<artifactId>github-release-api</artifactId>
<version>1.0.1</version>
<version>1.0.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>4.17.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>4.3.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>space.arim.morepaperlib</groupId>
<artifactId>morepaperlib</artifactId>
<version>0.4.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.20-R0.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -21,43 +21,101 @@ import lol.hyper.githubreleaseapi.GitHubRelease;
import lol.hyper.githubreleaseapi.GitHubReleaseAPI;
import lol.hyper.toolstats.commands.CommandToolStats;
import lol.hyper.toolstats.events.*;
import lol.hyper.toolstats.tools.HashMaker;
import lol.hyper.toolstats.tools.ItemChecker;
import lol.hyper.toolstats.tools.ItemLore;
import lol.hyper.toolstats.tools.NumberFormat;
import lol.hyper.toolstats.tools.config.ConfigTools;
import lol.hyper.toolstats.tools.config.ConfigUpdater;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import space.arim.morepaperlib.MorePaperLib;
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 {
// stores who created an item
/**
* Stores who created an item.
*/
public final NamespacedKey genericOwner = new NamespacedKey(this, "owner");
// stores when an item was created
/**
* Stores when the item was created.
*/
public final NamespacedKey timeCreated = new NamespacedKey(this, "time-created");
// stores how many player kills by sword
/**
* Stores how many player kills.
*/
public final NamespacedKey swordPlayerKills = new NamespacedKey(this, "player-kills");
// stores how many mob kills by sword
/**
* Stores how many mob kills.
*/
public final NamespacedKey swordMobKills = new NamespacedKey(this, "mob-kills");
// stores how blocks mined (used for all tools)
/**
* Stores how many blocks were mined.
*/
public final NamespacedKey genericMined = new NamespacedKey(this, "generic-mined");
// stores how many fish were caught
/**
* Stores how many crops were harvested.
*/
public final NamespacedKey cropsHarvested = new NamespacedKey(this, "crops-mined");
/**
* Stores how many fish were caught.
*/
public final NamespacedKey fishingRodCaught = new NamespacedKey(this, "fish-caught");
// stores how many times sheep were sheared
/**
* Stores how many sheep were sheared.
*/
public final NamespacedKey shearsSheared = new NamespacedKey(this, "sheared");
// stores how much damage armor has taken
/**
* Stores how much damage an armor piece has taken.
*/
public final NamespacedKey armorDamage = new NamespacedKey(this, "damage-taken");
// used for tracking new elytras
/**
* Stores how much damage an armor piece has taken (as an int).
*/
public final NamespacedKey armorDamageInt = new NamespacedKey(this, "damage-taken-int");
/**
* 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");
/**
* 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 Set<NamespacedKey> keys = new HashSet<>();
public final int CONFIG_VERSION = 7;
public final Logger logger = this.getLogger();
public final File configFile = new File(this.getDataFolder(), "config.yml");
public BlocksMined blocksMined;
public ChunkPopulate chunkPopulate;
@@ -67,22 +125,34 @@ public final class ToolStats extends JavaPlugin {
public PickupItem pickupItem;
public EntityDamage mobKill;
public PlayerFish playerFish;
public PlayerInteract playerInteract;
public SheepShear sheepShear;
public VillagerTrade villagerTrade;
public CommandToolStats commandToolStats;
public final Logger logger = this.getLogger();
public final File configFile = new File(this.getDataFolder(), "config.yml");
public FileConfiguration config;
public final int CONFIG_VERSION = 3;
public ItemLore itemLore;
public InventoryOpen inventoryOpen;
public PlayerJoin playerJoin;
public NumberFormat numberFormat;
public YamlConfiguration config;
private BukkitAudiences adventure;
public MorePaperLib morePaperLib;
public HashMaker hashMaker;
public CreativeEvent creativeEvent;
public PlayerMove playerMove;
public ItemChecker itemChecker;
public ShootBow shootBow;
public ConfigTools configTools;
@Override
public void onEnable() {
this.adventure = BukkitAudiences.create(this);
morePaperLib = new MorePaperLib(this);
if (!configFile.exists()) {
this.saveResource("config.yml", true);
logger.info("Copying default config!");
}
loadConfig();
hashMaker = new HashMaker(this);
blocksMined = new BlocksMined(this);
craftItem = new CraftItem(this);
chunkPopulate = new ChunkPopulate(this);
@@ -91,9 +161,18 @@ public final class ToolStats extends JavaPlugin {
pickupItem = new PickupItem(this);
mobKill = new EntityDamage(this);
playerFish = new PlayerFish(this);
playerInteract = new PlayerInteract(this);
sheepShear = new SheepShear(this);
villagerTrade = new VillagerTrade(this);
commandToolStats = new CommandToolStats(this);
itemLore = new ItemLore(this);
inventoryOpen = new InventoryOpen(this);
playerJoin = new PlayerJoin(this);
creativeEvent = new CreativeEvent(this);
playerMove = new PlayerMove(this);
itemChecker = new ItemChecker();
shootBow = new ShootBow(this);
configTools = new ConfigTools(this);
Bukkit.getServer().getPluginManager().registerEvents(blocksMined, this);
Bukkit.getServer().getPluginManager().registerEvents(chunkPopulate, this);
@@ -103,30 +182,31 @@ public final class ToolStats extends JavaPlugin {
Bukkit.getServer().getPluginManager().registerEvents(pickupItem, this);
Bukkit.getServer().getPluginManager().registerEvents(mobKill, this);
Bukkit.getServer().getPluginManager().registerEvents(playerFish, this);
Bukkit.getServer().getPluginManager().registerEvents(playerInteract, this);
Bukkit.getServer().getPluginManager().registerEvents(sheepShear, this);
Bukkit.getServer().getPluginManager().registerEvents(villagerTrade, this);
Bukkit.getServer().getPluginManager().registerEvents(inventoryOpen, this);
Bukkit.getServer().getPluginManager().registerEvents(playerJoin, this);
Bukkit.getServer().getPluginManager().registerEvents(creativeEvent, this);
Bukkit.getServer().getPluginManager().registerEvents(shootBow, this);
Bukkit.getServer().getPluginManager().registerEvents(playerMove, this);
this.getCommand("toolstats").setExecutor(commandToolStats);
new Metrics(this, 14110);
Bukkit.getScheduler().runTaskAsynchronously(this, this::checkForUpdates);
keys.add(genericOwner);
keys.add(timeCreated);
keys.add(swordPlayerKills);
keys.add(swordMobKills);
keys.add(genericMined);
keys.add(fishingRodCaught);
keys.add(shearsSheared);
keys.add(armorDamage);
morePaperLib.scheduling().asyncScheduler().run(this::checkForUpdates);
}
public void loadConfig() {
config = YamlConfiguration.loadConfiguration(configFile);
if (config.getInt("config-version") != CONFIG_VERSION) {
logger.warning("Your config file is outdated! Please regenerate the config.");
logger.warning("Your config file is outdated! We will try to update it, but you should regenerate it!");
ConfigUpdater configUpdater = new ConfigUpdater(this);
configUpdater.updateConfig();
}
numberFormat = new NumberFormat(this);
}
public void checkForUpdates() {
@@ -152,93 +232,22 @@ public final class ToolStats extends JavaPlugin {
}
}
public boolean checkConfig(ItemStack itemStack, String configName) {
String itemName = itemStack.getType().toString().toLowerCase();
String itemType = null;
if (itemName.contains("bow") || itemName.contains("shears")) {
if (itemName.contains("bow")) {
itemType = "bow";
}
if (itemName.contains("shears")) {
itemType = "shears";
}
} else {
itemType = itemName.substring(itemName.indexOf("_") + 1);
public BukkitAudiences getAdventure() {
if (this.adventure == null) {
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
}
if (itemType == null) {
return false;
}
switch (itemType) {
case "pickaxe": {
return config.getBoolean("enabled." + configName + ".pickaxe");
}
case "sword": {
return config.getBoolean("enabled." + configName + ".sword");
}
case "shovel": {
return config.getBoolean("enabled." + configName + ".shovel");
}
case "axe": {
return config.getBoolean("enabled." + configName + ".axe");
}
case "hoe": {
return config.getBoolean("enabled." + configName + ".hoe");
}
case "shears": {
return config.getBoolean("enabled." + configName + ".shears");
}
case "bow": {
return config.getBoolean("enabled." + configName + ".bow");
}
case "helmet":
case "chestplate":
case "leggings":
case "boots": {
return config.getBoolean("enabled." + configName + ".armor");
}
}
return false;
return this.adventure;
}
public String getLoreFromConfig(String configName, boolean raw) {
String lore = config.getString("messages." + configName);
if (lore == null) {
return null;
}
if (raw) {
return ChatColor.translateAlternateColorCodes('&', lore);
} else {
// we basically add the color codes then remove them
// this is a dirty trick to remove color codes
lore = ChatColor.translateAlternateColorCodes('&', lore);
lore = ChatColor.stripColor(lore);
if (lore.contains("{player}")) {
lore = lore.replace("{player}", "");
}
if (lore.contains("{date}")) {
lore = lore.replace("{date}", "");
}
if (lore.contains("{name}")) {
lore = lore.replace("{name}", "");
}
if (lore.contains("{kills}")) {
lore = lore.replace("{kills}", "");
}
if (lore.contains("{blocks}")) {
lore = lore.replace("{blocks}", "");
}
if (lore.contains("{sheep}")) {
lore = lore.replace("{sheep}", "");
}
if (lore.contains("{damage}")) {
lore = lore.replace("{damage}", "");
}
if (lore.contains("{fish}")) {
lore = lore.replace("{fish}", "");
}
}
return lore;
public void scheduleEntity(BukkitRunnable runnable, Entity entity, int delay) {
morePaperLib.scheduling().entitySpecificScheduler(entity).runDelayed(runnable, null, delay);
}
public void scheduleGlobal(BukkitRunnable runnable, int delay) {
morePaperLib.scheduling().globalRegionalScheduler().runDelayed(runnable, delay);
}
public void scheduleRegion(BukkitRunnable runnable, World world, Chunk chunk, int delay) {
morePaperLib.scheduling().regionSpecificScheduler(world, chunk.getX(), chunk.getZ()).runDelayed(runnable, delay);
}
}

View File

@@ -18,11 +18,16 @@
package lol.hyper.toolstats.commands;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.*;
import lol.hyper.toolstats.tools.UUIDDataType;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@@ -32,201 +37,282 @@ import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.SimpleDateFormat;
import java.util.*;
public class CommandToolStats implements TabExecutor {
private final ToolStats toolStats;
private final BukkitAudiences audiences;
public CommandToolStats(ToolStats toolStats) {
this.toolStats = toolStats;
this.audiences = toolStats.getAdventure();
}
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!sender.hasPermission("toolstats.use")) {
sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
if (!sender.hasPermission("toolstats.command")) {
audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true;
}
if (args.length == 0) {
sender.sendMessage(ChatColor.GREEN + "ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.");
audiences.sender(sender).sendMessage(Component.text("ToolStats version " + toolStats.getDescription().getVersion() + ". Created by hyperdefined.", NamedTextColor.GREEN));
return true;
}
switch (args[0]) {
case "reload": {
if (sender.isOp() || sender.hasPermission("toolstats.reload")) {
if (sender.hasPermission("toolstats.reload")) {
toolStats.loadConfig();
sender.sendMessage(ChatColor.GREEN + "Configuration reloaded!");
audiences.sender(sender).sendMessage(Component.text("Configuration reloaded!", NamedTextColor.GREEN));
} else {
sender.sendMessage(ChatColor.RED + "You do not have permission for this command.");
audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
}
return true;
}
case "reset": {
if (!sender.hasPermission("toolstats.reset")) {
audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true;
}
if (sender instanceof ConsoleCommandSender) {
audiences.sender(sender).sendMessage(Component.text("You must be a player for this command.", NamedTextColor.RED));
return true;
}
if (args.length == 2 && args[1].equalsIgnoreCase("confirm")) {
if (!sender.hasPermission("toolstats.reset.confirm")) {
audiences.sender(sender).sendMessage(Component.text("You do not have permission for this command.", NamedTextColor.RED));
return true;
}
Player player = (Player) sender;
ItemStack heldItem = player.getInventory().getItemInMainHand();
if (heldItem.getType() == Material.AIR) {
sender.sendMessage(ChatColor.RED + "You must hold an item!");
if (!toolStats.itemChecker.isValidItem(heldItem.getType())) {
audiences.sender(sender).sendMessage(Component.text("You must hold a valid item.", NamedTextColor.RED));
return true;
}
fixItemLore(heldItem, player);
sender.sendMessage(ChatColor.GREEN + "The lore was reset!");
audiences.sender(sender).sendMessage(Component.text("The lore was reset!", NamedTextColor.GREEN));
return true;
}
sender.sendMessage(ChatColor.GREEN + "This will remove ALL current lore from the held item and replace it with the correct lore.");
sender.sendMessage(ChatColor.GREEN + "The item owner will be who ever is currently running this command.");
sender.sendMessage(ChatColor.GREEN + "Only use this if the tags on the tool are incorrect.");
sender.sendMessage(ChatColor.GREEN + "Type /toolstats reset confirm to confirm this.");
audiences.sender(sender).sendMessage(Component.text("This will remove ALL current lore from the held item and replace it with the correct lore.", NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("If the owner of the item is broken, it will reset to the person holding it.", NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("Only use this if the tags on the tool are incorrect.", NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("Type /toolstats reset confirm to confirm this.", NamedTextColor.GREEN));
return true;
}
default: {
sender.sendMessage(ChatColor.RED + "Invalid sub-command.");
audiences.sender(sender).sendMessage(Component.text("Invalid sub-command.", NamedTextColor.RED));
}
}
return true;
}
private ItemStack fixItemLore(ItemStack original, Player player) {
/**
* Fixes lore on a given item. This will wipe all lore and reapply our custom ones.
*
* @param original The item we are fixing.
* @param player The player running the command.
*/
private void fixItemLore(ItemStack original, Player player) {
ItemStack finalItem = original.clone();
ItemMeta finalMeta = finalItem.getItemMeta();
if (finalMeta == null) {
return null;
return;
}
PersistentDataContainer container = finalMeta.getPersistentDataContainer();
List<String> lore = new ArrayList<>();
String caughtByLore = toolStats.getLoreFromConfig("fished.caught-by", false);
String lootedByLore = toolStats.getLoreFromConfig("looted.found-by", false);
String tradedByLore = toolStats.getLoreFromConfig("traded.traded-by", false);
if (caughtByLore == null || lootedByLore == null || tradedByLore == null) {
return null;
// set how the item was obtained
Integer origin = -1;
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
origin = container.get(toolStats.originType, PersistentDataType.INTEGER);
}
String type = "DEFAULT";
if (finalMeta.hasLore()) {
if (finalMeta.getLore() != null) {
for (String line : finalMeta.getLore()) {
if (line.contains(caughtByLore)) {
type = "CAUGHT";
}
if (line.contains(lootedByLore)) {
type = "LOOTED";
}
if (line.contains(tradedByLore)) {
type = "TRADED";
}
// set to -1 if it's invalid
if (origin == null) {
origin = -1;
}
// hard code elytras
if (finalItem.getType() == Material.ELYTRA) {
Long flightTime = null;
Long timeCreated = null;
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
timeCreated = container.get(toolStats.timeCreated, PersistentDataType.LONG);
}
if (container.has(toolStats.flightTime, PersistentDataType.LONG)) {
flightTime = container.get(toolStats.flightTime, PersistentDataType.LONG);
}
if (flightTime != null) {
if (toolStats.config.getBoolean("enabled.flight-time")) {
String line = toolStats.configTools.formatLore("flight-time", "{time}", toolStats.numberFormat.formatDouble((double) flightTime / 1000));
lore.add(line);
}
}
if (timeCreated != null) {
String timeCreatedLine = toolStats.configTools.formatLore("looted.found-by", "{player}", player.getName());
String playerOwnerLine = toolStats.configTools.formatLore("looted.found-on", "{date}", toolStats.numberFormat.formatDate(new Date(timeCreated)));
lore.add(timeCreatedLine);
lore.add(playerOwnerLine);
}
finalMeta.setLore(lore);
finalItem.setItemMeta(finalMeta);
int slot = player.getInventory().getHeldItemSlot();
player.getInventory().setItem(slot, finalItem);
}
if (toolStats.checkConfig(original, "created-by")) {
if (toolStats.configTools.checkConfig(original.getType(), "created-by")) {
if (container.has(toolStats.genericOwner, new UUIDDataType())) {
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", player.getName()));
UUID owner = container.get(toolStats.genericOwner, new UUIDDataType());
String ownerName = null;
// if we can read the current owner
if (owner != null) {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(owner);
ownerName = offlinePlayer.getName();
}
// if the owner's name is null for whatever reason, set the new owner
// to the current player running the command
if (ownerName == null) {
audiences.player(player).sendMessage(Component.text("The owner of this item is null. Setting to " + player.getName() + ".", NamedTextColor.RED));
ownerName = player.getName();
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
}
// show how the item was created based on the previous lore
switch (origin) {
case 0: {
lore.add(toolStats.configTools.formatLore("created.created-by", "{player}", ownerName));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName()));
case 2: {
lore.add(toolStats.configTools.formatLore("looted.looted-by", "{player}", ownerName));
break;
}
case "LOOTED": {
lore.add(toolStats.getLoreFromConfig("looted.looted-by", true).replace("{player}", player.getName()));
case 3: {
lore.add(toolStats.configTools.formatLore("traded.traded-by", "{player}", ownerName));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName()));
case 4: {
lore.add(toolStats.configTools.formatLore("looted.found-by", "{player}", ownerName));
break;
}
case 5: {
lore.add(toolStats.configTools.formatLore("fished.caught-by", "{player}", ownerName));
break;
}
case 6: {
lore.add(toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", ownerName));
break;
}
}
}
}
if (toolStats.checkConfig(original, "created-date")) {
if (toolStats.configTools.checkConfig(original.getType(), "created-date")) {
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time == null) {
return null;
}
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{date}", format.format(new Date(time))));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", format.format(new Date(time))));
break;
}
case "LOOTED": {
lore.add(toolStats.getLoreFromConfig("looted.looted-on", true).replace("{date}", format.format(new Date(time))));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-on", true).replace("{date}", format.format(new Date(time))));
break;
if (time != null) {
String date = toolStats.numberFormat.formatDate(new Date(time));
// show how when the item was created based on the previous lore
switch (origin) {
case 0: {
lore.add(toolStats.configTools.formatLore("created.created-on", "{date}", date));
break;
}
case 2: {
lore.add(toolStats.configTools.formatLore("looted.looted-on", "{date}", date));
break;
}
case 3: {
lore.add(toolStats.configTools.formatLore("traded.traded-on", "{date}", date));
break;
}
case 4: {
lore.add(toolStats.configTools.formatLore("looted.found-on", "{date}", date));
break;
}
case 5: {
lore.add(toolStats.configTools.formatLore("fished.caught-on", "{date}", date));
break;
}
case 6: {
lore.add(toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", date));
break;
}
}
}
}
}
if (toolStats.checkConfig(original, "player-kills")) {
if (toolStats.configTools.checkConfig(original.getType(), "player-kills")) {
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
if (kills == null) {
return null;
if (kills != null) {
lore.add(toolStats.configTools.formatLore("kills.player", "{kills}", toolStats.numberFormat.formatInt(kills)));
}
lore.add(toolStats.getLoreFromConfig("kills.player", true).replace("{kills}", Integer.toString(kills)));
}
}
if (toolStats.checkConfig(original, "mob-kills")) {
if (toolStats.configTools.checkConfig(original.getType(), "mob-kills")) {
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
if (kills == null) {
return null;
if (kills != null) {
lore.add(toolStats.configTools.formatLore("kills.mob", "{kills}", toolStats.numberFormat.formatInt(kills)));
}
lore.add(toolStats.getLoreFromConfig("kills.mob", true).replace("{kills}", Integer.toString(kills)));
}
}
if (toolStats.checkConfig(original, "blocks-mined")) {
if (toolStats.configTools.checkConfig(original.getType(), "blocks-mined")) {
if (original.getType().toString().toLowerCase(Locale.ROOT).contains("hoe")) {
if (container.has(toolStats.cropsHarvested, PersistentDataType.INTEGER)) {
Integer crops = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
if (crops != null) {
lore.add(toolStats.configTools.formatLore("crops-harvested", "{crops}", toolStats.numberFormat.formatInt(crops)));
}
}
}
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
if (blocksMined == null) {
return null;
if (blocksMined != null) {
lore.add(toolStats.configTools.formatLore("blocks-mined", "{blocks}", toolStats.numberFormat.formatInt(blocksMined)));
}
lore.add(toolStats.getLoreFromConfig("blocks-mined", true).replace("{blocks}", Integer.toString(blocksMined)));
}
}
if (toolStats.config.getBoolean("enabled.fish-caught")) {
if (container.has(toolStats.fishingRodCaught, PersistentDataType.INTEGER)) {
Integer fish = container.get(toolStats.fishingRodCaught, PersistentDataType.INTEGER);
if (fish == null) {
return null;
if (fish != null) {
lore.add(toolStats.configTools.formatLore("fished.fish-caught", "{fish}", toolStats.numberFormat.formatInt(fish)));
}
lore.add(toolStats.getLoreFromConfig("fished.fish-caught", true).replace("{fish}", Integer.toString(fish)));
}
}
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
if (container.has(toolStats.shearsSheared, PersistentDataType.INTEGER)) {
Integer sheep = container.get(toolStats.shearsSheared, PersistentDataType.INTEGER);
if (sheep == null) {
return null;
if (sheep != null) {
lore.add(toolStats.configTools.formatLore("sheep-sheared", "{sheep}", toolStats.numberFormat.formatInt(sheep)));
}
lore.add(toolStats.getLoreFromConfig("sheep-sheared", true).replace("{sheep}", Integer.toString(sheep)));
}
}
if (toolStats.config.getBoolean("enabled.armor-damage")) {
if (container.has(toolStats.armorDamage, PersistentDataType.INTEGER)) {
Integer damage = container.get(toolStats.armorDamage, PersistentDataType.INTEGER);
if (damage == null) {
return null;
if (container.has(toolStats.armorDamage, PersistentDataType.DOUBLE)) {
Double damage = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
if (damage != null) {
lore.add(toolStats.configTools.formatLore("damage-taken", "{damage}", toolStats.numberFormat.formatDouble(damage)));
}
}
}
if (toolStats.config.getBoolean("enabled.arrows-shot")) {
if (container.has(toolStats.arrowsShot, PersistentDataType.INTEGER)) {
Integer arrows = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER);
if (arrows != null) {
lore.add(toolStats.configTools.formatLore("arrows-shot", "{arrows}", toolStats.numberFormat.formatInt(arrows)));
}
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", Integer.toString(damage)));
}
}
finalMeta.setLore(lore);
finalItem.setItemMeta(finalMeta);
return finalItem;
int slot = player.getInventory().getHeldItemSlot();
player.getInventory().setItem(slot, finalItem);
}
@Nullable
@@ -235,13 +321,16 @@ public class CommandToolStats implements TabExecutor {
if (args.length == 1) {
if (sender.hasPermission("toolstats.reload")) {
return Arrays.asList("reset", "reload");
} else {
}
if (sender.hasPermission("toolstats.reset")) {
return Collections.singletonList("reset");
}
}
if (args.length == 2) {
if (args[0].equalsIgnoreCase("reset")) {
return Collections.singletonList("confirm");
if (sender.hasPermission("toolstats.reset.confirm")) {
return Collections.singletonList("confirm");
}
}
}
return null;

View File

@@ -20,98 +20,145 @@ package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
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.BlockBreakEvent;
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 org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class BlocksMined implements Listener {
private final ToolStats toolStats;
private final String[] validTools = {"pickaxe", "axe", "hoe", "shovel", "shear"};
public BlocksMined(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onBreak(BlockBreakEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer();
if (player.getGameMode() != GameMode.SURVIVAL) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) {
PlayerInventory inventory = player.getInventory();
ItemStack heldItem = inventory.getItemInMainHand();
Block block = event.getBlock();
if (block.getType() == Material.CHEST) {
toolStats.playerInteract.openedChests.put(block, player);
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
toolStats.playerInteract.openedChests.remove(block);
}
};
toolStats.scheduleGlobal(runnable, 20);
}
// only check certain items
if (!toolStats.itemChecker.isMineTool(heldItem.getType())) {
return;
}
String itemName = heldItem.getType().toString().toLowerCase();
if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
return;
if (heldItem.getType().toString().toLowerCase(Locale.ROOT).contains("hoe")) {
// player is breaking crops with a hoe
if (block.getBlockData() instanceof Ageable) {
updateCropsMined(heldItem, (Ageable) block.getBlockData());
}
} else {
// update the blocks mined
updateBlocksMined(heldItem);
}
updateBlocksMined(heldItem);
}
private void updateBlocksMined(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
private void updateBlocksMined(ItemStack playerTool) {
ItemMeta meta = playerTool.getItemMeta();
if (meta == null) {
toolStats.logger.warning(playerTool + " does NOT have any meta! Unable to update stats.");
return;
}
// read the current stats from the item
// if they don't exist, then start from 0
Integer blocksMined = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
}
if (blocksMined == null) {
return;
} else {
blocksMined++;
blocksMined = 0;
toolStats.logger.warning(playerTool + " does not have valid generic-mined set! Resting to zero. This should NEVER happen.");
}
container.set(toolStats.genericMined, PersistentDataType.INTEGER, blocksMined);
String configLore = toolStats.getLoreFromConfig("blocks-mined", false);
String configLoreRaw = toolStats.getLoreFromConfig("blocks-mined", true);
container.set(toolStats.genericMined, PersistentDataType.INTEGER, blocksMined + 1);
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(playerTool.getType(), "blocks-mined")) {
String oldBlocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined);
String newBlocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined + 1);
String oldLine = toolStats.configTools.formatLore("blocks-mined", "{blocks}", oldBlocksMinedFormatted);
String newLine = toolStats.configTools.formatLore("blocks-mined", "{blocks}", newBlocksMinedFormatted);
if (oldLine == null || newLine == null) {
return;
}
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(configLore)) {
hasLore = true;
lore.set(x, configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
break;
}
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(configLoreRaw.replace("{blocks}", Integer.toString(blocksMined)));
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
if (toolStats.checkConfig(itemStack, "blocks-mined")) {
meta.setLore(lore);
playerTool.setItemMeta(meta);
}
private void updateCropsMined(ItemStack playerTool, Ageable block) {
// ignore crops that are not fully grown
if (block.getAge() != block.getMaximumAge()) {
return;
}
itemStack.setItemMeta(meta);
ItemMeta meta = playerTool.getItemMeta();
if (meta == null) {
toolStats.logger.warning(playerTool + " does NOT have any meta! Unable to update stats.");
return;
}
// read the current stats from the item
// if they don't exist, then start from 0
Integer cropsMined = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.cropsHarvested, PersistentDataType.INTEGER)) {
cropsMined = container.get(toolStats.cropsHarvested, PersistentDataType.INTEGER);
}
if (cropsMined == null) {
cropsMined = 0;
toolStats.logger.warning(playerTool + " does not have valid crops-mined set! Resting to zero. This should NEVER happen.");
}
container.set(toolStats.cropsHarvested, PersistentDataType.INTEGER, cropsMined + 1);
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(playerTool.getType(), "blocks-mined")) {
String oldCropsMinedFormatted = toolStats.numberFormat.formatInt(cropsMined);
String newCropsMinedFormatted = toolStats.numberFormat.formatInt(cropsMined + 1);
String oldLine = toolStats.configTools.formatLore("crops-harvested", "{crops}", oldCropsMinedFormatted);
String newLine = toolStats.configTools.formatLore("crops-harvested", "{crops}", newCropsMinedFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
playerTool.setItemMeta(meta);
}
}

View File

@@ -18,24 +18,25 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkPopulateEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable;
public class ChunkPopulate implements Listener {
// this tags all elytras with a "new" tag
// this let's use tag any new elytras player loot
// this lets us track any new elytras player loot
private final ToolStats toolStats;
@@ -43,24 +44,31 @@ public class ChunkPopulate implements Listener {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onPopulate(ChunkPopulateEvent event) {
if (event.getChunk().getWorld().getEnvironment() != World.Environment.THE_END) {
return;
}
// this is delayed because entities are not loaded instantly
// we just check 1 second later
Bukkit.getScheduler().runTaskLater(toolStats, () -> {
Chunk chunk = event.getChunk();
for (Entity entity : chunk.getEntities()) {
if (entity instanceof ItemFrame) {
Chunk chunk = event.getChunk();
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
for (Entity entity : chunk.getEntities()) {
// if there is a new item frame
if (!(entity instanceof ItemFrame)) {
continue;
}
ItemFrame itemFrame = (ItemFrame) entity;
// if the item frame has an elytra
if (itemFrame.getItem().getType() == Material.ELYTRA) {
ItemStack elytraCopy = itemFrame.getItem();
ItemMeta meta = elytraCopy.getItemMeta();
if (meta == null) {
return;
continue;
}
// add the new tag so we know it's new
PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(toolStats.newElytra, PersistentDataType.INTEGER, 1);
elytraCopy.setItemMeta(meta);
@@ -68,6 +76,7 @@ public class ChunkPopulate implements Listener {
}
}
}
}, 20);
};
toolStats.scheduleRegion(runnable, chunk.getWorld(), chunk, 20);
}
}

View File

@@ -18,11 +18,13 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.ChatColor;
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.inventory.CraftItemEvent;
import org.bukkit.inventory.ItemStack;
@@ -30,93 +32,112 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.text.SimpleDateFormat;
import java.util.*;
public class CraftItem implements Listener {
private final ToolStats toolStats;
public final String[] validItems = {
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
};
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
public CraftItem(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onCraft(CraftItemEvent event) {
if (event.isCancelled()) {
return;
}
Player player = (Player) event.getWhoClicked();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
ItemStack itemStack = event.getCurrentItem();
if (itemStack == null || itemStack.getType() == Material.AIR) {
return;
}
String name = itemStack.getType().toString().toLowerCase(Locale.ROOT);
for (String x : validItems) {
if (name.contains(x)) {
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.crafting");
if (configMessage != null) {
if (configMessage.length() != 0) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
// only check certain items
if (!toolStats.itemChecker.isValidItem(itemStack.getType())) {
return;
}
// if the player shift clicks, send them this warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.crafting");
if (configMessage != null) {
if (!configMessage.isEmpty()) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
if (addLore(itemStack, player) == null) {
return;
}
event.setCurrentItem(addLore(itemStack, player));
}
}
// test the item before setting it
ItemStack newItem = addLore(itemStack, player);
if (newItem != null) {
// set the result
event.setCurrentItem(newItem);
}
}
/**
* Adds crafted tags to item.
*
* @param itemStack The item add item to.
* @param owner The player crafting.
* @return A copy of the item with the tags + lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
// clone the item
ItemStack newItem = itemStack.clone();
ItemMeta meta = newItem.getItemMeta();
if (meta == null) {
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats.");
return null;
}
// get the current time
long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has the tag
// this is to prevent duplicate tags
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return null;
}
// 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.genericOwner, new UUIDDataType(), owner.getUniqueId());
String createdByRaw = toolStats.getLoreFromConfig("created.created-by", true);
String createdOnRaw = toolStats.getLoreFromConfig("created.created-on", true);
if (createdOnRaw == null) {
toolStats.logger.warning("There is no lore message for messages.created.created-on!");
return null;
}
if (createdByRaw == null) {
toolStats.logger.warning("There is no lore message for messages.created.created-by!");
return null;
}
container.set(toolStats.originType, PersistentDataType.INTEGER, 0);
List<String> lore;
// get the current lore the item
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
if (toolStats.checkConfig(itemStack, "created-date")) {
lore.add(createdOnRaw.replace("{date}", format.format(finalDate)));
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(itemStack.getType(), "created-date")) {
String date = toolStats.numberFormat.formatDate(finalDate);
String newLine = toolStats.configTools.formatLore("created.created-on", "{date}", date);
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.setLore(lore);
}
if (toolStats.checkConfig(itemStack, "created-by")) {
lore.add(createdByRaw.replace("{player}", owner.getName()));
if (toolStats.configTools.checkConfig(itemStack.getType(), "created-by")) {
String newLine = toolStats.configTools.formatLore("created.created-by", "{player}", owner.getName());
if (newLine == null) {
return null;
}
lore.add(newLine);
meta.setLore(lore);
}
meta.setLore(lore);
newItem.setItemMeta(meta);
return newItem;
}

View File

@@ -0,0 +1,114 @@
/*
* 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 lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCreativeEvent;
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.List;
public class CreativeEvent implements Listener {
private final ToolStats toolStats;
public CreativeEvent(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onCreativeEvent(InventoryCreativeEvent event) {
Player player = (Player) event.getWhoClicked();
// make sure they are in creative mode
if (player.getGameMode() != GameMode.CREATIVE) {
return;
}
ItemStack spawnedItem = event.getCursor();
if (!toolStats.itemChecker.isValidItem(spawnedItem.getType())) {
return;
}
ItemMeta spawnedItemMeta = spawnedItem.getItemMeta();
if (spawnedItemMeta == null) {
return;
}
// 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
PersistentDataContainer container = spawnedItemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
return;
}
// add the tags to the item
ItemStack newItem = addLore(spawnedItem, player);
if (newItem != null) {
event.setCursor(newItem);
}
}
/**
* Adds tags to newly spawned items in creative.
*
* @param spawnedItem The item.
*/
private ItemStack addLore(ItemStack spawnedItem, Player owner) {
ItemStack newSpawnedItem = spawnedItem.clone();
ItemMeta meta = newSpawnedItem.getItemMeta();
if (meta == null) {
toolStats.logger.warning(newSpawnedItem + " does NOT have any meta! Unable to update stats.");
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer();
// if the item already has an origin set, don't add it again
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
return null;
}
// only make the hash if it's enabled
if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(spawnedItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 6);
if (toolStats.configTools.checkConfig(newSpawnedItem.getType(), "spawned-in")) {
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.setLore(newLore);
}
newSpawnedItem.setItemMeta(meta);
return newSpawnedItem;
}
}

View File

@@ -22,6 +22,7 @@ import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
@@ -32,247 +33,284 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
public class EntityDamage implements Listener {
private final ToolStats toolStats;
private final String[] validTools = {"sword", "trident", "axe"};
private final DecimalFormat decimalFormat = new DecimalFormat("0.00");
public final Set<UUID> trackedMobs = new HashSet<>();
private final List<EntityDamageEvent.DamageCause> ignoredCauses = Arrays.asList(EntityDamageEvent.DamageCause.SUICIDE, EntityDamageEvent.DamageCause.VOID, EntityDamageEvent.DamageCause.CUSTOM, EntityDamageEvent.DamageCause.KILL);
public EntityDamage(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onDamage(EntityDamageByEntityEvent event) {
if (event.isCancelled()) {
return;
}
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity livingEntity = (LivingEntity) event.getEntity();
LivingEntity mobBeingAttacked = (LivingEntity) event.getEntity();
// ignore void and /kill damage
EntityDamageEvent.DamageCause cause = event.getCause();
if (ignoredCauses.contains(cause)) {
return;
}
// mob is going to die
if (livingEntity.getHealth() - event.getFinalDamage() <= 0) {
if (mobBeingAttacked.getHealth() - event.getFinalDamage() <= 0) {
// a player is killing something
if (event.getDamager() instanceof Player) {
Player player = (Player) event.getDamager();
if (player.getGameMode() != GameMode.SURVIVAL) {
Player attackingPlayer = (Player) event.getDamager();
if (attackingPlayer.getGameMode() == GameMode.CREATIVE || attackingPlayer.getGameMode() == GameMode.SPECTATOR) {
return;
}
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) {
return;
}
String itemName = heldItem.getType().toString().toLowerCase();
if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
PlayerInventory attackingPlayerInventory = attackingPlayer.getInventory();
ItemStack heldItem = attackingPlayerInventory.getItemInMainHand();
// only check certain items
if (!toolStats.itemChecker.isMeleeWeapon(heldItem.getType())) {
return;
}
// a player is killing another player
if (livingEntity instanceof Player) {
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updatePlayerKills(heldItem));
if (mobBeingAttacked instanceof Player) {
updatePlayerKills(heldItem);
return;
}
// player is killing regular mob
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updateMobKills(heldItem));
trackedMobs.add(livingEntity.getUniqueId());
updateMobKills(heldItem);
trackedMobs.add(mobBeingAttacked.getUniqueId());
}
// trident is being thrown at something
if (event.getDamager() instanceof Trident) {
Trident trident = (Trident) event.getDamager();
ItemStack clone;
if (livingEntity instanceof Player) {
clone = updatePlayerKills(trident.getItem());
ItemStack newTrident;
// trident is killing player
if (mobBeingAttacked instanceof Player) {
newTrident = tridentPlayerKills(trident.getItem());
} else {
clone = updateMobKills(trident.getItem());
// trident is killing a mob
newTrident = tridentMobKills(trident.getItem());
trackedMobs.add(mobBeingAttacked.getUniqueId());
}
if (clone == null) {
return;
if (newTrident != null) {
trident.setItem(newTrident);
}
trident.setItem(clone);
}
// arrow is being shot
if (event.getDamager() instanceof Arrow) {
Arrow arrow = (Arrow) event.getDamager();
// if the shooter is a player
if (arrow.getShooter() instanceof Player) {
Player player = (Player) arrow.getShooter();
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null) {
Player shootingPlayer = (Player) arrow.getShooter();
if (shootingPlayer.getGameMode() == GameMode.CREATIVE || shootingPlayer.getGameMode() == GameMode.SPECTATOR) {
return;
}
if (heldItem.getType() == Material.BOW || heldItem.getType() == Material.CROSSBOW) {
if (livingEntity instanceof Player) {
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updatePlayerKills(heldItem));
} else {
player.getInventory().setItem(player.getInventory().getHeldItemSlot(), updateMobKills(heldItem));
}
PlayerInventory inventory = shootingPlayer.getInventory();
boolean isMainHand = inventory.getItemInMainHand().getType() == Material.BOW || inventory.getItemInMainHand().getType() == Material.CROSSBOW;
boolean isOffHand = inventory.getItemInOffHand().getType() == Material.BOW || inventory.getItemInMainHand().getType() == Material.CROSSBOW;
ItemStack heldBow = null;
if (isMainHand) {
heldBow = inventory.getItemInMainHand();
}
if (isOffHand) {
heldBow = inventory.getItemInOffHand();
}
// if the player is holding a bow in both hands
// default to main hand since that takes priority
if (isMainHand && isOffHand) {
heldBow = inventory.getItemInMainHand();
}
// player swapped
if (heldBow == null) {
return;
}
// player is shooting another player
if (mobBeingAttacked instanceof Player) {
updatePlayerKills(heldBow);
} else {
updateMobKills(heldBow);
trackedMobs.add(mobBeingAttacked.getUniqueId());
}
}
}
}
// player is taken damage but not being killed
if (livingEntity instanceof Player) {
Player player = (Player) livingEntity;
PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) {
updateArmorDamage(armor, event.getDamage());
if (mobBeingAttacked instanceof Player) {
Player playerTakingDamage = (Player) mobBeingAttacked;
if (playerTakingDamage.getGameMode() == GameMode.CREATIVE || playerTakingDamage.getGameMode() == GameMode.SPECTATOR) {
return;
}
PlayerInventory playerInventory = playerTakingDamage.getInventory();
for (ItemStack armorPiece : playerInventory.getArmorContents()) {
if (armorPiece != null) {
if (toolStats.itemChecker.isArmor(armorPiece.getType())) {
updateDamage(armorPiece, event.getFinalDamage());
}
}
}
}
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onDamage(EntityDamageEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity livingEntity = (LivingEntity) event.getEntity();
if (livingEntity instanceof Player) {
Player player = (Player) livingEntity;
PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) {
updateArmorDamage(armor, event.getDamage());
// ignore void and /kill damage
EntityDamageEvent.DamageCause cause = event.getCause();
if (ignoredCauses.contains(cause)) {
return;
}
LivingEntity mobBeingAttacked = (LivingEntity) event.getEntity();
// player is taken damage but not being killed
if (mobBeingAttacked instanceof Player) {
Player playerTakingDamage = (Player) mobBeingAttacked;
if (playerTakingDamage.getGameMode() == GameMode.CREATIVE || playerTakingDamage.getGameMode() == GameMode.SPECTATOR) {
return;
}
PlayerInventory playerInventory = playerTakingDamage.getInventory();
for (ItemStack armorPiece : playerInventory.getArmorContents()) {
if (armorPiece != null) {
if (toolStats.itemChecker.isArmor(armorPiece.getType())) {
updateDamage(armorPiece, event.getFinalDamage());
}
}
}
}
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onDamage(EntityDamageByBlockEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity livingEntity = (LivingEntity) event.getEntity();
if (livingEntity instanceof Player) {
Player player = (Player) livingEntity;
PlayerInventory inventory = player.getInventory();
for (ItemStack armor : inventory.getArmorContents()) {
if (armor != null) {
updateArmorDamage(armor, event.getDamage());
// ignore void and /kill damage
EntityDamageEvent.DamageCause cause = event.getCause();
if (ignoredCauses.contains(cause)) {
return;
}
LivingEntity mobBeingAttacked = (LivingEntity) event.getEntity();
// player is taken damage but not being killed
if (mobBeingAttacked instanceof Player) {
Player playerTakingDamage = (Player) mobBeingAttacked;
if (playerTakingDamage.getGameMode() == GameMode.CREATIVE || playerTakingDamage.getGameMode() == GameMode.SPECTATOR) {
return;
}
PlayerInventory playerInventory = playerTakingDamage.getInventory();
for (ItemStack armorPiece : playerInventory.getArmorContents()) {
if (armorPiece != null) {
if (toolStats.itemChecker.isArmor(armorPiece.getType())) {
updateDamage(armorPiece, event.getFinalDamage());
}
}
}
}
}
private ItemStack updatePlayerKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta();
/**
* Updates a weapon's player kills.
*
* @param itemStack The item to update.
*/
private void updatePlayerKills(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return null;
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats.");
return;
}
Integer playerKills = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
playerKills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
}
if (playerKills == null) {
return null;
} else {
playerKills++;
}
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills);
String playerKillsLore = toolStats.getLoreFromConfig("kills.player", false);
String playerKillsLoreRaw = toolStats.getLoreFromConfig("kills.player", true);
if (playerKillsLore == null || playerKillsLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.kills.player!");
return null;
playerKills = 0;
toolStats.logger.warning(itemStack + " does not have valid player-kills set! Resting to zero. This should NEVER happen.");
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(playerKillsLore)) {
hasLore = true;
lore.set(x, playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
break;
}
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills + 1);
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(itemStack.getType(), "player-kills")) {
String oldPlayerKillsFormatted = toolStats.numberFormat.formatInt(playerKills);
String newPlayerKillsFormatted = toolStats.numberFormat.formatInt(playerKills + 1);
String oldLine = toolStats.configTools.formatLore("kills.player", "{kills}", oldPlayerKillsFormatted);
String newLine = toolStats.configTools.formatLore("kills.player", "{kills}", newPlayerKillsFormatted);
if (oldLine == null || newLine == null) {
return;
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(playerKillsLoreRaw.replace("{kills}", Integer.toString(playerKills)));
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
if (toolStats.checkConfig(itemStack, "player-kills")) {
meta.setLore(lore);
}
finalItem.setItemMeta(meta);
return finalItem;
itemStack.setItemMeta(meta);
}
private ItemStack updateMobKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta();
/**
* Updates a weapon's mob kills.
*
* @param itemStack The item to update.
*/
private void updateMobKills(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return null;
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats.");
return;
}
Integer mobKills = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
mobKills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
}
if (mobKills == null) {
return null;
} else {
mobKills++;
}
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills);
String mobKillsLore = toolStats.getLoreFromConfig("kills.mob", false);
String mobKillsLoreRaw = toolStats.getLoreFromConfig("kills.mob", true);
if (mobKillsLore == null || mobKillsLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.kills.mob!");
return null;
mobKills = 0;
toolStats.logger.warning(itemStack + " does not have valid mob-kills set! Resting to zero. This should NEVER happen.");
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(mobKillsLore)) {
hasLore = true;
lore.set(x, mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
break;
}
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills + 1);
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(itemStack.getType(), "mob-kills")) {
String oldMobKillsFormatted = toolStats.numberFormat.formatInt(mobKills);
String newMobKillsFormatted = toolStats.numberFormat.formatInt(mobKills + 1);
String oldLine = toolStats.configTools.formatLore("kills.mob", "{kills}", oldMobKillsFormatted);
String newLine = toolStats.configTools.formatLore("kills.mob", "{kills}", newMobKillsFormatted);
if (oldLine == null || newLine == null) {
return;
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(mobKillsLoreRaw.replace("{kills}", Integer.toString(mobKills)));
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
if (toolStats.checkConfig(itemStack, "mob-kills")) {
meta.setLore(lore);
}
finalItem.setItemMeta(meta);
return finalItem;
itemStack.setItemMeta(meta);
}
private void updateArmorDamage(ItemStack itemStack, double damage) {
/**
* Updates a player's armor damage stats.
*
* @param itemStack The armor piece.
* @param damage How much damage is being added.
*/
private void updateDamage(ItemStack itemStack, double damage) {
// ignore if the damage is zero or negative
if (damage < 0) {
return;
}
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
toolStats.logger.warning(itemStack + " does NOT have any meta! Unable to update stats.");
return;
}
Double damageTaken = 0.0;
@@ -280,48 +318,107 @@ public class EntityDamage implements Listener {
if (container.has(toolStats.armorDamage, PersistentDataType.DOUBLE)) {
damageTaken = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
}
if (damageTaken == null) {
return;
} else {
damageTaken = damageTaken + damage;
}
decimalFormat.setRoundingMode(RoundingMode.DOWN);
container.set(toolStats.armorDamage, PersistentDataType.DOUBLE, damageTaken);
String damageTakenLore = toolStats.getLoreFromConfig("damage-taken", false);
String damageTakenLoreRaw = toolStats.getLoreFromConfig("damage-taken", true);
if (damageTakenLore == null || damageTakenLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.damage-taken!");
return;
damageTaken = 0.0;
toolStats.logger.warning(itemStack + " does not have valid damage-taken set! Resting to zero. This should NEVER happen.");
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(damageTakenLore)) {
hasLore = true;
lore.set(x, damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
break;
}
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(damageTakenLoreRaw.replace("{damage}", decimalFormat.format(damageTaken)));
}
container.set(toolStats.armorDamage, PersistentDataType.DOUBLE, damageTaken + damage);
if (toolStats.config.getBoolean("enabled.armor-damage")) {
meta.setLore(lore);
String oldDamageFormatted = toolStats.numberFormat.formatDouble(damageTaken);
String newDamageFormatted = toolStats.numberFormat.formatDouble(damageTaken + damage);
String oldLine = toolStats.configTools.formatLore("damage-taken", "{damage}", oldDamageFormatted);
String newLine = toolStats.configTools.formatLore("damage-taken", "{damage}", newDamageFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
}
/**
* Updates a trident's mob kills.
*
* @param trident The item to update.
*/
private ItemStack tridentMobKills(ItemStack trident) {
ItemStack newTrident = trident.clone();
ItemMeta meta = newTrident.getItemMeta();
if (meta == null) {
toolStats.logger.warning(newTrident + " does NOT have any meta! Unable to update stats.");
return null;
}
Integer mobKills = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
mobKills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
}
if (mobKills == null) {
mobKills = 0;
toolStats.logger.warning(newTrident + " does not have valid mob-kills set! Resting to zero. This should NEVER happen.");
}
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills + 1);
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(newTrident.getType(), "mob-kills")) {
String oldMobKillsFormatted = toolStats.numberFormat.formatDouble(mobKills);
String newMobKillsFormatted = toolStats.numberFormat.formatDouble(mobKills + 1);
String oldLine = toolStats.configTools.formatLore("kills.mob", "{kills}", oldMobKillsFormatted);
String newLine = toolStats.configTools.formatLore("kills.mob", "{kills}", newMobKillsFormatted);
if (oldLine == null || newLine == null) {
return null;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
newTrident.setItemMeta(meta);
return newTrident;
}
/**
* Updates a trident's player kills.
*
* @param trident The item to update.
*/
private ItemStack tridentPlayerKills(ItemStack trident) {
ItemStack newTrident = trident.clone();
ItemMeta meta = newTrident.getItemMeta();
if (meta == null) {
toolStats.logger.warning(newTrident + " does NOT have any meta! Unable to update stats.");
return null;
}
Integer playerKills = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
playerKills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
}
if (playerKills == null) {
playerKills = 0;
toolStats.logger.warning(newTrident + " does not have valid player-kills set! Resting to zero. This should NEVER happen.");
}
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills + 1);
// do we add the lore based on the config?
if (toolStats.configTools.checkConfig(newTrident.getType(), "player-kills")) {
String oldPlayerKillsFormatted = toolStats.numberFormat.formatDouble(playerKills);
String newPlayerKillsFormatted = toolStats.numberFormat.formatDouble(playerKills + 1);
String oldLine = toolStats.configTools.formatLore("kills.player", "{kills}", oldPlayerKillsFormatted);
String newLine = toolStats.configTools.formatLore("kills.player", "{kills}", newPlayerKillsFormatted);
if (oldLine == null || newLine == null) {
return null;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
newTrident.setItemMeta(meta);
return newTrident;
}
}

View File

@@ -21,10 +21,13 @@ import lol.hyper.toolstats.ToolStats;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.*;
@@ -36,19 +39,29 @@ public class EntityDeath implements Listener {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onDeath(EntityDeathEvent event) {
LivingEntity livingEntity = event.getEntity();
if (livingEntity instanceof Player) {
return;
}
UUID livingEntityUUID = event.getEntity().getUniqueId();
// if it's a mob we are tracking that matters
if (toolStats.mobKill.trackedMobs.contains(livingEntityUUID)) {
for (ItemStack current : event.getDrops()) {
String name = current.getType().toString().toLowerCase(Locale.ROOT);
for (String item : toolStats.craftItem.validItems) {
if (name.contains(item)) {
addLore(current, livingEntity.getName());
for (int i = 0; i < event.getDrops().size(); i++) {
ItemStack droppedItem = event.getDrops().get(i);
ItemMeta droppedItemMeta = droppedItem.getItemMeta();
if (droppedItemMeta != null) {
PersistentDataContainer container = droppedItemMeta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
continue; // ignore any items that have our tags
}
}
if (toolStats.itemChecker.isValidItem(droppedItem.getType())) {
ItemStack newItem = addLore(droppedItem, livingEntity.getName());
if (newItem != null) {
event.getDrops().set(i, newItem);
}
}
}
@@ -56,42 +69,28 @@ public class EntityDeath implements Listener {
}
}
private void addLore(ItemStack itemStack, String mob) {
ItemMeta meta = itemStack.getItemMeta();
/**
* Adds "drop by" tag to item.
*
* @param oldItem The item to add lore to.
* @param mob The mob or player name.
*/
private ItemStack addLore(ItemStack oldItem, String mob) {
ItemStack newItem = oldItem.clone();
ItemMeta meta = newItem.getItemMeta();
if (meta == null) {
return;
}
boolean hasTag = false;
String droppedByLore = toolStats.getLoreFromConfig("dropped-by", false);
String droppedByLoreRaw = toolStats.getLoreFromConfig("dropped-by", true);
if (droppedByLore == null || droppedByLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.dropped-by!");
return;
return null;
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(droppedByLore)) {
// replace existing tag
lore.set(x, droppedByLoreRaw.replace("{name}", mob));
hasTag = true;
}
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
}
if (!hasTag) {
lore.add(droppedByLoreRaw.replace("{name}", mob));
}
PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(toolStats.originType, PersistentDataType.INTEGER, 1);
if (toolStats.config.getBoolean("enabled.dropped-by")) {
meta.setLore(lore);
String newLine = toolStats.configTools.formatLore("dropped-by", "{name}", mob);
List<String> newLore = toolStats.itemLore.addItemLore(meta, newLine);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -18,63 +18,80 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.Bukkit;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.LootGenerateEvent;
import org.bukkit.inventory.Inventory;
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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class GenerateLoot implements Listener {
private final ToolStats toolStats;
public final String[] validItems = {
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
};
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
public GenerateLoot(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onGenerateLoot(LootGenerateEvent event) {
InventoryHolder inventoryHolder = event.getInventoryHolder();
if (inventoryHolder == null) {
return;
}
Inventory chest = inventoryHolder.getInventory();
Bukkit.getScheduler().runTaskLater(toolStats, () -> {
Player player = (Player) chest.getViewers().get(0);
for (int i = 0; i < chest.getContents().length; i++) {
ItemStack itemStack = chest.getItem(i);
if (itemStack == null || itemStack.getType() == Material.AIR) {
continue;
}
String name = itemStack.getType().toString().toLowerCase(Locale.ROOT);
for (String x : validItems) {
if (name.contains(x)) {
chest.setItem(i, addLore(itemStack, player));
Location lootLocation = event.getLootContext().getLocation();
if (inventoryHolder instanceof Chest) {
Block openedChest = null;
// look at the current list of opened chest and get the distance
// between the LootContext location and chest location
// if the distance is less than 1, it's the same chest
for (Block chest : toolStats.playerInteract.openedChests.keySet()) {
Location chestLocation = chest.getLocation();
if (chest.getWorld() == lootLocation.getWorld()) {
double distance = lootLocation.distance(chestLocation);
if (distance <= 1.0) {
openedChest = chest;
}
}
}
// ignore if the chest is not in the same location
if (openedChest == null) {
return;
}
},1);
Player player = toolStats.playerInteract.openedChests.get(openedChest);
setLoot(event.getLoot(), player);
}
if (inventoryHolder instanceof StorageMinecart) {
StorageMinecart mineCart = (StorageMinecart) inventoryHolder;
if (toolStats.playerInteract.openedMineCarts.containsKey(mineCart)) {
Player player = toolStats.playerInteract.openedMineCarts.get(mineCart);
setLoot(event.getLoot(), player);
}
}
}
/**
* Adds lore to newly generated items.
*
* @param itemStack The item to add lore to.
* @param owner The player that found the item.
* @return The item with the lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemStack newItem = itemStack.clone();
ItemMeta meta = itemStack.getItemMeta();
@@ -89,30 +106,44 @@ public class GenerateLoot implements Listener {
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.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 2);
String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true);
String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true);
if (foundByLoreRaw == null || foundOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.looted!");
return null;
if (toolStats.configTools.checkConfig(newItem.getType(), "looted-tag")) {
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.setLore(newLore);
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
if (toolStats.checkConfig(newItem, "looted-tag")) {
lore.add(foundOnLoreRaw.replace("{date}", format.format(finalDate)));
lore.add(foundByLoreRaw.replace("{player}", owner.getName()));
}
meta.setLore(lore);
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 = addLore(itemStack, player);
if (newItem != null) {
loot.set(i, newItem);
}
}
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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 lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
public class InventoryOpen implements Listener {
private final ToolStats toolStats;
public InventoryOpen(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onOpen(InventoryOpenEvent event) {
if (event.isCancelled()) {
return;
}
Inventory inventory = event.getInventory();
Location location = event.getInventory().getLocation();
for (ItemStack itemStack : inventory) {
if (itemStack == null) {
continue;
}
// ignore items that are not the right type
if (!toolStats.itemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) {
continue;
}
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// generate a hash if the item doesn't have one (if it's enabled in the config)
if (toolStats.config.getBoolean("generate-hash-for-items")) {
if (!container.has(toolStats.hash, PersistentDataType.STRING)) {
// make sure the item has an owner
if (!container.has(toolStats.genericOwner, new UUIDDataType())) {
continue;
}
UUID owner = container.get(toolStats.genericOwner, new UUIDDataType());
if (owner == null) {
continue;
}
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (timestamp == null) {
continue;
}
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
toolStats.logger.info(hash);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
}
}
ItemMeta clone = itemMeta.clone();
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
itemStack.setItemMeta(clone);
}
};
if (location != null) {
toolStats.scheduleRegion(runnable, location.getWorld(), location.getChunk(), 1);
}
}
}
}

View File

@@ -18,11 +18,12 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.inventory.ItemStack;
@@ -30,75 +31,82 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class PickupItem implements Listener {
private final ToolStats toolStats;
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
public PickupItem(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onPickup(EntityPickupItemEvent event) {
if (event.isCancelled()) {
return;
}
Entity entity = event.getEntity();
if (entity instanceof Player) {
ItemStack itemStack = event.getItem().getItemStack();
if (itemStack.getType() == Material.ELYTRA) {
Player player = (Player) entity;
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
Item item = event.getItem();
if (item.getType() == EntityType.DROPPED_ITEM) {
ItemStack itemStack = event.getItem().getItemStack();
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return;
}
PersistentDataContainer container = meta.getPersistentDataContainer();
// the elytra has the new key, set the lore to it
if (container.has(toolStats.newElytra, PersistentDataType.INTEGER)) {
container.remove(toolStats.newElytra);
addLore(itemStack, (Player) event.getEntity());
if (itemStack.getType() == Material.ELYTRA) {
// the elytra has the new key, set the lore to it
if (container.has(toolStats.newElytra, PersistentDataType.INTEGER)) {
ItemStack newElytra = addLore(itemStack, (Player) event.getEntity());
if (newElytra != null) {
item.setItemStack(newElytra);
}
}
}
}
}
}
private void addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
/**
* Adds "looted by" tags for elytras.
*
* @param itemStack The elytra to add lore to.
* @param owner The player who found it.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta();
if (meta == null) {
return;
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer();
// only make the hash if it's enabled
if (toolStats.config.getBoolean("generate-hash-for-items")) {
String hash = toolStats.hashMaker.makeHash(finalItem.getType(), owner.getUniqueId(), timeCreated);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
}
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 4);
container.remove(toolStats.newElytra);
String foundByLoreRaw = toolStats.getLoreFromConfig("looted.found-by", true);
String foundOnLoreRaw = toolStats.getLoreFromConfig("looted.found-on", true);
if (foundByLoreRaw == null || foundOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.looted!");
return;
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
if (toolStats.config.getBoolean("enabled.elytra-tag")) {
lore.add(foundOnLoreRaw.replace("{date}", format.format(finalDate)));
lore.add(foundByLoreRaw.replace("{player}", owner.getName()));
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.setLore(newLore);
}
meta.setLore(lore);
itemStack.setItemMeta(meta);
finalItem.setItemMeta(meta);
return finalItem;
}
}

View File

@@ -18,37 +18,34 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerFishEvent;
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 org.jetbrains.annotations.Nullable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class PlayerFish implements Listener {
private final ToolStats toolStats;
public final String[] validItems = {
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
};
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
public PlayerFish(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onFish(PlayerFishEvent event) {
if (event.isCancelled()) {
return;
@@ -59,25 +56,62 @@ public class PlayerFish implements Listener {
}
Player player = event.getPlayer();
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.FISHING_ROD) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
updateFishCount(heldItem);
ItemStack fishingRod = getItemStack(player);
// player swapped items?
if (fishingRod == null) {
return;
}
// update the fishing rod!
updateFishCount(fishingRod);
// check if the player caught an item
if (event.getCaught() == null) {
return;
}
ItemStack caughtItem = ((Item) event.getCaught()).getItemStack();
for (String x : validItems) {
if (caughtItem.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
addNewLore(caughtItem, player);
Item caughtItemEntity = (Item) event.getCaught();
if (toolStats.itemChecker.isValidItem(caughtItem.getType())) {
ItemStack newItem = addNewLore(caughtItem, player);
if (newItem != null) {
caughtItemEntity.setItemStack(newItem);
}
}
}
private void updateFishCount(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
private static @Nullable ItemStack getItemStack(Player player) {
PlayerInventory inventory = player.getInventory();
boolean isMainHand = inventory.getItemInMainHand().getType() == Material.FISHING_ROD;
boolean isOffHand = inventory.getItemInOffHand().getType() == Material.FISHING_ROD;
ItemStack fishingRod = null;
if (isMainHand) {
fishingRod = inventory.getItemInMainHand();
}
if (isOffHand) {
fishingRod = inventory.getItemInOffHand();
}
// if the player is hold fishing rods in both hands
// default to main hand since that takes priority
if (isMainHand && isOffHand) {
fishingRod = inventory.getItemInMainHand();
}
return fishingRod;
}
/**
* Update a fishing rod's fish count.
*
* @param fishingRod The fishing rod to update.
*/
private void updateFishCount(ItemStack fishingRod) {
ItemMeta meta = fishingRod.getItemMeta();
if (meta == null) {
toolStats.logger.warning(fishingRod + " does NOT have any meta! Unable to update stats.");
return;
}
Integer fishCaught = 0;
@@ -85,86 +119,62 @@ public class PlayerFish implements Listener {
if (container.has(toolStats.fishingRodCaught, PersistentDataType.INTEGER)) {
fishCaught = container.get(toolStats.fishingRodCaught, PersistentDataType.INTEGER);
}
if (fishCaught == null) {
return;
} else {
fishCaught++;
}
container.set(toolStats.fishingRodCaught, PersistentDataType.INTEGER, fishCaught);
String fishCaughtLore = toolStats.getLoreFromConfig("fished.fish-caught", false);
String fishCaughtLoreRaw = toolStats.getLoreFromConfig("fished.fish-caught", true);
if (fishCaughtLore == null || fishCaughtLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.fish-caught!");
return;
fishCaught = 0;
toolStats.logger.warning(fishingRod + " does not have valid fish-caught set! Resting to zero. This should NEVER happen.");
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(fishCaughtLore)) {
hasLore = true;
lore.set(x, fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
break;
}
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(fishCaughtLoreRaw.replace("{fish}", Integer.toString(fishCaught)));
}
container.set(toolStats.fishingRodCaught, PersistentDataType.INTEGER, fishCaught + 1);
if (toolStats.config.getBoolean("enabled.fish-caught")) {
meta.setLore(lore);
String oldFishFormatted = toolStats.numberFormat.formatInt(fishCaught);
String newFishFormatted = toolStats.numberFormat.formatInt(fishCaught + 1);
String oldLine = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", oldFishFormatted);
String newLine = toolStats.configTools.formatLore("fished.fish-caught", "{fish}", newFishFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
fishingRod.setItemMeta(meta);
}
private void addNewLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
/**
* Add lore to newly caught item.
*
* @param originalItem The original item to add lore.
* @param owner The player who caught it.
* @return A copy of the new item with lore.
*/
private ItemStack addNewLore(ItemStack originalItem, Player owner) {
ItemStack newItem = originalItem.clone();
ItemMeta meta = originalItem.getItemMeta();
if (meta == null) {
return;
return null;
}
long timeCreated = System.currentTimeMillis();
Date finalDate = new Date(timeCreated);
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.timeCreated, PersistentDataType.LONG) || container.has(toolStats.genericOwner, PersistentDataType.LONG)) {
return;
return null;
}
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.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 5);
String caughtByLoreRaw = toolStats.getLoreFromConfig("fished.caught-by", true);
String caughtOnLoreRaw = toolStats.getLoreFromConfig("fished.caught-on", true);
if (caughtByLoreRaw == null || caughtOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.fished!");
return;
if (toolStats.configTools.checkConfig(newItem.getType(), "fished-tag")) {
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.setLore(newLore);
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
if (toolStats.checkConfig(itemStack, "fished-tag")) {
lore.add(caughtOnLoreRaw.replace("{date}", format.format(finalDate)));
lore.add(caughtByLoreRaw.replace("{player}", owner.getName()));
}
meta.setLore(lore);
itemStack.setItemMeta(meta);
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
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.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.HashMap;
import java.util.Map;
public class PlayerInteract implements Listener {
private final ToolStats toolStats;
public final Map<Block, Player> openedChests = new HashMap<>();
public final Map<StorageMinecart, Player> openedMineCarts = new HashMap<>();
public PlayerInteract(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onInteract(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
Block block = event.getClickedBlock();
if (block == null) {
return;
}
Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
// store when a player opens a chest
if (block.getType() != Material.AIR && block.getType() == Material.CHEST) {
openedChests.put(block, player);
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
openedChests.remove(block);
}
};
toolStats.scheduleGlobal(runnable, 20);
}
}
@EventHandler
public void onInteract(PlayerInteractEntityEvent event) {
Entity clicked = event.getRightClicked();
Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
// store when a player opens a minecart
if (clicked.getType() == EntityType.MINECART_CHEST) {
StorageMinecart storageMinecart = (StorageMinecart) clicked;
openedMineCarts.put(storageMinecart, player);
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
openedMineCarts.remove(storageMinecart);
}
};
toolStats.scheduleGlobal(runnable, 20);
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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 lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
public class PlayerJoin implements Listener {
private final ToolStats toolStats;
public PlayerJoin(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
Inventory inventory = player.getInventory();
for (ItemStack itemStack : inventory) {
if (itemStack == null) {
continue;
}
// ignore items that are not the right type
if (!toolStats.itemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) {
continue;
}
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// generate a hash if the item doesn't have one
if (!container.has(toolStats.hash, PersistentDataType.STRING)) {
// make sure the item has an owner
if (!container.has(toolStats.genericOwner, new UUIDDataType())) {
continue;
}
UUID owner = container.get(toolStats.genericOwner, new UUIDDataType());
if (owner == null) {
continue;
}
Long timestamp = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (timestamp == null) {
continue;
}
String hash = toolStats.hashMaker.makeHash(itemStack.getType(), owner, timestamp);
container.set(toolStats.hash, PersistentDataType.STRING, hash);
}
ItemMeta clone = itemMeta.clone();
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
itemStack.setItemMeta(clone);
}
};
toolStats.scheduleEntity(runnable, player, 1);
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.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.player.PlayerMoveEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PlayerMove implements Listener {
private final ToolStats toolStats;
private final Map<Player, Long> playerStartFlight = new HashMap<>();
public PlayerMove(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onCraft(PlayerMoveEvent event) {
Player player = event.getPlayer();
// player starts to fly
if (player.isGliding()) {
// if they are flying, and we don't have them tracked, add them
if (!playerStartFlight.containsKey(player)) {
playerStartFlight.put(player, System.currentTimeMillis());
}
} else {
// player is not flying
if (playerStartFlight.containsKey(player)) {
trackFlight(player, playerStartFlight.get(player));
playerStartFlight.remove(player);
}
}
}
private void trackFlight(Player player, long startTime) {
ItemStack chest = player.getInventory().getChestplate();
// make sure their chest piece is an elytra
if (chest == null || chest.getType() != Material.ELYTRA) {
return;
}
ItemMeta meta = chest.getItemMeta();
if (meta == null) {
toolStats.logger.warning(chest + " does NOT have any meta! Unable to update stats.");
return;
}
// read the current stats from the item
// if they don't exist, then start from 0
Long flightTime = 0L;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.flightTime, PersistentDataType.LONG)) {
flightTime = container.get(toolStats.flightTime, PersistentDataType.LONG);
}
if (flightTime == null) {
flightTime = 0L;
toolStats.logger.warning(flightTime + " does not have valid flight-time set! Resting to zero. This should NEVER happen.");
}
// get the duration of the flight
long duration = (System.currentTimeMillis() - startTime) + flightTime;
container.set(toolStats.flightTime, PersistentDataType.LONG, flightTime + duration);
// do we add the lore based on the config?
if (toolStats.config.getBoolean("enabled.flight-time")) {
String oldFlightFormatted = toolStats.numberFormat.formatDouble((double) flightTime / 1000);
String newFlightFormatted = toolStats.numberFormat.formatDouble((double) (flightTime + duration) / 1000);
String oldLine = toolStats.configTools.formatLore("flight-time", "{time}", oldFlightFormatted);
String newLine = toolStats.configTools.formatLore("flight-time", "{time}", newFlightFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
chest.setItemMeta(meta);
}
}

View File

@@ -18,19 +18,22 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
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 org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class SheepShear implements Listener {
@@ -41,30 +44,66 @@ public class SheepShear implements Listener {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onShear(PlayerInteractEntityEvent event) {
if (event.isCancelled()) {
return;
}
Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
Entity entity = event.getRightClicked();
if (!(entity instanceof Sheep)) {
return;
}
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.SHEARS) {
ItemStack shears = getShears(player);
// player swapped items?
if (shears == null) {
return;
}
Sheep sheep = (Sheep) entity;
if (!sheep.isSheared()) {
addLore(heldItem);
// make sure the sheep is not sheared
if (sheep.isSheared()) {
return;
}
// update the stats
ItemStack finalShears = shears;
addLore(finalShears);
}
private void addLore(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
private static @Nullable ItemStack getShears(Player player) {
PlayerInventory inventory = player.getInventory();
boolean isMainHand = inventory.getItemInMainHand().getType() == Material.SHEARS;
boolean isOffHand = inventory.getItemInOffHand().getType() == Material.SHEARS;
ItemStack shears = null;
if (isMainHand) {
shears = inventory.getItemInMainHand();
}
if (isOffHand) {
shears = inventory.getItemInOffHand();
}
// if the player is hold shears in both hands
// default to main hand since that takes priority
if (isMainHand && isOffHand) {
shears = inventory.getItemInMainHand();
}
return shears;
}
/**
* Adds tags to shears.
*
* @param newShears The shears.
*/
private void addLore(ItemStack newShears) {
ItemMeta meta = newShears.getItemMeta();
if (meta == null) {
toolStats.logger.warning(newShears + " does NOT have any meta! Unable to update stats.");
return;
}
Integer sheepSheared = 0;
@@ -72,47 +111,25 @@ public class SheepShear implements Listener {
if (container.has(toolStats.shearsSheared, PersistentDataType.INTEGER)) {
sheepSheared = container.get(toolStats.shearsSheared, PersistentDataType.INTEGER);
}
if (sheepSheared == null) {
return;
} else {
sheepSheared++;
}
container.set(toolStats.shearsSheared, PersistentDataType.INTEGER, sheepSheared);
String sheepShearedLore = toolStats.getLoreFromConfig("sheep-sheared", false);
String sheepShearedLoreRaw = toolStats.getLoreFromConfig("sheep-sheared", true);
if (sheepShearedLore == null || sheepShearedLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.sheep-sheared!");
return;
sheepSheared = 0;
toolStats.logger.warning(newShears + " does not have valid sheared set! Resting to zero. This should NEVER happen.");
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
boolean hasLore = false;
// we do a for loop like this, we can keep track of index
// this doesn't mess the lore up of existing items
for (int x = 0; x < lore.size(); x++) {
if (lore.get(x).contains(sheepShearedLore)) {
hasLore = true;
lore.set(x, sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
break;
}
}
// if the item has lore but doesn't have the tag, add it
if (!hasLore) {
lore.add(sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
}
} else {
// if the item has no lore, create a new list and add the string
lore = new ArrayList<>();
lore.add(sheepShearedLoreRaw.replace("{sheep}", Integer.toString(sheepSheared)));
}
container.set(toolStats.shearsSheared, PersistentDataType.INTEGER, sheepSheared + 1);
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
meta.setLore(lore);
String oldSheepFormatted = toolStats.numberFormat.formatInt(sheepSheared);
String newSheepFormatted = toolStats.numberFormat.formatInt(sheepSheared + 1);
String oldLine = toolStats.configTools.formatLore("sheep-sheared", "{sheep}", oldSheepFormatted);
String newLine = toolStats.configTools.formatLore("sheep-sheared", "{sheep}", newSheepFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
newShears.setItemMeta(meta);
}
}

View File

@@ -0,0 +1,124 @@
/*
* 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.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityShootBowEvent;
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 org.jetbrains.annotations.Nullable;
import java.util.List;
public class ShootBow implements Listener {
private final ToolStats toolStats;
public ShootBow(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onShoot(EntityShootBowEvent event) {
Entity shooter = event.getEntity();
// only listen for players
if (!(shooter instanceof Player)) {
return;
}
Player player = (Player) shooter;
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.ADVENTURE) {
return;
}
PlayerInventory inventory = player.getInventory();
ItemStack heldBow = getBow(inventory);
// player swapped
if (heldBow == null) {
return;
}
updateArrowsShot(heldBow);
}
private static @Nullable ItemStack getBow(PlayerInventory inventory) {
boolean isMainHand = inventory.getItemInMainHand().getType() == Material.BOW || inventory.getItemInMainHand().getType() == Material.CROSSBOW;
boolean isOffHand = inventory.getItemInOffHand().getType() == Material.BOW || inventory.getItemInMainHand().getType() == Material.CROSSBOW;
ItemStack heldBow = null;
if (isMainHand) {
heldBow = inventory.getItemInMainHand();
}
if (isOffHand) {
heldBow = inventory.getItemInOffHand();
}
// if the player is holding a bow in both hands
// default to main hand since that takes priority
if (isMainHand && isOffHand) {
heldBow = inventory.getItemInMainHand();
}
return heldBow;
}
private void updateArrowsShot(ItemStack bow) {
ItemMeta meta = bow.getItemMeta();
if (meta == null) {
toolStats.logger.warning(bow + " does NOT have any meta! Unable to update stats.");
return;
}
// read the current stats from the item
// if they don't exist, then start from 0
Integer arrowsShot = 0;
PersistentDataContainer container = meta.getPersistentDataContainer();
if (container.has(toolStats.arrowsShot, PersistentDataType.INTEGER)) {
arrowsShot = container.get(toolStats.arrowsShot, PersistentDataType.INTEGER);
}
if (arrowsShot == null) {
arrowsShot = 0;
toolStats.logger.warning(arrowsShot + " does not have valid arrows-shot set! Resting to zero. This should NEVER happen.");
}
container.set(toolStats.arrowsShot, PersistentDataType.INTEGER, arrowsShot + 1);
// do we add the lore based on the config?
if (toolStats.config.getBoolean("enabled.arrows-shot")) {
String oldArrowsFormatted = toolStats.numberFormat.formatInt(arrowsShot);
String newArrowsFormatted = toolStats.numberFormat.formatInt(arrowsShot + 1);
String oldLine = toolStats.configTools.formatLore("arrows-shot", "{arrows}", oldArrowsFormatted);
String newLine = toolStats.configTools.formatLore("arrows-shot", "{arrows}", newArrowsFormatted);
if (oldLine == null || newLine == null) {
return;
}
List<String> newLore = toolStats.itemLore.updateItemLore(meta, oldLine, newLine);
meta.setLore(newLore);
}
bow.setItemMeta(meta);
}
}

View File

@@ -18,11 +18,12 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.Bukkit;
import lol.hyper.toolstats.tools.UUIDDataType;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
@@ -33,55 +34,67 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class VillagerTrade implements Listener {
private final ToolStats toolStats;
public final String[] validItems = {
"pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing"
};
private final SimpleDateFormat format = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
public VillagerTrade(ToolStats toolStats) {
this.toolStats = toolStats;
}
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onTrade(InventoryClickEvent event) {
if (event.isCancelled() || event.getCurrentItem() == null) {
return;
}
Inventory inventory = event.getClickedInventory();
if (!(event.getWhoClicked() instanceof Player)) {
return;
}
Player player = (Player) event.getWhoClicked();
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
// only check villager inventories
if (inventory instanceof MerchantInventory) {
// only check the result slot (the item you receive)
if (event.getSlotType() == InventoryType.SlotType.RESULT) {
ItemStack item = event.getCurrentItem();
for (String x : validItems) {
if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.trading");
if (configMessage != null) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
ItemStack newItem = addLore(item, (Player) event.getWhoClicked());
if (newItem == null) {
return;
}
Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5);
// only check items we want
if (!toolStats.itemChecker.isValidItem(item.getType())) {
return;
}
// if the player shift clicks, show the warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.trading");
if (configMessage != null) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
ItemStack newItem = addLore(item, player);
if (newItem != null) {
// set the new item
inventory.setItem(event.getSlot(), newItem);
}
}
}
}
private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
/**
* Adds "traded by" tags to item.
*
* @param oldItem The item to add lore.
* @param owner The player who traded.
* @return The item with lore.
*/
private ItemStack addLore(ItemStack oldItem, Player owner) {
ItemStack newItem = oldItem.clone();
ItemMeta meta = newItem.getItemMeta();
if (meta == null) {
toolStats.logger.warning(newItem + " does NOT have any meta! Unable to update stats.");
return null;
}
long timeCreated = System.currentTimeMillis();
@@ -92,30 +105,22 @@ public class VillagerTrade implements Listener {
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.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 3);
String tradedByLoreRaw = toolStats.getLoreFromConfig("traded.traded-by", true);
String tradedOnLoreRaw = toolStats.getLoreFromConfig("traded.traded-on", true);
if (tradedByLoreRaw == null || tradedOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.traded!");
return null;
if (toolStats.configTools.checkConfig(newItem.getType(), "traded-tag")) {
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
meta.setLore(newLore);
}
List<String> lore;
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
if (toolStats.checkConfig(itemStack, "traded-tag")) {
lore.add(tradedOnLoreRaw.replace("{date}", format.format(finalDate)));
lore.add(tradedByLoreRaw.replace("{player}", owner.getName()));
}
meta.setLore(lore);
itemStack.setItemMeta(meta);
return itemStack;
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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 java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
public class HashMaker {
private final ToolStats toolStats;
public HashMaker(ToolStats toolStats) {
this.toolStats = toolStats;
}
public String makeHash(Material itemType, UUID player, long timestamp) {
String input = itemType.toString() + player.toString() + timestamp;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : hashBytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException exception) {
toolStats.logger.warning("Unable to generate hash for " + player + "!");
toolStats.logger.warning("Generating a random UUID instead.");
exception.printStackTrace();
return java.util.UUID.randomUUID().toString();
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.Material;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class ItemChecker {
private final List<Material> validItems = new ArrayList<>();
private final List<Material> armorItems = new ArrayList<>();
private final List<Material> meleeItems = new ArrayList<>();
private final List<Material> mineItems = new ArrayList<>();
/**
* Creates an item checker and saves all valid items we want.
*/
public ItemChecker() {
for (Material material : Material.values()) {
String lowerCase = material.toString().toLowerCase(Locale.ROOT);
if (lowerCase.contains("_pickaxe") || lowerCase.contains("_axe") || lowerCase.contains("_hoe") || lowerCase.contains("_shovel")) {
mineItems.add(material);
}
if (lowerCase.contains("_sword") || lowerCase.contains("_axe")) {
meleeItems.add(material);
}
if (lowerCase.contains("_helmet") || lowerCase.contains("_chestplate") || lowerCase.contains("_leggings") || lowerCase.contains("_boots")) {
armorItems.add(material);
}
}
// hardcode these
mineItems.add(Material.SHEARS);
meleeItems.add(Material.TRIDENT);
validItems.add(Material.BOW);
validItems.add(Material.FISHING_ROD);
validItems.add(Material.CROSSBOW);
validItems.add(Material.ELYTRA);
// combine the lists
validItems.addAll(armorItems);
validItems.addAll(meleeItems);
validItems.addAll(mineItems);
}
/**
* Check if item is an armor piece.
*
* @param itemType The item type, not name.
* @return If the item is an armor piece.
*/
public boolean isArmor(Material itemType) {
return armorItems.contains(itemType);
}
/**
* Check if item is a tool or armor piece we want to track.
*
* @param itemType The item type, not name.
* @return If the item something we want to track.
*/
public boolean isValidItem(Material itemType) {
return validItems.contains(itemType);
}
/**
* Check if item is a melee weapon.
*
* @param itemType The item type, not name.
* @return If the item is a melee weapon.
*/
public boolean isMeleeWeapon(Material itemType) {
return meleeItems.contains(itemType);
}
/**
* Check if item is a mining tool.
*
* @param itemType The item type, not name.
* @return If the item is a mining tool.
*/
public boolean isMineTool(Material itemType) {
return mineItems.contains(itemType);
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class ItemLore {
private final ToolStats toolStats;
public static final Pattern COLOR_CODES = Pattern.compile("[&§]([0-9a-fk-or])");
public static final Pattern HEX_PATTERN = Pattern.compile("[&§]#([A-Fa-f0-9]{6})");
public ItemLore(ToolStats toolStats) {
this.toolStats = toolStats;
}
/**
* Updates existing lore on an item.
*
* @param itemMeta The item's meta.
* @param oldLine The old line to replace.
* @param newLine The new line to replace oldLine.
* @return The item's new lore.
*/
public List<String> updateItemLore(ItemMeta itemMeta, String oldLine, String newLine) {
List<String> itemLore;
oldLine = toolStats.configTools.removeColor(oldLine);
if (itemMeta.hasLore()) {
itemLore = itemMeta.getLore();
// keep track of line index
// this doesn't mess the lore of existing items
for (int x = 0; x < itemLore.size(); x++) {
// check to see if the line matches the config value
// this means we update this line only!
String line = toolStats.configTools.removeColor(itemLore.get(x));
if (line.equals(oldLine)) {
itemLore.set(x, newLine);
return itemLore;
}
}
// if the item has lore, but we didn't find the line
itemLore.add(newLine);
} else {
// if the item has no lore, create a new list and add the line
itemLore = new ArrayList<>();
itemLore.add(newLine);
}
return itemLore;
}
public List<String> addItemLore(ItemMeta itemMeta, String newLine) {
List<String> itemLore;
if (itemMeta.hasLore()) {
itemLore = itemMeta.getLore();
itemLore.add(newLine);
} else {
itemLore = new ArrayList<>();
itemLore.add(newLine);
}
return itemLore;
}
/**
* Adds new ownership to an item.
*
* @param itemMeta The item meta.
* @param playerName The new owner of item.
* @param formattedDate The date of the ownership.
* @return The item's new lore.
*/
public List<String> addNewOwner(ItemMeta itemMeta, String playerName, String formattedDate) {
String dateCreatedLore;
String itemOwnerLore;
Integer origin = null;
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
origin = container.get(toolStats.originType, PersistentDataType.INTEGER);
}
// if the origin is broken, don't try to set the lore
if (origin == null) {
toolStats.logger.info("Unable to determine origin for item " + itemMeta.getAsString());
toolStats.logger.info("This IS a bug, please report this to the GitHub.");
return itemMeta.getLore();
}
// set the lore based on the origin
switch (origin) {
case 2: {
dateCreatedLore = toolStats.configTools.formatLore("looted.looted-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("looted.looted-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.looted.looted-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.looted.looted-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
break;
}
case 3: {
dateCreatedLore = toolStats.configTools.formatLore("traded.traded-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("traded.traded-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.traded.traded-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.traded.traded-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
break;
}
case 4: {
dateCreatedLore = toolStats.configTools.formatLore("looted.found-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("looted.found-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.looted.found-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.looted.found-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
break;
}
case 5: {
dateCreatedLore = toolStats.configTools.formatLore("fished.caught-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("fished.caught-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.fished.caught-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.fished.caught-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
break;
}
case 6: {
dateCreatedLore = toolStats.configTools.formatLore("spawned-in.spawned-on", "{date}", formattedDate);
itemOwnerLore = toolStats.configTools.formatLore("spawned-in.spawned-by", "{player}", playerName);
if (dateCreatedLore == null) {
toolStats.logger.warning("messages.spawned-in.spawned-on is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
if (itemOwnerLore == null) {
toolStats.logger.warning("messages.spawned-in.spawned-by is not set in your config!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
break;
}
default: {
toolStats.logger.warning("Origin " + origin + " was found. Data was modified OR something REALLY broke.");
toolStats.logger.warning(itemMeta.getAsString());
return itemMeta.getLore();
}
}
List<String> newLore;
if (itemMeta.hasLore()) {
newLore = itemMeta.getLore();
} else {
newLore = new ArrayList<>();
}
newLore.add(dateCreatedLore.replace("{date}", formattedDate));
newLore.add(itemOwnerLore.replace("{player}", playerName));
return newLore;
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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 java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class NumberFormat {
private DecimalFormat DECIMAL_FORMAT;
private DecimalFormat COMMA_FORMAT;
private SimpleDateFormat DATE_FORMAT;
/**
* Utility class to format different numbers
* @param toolStats Plugin instance.
*/
public NumberFormat(ToolStats toolStats) {
String dateFormat = toolStats.config.getString("date-format");
String decimalSeparator = toolStats.config.getString("number-formats.decimal-separator");
String commaSeparator = toolStats.config.getString("number-formats.comma-separator");
String commaFormat = toolStats.config.getString("number-formats.comma-format");
String decimalFormat = toolStats.config.getString("number-formats.decimal-format");
// if these config values are missing, use the default ones
if (dateFormat == null) {
dateFormat = "M/dd/yyyy";
toolStats.logger.warning("date-format is missing! Using default American English format.");
}
if (decimalSeparator == null) {
decimalSeparator = ".";
toolStats.logger.warning("number-formats.decimal-separator is missing! Using default \".\" instead.");
}
if (commaSeparator == null) {
commaSeparator = ",";
toolStats.logger.warning("number-formats.comma-separator is missing! Using default \",\" instead.");
}
if (commaFormat == null) {
commaFormat = "#,###";
toolStats.logger.warning("number-formats.comma-format is missing! Using default #,### instead.");
}
if (decimalFormat == null) {
decimalFormat = "#,###.00";
toolStats.logger.warning("number-formats.comma-separator is missing! Using default #,###.00 instead.");
}
// test the date format
try {
DATE_FORMAT = new SimpleDateFormat(dateFormat, Locale.getDefault());
} catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("date-format is NOT a valid format! Using default American English format.");
exception.printStackTrace();
DATE_FORMAT = new SimpleDateFormat("M/dd/yyyy", Locale.ENGLISH);
}
// set the separators
DecimalFormatSymbols formatSymbols = new DecimalFormatSymbols(Locale.getDefault());
formatSymbols.setDecimalSeparator(decimalSeparator.charAt(0));
formatSymbols.setGroupingSeparator(commaSeparator.charAt(0));
// test the comma format
try {
COMMA_FORMAT = new DecimalFormat(commaFormat, formatSymbols);
} catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("number-formats.comma-format is NOT a valid format! Using default #,### instead.");
exception.printStackTrace();
COMMA_FORMAT = new DecimalFormat("#,###", formatSymbols);
}
// test the decimal format
try {
DECIMAL_FORMAT = new DecimalFormat(decimalFormat, formatSymbols);
} catch (NullPointerException | IllegalArgumentException exception) {
toolStats.logger.warning("number-formats.decimal-format is NOT a valid format! Using default #,###.00 instead.");
exception.printStackTrace();
DECIMAL_FORMAT = new DecimalFormat("#,###.00", formatSymbols);
}
}
/**
* Formats a number to make it pretty. Example: 4322 to 4,322
*
* @param number The number to format.
* @return The formatted number.
*/
public String formatInt(int number) {
String finalNumber = COMMA_FORMAT.format(number);
finalNumber = finalNumber.replaceAll("[\\x{202f}\\x{00A0}]", " ");
return finalNumber;
}
/**
* Formats a number to make it pretty. Example: 4322.33 to 4,322.33
*
* @param number The number to format.
* @return The formatted number.
*/
public String formatDouble(double number) {
String finalNumber = DECIMAL_FORMAT.format(number);
finalNumber = finalNumber.replaceAll("[\\x{202f}\\x{00A0}]", " ");
return finalNumber;
}
/**
* Formats a date into the readable format.
*
* @param date The date to format.
* @return The date into a readable format.
*/
public String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
}

View File

@@ -15,7 +15,24 @@
* along with ToolStats. If not, see <https://www.gnu.org/licenses/>.
*/
package lol.hyper.toolstats;
/*
* 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;

View File

@@ -0,0 +1,152 @@
/*
* 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 lol.hyper.toolstats.tools.ItemLore;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import java.util.regex.Matcher;
public class ConfigTools {
private final ToolStats toolStats;
public ConfigTools(ToolStats toolStats) {
this.toolStats = toolStats;
}
/**
* Checks the config to see if we want to show lore on certain items.
*
* @param material The item type to check.
* @param configName The config we are checking under.
* @return If we want to allow lore or not.
*/
public boolean checkConfig(Material material, String configName) {
String itemName = material.toString().toLowerCase();
String itemType = null;
// hardcode these
if (material == Material.BOW || material == Material.CROSSBOW || material == Material.SHEARS || material == Material.TRIDENT || material == Material.FISHING_ROD) {
switch (material) {
case CROSSBOW:
case BOW: {
itemType = "bow";
break;
}
case SHEARS: {
itemType = "shears";
break;
}
case TRIDENT: {
itemType = "trident";
break;
}
case FISHING_ROD: {
itemType = "fishing-rod";
break;
}
}
} else {
itemType = itemName.substring(itemName.indexOf('_') + 1);
}
switch (itemType) {
case "pickaxe": {
return toolStats.config.getBoolean("enabled." + configName + ".pickaxe");
}
case "sword": {
return toolStats.config.getBoolean("enabled." + configName + ".sword");
}
case "shovel": {
return toolStats.config.getBoolean("enabled." + configName + ".shovel");
}
case "axe": {
return toolStats.config.getBoolean("enabled." + configName + ".axe");
}
case "hoe": {
return toolStats.config.getBoolean("enabled." + configName + ".hoe");
}
case "shears": {
return toolStats.config.getBoolean("enabled." + configName + ".shears");
}
case "crossbow":
case "bow": {
return toolStats.config.getBoolean("enabled." + configName + ".bow");
}
case "trident": {
return toolStats.config.getBoolean("enabled." + configName + ".trident");
}
case "fishing-rod": {
return toolStats.config.getBoolean("enabled." + configName + ".fishing-rod");
}
case "helmet":
case "chestplate":
case "leggings":
case "boots": {
return toolStats.config.getBoolean("enabled." + configName + ".armor");
}
}
return false;
}
/**
* Format a string to be ready for lore usage.
*
* @param configName The message to use.
* @param placeHolder The placeholder text in the message.
* @param value The value to set the placeholder.
* @return Formatted string, null if the configName doesn't exist.
*/
public String formatLore(String configName, String placeHolder, Object value) {
String lore = toolStats.config.getString("messages." + configName);
if (lore == null) {
return null;
}
// set the placeholder to the value
lore = lore.replace(placeHolder, String.valueOf(value));
Matcher hexMatcher = ItemLore.HEX_PATTERN.matcher(lore);
while (hexMatcher.find()) {
String hexCode = hexMatcher.group(1);
lore = lore.replaceAll(hexMatcher.group(), net.md_5.bungee.api.ChatColor.of("#" + hexCode).toString());
}
Matcher colorMatcher = ItemLore.COLOR_CODES.matcher(lore);
while (colorMatcher.find()) {
String colorCode = colorMatcher.group(1);
lore = lore.replaceAll("&" + colorCode, ChatColor.getByChar(colorCode).toString());
}
return ChatColor.translateAlternateColorCodes('§', lore);
}
/**
* Remove all color codes from a message.
*
* @param message The message.
* @return The message without color codes.
*/
public String removeColor(String message) {
message = ItemLore.COLOR_CODES.matcher(message).replaceAll("");
message = ItemLore.HEX_PATTERN.matcher(message).replaceAll("");
return message;
}
}

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/>.
*/
/*
* 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 lol.hyper.toolstats.tools.config.versions.Version6;
import lol.hyper.toolstats.tools.config.versions.Version7;
public class ConfigUpdater {
private final ToolStats toolStats;
public ConfigUpdater(ToolStats toolStats) {
this.toolStats = toolStats;
}
public void updateConfig() {
int version = toolStats.config.getInt("config-version");
// this will be a switch in the future
// Upgrade 5 to 6
if (version == 5) {
Version6 version6 = new Version6(toolStats);
version6.update();
}
// Upgrade 6 to 7
if (version == 6) {
Version7 version7 = new Version7(toolStats);
version7.update();
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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.ArrayList;
import java.util.Collections;
import java.util.List;
public class Version6 {
private final ToolStats toolStats;
/**
* Used for updating from version 5 to 6.
*
* @param toolStats ToolStats instance.
*/
public Version6(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-5.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config-5.yml!");
throw new RuntimeException(exception);
}
// we make this super verbose so that admins can see what's being added
toolStats.logger.info("Updating config.yml to version 6.");
toolStats.config.set("config-version", 6);
toolStats.logger.info("Adding enabled.spawned-in.pickaxe to config.yml.");
toolStats.config.set("enabled.spawned-in.pickaxe", true);
toolStats.logger.info("Adding enabled.spawned-in.sword to config.yml.");
toolStats.config.set("enabled.spawned-in.sword", true);
toolStats.logger.info("Adding enabled.spawned-in.shovel to config.yml.");
toolStats.config.set("enabled.spawned-in.shovel", true);
toolStats.logger.info("Adding enabled.spawned-in.axe to config.yml.");
toolStats.config.set("enabled.spawned-in.axe", true);
toolStats.logger.info("Adding enabled.spawned-in.hoe to config.yml.");
toolStats.config.set("enabled.spawned-in.hoe", true);
toolStats.logger.info("Adding enabled.spawned-in.fishing-rod to config.yml.");
toolStats.config.set("enabled.spawned-in.fishing-rod", true);
toolStats.logger.info("Adding enabled.spawned-in.shears to config.yml.");
toolStats.config.set("enabled.spawned-in.shears", true);
toolStats.logger.info("Adding enabled.spawned-in.bow to config.yml.");
toolStats.config.set("enabled.spawned-in.bow", true);
toolStats.logger.info("Adding enabled.spawned-in.armor to config.yml.");
toolStats.config.set("enabled.spawned-in.armor", true);
toolStats.logger.info("Adding messages.spawned-in.spawned-by to config.yml.");
toolStats.config.set("messages.spawned-in.spawned-by", "&7Spawned in by: &8{player}");
toolStats.logger.info("Adding messages.spawned-in.spawned-on to config.yml.");
toolStats.config.set("messages.spawned-in.spawned-on", "&7Spawned on: &8{date}");
toolStats.logger.info("Adding generate-hash-for-items to config.yml.");
toolStats.config.set("generate-hash-for-items", true);
toolStats.logger.info("Adding enabled.arrows-shot to config.yml.");
toolStats.config.set("enabled.arrows-shot", true);
toolStats.logger.info("Adding messages.arrows-shot to config.yml.");
toolStats.config.set("messages.arrows-shot", "&7Arrows shot: &8{arrows}");
List<String> hashComments = new ArrayList<>();
hashComments.add("When any tool is created, it will generate a hash for the item.");
hashComments.add("This hash is not on the item lore, only stored in the NBT data.");
hashComments.add("This has no use currently, but can be used for future features for dupe detection.");
toolStats.config.setComments("generate-hash-for-items", hashComments);
toolStats.config.setComments("enabled.spawned-in", Collections.singletonList("Will show \"Spawned in by <player>\""));
// save the config and reload it
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!");
throw new RuntimeException(exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 6. A copy of version 5 has been saved as config-5.yml");
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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 Version7 {
private final ToolStats toolStats;
/**
* Used for updating from version 6 to 7.
*
* @param toolStats ToolStats instance.
*/
public Version7(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-6.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config-5.yml!");
throw new RuntimeException(exception);
}
// we make this super verbose so that admins can see what's being added
toolStats.logger.info("Updating config.yml to version 7.");
toolStats.config.set("config-version", 7);
toolStats.logger.info("Adding messages.flight-time to config.yml.");
toolStats.config.set("messages.flight-time", "&7Flight time: &8{time}");
toolStats.logger.info("Adding enabled.flight-time to config.yml.");
toolStats.config.set("enabled.flight-time", true);
// save the config and reload it
try {
toolStats.config.save("plugins" + File.separator + "ToolStats" + File.separator + "config.yml");
} catch (IOException exception) {
toolStats.logger.severe("Unable to save config.yml!");
throw new RuntimeException(exception);
}
toolStats.loadConfig();
toolStats.logger.info("Config has been updated to version 7. A copy of version 5 has been saved as config-6.yml");
}
}

View File

@@ -65,11 +65,23 @@ enabled:
axe: true
hoe: true
shears: true
# Will show "Spawned in by <player>"
spawned-in:
pickaxe: true
sword: true
shovel: true
axe: true
hoe: true
shears: true
bow: true
armor: true
fish-caught: true
sheep-sheared: true
armor-damage: true
dropped-by: true
elytra-tag: true
arrows-shot: true
flight-time: true
messages:
created:
@@ -80,6 +92,8 @@ messages:
caught-on: "&7Caught on: &8{date}"
fish-caught: "&7Fish caught: &8{fish}"
looted:
looted-by: "&7Looted by: &8{player}"
looted-on: "&7Looted on: &8{date}"
found-by: "&7Found by: &8{player}"
found-on: "&7Found on: &8{date}"
traded:
@@ -88,14 +102,38 @@ messages:
kills:
mob: "&7Mob kills: &8{kills}"
player: "&7Player kills: &8{kills}"
spawned-in:
spawned-by: "&7Spawned in by: &8{player}"
spawned-on: "&7Spawned on: &8{date}"
blocks-mined: "&7Blocks mined: &8{blocks}"
crops-harvested: "&7Crops harvested: &8{crops}"
sheep-sheared: "&7Sheep sheared: &8{sheep}"
dropped-by: "&7Dropped by: &8{name}" # name will be player/mob name
damage-taken: "&7Damage taken: &8{damage}"
arrows-shot: "&7Arrows shot: &8{arrows}"
flight-time: "&7Flight time: &8{time}"
# Display this message if the player shift click trades/crafts items. It's not really easy to get every single item
# that is crafted. The tag will only be added to the first item. If you don't want this message, simply replace them both with ""
shift-click-warning:
crafting: "&cCrafting items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
trading: "&cTrading items via shift clicking does not fully apply tags to each item. This is a limitation with the Bukkit API."
config-version: 3
# Change the default formatting for dates.
# See: https://www.digitalocean.com/community/tutorials/java-simpledateformat-java-date-format
# Example: "dd/MM/yyyy"
date-format: "M/dd/yyyy"
# Change number formatting.
# You probably do not need to touch this.
number-formats:
comma-separator: ","
decimal-separator: "."
comma-format: "#,###"
decimal-format: "#,###.00"
# When any tool is created, it will generate a hash for the item.
# This hash is not on the item lore, only stored in the NBT data.
# This has no use currently, but can be used for future features for dupe detection.
generate-hash-for-items: true
config-version: 7

View File

@@ -4,15 +4,21 @@ main: lol.hyper.toolstats.ToolStats
api-version: 1.15
author: hyperdefined
description: Track various tool stats!
folia-supported: true
commands:
toolstats:
usage: /toolstats
description: Main command.
permission: toolstats.main
permission: toolstats.command
permissions:
toolstats.main:
description: Allows the usage of /toolstats
toolstats.command:
description: Allows the usage of /toolstats.
default: true
toolstats.reload:
description: Allows the usage of /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