Compare commits

...
190 Commits
Author SHA1 Message Date
Elikill58 26b71376b1 Upgrade to 2.4.6 2023-02-27 22:59:58 +01:00
Elikill58 9b25f2e0ae Fix control 2023-02-27 17:39:50 +01:00
dependabot[bot] cd40bc0894 Bump EcoEnchants from 9.17.0 to 9.17.1 (#63)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.17.0 to 9.17.1.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.17.0...9.17.1)

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 18:08:33 +01:00
dependabot[bot] 06493ab38c Bump EcoEnchants from 9.16.0 to 9.17.0 (#62)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.16.0 to 9.17.0.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.16.0...9.17.0)

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-13 21:00:23 +01:00
Elikill58 5c3519171e Change for string 2023-02-13 20:59:48 +01:00
Elikill58 ca6982d7b0 Clean for empty lines 2023-02-11 16:19:06 +01:00
dependabot[bot] 1c5a8dbdcc Bump EcoEnchants from 9.15.0 to 9.16.0 (#61)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.15.0 to 9.16.0.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.15.0...9.16.0)

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-30 12:26:33 +01:00
Elikill58 0cf3c25b2c Prevent NPE 2023-01-27 10:04:47 +01:00
Elikill58 d0122a123e Update few things 2023-01-26 10:49:59 +01:00
dependabot[bot] 5493d76d00 Bump EcoEnchants from 9.14.4 to 9.15.0 (#56)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.14.4 to 9.15.0.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.14.4...9.15.0)

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 17:54:58 +01:00
Elikill58 7fc535ffc6 Introduce chat object (#57)
* Refactor how manager check messages

* Rename config variables

* Fix searching chat id

* Remove some debug lines

* Change default config

* Fix for empty recipients
2023-01-09 17:54:46 +01:00
Elikill58 8b9f9a2842 Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2023-01-03 17:10:38 +01:00
Elikill58 c60ade6a9c Skip mmo item wrong val 2023-01-03 17:10:27 +01:00
dependabot[bot] a0265599f6 Bump EcoEnchants from 9.14.3 to 9.14.4 (#55)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.14.3 to 9.14.4.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.14.3...9.14.4)

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-02 11:12:09 +01:00
dependabot[bot] 9f45069c08 Bump EcoEnchants from 9.13.0-all to 9.14.3 (#54)
Bumps EcoEnchants from 9.13.0-all to 9.14.3.

---
updated-dependencies:
- dependency-name: com.willfp:EcoEnchants
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-26 23:44:33 +01:00
Elikill58 f3b95ad32d Prevent trying to save file 2022-12-18 11:28:33 +01:00
dependabot[bot] 444d58900e Bump viaversion-api from 4.3.0 to 4.5.1 (#50)
Bumps viaversion-api from 4.3.0 to 4.5.1.

---
updated-dependencies:
- dependency-name: com.viaversion:viaversion-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 21:10:16 +01:00
Elikill58 72f239b293 Fix ComponentNMS 2022-12-12 21:09:11 +01:00
Elikill58 6bc0b919c5 Be able to continue to next manager 2022-12-10 12:53:07 +01:00
Elikill58 4864272c34 Multiple quick fix 2022-12-10 12:49:23 +01:00
Elikill58 a421e6e167 Be able to use direct base component object 2022-12-09 10:56:26 +01:00
Elikill58 76c6bafea7 Fix for children and adventure 2022-12-09 10:43:53 +01:00
Elikill58 f50dd5a1f8 Update adventure support 2022-12-09 00:04:41 +01:00
Elikill58 0dbc6c14bb Fix wrong var used 2022-12-07 21:41:41 +01:00
Elikill58 1d41b02f79 Fix #46 2022-12-07 18:02:07 +01:00
Elikill58 ec278c7d08 Update versions 2022-12-07 17:15:57 +01:00
dependabot[bot] 5729dbf4a6 Bump discordsrv from 1.25.1 to 1.26.0 (#48)
Bumps [discordsrv](https://github.com/DiscordSRV/DiscordSRV) from 1.25.1 to 1.26.0.
- [Release notes](https://github.com/DiscordSRV/DiscordSRV/releases)
- [Commits](https://github.com/DiscordSRV/DiscordSRV/compare/v1.25.1...v1.26.0)

---
updated-dependencies:
- dependency-name: com.discordsrv:discordsrv
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-07 16:05:38 +01:00
Elikill58 4129b52dc5 Update workflow versions 2022-12-07 16:05:22 +01:00
Elikill58 55c9cc6673 Update ViaVersion (Fix #49) 2022-12-07 16:04:14 +01:00
dependabot[bot] 59e75770fb Bump netty-all from 4.1.53.Final to 4.1.58.Final (#47)
Bumps netty-all from 4.1.53.Final to 4.1.58.Final.

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-07 16:01:30 +01:00
Elikill58 d6ce0c62ff Delete travis file 2022-12-07 16:00:45 +01:00
Elikill58 0ef13e39ae Add dependabot 2022-12-07 15:59:28 +01:00
Elikill58 26b0837784 Temporary remove EcoEnchants support to prevent error 2022-12-07 15:58:18 +01:00
Elikill58 1f3a510411 Remove log4j unused thing 2022-12-07 15:29:46 +01:00
Elikill58 039d5fb6d5 Remove name showed 2022-12-07 14:54:20 +01:00
Elikill58 048fe69204 Missing one change 2022-12-04 23:28:39 +01:00
Elikill58 358c574153 Maybe fix empty extra 2022-12-04 23:27:18 +01:00
Elikill58 efa0a345f9 Add more loggers 2022-12-04 22:58:53 +01:00
Elikill58 78670bf8ec Fix multiple send 2022-11-19 08:58:36 +01:00
Elikill58 a47b93ea1a Upgrade to snapshot 2022-11-16 19:11:17 +01:00
Elikill58 f4d56b56e1 Fix double name 2022-11-16 19:10:51 +01:00
Elikill58 3eb54bb4d6 Fix mistake 2022-11-15 12:09:23 +01:00
Elikill58 a0f54df9b7 Fix color codes 2022-11-15 12:07:22 +01:00
Elikill58 80a000cee7 Update NMS behavior 2022-11-15 11:56:13 +01:00
Elikill58 8bd6bed5fb rename components 2022-11-15 11:11:42 +01:00
Elikill58 ba5e8d9935 Complete refactor of String ComponentGetter 2022-11-15 11:10:39 +01:00
Elikill58 8d6b3e7987 Quickly change for some extra/text things 2022-11-14 23:13:27 +01:00
Elikill58 3fd14b3bdb Upgrade to 2.4.5 2022-10-18 19:40:45 +02:00
Elikill58 6c3784e662 Fix multiple quick issues 2022-10-12 17:27:34 +02:00
Elikill58 6256de065e Change base component 2022-10-03 16:10:59 +02:00
Elikill58 4c1d64f04c Fix v1 detection in v2 2022-09-26 09:20:34 +02:00
Elikill58 4475f19268 Upgrade to snapshot 2022-09-14 15:50:01 +02:00
Elikill58 2b5065dbec Update multiple things into v1 2022-09-14 15:49:27 +02:00
Elikill58 ba54582f7f Fix only first line take in count 2022-08-30 12:31:08 +02:00
Elikill58 2b0de9aa3c Upgrade to 2.4.4 2022-08-26 08:11:55 +02:00
Elikill58 3981992e37 Fix for new packet version 2022-08-24 09:56:51 +02:00
Elikill58 439710086e Fix color and hover 2022-08-12 08:43:51 +02:00
Elikill58 f5381b0430 Fix unknow color code 2022-08-12 08:28:06 +02:00
Elikill58 3cce52953a Make things more global 2022-08-12 08:16:58 +02:00
Elikill58 797de9c602 Fix issue with shulker check 2022-08-08 14:43:23 +02:00
Elikill58 c7f76d9f7b Fix #43 2022-08-08 14:37:28 +02:00
Elikill58 3947ea88d5 Add debug things 2022-07-26 15:56:02 +02:00
Elikill58 cc30049fdf Prevent error with books 2022-07-26 15:54:41 +02:00
Elikill58 7a964bb97c Upgrade to snapshot 2022-07-26 15:50:12 +02:00
Elikill58 13bbf3e5ca Fix first color thing 2022-07-22 12:44:11 +02:00
Elikill58 46de91b2ff Add some messages in config 2022-07-22 11:37:33 +02:00
Elikill58 cb5b3acab0 Add check update in admin inv 2022-07-22 11:36:52 +02:00
Elikill58 6f6d4dc263 Fix hex color 2022-07-22 11:33:29 +02:00
Elikill58 250b119391 Several fix 2022-07-21 23:00:51 +02:00
Elikill58 beee98d5d6 Upgrade to 2.4.3 2022-07-21 17:58:33 +02:00
Elikill58 4d270891be Fix when not using extra 2022-07-21 17:21:37 +02:00
Elikill58 7e9352661e Fix multiple color for same chat line 2022-07-21 17:17:31 +02:00
Elikill58 3f47d56bed Add chatitem broadcast command 2022-07-21 11:27:51 +02:00
Elikill58 1d0cac3a2b Fix chatitem show 2022-07-20 19:31:31 +02:00
Elikill58 64da26ea9f Use protocollib for all versions 2022-07-19 17:18:37 +02:00
Elikill58 4e53b6d5b0 Fix diff for spigot & paper 2022-07-16 09:50:01 +02:00
Elikill58 3b4ede3c22 Fix lib issue 2022-07-15 22:42:50 +02:00
Elikill58 59aade10a7 Prevent higher version 2022-07-15 10:53:05 +02:00
Elikill58 cd5bf7281b Change how color are managed 2022-07-15 10:48:59 +02:00
Elikill58 cd5bd87835 Fix wrong version detection 2022-07-12 21:36:49 +02:00
Elikill58 9384277901 Update few debugger 2022-07-12 19:42:57 +02:00
Elikill58 3b43e647a4 Update color management for v2 2022-07-12 19:34:23 +02:00
Elikill58 f28ad44e62 Fix color code 2022-07-12 18:53:21 +02:00
Elikill58 0baec19db1 Upgrade to snpashot 2022-07-12 18:13:02 +02:00
Elikill58 8ea83b3fab Prevent cooldown 2022-07-12 18:12:17 +02:00
Elikill58 7eaadd9ad6 Fix color 2022-07-08 11:27:05 +02:00
Elikill58 506985c9d1 Fix custom enchants 2022-07-08 10:04:55 +02:00
Elikill58 3fb0181ad7 Wrong char <.< 2022-07-08 09:29:14 +02:00
Elikill58 fc56bb6017 Add command to show item in chat 2022-07-05 23:10:14 +02:00
Elikill58 d9c60f45a4 Quick several fix 2022-07-02 14:32:25 +02:00
Elikill58 342060b86e Upgrade to 2.4.2 2022-06-30 16:10:38 +02:00
Elikill58 b5b30bd9d8 Fix hex color 2022-06-27 18:28:17 +02:00
Elikill58 55eaac0bd4 Update players 2022-06-25 18:27:29 +02:00
Elikill58 7583aeade7 Update constructor 2022-06-25 18:27:04 +02:00
Elikill58 4be3712082 Fix compatibility with old PL 2022-06-23 16:22:51 +02:00
Elikill58 c1e28709ac Fix array as string 2022-06-23 01:01:06 +02:00
Elikill58 f0965efe73 Fix wrong constructor used 2022-06-23 00:20:09 +02:00
Elikill58 529cdd1e04 Second wave to fix with other plugins 2022-06-22 17:35:23 +02:00
Elikill58 ce867d4065 Remove tag for adventure 2022-06-21 17:29:08 +02:00
Elikill58 1eefb78157 Fix adventure not found 2022-06-21 16:44:08 +02:00
Elikill58 ff0c8d2a8d Upgrade to snapshot 2022-06-21 15:29:22 +02:00
Elikill58 5a250d854d Upgrade to 2.4.1 2022-06-15 00:53:36 +02:00
Elikill58 caacf0d8ae Don't use deprecated things 2022-06-15 00:52:18 +02:00
Elikill58 0f7d4a0548 Remove strange char 2022-06-15 00:49:33 +02:00
Elikill58 4529f74f0a Update dependencies 2022-06-15 00:49:06 +02:00
Elikill58 1eaf32983a Fix purpur issue 2022-06-14 10:15:49 +02:00
Elikill58 24b0682e8b Go to snapshot 2022-06-14 09:25:28 +02:00
Elikill58 cbf3326de6 Fix, again 2022-06-13 19:12:40 +02:00
Elikill58 c4ae9198a4 Fix #41 (included in spigot release) 2022-06-13 15:28:15 +02:00
Elikill58 c01798f2e2 Upgrade to 2.4 2022-06-12 20:27:49 +02:00
Elikill58 5de8dbe98a Update item method 2022-06-10 18:01:41 +02:00
Elikill58 00eecd1841 Remove other useless debug 2022-06-10 16:37:00 +02:00
Elikill58 54783d657e Remove useless debug 2022-06-10 16:36:03 +02:00
Elikill58 e17b618b18 Fix v1 packets 2022-06-10 16:30:44 +02:00
Elikill58 3c8371fe28 Fix v2 chat manager for empty items 2022-06-10 14:42:29 +02:00
Elikill58 aafb677d01 Fix channel detection 2022-06-10 11:03:02 +02:00
Elikill58 3a945560a8 If it doesn't works, it's not because of me. Sorry for github msg 2022-06-06 20:57:01 +02:00
Elikill58 516156624e Upgrade maven compiler 2022-06-06 20:45:25 +02:00
Elikill58 b6e37edfa3 Update maven's plugin 2022-06-06 20:30:27 +02:00
Elikill58 6772d26747 Use java version 2022-06-06 20:26:17 +02:00
Elikill58 145ff70e3d Let maven manage own things 2022-06-06 20:24:12 +02:00
Elikill58 cd57c3d37f Change maven copmpiler option 2022-06-06 20:11:18 +02:00
Elikill58 80413bab3a Remove jitpack file and just use maven things 2022-06-06 20:00:59 +02:00
Elikill58 319e70696e Add target java versions 2022-06-06 19:46:20 +02:00
Elikill58 dfda46bcb7 Make jitpack use JDK 17 2022-06-06 19:29:32 +02:00
Elikill58 848a44c5da Finally fix with Kyori adventure messae 2022-06-01 19:01:06 +02:00
Elikill58 48a0666c79 Fix writing issue 2022-06-01 17:15:44 +02:00
Elikill58 d828a747db Possible fix for cmd 2022-06-01 17:02:12 +02:00
Elikill58 7ff7eb20b9 Change how base component is obtained 2022-06-01 16:57:15 +02:00
Elikill58 bae9d14ae5 Add discordSRV as soft dep 2022-05-31 22:44:04 +02:00
Elikill58 9b2fc7da65 Rename method 2022-05-30 13:33:32 +02:00
Elikill58 163686cf77 Fix discord srv message 2022-05-30 12:21:57 +02:00
Elikill58 895fbcf07e Fix ProtocolLib support 2022-05-23 22:14:46 +02:00
Elikill58 004131ddc3 Remove some useless color codes 2022-05-23 22:03:19 +02:00
Elikill58 e59d116918 Prevent some message to be sent multiple times 2022-05-23 17:10:07 +02:00
Elikill58 4ee9d4525a Fix cooldown 2022-05-15 11:11:12 +02:00
Elikill58 3d1672d4ef Upgrade to 2.3 2022-05-11 10:52:34 +02:00
Elikill58 91fc9ee913 Don't use removed class 2022-05-09 19:57:14 +02:00
Elikill58 15604b0ec4 Wtf wrong item 2022-05-08 17:38:37 +02:00
Elikill58 8108b949f7 Refactor of json manipulator 2022-05-06 11:55:36 +02:00
Elikill58 aabaa2a332 Remove wtf file 2022-05-03 22:03:08 +02:00
Elikill58 0896a7c63e Fix packet manager not well working 2022-05-03 22:02:52 +02:00
Elikill58 b4b6b19ec3 Fix limit message wrong triggering 2022-05-03 13:52:12 +02:00
Elikill58 93289f5b24 Fix possible NPE 2022-05-02 12:52:31 +02:00
Elikill58 5810652007 Add EcoEnchants support 2022-04-28 20:50:11 +02:00
Elikill58 1e92763497 Make method generic to fix for cmd in v1 2022-04-23 21:57:37 +02:00
Elikill58 a699c807fd Fix limit not working 2022-04-23 21:49:37 +02:00
Elikill58 7ef48f4202 Move some methods 2022-04-23 21:42:21 +02:00
Elikill58 7dc8042de7 Fix multiple items 2022-04-18 17:13:24 +02:00
Elikill58 9d13bd482c Fix loading managers 2022-04-18 16:50:10 +02:00
outsparkled 306ab41f08 Code cleanups (#39) 2022-04-15 18:17:44 +02:00
Elikill58 aea4950398 Fix error for PR without discord link 2022-04-15 11:24:45 +02:00
Elikill58 042c27c088 Fix building by using own ProtocolSupport build 2022-04-10 19:01:23 +02:00
Elikill58 b699d2ffad Fix object can't be founded 2022-04-10 17:12:11 +02:00
Elikill58 0400b0beaf Fix wrong name of item 2022-03-10 14:37:44 +01:00
Elikill58 88030f82b6 Fix wrong ID for 1.7 clients 2022-03-10 13:42:37 +01:00
Elikill58 e8f8bd5af4 Add way to show item with less informations for bugged clients 2022-03-10 13:39:48 +01:00
Elikill58 bfbcaf1598 Remove some debug messages 2022-03-10 13:07:39 +01:00
Elikill58 ffc57dd69a Clean code specially for json formatting 2022-03-10 13:03:29 +01:00
Elikill58 07fa5c256b Prevent some type of issues 2022-03-10 11:51:25 +01:00
Elikill58 c07357b89b Fix other placeholders 2022-03-10 01:01:40 +01:00
Elikill58 629d492fad Remove unused field 2022-03-10 00:58:00 +01:00
Elikill58 693ca51315 Fix NMU & content modifier 2022-03-10 00:56:36 +01:00
Elikill58 f65444cfe9 Put player as var 2022-03-10 00:30:09 +01:00
Elikill58 464b887ed5 Begin of prevent lunar issue 2022-03-10 00:26:24 +01:00
Elikill58 1bdf20feb0 Deprecated unused class to check in the future if they are useful 2022-03-06 02:00:57 +01:00
Elikill58 db89bfb5b5 Clean JSON use 2022-03-06 01:57:44 +01:00
Elikill58 efe2dd22e9 Use new json manager 2022-03-06 01:46:09 +01:00
Elikill58 144be87448 Upgrade to 2.2.1 2022-02-28 12:30:18 +01:00
Elikill58 217e7316b9 Add jitpack support 2022-02-26 14:10:11 +01:00
CatAndPaste 9bf2900bb5 Hot fix for hex-colored nicknames changed by Essentials-X. After the general hex-colored fix by Elikill58 that fixed 99% of the problem, first character formatting still was off (as you can see on screenshot: https://media.discordapp.net/attachments/171243756849201153/946441326205993010/unknown.png), this was caused by §r added to the begining of the name. I fixed an error by adding check for char 'r' in showItem function (ChatListener.java : 235). (#37) 2022-02-24 19:31:10 +01:00
Elikill58 23640b1772 Fix hex color ... again 2022-02-23 23:45:44 +01:00
Elikill58 fecf35b3a9 Add discord srv support and fix logged messages 2022-02-23 20:42:05 +01:00
Elikill58 8068fe6a7f Fix append for legacy versions 2022-02-23 19:31:23 +01:00
Elikill58 2f21538c76 Possible fix fox colors codes 2022-02-23 17:48:44 +01:00
Elikill58 340cad0b2f Fix item for old spigot version 2022-02-20 23:11:01 +01:00
Elikill58 0c51c73f31 Add option in inv to manage debug mode 2022-02-20 23:08:53 +01:00
Elikill58 717db94dc2 Prefer manage v1 rep if v2 is enabled 2022-02-20 23:02:11 +01:00
Elikill58 51e6708fcb Update which item is showed 2022-02-19 21:59:37 +01:00
Elikill58 a6f22d090a Fix some color for v1 2022-02-19 21:44:32 +01:00
Elikill58 979f39a171 If not comp, try to use chat base comp 2022-02-19 21:38:43 +01:00
Elikill58 0f057720b8 Prevent one method not found on some paper 2022-02-19 19:37:50 +01:00
Elikill58 a4eb8bd8fe Fix duplicated text 2022-02-19 19:21:11 +01:00
Elikill58 38a8f24c9c Add way to find ichatbase comp 2022-02-19 19:09:01 +01:00
Elikill58 82de0cf4dc Fix wrong parsing fields 2022-02-19 19:05:24 +01:00
Elikill58 13fcea5b57 Change how chat manager works 2022-02-19 15:52:35 +01:00
Elikill58 4292871294 Fix items messages (From XeonZ's config) 2022-02-18 11:06:22 +01:00
Elikill58 827c7f92ae Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2022-02-16 16:16:58 +01:00
Elikill58 bcd28eddca Prevent instance error 2022-02-16 15:32:51 +01:00
outsparkled 4d873146dd Fix gson compatibility issues on 1.8 and clean up pom (#36)
* Fix gson compatibility issues on 1.8 and clean up pom

* re-add export_dir
2022-02-15 19:42:33 +01:00
65 changed files with 2845 additions and 2417 deletions

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
+30
View File
@@ -0,0 +1,30 @@
name: Build v2 for PR
on:
pull_request:
branches: [ v2 ]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
name: Checkout repo
- name: Set up JDK 17 (LTS)
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
cache: maven
- name: Build with Maven
run: mvn install --file pom.xml
- uses: actions/upload-artifact@v3
name: Upload Artifact
with:
name: ChatItem.jar
path: target/ChatItem-*.jar
+3 -5
View File
@@ -3,8 +3,6 @@ name: Build v2
on:
push:
branches: [ v2 ]
pull_request:
branches: [ v2 ]
jobs:
build:
@@ -12,11 +10,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
name: Checkout repo
- name: Set up JDK 17 (LTS)
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
@@ -25,7 +23,7 @@ jobs:
- name: Build with Maven
run: mvn install --file pom.xml
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
name: Upload Artifact
with:
name: ChatItem.jar
-2
View File
@@ -1,2 +0,0 @@
language: java
script: "mvn clean package -DskipTests"
+70 -34
View File
@@ -6,7 +6,7 @@
<groupId>me.dadus33</groupId>
<artifactId>chatitem</artifactId>
<version>2.2</version>
<version>2.4.6</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -45,6 +45,14 @@
<id>elikill-repo</id>
<url>https://repo.eliapp.fr:8081/repository/internal/</url>
</repository>
<repository>
<id>dv8tion</id>
<url>https://m2.dv8tion.net/releases</url>
</repository>
<repository>
<id>Scarsz-Nexus</id>
<url>https://nexus.scarsz.me/content/groups/public/</url>
</repository>
</repositories>
@@ -63,15 +71,10 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
<scope>provided</scope>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.meowj</groupId>
@@ -82,26 +85,26 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>4.7.0</version>
<version>5.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>3.0.0</version>
<groupId>com.viaversion</groupId>
<artifactId>viaversion-api</artifactId>
<version>4.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.ProtocolSupport</groupId>
<groupId>io.shevchik</groupId>
<artifactId>ProtocolSupport</artifactId>
<version>f34959c331</version>
<version>1.18.2-1-dev</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.53.Final</version>
<scope>compile</scope>
<version>4.1.58.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.GeyserMC</groupId>
@@ -118,7 +121,25 @@
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>4.9.3</version>
<version>4.11.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.discordsrv</groupId>
<artifactId>discordsrv</artifactId>
<version>1.26.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.willfp</groupId>
<artifactId>EcoEnchants</artifactId>
<version>9.17.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -137,29 +158,20 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<outputDirectory>${dir}</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
@@ -168,6 +180,30 @@
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>com.google.gson</pattern>
<shadedPattern>me.dadus33.libs.gson</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori.adventure.text.serializer.bungeecord</pattern>
<shadedPattern>me.dadus33.libs.kyori.serializer.bungeecord</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*</artifact>
<excludes>
<exclude>net.kyori:examination-api:**</exclude>
<exclude>net.kyori:examination-string:**</exclude>
<exclude>net.kyori:adventure-platform-api:**</exclude>
<exclude>net.kyori:adventure-text-serializer-legacy:**</exclude>
<exclude>net.kyori:adventure-text-serializer-gson:**</exclude>
<exclude>net.kyori:adventure-platform-facet:**</exclude>
<exclude>net.kyori:adventure-nbt:**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
@@ -175,10 +211,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<outputDirectory>${export_dir}</outputDirectory>
</configuration>
<version>3.3.0</version>
<configuration>
<outputDirectory>${export_dir}</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
+123 -116
View File
@@ -1,8 +1,10 @@
package me.dadus33.chatitem;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.StringJoiner;
@@ -21,7 +23,6 @@ import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager;
import me.dadus33.chatitem.chatmanager.v2.ChatListenerChatManager;
import me.dadus33.chatitem.commands.CIReloadCommand;
import me.dadus33.chatitem.commands.ChatItemCommand;
import me.dadus33.chatitem.filters.Log4jFilter;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.listeners.InventoryListener;
import me.dadus33.chatitem.listeners.JoinListener;
@@ -34,153 +35,159 @@ import me.dadus33.chatitem.utils.Version;
public class ChatItem extends JavaPlugin {
public final static int CFG_VER = 13;
public static boolean discordSrvSupport = false, hasNewVersion = false;
private static ChatItem instance;
private Log4jFilter filter;
private final String brandChannelName = Version.getVersion().isNewerOrEquals(Version.V1_13) ? "minecraft:brand" : "MC|Brand";
private final List<ChatManager> chatManager = new ArrayList<>();
private Storage storage;
private boolean hasNewVersion = false;
private List<ChatManager> chatManager = new ArrayList<>();
private void chooseManagers() {
this.chatManager.forEach((cm) -> cm.unload(this));
this.chatManager.clear();
PluginManager pm = getServer().getPluginManager();
String managerName = getStorage().MANAGER;
if(managerName.equalsIgnoreCase("both")) {
this.chatManager.add(new PacketEditingChatManager(this));
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager automatically choosed: " + getVisualChatManagers());
} else if(managerName.equalsIgnoreCase("auto")) {
if(getPluginThatRequirePacket().stream().map(pm::getPlugin).filter(Objects::nonNull).count() > 0 && Version.getVersion().isNewerThan(Version.V1_7))
this.chatManager.add(new PacketEditingChatManager(this));
else
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager automatically choosed: " + getVisualChatManagers());
} else {
if(managerName.equalsIgnoreCase("packet")) {
this.chatManager.add(new PacketEditingChatManager(this));
getLogger().info("Manager choosed: " + getVisualChatManagers());
} else if(managerName.equalsIgnoreCase("chat")) {
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager choosed: " + getVisualChatManagers());
} else {
getLogger().severe("----- WARN -----");
getLogger().severe("Failed to find manager: " + managerName + ".");
getLogger().severe("Please reset your config and/or check wiki for more informations");
getLogger().severe("Using default manager: chat.");
getLogger().severe("----- WARN -----");
this.chatManager.add(new ChatListenerChatManager(this));
}
}
this.chatManager.forEach((cm) -> cm.load(this, getStorage()));
NamerManager.load(this);
PlayerNamerManager.load(this);
}
private List<String> getPluginThatRequirePacket(){
return Arrays.asList("DeluxeChat", "HexNicks", "VentureChat");
}
public static void reload(CommandSender sender) {
ChatItem pl = getInstance();
if(pl.getConfig() == null || pl.getConfig().getKeys(false).isEmpty())
pl.saveDefaultConfig();
if (pl.getConfig().getKeys(false).isEmpty())
pl.saveDefaultConfig();
pl.reloadConfig();
String oldChatManager = pl.storage.MANAGER;
String oldChatManager = pl.storage.manager;
pl.storage = new Storage(pl.getConfig());
pl.chooseManagers();
pl.filter.setStorage(pl.storage);
if (!pl.storage.RELOAD_MESSAGE.isEmpty())
sender.sendMessage(pl.storage.RELOAD_MESSAGE);
if(!oldChatManager.equalsIgnoreCase(pl.storage.MANAGER))
sender.sendMessage(ChatColor.GOLD + "Changing the manager with command reloading CAN produce issue. It's mostly suggested to restart after finding the better manager for you.");
if (!pl.storage.messageReload.isEmpty())
sender.sendMessage(pl.storage.messageReload);
if (!oldChatManager.equalsIgnoreCase(pl.storage.manager))
sender.sendMessage(ChatColor.GOLD + "Changing the manager with command reloading CAN produce issue. It's mostly suggested to restart after finding the better manager for you.");
}
public static ChatItem getInstance() {
return instance;
}
public static void debug(String msg) {
if (getInstance().getStorage().debug)
getInstance().getLogger().info("[Debug] " + msg.replace(ChatManager.SEPARATOR, 'S').replace(ChatManager.SEPARATOR_END, 'E'));
}
private void chooseManagers() {
this.chatManager.forEach((cm) -> cm.unload(this));
this.chatManager.clear();
PluginManager pm = getServer().getPluginManager();
String managerName = getStorage().manager;
switch (managerName.toLowerCase(Locale.ROOT)) {
case "both":
this.chatManager.add(new PacketEditingChatManager(this));
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager automatically chosen: " + getVisualChatManagers());
break;
case "auto":
if (getPluginThatRequirePacket().stream().map(pm::getPlugin).anyMatch(Objects::nonNull) && Version.getVersion().isNewerThan(Version.V1_7))
this.chatManager.add(new PacketEditingChatManager(this));
else
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager automatically chosen: " + getVisualChatManagers());
break;
case "packet":
this.chatManager.add(new PacketEditingChatManager(this));
getLogger().info("Manager chosen: " + getVisualChatManagers());
break;
case "chat":
this.chatManager.add(new ChatListenerChatManager(this));
getLogger().info("Manager chosen: " + getVisualChatManagers());
break;
default:
getLogger().severe("----- WARN -----");
getLogger().severe("Failed to find manager: " + managerName + ".");
getLogger().severe("Please reset your config and/or check wiki for more information");
getLogger().severe("Using default manager: chat.");
getLogger().severe("----- WARN -----");
this.chatManager.add(new ChatListenerChatManager(this));
break;
}
this.chatManager.forEach((cm) -> cm.load(this, getStorage()));
NamerManager.load(this);
PlayerNamerManager.load(this);
}
private List<String> getPluginThatRequirePacket() {
return Arrays.asList("DeluxeChat", "HexNicks", "VentureChat", "ItemsAdder");
}
@Override
public void onEnable() {
//Save the instance (we're basically a singleton)
instance = this;
//Load ProtocolManager
//pm = ProtocolLibrary.getProtocolManager();
getLogger().info("Detected server version: " + Version.getVersion().name().toLowerCase());
//Load config
saveDefaultConfig();
if(!new File(getDataFolder(), "config.yml").exists())
saveDefaultConfig();
storage = new Storage(getConfig());
//We halt the use of this system for now, until we can solve the infamous getProtocolVersion issue
//Till then, users of both ViaVersion and ProtocolSupport should do just fine
/*if(!protocolSupport && !viaVersion) {
//We only implement our own way of getting protocol versions if we have no other choice
pm.addPacketListener(new HandshakeListener(this, ListenerPriority.MONITOR, PacketType.Handshake.Client.SET_PROTOCOL));
}*/
//Commands
loadCommand(getCommand("cireload"), new CIReloadCommand());
loadCommand(getCommand("chatitem"), new ChatItemCommand());
// events
getServer().getPluginManager().registerEvents(new JoinListener(), this);
getServer().getPluginManager().registerEvents(new InventoryListener(), this);
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new JoinListener(), this);
pm.registerEvents(new InventoryListener(), this);
chooseManagers();
//Initialize Log4J filter (remove ugly console messages)
filter = new Log4jFilter(storage);
StringJoiner plugins = new StringJoiner(", ");
if (pm.isPluginEnabled("DiscordSRV")) {
discordSrvSupport = true;
plugins.add("DiscordSRV");
}
if(plugins.length() > 0)
getLogger().info("Load " + plugins.toString() + " support.");
if(storage.CHECK_UPDATE) {
getServer().getScheduler().runTaskAsynchronously(this, () -> {
String urlName = "https://api.spigotmc.org/legacy/update.php?resource=19064";
String content = Utils.getFromURL(urlName);
if(Strings.isNullOrEmpty(content))
return;
SemVer currentVersion = SemVer.parse(getDescription().getVersion());
if (currentVersion == null)
return;
SemVer latestVersion = SemVer.parse(content);
if (latestVersion != null && latestVersion.isNewerThan(currentVersion)) {
hasNewVersion = !content.equalsIgnoreCase(getDescription().getVersion());
if(hasNewVersion) {
getLogger().info(storage.JOIN_UPDATE_MESSAGE);
}
}
});
getServer().getMessenger().registerIncomingPluginChannel(this, brandChannelName, (chan, p, msg) -> ItemPlayer.getPlayer(p).setClientName(new String(msg).substring(1)));
if (storage.checkUpdate) {
getServer().getScheduler().runTaskAsynchronously(this, () -> {
String urlName = "https://api.spigotmc.org/legacy/update.php?resource=19064";
String content = Utils.getFromURL(urlName);
if (Strings.isNullOrEmpty(content))
return;
SemVer currentVersion = SemVer.parse(getDescription().getVersion());
if (currentVersion == null)
return;
SemVer latestVersion = SemVer.parse(content);
if (latestVersion != null && latestVersion.isNewerThan(currentVersion)) {
hasNewVersion = !content.equalsIgnoreCase(getDescription().getVersion());
if (hasNewVersion)
getLogger().info(storage.updateMessage);
}
});
}
}
public void loadCommand(PluginCommand cmd, Object obj) {
if(obj instanceof CommandExecutor)
cmd.setExecutor((CommandExecutor) obj);
if(obj instanceof TabCompleter)
cmd.setTabCompleter((TabCompleter) obj);
}
public Storage getStorage() {
return storage;
}
public List<ChatManager> getChatManager() {
return chatManager;
}
public String getVisualChatManagers() {
StringJoiner sj = new StringJoiner(", ");
for(ChatManager cm : chatManager) {
sj.add(cm.getName() + " (" + cm.getId() + ")");
}
return sj.toString();
public void loadCommand(PluginCommand cmd, Object obj) {
if (obj instanceof CommandExecutor)
cmd.setExecutor((CommandExecutor) obj);
if (obj instanceof TabCompleter)
cmd.setTabCompleter((TabCompleter) obj);
}
public Storage getStorage() {
return storage;
}
public List<ChatManager> getChatManager() {
return chatManager;
}
public String getVisualChatManagers() {
StringJoiner sj = new StringJoiner(", ");
for (ChatManager cm : chatManager) {
sj.add(cm.getName() + " (" + cm.getId() + ")");
}
return sj.toString();
}
public boolean isHasNewVersion() {
return hasNewVersion;
}
public static void debug(String msg) {
if(getInstance().getConfig().getBoolean("debug", false))
getInstance().getLogger().info("[Debug] " + msg);
return hasNewVersion;
}
}
@@ -0,0 +1,83 @@
package me.dadus33.chatitem;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.playerversion.PlayerVersionManager;
import me.dadus33.chatitem.utils.Version;
public class ItemPlayer {
private static final ConcurrentHashMap<UUID, ItemPlayer> PLAYERS = new ConcurrentHashMap<>();
public static ItemPlayer getPlayer(Player p) {
return PLAYERS.computeIfAbsent(p.getUniqueId(), ItemPlayer::new);
}
public static ItemPlayer getPlayer(UUID uuid) {
return PLAYERS.computeIfAbsent(uuid, ItemPlayer::new);
}
private final UUID uuid;
private int protocolVersion = 0;
private Version version = null;
private String clientName = "unknow";
public ItemPlayer(UUID uuid) {
this.uuid = uuid;
Player p = Bukkit.getPlayer(uuid);
if(p != null)
setVersion(PlayerVersionManager.getPlayerVersionAdapter().getPlayerVersion(p));
}
public UUID getUUID() {
return uuid;
}
public Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public int getProtocolVersion() {
if(protocolVersion == 0)
setProtocolVersion(PlayerVersionManager.getPlayerVersionAdapter().getProtocolVersion(getPlayer()));
return protocolVersion;
}
public void setProtocolVersion(int protocolVersion) {
this.protocolVersion = protocolVersion;
if(version == Version.getVersion()) {// if is default
version = Version.getVersion(protocolVersion);
ChatItem.debug("Detected version " + version.name() + " (protocol: " + protocolVersion + ")");
}
}
public Version getVersion() {
if(version == null)
setVersion(PlayerVersionManager.getPlayerVersionAdapter().getPlayerVersion(getPlayer()));
return version;
}
public void setVersion(Version version) {
this.version = version;
if(protocolVersion == 0)
this.protocolVersion = version.MAX_VER;
}
public boolean isBuggedClient() {
return getVersion().equals(Version.V1_7) && getClientName().toLowerCase().contains("lunarclient");
}
@Override
public String toString() {
return "ItemPlayer[uuid=" + uuid + ",name=" + (getPlayer() != null ? getPlayer().getName() : "-") + ",version=" + version.name() + ",protocol=" + protocolVersion + ",client=" + clientName + "]";
}
}
@@ -0,0 +1,86 @@
package me.dadus33.chatitem.chatmanager;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.utils.Utils;
public class Chat {
private static int actualId = 0;
private static final List<Chat> CHAT = new ArrayList<>();
public static Optional<Chat> getChat(int id) {
synchronized (CHAT) {
CHAT.removeIf(Chat::isOld);
return CHAT.stream().filter(o -> o.getId() == id).findFirst();
}
}
public static Chat create(Player p, String message) {
return new Chat(actualId++, p, message);
}
public static Chat getFrom(String message) {
boolean found = false;
String id = "";
for(char c : ChatManager.fixSeparator(message).toCharArray()) {
if(c == ChatManager.SEPARATOR)
found = true;
else if(c == ChatManager.SEPARATOR_END)
break;
else if(found)
id += c;
}
ChatItem.debug("Search in " + message + ", id found: " + id);
return (id != "" && Utils.isInteger(id)) ? Chat.getChat(Integer.parseInt(id)).orElse(null) : null;
}
private final long time;
private final int id;
private final Player p;
private final String message;
public Chat(int id, Player p, String message) {
this.time = System.currentTimeMillis();
this.id = id;
this.p = p;
this.message = message;
CHAT.add(this);
}
public long getTime() {
return time;
}
public int getId() {
return id;
}
public Player getPlayer() {
return p;
}
public String getMessage() {
return message;
}
public ItemPlayer getItemPlayer() {
return ItemPlayer.getPlayer(getPlayer());
}
private boolean isOld() {
return System.currentTimeMillis() > time + 10000;
}
public void remove() {
CHAT.remove(this);
}
@Override
public String toString() {
return "Chat{id=" + id + ",message=" + message + ",time=" + time + "}";
}
}
@@ -1,30 +1,286 @@
package me.dadus33.chatitem.chatmanager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Utils;
public abstract class ChatManager {
private final static HashMap<UUID, Long> COOLDOWNS = new HashMap<>();
private final static HashMap<UUID, Long> LAST_INFO_MESSAGE = new HashMap<>();
private final static String NAME = "{name}";
private final static String AMOUNT = "{amount}";
private final static String TIMES = "{times}";
private final static String LEFT = "{remaining}";
public final static char SEPARATOR = ((char) 0x0007);
public final static String SEPARATOR_STR = "\\u0007";
protected Storage s;
public ChatManager() {
public final static char SEPARATOR_END = ((char) 0x0003);
public final static String SEPARATOR_END_STR = "\\u0003";
public static String removeSeparator(String message) {
return fixSeparator(message).replace(Character.toString(SEPARATOR), "").replace(Character.toString(SEPARATOR_END), "");
}
public static String replaceSeparator(Chat chat, String message, String replacement) {
return fixSeparator(message).replace(Character.toString(SEPARATOR) + (chat != null ? chat.getId() : "") + Character.toString(SEPARATOR_END), replacement);
}
public static String fixSeparator(String s) {
return s == null ? "" : s.replace(SEPARATOR_STR, Character.toString(SEPARATOR)).replace(SEPARATOR_END_STR, Character.toString(SEPARATOR_END));
}
public static boolean equalsSeparator(String s) {
return s != null && (s.equalsIgnoreCase(SEPARATOR_STR) || s.equalsIgnoreCase(Character.toString(SEPARATOR)));
}
public static boolean containsSeparator(String s) {
return s != null && (s.contains(SEPARATOR_STR) || s.contains(Character.toString(SEPARATOR)));
}
public static boolean equalsSeparatorEnd(String s) {
return s != null && (s.equalsIgnoreCase(SEPARATOR_END_STR) || s.equalsIgnoreCase(Character.toString(SEPARATOR_END)));
}
public static boolean containsSeparatorEnd(String s) {
return s != null && (s.contains(SEPARATOR_END_STR) || s.contains(Character.toString(SEPARATOR_END)));
}
protected Storage s;
public ChatManager() {
}
public abstract String getName();
public abstract String getId();
public Storage getStorage() {
return s;
}
public void load(ChatItem pl, Storage s) {
this.s = s;
}
public abstract void unload(ChatItem pl);
/**
* Get the item in hand as usable one.<br>
* Will include, in lore, all informations from other plugins.
*
* @param p the player
* @return the usable item
*/
public static ItemStack getUsableItem(Player p) {
ItemStack item = HandItem.getBetterItem(p).clone();
/*
* if(ChatItem.ecoEnchantsSupport) { List<String> addLore =
* EcoEnchantsSupport.getLores(item); if(!addLore.isEmpty()) { ItemMeta meta =
* item.getItemMeta(); List<String> lores = meta.hasLore() ? meta.getLore() :
* new ArrayList<>(); for(int i = 0; i < addLore.size(); i++) lores.add(i,
* addLore.get(i));
*
* meta.setLore(lores); item.setItemMeta(meta); ChatItem.debug("Added " +
* addLore.size() + " lores from EcoEnchants"); } else
* ChatItem.debug("No lore to add from EcoEnchants"); }
*/
return item;
}
/**
* Get all lores lines of an item, to replace the show_item action which is not
* working with ViaBackwards
*
* @param item the item to get lines from
* @return all lores
*/
public static List<String> getMaxLinesFromItem(Player p, ItemStack item) {
List<String> lines = new ArrayList<>();
if (item.hasItemMeta()) {
ItemMeta meta = item.getItemMeta();
lines.add(meta.hasDisplayName() ? meta.getDisplayName() : NamerManager.getName(p, item, ChatItem.getInstance().getStorage()));
if (meta.hasEnchants()) {
meta.getEnchants().forEach((enchant, lvl) -> {
lines.add(ChatColor.RESET + Utils.getEnchantName(enchant) + " " + Utils.toRoman(lvl));
});
}
if (meta.hasLore())
lines.addAll(meta.getLore());
} else {
lines.add(NamerManager.getName(p, item, ChatItem.getInstance().getStorage()));
}
return lines;
}
/**
* Get the name of item according to player & config<br>
* Prefer use {@link #getNameOfItem(Player, ItemStack, Storage)} if you want
* take in count the empty item
*
* @param p the player
* @param item the item
* @param c the config
* @return the name of item
*/
public static String styleItem(Player p, ItemStack item, Storage c) {
String replacer = c.nameFormat;
String amount = c.amountFormat;
boolean dname = item.hasItemMeta() && item.getItemMeta().hasDisplayName();
if (item.getAmount() == 1) {
if (c.addAmountForced) {
amount = amount.replace(TIMES, "1");
replacer = replacer.replace(AMOUNT, amount);
} else {
replacer = replacer.replace(AMOUNT, "");
}
} else {
amount = amount.replace(TIMES, String.valueOf(item.getAmount()));
replacer = replacer.replace(AMOUNT, amount);
}
if (dname) {
String trp = item.getItemMeta().getDisplayName();
ChatItem.debug("trp: " + trp);
if (c.colorIfColored) {
replacer = replacer.replace(NAME, ChatColor.stripColor(trp));
} else {
replacer = replacer.replace(NAME, trp);
}
} else {
replacer = replacer.replace(NAME, NamerManager.getName(p, item, c));
}
return replacer;
}
/**
* Get the name of item according to player & config
*
* @param p the player that is owner of item
* @param item the item
* @param c the config
* @return the name of item or hand
*/
public static String getNameOfItem(Player p, ItemStack item, Storage c) {
if (ItemUtils.isEmpty(item)) {
if (c.handDisabled)
return c.placeholders.get(0);
else
return c.handName;
}
return styleItem(p, item, c);
}
public static String calculateTime(long seconds) {
Storage c = ChatItem.getInstance().getStorage();
if (seconds < 60) {
return seconds + c.SECONDS;
}
if (seconds < 3600) {
StringBuilder builder = new StringBuilder();
int minutes = (int) seconds / 60;
builder.append(minutes).append(c.minutes);
int secs = (int) seconds - minutes * 60;
if (secs != 0) {
builder.append(" ").append(secs).append(c.SECONDS);
}
return builder.toString();
}
StringBuilder builder = new StringBuilder();
int hours = (int) seconds / 3600;
builder.append(hours).append(c.hours);
int minutes = (int) (seconds / 60) - (hours * 60);
if (minutes != 0) {
builder.append(" ").append(minutes).append(c.minutes);
}
int secs = (int) (seconds - ((seconds / 60) * 60));
if (secs != 0) {
builder.append(" ").append(secs).append(c.SECONDS);
}
return builder.toString();
}
public static boolean canShowItem(Player p, ItemStack item, @Nullable Cancellable e) {
Storage c = ChatItem.getInstance().getStorage();
if (c.permissionEnabled && !p.hasPermission(c.permissionName)) {
if (!c.letMessageThrough) {
if (e != null)
e.setCancelled(true);
}
if (!c.messageNoPermission.isEmpty() && c.showNoPermissionMessage) {
sendIfNeed(p, c.messageNoPermission);
}
return false;
}
if (item.getType().equals(Material.AIR)) {
if (c.denyIfNoItem) {
if (e != null)
e.setCancelled(true);
if (!c.messageDeny.isEmpty())
sendIfNeed(p, c.messageDeny);
return false;
}
if (c.handDisabled) {
return false;
}
}
if (c.cooldown > 0 && !p.hasPermission("chatitem.ignore-cooldown")) {
if (COOLDOWNS.containsKey(p.getUniqueId())) {
long start = COOLDOWNS.get(p.getUniqueId());
long current = System.currentTimeMillis() / 1000;
long elapsed = current - start;
if (elapsed >= c.cooldown) {
COOLDOWNS.remove(p.getUniqueId());
} else {
if (!c.letMessageThrough) {
if (e != null)
e.setCancelled(true);
}
if (!c.messageCooldown.isEmpty()) {
long left = (start + c.cooldown) - current;
sendIfNeed(p, c.messageCooldown.replace(LEFT, ChatManager.calculateTime(left)));
}
ChatItem.debug("Cooldown");
return false;
}
}
}
LAST_INFO_MESSAGE.put(p.getUniqueId(), System.currentTimeMillis()); // prevent showing item then send cooldown error message
return true;
}
private static void sendIfNeed(Player p, String msg) {
Long time = LAST_INFO_MESSAGE.remove(p.getUniqueId());
if (time != null) {
long diff = System.currentTimeMillis() - time;
if (diff < 100)
return; // don't show message
}
p.sendMessage(msg);
LAST_INFO_MESSAGE.put(p.getUniqueId(), System.currentTimeMillis());
}
public static void clear(Player p) {
COOLDOWNS.remove(p.getUniqueId());
LAST_INFO_MESSAGE.remove(p.getUniqueId());
}
public static void applyCooldown(Player p) {
COOLDOWNS.put(p.getUniqueId(), System.currentTimeMillis() / 1000);
}
}
@@ -0,0 +1,22 @@
package me.dadus33.chatitem.chatmanager;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Version;
public class HandItem {
@SuppressWarnings("deprecation")
public static ItemStack getBetterItem(Player p) {
if(Version.getVersion().isNewerOrEquals(Version.V1_9)) {
ItemStack main = p.getInventory().getItemInMainHand();
if(!ItemUtils.isEmpty(main))
return main;
ItemStack off = p.getInventory().getItemInOffHand();
return ItemUtils.isEmpty(off) ? main : off;
}
return p.getItemInHand();
}
}
@@ -1,93 +1,89 @@
package me.dadus33.chatitem.chatmanager.v1;
import java.lang.reflect.Constructor;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulatorCurrent;
import me.dadus33.chatitem.chatmanager.v1.listeners.ChatEventListener;
import me.dadus33.chatitem.chatmanager.v1.listeners.ChatPacketManager;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacketManager;
import me.dadus33.chatitem.chatmanager.v1.playerversion.IPlayerVersion;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.ProtocolSupportHook;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.ViaVersionHook;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.Storage;
public class PacketEditingChatManager extends ChatManager {
private final JSONManipulatorCurrent jsonManipulator;
private boolean baseComponentAvailable = true;
private final ChatItemPacketManager packetManager;
private final ChatEventListener chatEventListener;
private final ChatPacketManager chatPacketManager;
private IPlayerVersion playerVersionAdapter;
public PacketEditingChatManager(ChatItem pl) {
jsonManipulator = new JSONManipulatorCurrent();
packetManager = new ChatItemPacketManager(pl);
packetManager = new ChatItemPacketManager(pl);
chatEventListener = new ChatEventListener(this);
chatPacketManager = new ChatPacketManager(this);
//Check for existence of BaseComponent class (only on spigot)
try {
Class.forName("net.md_5.bungee.api.chat.BaseComponent");
} catch (ClassNotFoundException e) {
baseComponentAvailable = false;
}
chatPacketManager = new ChatPacketManager(this);
// Check for existence of BaseComponent class (only on spigot)
try {
Class.forName("net.md_5.bungee.api.chat.BaseComponent");
} catch (ClassNotFoundException e) {
baseComponentAvailable = false;
}
}
@Override
public String getName() {
return "PacketEditing";
}
@Override
public String getId() {
return "packet";
}
@Override
public void load(ChatItem pl, Storage s) {
super.load(pl, s);
Bukkit.getPluginManager().registerEvents(chatEventListener, pl);
packetManager.getPacketManager().addHandler(chatPacketManager);
if(Bukkit.getPluginManager().getPlugin("ViaVersion") != null){
playerVersionAdapter = new ViaVersionHook();
pl.getLogger().info("Loading ViaVersion support ...");
} else if(Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null){
playerVersionAdapter = new ProtocolSupportHook();
pl.getLogger().info("Loading ProtocolSupport support ...");
} else {
playerVersionAdapter = new DefaultVersionHook();
}
PacketManager pm = packetManager.getPacketManager();
pm.addHandler(chatPacketManager);
Bukkit.getOnlinePlayers().forEach(pm::addPlayer); // add actual online players
}
@Override
public void unload(ChatItem pl) {
HandlerList.unregisterAll(chatEventListener);
packetManager.getPacketManager().removeHandler(chatPacketManager);
packetManager.getPacketManager().stop();
}
public JSONManipulator getManipulator(){
/*
We used to have 2 kinds of JSONManipulators because of my bad understanding of the 1.7 way of parsing JSON chat
The interface should however stay as there might be great changes in future versions in JSON parsing (most likely 1.13)
*/
return jsonManipulator;
//We just return a new one whenever requested for the moment, should implement a cache of some sort some time though
}
public IPlayerVersion getPlayerVersionAdapter() {
return playerVersionAdapter;
PacketManager pm = packetManager.getPacketManager();
pm.removeHandler(chatPacketManager);
pm.stop();
}
public boolean supportsChatComponentApi(){
return baseComponentAvailable;
}
public boolean supportsChatComponentApi() {
return baseComponentAvailable;
}
public static Object createSystemChatPacket(String json) throws Exception {
Class<?> packetClass = PacketUtils.getNmsClass("ClientboundSystemChatPacket", "network.protocol.game.");
for (Constructor<?> cons : packetClass.getDeclaredConstructors()) {
if (!cons.isAccessible())
cons.setAccessible(true);
if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].equals(String.class)
&& cons.getParameterTypes()[1].equals(int.class)) { // "string, int"
return cons.newInstance(json, 1);
} else if (cons.getParameterCount() == 3 && cons.getParameterTypes()[1].equals(String.class)) { // "component", "string", <something not checked>
Class<?> secondParam = cons.getParameterTypes()[2];
if(secondParam.equals(int.class)) // "component", "string", "int"
return cons.newInstance(null, json, 1);
else if(secondParam.equals(boolean.class)) // "component", "string", "boolean"
return cons.newInstance(null, json, false);
}
}
ChatItem.getInstance().getLogger()
.warning("Can't create a new packet for json " + json + ": no constructor found.");
return null;
}
}
@@ -0,0 +1,128 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp;
import javax.annotation.Nullable;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Utils;
public interface IComponentManager {
default boolean hasConditions() {
return true;
}
String getBaseComponentAsJSON(ChatItemPacket packet);
void writeJson(ChatItemPacket packet, String json);
default @Nullable Chat getChat(String json) {
json = ChatManager.fixSeparator(json);
try {
Chat possibleChat = Chat.getFrom(json);
if (possibleChat != null) // found something with basic search
return possibleChat;
Chat chat = new Searching(json).search();
if (chat == null)
ChatItem.debug("Failed to find chat for JSON " + json);
return chat;
} catch (Exception e) {
e.printStackTrace();
} // not JSON
return null;
}
default Object manageItem(Player p, Chat chat, ChatItemPacket packet, ItemStack item, Storage c) throws Exception {
String message = JSONManipulator.getInstance().parse(getBaseComponentAsJSON(packet), item, ChatManager.styleItem(chat.getPlayer(), item, c),
ItemPlayer.getPlayer(p).getProtocolVersion());
if (message != null) {
ChatItem.debug("(v1) Writing message: " + message);
writeJson(packet, message);
}
return packet.getPacket();
}
default Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, Storage c) {
String message = JSONManipulator.getInstance().parseEmpty(getBaseComponentAsJSON(packet), c.handName, c.tooltipHand, chat.getPlayer());
if (message != null) {
ChatItem.debug("(v1) Writing empty message: " + message);
writeJson(packet, message);
}
return packet.getPacket();
}
public static class Searching {
private boolean found = false;
private String id = "", json;
public Searching(String json) {
this.json = json;
}
private Chat search() {
JsonObject jsonObj = JsonParser.parseString(json).getAsJsonObject();
if (jsonObj.has("extra")) {
if (searchInExtra(jsonObj.getAsJsonArray("extra"))) {
return getWithId();
}
}
if (jsonObj.has("text")) {
JsonElement text = jsonObj.get("text");
if(text.isJsonObject() && searchInObject(text.getAsJsonObject()))
return getWithId();
else if(text.isJsonArray() && searchInExtra(text.getAsJsonArray()))
return getWithId();
else if(text.isJsonPrimitive() && searchInString(text.getAsString()))
return getWithId();
}
return null;
}
private Chat getWithId() {
return id != "" && Utils.isInteger(id) ? Chat.getChat(Integer.parseInt(id)).orElse(null) : null;
}
private boolean searchInExtra(JsonArray json) {
for (JsonElement element : json) {
if (element.isJsonObject()) {
JsonObject withObj = element.getAsJsonObject();
if (withObj.has("extra") && searchInExtra(withObj.getAsJsonArray("extra")))
return true;
else if (withObj.has("text") && searchInObject(withObj))
return true;
}
}
return false;
}
private boolean searchInObject(JsonObject json) {
return json.has("text") && json.get("text").isJsonPrimitive() && searchInString(json.get("text").getAsString());
}
private boolean searchInString(String s) {
for (char c : ChatManager.fixSeparator(s).toCharArray()) {
if (c == ChatManager.SEPARATOR)
found = true;
else if (c == ChatManager.SEPARATOR_END)
return true;
else if (found)
id += c;
}
return false;
}
}
}
@@ -0,0 +1,114 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent.ContentModifier;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.Storage;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
public class AdventureComponentManager implements IComponentManager {
@Override
public boolean hasConditions() {
try {
for (String cl : Arrays.asList("net.kyori.adventure.text.Component", "net.kyori.adventure.text.serializer.gson.GsonComponentSerializer"))
Class.forName(cl);
} catch (Exception e) { // can't support this, adventure comp not found
ChatItem.debug("Can't load AdventureComponentManager : " + e.getMessage());
return false;
}
return true;
}
@Override
public void writeJson(ChatItemPacket packet, String json) {}
@Override
public String getBaseComponentAsJSON(ChatItemPacket packet) {
Component comp = packet.getContent().getSpecificModifier(Component.class).readSafely(0);
if (comp == null)
return null;
String json = GsonComponentSerializer.gson().serialize(comp);
JsonObject jsonObj = JsonParser.parseString(json).getAsJsonObject();
ChatItem.debug("AdventureJSON : " + json);
if (jsonObj.has("with")) {
JsonObject next = new JsonObject();
next.add("extra", jsonObj.get("with"));
return next.toString();
}
return json;
}
@Override
public Object manageItem(Player p, Chat chat, ChatItemPacket packet, ItemStack item, Storage c) throws Exception {
String itemName = ChatManager.getNameOfItem(chat.getPlayer(), item, c);
return manage(p, chat, packet, itemName, HoverEvent.showItem(Key.key(item.getType().getKey().getKey()), item.getAmount(), BinaryTagHolder.of(PacketUtils.getNbtTag(item))));
}
@Override
public Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, Storage c) {
Component builder = Component.text("");
c.tooltipHand.forEach(s -> builder.append(Component.text(s)));
Player sender = chat.getPlayer();
String handName = c.handName.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName());
return manage(p, chat, packet, handName, HoverEvent.showText(builder));
}
private Object manage(Player p, Chat chat, ChatItemPacket packet, String replacement, HoverEvent<?> hover) {
ContentModifier<Component> modifier = packet.getContent().getSpecificModifier(Component.class);
Component comp = modifier.readSafely(0);
if (comp == null) {
ChatItem.debug("The component is null.");
return null;
}
comp = checkComponent(comp, hover, replacement, chat);
ChatItem.debug("Result: " + GsonComponentSerializer.gson().serialize(comp));
modifier.write(0, comp);
packet.setPacket(modifier.getObj());
return packet.getPacket();
}
private Component checkComponent(Component comp, HoverEvent<?> hover, String itemName, Chat chat) {
if (comp instanceof TextComponent) {
TextComponent tc = (TextComponent) comp;
if (ChatManager.containsSeparator(tc.content())) {
ChatItem.debug("Changing text " + tc.content() + " to " + itemName);
comp = tc.content(ChatManager.replaceSeparator(chat, tc.content(), itemName)).hoverEvent(hover);
} else
ChatItem.debug("No insert of text without separator: " + tc.content());
} else if(comp instanceof TranslatableComponent) {
TranslatableComponent tc = (TranslatableComponent) comp;
List<Component> next = new ArrayList<>();
for (Component extra : tc.args()) {
next.add(checkComponent(extra, hover, itemName, chat));
}
comp = tc.args(next);
} else
ChatItem.debug("Not valid comp class " + comp.getClass().getSimpleName() + " : " + comp);
List<Component> next = new ArrayList<>();
for (Component extra : comp.children()) {
next.add(checkComponent(extra, hover, itemName, chat));
}
return comp.children(next);
}
}
@@ -0,0 +1,35 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.utils.PacketUtils;
public class ComponentNMSManager implements IComponentManager {
@Override
public boolean hasConditions() {
return PacketUtils.COMPONENT_CLASS != null;
}
@Override
public String getBaseComponentAsJSON(ChatItemPacket packet) {
Object chatBaseComp = packet.getContent().getSpecificModifier(PacketUtils.COMPONENT_CLASS).readSafely(0);
if (chatBaseComp != null) {
try {
return PacketUtils.CHAT_SERIALIZER.getMethod("a", PacketUtils.COMPONENT_CLASS).invoke(null, chatBaseComp).toString();
} catch (Exception exc) {
exc.printStackTrace();
}
}
return null;
}
@Override
public void writeJson(ChatItemPacket packet, String json) {
try {
packet.getContent().getChatComponents().write(0, PacketUtils.CHAT_SERIALIZER.getMethod("a", String.class).invoke(null, json));
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,90 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.time.Instant;
import java.util.Optional;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
public class IChatBaseComponentManager implements IComponentManager {
private Method serializerGetJson, fromJson;
private boolean canEditVariable = true;
public IChatBaseComponentManager() {
try {
Class<?> chatSerializer = PacketUtils.CHAT_SERIALIZER;
fromJson = chatSerializer.getMethod("a", String.class);
for (Method m : chatSerializer.getDeclaredMethods()) {
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(PacketUtils.COMPONENT_CLASS) && m.getReturnType().equals(String.class)) {
serializerGetJson = m;
break;
}
}
if (serializerGetJson == null)
ChatItem.getInstance().getLogger().warning("Failed to find JSON serializer in class: " + chatSerializer.getCanonicalName());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean hasConditions() {
return serializerGetJson != null;
}
@Override
public String getBaseComponentAsJSON(ChatItemPacket packet) {
try {
Object obj = packet.getContent().getChatComponents().readSafely(0);
return obj == null ? null : (String) serializerGetJson.invoke(null, obj);
} catch (Exception exc) {
exc.printStackTrace();
}
return null;
}
@Override
public void writeJson(ChatItemPacket packet, String json) {
try {
PacketContent content = packet.getContent();
Object chatComponent = fromJson.invoke(null, json);
if (canEditVariable)
content.getChatComponents().write(0, chatComponent);
else {
try {
Class<?> packetClass = packet.getPacket().getClass();
if (packetClass.getSimpleName().equalsIgnoreCase("ClientboundSystemChatPacket")) {
for (Constructor<?> cons : packetClass.getConstructors()) {
if (cons.getParameterCount() == 6) {
Object newPacket = cons.newInstance(chatComponent, Optional.empty(), content.getIntegers().readSafely(0, 0),
content.getSpecificModifier(PacketUtils.getNmsClass("ChatSender", "network.chat.")).read(0), content.getSpecificModifier(Instant.class).read(0),
ReflectionUtils.getObject(packet.getPacket(), "f"));
packet.setPacket(newPacket);
}
}
throw new UnsupportedOperationException("Failed to find valid constructor for packet " + packetClass.getSimpleName() + ". Please report this.");
} else {
throw new UnsupportedOperationException("The packet " + packetClass.getSimpleName() + " isn't supported by the IChatBaseComponentManager. Please report this.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IllegalAccessException e) {
if (canEditVariable) {
canEditVariable = false;
writeJson(packet, json); // try again with good config
} else
e.printStackTrace(); // something else
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,137 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Utils;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
public class StringComponentManager implements IComponentManager {
@Override
public String getBaseComponentAsJSON(ChatItemPacket packet) {
String json = packet.getContent().getStrings().readSafely(0);
if (json != null && json.startsWith("[") && json.endsWith("]")) { // if used as array instead of json obj
JsonArray extra = new JsonArray();
for (JsonElement element : JsonParser.parseString(json).getAsJsonArray()) {
if (element.isJsonObject()) { // ignore this
extra.add(element);
} else {
ChatItem.debug("Ignoring element " + element);
}
}
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", "");
jsonObject.add("extra", extra);
json = jsonObject.toString();
} else if (json == null) {
BaseComponent[] comp = packet.getContent().getSpecificModifier(BaseComponent[].class).readSafely(0);
if (comp != null)
return ComponentSerializer.toString(comp);
}
return json;
}
@Override
public void writeJson(ChatItemPacket packet, String json) {
try {
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object manageItem(Player p, Chat chat, ChatItemPacket packet, ItemStack item, Storage c) throws Exception {
return manage(p, chat, packet, ChatManager.getNameOfItem(chat.getPlayer(), item, c), Utils.createItemHover(item));
}
@Override
public Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, Storage c) {
ComponentBuilder builder = new ComponentBuilder("");
c.tooltipHand.forEach(s -> builder.append(s));
Player sender = chat.getPlayer();
String handName = c.handName.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName());
return manage(p, chat, packet, handName, Utils.createTextHover(builder.create()));
}
private Object manage(Player p, Chat chat, ChatItemPacket packet, String replacement, HoverEvent hover) {
BaseComponent[] components = packet.getContent().getSpecificModifier(BaseComponent[].class).readSafely(0);
if (components == null) {
String json = packet.getContent().getStrings().readSafely(0);
if (json != null && json.startsWith("[") && json.endsWith("]")) { // if used as array instead of json obj
JsonArray extra = new JsonArray();
for (JsonElement element : JsonParser.parseString(json).getAsJsonArray()) {
if (element.isJsonObject()) { // ignore this
extra.add(element);
} else {
ChatItem.debug("Ignoring element " + element);
}
}
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", "");
jsonObject.add("extra", extra);
json = jsonObject.toString();
}
try {
components = ComponentSerializer.parse(json);
} catch (Exception e) {
ChatItem.getInstance().getLogger().severe("Failed to parse JSON: " + json + ". Error:");
e.printStackTrace();
return packet.getPacket();
}
}
ChatItem.debug("Checking for " + components.length + " components");
Arrays.asList(components).forEach(comp -> checkComponent(comp, hover, replacement, chat));
try {
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(ComponentSerializer.toString(components)));
} catch (Exception e) {
e.printStackTrace();
}
return packet.getPacket();
}
private void checkComponent(BaseComponent comp, HoverEvent hover, String itemName, Chat chat) {
if (comp instanceof TextComponent) {
TextComponent tc = (TextComponent) comp;
if (ChatManager.containsSeparator(tc.getText())) {
ChatItem.debug("Changing text " + tc.getText() + " to " + itemName);
tc.setText(ChatManager.replaceSeparator(chat, tc.getText(), itemName));
tc.setHoverEvent(hover);
List<BaseComponent> extra = new ArrayList<>();
for (BaseComponent legacyExtra : TextComponent.fromLegacyText(itemName, tc.getColor())) {
extra.add(legacyExtra);
}
if (tc.getExtra() != null)
extra.addAll(tc.getExtra());
tc.setExtra(extra);
} else
ChatItem.debug("No insert of text without separator: " + tc.getText() + " (legacy: " + tc.toLegacyText() + ")");
}
if (comp.getExtra() != null) {
for (BaseComponent extra : comp.getExtra()) {
checkComponent(extra, hover, itemName, chat);
}
}
}
}
@@ -1,14 +1,292 @@
package me.dadus33.chatitem.chatmanager.v1.json;
import java.util.List;
import static me.dadus33.chatitem.utils.PacketUtils.getNmsClass;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
public interface JSONManipulator {
String parse(String json, List<String> replacements, ItemStack item, String repl, int protocol) throws Exception;
String parseEmpty(String json, List<String> replacements, String repl, List<String> tooltip, Player sender);
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Version;
public class JSONManipulator {
private static JSONManipulator instance = new JSONManipulator();
public static JSONManipulator getInstance() {
return instance;
}
private static final List<String> SKIPPED = Arrays.asList("HSTRY_ENCHANTS");
public static final Class<?> CRAFT_ITEM_STACK_CLASS = PacketUtils.getObcClass("inventory.CraftItemStack");
public static final Class<?> NMS_ITEM_STACK_CLASS = getNmsClass("ItemStack", "world.item.");
public static final Method AS_NMS_COPY = ReflectionUtils.getMethod(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class);
public static final Class<?> NBT_TAG_COMPOUND = getNmsClass("NBTTagCompound", "nbt.");
public static final Method SAVE_NMS_ITEM_STACK_METHOD = ReflectionUtils.getMethod(NMS_ITEM_STACK_CLASS, NBT_TAG_COMPOUND, NBT_TAG_COMPOUND);
public static final Field MAP = ReflectionUtils.getField(NBT_TAG_COMPOUND, "map", "x");
private static final ConcurrentHashMap<Map.Entry<Version, ItemStack>, JsonObject> STACKS = new ConcurrentHashMap<>();
private JsonObject itemTooltip;
private JsonArray classicTooltip;
public String parse(String json, ItemStack item, String replacement, int protocol) throws Exception {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
final AbstractMap.SimpleEntry<Version, ItemStack> p = new AbstractMap.SimpleEntry<>(Version.getVersion(protocol), item);
JsonObject wrapper = new JsonObject(); // Create a wrapper object for the whole array
if ((itemTooltip = STACKS.get(p)) == null) {
JsonArray use = Translator.toJson(replacement); // We get the json representation of the old color
// formatting method
ChatItem.debug("Remplacement: " + replacement + " use: " + use.toString());
// There's no public clone method for JSONObjects so we need to parse them every
// time
JsonObject hover = new JsonObject();
hover.addProperty("action", "show_item");
// Get the JSON representation of the item (well, not really JSON, but rather a
// string representation of NBT data)
hover.addProperty("value", stringifyItem(item));
if (use.size() == 1) {
JsonElement extraElement = use.get(0);
if (extraElement.isJsonPrimitive())
wrapper.addProperty("text", extraElement.getAsString());
else if (extraElement.isJsonObject())
wrapper.addProperty("text", extraElement.getAsJsonObject().get("text").getAsString());
else
wrapper.add("extra", use); // add it only if
} else if (!use.isEmpty())
wrapper.add("extra", use); // add it only if
if (!wrapper.has("text"))
wrapper.addProperty("text", ""); // The text field is compulsory, even if it's empty
wrapper.add("hoverEvent", hover);
itemTooltip = wrapper; // Save the tooltip for later use when we encounter a placeholder
STACKS.put(p, itemTooltip); // Save it in the cache too so when parsing other packets with the same item
// (and client version) we no longer have to create it again
// We remove it later when no longer needed to save memory
Bukkit.getScheduler().runTaskLaterAsynchronously(ChatItem.getInstance(), () -> STACKS.remove(p), 100L);
}
if (obj.size() == 1 && obj.has("text")) {
itemTooltip.add("text", obj.get("text"));
ChatItem.debug("[JsonManipulator] Parsed quick: " + obj.toString() + ", wrapper: " + itemTooltip);
return itemTooltip.toString().replace(Character.toString(ChatManager.SEPARATOR), "").replace(ChatManager.SEPARATOR_STR, "");
}
obj.add("extra", parseArray(obj.has("extra") ? obj.getAsJsonArray("extra") : new JsonArray(), itemTooltip));
if (!obj.has("text")) {
obj.addProperty("text", "");
}
ChatItem.debug("Parsed array for item: " + obj.toString() + ", wrapper: " + itemTooltip);
return obj.toString();
}
public String parseEmpty(String json, String repl, List<String> tooltip, Player sender) {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
JsonArray array = obj.has("extra") ? obj.getAsJsonArray("extra") : new JsonArray();
JsonArray use = Translator.toJson(repl.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName()));
JsonObject hover = JsonParser.parseString("{\"action\":\"show_text\", \"value\": \"\"}").getAsJsonObject();
StringBuilder oneLineTooltip = new StringBuilder("");
int index = 0;
for (String m : tooltip) {
oneLineTooltip.append(m.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName()));
++index;
if (index != tooltip.size()) {
oneLineTooltip.append('\n');
}
}
hover.add("value", new JsonPrimitive(oneLineTooltip.toString()));
if (!tooltip.isEmpty()) {
for (JsonElement ob : use)
ob.getAsJsonObject().add("hoverEvent", hover);
classicTooltip = use;
}
obj.add("extra", parseArray(array, classicTooltip));
if (!obj.has("text")) {
obj.addProperty("text", "");
}
return obj.toString();
}
private JsonArray parseArray(JsonArray arr, JsonElement tooltip) {
JsonArray replacer = new JsonArray();
boolean isComplex = false;
for (int i = 0; i < arr.size(); ++i) {
JsonElement element = arr.get(i);
if (element.isJsonNull()) {
continue;
} else if (element.isJsonObject()) {
isComplex = true;
addParsedJsonObjectToArray(element.getAsJsonObject(), replacer, tooltip);
} else if (element.isJsonArray()) {
isComplex = true;
JsonArray jar = element.getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(element.getAsJsonArray(), tooltip);
replacer.set(i, jar);
}
} else if (element.isJsonPrimitive() && isComplex) {
ChatItem.debug("[JSONManipulator] Put " + element + " to trash as it's primitive with complex things");
// ignore
} else {
addParsedStringToArray(element.getAsString(), replacer, element, tooltip);
}
}
return replacer;
}
private void addParsedJsonObjectToArray(JsonObject o, JsonArray rep, JsonElement tooltip) {
JsonElement text = o.get("text");
if (text == null) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
JsonArray tmpArray = parseArray(jar, tooltip);
if (!tmpArray.isEmpty())
o.add("extra", tmpArray);
else
o.remove("extra");
} else {
o.remove("extra");
}
}
return;
} else {
if (text.getAsString().isEmpty()) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (!jar.isEmpty()) {
JsonArray tmpArray = parseArray(jar, tooltip);
if (!tmpArray.isEmpty())
o.add("extra", tmpArray);
else
o.remove("extra");
} else {
o.remove("extra");
}
}
}
}
addParsedStringToArray(text.getAsString(), rep, o, tooltip);
}
private void addParsedStringToArray(String msg, JsonArray rep, JsonElement o, JsonElement tooltip) {
ChatItem.debug("Checking " + msg + " > " + rep + ", o: " + o);
if (!ChatManager.containsSeparator(msg)) {
rep.add(o);
return;
}
String current = "";
boolean wasSep = false;
for (String parts : msg.split("")) {
if (ChatManager.equalsSeparator(parts)) {
if (!current.isEmpty()) {
rep.add(current);
current = "";
}
rep.add(tooltip);
wasSep = true;
} else if (wasSep) {
if (ChatManager.equalsSeparatorEnd(parts)) // sep finished
wasSep = false;
} else {
current += parts;
}
}
if (!current.isEmpty())
rep.add(current);
}
public static String stringifyItem(ItemStack is) {
try {
return stringifyItemInternal(is);
} catch (Exception e) {
e.printStackTrace();
return "{}";
}
}
@SuppressWarnings({ "deprecation" })
public static String stringifyItemInternal(ItemStack is) throws Exception {
Object nmsStack = JSONManipulator.AS_NMS_COPY.invoke(null, is);
Object nmsTag = JSONManipulator.NBT_TAG_COMPOUND.newInstance();
JSONManipulator.SAVE_NMS_ITEM_STACK_METHOD.invoke(nmsStack, nmsTag);
HashMap<String, String> tagMap = new HashMap<>();
Map<String, Object> nmsMap = (Map<String, Object>) JSONManipulator.MAP.get(nmsTag);
String id = nmsMap.get("id").toString().replace("\"", "");
Object realTag = nmsMap.get("tag");
if (JSONManipulator.NBT_TAG_COMPOUND.isInstance(realTag)) { // We need to make sure this is indeed an
// NBTTagCompound
Map<String, Object> realMap = (Map<String, Object>) JSONManipulator.MAP.get(realTag);
Set<Map.Entry<String, Object>> entrySet = realMap.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
tagMap.put(entry.getKey(), entry.getValue().toString());
}
}
// TODO check for ID remapping
// ItemRewriter.remapIds(Version.getVersion().MAX_VER, protocolVersion.MAX_VER,
// is);
StringBuilder sb = new StringBuilder("{id:");
sb.append("\"").append(id).append("\"").append(","); // Append the id
sb.append("Count:").append(is.getAmount()).append("b"); // Append the amount
if (!tagMap.containsKey("Damage")) { // for new versions
sb.append(",Damage:").append(is.getDurability()).append("s"); // Append the durability data
}
if (tagMap.isEmpty()) {
sb.append("}");
return sb.toString();
}
Set<Map.Entry<String, String>> entrySet = tagMap.entrySet();
boolean first = true;
sb.append(",tag:{"); // Start of the tag
for (Map.Entry<String, String> entry : entrySet) {
if (SKIPPED.contains(entry.getKey()))
continue;
if (!first)
sb.append(",");
first = false;
if (!entry.getKey().isEmpty()) {
if (entry.getKey().contains(";"))
sb.append("\"" + entry.getKey() + "\"");
else
sb.append(entry.getKey());
sb.append(":");
}
ChatItem.debug("Cleaning " + entry.getKey() + ": " + entry.getValue() + " > " + cleanStr(entry.getValue()));
sb.append(cleanStr(entry.getValue()));
}
sb.append("}}"); // End of tag and end of item
return sb.toString();
}
private static String cleanStr(String s) {
return s.startsWith("'") && s.endsWith("'") ? s.substring(1, s.length() - 1) : s;
}
}
@@ -1,947 +0,0 @@
package me.dadus33.chatitem.chatmanager.v1.json;
import static me.dadus33.chatitem.utils.PacketUtils.getNmsClass;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.DoubleTag;
import com.github.steveice10.opennbt.tag.builtin.FloatTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.utils.Item;
import me.dadus33.chatitem.chatmanager.v1.utils.ItemRewriter;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.Reflect;
import me.dadus33.chatitem.utils.Version;
@SuppressWarnings("unchecked")
public class JSONManipulatorCurrent implements JSONManipulator {
private static final Class<?> CRAFT_ITEM_STACK_CLASS = PacketUtils.getObcClass("inventory.CraftItemStack");
private static final Class<?> NBT_STRING = getNmsClass("NBTTagString", "nbt.");
private static final Class<?> NBT_LIST = getNmsClass("NBTTagList", "nbt.");
private static final Map<Class<?>, BiFunction<String, Object, Tag>> TYPES_TO_MC_NBT_TAGS = new HashMap<>();
private static final Map<Class<?>, Function<String, Tag>> TYPES_TO_OPEN_NBT_TAGS = new HashMap<>();
private static final List<Class<?>> NBT_BASE_CLASSES = new ArrayList<>();
private static final List<Field> NBT_BASE_DATA_FIELD = new ArrayList<>();
private static final Class<?> NMS_ITEM_STACK_CLASS = getNmsClass("ItemStack", "world.item.");
private static final Method AS_NMS_COPY = Reflect.getMethod(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class);
private static final Class<?> NBT_TAG_COMPOUND = getNmsClass("NBTTagCompound", "nbt.");
private static final Method SAVE_NMS_ITEM_STACK_METHOD = Reflect.getMethod(NMS_ITEM_STACK_CLASS, NBT_TAG_COMPOUND,
NBT_TAG_COMPOUND);
private static final Field MAP = Reflect.getField(NBT_TAG_COMPOUND, "map", "x");
private static final Field LIST_FIELD = Reflect.getField(NBT_LIST, "list", "c");
// Tags to be ignored. Currently it only contains tags from PortableHorses, but
// feel free to submit a pull request to add tags from your plugins
private static final List<String> IGNORED = Arrays.asList("horsetag", "phorse", "iscnameviz", "cname");
private static final ConcurrentHashMap<Map.Entry<Version, ItemStack>, JsonObject> STACKS = new ConcurrentHashMap<>();
static {
NBT_BASE_CLASSES.add(getNmsClass("NBTTagByte", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagByteArray", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagDouble", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagFloat", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagInt", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagIntArray", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagLong", "nbt."));
NBT_BASE_CLASSES.add(getNmsClass("NBTTagShort", "nbt."));
for (Class<?> NBT_BASE_CLASS : NBT_BASE_CLASSES) {
NBT_BASE_DATA_FIELD.add(Reflect.getField(NBT_BASE_CLASS, "data", "c", "x"));
}
// include NBT tags
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagByte", "nbt."), (name, obj) -> new ByteTag(name, get(obj, "h")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagByteArray", "nbt."), (name, obj) -> new ByteArrayTag(name, get(obj, "d")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagDouble", "nbt."), (name, obj) -> new DoubleTag(name, get(obj, "i")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagFloat", "nbt."), (name, obj) -> new FloatTag(name, get(obj, "j")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagInt", "nbt."), (name, obj) -> new IntTag(name, get(obj, "f")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagIntArray", "nbt."), (name, obj) -> new IntArrayTag(name, get(obj, "c")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagLong", "nbt."), (name, obj) -> new LongTag(name, get(obj, "e")));
TYPES_TO_MC_NBT_TAGS.put(getNmsClass("NBTTagShort", "nbt."), (name, obj) -> new ShortTag(name, get(obj, "g")));
// now basic types
TYPES_TO_OPEN_NBT_TAGS.put(Byte.class, ByteTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Byte[].class, ByteArrayTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Double.class, DoubleTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Float.class, FloatTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Integer.class, IntTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Integer[].class, IntArrayTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Long.class, LongTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(Short.class, ShortTag::new);
// Add the primitive types too, just in case
TYPES_TO_OPEN_NBT_TAGS.put(byte.class, ByteTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(byte[].class, ByteArrayTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(double.class, DoubleTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(float.class, FloatTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(int.class, IntTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(int[].class, IntArrayTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(long.class, LongTag::new);
TYPES_TO_OPEN_NBT_TAGS.put(short.class, ShortTag::new);
}
public static <T> T get(Object obj, String methodName){
try {
return (T) obj.getClass().getDeclaredMethod(methodName).invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private List<String> replaces;
private String rgx;
private Version protocolVersion;
private JsonObject itemTooltip;
private JsonArray classicTooltip;
private final JsonParser PARSER = new JsonParser();
public String parse(String json, List<String> replacements, ItemStack item, String replacement, int protocol)
throws Exception {
JsonObject obj = PARSER.parse(json).getAsJsonObject();
JsonArray array = obj.getAsJsonArray("extra");
replaces = replacements;
String regex = "";
for (int i = 0; i < replacements.size(); ++i) {
if (replacements.size() == 1) {
regex = Pattern.quote(replacements.get(0));
break;
}
if (i == 0 || i + 1 == replacements.size()) {
if (i == 0) {
regex = "(" + Pattern.quote(replacements.get(i));
} else {
regex = regex.concat("|").concat(Pattern.quote(replacements.get(i))).concat(")");
}
continue;
}
regex = regex.concat("|").concat(Pattern.quote(replacements.get(i)));
}
rgx = regex;
JsonArray rep = new JsonArray();
final AbstractMap.SimpleEntry<Version, ItemStack> p = new AbstractMap.SimpleEntry<>(
protocolVersion = Version.getVersion(protocol), item);
if ((itemTooltip = STACKS.get(p)) == null) {
JsonArray use = Translator.toJson(replacement); // We get the json representation of the old color
// formatting method
// There's no public clone method for JSONObjects so we need to parse them every time
JsonObject hover = PARSER.parse("{\"action\":\"show_item\", \"value\": \"\"}").getAsJsonObject();
String jsonRep = stringifyItem(item); // Get the JSON representation of the item (well, not really JSON, but
// rather a string representation of NBT data)
hover.addProperty("value", jsonRep);
JsonObject wrapper = new JsonObject(); // Create a wrapper object for the whole array
wrapper.addProperty("text", ""); // The text field is compulsory, even if it's empty
wrapper.add("extra", use);
wrapper.add("hoverEvent", hover);
itemTooltip = wrapper; // Save the tooltip for later use when we encounter a placeholder
STACKS.put(p, itemTooltip); // Save it in the cache too so when parsing other packets with the same item
// (and client version) we no longer have to create it again
// We remove it later when no longer needed to save memory
Bukkit.getScheduler().runTaskLaterAsynchronously(ChatItem.getInstance(), () -> STACKS.remove(p), 100L);
}
for (int i = 0; i < array.size(); ++i) {
if (array.get(i).isJsonObject()) {
JsonObject o = array.get(i).getAsJsonObject();
boolean inside = false;
for (String replace : replacements)
if (o.toString().contains(replace)) {
if (inside) {
break;
}
inside = true;
}
JsonElement text = o.get("text");
if (text == null) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
continue;
} else {
if (text.getAsString().isEmpty()) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
}
}
String msg = text.getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replacements) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(regex);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
String st = o.toString();
JsonObject fix = PARSER.parse(st).getAsJsonObject();
fix.addProperty("text", splits[j]);
rep.add(fix);
}
if (j != splits.length - 1) {
rep.add(itemTooltip);
}
}
if (!fnd) {
rep.add(o);
}
} else {
if (array.get(i).isJsonNull()) {
continue;
} else {
if (array.get(i).isJsonArray()) {
JsonArray jar = array.get(i).getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(array.get(i).getAsJsonArray());
rep.set(i, jar);
}
} else {
String msg = array.get(i).getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replacements) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(regex);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
JsonElement fix = new JsonPrimitive(splits[j]);
rep.add(fix);
}
if (j != splits.length - 1) {
rep.add(itemTooltip);
}
}
if (!fnd) {
rep.add(array.get(i));
}
}
}
}
}
obj.add("extra", rep);
if (!obj.has("text")) {
obj.addProperty("text", "");
}
return obj.toString();
}
@Override
public String parseEmpty(String json, List<String> replacements, String repl, List<String> tooltip, Player sender) {
JsonObject obj = PARSER.parse(json).getAsJsonObject();
JsonArray array = obj.getAsJsonArray("extra");
replaces = replacements;
String regex = "";
for (int i = 0; i < replacements.size(); ++i) {
if (replacements.size() == 1) {
regex = Pattern.quote(replacements.get(0));
break;
}
if (i == 0 || i + 1 == replacements.size()) {
if (i == 0) {
regex = "(" + Pattern.quote(replacements.get(i));
} else {
regex = regex.concat("|").concat(Pattern.quote(replacements.get(i))).concat(")");
}
continue;
}
regex = regex.concat("|").concat(Pattern.quote(replacements.get(i)));
}
rgx = regex;
JsonArray rep = new JsonArray();
JsonArray use = Translator
.toJson(repl.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName()));
JsonObject hover = PARSER.parse("{\"action\":\"show_text\", \"value\": \"\"}").getAsJsonObject();
StringBuilder oneLineTooltip = new StringBuilder("");
int index = 0;
for (String m : tooltip) {
oneLineTooltip
.append(m.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName()));
++index;
if (index != tooltip.size()) {
oneLineTooltip.append('\n');
}
}
hover.add("value", new JsonPrimitive(oneLineTooltip.toString()));
for (JsonElement ob : use)
ob.getAsJsonObject().add("hoverEvent", hover);
classicTooltip = use;
for (int i = 0; i < array.size(); ++i) {
if (array.get(i).isJsonObject()) {
JsonObject o = array.get(i).getAsJsonObject();
boolean inside = false;
for (String replace : replacements)
if (o.toString().contains(replace)) {
if (inside) {
break;
}
inside = true;
}
JsonElement text = o.get("text");
if (text == null) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseNoItemArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
continue;
} else {
if (text.getAsString().isEmpty()) {
JsonElement el = o.get("extra");
if (el != null) {
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseNoItemArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
}
}
String msg = text.getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replacements) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(regex);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
String st = o.toString();
JsonObject fix = PARSER.parse(st).getAsJsonObject();
fix.addProperty("text", splits[j]);
rep.add(fix);
}
if (j != splits.length - 1) {
rep.addAll(use);
}
}
if (!fnd) {
rep.add(o);
}
} else {
if (array.get(i).isJsonNull()) {
continue;
} else {
if (array.get(i).isJsonArray()) {
JsonArray jar = array.get(i).getAsJsonArray();
if (jar.size() != 0) {
jar = parseNoItemArray(array.get(i).getAsJsonArray());
rep.set(i, jar);
}
} else {
String msg = array.get(i).getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replacements) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(regex);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
JsonElement fix = new JsonPrimitive(splits[j]);
rep.add(fix);
}
if (j != splits.length - 1) {
rep.addAll(use);
}
}
if (!fnd) {
rep.add(array.get(i));
}
}
}
}
}
obj.add("extra", rep);
return obj.toString();
}
private JsonArray parseNoItemArray(JsonArray arr) {
JsonArray replacer = new JsonArray();
for (int i = 0; i < arr.size(); ++i) {
if (arr.get(i).isJsonObject()) {
JsonObject o = arr.get(i).getAsJsonObject();
boolean inside = false;
for (String replacement : replaces)
if (o.toString().contains(replacement)) {
if (inside) {
break;
}
inside = true;
}
if (!inside) { // the placeholder we're looking for is not inside this element, so we continue
// searching
replacer.add(o);
continue;
}
JsonElement text = o.get("text");
if (text == null) {
continue;
}
if (text.getAsString().isEmpty()) {
JsonElement el = o.get("extra");
if (el == null) {
continue;
}
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseNoItemArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
String msg = text.getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replaces) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(rgx);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
String st = o.toString();
JsonObject fix = PARSER.parse(st).getAsJsonObject();
fix.addProperty("text", splits[j]);
replacer.add(fix);
}
if (j != splits.length - 1) {
replacer.addAll(classicTooltip);
}
}
if (!fnd) {
replacer.add(o);
}
} else {
if (arr.get(i).isJsonNull()) {
continue;
} else {
if (arr.get(i).isJsonArray()) {
JsonArray jar = arr.get(i).getAsJsonArray();
if (jar.size() != 0) {
jar = parseNoItemArray(arr.get(i).getAsJsonArray());
replacer.set(i, jar);
}
} else {
String msg = arr.get(i).getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replaces) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(rgx);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
JsonElement fix = new JsonPrimitive(splits[j]);
replacer.add(fix);
}
if (j != splits.length - 1) {
replacer.addAll(classicTooltip);
}
}
if (!fnd) {
replacer.add(arr.get(i));
}
}
}
}
}
return replacer;
}
private JsonArray parseArray(JsonArray arr) {
JsonArray replacer = new JsonArray();
for (int i = 0; i < arr.size(); ++i) {
if (arr.get(i).isJsonObject()) {
JsonObject o = arr.get(i).getAsJsonObject();
boolean inside = false;
for (String replacement : replaces)
if (o.toString().contains(replacement)) {
if (inside) {
break;
}
inside = true;
}
if (!inside) { // the placeholder we're looking for is not inside this element, so we continue
// searching
replacer.add(o);
continue;
}
JsonElement text = o.get("text");
if (text == null) {
continue;
}
if (text.getAsString().isEmpty()) {
JsonElement el = o.get("extra");
if (el == null) {
continue;
}
JsonArray jar = el.getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(jar);
o.add("extra", jar);
} else {
o.remove("extra");
}
}
String msg = text.getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replaces) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(rgx);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
String st = o.toString();
JsonObject fix = PARSER.parse(st).getAsJsonObject();
fix.addProperty("text", splits[j]);
replacer.add(fix);
}
if (j != splits.length - 1) {
replacer.add(itemTooltip);
}
}
if (!fnd) {
replacer.add(o);
}
} else {
if (arr.get(i).isJsonNull()) {
continue;
} else {
if (arr.get(i).isJsonArray()) {
JsonArray jar = arr.get(i).getAsJsonArray();
if (jar.size() != 0) {
jar = parseArray(arr.get(i).getAsJsonArray());
replacer.set(i, jar);
}
} else {
String msg = arr.get(i).getAsString();
boolean isLast = false;
boolean done = false;
boolean fnd;
String[] splits;
for (String repls : replaces) {
if (done) {
break;
}
isLast = msg.endsWith(repls);
if (isLast) {
done = true;
msg = msg.concat(".");
}
}
splits = msg.split(rgx);
fnd = splits.length != 1;
if (fnd)
for (int j = 0; j < splits.length; ++j) {
boolean endDot = (j == splits.length - 1) && isLast;
if (!splits[j].isEmpty() && !endDot) {
JsonElement fix = new JsonPrimitive(splits[j]);
replacer.add(fix);
}
if (j != splits.length - 1) {
replacer.add(itemTooltip);
}
}
if (!fnd) {
replacer.add(arr.get(i));
}
}
}
}
}
return replacer;
}
@SuppressWarnings("deprecation")
private Item toItem(ItemStack is) throws Exception {
CompoundTag tag = new CompoundTag("tag");
Object nmsStack = AS_NMS_COPY.invoke(null, is);
Object nmsTag = NBT_TAG_COMPOUND.newInstance();
SAVE_NMS_ITEM_STACK_METHOD.invoke(nmsStack, nmsTag);
Map<String, Object> nmsMap = (Map<String, Object>) MAP.get(nmsTag);
String id = nmsMap.get("id").toString().replace("\"", "");
Object realTag = nmsMap.get("tag");
if (NBT_TAG_COMPOUND.isInstance(realTag)) { // We need to make sure this is indeed an NBTTagCompound
Map<String, Object> realMap = (Map<String, Object>) MAP.get(realTag);
Set<Map.Entry<String, Object>> entrySet = realMap.entrySet();
Map<String, Tag> map = tag.getValue();
for (Map.Entry<String, Object> entry : entrySet) {
map.put(entry.getKey(), toOpenTag(entry.getValue(), entry.getKey()));
}
tag.setValue(map);
}
Item item = new Item();
item.setAmount((byte) is.getAmount());
item.setData(is.getDurability());
item.setId(id);
item.setTag(tag);
return item;
}
private Tag toOpenTag(Object nmsTag, String name) throws Exception {
if (NBT_TAG_COMPOUND.isInstance(nmsTag)) {
CompoundTag tag = new CompoundTag(name);
Map<String, Tag> tagMap = tag.getValue();
Map<String, Object> nmsMap = (Map<String, Object>) MAP.get(nmsTag);
Set<Map.Entry<String, Object>> entrySet = nmsMap.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
Tag value = toOpenTag(entry.getValue(), entry.getKey());
tagMap.put(entry.getKey(), value);
}
tag.setValue(tagMap);
return tag;
} else {
// Strings are a special case as they need proper escaping
if (NBT_STRING.isInstance(nmsTag)) {
String toString = nmsTag.toString();
if (toString.startsWith("\"") && toString.endsWith("\"")) {
toString = toString.substring(1, toString.length() - 1);
// toString = escapeSpecials(toString);
return new StringTag(name, toString);
}
}
// NBTTag Lists are also special, as they are a sort of compound themselves and
// need to be parsed recursively
if (NBT_LIST.isInstance(nmsTag)) {
List<Object> nmsNBTBaseList = (List<Object>) LIST_FIELD.get(nmsTag);
List<Tag> list = new ArrayList<>();
//int i = 0;
for (Object baseTag : nmsNBTBaseList) {
list.add(toOpenTag(baseTag, ""));
//++i;
}
return new ListTag(name, list);
}
for (int i = 0; i < NBT_BASE_CLASSES.size(); ++i) {
Class<?> c = NBT_BASE_CLASSES.get(i);
if (c.isInstance(nmsTag)) {
Object value = NBT_BASE_DATA_FIELD.get(i).get(nmsTag);
if(value.getClass().getSimpleName().startsWith("NBTTag")) {
if(!TYPES_TO_MC_NBT_TAGS.containsKey(value.getClass())) {
ChatItem.getInstance().getLogger().warning("Failed to find NBT tag for class: " + value.getClass().getSimpleName());
continue;
}
return TYPES_TO_MC_NBT_TAGS.get(value.getClass()).apply(name, value);
} else {
Tag t = TYPES_TO_OPEN_NBT_TAGS.get(value.getClass()).apply(name);
if (t instanceof ByteTag) {
((ByteTag) t).setValue((byte) value);
((ByteTag) t).setValue((byte) value);
} else if (t instanceof ByteArrayTag)
((ByteArrayTag) t).setValue((byte[]) value);
else if (t instanceof DoubleTag)
((DoubleTag) t).setValue((double) value);
else if (t instanceof FloatTag)
((FloatTag) t).setValue((float) value);
else if (t instanceof IntTag)
((IntTag) t).setValue((int) value);
else if (t instanceof IntArrayTag)
((IntArrayTag) t).setValue((int[]) value);
else if (t instanceof LongTag)
((LongTag) t).setValue((long) value);
else if (t instanceof ShortTag)
((ShortTag) t).setValue((short) value);
else
ChatItem.getInstance().getLogger().warning("Failed to find Open tag for class: " + t.getClass().getSimpleName());
return t; // Should never happen
}
}
}
return null; // Should never happen
}
}
private String stringifyItem(ItemStack stack) throws Exception {
Item item = toItem(stack);
ItemRewriter.remapIds(Version.getVersion().MAX_VER, protocolVersion.MAX_VER, item);
StringBuilder sb = new StringBuilder("{id:");
sb.append("\"").append(item.getId()).append("\"").append(","); // Append the id
sb.append("Count:").append(item.getAmount()).append("b,"); // Append the amount
sb.append("Damage:").append(item.getData()).append("s"); // Append the durability data
Map<String, Tag> tagMap = item.getTag().getValue();
if (tagMap.isEmpty()) {
sb.append("}");
return sb.toString();
}
Set<Map.Entry<String, Tag>> entrySet = tagMap.entrySet();
boolean first = true;
sb.append(",tag:{"); // Start of the tag
for (Map.Entry<String, Tag> entry : entrySet) {
String key = entry.getKey();
if (IGNORED.contains(key)) {
continue;
}
Pattern pattern = Pattern.compile("[{}\\[\\],\":\\\\/]");
Matcher matcher = pattern.matcher(key);
if (matcher.find()) {
continue; // Skip invalid keys, as they can cause exceptions client-side
}
String value = stringifyTag(entry.getValue());
if (!first) {
sb.append(",");
}
sb.append(key).append(":").append(value);
first = false;
}
sb.append("}}"); // End of tag and end of item
return sb.toString();
}
private String stringifyTag(Tag normalTag) {
if (normalTag instanceof CompoundTag) {
StringBuilder sb = new StringBuilder("{");
CompoundTag tagCompound = (CompoundTag) normalTag;
Map<String, Tag> tagMap = tagCompound.getValue();
Set<Map.Entry<String, Tag>> entrySet = tagMap.entrySet();
for (Map.Entry<String, Tag> entry : entrySet) {
String value = stringifyTag(entry.getValue());
if (value == null) {
continue;
}
if (sb.length() > 1) {
sb.append(",");
}
sb.append(entry.getKey()).append(":").append(value);
}
sb.append("}");
return sb.toString();
} else {
if (normalTag instanceof StringTag) {
return "\"" + ((StringTag) normalTag).getValue() + "\""; // Should be already escaped
}
if (normalTag instanceof ListTag) {
List<Tag> list = ((ListTag) normalTag).getValue();
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Tag tag : list) {
String index = tag.getName();
String value = stringifyTag(tag);
if (value == null) {
continue;
}
if (!first) {
sb.append(",");
}
if (protocolVersion.MAX_VER <= Version.V1_11.MAX_VER) { // it's before 1.12
sb.append(index).append(":").append(value);
} else {
sb.append(value);
}
first = false;
}
sb.append("]");
return sb.toString();
}
if (normalTag instanceof ByteTag) {
return normalTag.getValue() + "b";
}
if (normalTag instanceof ByteArrayTag) {
return "[" + ((byte[]) normalTag.getValue()).length + " bytes]";
}
if (normalTag instanceof DoubleTag) {
return (double) normalTag.getValue() + "d";
}
if (normalTag instanceof FloatTag) {
return (float) normalTag.getValue() + "f";
}
if (normalTag instanceof IntTag) {
return String.valueOf((int) normalTag.getValue());
}
if (normalTag instanceof IntArrayTag) {
int[] array = (int[]) normalTag.getValue();
if (array.length == 0) {
return null;
}
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (int i : array) {
if (!first) {
sb.append(",");
}
sb.append(i);
first = false;
}
sb.append("]");
return sb.toString();
}
if (normalTag instanceof LongTag) {
return (long) normalTag.getValue() + "L";
}
if (normalTag instanceof ShortTag) {
return (short) normalTag.getValue() + "s";
}
return null; // Should never happen
}
}
}
@@ -1,17 +1,83 @@
package me.dadus33.chatitem.chatmanager.v1.json;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.bukkit.ChatColor;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.utils.ColorManager;
import net.md_5.bungee.api.ChatColor;
//Based on DarkSeraphim's system, but using Gson and supporting some more edge cases
public class Translator {
private static final String STYLES = "klmnor"; //All style codes
public static JsonArray toJson(String old){
if(old.lastIndexOf(ChatColor.COLOR_CHAR) == -1){
JsonArray arr = new JsonArray();
JsonObject obj = new JsonObject();
obj.addProperty("text", old);
arr.add(obj);
return arr;
}
JsonArray message = new JsonArray();
JsonObject next = new JsonObject();
String colorCode = "", text = "";
boolean waiting = false;
for (char args : old.toCharArray()) {
if (args == '§') { // begin of color
if(!text.isEmpty()) {
next.addProperty("text", text);
message.add(next);
next = new JsonObject();
text = "";
}
waiting = true; // waiting for color code
} else if (waiting) { // if waiting for code and valid str
// if it's hexademical value and with enough space for full color
waiting = false;
if(isStyle(args)) { // is style and not making rich color code
next.addProperty(getStyleName(args), true);
continue;
}
if(args == 'x' && !colorCode.isEmpty()) {
if(!text.isEmpty()) // ignore this if no text before
text += ColorManager.getColorString(colorCode);
colorCode = "x";
} else
colorCode += args; // a color by itself
} else {
waiting = false;
if(!colorCode.isEmpty()) { // manage color
if(colorCode.startsWith("x") && colorCode.length() == 7) { // hex color code
next.addProperty("color", ColorManager.getColor(colorCode).getName());
} else if(colorCode.length() == 1) { // if only one color code
if(next.has("color"))
text += ColorManager.getColor(colorCode);
else
next.addProperty("color", ColorManager.getColor(colorCode).getName());
} else if(!text.isEmpty())// no text before -> color will be used as "color"
text += ColorManager.getColorString(colorCode);
ChatItem.debug("Add " + colorCode + " to " + text + ", msg: " + message);
colorCode = "";
}
// basic text, not waiting for code after '§'
text += args;
}
}
if(!text.isEmpty() || message.isEmpty()) {
next.addProperty("text", text);
if(!next.has("color"))
next.addProperty("color", "white");
message.add(next);
}
return message;
}
public static JsonArray toJsonOld(String old){
if(old.lastIndexOf(ChatColor.COLOR_CHAR) == -1){
JsonArray arr = new JsonArray();
JsonObject obj = new JsonObject();
@@ -105,7 +171,7 @@ public class Translator {
}
private static String getColorName(char code){
return ChatColor.getByChar(code).name().toLowerCase();
return ChatColor.getByChar(code).getName().toLowerCase();
}
private static String getStyleName(char code){
@@ -116,7 +182,9 @@ public class Translator {
case 'n': return "underlined";
case 'o': return "italic";
case 'r': return "reset";
default: return null; //Should never happen. Made it return null to throw errors if a new format pops up and it really happens
default:
ChatItem.getInstance().getLogger().severe("Can't find code for style " + code);
return null; //Should never happen. Made it return null to throw errors if a new format pops up and it really happens
}
}
@@ -1,28 +1,24 @@
package me.dadus33.chatitem.chatmanager.v1.listeners;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR_END;
import java.util.HashMap;
import java.util.StringJoiner;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
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.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Utils;
public class ChatEventListener implements Listener {
private final static String LEFT = "{remaining}";
private final HashMap<String, Long> COOLDOWNS = new HashMap<>();
private final PacketEditingChatManager manage;
public ChatEventListener(PacketEditingChatManager manage) {
@@ -33,250 +29,42 @@ public class ChatEventListener implements Listener {
return this.manage.getStorage();
}
private String calculateTime(long seconds) {
if (seconds < 60) {
return seconds + getStorage().SECONDS;
}
if (seconds < 3600) {
StringBuilder builder = new StringBuilder();
int minutes = (int) seconds / 60;
builder.append(minutes).append(getStorage().MINUTES);
int secs = (int) seconds - minutes * 60;
if (secs != 0) {
builder.append(" ").append(secs).append(getStorage().SECONDS);
}
return builder.toString();
}
StringBuilder builder = new StringBuilder();
int hours = (int) seconds / 3600;
builder.append(hours).append(getStorage().HOURS);
int minutes = (int) (seconds / 60) - (hours * 60);
if (minutes != 0) {
builder.append(" ").append(minutes).append(getStorage().MINUTES);
}
int secs = (int) (seconds - ((seconds / 60) * 60));
if (secs != 0) {
builder.append(" ").append(secs).append(getStorage().SECONDS);
}
return builder.toString();
}
private int countOccurrences(String findStr, String str) {
int lastIndex = 0;
int count = 0;
while (lastIndex != -1) {
lastIndex = str.indexOf(findStr, lastIndex);
if (lastIndex != -1) {
count++;
lastIndex += findStr.length();
}
}
return count;
}
@SuppressWarnings("deprecation")
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) // We need to have lowest priority in order
// to get to the event before DeluxeChat or
// other plugins do
@EventHandler(priority = EventPriority.LOWEST)
public void onChat(AsyncPlayerChatEvent e) {
ChatItem.debug("(v1) Check for v1 system. Cancelled: " + e.isCancelled());
if (e.getMessage().indexOf(SEPARATOR) != -1) { // If the BELL character is found, we have to remove it
String msg = e.getMessage().replace(Character.toString(SEPARATOR), "");
ChatItem.debug("Already bell in message: " + e.getMessage());
e.setMessage(msg);
if (ChatManager.containsSeparator(e.getMessage())) { // If the BELL character is found, we have to remove it
e.setMessage(ChatManager.removeSeparator(e.getMessage()));
}
boolean found = false;
final String oldMsg = e.getMessage();
for (String rep : getStorage().PLACEHOLDERS)
for (String rep : getStorage().placeholders) {
if (oldMsg.contains(rep)) {
found = true;
break;
}
}
if (!found) {
ChatItem.debug("(v1) not found placeholders in: " + e.getMessage());
return;
}
Player p = e.getPlayer();
if (getStorage().PERMISSION_ENABLED && !p.hasPermission(getStorage().PERMISSION_NAME)) {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!getStorage().NO_PERMISSION_MESSAGE.isEmpty() && getStorage().SHOW_NO_PERM_NORMAL) {
p.sendMessage(getStorage().NO_PERMISSION_MESSAGE);
}
ChatItem.debug("(v1) Don't have permission");
ItemStack item = ChatManager.getUsableItem(p);
if (!ChatManager.canShowItem(p, item, e))
return;
}
if (p.getItemInHand().getType().equals(Material.AIR)) {
if (getStorage().DENY_IF_NO_ITEM) {
e.setCancelled(true);
if (!getStorage().DENY_MESSAGE.isEmpty())
e.getPlayer().sendMessage(getStorage().DENY_MESSAGE);
ChatItem.debug("(v1) No item and must deny");
return;
}
if (getStorage().HAND_DISABLED) {
ChatItem.debug("(v1) Hand disabled");
return;
}
}
ChatItem.debug("(v1) Checking cooldown " + e.getMessage());
if (getStorage().COOLDOWN > 0 && !p.hasPermission("chatitem.ignore-cooldown")) {
if (COOLDOWNS.containsKey(p.getName())) {
long start = COOLDOWNS.get(p.getName());
long current = System.currentTimeMillis() / 1000;
long elapsed = current - start;
if (elapsed >= getStorage().COOLDOWN) {
COOLDOWNS.remove(p.getName());
} else {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!getStorage().COOLDOWN_MESSAGE.isEmpty()) {
long left = (start + getStorage().COOLDOWN) - current;
p.sendMessage(getStorage().COOLDOWN_MESSAGE.replace(LEFT, calculateTime(left)));
}
ChatItem.debug("(v1) Cooldown");
return;
}
}
}
String s = e.getMessage(), firstPlaceholder = getStorage().PLACEHOLDERS.get(0);
for (String placeholder : getStorage().PLACEHOLDERS) {
String s = e.getMessage(), firstPlaceholder = getStorage().placeholders.get(0);
for (String placeholder : getStorage().placeholders) {
s = s.replace(placeholder, firstPlaceholder);
}
int occurrences = countOccurrences(firstPlaceholder, s);
if (occurrences > getStorage().LIMIT) {
if (Utils.countMatches(s, firstPlaceholder) > getStorage().limit) {
e.setCancelled(true);
ChatItem.debug("(v1) Reach message limit");
if (getStorage().LIMIT_MESSAGE.isEmpty()) {
return;
}
e.getPlayer().sendMessage(getStorage().LIMIT_MESSAGE);
if (!getStorage().messageLimit.isEmpty())
p.sendMessage(getStorage().messageLimit);
return;
}
ChatItem.debug("(v1) Set placeholder: " + e.getMessage());
try {
StringJoiner msg = new StringJoiner(" ");
for(String part : e.getMessage().split(" ")) {
if(part.equalsIgnoreCase(firstPlaceholder)) {
msg.add(firstPlaceholder + SEPARATOR + p.getName());
} else {
msg.add(part);
}
}
e.setMessage(msg.toString());
e.setFormat(e.getFormat().replace(oldMsg, e.getMessage())); // set own message for plugin that already put the message into the format
} catch (Exception exc) {
exc.printStackTrace();
}
if (!p.hasPermission("chatitem.ignore-cooldown")) {
COOLDOWNS.put(p.getName(), System.currentTimeMillis() / 1000);
}
}
@SuppressWarnings("deprecation")
@EventHandler(priority = EventPriority.LOWEST)
public void onCommand(final PlayerCommandPreprocessEvent e) {
if (e.getMessage().indexOf(SEPARATOR) != -1) { // If the BELL character is found, we have to remove it
String msg = e.getMessage().replace(Character.toString(SEPARATOR), "");
e.setMessage(msg);
}
String commandString = e.getMessage().split(" ")[0].replaceAll("^/+", ""); // First part of the command, without
// leading slashes and without
// arguments
Command cmd = Bukkit.getPluginCommand(commandString);
if (cmd == null) { // not a plugin command
if (!getStorage().ALLOWED_DEFAULT_COMMANDS.contains(commandString)) {
return;
}
} else {
if (!getStorage().ALLOWED_PLUGIN_COMMANDS.contains(cmd)) {
return;
}
}
Player p = e.getPlayer();
boolean found = false;
for (String rep : getStorage().PLACEHOLDERS) {
if (e.getMessage().contains(rep)) {
found = true;
break;
}
}
if (!found) {
return;
}
if (!p.hasPermission("chatitem.use")) {
if (!getStorage().NO_PERMISSION_MESSAGE.isEmpty() && getStorage().SHOW_NO_PERM_COMMAND) {
p.sendMessage(getStorage().NO_PERMISSION_MESSAGE);
}
e.setCancelled(true);
return;
}
if (e.getPlayer().getItemInHand().getType().equals(Material.AIR)) {
if (getStorage().DENY_IF_NO_ITEM) {
e.setCancelled(true);
if (!getStorage().DENY_MESSAGE.isEmpty()) {
e.getPlayer().sendMessage(getStorage().DENY_MESSAGE);
}
}
if (getStorage().HAND_DISABLED) {
return;
}
}
if (getStorage().COOLDOWN > 0 && !p.hasPermission("chatitem.ignore-cooldown")) {
if (COOLDOWNS.containsKey(p.getName())) {
long start = COOLDOWNS.get(p.getName());
long current = System.currentTimeMillis() / 1000;
long elapsed = current - start;
if (elapsed >= getStorage().COOLDOWN) {
COOLDOWNS.remove(p.getName());
} else {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!getStorage().COOLDOWN_MESSAGE.isEmpty()) {
long left = (start + getStorage().COOLDOWN) - current;
p.sendMessage(getStorage().COOLDOWN_MESSAGE.replace(LEFT, calculateTime(left)));
}
return;
}
}
}
String s = e.getMessage();
for (String placeholder : getStorage().PLACEHOLDERS) {
s = s.replace(placeholder, getStorage().PLACEHOLDERS.get(0));
}
int occurrences = countOccurrences(getStorage().PLACEHOLDERS.get(0), s);
if (occurrences > getStorage().LIMIT) {
e.setCancelled(true);
if (getStorage().LIMIT_MESSAGE.isEmpty()) {
return;
}
e.getPlayer().sendMessage(getStorage().LIMIT_MESSAGE);
return;
}
StringBuilder sb = new StringBuilder(e.getMessage());
sb.append(SEPARATOR).append(e.getPlayer().getName());
e.setMessage(sb.toString());
if (!p.hasPermission("chatitem.ignore-cooldown")) {
COOLDOWNS.put(p.getName(), System.currentTimeMillis() / 1000);
}
Chat c = Chat.create(p, oldMsg);
ChatItem.debug("(v1) Set placeholder to message " + c);
e.setMessage(s.replace(firstPlaceholder, SEPARATOR + Integer.toString(c.getId()) + SEPARATOR_END));
e.setFormat(e.getFormat().replace(oldMsg, e.getMessage())); // set own message for plugin that already put the message into the format
}
}
@@ -1,15 +1,14 @@
package me.dadus33.chatitem.chatmanager.v1.listeners;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR_STR;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.UUID;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Player;
@@ -19,11 +18,21 @@ import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.ItemMeta;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.IComponentManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.hook.AdventureComponentManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.hook.ComponentNMSManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.hook.IChatBaseComponentManager;
import me.dadus33.chatitem.chatmanager.v1.basecomp.hook.StringComponentManager;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketHandler;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketType;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Version;
@@ -32,175 +41,171 @@ import net.md_5.bungee.chat.ComponentSerializer;
public class ChatPacketManager extends PacketHandler {
private final static String NAME = "{name}";
private final static String AMOUNT = "{amount}";
private final static String TIMES = "{times}";
private Object lastSentPacket = null;
private Method serializerGetJson;
private PacketEditingChatManager manager;
private final List<IComponentManager> componentManager = new ArrayList<>();
public ChatPacketManager(PacketEditingChatManager manager) {
this.manager = manager;
try {
for (Method m : PacketUtils.CHAT_SERIALIZER.getDeclaredMethods()) {
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(PacketUtils.COMPONENT_CLASS)
&& m.getReturnType().equals(String.class)) {
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(PacketUtils.COMPONENT_CLASS) && m.getReturnType().equals(String.class)) {
serializerGetJson = m;
break;
}
}
if (serializerGetJson == null)
ChatItem.getInstance().getLogger().warning(
"Failed to find JSON serializer in class: " + PacketUtils.CHAT_SERIALIZER.getCanonicalName());
ChatItem.getInstance().getLogger().warning("Failed to find JSON serializer in class: " + PacketUtils.CHAT_SERIALIZER.getCanonicalName());
} catch (Exception e) {
e.printStackTrace();
}
for (IComponentManager getter : Arrays.asList(new StringComponentManager(), new IChatBaseComponentManager(), new ComponentNMSManager())) {
tryRegister(getter);
}
try {
if (Class.forName("net.kyori.adventure.text.Component") != null)
tryRegister(new AdventureComponentManager());
} catch (Exception e) {
}
ChatItem.getInstance().getLogger().info("Loaded " + componentManager.size() + " getter for base components.");
ChatItem.debug("ComponentManager: " + String.join(", ", componentManager.stream().map(IComponentManager::getClass).map(Class::getSimpleName).collect(Collectors.toList())));
}
private void tryRegister(IComponentManager getter) {
if (getter.hasConditions())
componentManager.add(getter);
}
@SuppressWarnings("deprecation")
@Override
public void onSend(ChatItemPacket e) {
if (!e.hasPlayer() || !e.getPacketType().equals(PacketType.Server.CHAT)) {
if (!e.hasPlayer() || !e.getPacketType().equals(PacketType.Server.CHAT))
return;
}
if (lastSentPacket != null && lastSentPacket == e.getPacket())
return; // prevent infinite loop
ChatItem.debug("Checking: " + e.getPacketType().getFullName() + " to " + e.getPlayername());
PacketContent packet = e.getContent();
Version version = Version.getVersion();
if (version.isNewerOrEquals(Version.V1_8)) { // only if action bar messages are supported in this
// version of minecraft
if (version.isNewerOrEquals(Version.V1_12)) {
String json = "{}";
IComponentManager choosedGetter = null;
if (version.isNewerOrEquals(Version.V1_19)) {
if (packet.getIntegers().readSafely(0, 0) > 1) { // not parsed chat message type
ChatItem.debug("Invalid int: " + packet.getIntegers().read(0));
return;
}
choosedGetter = new StringComponentManager();
json = choosedGetter.getBaseComponentAsJSON(e); // if null, will be re-checked so anyway
} else if (version.isNewerOrEquals(Version.V1_12)) {
// only if action bar messages are supported
if (((Enum<?>) packet.getSpecificModifier(PacketUtils.getNmsClass("ChatMessageType", "network.chat.")).read(0)).name().equals("GAME_INFO"))
return; // It's an actionbar message, ignoring
} else if (version.isNewerOrEquals(Version.V1_8) && packet.getBytes().readSafely(0) == (byte) 2)
return; // It's an actionbar message, ignoring
if (json == null || choosedGetter == null) {
for (IComponentManager getters : componentManager) {
String tmpJson = getters.getBaseComponentAsJSON(e);
if (tmpJson != null) {
json = ChatManager.fixSeparator(tmpJson);
choosedGetter = getters;
if (ChatManager.containsSeparator(json))
break; // be sure it's valid one
}
}
}
if (json == null || choosedGetter == null) {
ChatItem.debug("Can't find valid json getter or json itself");
ChatItem.debug("String: " + packet.getStrings().getContent());
for (Field f : e.getPacket().getClass().getDeclaredFields()) {
f.setAccessible(true);
try {
if (((Enum<?>) e.getContent()
.getSpecificModifier(PacketUtils.getNmsClass("ChatMessageType", "network.chat.")).read(0))
.name().equals("GAME_INFO")) {
return; // It means it's an actionbar message, and we ain't intercepting those
}
ChatItem.debug(f.getName() + ": " + f.get(e.getPacket()));
} catch (Exception exc) {
exc.printStackTrace();
}
} else if (e.getContent().getBytes().readSafely(0) == (byte) 2) {
return; // It means it's an actionbar message, and we ain't intercepting those
}
return; // can't find something
}
ChatItem.debug("UUID: " + e.getContent().getSpecificModifier(UUID.class).readSafely(0, null));
boolean usesBaseComponents = false;
PacketContent packet = e.getContent();
String json;
if (packet.getChatComponents().readSafely(0) == null) { // null check for some cases of messages sent using
// spigot's Chat Component API or other means
if (!manager.supportsChatComponentApi()) // only if the API is supported in this server distribution
return;// We don't know how to deal with anything else. Most probably some mod message
// we shouldn't mess with anyways
BaseComponent[] components = packet.getSpecificModifier(BaseComponent[].class).readSafely(0);
if (components == null) {
ChatItem.debug("No base components");
return;
}
json = ComponentSerializer.toString(components);
usesBaseComponents = true;
} else {
try {
json = (String) serializerGetJson.invoke(null, packet.getChatComponents().readSafely(0));
} catch (Exception exc) {
exc.printStackTrace();
json = "{}";
}
}
boolean found = false;
for (String rep : getStorage().PLACEHOLDERS) {
if (json.contains(rep)) {
found = true;
break;
}
}
if (!found) {
ChatItem.debug("No placeholders founded");
return; // then it's just a normal message without placeholders, so we leave it alone
}
Object toReplace = null;
if(json.lastIndexOf(SEPARATOR) != -1)
toReplace = SEPARATOR;
if(json.lastIndexOf(SEPARATOR_STR) != -1)
toReplace = SEPARATOR_STR;
if (toReplace == null) { // if the message doesn't contain the BELL separator, then it's certainly NOT a message we want to parse
ChatItem.debug("Not contains bell " + json);
if (!ChatManager.containsSeparator(json)) { // if the message doesn't contain the BELL separator
ChatItem.debug("Not containing bell " + json + " (manager: " + choosedGetter.getClass().getName() + ")");
return;
}
ChatItem.debug("Add packet meta");
String fjson = json, toReplaceStr = toReplace.toString();
boolean bUsesBaseComponents = usesBaseComponents;
e.setCancelled(true); // We cancel the packet as we're going to resend it anyways (ignoring listeners
// this time)
ChatItem.debug("Found with " + choosedGetter.getClass().getName());
Chat chat = choosedGetter.getChat(json);
if (chat == null) { // something went really bad, so we run away and hide (AKA the player left or is
// on another server)
ChatItem.debug("Chat null for " + json);
return;
}
Player itemPlayer = chat.getPlayer();
IComponentManager getter = choosedGetter;
e.setCancelled(true); // We cancel the packet as we're going to resends it anyways
Bukkit.getScheduler().runTaskAsynchronously(ChatItem.getInstance(), () -> {
int topIndex = -1;
String name = null;
for (Player p : Bukkit.getOnlinePlayers()) {
String pname = toReplaceStr + p.getName();
if (!fjson.contains(pname)) {
continue;
}
int index = fjson.lastIndexOf(pname) + pname.length();
if (index > topIndex) {
topIndex = index;
name = pname.replace(toReplaceStr, "");
}
}
if (name == null) { // something went really bad, so we run away and hide (AKA the player left or is
// on another server)
ChatItem.debug("Name null for " + fjson);
return;
}
Player p = Bukkit.getPlayer(name);
StringBuilder builder = new StringBuilder(fjson);
builder.replace(topIndex - (name.length() + 6), topIndex, ""); // we remove both the name and the separator
// from the json string
String localJson = builder.toString();
Player p = e.getPlayer();
String message = null;
try {
if (!p.getItemInHand().getType().equals(Material.AIR)) {
ItemStack copy = p.getItemInHand().clone();
if (copy.getType().name().contains("_BOOK")) { // filtering written books
BookMeta bm = (BookMeta) copy.getItemMeta();
bm.setPages(Collections.emptyList());
copy.setItemMeta(bm);
} else {
if (copy.getType().name().contains("SHULKER_BOX")) { // if it's shulker
if (copy.hasItemMeta()) {
BlockStateMeta bsm = (BlockStateMeta) copy.getItemMeta();
if (bsm.hasBlockState()) {
ShulkerBox sb = (ShulkerBox) bsm.getBlockState();
for (ItemStack item : sb.getInventory()) {
stripData(item);
}
bsm.setBlockState(sb);
ItemStack item = ChatManager.getUsableItem(itemPlayer);
if (!ItemUtils.isEmpty(item)) {
ItemStack copy = item.clone();
if (ItemPlayer.getPlayer(p).isBuggedClient()) { // if the guy that will receive it is bugged
String act = getStorage().buggedClientAction;
List<String> tooltip;
if (act.equalsIgnoreCase("tooltip"))
tooltip = getStorage().tooltipBuggedClient;
else if (act.equalsIgnoreCase("item"))
tooltip = ChatManager.getMaxLinesFromItem(p, copy);
else if (act.equalsIgnoreCase("show_both")) {
tooltip = ChatManager.getMaxLinesFromItem(p, copy);
tooltip.addAll(getStorage().tooltipBuggedClient);
} else
tooltip = new ArrayList<>();
message = JSONManipulator.getInstance().parseEmpty(getter.getBaseComponentAsJSON(e), ChatManager.styleItem(p, copy, getStorage()), tooltip, chat.getPlayer());
if (!manager.supportsChatComponentApi()) {
ChatItem.debug("Use basic for 1.7 lunar");
packet.getChatComponents().write(0, jsonToChatComponent(message));
} else {
ChatItem.debug("Use baseComponent for 1.7 lunar");
packet.getSpecificModifier(BaseComponent[].class).write(0, ComponentSerializer.parse(message));
}
lastSentPacket = e.getPacket();
PacketUtils.sendPacket(p, lastSentPacket);
return;
}
if (copy.hasItemMeta()) {
ItemMeta meta = copy.getItemMeta();
if (meta instanceof BookMeta) { // filtering written books
BookMeta bm = (BookMeta) copy.getItemMeta();
bm.setPages(Collections.emptyList());
copy.setItemMeta(bm);
} else if (meta instanceof BlockStateMeta && Version.getVersion().isNewerOrEquals(Version.V1_9)) { // if it's a block
BlockStateMeta bsm = (BlockStateMeta) copy.getItemMeta();
if (bsm.hasBlockState() && bsm.getBlockState() instanceof ShulkerBox) {
ShulkerBox sb = (ShulkerBox) bsm.getBlockState();
for (ItemStack itemInv : sb.getInventory()) {
stripData(itemInv);
}
copy.setItemMeta(bsm);
bsm.setBlockState(sb);
}
copy.setItemMeta(bsm);
}
}
message = manager.getManipulator().parse(localJson, getStorage().PLACEHOLDERS, copy,
styleItem(copy, getStorage()), manager.getPlayerVersionAdapter().getProtocolVersion(p));
lastSentPacket = getter.manageItem(p, chat, e, item, getStorage());
} else {
if (!getStorage().HAND_DISABLED) {
message = manager.getManipulator().parseEmpty(localJson, getStorage().PLACEHOLDERS,
getStorage().HAND_NAME, getStorage().HAND_TOOLTIP, p);
if (!getStorage().handDisabled) {
lastSentPacket = getter.manageEmpty(p, chat, e, getStorage());
}
}
if (lastSentPacket == null)
ChatItem.debug("(v1) No packet to sent with manager " + getter.getClass().getName());
else
PacketUtils.sendPacket(p, lastSentPacket);
} catch (Exception e1) {
e1.printStackTrace();
}
if (message != null) {
if (!bUsesBaseComponents) {
packet.getChatComponents().write(0, jsonToChatComponent(message));
} else {
packet.getSpecificModifier(BaseComponent[].class).write(0, ComponentSerializer.parse(message));
}
}
PacketUtils.sendPacket(e.getPlayer(), e.getPacket());
});
}
private Object jsonToChatComponent(String json) {
try {
return PacketUtils.CHAT_SERIALIZER.getMethod("a", String.class).invoke(null, json);
@@ -210,70 +215,6 @@ public class ChatPacketManager extends PacketHandler {
return null;
}
public static String styleItem(ItemStack item, Storage c) {
String replacer = c.NAME_FORMAT;
String amount = c.AMOUNT_FORMAT;
boolean dname = item.hasItemMeta() ? item.getItemMeta().hasDisplayName() : false;
if (item.getAmount() == 1) {
if (c.FORCE_ADD_AMOUNT) {
amount = amount.replace(TIMES, "1");
replacer = replacer.replace(AMOUNT, amount);
} else {
replacer = replacer.replace(AMOUNT, "");
}
} else {
amount = amount.replace(TIMES, String.valueOf(item.getAmount()));
replacer = replacer.replace(AMOUNT, amount);
}
if (dname) {
String trp = item.getItemMeta().getDisplayName();
if (c.COLOR_IF_ALREADY_COLORED) {
replacer = replacer.replace(NAME, ChatColor.stripColor(trp));
} else {
replacer = replacer.replace(NAME, trp);
}
} else {
HashMap<Short, String> translationSection = c.TRANSLATIONS.get(item.getType().name());
if (translationSection == null) {
String trp = materialToName(item.getType());
replacer = replacer.replace(NAME, trp);
} else {
@SuppressWarnings("deprecation")
String translated = translationSection.get(item.getDurability());
if (translated != null) {
replacer = replacer.replace(NAME, translated);
} else {
replacer = replacer.replace(NAME, materialToName(item.getType()));
}
}
}
return replacer;
}
private static String materialToName(Material m) {
if (m.equals(Material.TNT)) {
return "TNT";
}
String orig = m.toString().toLowerCase();
String[] splits = orig.split("_");
StringBuilder sb = new StringBuilder(orig.length());
int pos = 0;
for (String split : splits) {
sb.append(split);
int loc = sb.lastIndexOf(split);
char charLoc = sb.charAt(loc);
if (!(split.equalsIgnoreCase("of") || split.equalsIgnoreCase("and") || split.equalsIgnoreCase("with")
|| split.equalsIgnoreCase("on")))
sb.setCharAt(loc, Character.toUpperCase(charLoc));
if (pos != splits.length - 1)
sb.append(' ');
++pos;
}
return sb.toString();
}
private void stripData(ItemStack i) {
if (i == null) {
return;
@@ -292,7 +233,6 @@ public class ChatPacketManager extends PacketHandler {
i.setItemMeta(im);
}
public Storage getStorage() {
return manager.getStorage();
}
@@ -8,7 +8,7 @@ import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.utils.Version;
public class HandshakeListener extends PacketAdapter {
@@ -4,11 +4,10 @@ import org.bukkit.entity.Player;
public class ChatItemPacket {
protected Player player;
protected final Player player;
protected Object packet;
protected PacketType type;
protected boolean cancel = false;
protected PacketMetadata metaData = new PacketMetadata();
public ChatItemPacket(PacketType type, Object packet, Player player) {
this.player = player;
@@ -31,6 +30,10 @@ public class ChatItemPacket {
public Object getPacket() {
return packet;
}
public void setPacket(Object packet) {
this.packet = packet;
}
public String getPacketName() {
return packet.getClass().getSimpleName();
@@ -51,8 +54,4 @@ public class ChatItemPacket {
public PacketContent getContent() {
return new PacketContent(this);
}
public PacketMetadata getMetaData() {
return metaData;
}
}
@@ -1,5 +1,7 @@
package me.dadus33.chatitem.chatmanager.v1.packets;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
@@ -18,7 +20,7 @@ public class ChatItemPacketManager {
pl.getLogger().info("The plugin ProtocolLib has been detected. Loading Protocollib support ...");
packetManager = new ProtocollibPacketManager(pl);
} else {
pl.getLogger().warning("The plugin ProtocolLib has been detected but you have an OLD version, so we cannot use it.");
pl.getLogger().warning("The plugin ProtocolLib has been detected but you have an old or too new version, so we cannot use it.");
pl.getLogger().warning("Fallback to default Packet system ...");
packetManager = new CustomPacketManager(pl);
}
@@ -33,11 +35,12 @@ public class ChatItemPacketManager {
}
private boolean checkProtocollibConditions() {
try {
Class.forName("com.comphenix.protocol.injector.server.TemporaryPlayer");
return true;
} catch (ClassNotFoundException e) {
return false;
for(String searchedClass : Arrays.asList("com.comphenix.protocol.injector.server.TemporaryPlayer", "com.comphenix.protocol.injector.temporary.TemporaryPlayer")) { // class since 4.4.0 until 4.8.0, then the new one
try {
Class.forName(searchedClass);
return true; // class found
} catch (ClassNotFoundException e) {}
}
return false;
}
}
@@ -2,8 +2,10 @@ package me.dadus33.chatitem.chatmanager.v1.packets;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.stream.Collectors;
import me.dadus33.chatitem.utils.PacketUtils;
@@ -65,7 +67,6 @@ public class PacketContent {
return new ContentModifier<byte[]>(obj, byte[].class);
}
@SuppressWarnings("unchecked")
public ContentModifier<Object> getChatComponents() {
return (ContentModifier<Object>) getSpecificModifier(PacketUtils.COMPONENT_CLASS);
}
@@ -75,7 +76,6 @@ public class PacketContent {
private Object obj;
private HashMap<Field, T> content = new HashMap<>();
@SuppressWarnings("unchecked")
public ContentModifier(Object obj, Class<?> clazz) {
this.obj = obj;
@@ -103,6 +103,10 @@ public class PacketContent {
}
}
public Object getObj() {
return obj;
}
/**
* Get the size of the Map of content
*
@@ -148,7 +152,7 @@ public class PacketContent {
* @throws NoSuchElementException if the value doesn't exist
*/
public T read(int i) {
return content.values().stream().filter(Objects::nonNull).findFirst().get();
return content.values().stream().filter(Objects::nonNull).collect(Collectors.toList()).get(i);
}
/**
@@ -169,7 +173,8 @@ public class PacketContent {
* @return the requested value.
*/
public T readSafely(int i, T defaultValue) {
return content.values().stream().filter(Objects::nonNull).findFirst().orElse(defaultValue);
List<T> vals = content.values().stream().filter(Objects::nonNull).collect(Collectors.toList());
return vals.size() <= i ? defaultValue : vals.get(i);
}
/**
@@ -185,6 +190,12 @@ public class PacketContent {
} else {
content.put(key, value);
try {
key.setAccessible(true);
/*if(Modifier.isFinal(key.getModifiers())) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(key, key.getModifiers() & ~Modifier.FINAL);
}*/
key.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
@@ -1,29 +0,0 @@
package me.dadus33.chatitem.chatmanager.v1.packets;
import java.util.HashMap;
public class PacketMetadata {
private final HashMap<String, Object> metas = new HashMap<>();
public void setMeta(String key, Object obj) {
this.metas.put(key, obj);
}
public boolean hasMeta(String key) {
return metas.containsKey(key);
}
public void removeMeta(String key) {
metas.remove(key);
}
@SuppressWarnings("unchecked")
public <T> T getMeta(String key, T def) {
return (T) metas.getOrDefault(key, def);
}
public HashMap<String, Object> getMetas() {
return metas;
}
}
@@ -1,6 +1,7 @@
package me.dadus33.chatitem.chatmanager.v1.packets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public interface PacketType {
@@ -10,6 +11,13 @@ public interface PacketType {
String getFullName();
List<String> getAlias();
public static List<PacketType> values() {
List<PacketType> list = new ArrayList<>();
list.addAll(Arrays.asList(Server.values()));
list.addAll(Arrays.asList(Handshake.values()));
return list;
}
static final String SERVER_PREFIX = "PacketPlayOut", HANDSHAKE_PREFIX = "PacketHandshaking";
public static PacketType getType(String packetName) {
@@ -18,6 +26,10 @@ public interface PacketType {
} else if(packetName.startsWith(HANDSHAKE_PREFIX)) {
return getPacketTypeFor(packetName, Handshake.values(), Handshake.UNSET);
} else {
for(PacketType types : values()) {
if(types.getFullName().equalsIgnoreCase(packetName) || types.getAlias().contains(packetName))
return types;
}
return null;
}
}
@@ -31,7 +43,7 @@ public interface PacketType {
public static enum Server implements PacketType {
CHAT("Chat"),
CHAT("Chat", "ClientboundPlayerChatPacket", "ClientboundSystemChatPacket"),
UNSET("Unset");
private final String packetName, fullName;
@@ -41,7 +53,7 @@ public interface PacketType {
this.packetName = packetName;
this.fullName = SERVER_PREFIX + packetName;
for(String al : alias)
this.alias.add(SERVER_PREFIX + al);
this.alias.add(al);
}
@Override
@@ -83,7 +83,6 @@ public class CustomPacketManager extends PacketManager implements Listener {
public ChatItemPacket onPacketSent(PacketType type, Player sender, Object packet) {
if(type == null) {
//ChatItem.debug("Failed to find packet type for " + packet.getClass().getSimpleName());
return null;
}
ChatItemPacket customPacket = new ChatItemPacket(type, packet, sender);
@@ -9,8 +9,8 @@ import java.util.concurrent.Executors;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.DefaultVersionHook;
public abstract class ChannelAbstract {
@@ -54,7 +54,7 @@ public abstract class ChannelAbstract {
try {
Integer protocol = customPacketManager.protocolVersionPerChannel.remove(getChannel(p));
if(protocol != null)
DefaultVersionHook.PROTOCOL_PER_UUID.put(p.getUniqueId(), protocol);
ItemPlayer.getPlayer(p).setProtocolVersion(protocol);
} catch (Exception e) {
e.printStackTrace();
}
@@ -1,24 +1,24 @@
package me.dadus33.chatitem.chatmanager.v1.packets.custom.channel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketType;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent.ContentModifier;
import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager;
public class ChannelInboundHandler extends ChannelInboundHandlerAdapter {
public static final HashMap<Channel, ChatItemPacket> TMP = new HashMap<>();
private CustomPacketManager packetManager;
private List<ChannelPipeline> pipelines = new ArrayList<>();
@@ -74,7 +74,13 @@ public class ChannelInboundHandler extends ChannelInboundHandlerAdapter {
try {
PacketType packetType = PacketType.getType(packet.getClass().getSimpleName());
if(packetType != null && packetType == PacketType.Handshake.IS_SET_PROTOCOL) {
packetManager.protocolVersionPerChannel.put(channel, new PacketContent(packet).getIntegers().readSafely(0, 0));
ContentModifier<Integer> ints = new PacketContent(packet).getIntegers();
int possibleProtocol = ints.readSafely(0, 0);
if(possibleProtocol == Bukkit.getPort())
possibleProtocol = ints.readSafely(1, 0);
if(possibleProtocol == -1 || possibleProtocol == 255)
possibleProtocol = ints.readSafely(2, 0);
packetManager.protocolVersionPerChannel.put(channel, possibleProtocol);
}
super.channelRead(ctx, packet);
} catch (Exception e) {
@@ -17,7 +17,6 @@ import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketType;
import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Version;
@@ -27,14 +26,13 @@ public class INC2Channel extends ChannelAbstract {
private final ChannelInboundHandler boundHandler;
private ChannelPipeline pipeline;
@SuppressWarnings("unchecked")
public INC2Channel(CustomPacketManager customPacketManager) {
super(customPacketManager);
boundHandler = new ChannelInboundHandler(customPacketManager);
try {
Object mcServer = ReflectionUtils.callMethod(PacketUtils.getCraftServer(), Version.getVersion().equals(Version.V1_17) ? "getServer" : "b");
Object co = ReflectionUtils.getFirstWith(mcServer, PacketUtils.getNmsClass("MinecraftServer", "server."), PacketUtils.getNmsClass("ServerConnection", "server.network."));
((List<ChannelFuture>) ReflectionUtils.getField(co, "f")).forEach((channelFuture) -> {
((List<ChannelFuture>) ReflectionUtils.getObject(co, "f")).forEach((channelFuture) -> {
pipeline = channelFuture.channel().pipeline();
pipeline.addFirst(boundHandler);
});
@@ -58,10 +56,6 @@ public class INC2Channel extends ChannelAbstract {
Channel channel = getChannel(player);
// Managing outgoing packet (to the player)
channel.pipeline().addAfter(KEY_HANDLER_SERVER, KEY_SERVER + endChannelName, new ChannelHandlerSent(player));
ChatItemPacket pa = ChannelInboundHandler.TMP.remove(channel);
if(pa != null)
DefaultVersionHook.PROTOCOL_PER_UUID.put(player.getUniqueId(), pa.getContent().getIntegers().readSafely(0, Version.getVersion().MAX_VER));
} catch (NoSuchElementException e) {
// appear when the player's channel isn't accessible because of reload.
getPacketManager().getPlugin().getLogger().warning("Please, don't use reload, this can produce some problem. Currently, " + player.getName() + " isn't fully checked because of that. More details: " + e.getMessage() + " (NoSuchElementException)");
@@ -92,9 +86,9 @@ public class INC2Channel extends ChannelAbstract {
@Override
public Channel getChannel(Player p) throws Exception {
Object playerConnection = getPlayerConnection(p);
Object networkManager = playerConnection.getClass().getField("a").get(playerConnection);
return (Channel) networkManager.getClass().getDeclaredField("k").get(networkManager);//(Channel) networkManager.getClass().getDeclaredField("channel").get(networkManager);
Class<?> networkClass = PacketUtils.getNmsClass("NetworkManager", "network.");
Object networkManager = ReflectionUtils.getFirstWith(getPlayerConnection(p), PacketUtils.getNmsClass("PlayerConnection", "server.network."), networkClass);
return ReflectionUtils.getFirstWith(networkManager, networkClass, Channel.class);
}
private class ChannelHandlerSent extends ChannelOutboundHandlerAdapter {
@@ -110,7 +104,7 @@ public class INC2Channel extends ChannelAbstract {
ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet);
if(nextPacket != null && nextPacket.isCancelled())
return;
super.write(ctx, packet, promise);
super.write(ctx, nextPacket == null ? packet : nextPacket.getPacket(), promise);
}
}
}
@@ -19,12 +19,9 @@ import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketContent;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketType;
import me.dadus33.chatitem.chatmanager.v1.packets.custom.CustomPacketManager;
import me.dadus33.chatitem.chatmanager.v1.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Version;
@SuppressWarnings("unchecked")
public class INCChannel extends ChannelAbstract {
private final ChannelInboundHandler boundHandler;
@@ -70,10 +67,6 @@ public class INCChannel extends ChannelAbstract {
Channel channel = getChannel(player);
// Managing outgoing packet (to the player)
channel.pipeline().addAfter(KEY_HANDLER_SERVER, KEY_SERVER + endChannelName, new ChannelHandlerSent(player));
ChatItemPacket pa = ChannelInboundHandler.TMP.remove(channel);
if(pa != null)
DefaultVersionHook.PROTOCOL_PER_UUID.put(player.getUniqueId(), pa.getContent().getIntegers().readSafely(0, Version.getVersion().MAX_VER));
} catch (NoSuchElementException e) {
// appear when the player's channel isn't accessible because of reload.
getPacketManager().getPlugin().getLogger().warning("Please, don't use reload, this can produce some problem. Currently, " + player.getName() + " isn't fully checked because of that. More details: " + e.getMessage() + " (NoSuchElementException)");
@@ -123,7 +116,7 @@ public class INCChannel extends ChannelAbstract {
ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet);
if(nextPacket != null && nextPacket.isCancelled())
return;
super.write(ctx, packet, promise);
super.write(ctx, nextPacket == null ? packet : nextPacket.getPacket(), promise);
}
}
}
@@ -36,8 +36,7 @@ public class NMUChannel extends ChannelAbstract {
Object dedicatedSrv = PacketUtils.getCraftServer();
Object mcServer = dedicatedSrv.getClass().getMethod("getServer").invoke(dedicatedSrv);
Object co = ReflectionUtils.getFirstWith(mcServer, PacketUtils.getNmsClass("MinecraftServer", "server."), PacketUtils.getNmsClass("ServerConnection", "network."));
@SuppressWarnings("unchecked")
List<ChannelFuture> g = (List<ChannelFuture>) ReflectionUtils.getField(co, "g");
List<ChannelFuture> g = (List<ChannelFuture>) ReflectionUtils.getObject(co, "g", "e");
g.forEach((channelFuture) -> {
pipeline = channelFuture.channel().pipeline();
pipeline.addFirst(boundHandler = new ChannelInboundHandlerAdapter() {
@@ -139,7 +138,7 @@ public class NMUChannel extends ChannelAbstract {
ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet);
if(nextPacket != null && nextPacket.isCancelled())
return;
super.write(ctx, packet, promise);
super.write(ctx, nextPacket == null ? packet : nextPacket.getPacket(), promise);
}
}
@@ -156,7 +155,7 @@ public class NMUChannel extends ChannelAbstract {
try {
PacketType packetType = PacketType.getType(packet.getClass().getSimpleName());
if(packetType != null && packetType == PacketType.Handshake.IS_SET_PROTOCOL) {
getPacketManager().protocolVersionPerChannel.put(channel, new PacketContent(packet).getIntegers().readSafely(0, 0));
getPacketManager().protocolVersionPerChannel.put(channel, new PacketContent(packet).getIntegers().readSafely(1, 0));
}
super.channelRead(ctx, packet);
} catch (Exception e) {
@@ -1,6 +1,7 @@
package me.dadus33.chatitem.chatmanager.v1.packets.protocollib;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.entity.Player;
@@ -23,16 +24,24 @@ public class ProtocollibPacketManager extends PacketManager {
public ProtocollibPacketManager(ChatItem pl) {
protocolManager = ProtocolLibrary.getProtocolManager();
protocolManager.addPacketListener(new PacketAdapter(pl, ListenerPriority.LOWEST, Arrays.asList(Play.Server.CHAT)) {
List<com.comphenix.protocol.PacketType> list = new ArrayList<>();
list.add(Play.Server.CHAT);
try {
list.add((com.comphenix.protocol.PacketType) Play.Server.class.getDeclaredField("SYSTEM_CHAT").get(null));
} catch (Exception e) {
// ignore because using old version
}
protocolManager.addPacketListener(new PacketAdapter(pl, ListenerPriority.LOWEST, list) {
@Override
public void onPacketSending(PacketEvent e) {
Player p = e.getPlayer();
if (p == null || e.isPlayerTemporary())
return;
ChatItemPacket packet = onPacketSent(PacketType.getType(e.getPacket().getHandle().getClass().getSimpleName()),
p, e.getPacket().getHandle());
if(packet == null)
ChatItemPacket packet = onPacketSent(PacketType.getType(e.getPacket().getHandle().getClass().getSimpleName()), p, e.getPacket().getHandle());
if(packet == null) {
ChatItem.debug("Can't find packet: " + e.getPacket().getHandle().getClass().getName());
return;
}
if(!e.isCancelled())
e.setCancelled(packet.isCancelled());
}
@@ -3,6 +3,7 @@ package me.dadus33.chatitem.chatmanager.v1.utils;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
@Deprecated
public class Item {
private String id;
private byte amount;
@@ -5,19 +5,25 @@ import static me.dadus33.chatitem.utils.Version.V1_11;
import static me.dadus33.chatitem.utils.Version.V1_8;
import static me.dadus33.chatitem.utils.Version.V1_9;
import org.bukkit.inventory.ItemStack;
@Deprecated
public class ItemRewriter {
public static void remapIds(int server, int player, Item item) {
public static String remapIds(int server, int player, ItemStack is) {
Item item = new Item();
item.setAmount((byte)is.getAmount());
//item.setData(is.getDurability());
//item.setId(id);
//item.setTag(tag);
if (areIdsCompatible(server, player)) {
return;
return item.getId();
}
if ((server >= V1_9.MIN_VER && player <= V1_8.MAX_VER) || (player >= V1_9.MIN_VER && server <= V1_8.MAX_VER)) {
if ((server >= V1_9.MIN_VER && player <= V1_8.MAX_VER)) {
ItemRewriter_1_9_TO_1_8.reversedToClient(item);
return;
}
ItemRewriter_1_9_TO_1_8.toClient(item);
return;
} else
ItemRewriter_1_9_TO_1_8.toClient(item);
}
if ((server <= V1_10.MAX_VER && player >= V1_11.MIN_VER)
|| (player <= V1_10.MAX_VER && server >= V1_11.MIN_VER)) {
@@ -27,6 +33,7 @@ public class ItemRewriter {
ItemRewriter_1_11_TO_1_10.reverseToClient(item);
}
}
return item.getId();
}
public static boolean areIdsCompatible(int version1, int version2) {
@@ -10,6 +10,7 @@ import com.google.common.collect.HashBiMap;
/**
* Thanks to the developers of ViaVersion for this!
*/
@Deprecated
public class ItemRewriter_1_11_TO_1_10 {
private static BiMap<String, String> oldToNewNames = HashBiMap.create();
@@ -9,6 +9,7 @@ import java.util.Map;
/**
* Thanks to the developers of ViaVersion for this!
*/
@Deprecated
public class ItemRewriter_1_9_TO_1_8 {
private static final Map<String, Integer> ENTTIY_NAME_TO_ID = new HashMap<>();
@@ -1,46 +1,46 @@
package me.dadus33.chatitem.chatmanager.v2;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.hook.DiscordSrvSupport;
import me.dadus33.chatitem.playernamer.PlayerNamerManager;
import me.dadus33.chatitem.utils.ColorManager;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Version;
import me.dadus33.chatitem.utils.Utils;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.HoverEvent.Action;
import net.md_5.bungee.api.chat.TextComponent;
@SuppressWarnings("deprecation")
public class ChatListener implements Listener {
public final static char SEPARATOR = ((char) 0x0007);
private final static String NAME = "{name}";
private final static String AMOUNT = "{amount}";
private final static String TIMES = "{times}";
private final static String LEFT = "{remaining}";
private final HashMap<String, Long> COOLDOWNS = new HashMap<>();
private ChatListenerChatManager manage;
private Method saveMethod;
public ChatListener(ChatListenerChatManager manage) {
this.manage = manage;
private static Method saveMethod;
private static boolean shouldUseAppendMethod = false;
static {
try {
Class<?> nbtTag = PacketUtils.getNmsClass("NBTTagCompound", "nbt.");
Class<?> itemClass = PacketUtils.getNmsClass("ItemStack", "world.item.");
@@ -51,56 +51,42 @@ public class ChatListener implements Listener {
}
}
}
try {
ComponentBuilder.class.getDeclaredMethod("append", BaseComponent[].class);
shouldUseAppendMethod = true;
} catch (Exception e) {
shouldUseAppendMethod = false;
}
} catch (Exception e) {
}
Logger log = ChatItem.getInstance().getLogger();
String appendMethodMsg = shouldUseAppendMethod ? "Use ComponentBuilder's method." : "Use own ComponentBuilder append method.";
if (saveMethod == null)
ChatItem.getInstance().getLogger().info("Failed to find save method. Using default system...");
log.info("Failed to find save method. Using default system. " + appendMethodMsg);
else
ChatItem.getInstance().getLogger().info("Save method founded: " + saveMethod.getName() + ".");
log.info("Save method founded: " + saveMethod.getName() + ". " + appendMethodMsg);
}
private ChatListenerChatManager manage;
public ChatListener(ChatListenerChatManager manage) {
this.manage = manage;
}
public Storage getStorage() {
return manage.getStorage();
}
private String calculateTime(long seconds) {
if (seconds < 60) {
return seconds + getStorage().SECONDS;
}
if (seconds < 3600) {
StringBuilder builder = new StringBuilder();
int minutes = (int) seconds / 60;
builder.append(minutes).append(getStorage().MINUTES);
int secs = (int) seconds - minutes * 60;
if (secs != 0) {
builder.append(" ").append(secs).append(getStorage().SECONDS);
}
return builder.toString();
}
StringBuilder builder = new StringBuilder();
int hours = (int) seconds / 3600;
builder.append(hours).append(getStorage().HOURS);
int minutes = (int) (seconds / 60) - (hours * 60);
if (minutes != 0) {
builder.append(" ").append(minutes).append(getStorage().MINUTES);
}
int secs = (int) (seconds - ((seconds / 60) * 60));
if (secs != 0) {
builder.append(" ").append(secs).append(getStorage().SECONDS);
}
return builder.toString();
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.MONITOR)
public void onChat(AsyncPlayerChatEvent e) {
Storage c = getStorage();
if (e.isCancelled()) {
if (ChatItem.getInstance().getChatManager().size() == 1) { // only chat
String msg = e.getMessage().toLowerCase();
for (String rep : getStorage().PLACEHOLDERS) {
for (String rep : c.placeholders) {
if (msg.contains(rep)) {
ChatItem.debug(
"You choose 'chat' manager but it seems to don't be the good choice. More informations here: https://github.com/dadus33-plugins/ChatItem/wiki");
ChatItem.debug("You choose 'chat' manager but it seems to don't be the good choice. More informations here: https://github.com/dadus33-plugins/ChatItem/wiki");
return;
}
}
@@ -109,244 +95,236 @@ public class ChatListener implements Listener {
return;
}
Player p = e.getPlayer();
for (String rep : getStorage().PLACEHOLDERS) {
if (e.getMessage().contains(rep + ChatManager.SEPARATOR + p.getName())) { // already managed by v1
return;
if(ChatManager.containsSeparator(e.getMessage())) { // fix for v1
Chat chat = Chat.getFrom(e.getMessage());
if(chat == null)
ChatItem.debug("Chat for message " + e.getMessage() + " can't be found");
else {
e.setMessage(ChatManager.replaceSeparator(chat, e.getMessage(), c.placeholders.get(0)));
chat.remove();
}
}
boolean found = false;
for (String key : e.getMessage().split(" ")) {
if (found)
String placeholder = null;
for (String rep : c.placeholders) {
if (e.getMessage().contains(rep)) {
placeholder = rep;
break;
for (String rep : getStorage().PLACEHOLDERS) {
if (key.equalsIgnoreCase(rep)) {
found = true;
break;
}
}
}
if (!found) {
if (placeholder == null) { // if not found
ChatItem.debug("(v2) Can't found placeholder in: " + e.getMessage() + " > " + PlayerNamerManager.getPlayerNamer().getName(p));
return;
}
if (getStorage().PERMISSION_ENABLED && !p.hasPermission(getStorage().PERMISSION_NAME)) {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!getStorage().NO_PERMISSION_MESSAGE.isEmpty() && getStorage().SHOW_NO_PERM_NORMAL) {
p.sendMessage(getStorage().NO_PERMISSION_MESSAGE);
}
ItemStack item = ChatManager.getUsableItem(p);
if (!ChatManager.canShowItem(p, item, e))
return;
}
if (p.getItemInHand().getType().equals(Material.AIR)) {
if (getStorage().DENY_IF_NO_ITEM) {
e.setCancelled(true);
if (!getStorage().DENY_MESSAGE.isEmpty())
e.getPlayer().sendMessage(getStorage().DENY_MESSAGE);
return;
}
if (getStorage().HAND_DISABLED) {
return;
}
}
if (getStorage().COOLDOWN > 0 && !p.hasPermission("chatitem.ignore-cooldown")) {
if (COOLDOWNS.containsKey(p.getName())) {
long start = COOLDOWNS.get(p.getName());
long current = System.currentTimeMillis() / 1000;
long elapsed = current - start;
if (elapsed >= getStorage().COOLDOWN) {
COOLDOWNS.remove(p.getName());
} else {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!getStorage().COOLDOWN_MESSAGE.isEmpty()) {
long left = (start + getStorage().COOLDOWN) - current;
p.sendMessage(getStorage().COOLDOWN_MESSAGE.replace(LEFT, calculateTime(left)));
}
return;
}
}
}
e.setCancelled(true);
String format = e.getFormat(), defMsg = e.getMessage();
Bukkit.getConsoleSender().sendMessage(String.format(e.getFormat(), e.getPlayer().getDisplayName(), defMsg)); // show
// in
// log
boolean isAlreadyParsed = false;
if (format.contains("%1$s") && format.contains("%2$s")) // message not parsed but not default way
isAlreadyParsed = false;
if (format.equalsIgnoreCase(defMsg)) // is message already parsed
isAlreadyParsed = true;
if (format.equalsIgnoreCase("<%1$s> %2$s")) // default MC message
isAlreadyParsed = false;
String msg = isAlreadyParsed ? format : String.format(format, p.getDisplayName(), defMsg);
ItemStack item = p.getItemInHand();
ItemMeta meta = item == null ? null : item.getItemMeta();
if(Version.getVersion().isNewerOrEquals(Version.V1_16))
e.getRecipients().forEach((pl) -> showWithHex(pl, p, item, meta, format, msg));
else
e.getRecipients().forEach((pl) -> showWithoutHex(pl, p, item, meta, format, msg));
String format = e.getFormat();
String msg, defMsg = e.getMessage();
for (String rep : c.placeholders) {
defMsg = defMsg.replace(rep, Character.toString(ChatManager.SEPARATOR));
}
if (Utils.countMatches(defMsg, Character.toString(ChatManager.SEPARATOR)) > getStorage().limit) {
if (!getStorage().messageLimit.isEmpty())
p.sendMessage(getStorage().messageLimit);
return;
}
if (format.contains("%1$s") || format.contains("%2$s")) {
msg = (format.contains("%2$s") ? String.format(format, p.getDisplayName(), defMsg) : String.format(format, p.getDisplayName()));
} else {
msg = format.replace(e.getMessage(), defMsg);
}
String itemName = ChatManager.getNameOfItem(p, item, c);
String loggedMessage = msg.replace(ChatManager.SEPARATOR + "", itemName).replace("{name}", p.getName()).replace("{display-name}", p.getDisplayName());
Bukkit.getConsoleSender().sendMessage(loggedMessage); // show in log
if (ChatItem.discordSrvSupport)
DiscordSrvSupport.sendChatMessage(p, defMsg.replace(ChatManager.SEPARATOR + "", itemName).replace("{name}", p.getName()).replace("{display-name}", p.getDisplayName()));
Set<Player> recipients = e.getRecipients().isEmpty() ? new HashSet<>(Bukkit.getOnlinePlayers()) : e.getRecipients();
ChatItem.debug("Msg: " + msg.replace(ChatColor.COLOR_CHAR, '&') + ", format: " + format + " to " + recipients.size() + " players");
recipients.forEach((pl) -> showItem(pl, p, item, msg));
if (c.cooldown > 0 && !p.hasPermission("chatitem.ignore-cooldown"))
ChatManager.applyCooldown(p);
}
private void showWithoutHex(Player to, Player origin, ItemStack item, ItemMeta meta, String format, String msg) {
ComponentBuilder component = new ComponentBuilder();
ChatColor color = ChatColor.getByChar(getColorChat(format));
for (String args : msg.split(" ")) {
if (getStorage().PLACEHOLDERS.contains(args)) {
if (meta != null) {
ComponentBuilder itemComponent = new ComponentBuilder(
ChatListener.styleItem(to, item, getStorage()));
String itemJson = convertItemStackToJson(item);
itemComponent.event(new HoverEvent(Action.SHOW_ITEM, new ComponentBuilder(itemJson).create()));
component.append(itemComponent.create());
} else {
if (getStorage().HAND_DISABLED)
component.append(color + args);
else {
String handName = getStorage().HAND_NAME;
ComponentBuilder handComp = new ComponentBuilder();
ComponentBuilder handTooltip = new ComponentBuilder();
int stay = getStorage().HAND_TOOLTIP.size();
for (String line : getStorage().HAND_TOOLTIP) {
stay--;
handTooltip.append(line.replace("{name}", origin.getName()).replace("{display-name}",
origin.getDisplayName()));
if (stay > 0)
handTooltip.append("\n");
}
handComp.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, handTooltip.create()));
if (handName.contains("{name}")) {
String[] splitted = handName.split("{name}");
for (int i = 0; i < (splitted.length - 1); i++) {
handComp.append(new ComponentBuilder(splitted[i]).create());
handComp.append(PlayerNamerManager.getPlayerNamer().getName(origin));
}
handComp.append(new ComponentBuilder(splitted[splitted.length - 1]).create());
} else
handComp.append(handName.replace("{display-name}", origin.getDisplayName()));
component.append(handComp.create());
}
public static void showItem(Player to, Player origin, ItemStack item, String msg) {
ComponentBuilder builder = new ComponentBuilder("");
ChatColor color = ChatColor.WHITE;
String colorCode = "", text = "";
boolean waiting = false;
for (char args : msg.toCharArray()) {
if (args == '§') { // begin of color
if (colorCode.isEmpty() && !text.isEmpty()) { // text before this char
ChatItem.debug("Append '" + text + "' (len: " + text.length() + ")");
appendToComponentBuilder(builder, createComponent(text, color));
text = "";
}
} else {
component.append(color + args);
}
component.append(" ");
char maybeNextCode = getColorChat(args);
if (maybeNextCode != 'r') {
color = ChatColor.getByChar(maybeNextCode);
}
}
to.spigot().sendMessage(component.create());
}
private void showWithHex(Player to, Player origin, ItemStack item, ItemMeta meta, String format, String msg) {
ComponentBuilder component = new ComponentBuilder();
for (String args : msg.split(" ")) {
if (getStorage().PLACEHOLDERS.contains(args)) {
if (meta != null) {
ComponentBuilder itemComponent = new ComponentBuilder(
ChatListener.styleItem(to, item, getStorage()));
String itemJson = convertItemStackToJson(item);
itemComponent.event(new HoverEvent(Action.SHOW_ITEM, new ComponentBuilder(itemJson).create()));
component.append(itemComponent.create());
} else {
if (getStorage().HAND_DISABLED)
component.append(ColorManager.getChatWithHex(args));
else {
String handName = getStorage().HAND_NAME;
ComponentBuilder handComp = new ComponentBuilder();
ComponentBuilder handTooltip = new ComponentBuilder();
int stay = getStorage().HAND_TOOLTIP.size();
for (String line : getStorage().HAND_TOOLTIP) {
stay--;
handTooltip.append(line.replace("{name}", origin.getName()).replace("{display-name}",
origin.getDisplayName()));
if (stay > 0)
handTooltip.append("\n");
}
handComp.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, handTooltip.create()));
if (handName.contains("{name}")) {
String[] splitted = handName.split("{name}");
for (int i = 0; i < (splitted.length - 1); i++) {
handComp.append(new ComponentBuilder(splitted[i]).create());
handComp.append(PlayerNamerManager.getPlayerNamer().getName(origin));
}
handComp.append(new ComponentBuilder(splitted[splitted.length - 1]).create());
} else
handComp.append(handName.replace("{display-name}", origin.getDisplayName()));
component.append(handComp.create());
}
waiting = true; // waiting for color code
} else if (waiting) { // if waiting for code and valid str
// if it's hexademical value and with enough space for full color
waiting = false;
if (args == 'r' && colorCode.isEmpty()) {
color = ChatColor.RESET;
continue;
}
if (args == 'x' && !colorCode.isEmpty()) {
text += ColorManager.getColorString(colorCode);
colorCode = "x";
} else
colorCode += args; // a color by itself
} else {
component.append(ColorManager.getChatWithHex(args));
waiting = false;
if (!colorCode.isEmpty()) {
if (colorCode.startsWith("x") && colorCode.length() >= 7) {
if (colorCode.length() == 7)
color = ColorManager.getColor(colorCode);
else {
color = ColorManager.getColor(colorCode.substring(0, 7)); // only the hex code
ChatItem.debug("Adding color for " + colorCode.substring(7, colorCode.length()) + " (in " + colorCode + ")");
text += ColorManager.getColorString(colorCode.substring(7, colorCode.length()));
}
} else if (colorCode.length() == 1) // if only one color code
color = ColorManager.getColor(colorCode);
else
text += ColorManager.getColorString(colorCode);
colorCode = "";
}
if (args == ChatManager.SEPARATOR) {
// here put the item
appendToComponentBuilder(builder, fixColorComponent(text, color));
addItem(builder, to, origin, item);
text = "";
} else {
// basic text, not waiting for code after '§'
text += args;
}
}
component.append(" ");
}
to.spigot().sendMessage(component.create());
if (!text.isEmpty())
appendToComponentBuilder(builder, createComponent(text, color));
to.spigot().sendMessage(builder.create());
}
/**
* Converts an {@link org.bukkit.inventory.ItemStack} to a Json string for
* sending with {@link net.md_5.bungee.api.chat.BaseComponent}'s.
*
* @param itemStack the item to convert
* @return the Json string representation of the item
*/
public String convertItemStackToJson(ItemStack itemStack) {
try {
Class<?> nbtTag = PacketUtils.getNmsClass("NBTTagCompound", "nbt.");
Class<?> craftItemClass = PacketUtils.getObcClass("inventory.CraftItemStack");
Object nmsNbtTagCompoundObj = nbtTag.newInstance();
if (saveMethod == null) {
Object nmsItemStackObj = craftItemClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack);
return nmsItemStackObj.getClass().getMethod("save", nbtTag)
.invoke(nmsItemStackObj, nmsNbtTagCompoundObj).toString();
} else {
Object nmsItemStackObj = craftItemClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack);
return saveMethod.invoke(nmsItemStackObj, nmsNbtTagCompoundObj).toString();
public static void addItem(ComponentBuilder builder, Player to, Player origin, ItemStack item) {
Storage c = ChatItem.getInstance().getStorage();
if (!ItemUtils.isEmpty(item)) {
ComponentBuilder itemComponent = new ComponentBuilder("");
appendToComponentBuilder(itemComponent, fixColorComponent(ChatManager.getNameOfItem(to, item, c), ChatColor.WHITE, item));
ChatItem.debug("Item for " + to.getName() + " (ver: " + ItemPlayer.getPlayer(to).getVersion().name() + ") : " + PacketUtils.getNbtTag(item));
// itemComponent.event(new HoverEvent(Action.SHOW_ITEM, itemBaseComponent));
appendToComponentBuilder(builder, itemComponent.create());
} else {
String handName = c.handName;
ComponentBuilder handComp = new ComponentBuilder("");
ComponentBuilder handTooltip = new ComponentBuilder("");
int stay = c.tooltipHand.size();
for (String line : c.tooltipHand) {
stay--;
handTooltip.append(ColorManager.fixColor(line.replace("{name}", origin.getName()).replace("{display-name}", origin.getDisplayName())));
if (stay > 0)
handTooltip.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
return null;
handComp.event(Utils.createTextHover(handTooltip.create()));
if (handName.contains("{display-name}")) {
String[] splitted = handName.split("\\{display-name\\}");
for (int i = 0; i < (splitted.length - 1); i++) {
handComp.append(splitted[i]);
appendToComponentBuilder(handComp, PlayerNamerManager.getPlayerNamer().getName(origin));
}
handComp.append(splitted[splitted.length - 1]);
} else
handComp.append(handName.replace("{name}", origin.getName()));
appendToComponentBuilder(builder, handComp.create());
}
}
/**
* Get the latest color chat
*
* @param msg the message that contains color
* @return the char of the color or 'r' if nothing found
*/
private char getColorChat(String msg) {
if (msg.length() < 2)
return 'r';
for (int i = msg.length() - 2; i > 0; i--) {
char s = msg.charAt(i);
if (ChatColor.COLOR_CHAR == s) {
return msg.charAt(i + 1);
}
}
return 'r';
}
public static String styleItem(Player p, ItemStack item, Storage c) {
String replacer = c.NAME_FORMAT;
String amount = c.AMOUNT_FORMAT;
if (item.getAmount() == 1) {
if (c.FORCE_ADD_AMOUNT) {
amount = amount.replace(TIMES, "1");
replacer = replacer.replace(AMOUNT, amount);
} else {
replacer = replacer.replace(AMOUNT, "");
public static void appendToComponentBuilder(ComponentBuilder builder, BaseComponent[] comps) {
if (shouldUseAppendMethod) {
try {
builder.append(comps);
} catch (Exception e) {
ChatItem.getInstance().getLogger().severe("This should NEVER append. The ComponentBuilder#append(BaseComponent[]) was found but it's NOT. Using own next time.");
shouldUseAppendMethod = false;
}
} else {
amount = amount.replace(TIMES, String.valueOf(item.getAmount()));
replacer = replacer.replace(AMOUNT, amount);
try {
Field currentField = ReflectionUtils.getField(builder, "current");
List<BaseComponent> parts = (List<BaseComponent>) ReflectionUtils.getObject(builder, "parts");
parts.add(new TextComponent((TextComponent) currentField.get(builder)));
parts.addAll(Arrays.asList(comps));
currentField.set(builder, new TextComponent(""));
} catch (Exception e) {
e.printStackTrace();
}
}
replacer = replacer.replace(NAME, NamerManager.getName(p, item, c));
return replacer;
}
public static BaseComponent[] fixColorComponent(String message, ChatColor color) {
return fixColorComponent(message, color, null);
}
public static BaseComponent[] fixColorComponent(String message, ChatColor color, @Nullable ItemStack item) {
ComponentBuilder builder = new ComponentBuilder("");
String colorCode = "", text = "";
boolean waiting = false;
for (char args : message.toCharArray()) {
if (args == '§') { // begin of color
if (colorCode.isEmpty() && !text.isEmpty()) { // text before this char
ChatItem.debug("Append while fixing name " + (ColorManager.isHexColor(color) && builder.getParts().isEmpty() ? ColorManager.removeColorAtBegin(text) : text));
appendToComponentBuilder(builder, createComponent(ColorManager.isHexColor(color) ? ColorManager.removeColorAtBegin(text) : text, color, item));
text = "";
}
waiting = true; // waiting for color code
} else if (waiting) { // if waiting for code and valid str
// if it's hexademical value and with enough space for full color
waiting = false;
if (args == 'r' && colorCode.isEmpty()) {
color = ChatColor.RESET;
continue;
}
if (args == 'x' && !colorCode.isEmpty()) {
text += ColorManager.getColorString(colorCode);
colorCode = "x";
} else
colorCode += args; // a color by itself
} else {
waiting = false;
if (!colorCode.isEmpty()) {
if (colorCode.startsWith("x") && colorCode.length() >= 7) {
if (colorCode.length() == 7)
color = ColorManager.getColor(colorCode);
else {
color = ColorManager.getColor(colorCode.substring(0, 7)); // only the hex code
ChatItem.debug("Adding color for " + colorCode.substring(7, colorCode.length()) + " (in " + colorCode + ")");
text += ColorManager.getColorString(colorCode.substring(7, colorCode.length()));
}
} else if (colorCode.length() == 1) // if only one color code
color = ColorManager.getColor(colorCode);
else
text += ColorManager.getColorString(colorCode);
ChatItem.debug("Color: " + color + ", text: " + text + ", code: " + colorCode);
colorCode = "";
}
// basic text, not waiting for code after '§'
text += args;
}
}
if (!text.isEmpty()) {
appendToComponentBuilder(builder, createComponent(text, color, item));
}
return builder.create();
}
private static BaseComponent[] createComponent(String text, ChatColor color) {
return createComponent(text, color, null);
}
private static BaseComponent[] createComponent(String text, ChatColor color, ItemStack item) {
ComponentBuilder littleBuilder = new ComponentBuilder(text);
if(color != null && color != ChatColor.RESET) // don't add reset thing
littleBuilder.color(color);
if (item != null) // add to all possible sub parts
littleBuilder.event(Utils.createItemHover(item));
return littleBuilder.create();
}
}
@@ -5,18 +5,14 @@ import org.bukkit.event.HandlerList;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulatorCurrent;
import me.dadus33.chatitem.utils.Storage;
public class ChatListenerChatManager extends ChatManager {
private final JSONManipulatorCurrent jsonManipulator;
private final ChatListener chatListener;
private boolean baseComponentAvailable = true;
public ChatListenerChatManager(ChatItem pl) {
jsonManipulator = new JSONManipulatorCurrent();
chatListener = new ChatListener(this);
//Check for existence of BaseComponent class (only on spigot)
@@ -48,15 +44,6 @@ public class ChatListenerChatManager extends ChatManager {
public void unload(ChatItem pl) {
HandlerList.unregisterAll(chatListener);
}
public JSONManipulator getManipulator(){
/*
We used to have 2 kinds of JSONManipulators because of my bad understanding of the 1.7 way of parsing JSON chat
The interface should however stay as there might be great changes in future versions in JSON parsing (most likely 1.13)
*/
return jsonManipulator;
//We just return a new one whenever requested for the moment, should implement a cache of some sort some time though
}
public boolean supportsChatComponentApi(){
return baseComponentAvailable;
@@ -5,14 +5,18 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.chatmanager.v2.ChatListener;
import me.dadus33.chatitem.listeners.InventoryListener;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.Storage;
@@ -20,50 +24,71 @@ import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
public class ChatItemCommand implements CommandExecutor, TabExecutor {
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if(!(sender instanceof Player)) {
Messages.sendMessage(sender, "only-players");
return false;
}
Player p = (Player) sender;
if(args.length == 0) {
Messages.sendMessage(p, "chatitem-cmd.help");
} else if(args[0].equalsIgnoreCase("admin")) {
InventoryListener.open(p);
} else if(args[0].equalsIgnoreCase("reload")) {
ChatItem.reload(sender);
} else if(args[0].equalsIgnoreCase("link") || args[0].equalsIgnoreCase("links")) {
ConfigurationSection config = ChatItem.getInstance().getConfig().getConfigurationSection("messages.chatitem-cmd.links");
TextComponent text = new TextComponent(Storage.color(config.getString("begin")));
for(String key : config.getConfigurationSection("list").getKeys(false)) {
ConfigurationSection linkConfig = config.getConfigurationSection("list." + key);
TextComponent linkComp = new TextComponent(Storage.color(linkConfig.getString("message")));
String hover = Storage.color(linkConfig.getString("hover"));
if(hover != null)
linkComp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(hover).create()));
String link = linkConfig.getString("link");
if(link != null)
linkComp.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, link));
text.addExtra(linkComp);
}
p.spigot().sendMessage(text);
} else {
Messages.sendMessage(p, "chatitem-cmd.help");
}
return false;
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (!(sender instanceof Player)) {
Messages.sendMessage(sender, "only-players");
return false;
}
Player p = (Player) sender;
if (args.length == 0) {
Messages.sendMessage(p, "chatitem-cmd.help");
} else if (args[0].equalsIgnoreCase("admin")) {
InventoryListener.open(p);
} else if (args[0].equalsIgnoreCase("reload")) {
ChatItem.reload(sender);
} else if (args[0].equalsIgnoreCase("show")) {
Player cible = args.length == 1 ? p : Bukkit.getPlayer(args[1]);
if(cible == null) {
Messages.sendMessage(p, "player-not-found", "%arg%", args[1]);
return false;
}
Storage c = ChatItem.getInstance().getStorage();
ItemStack item = ChatManager.getUsableItem(cible);
ChatListener.showItem(p, cible, item, c.commandFormat.replace("%name%", cible.getName()).replace("%item%", ChatManager.SEPARATOR + ""));
} else if (args[0].equalsIgnoreCase("broadcast")) {
Player cible = args.length == 1 ? p : Bukkit.getPlayer(args[1]);
if(cible == null) {
Messages.sendMessage(p, "player-not-found", "%arg%", args[1]);
return false;
}
Storage c = ChatItem.getInstance().getStorage();
ItemStack item = ChatManager.getUsableItem(cible);
for(Player all : Bukkit.getOnlinePlayers())
ChatListener.showItem(all, cible, item, c.commandFormat.replace("%name%", cible.getName()).replace("%item%", ChatManager.SEPARATOR + ""));
} else if (args[0].equalsIgnoreCase("link") || args[0].equalsIgnoreCase("links")) {
ConfigurationSection config = ChatItem.getInstance().getConfig()
.getConfigurationSection("messages.chatitem-cmd.links");
TextComponent text = new TextComponent(Storage.color(config.getString("begin")));
for (String key : config.getConfigurationSection("list").getKeys(false)) {
ConfigurationSection linkConfig = config.getConfigurationSection("list." + key);
TextComponent linkComp = new TextComponent(Storage.color(linkConfig.getString("message")));
String hover = Storage.color(linkConfig.getString("hover"));
if (hover != null)
linkComp.setHoverEvent(
new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder(hover).create())));
String link = linkConfig.getString("link");
if (link != null)
linkComp.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, link));
text.addExtra(linkComp);
}
p.spigot().sendMessage(text);
} else {
Messages.sendMessage(p, "chatitem-cmd.help");
}
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] arg) {
List<String> list = new ArrayList<>();
String prefix = arg[arg.length - 1].toLowerCase(Locale.ROOT);
for(String s : Arrays.asList("help", "admin", "reload"))
if(prefix.isEmpty() || s.startsWith(prefix))
for (String s : Arrays.asList("help", "admin", "reload", "link", "show", "broadcast"))
if (prefix.isEmpty() || s.startsWith(prefix))
list.add(s);
return list.isEmpty() ? null : list;
}
@@ -1,83 +0,0 @@
package me.dadus33.chatitem.filters;
import static org.apache.logging.log4j.core.Filter.Result.NEUTRAL;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.message.Message;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.chatmanager.v2.ChatListener;
import me.dadus33.chatitem.utils.Storage;
public class Log4jFilter implements Filter {
private Storage c;
public Log4jFilter(Storage st){
c = st;
((Logger) LogManager.getRootLogger()).addFilter(this);
}
@Override
public Result getOnMismatch() {
return NEUTRAL;
}
@Override
public Result getOnMatch() {
return NEUTRAL;
}
@Override
public Result filter(Logger logger, Level level, Marker marker, String s, Object... objects) {
return checkMessage(s);
}
@Override
public Result filter(Logger logger, Level level, Marker marker, Object o, Throwable throwable) {
return checkMessage(((Message)o).getFormattedMessage());
}
@Override
public Result filter(Logger logger, Level level, Marker marker, Message message, Throwable throwable) {
return checkMessage(message.getFormattedMessage());
}
@Override
public Result filter(LogEvent logEvent) {
return checkMessage(logEvent.getMessage().getFormattedMessage());
}
public void stop() {
// seems to be required
}
private Result checkMessage(String msg){
if(msg==null){
return Result.NEUTRAL;
}
for(String placeholder : c.PLACEHOLDERS){
if(msg.contains(placeholder)){
for(Player p : Bukkit.getOnlinePlayers()){
if(msg.contains(ChatListener.SEPARATOR +p.getName())){
return Result.DENY;
}
}
}
}
return Result.NEUTRAL;
}
public void setStorage(Storage nst){
this.c = nst;
}
}
@@ -0,0 +1,17 @@
package me.dadus33.chatitem.hook;
import org.bukkit.entity.Player;
import github.scarsz.discordsrv.DiscordSRV;
public class DiscordSrvSupport {
@SuppressWarnings("deprecation")
public static void sendChatMessage(Player p, String message) {
DiscordSRV pl = DiscordSRV.getPlugin();
if (DiscordSRV.config().getBooleanElse("UseModernPaperChatEvent", false) && pl.isModernChatEventAvailable()) {
return;
}
pl.processChatMessage(p, message, pl.getOptionalChannel("global"), false);
}
}
@@ -30,7 +30,7 @@ public interface INamer {
*/
String getName(Player p, ItemStack item, Storage storage);
public static enum Priority {
enum Priority {
MAJOR(4),
IMPORTANT(3),
MEDIUM(2),
@@ -39,7 +39,7 @@ public interface INamer {
private final int priority;
private Priority(int priority) {
Priority(int priority) {
this.priority = priority;
}
@@ -48,7 +48,7 @@ public interface INamer {
}
public static List<Priority> getOrderedPriorities() {
return Arrays.asList(values()).stream().sorted((p1, p2) -> p2.getPriority() - p1.getPriority()).collect(Collectors.toList());
return Arrays.stream(values()).sorted((p1, p2) -> p2.getPriority() - p1.getPriority()).collect(Collectors.toList());
}
}
}
@@ -56,8 +56,9 @@ public class NamerManager {
/**
* Get the name of this item, according to this storage.
*
* @param item
* @param storage
* @param p the player that will see the name
* @param item the item to show
* @param storage the storage
* @return the name (should NOT return null)
*/
public static String getName(Player p, ItemStack item, Storage storage) {
@@ -17,13 +17,11 @@ public class ChatItemTranslationNamer implements INamer {
@Override
public String getName(Player p, ItemStack item, Storage storage) {
HashMap<Short, String> translationSection = storage.TRANSLATIONS.get(item.getType().name());
HashMap<Short, String> translationSection = storage.translations.get(item.getType().name());
if (translationSection != null) {
@SuppressWarnings("deprecation")
String translated = translationSection.get(item.getDurability());
if (translated != null) {
return translated;
}
return translated;
}
return null;
}
@@ -18,7 +18,7 @@ public class ItemDisplayNamer implements INamer {
public String getName(Player p, ItemStack item, Storage storage) {
if(item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
String name = item.getItemMeta().getDisplayName();
return storage.COLOR_IF_ALREADY_COLORED ? ChatColor.stripColor(name) : name;
return storage.colorIfColored ? ChatColor.stripColor(name) : name;
}
return null;
}
@@ -42,27 +42,33 @@ public class InventoryListener implements Listener {
ChatItem.reload(p);
}
} else if(type.equals(ItemUtils.INK_SAC)) {
setInConfig("general.color-if-already-colored", c.COLOR_IF_ALREADY_COLORED = !c.COLOR_IF_ALREADY_COLORED);
setInConfig("general.color-if-already-colored", c.colorIfColored = !c.colorIfColored);
open(p);
} else if(type.equals(Material.REDSTONE)) {
setInConfig("general.deny-if-no-item", c.DENY_IF_NO_ITEM = !c.DENY_IF_NO_ITEM);
setInConfig("general.deny-if-no-item", c.denyIfNoItem = !c.denyIfNoItem);
open(p);
} else if(type.equals(Material.STICK)) {
setInConfig("general.hand.disabled", c.HAND_DISABLED = !c.HAND_DISABLED);
setInConfig("general.hand.disabled", c.handDisabled = !c.handDisabled);
open(p);
} else if(type.equals(Material.BOOK)) {
setInConfig("general.check-update", c.checkUpdate = !c.checkUpdate);
open(p);
} else if(type.equals(ItemUtils.FIREWORK_CHARGE)) {
setInConfig("debug", c.debug = !c.debug);
open(p);
} else if(type.equals(Material.IRON_DOOR)) {
if(e.getClick().equals(ClickType.RIGHT))
c.LIMIT--;
c.limit--;
else if(e.getClick().equals(ClickType.LEFT))
c.LIMIT++;
setInConfig("general.limit-per-message", c.LIMIT);
c.limit++;
setInConfig("general.limit-per-message", c.limit);
open(p);
} else if(type.equals(Material.APPLE)) {
if(e.getClick().equals(ClickType.RIGHT))
c.COOLDOWN--;
c.cooldown--;
else if(e.getClick().equals(ClickType.LEFT))
c.COOLDOWN++;
setInConfig("general.cooldown", c.COOLDOWN);
c.cooldown++;
setInConfig("general.cooldown", c.cooldown);
open(p);
}
}
@@ -85,13 +91,16 @@ public class InventoryListener implements Listener {
holder.keyBySlot.put(slot, manager);
inv.setItem(slot++, getManagerItem(manager));
}
inv.setItem(slot + 1, getManagerItem("actual", "%manager%", Messages.getMessage("admin-inv.manager." + c.MANAGER + ".name")));
inv.setItem(slot + 1, getManagerItem("actual", "%manager%", Messages.getMessage("admin-inv.manager." + c.manager + ".name")));
inv.setItem(8, getBoolChangeItem(ItemUtils.FIREWORK_CHARGE, "debug", c.debug));
inv.setItem(18, getBoolChangeItem(ItemUtils.INK_SAC, "color-if-already-colored", c.COLOR_IF_ALREADY_COLORED));
inv.setItem(19, getBoolChangeItem(Material.REDSTONE, "deny-no-item", c.DENY_IF_NO_ITEM));
inv.setItem(20, getBoolChangeItem(Material.STICK, "hand-disabled", c.HAND_DISABLED));
inv.setItem(21, getAmountChangeItem(Material.IRON_DOOR, "limit-per-message", c.LIMIT));
inv.setItem(22, getAmountChangeItem(Material.APPLE, "cooldown", c.COOLDOWN));
inv.setItem(18, getBoolChangeItem(ItemUtils.INK_SAC, "color-if-already-colored", c.colorIfColored));
inv.setItem(19, getBoolChangeItem(Material.REDSTONE, "deny-no-item", c.denyIfNoItem));
inv.setItem(20, getBoolChangeItem(Material.STICK, "hand-disabled", c.handDisabled));
inv.setItem(21, getAmountChangeItem(Material.IRON_DOOR, "limit-per-message", c.limit));
inv.setItem(22, getAmountChangeItem(Material.APPLE, "cooldown", c.cooldown));
inv.setItem(23, getBoolChangeItem(Material.BOOK, "check-update", c.checkUpdate));
inv.setItem(26, createItem(ItemUtils.MATERIAL_CLOSE, Messages.getMessage("admin-inv.close")));
p.openInventory(inv);
@@ -4,16 +4,18 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
public class JoinListener implements Listener {
@SuppressWarnings("deprecation")
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player p = e.getPlayer();
@@ -21,10 +23,15 @@ public class JoinListener implements Listener {
return;
ChatItem pl = ChatItem.getInstance();
if(pl.isHasNewVersion()) {
TextComponent text = new TextComponent(pl.getStorage().JOIN_UPDATE_MESSAGE);
text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(pl.getStorage().JOIN_UPDATE_HOVER).create()));
TextComponent text = new TextComponent(pl.getStorage().updateMessage);
text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(new ComponentBuilder(pl.getStorage().updateHover).create())));
text.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.spigotmc.org/resources/19064/"));
p.spigot().sendMessage(text);
}
}
@EventHandler
public void onLeft(PlayerQuitEvent e) {
ChatManager.clear(e.getPlayer());
}
}
@@ -1,4 +1,4 @@
package me.dadus33.chatitem.chatmanager.v1.playerversion;
package me.dadus33.chatitem.playerversion;
import org.bukkit.entity.Player;
@@ -9,6 +9,6 @@ public interface IPlayerVersion {
public int getProtocolVersion(Player p);
default Version getPlayerVersion(Player p) {
return Version.getVersion(getProtocolVersion(p));
return Version.getVersion(getProtocolVersion(p), Version.getVersion());
}
}
@@ -0,0 +1,29 @@
package me.dadus33.chatitem.playerversion;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.playerversion.hooks.ProtocolSupportHook;
import me.dadus33.chatitem.playerversion.hooks.ViaVersionHook;
import org.bukkit.Bukkit;
public class PlayerVersionManager {
private static final IPlayerVersion playerVersionAdapter;
static {
ChatItem pl = ChatItem.getInstance();
if (Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null) {
playerVersionAdapter = new ProtocolSupportHook();
pl.getLogger().info("Loading ProtocolSupport support ...");
} else if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) {
playerVersionAdapter = new ViaVersionHook();
pl.getLogger().info("Loading ViaVersion support ...");
} else {
playerVersionAdapter = new DefaultVersionHook();
}
}
public static IPlayerVersion getPlayerVersionAdapter() {
return playerVersionAdapter;
}
}
@@ -1,22 +1,18 @@
package me.dadus33.chatitem.chatmanager.v1.playerversion.hooks;
package me.dadus33.chatitem.playerversion.hooks;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.chatmanager.v1.playerversion.IPlayerVersion;
import me.dadus33.chatitem.playerversion.IPlayerVersion;
import me.dadus33.chatitem.utils.Version;
public class DefaultVersionHook implements IPlayerVersion {
public static final HashMap<String, Integer> PROTOCOL_PER_ADDRESS = new HashMap<>();
public static final HashMap<UUID, Integer> PROTOCOL_PER_UUID = new HashMap<>();
@Override
public int getProtocolVersion(Player p) {
if(PROTOCOL_PER_UUID.containsKey(p.getUniqueId()))
return PROTOCOL_PER_UUID.get(p.getUniqueId());
return PROTOCOL_PER_ADDRESS.getOrDefault(Version.stringifyAdress(p.getAddress()), Version.getVersion().MAX_VER);
}
}
@@ -1,8 +1,8 @@
package me.dadus33.chatitem.chatmanager.v1.playerversion.hooks;
package me.dadus33.chatitem.playerversion.hooks;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.chatmanager.v1.playerversion.IPlayerVersion;
import me.dadus33.chatitem.playerversion.IPlayerVersion;
import protocolsupport.api.ProtocolSupportAPI;
public class ProtocolSupportHook implements IPlayerVersion {
@@ -1,9 +1,10 @@
package me.dadus33.chatitem.chatmanager.v1.playerversion.hooks;
package me.dadus33.chatitem.playerversion.hooks;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.chatmanager.v1.playerversion.IPlayerVersion;
import us.myles.ViaVersion.api.Via;
import com.viaversion.viaversion.api.Via;
import me.dadus33.chatitem.playerversion.IPlayerVersion;
public class ViaVersionHook implements IPlayerVersion {
@@ -1,52 +1,121 @@
package me.dadus33.chatitem.utils;
import java.util.Arrays;
import java.util.List;
import me.dadus33.chatitem.ChatItem;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
public class ColorManager {
public static BaseComponent[] getChatWithHex(String msg) {
ChatItem.debug("Converting " + msg);
ComponentBuilder builder = new ComponentBuilder();
ChatColor color = ChatColor.WHITE;
String colorCode = "", text = "";
boolean waiting = false;
for(char c : msg.toCharArray()) {
if(c == '§') { // begin of color
if(colorCode.isEmpty() && !text.isEmpty()) { // text before this char
ChatItem.debug("Append " + text);
builder.append(new ComponentBuilder(text).color(color).create());
text = "";
}
waiting = true; // waiting for color code
} else if(waiting) { // if waiting for code and valid str
if(String.valueOf(c).matches("-?[0-9a-fA-F]+") && colorCode.length() <= 5) { // if it's hexademical value and with enough space for full color
colorCode += c; // add char to it
waiting = false;
} else {
color = ChatColor.getByChar(c); // a color by itself
colorCode = ""; // clean actual code, it's only to prevent some kind of issue
waiting = false;
}
} else {
if(!colorCode.isEmpty()) {
color = getColor(colorCode);
}
// basic text, not waiting for code after '§'
text += c;
colorCode = ""; // clean actual code
waiting = false;
}
}
if(!text.isEmpty())
builder.append(new ComponentBuilder(text).color(color).create()); // add last char
return builder.create();
public static final List<String> COLORS = Arrays.asList("4", "c", "6", "e", "2", "a", "b", "3", "1", "9", "d", "5", "f", "7", "8", "0");
public static boolean isHexColor(ChatColor c) {
return Version.getVersion().isNewerOrEquals(Version.V1_16) && c.getName().startsWith("#");
}
private static ChatColor getColor(String input) {
return input.isEmpty() ? ChatColor.WHITE : (input.length() == 1 ? ChatColor.getByChar(input.charAt(0)) : ChatColor.of("#" + input));
public static boolean isHexColor(String c) {
return Version.getVersion().isNewerOrEquals(Version.V1_16) && c.startsWith("x");
}
public static String removeColorAtBegin(String s) {
if(s == null || s.isEmpty())
return "";
boolean wasColorChar = s.startsWith(Character.toString(ChatColor.COLOR_CHAR));
if(!wasColorChar)
return s;
String next = "";
for(int i = 1; i < s.length(); i++) {
char c = s.charAt(i);
if(wasColorChar) {
if(!COLORS.contains(Character.toString(c)))
next = next + ChatColor.COLOR_CHAR + "" + c;
wasColorChar = false;
} else {
wasColorChar = c == ChatColor.COLOR_CHAR;
if(!wasColorChar) { // something other than color code
next += s.substring(i);
break;
}
}
}
if(next.isEmpty())
next = s;
return next;
}
public static String getColorString(String input) {
if (input == null || input.isEmpty())
return "";
StringBuilder str = new StringBuilder();
if (isHexColor(input)) { // x mean it's an hex
input = input.substring(1);
if (input.length() >= 6) { // at least hex
str.append(ChatColor.of("#" + input.substring(0, 6))); // get first hex color code
ChatItem.debug("Str with hex: " + str);
if (input.length() > 6) // if as another color code
str.append(getColorString(input.substring(6))); // get color for after
return str.toString();
} else
ChatItem.debug("Low len: " + input.length());
}
// not hex
for (char c : input.toCharArray())
str.append(ChatColor.getByChar(c));
return str.toString();
}
public static ChatColor getColor(String input) {
if (input == null || input.isEmpty())
return ChatColor.RESET;
if (isHexColor(input)) { // x mean it's an hex
if (input.length() >= 7) { // at least hex, and 7 because we count the "x"
return ChatColor.of("#" + input.substring(1, 7)); // get first hex color code
} else
ChatItem.debug("Low len: " + input.length());
}
// not hex
return ChatColor.getByChar(input.charAt(0));
}
public static String fixColor(String message) {
String colorCode = "", text = "";
boolean waiting = false;
for (char args : message.toCharArray()) {
if (args == '§') { // begin of color
waiting = true; // waiting for color code
} else if (waiting) { // if waiting for code and valid str
// if it's hexademical value and with enough space for full color
waiting = false;
if (args == 'r' && colorCode.isEmpty()) {
text += ChatColor.RESET;
continue;
}
if (args == 'x' && !colorCode.isEmpty()) {
text += ColorManager.getColorString(colorCode);
colorCode = "x";
} else if(Character.digit(Character.toLowerCase(args), 16) != -1)
colorCode += args; // a color by itself
} else {
waiting = false;
if (!colorCode.isEmpty()) {
if (isHexColor(colorCode) && colorCode.length() >= 7) {
if (colorCode.length() == 7)
text += ColorManager.getColor(colorCode);
else {
text += ColorManager.getColor(colorCode.substring(0, 7)); // only the hex code
text += ColorManager.getColorString(colorCode.substring(7, colorCode.length()));
}
} else if (colorCode.length() == 1) // if only one color code
text += ColorManager.getColor(colorCode);
else
text += ColorManager.getColorString(colorCode);
colorCode = "";
}
// basic text, not waiting for code after '§'
text += args;
}
}
return text;
}
}
@@ -19,6 +19,7 @@ public class ItemUtils {
public static final Material WEB = getMaterialWithCompatibility("WEB", "COBWEB");
public static final Material FIREBALL = getMaterialWithCompatibility("FIREBALL", "FIRE_CHARGE");
public static final Material INK_SAC = getMaterialWithCompatibility("INK_SAC", "INK_SACK", "DYE", "GRAY_DYE");
public static final Material FIREWORK_CHARGE = getMaterialWithCompatibility("FIREWORK_CHARGE", "FIRE_CHARGE");
public static final Material BIRCH_WOOD_STAIRS = getMaterialWithCompatibility("BIRCH_WOOD_STAIRS", "BIRCH_STAIRS");
@@ -84,4 +85,8 @@ public class ItemUtils {
}
return stack;
}
public static boolean isEmpty(ItemStack item) {
return item == null || item.getType().equals(Material.AIR);
}
}
@@ -18,7 +18,6 @@ public class Messages {
return colorAndPlaceholders(ChatItem.getInstance().getConfig().getString("messages." + key, key), placeholders);
}
@SuppressWarnings("unchecked")
public static List<String> getMessageList(String key, Object... placeholders) {
Object obj = ChatItem.getInstance().getConfig().get("messages." + key);
if(obj == null)
@@ -6,6 +6,9 @@ import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
public class PacketUtils {
@@ -14,88 +17,91 @@ public class PacketUtils {
public static final String NMS_PREFIX;
public static final String OBC_PREFIX;
public static final boolean IS_THERMOS;
public static final Class<?> CRAFT_PLAYER_CLASS, CRAFT_SERVER_CLASS, CHAT_SERIALIZER, COMPONENT_CLASS;
public static final Class<?> CHAT_SERIALIZER, COMPONENT_CLASS;
/**
* This Map is to reduce Reflection action which take more resources than just RAM action
* This Map is to reduce Reflection action which take more resources than just
* RAM action
*/
private static final Map<String, Class<?>> ALL_CLASS = Collections.synchronizedMap(new HashMap<String, Class<?>>());
static {
IS_THERMOS = isClassExist("thermos.Thermos");
NMS_PREFIX = Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? "net.minecraft." : "net.minecraft.server." + VERSION + ".";
NMS_PREFIX = Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? "net.minecraft."
: "net.minecraft.server." + VERSION + ".";
OBC_PREFIX = "org.bukkit.craftbukkit." + VERSION + ".";
CRAFT_PLAYER_CLASS = getObcClass("entity.CraftPlayer");
CHAT_SERIALIZER = getNmsClass("IChatBaseComponent$ChatSerializer", "network.chat.", "ChatSerializer");
COMPONENT_CLASS = getNmsClass("IChatBaseComponent", "network.chat.");
CRAFT_SERVER_CLASS = getObcClass("CraftServer");
}
/**
* Get the Class in NMS, with a processing reducer
*
* @param name of the NMS class (in net.minecraft.server package ONLY, because it's NMS)
* @param name of the NMS class (in net.minecraft.server package ONLY, because
* it's NMS)
* @return clazz the searched class
*/
public static Class<?> getNmsClass(String name, String packagePrefix, String... alias){
public static Class<?> getNmsClass(String name, String packagePrefix, String... alias) {
return ALL_CLASS.computeIfAbsent(name, (a) -> {
String fullPrefix = NMS_PREFIX + (Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? packagePrefix : "");
String fullPrefix = NMS_PREFIX
+ (Version.getVersion().isNewerOrEquals(Version.V1_17) || IS_THERMOS ? packagePrefix : "");
try {
Class<?> clazz = Class.forName(fullPrefix + name);
if(clazz != null)
if (clazz != null)
return clazz;
} catch (ClassNotFoundException e) {
if(alias.length == 0)
if (alias.length == 0)
e.printStackTrace(); // no alias, print error
// else ignore and go check for alias
}
for(String className : alias) {
for (String className : alias) {
try {
Class<?> clazz = Class.forName(fullPrefix + className);
if(clazz != null)
if (clazz != null)
return clazz;
} catch (ClassNotFoundException e) {
if(className == alias[alias.length - 1]) // if it's last alias, print error
if (className == alias[alias.length - 1]) // if it's last alias, print error
e.printStackTrace();
}
}
return null;
});
}
/**
* Get the Class in NMS, with a processing reducer
*
* @param name of the NMS class (in net.minecraft.server package ONLY, because it's NMS)
* @param name of the NMS class (in net.minecraft.server package ONLY, because
* it's NMS)
* @return clazz the searched class
*/
public static Class<?> getObcClass(String name, String... alias){
public static Class<?> getObcClass(String name, String... alias) {
return ALL_CLASS.computeIfAbsent(name, (a) -> {
try {
Class<?> clazz = Class.forName(OBC_PREFIX + name);
if(clazz != null)
if (clazz != null)
return clazz;
} catch (ClassNotFoundException e) {
if(alias.length == 0)
if (alias.length == 0)
e.printStackTrace(); // no alias, print error
// else ignore and go check for alias
}
for(String className : alias) {
for (String className : alias) {
try {
Class<?> clazz = Class.forName(OBC_PREFIX + className);
if(clazz != null)
if (clazz != null)
return clazz;
} catch (ClassNotFoundException e) {
if(className == alias[alias.length - 1]) // if it's last alias, print error
if (className == alias[alias.length - 1]) // if it's last alias, print error
e.printStackTrace();
}
}
return null;
});
}
/**
* Get NMS entity player of specified one
*
@@ -104,14 +110,13 @@ public class PacketUtils {
*/
public static Object getEntityPlayer(Player p) {
try {
Object craftPlayer = CRAFT_PLAYER_CLASS.cast(p);
return craftPlayer.getClass().getMethod("getHandle").invoke(craftPlayer);
return getObcClass("entity.CraftPlayer").getMethod("getHandle").invoke(p);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static boolean isClassExist(String name) {
try {
Class.forName(name);
@@ -130,7 +135,7 @@ public class PacketUtils {
public static Object getPlayerConnection(Player p) {
try {
Object entityPlayer = getEntityPlayer(p);
if(Version.getVersion().isNewerOrEquals(Version.V1_17))
if (Version.getVersion().isNewerOrEquals(Version.V1_17))
return entityPlayer.getClass().getField("b").get(entityPlayer);
else
return entityPlayer.getClass().getField("playerConnection").get(entityPlayer);
@@ -139,7 +144,7 @@ public class PacketUtils {
return null;
}
}
/**
* Get NMS entity player of specified one
*
@@ -148,8 +153,7 @@ public class PacketUtils {
*/
public static Object getCraftServer() {
try {
Object craftServer = CRAFT_SERVER_CLASS.cast(Bukkit.getServer());
return craftServer.getClass().getMethod("getHandle").invoke(craftServer);
return getObcClass("CraftServer").getMethod("getHandle").invoke(Bukkit.getServer());
} catch (Exception e) {
e.printStackTrace();
return null;
@@ -159,15 +163,39 @@ public class PacketUtils {
/**
* Send the packet to the specified player
*
* @param p which will receive the packet
* @param p which will receive the packet
* @param packet the packet to sent
*/
public static void sendPacket(Player p, Object packet) {
try {
Object playerConnection = getPlayerConnection(p);
playerConnection.getClass().getMethod(Version.getVersion().isNewerOrEquals(Version.V1_18) ? "a" : "sendPacket", getNmsClass("Packet", "network.protocol.")).invoke(playerConnection, packet);
playerConnection.getClass()
.getMethod(Version.getVersion().isNewerOrEquals(Version.V1_18) ? "a" : "sendPacket",
getNmsClass("Packet", "network.protocol."))
.invoke(playerConnection, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Converts an {@link org.bukkit.inventory.ItemStack} to a Json string for
* sending with {@link net.md_5.bungee.api.chat.BaseComponent}'s.
*
* @param item the item to convert
* @return the Json string representation of the item
*/
public static String getNbtTag(ItemStack item) {
try {
Object nmsStack = JSONManipulator.AS_NMS_COPY.invoke(null, item);
Version v = Version.getVersion();
Object tag = getNmsClass("ItemStack", "world.item.")
.getMethod(v.equals(Version.V1_18) ? "t" : (v.isNewerOrEquals(Version.V1_19) ? "u" : "getTag"))
.invoke(nmsStack);
return tag == null ? "{}" : tag.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "{}";
}
}
@@ -1,56 +0,0 @@
package me.dadus33.chatitem.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import me.dadus33.chatitem.ChatItem;
public class Reflect {
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... params) {
try {
return clazz.getMethod(methodName, params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Method getMethod(Class<?> clazz, Class<?> returned, Class<?>... params) {
try {
for(Method m : clazz.getDeclaredMethods()) {
if(returned.equals(m.getReturnType()) && areParamsEquals(m.getParameterTypes(), params))
return m;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static boolean areParamsEquals(Class<?>[] p1, Class<?>[] p2) {
if(p1.length != p2.length)
return false;
for(int i = 0; i < p1.length; i++) {
if(!p1[i].equals(p2[i]))
return false;
}
return true;
}
public static Field getField(Class<?> clazz, String... fieldNames){
for(String field : fieldNames) {
try{
Field f = clazz.getDeclaredField(field);
f.setAccessible(true);
return f;
} catch (NoSuchFieldException e) {
// go to next
}
}
ChatItem.getInstance().getLogger().severe("Failed to find field: " + Arrays.asList(fieldNames) + " in class: " + clazz.getCanonicalName());
return null;
}
}
@@ -1,8 +1,58 @@
package me.dadus33.chatitem.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import me.dadus33.chatitem.ChatItem;
public class ReflectionUtils {
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... params) {
try {
return clazz.getMethod(methodName, params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Method getMethod(Class<?> clazz, Class<?> returned, Class<?>... params) {
try {
for(Method m : clazz.getDeclaredMethods()) {
if(returned.equals(m.getReturnType()) && areParamsEquals(m.getParameterTypes(), params))
return m;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static boolean areParamsEquals(Class<?>[] p1, Class<?>[] p2) {
if(p1.length != p2.length)
return false;
for(int i = 0; i < p1.length; i++) {
if(!p1[i].equals(p2[i]))
return false;
}
return true;
}
public static Field getField(Class<?> clazz, String... fieldNames){
for(String field : fieldNames) {
try{
Field f = clazz.getDeclaredField(field);
f.setAccessible(true);
return f;
} catch (NoSuchFieldException e) {
// go to next
}
}
ChatItem.getInstance().getLogger().severe("Failed to find field: " + Arrays.asList(fieldNames) + " in class: " + clazz.getCanonicalName());
return null;
}
public static Object getPrivateField(Object object, String field)
throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
@@ -21,6 +71,31 @@ public class ReflectionUtils {
}
}
/**
* Get the specified field name in the object source
*
* @param source where we will find the field
* @param field the name of the field
* @return the requested object of the field
*/
public static Object getObject(Object source, String... field) {
try {
for(String fieldName : field) {
try {
Field f = source.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
return f.get(source);
} catch (NoSuchFieldException e) {
// ignore because going to next item
}
}
ChatItem.getInstance().getLogger().severe("Failed to find fields: " + String.join(", ", field) + " in " + source.getClass().getSimpleName());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Get the specified field name in the object source
*
@@ -28,11 +103,11 @@ public class ReflectionUtils {
* @param field the name of the field
* @return the requested field
*/
public static Object getField(Object source, String field) {
public static Field getField(Object source, String field) {
try {
Field f = source.getClass().getDeclaredField(field);
f.setAccessible(true);
return f.get(source);
return f;
} catch (Exception e) {
e.printStackTrace();
return null;
@@ -55,6 +130,25 @@ public class ReflectionUtils {
}
}
/**
* Get the first object which have the searching for class type
*
* @param from the object where we will try to find the field
* @param clazz the class that have to define the field
* @param searchingFor the class of the required field
* @return the field (or null if not found)
* @throws Exception if something gone wrong
*/
public static <T> T getFirstWith(Object from, Class<?> clazz, Class<T> searchingFor) throws Exception {
for (Field f : clazz.getDeclaredFields()) {
if (f.getType().equals(searchingFor) && !Modifier.isStatic(f.getModifiers())) {
f.setAccessible(true);
return (T) f.get(from);
}
}
return null;
}
/**
* Get the first field which have the searching for class type
*
@@ -64,12 +158,11 @@ public class ReflectionUtils {
* @return the field (or null if not found)
* @throws Exception if something gone wrong
*/
@SuppressWarnings("unchecked")
public static <T> T getFirstWith(Object from, Class<?> clazz, Class<T> searchingFor) throws Exception {
public static Field getFirstFieldWith(Class<?> clazz, Class<?> searchingFor) throws Exception {
for (Field f : clazz.getDeclaredFields()) {
if (f.getType().equals(searchingFor)) {
if (f.getType().equals(searchingFor) && !Modifier.isStatic(f.getModifiers())) {
f.setAccessible(true);
return (T) f.get(from);
return f;
}
}
return null;
@@ -1,13 +1,11 @@
package me.dadus33.chatitem.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.configuration.file.FileConfiguration;
import com.google.common.collect.ImmutableList;
@@ -16,105 +14,95 @@ import me.dadus33.chatitem.ChatItem;
public class Storage {
private FileConfiguration conf;
public final HashMap<String, HashMap<Short, String>> TRANSLATIONS = new HashMap<>();
public boolean COLOR_IF_ALREADY_COLORED, FORCE_ADD_AMOUNT, LET_MESSAGE_THROUGH, DENY_IF_NO_ITEM,
HAND_DISABLED, SHOW_NO_PERM_NORMAL, CHECK_UPDATE, SHOW_NO_PERM_COMMAND, PERMISSION_ENABLED;
public final String HAND_NAME, NAME_FORMAT, AMOUNT_FORMAT, MANAGER, PERMISSION_NAME;
public final String NO_PERMISSION_MESSAGE, DENY_MESSAGE, RELOAD_MESSAGE, COOLDOWN_MESSAGE, LIMIT_MESSAGE;
public final String SECONDS, MINUTES, HOURS;
public final String JOIN_UPDATE_MESSAGE, JOIN_UPDATE_HOVER;
public int CONFIG_VERSION, LIMIT, COOLDOWN;
public final List<Command> ALLOWED_PLUGIN_COMMANDS = new ArrayList<>();
public final List<String> ALLOWED_DEFAULT_COMMANDS = new ArrayList<>();
public final List<String> PLACEHOLDERS, HAND_TOOLTIP;
public final HashMap<String, HashMap<Short, String>> translations = new HashMap<>();
public final String handName, nameFormat, amountFormat, commandFormat, manager, permissionName, buggedClientAction;
public final String messageNoPermission, messageDeny, messageReload, messageCooldown, messageLimit;
public final String SECONDS, minutes, hours;
public final String updateMessage, updateHover;
public final List<String> placeholders, tooltipHand, tooltipBuggedClient;
public boolean colorIfColored, addAmountForced, letMessageThrough, denyIfNoItem, debug,
handDisabled, showNoPermissionMessage, checkUpdate, permissionEnabled;
public int configVersion, limit, cooldown;
private FileConfiguration conf;
public Storage(FileConfiguration cnf) {
this.conf = cnf;
CONFIG_VERSION = conf.getInt("config-version", 13);
checkConfigVersion();
this.MANAGER = conf.getString("manager", "auto");
Set<String> keys = conf.getConfigurationSection("translations").getKeys(false);
for (String key : keys) {
HashMap<Short, String> entry = new HashMap<>();
Set<String> subKeys = conf.getConfigurationSection("translations.".concat(key)).getKeys(false);
for (String subKey : subKeys) {
entry.put(Short.parseShort(subKey),
color(conf.getString("translations.".concat(key).concat(".").concat(subKey))));
}
public Storage(FileConfiguration cnf) {
this.conf = cnf;
configVersion = conf.getInt("config-version", 13);
checkConfigVersion();
this.manager = conf.getString("manager", "auto");
Set<String> keys = conf.getConfigurationSection("translations").getKeys(false);
for (String key : keys) {
HashMap<Short, String> entry = new HashMap<>();
Set<String> subKeys = conf.getConfigurationSection("translations.".concat(key)).getKeys(false);
for (String subKey : subKeys) {
entry.put(Short.parseShort(subKey),
color(conf.getString("translations.".concat(key).concat(".").concat(subKey))));
}
TRANSLATIONS.put(key, entry);
}
PLACEHOLDERS = ImmutableList.copyOf(conf.getStringList("general.placeholders"));
NAME_FORMAT = color(conf.getString("general.name-format", "&b&l&o{name} {amount}&r"));
AMOUNT_FORMAT = color(conf.getString("general.amount-format", "x{times}"));
COLOR_IF_ALREADY_COLORED = conf.getBoolean("general.color-if-already-colored", true);
LET_MESSAGE_THROUGH = conf.getBoolean("general.let-message-through", true);
FORCE_ADD_AMOUNT = conf.getBoolean("general.force-add-amount", true);
DENY_IF_NO_ITEM = conf.getBoolean("general.deny-if-no-item", false);
LIMIT = conf.getInt("general.limit", 8);
COOLDOWN = conf.getInt("general.cooldown", 60);
SHOW_NO_PERM_NORMAL = conf.getBoolean("general.show-no-permission-message.normal", true);
SHOW_NO_PERM_COMMAND = conf.getBoolean("general.show-no-permission-message.command", false);
PERMISSION_ENABLED = conf.getBoolean("general.permission.enabled", false);
PERMISSION_NAME = conf.getString("general.permission.name", "chatitem.use");
HAND_DISABLED = conf.getBoolean("general.hand.disabled", false);
HAND_NAME = color(conf.getString("general.hand.name", "&b&l&o{display-name}&b&l&o's hand"));
HAND_TOOLTIP = conf.getStringList("general.hand.tooltip");
CHECK_UPDATE = conf.getBoolean("general.check-update", true);
DENY_MESSAGE = color(conf.getString("messages.deny-message", "&c&lYou have no item in hand!"));
RELOAD_MESSAGE = color(conf.getString("messages.reload-success", "&b&lSuccessful reload!"));
NO_PERMISSION_MESSAGE = color(conf.getString("messages.no-permission",
"&c&lI'm sorry, but you are not allowed to use the placeholder in chat!"));
COOLDOWN_MESSAGE = color(conf.getString("messages.cooldown-message",
"&c&lYou can only use items in chat once a minute! You have {remaining} left!"));
JOIN_UPDATE_MESSAGE = color(conf.getString("messages.join-update.message",
"&cA new version of ChatItem is available. &aClick here to download."));
JOIN_UPDATE_HOVER = color(conf.getString("messages.join-update.hover", "&6Click to go to spigot page !"));
LIMIT_MESSAGE = color(conf.getString("messages.limit-message", "&c&lYou can only add 8 item placeholders per message!"));
SECONDS = color(conf.getString("messages.seconds", " seconds"));
MINUTES = color(conf.getString("messages.minutes", " minutes"));
HOURS = color(conf.getString("messages.hours", " hours"));
colorStringList(HAND_TOOLTIP);
final List<String> cmds = conf.getStringList("general.commands");
Bukkit.getScheduler().runTaskLaterAsynchronously(ChatItem.getInstance(), () -> {
for (String s : cmds) {
Command c = Bukkit.getPluginCommand(s);
if (c != null) {
ALLOWED_PLUGIN_COMMANDS.add(c);
} else {
ALLOWED_DEFAULT_COMMANDS.add(s);
}
}
}, 100L);
translations.put(key, entry);
}
debug = conf.getBoolean("debug", false);
placeholders = ImmutableList.copyOf(conf.getStringList("general.placeholders"));
nameFormat = color(conf.getString("general.name-format", "&b&l&o{name} {amount}&r"));
amountFormat = color(conf.getString("general.amount-format", "x{times}"));
commandFormat = color(conf.getString("general.command-format", "&6%name%'s item is %item%"));
colorIfColored = conf.getBoolean("general.color-if-already-colored", true);
letMessageThrough = conf.getBoolean("general.let-message-through", true);
addAmountForced = conf.getBoolean("general.force-add-amount", true);
denyIfNoItem = conf.getBoolean("general.deny-if-no-item", false);
limit = conf.getInt("general.limit", 8);
cooldown = conf.getInt("general.cooldown", 60);
showNoPermissionMessage = conf.getBoolean("general.show-no-permission-message.normal", true);
permissionEnabled = conf.getBoolean("general.permission.enabled", false);
permissionName = conf.getString("general.permission.name", "chatitem.use");
handDisabled = conf.getBoolean("general.hand.disabled", false);
handName = color(conf.getString("general.hand.name", "&b&l&o{display-name}&b&l&o's hand"));
tooltipHand = conf.getStringList("general.hand.tooltip").stream().map(Storage::color).collect(Collectors.toList());
buggedClientAction = conf.getString("general.bugged_client.action", "show_both");
tooltipBuggedClient = conf.getStringList("general.bugged_client.tooltip").stream().map(Storage::color).collect(Collectors.toList());
checkUpdate = conf.getBoolean("general.check-update", true);
messageDeny = color(conf.getString("messages.deny-message", "&c&lYou have no item in hand!"));
messageReload = color(conf.getString("messages.reload-success", "&b&lSuccessful reload!"));
messageNoPermission = color(conf.getString("messages.no-permission",
"&c&lI'm sorry, but you are not allowed to use the placeholder in chat!"));
messageCooldown = color(conf.getString("messages.cooldown-message",
"&c&lYou can only use items in chat once a minute! You have {remaining} left!"));
updateMessage = color(conf.getString("messages.join-update.message",
"&cA new version of ChatItem is available. &aClick here to download."));
updateHover = color(conf.getString("messages.join-update.hover", "&6Click to go to spigot page !"));
messageLimit = color(conf.getString("messages.limit-message", "&c&lYou can only add 8 item placeholders per message!"));
}
SECONDS = color(conf.getString("messages.seconds", " seconds"));
minutes = color(conf.getString("messages.minutes", " minutes"));
hours = color(conf.getString("messages.hours", " hours"));
colorStringList(tooltipHand);
public static String color(String s) {
return s == null || s.isEmpty() ? s : ChatColor.translateAlternateColorCodes('&', s);
}
}
private void checkConfigVersion() {
int latestVersion = ChatItem.CFG_VER;
if (latestVersion != CONFIG_VERSION) {
ChatItem pl = ChatItem.getInstance();
pl.getLogger().warning(ChatColor.RED
+ "ChatItem detected an older or invalid configuration file. Replacing it with the default config...");
performOverwrite();
conf = pl.getConfig();
pl.getLogger().warning(ChatColor.RED + "Replacement complete!");
}
}
public static String color(String s) {
return s == null || s.isEmpty() ? s : ChatColor.translateAlternateColorCodes('&', s);
}
private void performOverwrite() {
ChatItem.getInstance().saveResource("config.yml", true);
}
private static void colorStringList(List<String> input) {
for (int i = 0; i < input.size(); ++i) {
input.set(i, color(input.get(i)));
}
}
private static void colorStringList(List<String> input) {
for (int i = 0; i < input.size(); ++i) {
input.set(i, color(input.get(i)));
}
}
private void checkConfigVersion() {
int latestVersion = ChatItem.CFG_VER;
if (latestVersion != configVersion) {
ChatItem pl = ChatItem.getInstance();
pl.getLogger().warning(ChatColor.RED
+ "ChatItem detected an older or invalid configuration file. Replacing it with the default config...");
performOverwrite();
conf = pl.getConfig();
pl.getLogger().warning(ChatColor.RED + "Replacement complete!");
}
}
private void performOverwrite() {
ChatItem.getInstance().saveResource("config.yml", true);
}
}
@@ -10,25 +10,98 @@ import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;
import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.ItemTag;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
public class Utils {
@SuppressWarnings("unchecked")
public static List<Player> getOnlinePlayers() {
Object players = Bukkit.getOnlinePlayers();
if(players instanceof Player[])
return Arrays.asList((Player[]) players);
return new ArrayList<>((Collection<Player>) players);
private final static TreeMap<Integer, String> ROMAN_KEYS = new TreeMap<>();
private final static HashMap<String, String> ENCHANTS_NAMES = new HashMap<>();
static {
ROMAN_KEYS.put(1000, "M");
ROMAN_KEYS.put(900, "CM");
ROMAN_KEYS.put(500, "D");
ROMAN_KEYS.put(400, "CD");
ROMAN_KEYS.put(100, "C");
ROMAN_KEYS.put(90, "XC");
ROMAN_KEYS.put(50, "L");
ROMAN_KEYS.put(40, "XL");
ROMAN_KEYS.put(10, "X");
ROMAN_KEYS.put(9, "IX");
ROMAN_KEYS.put(5, "V");
ROMAN_KEYS.put(4, "IV");
ROMAN_KEYS.put(1, "I");
ENCHANTS_NAMES.put("ARROW_DAMAGE", "Power");
ENCHANTS_NAMES.put("ARROW_FIRE", "Flame");
ENCHANTS_NAMES.put("ARROW_INFINITE", "Infinity");
ENCHANTS_NAMES.put("ARROW_KNOCKBACK", "Punch");
ENCHANTS_NAMES.put("BINDING_CURSE", "Curse of Binding");
ENCHANTS_NAMES.put("DAMAGE_ALL", "Sharpness");
ENCHANTS_NAMES.put("DAMAGE_ARTHROPODS", "Bane of Arthropods");
ENCHANTS_NAMES.put("DAMAGE_UNDEAD", "Smite");
ENCHANTS_NAMES.put("DEPTH_STRIDER", "Depth Strider");
ENCHANTS_NAMES.put("DIG_SPEED", "Efficiency");
ENCHANTS_NAMES.put("DURABILITY", "Unbreaking");
ENCHANTS_NAMES.put("FIRE_ASPECT", "Fire Aspect");
ENCHANTS_NAMES.put("FROST_WALKER", "Frost Walker");
ENCHANTS_NAMES.put("KNOCKBACK", "Knockback");
ENCHANTS_NAMES.put("LOOT_BONUS_BLOCKS", "Fortune");
ENCHANTS_NAMES.put("LOOT_BONUS_MOBS", "Looting");
ENCHANTS_NAMES.put("LUCK", "Luck of the Sea");
ENCHANTS_NAMES.put("LURE", "Lure");
ENCHANTS_NAMES.put("MENDING", "Mending");
ENCHANTS_NAMES.put("OXYGEN", "Respiration");
ENCHANTS_NAMES.put("PROTECTION_ENVIRONMENTAL", "Protection");
ENCHANTS_NAMES.put("PROTECTION_EXPLOSIONS", "Blast Protection");
ENCHANTS_NAMES.put("PROTECTION_FALL", "Feather Falling");
ENCHANTS_NAMES.put("PROTECTION_FIRE", "Fire Protection");
ENCHANTS_NAMES.put("PROTECTION_PROJECTILE", "Projectile Protection");
ENCHANTS_NAMES.put("SILK_TOUCH", "Silk Touch");
ENCHANTS_NAMES.put("SWEEPING_EDGE", "Sweeping Edge");
ENCHANTS_NAMES.put("THORNS", "Thorns");
ENCHANTS_NAMES.put("VANISHING_CURSE", "Cure of Vanishing");
ENCHANTS_NAMES.put("WATER_WORKER", "Aqua Affinity");
}
public static List<Player> getOnlinePlayers() {
return new ArrayList<>(Bukkit.getOnlinePlayers());
}
public static String toRoman(int number) {
int l = ROMAN_KEYS.floorKey(number);
if (number == l) {
return ROMAN_KEYS.get(number);
}
return ROMAN_KEYS.get(l) + toRoman(number - l);
}
@SuppressWarnings("deprecation")
public static String getEnchantName(Enchantment enchant) {
String name = ENCHANTS_NAMES.get(enchant.getName());
if (name == null) {
ChatItem.getInstance().getLogger()
.warning("Unknown enchant " + enchant.getName() + ". Please report this to Elikill58.");
}
return name;
}
public static String getFromURL(String urlName) {
ChatItem pl = ChatItem.getInstance();
try {
@@ -41,21 +114,99 @@ public class Utils {
connection.setDoOutput(true);
connection.setRequestMethod("GET");
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String content = "";
StringBuilder content = new StringBuilder();
String input;
while ((input = br.readLine()) != null)
content = content + input;
content.append(input);
br.close();
return content;
} catch (SocketTimeoutException e) {
pl.getLogger().info("Failed to access to " + urlName + " (Reason: timed out).");
} catch (UnknownHostException | MalformedURLException e) {
pl.getLogger().info("Could not use the internet connection to check for update or send stats");
} catch (ConnectException e) {
pl.getLogger().warning("Cannot connect to " + urlName + " (Reason: " + e.getMessage() + ").");
} catch (IOException e) {
e.printStackTrace();
return content.toString();
} catch (SocketTimeoutException e) {
pl.getLogger().info("Failed to access to " + urlName + " (Reason: timed out).");
} catch (UnknownHostException | MalformedURLException e) {
pl.getLogger().info("Could not use the internet connection to check for update or send stats");
} catch (ConnectException e) {
pl.getLogger().warning("Cannot connect to " + urlName + " (Reason: " + e.getMessage() + ").");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static int indexOf(CharSequence s, CharSequence searched, int i) {
return s.toString().indexOf(searched.toString(), i);
}
public static boolean isEmpty(CharSequence s) {
return (s == null || s.length() == 0);
}
public static int countMatches(CharSequence str, CharSequence searched) {
if (isEmpty(str) || isEmpty(searched))
return 0;
byte b = 0;
int i = 0;
while ((i = indexOf(str, searched, i)) != -1) {
b++;
i += searched.length();
}
return b;
}
@SuppressWarnings("deprecation")
public static HoverEvent createItemHover(ItemStack item) {
if(Version.getVersion().isNewerOrEquals(Version.V1_13)) {
return new HoverEvent(HoverEvent.Action.SHOW_ITEM, new Item(item.getType().getKey().getKey(), item.getAmount(), ItemTag.ofNbt(PacketUtils.getNbtTag(item))));
} else {
return new HoverEvent(HoverEvent.Action.SHOW_ITEM, new ComponentBuilder(JSONManipulator.stringifyItem(item)).create());
}
}
public static HoverEvent createTextHover(String text) {
return createTextHover(new ComponentBuilder(text).create());
}
@SuppressWarnings("deprecation")
public static HoverEvent createTextHover(BaseComponent[] comps) {
if(Version.getVersion().isNewerOrEquals(Version.V1_13)) {
return new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(comps));
} else {
return new HoverEvent(HoverEvent.Action.SHOW_TEXT, comps);
}
}
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
return true;
} catch (Exception e) {
return false;
}
}
public static boolean isByte(String s) {
try {
Byte.parseByte(s);
return true;
} catch (Exception e) {
return false;
}
}
public static boolean isShort(String s) {
try {
Short.parseShort(s);
return true;
} catch (Exception e) {
return false;
}
}
public static boolean isLong(String s) {
try {
Long.parseLong(s);
return true;
} catch (Exception e) {
return false;
}
}
}
@@ -4,6 +4,8 @@ import java.net.InetSocketAddress;
import org.bukkit.Bukkit;
import me.dadus33.chatitem.ChatItem;
public enum Version {
// http://wiki.vg/Protocol_version_numbers
@@ -18,8 +20,8 @@ public enum Version {
V1_15(100, 550, 578),
V1_16(100, 700, 754),
V1_17(100, 755, 756),
V1_18(100, 757, 800),
V1_19(100, 801, 1000),
V1_18(100, 757, 758),
V1_19(100, 761, 1000),
HIGHER(Integer.MAX_VALUE, -1, Integer.MAX_VALUE);
// Latest version should always have the upper limit set to Integer.MAX_VALUE so
@@ -67,11 +69,23 @@ public enum Version {
return HIGHER;
}
public static Version getVersion(int protocolVersion, Version def) {
for (Version ver : Version.values()) {
if (protocolVersion >= ver.MIN_VER && protocolVersion <= ver.MAX_VER) {
return ver;
}
}
ChatItem.debug("Failed to find version for protocol " + protocolVersion);
return def;
}
public static Version getVersion() {
return SERVER_VERSION;
}
public static String stringifyAdress(InetSocketAddress address) {
if(address == null)
return "0.0.0.0:0";
String port = String.valueOf(address.getPort());
String ip = address.getAddress().getHostAddress();
return ip + ":" + port;
+36 -25
View File
@@ -2,10 +2,10 @@
# For info visit
# Spigotmc: https://www.spigotmc.org/resources/chatitem.19064/
# Discord: https://discord.gg/ttA5CjMhk7
# Version info, DON'T TOUCH
config-version: 13
# By default, it's in "both" mode.
#
# Available mode :
@@ -24,6 +24,8 @@ general:
# The placeholders to display an item in chat.
placeholders:
- "[i]"
- "{i}"
- "[item]"
- "{item}"
# The format of the item placeholders.
name-format: "&b&l&o{name} {amount}&r"
@@ -50,15 +52,25 @@ general:
tooltip:
- "&7Nothing to see here"
- "&7Just the empty hand of {display-name}."
# Manage what is showed for bugged client.
# Specially lunar client with old version (1.7)
bugged_client:
# You can try to show the most informations as possible:
# item name & lore. You will not see specific item meta-data
# Or just show the bugged tooltip.
#
# Action available:
# nothing: no hover
# item: only try to get values from item
# tooltip: only show tooltip
# show_both: show item & tooltip below
action: "show_both"
tooltip:
- "&7Failed to parse item for your client"
# Format used with using /chatitem show
command-format: "&6%name%'s item is %item%"
# Here you can choose which commands will the plugin attempt to parse. Console commands will all be ignored,
# however player commands will be taken into consideration. To add a command, simply add an element to the list
# bellow containing an alias (or name) for that command.
# It is enough to add only ONE alias for each command, and the others will automatically be supported. However,
# this is only available for plugin commands. If you're planning to add bukkit or mojang commands here, you'll have
# to manually specify ALL aliases for those.
commands:
- "msg"
# Here you can set when the players should see the no-permission message (defined in the 'Messages' section bellow).
# 'normal' dictates whether the user should see the message when using the placeholder in normal chat, and 'command'
# sets whether the user should see it when using the placeholder in a command.
@@ -77,8 +89,8 @@ general:
cooldown: 60
# Check if the plugin have update
check-update: true
# Messages section. You can disable any of them by simply leaving them empty, like this: ""
messages:
# The message sent if showing off hands is disabled and the user isn't holding an item.
@@ -98,6 +110,8 @@ messages:
hover: "&6Click to go to spigot page !"
# For all commands ran by console by reserved to player
only-players: "&cOnly players can run this command"
# The player is not found
player-not-found: "&cThe player %arg% can't be founded."
# All messages for the /chatitem command
chatitem-cmd:
help:
@@ -142,6 +156,8 @@ messages:
hand-disabled: "&6Hand disabled: %state%"
limit-per-message: "&6Limit per message: &a%state%"
cooldown: "&6Cooldown: &a%state%"
debug: "&6Debug: &a%state%"
check-update: "&6Check updates: &a%state%"
# Change name and lore of all managers
manager:
both:
@@ -184,14 +200,14 @@ messages:
seconds: " seconds"
minutes: " minutes"
hours: " hours"
enabled: "&aEnabled"
disabled: "&cDisabled"
# Translations
# This is used to display prettier names in chat for items/blocks. Modifying this is usually unnecessary unless you know what you're doing.
translations:
## Blocks ##
STONE:
1: "Granite"
STONE:
0: "Stone"
1: "Granite"
@@ -784,8 +800,8 @@ translations:
STONE_PICKAXE:
0: "Stone Pickaxe"
STONE_AXE:
0: "Stone Axe
DIAMOND_SWORD: "
0: "Stone Axe"
DIAMOND_SWORD:
0: "Diamond Sword"
DIAMOND_SPADE:
0: "Diamond Shovel"
@@ -937,8 +953,6 @@ translations:
1: "Raw Salmon"
2: "Clownfish"
3: "Pufferfish"
COOKED_FISH:
0: "Cooked Fish"
COOKED_FISH:
0: "Cooked Salmon"
INK_SACK:
@@ -1070,9 +1084,6 @@ translations:
16394: "Splash Potion of Slowness"
16426: "Splash Potion of Slowness II"
16458: "Extended Splash Potion of Slowness"
16395: "Splash Potion of Leaping"
16427: "Splash Potion of Leaping II"
16459: "Extended Splash Potion of Leaping"
16396: "Splash Potion of Harming"
16428: "Splash Potion of Harming II"
16460: "Extended Splash Potion of Harming"
@@ -1153,8 +1164,8 @@ translations:
POISONOUS_POTATO:
0: "Poisonous Potato"
EMPTY_MAP:
0: "Empty Map
GOLDEN_CARROT: "
0: "Empty Map"
GOLDEN_CARROT:
0: "Golden Carrot"
SKULL_ITEM:
0: "Skeleton Head"
+1 -1
View File
@@ -2,7 +2,7 @@ name: ChatItem
main: me.dadus33.chatitem.ChatItem
version: ${project.version}
softdepend: [ViaVersion, ProtocolSupport, ProtocolLib, LangUtils, HexNicks]
softdepend: [ViaVersion, ProtocolSupport, ProtocolLib, LangUtils, HexNicks, EcoEnchants, DiscordSRV]
authors: [dadus33, WOLFI3654, Elikill58]
api-version: 1.13