Compare commits

...

132 Commits
1.3.2 ... 1.7

Author SHA1 Message Date
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
23 changed files with 1553 additions and 683 deletions

View File

@@ -1,11 +1,9 @@
<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.19.2-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>
<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>
@@ -36,5 +34,8 @@ If item lore is ever incorrect, you can run `/toolstats reset` to reset the item
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image9.png)
![Image](https://raw.githubusercontent.com/hyperdefined/ToolStats/master/images/image10.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).

55
pom.xml
View File

@@ -23,7 +23,7 @@
<groupId>lol.hyper</groupId>
<artifactId>toolstats</artifactId>
<version>1.3.2</version>
<version>1.7</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.3.1</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.10.0</version>
<version>3.11.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.5.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,48 @@
<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.19-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.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>lol.hyper</groupId>
<artifactId>github-release-api</artifactId>
<version>1.0.1</version>
<version>1.0.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>4.14.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>space.arim.morepaperlib</groupId>
<artifactId>morepaperlib</artifactId>
<version>0.4.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -21,43 +21,75 @@ 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.ItemLore;
import lol.hyper.toolstats.tools.NumberFormat;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.NamespacedKey;
import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
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 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");
public final Set<NamespacedKey> keys = new HashSet<>();
/**
* Stores how an item was created.
* 0 = crafted.
* 1 = dropped.
* 2 = looted.
* 3 = traded.
* 4 = founded (for elytras).
* 5 = fished.
*/
public final NamespacedKey originType = new NamespacedKey(this, "origin");
public BlocksMined blocksMined;
public ChunkPopulate chunkPopulate;
@@ -67,17 +99,28 @@ 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 ItemLore itemLore;
public InventoryOpen inventoryOpen;
public PlayerJoin playerJoin;
public NumberFormat numberFormat;
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 final int CONFIG_VERSION = 5;
private BukkitAudiences adventure;
public MorePaperLib morePaperLib;
@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!");
@@ -91,9 +134,13 @@ 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);
Bukkit.getServer().getPluginManager().registerEvents(blocksMined, this);
Bukkit.getServer().getPluginManager().registerEvents(chunkPopulate, this);
@@ -103,23 +150,17 @@ 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);
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() {
@@ -127,6 +168,8 @@ public final class ToolStats extends JavaPlugin {
if (config.getInt("config-version") != CONFIG_VERSION) {
logger.warning("Your config file is outdated! Please regenerate the config.");
}
numberFormat = new NumberFormat(this);
}
public void checkForUpdates() {
@@ -154,22 +197,26 @@ public final class ToolStats extends JavaPlugin {
/**
* Checks the config to see if we want to show lore on certain items.
* @param itemStack The item to check.
*
* @param itemStack The item to check.
* @param configName The config we are checking under.
* @return If we want to allow lore or not.
*/
public boolean checkConfig(ItemStack itemStack, String configName) {
String itemName = itemStack.getType().toString().toLowerCase();
String itemType = null;
if (itemName.contains("bow") || itemName.contains("shears")) {
if (itemName.contains("bow") || itemName.contains("shears") || itemName.contains("trident")) {
if (itemName.contains("bow")) {
itemType = "bow";
}
if (itemName.contains("shears")) {
itemType = "shears";
}
if (itemName.contains("trident")) {
itemType = "trident";
}
} else {
itemType = itemName.substring(itemName.indexOf("_") + 1);
itemType = itemName.substring(itemName.indexOf('_') + 1);
}
if (itemType == null) {
@@ -198,6 +245,9 @@ public final class ToolStats extends JavaPlugin {
case "bow": {
return config.getBoolean("enabled." + configName + ".bow");
}
case "trident": {
return config.getBoolean("enabled." + configName + ".trident");
}
case "helmet":
case "chestplate":
case "leggings":
@@ -210,8 +260,9 @@ public final class ToolStats extends JavaPlugin {
/**
* Gets the lore message from the config.
*
* @param configName The config name, "messages." is already in front.
* @param raw If you want the raw message with the formatting codes and placeholders.
* @param raw If you want the raw message with the formatting codes and placeholders.
* @return The lore message.
*/
public String getLoreFromConfig(String configName, boolean raw) {
@@ -253,4 +304,23 @@ public final class ToolStats extends JavaPlugin {
}
return lore;
}
public BukkitAudiences getAdventure() {
if (this.adventure == null) {
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
}
return this.adventure;
}
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,10 +18,15 @@
package lol.hyper.toolstats.commands;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.*;
import lol.hyper.toolstats.tools.ItemChecker;
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.Material;
import org.bukkit.command.Command;
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;
@@ -31,57 +36,70 @@ 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.").color(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.").color(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!").color(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.").color(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.").color(NamedTextColor.RED));
return true;
}
if (sender instanceof ConsoleCommandSender) {
audiences.sender(sender).sendMessage(Component.text("You must be a player for this command.").color(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.").color(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 (!ItemChecker.isValidItem(heldItem.getType())) {
audiences.sender(sender).sendMessage(Component.text("You must hold a valid item.").color(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!").color(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.").color(NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("The item owner will be who ever is currently running this command.").color(NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("Only use this if the tags on the tool are incorrect.").color(NamedTextColor.GREEN));
audiences.sender(sender).sendMessage(Component.text("Type /toolstats reset confirm to confirm this.").color(NamedTextColor.GREEN));
return true;
}
default: {
sender.sendMessage(ChatColor.RED + "Invalid sub-command.");
audiences.sender(sender).sendMessage(Component.text("Invalid sub-command.").color(NamedTextColor.RED));
}
}
return true;
@@ -89,8 +107,9 @@ public class CommandToolStats implements TabExecutor {
/**
* 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.
* @param player The player running the command.
*/
private void fixItemLore(ItemStack original, Player player) {
ItemStack finalItem = original.clone();
@@ -110,24 +129,15 @@ public class CommandToolStats implements TabExecutor {
return;
}
// determine how the item was originally created
// this doesn't get saved, so we just rely on the lore
// if there isn't a tag, default to crafted
String type = "DEFAULT";
if (finalMeta.hasLore()) {
if (finalMeta.getLore() != null) {
for (String line : finalMeta.getLore()) {
if (line.contains(caughtByLore)) {
type = "CAUGHT";
}
if (line.contains(lootedByLore)) {
type = "LOOTED";
}
if (line.contains(tradedByLore)) {
type = "TRADED";
}
}
}
// set how the item was obtained
Integer origin = -1;
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
origin = container.get(toolStats.originType, PersistentDataType.INTEGER);
}
// set to -1 if it's invalid
if (origin == null) {
origin = -1;
}
// hard code elytras
@@ -137,7 +147,7 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.timeCreated, PersistentDataType.LONG)) {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) {
lore.add(toolStats.getLoreFromConfig("looted.found-on", true).replace("{date}", format.format(new Date(time))));
lore.add(toolStats.getLoreFromConfig("looted.found-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
}
}
finalMeta.setLore(lore);
@@ -152,21 +162,25 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.genericOwner, new UUIDDataType())) {
container.set(toolStats.genericOwner, new UUIDDataType(), player.getUniqueId());
// show how the item was created based on the previous lore
switch (type) {
case "DEFAULT": {
switch (origin) {
case 0: {
lore.add(toolStats.getLoreFromConfig("created.created-by", true).replace("{player}", player.getName()));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName()));
case 2: {
lore.add(toolStats.getLoreFromConfig("looted.looted-by", true).replace("{player}", player.getName()));
break;
}
case "LOOTED": {
case 3: {
lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName()));
break;
}
case 4: {
lore.add(toolStats.getLoreFromConfig("looted.found-by", true).replace("{player}", player.getName()));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-by", true).replace("{player}", player.getName()));
case 5: {
lore.add(toolStats.getLoreFromConfig("fished.caught-by", true).replace("{player}", player.getName()));
break;
}
}
@@ -177,21 +191,25 @@ public class CommandToolStats implements TabExecutor {
Long time = container.get(toolStats.timeCreated, PersistentDataType.LONG);
if (time != null) {
// show how when the item was created based on the previous lore
switch (type) {
case "DEFAULT": {
lore.add(toolStats.getLoreFromConfig("created.created-on", true).replace("{date}", format.format(new Date(time))));
switch (origin) {
case 0: {
lore.add(toolStats.getLoreFromConfig("created.created-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
break;
}
case "CAUGHT": {
lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", format.format(new Date(time))));
case 2: {
lore.add(toolStats.getLoreFromConfig("looted.looted-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
break;
}
case "LOOTED": {
lore.add(toolStats.getLoreFromConfig("looted.foundon", true).replace("{date}", format.format(new Date(time))));
case 3: {
lore.add(toolStats.getLoreFromConfig("traded.traded-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
break;
}
case "TRADED": {
lore.add(toolStats.getLoreFromConfig("traded.traded-on", true).replace("{date}", format.format(new Date(time))));
case 4: {
lore.add(toolStats.getLoreFromConfig("looted.found-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
break;
}
case 5: {
lore.add(toolStats.getLoreFromConfig("fished.caught-on", true).replace("{date}", toolStats.numberFormat.formatDate(new Date(time))));
break;
}
}
@@ -202,7 +220,7 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.swordPlayerKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordPlayerKills, PersistentDataType.INTEGER);
if (kills != null) {
lore.add(toolStats.getLoreFromConfig("kills.player", true).replace("{kills}", Integer.toString(kills)));
lore.add(toolStats.getLoreFromConfig("kills.player", true).replace("{kills}", toolStats.numberFormat.formatInt(kills)));
}
}
}
@@ -210,7 +228,7 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.swordMobKills, PersistentDataType.INTEGER)) {
Integer kills = container.get(toolStats.swordMobKills, PersistentDataType.INTEGER);
if (kills != null) {
lore.add(toolStats.getLoreFromConfig("kills.mob", true).replace("{kills}", Integer.toString(kills)));
lore.add(toolStats.getLoreFromConfig("kills.mob", true).replace("{kills}", toolStats.numberFormat.formatInt(kills)));
}
}
}
@@ -218,7 +236,7 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.genericMined, PersistentDataType.INTEGER)) {
Integer blocksMined = container.get(toolStats.genericMined, PersistentDataType.INTEGER);
if (blocksMined != null) {
lore.add(toolStats.getLoreFromConfig("blocks-mined", true).replace("{blocks}", Integer.toString(blocksMined)));
lore.add(toolStats.getLoreFromConfig("blocks-mined", true).replace("{blocks}", toolStats.numberFormat.formatInt(blocksMined)));
}
}
}
@@ -226,7 +244,7 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.fishingRodCaught, PersistentDataType.INTEGER)) {
Integer fish = container.get(toolStats.fishingRodCaught, PersistentDataType.INTEGER);
if (fish != null) {
lore.add(toolStats.getLoreFromConfig("fished.fish-caught", true).replace("{fish}", Integer.toString(fish)));
lore.add(toolStats.getLoreFromConfig("fished.fish-caught", true).replace("{fish}", toolStats.numberFormat.formatInt(fish)));
}
}
}
@@ -234,15 +252,15 @@ public class CommandToolStats implements TabExecutor {
if (container.has(toolStats.shearsSheared, PersistentDataType.INTEGER)) {
Integer sheep = container.get(toolStats.shearsSheared, PersistentDataType.INTEGER);
if (sheep != null) {
lore.add(toolStats.getLoreFromConfig("sheep-sheared", true).replace("{sheep}", Integer.toString(sheep)));
lore.add(toolStats.getLoreFromConfig("sheep-sheared", true).replace("{sheep}", toolStats.numberFormat.formatInt(sheep)));
}
}
}
if (toolStats.config.getBoolean("enabled.armor-damage")) {
if (container.has(toolStats.armorDamage, PersistentDataType.INTEGER)) {
Integer damage = container.get(toolStats.armorDamage, PersistentDataType.INTEGER);
if (container.has(toolStats.armorDamage, PersistentDataType.DOUBLE)) {
Double damage = container.get(toolStats.armorDamage, PersistentDataType.DOUBLE);
if (damage != null) {
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", Integer.toString(damage)));
lore.add(toolStats.getLoreFromConfig("damage-taken", true).replace("{damage}", toolStats.numberFormat.formatDouble(damage)));
}
}
}
@@ -258,13 +276,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

@@ -18,57 +18,53 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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();
// ignore creative mode
if (player.getGameMode() != GameMode.SURVIVAL) {
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
return;
}
// if the player mines something with their fist
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) {
return;
}
PlayerInventory inventory = player.getInventory();
ItemStack heldItem = inventory.getItemInMainHand();
// only check certain items
String itemName = heldItem.getType().toString().toLowerCase();
if (Arrays.stream(validTools).noneMatch(itemName::contains)) {
if (!ItemChecker.isMineTool(heldItem.getType())) {
return;
}
// if it's an item we want, update the stats
// update the blocks mined
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
@@ -78,48 +74,22 @@ public class BlocksMined implements Listener {
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.");
}
blocksMined++;
container.set(toolStats.genericMined, PersistentDataType.INTEGER, blocksMined);
String configLore = toolStats.getLoreFromConfig("blocks-mined", false);
String configLoreRaw = toolStats.getLoreFromConfig("blocks-mined", true);
String blocksMinedFormatted = toolStats.numberFormat.formatInt(blocksMined);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{blocks}", blocksMinedFormatted, "blocks-mined");
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.blocks-mined!");
return;
}
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(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)));
}
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "blocks-mined")) {
meta.setLore(lore);
if (toolStats.checkConfig(playerTool, "blocks-mined")) {
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
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,25 +44,29 @@ 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 there is a new item frame
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();
@@ -71,6 +76,7 @@ public class ChunkPopulate implements Listener {
}
}
}
}, 20);
};
toolStats.scheduleRegion(runnable, chunk.getWorld(), chunk, 20);
}
}

View File

@@ -18,11 +18,14 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import lol.hyper.toolstats.tools.ItemChecker;
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,58 +33,56 @@ 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);
// only check for items we want
for (String x : validItems) {
if (name.contains(x)) {
// if the player shift clicks, send them this warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.crafting");
if (configMessage != null) {
if (configMessage.length() != 0) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
// only check certain items
if (!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.length() != 0) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
// test the item before setting it
if (addLore(itemStack, player) == null) {
return;
}
// set the result
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.
* @param owner The player crafting.
* @return A copy of the item with the tags + lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
@@ -89,6 +90,7 @@ public class CraftItem implements Listener {
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
@@ -104,6 +106,7 @@ public class CraftItem implements Listener {
container.set(toolStats.timeCreated, PersistentDataType.LONG, timeCreated);
container.set(toolStats.genericOwner, new UUIDDataType(), owner.getUniqueId());
container.set(toolStats.originType, PersistentDataType.INTEGER, 0);
String createdByRaw = toolStats.getLoreFromConfig("created.created-by", true);
String createdOnRaw = toolStats.getLoreFromConfig("created.created-on", true);
@@ -121,13 +124,12 @@ public class CraftItem implements Listener {
// get the current lore the item
if (meta.hasLore()) {
lore = meta.getLore();
assert lore != null;
} else {
lore = new ArrayList<>();
}
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "created-date")) {
lore.add(createdOnRaw.replace("{date}", format.format(finalDate)));
lore.add(createdOnRaw.replace("{date}", toolStats.numberFormat.formatDate(finalDate)));
}
if (toolStats.checkConfig(itemStack, "created-by")) {
lore.add(createdByRaw.replace("{player}", owner.getName()));

View File

@@ -18,10 +18,12 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker;
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,137 +34,187 @@ 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);
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;
}
// a player killed something with their fist
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR) {
return;
}
// check items we want
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 (!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;
ItemStack newTrident;
// trident is killing player
if (livingEntity instanceof Player) {
clone = updatePlayerKills(trident.getItem());
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 the player is holding the bow/crossbow
// if they switch then oh well
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 hold 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 (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();
// 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 (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 (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();
// 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 (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 (ItemChecker.isArmor(armorPiece.getType())) {
updateDamage(armorPiece, event.getFinalDamage());
}
}
}
}
@@ -170,136 +222,84 @@ public class EntityDamage implements Listener {
/**
* Updates a weapon's player kills.
*
* @param itemStack The item to update.
* @return A copy of the item.
*/
private ItemStack updatePlayerKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta();
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++;
playerKills = 0;
toolStats.logger.warning(itemStack + " does not have valid player-kills set! Resting to zero. This should NEVER happen.");
}
playerKills++;
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills);
String playerKillsLore = toolStats.getLoreFromConfig("kills.player", false);
String playerKillsLoreRaw = toolStats.getLoreFromConfig("kills.player", true);
String playerKillsFormatted = toolStats.numberFormat.formatInt(playerKills);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player");
if (playerKillsLore == null || playerKillsLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.kills.player!");
return null;
}
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;
}
}
// 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)));
}
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "player-kills")) {
meta.setLore(lore);
meta.setLore(newLore);
}
finalItem.setItemMeta(meta);
return finalItem;
itemStack.setItemMeta(meta);
}
/**
* Updates a weapon's mob kills.
*
* @param itemStack The item to update.
* @return A copy of the item.
*/
private ItemStack updateMobKills(ItemStack itemStack) {
ItemStack finalItem = itemStack.clone();
ItemMeta meta = finalItem.getItemMeta();
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++;
mobKills = 0;
toolStats.logger.warning(itemStack + " does not have valid mob-kills set! Resting to zero. This should NEVER happen.");
}
mobKills++;
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills);
String mobKillsLore = toolStats.getLoreFromConfig("kills.mob", false);
String mobKillsLoreRaw = toolStats.getLoreFromConfig("kills.mob", true);
String mobKillsFormatted = toolStats.numberFormat.formatInt(mobKills);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob");
if (mobKillsLore == null || mobKillsLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.kills.mob!");
return null;
}
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;
}
}
// 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)));
}
// do we add the lore based on the config?
if (toolStats.checkConfig(itemStack, "mob-kills")) {
meta.setLore(lore);
meta.setLore(newLore);
}
finalItem.setItemMeta(meta);
return finalItem;
itemStack.setItemMeta(meta);
}
/**
* Updates a player's armor damage stats.
*
* @param itemStack The armor piece.
* @param damage How much damage is being added.
* @param damage How much damage is being added.
*/
private void updateArmorDamage(ItemStack itemStack, double damage) {
private void updateDamage(ItemStack itemStack, double damage) {
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;
@@ -307,48 +307,96 @@ 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;
damageTaken = 0.0;
toolStats.logger.warning(itemStack + " does not have valid damage-taken set! Resting to zero. This should NEVER happen.");
}
decimalFormat.setRoundingMode(RoundingMode.DOWN);
damageTaken = damageTaken + damage;
container.set(toolStats.armorDamage, PersistentDataType.DOUBLE, damageTaken);
container.set(toolStats.armorDamageInt, PersistentDataType.INTEGER, damageTaken.intValue());
String damageTakenLore = toolStats.getLoreFromConfig("damage-taken", false);
String damageTakenLoreRaw = toolStats.getLoreFromConfig("damage-taken", true);
String damageTakenFormatted = toolStats.numberFormat.formatDouble(damageTaken);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{damage}", damageTakenFormatted, "damage-taken");
if (damageTakenLore == null || damageTakenLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.damage-taken!");
return;
}
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)));
}
if (toolStats.config.getBoolean("enabled.armor-damage")) {
meta.setLore(lore);
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.");
}
mobKills++;
container.set(toolStats.swordMobKills, PersistentDataType.INTEGER, mobKills);
String mobKillsFormatted = toolStats.numberFormat.formatInt(mobKills);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", mobKillsFormatted, "kills.mob");
// do we add the lore based on the config?
if (toolStats.checkConfig(newTrident, "mob-kills")) {
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.");
}
playerKills++;
container.set(toolStats.swordPlayerKills, PersistentDataType.INTEGER, playerKills);
String playerKillsFormatted = toolStats.numberFormat.formatInt(playerKills);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{kills}", playerKillsFormatted, "kills.player");
// do we add the lore based on the config?
if (toolStats.checkConfig(newTrident, "player-kills")) {
meta.setLore(newLore);
}
newTrident.setItemMeta(meta);
return newTrident;
}
}

View File

@@ -18,13 +18,17 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.tools.ItemChecker;
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,7 +40,7 @@ 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) {
@@ -45,11 +49,20 @@ public class EntityDeath implements Listener {
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 (ItemChecker.isValidItem(droppedItem.getType())) {
ItemStack newItem = addLore(droppedItem, livingEntity.getName());
if (newItem != null) {
event.getDrops().set(i, newItem);
}
}
}
@@ -59,45 +72,26 @@ public class EntityDeath implements Listener {
/**
* Adds "drop by" tag to item.
* @param itemStack The item to add lore to.
* @param mob The mob or player name.
*
* @param oldItem The item to add lore to.
* @param mob The mob or player name.
*/
private void addLore(ItemStack itemStack, String mob) {
ItemMeta meta = itemStack.getItemMeta();
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);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{name}", mob, "dropped-by");
if (toolStats.config.getBoolean("enabled.dropped-by")) {
meta.setLore(lore);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
newItem.setItemMeta(meta);
return newItem;
}
}

View File

@@ -18,11 +18,16 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.Bukkit;
import lol.hyper.toolstats.tools.ItemChecker;
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;
@@ -31,57 +36,98 @@ 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.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();
// run task later since if it runs on the same tick it breaks idk
Bukkit.getScheduler().runTaskLater(toolStats, () -> {
Player player = (Player) chest.getViewers().get(0);
// do a classic for loot so we keep track of chest index of item
for (int i = 0; i < chest.getContents().length; i++) {
ItemStack itemStack = chest.getItem(i);
// ignore air
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();
Inventory chestInv = inventoryHolder.getInventory();
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);
// run task later since if it runs on the same tick it breaks
Block finalOpenedChest = openedChest;
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
Player player = toolStats.playerInteract.openedChests.get(finalOpenedChest);
// keep track of chest index of item
for (int i = 0; i < chestInv.getContents().length; i++) {
ItemStack itemStack = chestInv.getItem(i);
// ignore air
if (itemStack == null || itemStack.getType() == Material.AIR) {
continue;
}
if (ItemChecker.isValidItem(itemStack.getType())) {
ItemStack newItem = addLore(itemStack, player);
if (newItem != null) {
chestInv.setItem(i, newItem);
}
}
}
}
};
toolStats.scheduleRegion(runnable, lootLocation.getWorld(), lootLocation.getChunk(), 1);
}
if (inventoryHolder instanceof StorageMinecart) {
StorageMinecart mineCart = (StorageMinecart) inventoryHolder;
if (toolStats.playerInteract.openedMineCarts.containsKey(mineCart)) {
Player player = toolStats.playerInteract.openedMineCarts.get(mineCart);
// player clicked this minecart
for (int i = 0; i < chestInv.getContents().length; i++) {
ItemStack itemStack = chestInv.getItem(i);
// ignore air
if (itemStack == null || itemStack.getType() == Material.AIR) {
continue;
}
if (ItemChecker.isValidItem(itemStack.getType())) {
ItemStack newItem = addLore(itemStack, player);
if (newItem != null) {
chestInv.setItem(i, newItem);
}
}
}
}
}
}
/**
* Adds lore to newly generated items.
*
* @param itemStack The item to add lore to.
* @param owner The player that found the item.
* @param owner The player that found the item.
* @return The item with the lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
@@ -100,27 +146,14 @@ public class GenerateLoot implements Listener {
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);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (foundByLoreRaw == null || foundOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.looted!");
return null;
}
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(newLore);
}
meta.setLore(lore);
newItem.setItemMeta(meta);
return newItem;
}

View File

@@ -0,0 +1,87 @@
/*
* 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.ItemChecker;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
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.List;
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();
for (ItemStack itemStack : inventory) {
if (itemStack == null) {
continue;
}
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) {
continue;
}
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// ignore any items that already have the origin tag
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
continue;
}
// ignore items that are not the right type
if (!ItemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta newMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA);
if (newMeta == null) {
continue;
}
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
itemStack.setItemMeta(newMeta);
}
};
Location location = inventory.getLocation();
// only run for actual inventories
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,38 +31,44 @@ 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)) {
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);
}
}
}
}
}
@@ -69,41 +76,31 @@ public class PickupItem implements Listener {
/**
* Adds "looted by" tags for elytras.
*
* @param itemStack The elytra to add lore to.
* @param owner The player who found it.
* @param owner The player who found it.
*/
private void addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
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();
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);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
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()));
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.ItemChecker;
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 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,29 +56,59 @@ 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);
// make sure the player is holding a fishing rod
// player can fish with their offhand
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();
}
// 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 (ItemChecker.isValidItem(caughtItem.getType())) {
ItemStack newItem = addNewLore(caughtItem, player);
if (newItem != null) {
caughtItemEntity.setItemStack(newItem);
}
}
}
/**
* Updates a fishing rod's count.
* @param itemStack The fishing rod to update.
* Update a fishing rod's fish count.
*
* @param fishingRod The fishing rod to update.
*/
private void updateFishCount(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
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;
@@ -89,91 +116,56 @@ 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++;
fishCaught = 0;
toolStats.logger.warning(fishingRod + " does not have valid fish-caught set! Resting to zero. This should NEVER happen.");
}
fishCaught++;
container.set(toolStats.fishingRodCaught, PersistentDataType.INTEGER, fishCaught);
String fishCaughtLore = toolStats.getLoreFromConfig("fished.fish-caught", false);
String fishCaughtLoreRaw = toolStats.getLoreFromConfig("fished.fish-caught", true);
String fishCaughtFormatted = toolStats.numberFormat.formatInt(fishCaught);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{fish}", fishCaughtFormatted, "fished.fish-caught");
if (fishCaughtLore == null || fishCaughtLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.fish-caught!");
return;
}
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)));
}
if (toolStats.config.getBoolean("enabled.fish-caught")) {
meta.setLore(lore);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
fishingRod.setItemMeta(meta);
}
/**
* Adds "caught by" tags to newly fished items.
* @param itemStack The item to add lore to.
* @param owner The player who caught the item.
* 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 void addNewLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
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;
}
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);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (caughtByLoreRaw == null || caughtOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.fished!");
return;
if (toolStats.checkConfig(newItem, "fished-tag")) {
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,96 @@
/*
* 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;
public class PlayerInteract implements Listener {
private final ToolStats toolStats;
public final HashMap<Block, Player> openedChests = new HashMap<>();
public final HashMap<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,83 @@
/*
* 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.ItemChecker;
import org.bukkit.Location;
import org.bukkit.Material;
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;
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;
}
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) {
continue;
}
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
// ignore any items that already have the origin tag
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
continue;
}
// ignore items that are not the right type
if (!ItemChecker.isValidItem(itemStack.getType())) {
continue;
}
ItemMeta newMeta = toolStats.itemLore.getOrigin(itemMeta, itemStack.getType() == Material.ELYTRA);
if (newMeta == null) {
continue;
}
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
itemStack.setItemMeta(newMeta);
}
};
Location location = inventory.getLocation();
// only run for actual inventories
if (location != null) {
toolStats.scheduleRegion(runnable, location.getWorld(), location.getChunk(), 1);
}
}
}
}

View File

@@ -18,19 +18,21 @@
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 java.util.ArrayList;
import java.util.List;
public class SheepShear implements Listener {
@@ -41,36 +43,64 @@ 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;
}
// check if the player is right-clicking with shears only
ItemStack heldItem = player.getInventory().getItem(player.getInventory().getHeldItemSlot());
if (heldItem == null || heldItem.getType() == Material.AIR || heldItem.getType() != Material.SHEARS) {
// make sure the player is holding shears
// player can shear with their offhand
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 fishing rods in both hands
// default to main hand since that takes priority
if (isMainHand && isOffHand) {
shears = inventory.getItemInMainHand();
}
// player swapped items?
if (shears == null) {
return;
}
Sheep sheep = (Sheep) entity;
// make sure the sheep is not sheared
if (!sheep.isSheared()) {
addLore(heldItem);
if (sheep.isSheared()) {
return;
}
// update the stats
ItemStack finalShears = shears;
addLore(finalShears);
}
/**
* Adds tags to shears.
* @param itemStack The shears.
*
* @param newShears The shears.
*/
private void addLore(ItemStack itemStack) {
ItemMeta meta = itemStack.getItemMeta();
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;
@@ -78,47 +108,21 @@ 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++;
sheepSheared = 0;
toolStats.logger.warning(newShears + " does not have valid sheared set! Resting to zero. This should NEVER happen.");
}
sheepSheared++;
container.set(toolStats.shearsSheared, PersistentDataType.INTEGER, sheepSheared);
String sheepShearedLore = toolStats.getLoreFromConfig("sheep-sheared", false);
String sheepShearedLoreRaw = toolStats.getLoreFromConfig("sheep-sheared", true);
String sheepShearedFormatted = toolStats.numberFormat.formatInt(sheepSheared);
List<String> newLore = toolStats.itemLore.addItemLore(meta, "{sheep}", sheepShearedFormatted, "sheep-sheared");
if (sheepShearedLore == null || sheepShearedLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.sheep-sheared!");
return;
}
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)));
}
if (toolStats.config.getBoolean("enabled.sheep-sheared")) {
meta.setLore(lore);
meta.setLore(newLore);
}
itemStack.setItemMeta(meta);
newShears.setItemMeta(meta);
}
}

View File

@@ -18,11 +18,13 @@
package lol.hyper.toolstats.events;
import lol.hyper.toolstats.ToolStats;
import lol.hyper.toolstats.UUIDDataType;
import org.bukkit.Bukkit;
import lol.hyper.toolstats.tools.ItemChecker;
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,67 +35,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();
// only check items we want
for (String x : validItems) {
if (item.getType().toString().toLowerCase(Locale.ROOT).contains(x)) {
// if the player shift clicks show the warning
if (event.isShiftClick()) {
String configMessage = toolStats.config.getString("messages.shift-click-warning.trading");
if (configMessage != null) {
event.getWhoClicked().sendMessage(ChatColor.translateAlternateColorCodes('&', configMessage));
}
}
ItemStack newItem = addLore(item, (Player) event.getWhoClicked());
if (newItem == null) {
return;
}
// this gets delayed since villager inventories suck for no reason
// if you don't delay this it doesn't work idk
Bukkit.getScheduler().runTaskLater(toolStats, ()-> event.setCurrentItem(newItem), 5);
if (!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);
}
}
}
}
/**
* Adds "traded by" tags to item.
* @param itemStack The item to add lore.
* @param owner The player who traded.
*
* @param oldItem The item to add lore.
* @param owner The player who traded.
* @return The item with lore.
*/
private ItemStack addLore(ItemStack itemStack, Player owner) {
ItemMeta meta = itemStack.getItemMeta();
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();
@@ -106,28 +108,15 @@ public class VillagerTrade implements Listener {
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);
String formattedDate = toolStats.numberFormat.formatDate(finalDate);
List<String> newLore = toolStats.itemLore.addNewOwner(meta, owner.getName(), formattedDate);
if (tradedByLoreRaw == null || tradedOnLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages.traded!");
return null;
if (toolStats.checkConfig(newItem, "traded-tag")) {
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,71 @@
/*
* 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.Arrays;
import java.util.Locale;
public class ItemChecker {
private static final String[] validItems = { "pickaxe", "sword", "shovel", "axe", "hoe", "bow", "helmet", "chestplate", "leggings", "boots", "fishing", "elytra" };
private static final String[] validArmor = { "helmet", "chestplate", "leggings", "boots" };
private static final String[] validMelee = {"sword", "trident", "axe"};
private static final String[] validMine = { "pickaxe", "axe", "hoe", "shovel", "shear" };
/**
* Check if item is an armor piece.
*
* @param itemType The item type, not name.
* @return If the item is an armor piece.
*/
public static boolean isArmor(Material itemType) {
return Arrays.stream(validArmor).anyMatch(type -> itemType.toString().toLowerCase(Locale.ROOT).contains(type));
}
/**
* 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 static boolean isValidItem(Material itemType) {
return Arrays.stream(validItems).anyMatch(type -> itemType.toString().toLowerCase(Locale.ROOT).contains(type));
}
/**
* Check if item is a melee weapon.
*
* @param itemType The item type, not name.
* @return If the item is a melee weapon.
*/
public static boolean isMeleeWeapon(Material itemType) {
return Arrays.stream(validMelee).anyMatch(type -> itemType.toString().toLowerCase(Locale.ROOT).contains(type));
}
/**
* Check if item is a mining tool.
*
* @param itemType The item type, not name.
* @return If the item is a mining tool.
*/
public static boolean isMineTool(Material itemType) {
return Arrays.stream(validMine).anyMatch(type -> itemType.toString().toLowerCase(Locale.ROOT).contains(type));
}
}

View File

@@ -0,0 +1,200 @@
/*
* 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;
public class ItemLore {
private final ToolStats toolStats;
public ItemLore(ToolStats toolStats) {
this.toolStats = toolStats;
}
/**
* Adds new lore to an item.
*
* @param placeholder The placeholder from the config. ex: {kills}
* @param placeholderValue The value to replace the placeholder.
* @param configLorePath The path to the config message.
* @return The item's new lore.
*/
public List<String> addItemLore(ItemMeta itemMeta, String placeholder, String placeholderValue, String configLorePath) {
String configLore = toolStats.getLoreFromConfig(configLorePath, false);
String configLoreRaw = toolStats.getLoreFromConfig(configLorePath, true);
if (configLore == null || configLoreRaw == null) {
toolStats.logger.warning("There is no lore message for messages." + configLorePath + "!");
toolStats.logger.warning("Unable to update lore for item.");
return itemMeta.getLore();
}
List<String> newLore;
// replace the placeholder with the value
// ex: {kills} -> a number
String newLine = configLoreRaw.replace(placeholder, placeholderValue);
if (itemMeta.hasLore()) {
newLore = itemMeta.getLore();
// keep track of line index
// this doesn't mess the lore of existing items
for (int x = 0; x < newLore.size(); x++) {
// check to see if the line matches the config value
// this means we update this line only!
if (newLore.get(x).contains(configLore)) {
newLore.set(x, newLine);
return newLore;
}
}
// if the item has lore, but we didn't find the line
newLore.add(newLine);
} else {
// if the item has no lore, create a new list and add the line
newLore = new ArrayList<>();
newLore.add(newLine);
}
return newLore;
}
/**
* Adds new ownership tag 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 dateCreated = null;
String itemOwner = null;
Integer origin = null;
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
if (container.has(toolStats.originType, PersistentDataType.INTEGER)) {
origin = container.get(toolStats.originType, PersistentDataType.INTEGER);
}
if (origin == null) {
origin = -1;
}
switch (origin) {
case 2: {
dateCreated = toolStats.getLoreFromConfig("looted.looted-on", true);
itemOwner = toolStats.getLoreFromConfig("looted.looted-by", true);
break;
}
case 3: {
dateCreated = toolStats.getLoreFromConfig("traded.traded-on", true);
itemOwner = toolStats.getLoreFromConfig("traded.traded-by", true);
break;
}
case 4: {
dateCreated = toolStats.getLoreFromConfig("looted.found-on", true);
itemOwner = toolStats.getLoreFromConfig("looted.found-by", true);
break;
}
case 5: {
dateCreated = toolStats.getLoreFromConfig("fished.caught-on", true);
itemOwner = toolStats.getLoreFromConfig("fished.caught-by", true);
break;
}
}
if (dateCreated == null || itemOwner == null) {
toolStats.logger.info("Unable to determine origin of item for " + itemMeta);
return itemMeta.getLore();
}
List<String> newLore;
if (itemMeta.hasLore()) {
newLore = itemMeta.getLore();
} else {
newLore = new ArrayList<>();
}
newLore.add(dateCreated.replace("{date}", formattedDate));
newLore.add(itemOwner.replace("{player}", playerName));
return newLore;
}
/**
* Determine an item's origin based on lore.
*
* @param itemMeta The item's meta.
* @param elytra If they item is an elytra.
* @return The new item meta with the new origin tag. Returns null if origin cannot be determined.
*/
public ItemMeta getOrigin(ItemMeta itemMeta, boolean elytra) {
List<String> lore;
if (!itemMeta.hasLore()) {
return null;
}
lore = itemMeta.getLore();
Integer origin = null;
for (String line : lore) {
// this is the worst code I have ever written
String createdBy = toolStats.getLoreFromConfig("created.created-by", false);
String createdOn = toolStats.getLoreFromConfig("created.created-on", false);
String caughtBy = toolStats.getLoreFromConfig("fished.caught-by", false);
String lootedBy = toolStats.getLoreFromConfig("looted.looted-by", false);
String foundBy = toolStats.getLoreFromConfig("looted.found-by", false);
String tradedBy = toolStats.getLoreFromConfig("traded.traded-by", false);
if (createdBy != null && line.contains(createdBy)) {
origin = 0;
}
if (createdOn != null && line.contains(createdOn)) {
origin = 0;
}
if (caughtBy != null && line.contains(caughtBy)) {
origin = 5;
}
if (lootedBy != null && line.contains(lootedBy)) {
origin = 2;
}
// because the config changed, "found-by" was being used for ALL looted items
// this includes elytras, so we have to check for this mistake
if (foundBy != null && line.contains(foundBy)) {
if (elytra) {
origin = 4;
} else {
origin = 5;
}
}
if (tradedBy != null && line.contains(tradedBy)) {
origin = 3;
}
}
if (origin == null) {
return null;
}
PersistentDataContainer container = itemMeta.getPersistentDataContainer();
container.set(toolStats.originType, PersistentDataType.INTEGER, origin);
return itemMeta;
}
}

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

@@ -80,6 +80,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:
@@ -98,4 +100,17 @@ messages:
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"
config-version: 5

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