Compare commits

...
284 Commits
Author SHA1 Message Date
Elikill58 5a310e3f60 Upgrade to 2.5 2024-01-30 22:50:31 +01:00
Elikill58 58c5f4607f Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2024-01-27 18:34:53 +01:00
Elikill58 b436c73f47 Fix ecoenchants support 2024-01-27 18:34:46 +01:00
Elikill58 806ceea250 Change for adventure 2024-01-25 22:24:27 +01:00
Elikill58 9a4ef0fe5b Fix some issue with primitive 2024-01-23 20:21:51 +01:00
Elikill58 241f80ca3c Fix strange EC 2024-01-22 19:27:01 +01:00
Elikill58 710bbf3163 Prevent inventory click 2024-01-14 12:11:18 +01:00
Elikill58 4ee561c18f Try to send message using discord srv 2024-01-13 11:34:00 +01:00
Elikill58 17754f2dfe Inv and ec for others managers 2024-01-11 22:25:28 +01:00
Elikill58 6a683508d4 Prevent & Fix #114 2024-01-11 22:05:02 +01:00
Elikill58 bcc8ac08f2 Begin of #31 2024-01-11 22:02:35 +01:00
dependabot[bot] 429a664e81 Bump com.willfp:eco from 6.65.5 to 6.66.1 (#109)
Bumps [com.willfp:eco](https://github.com/Auxilor/eco) from 6.65.5 to 6.66.1.
- [Release notes](https://github.com/Auxilor/eco/releases)
- [Commits](https://github.com/Auxilor/eco/compare/6.65.5...6.66.1)

---
updated-dependencies:
- dependency-name: com.willfp:eco
  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-12-11 08:32:27 +01:00
dependabot[bot] 49dadb897a Bump com.viaversion:viaversion-api from 4.8.1 to 4.9.2 (#113)
Bumps com.viaversion:viaversion-api from 4.8.1 to 4.9.2.

---
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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 08:31:55 +01:00
Elikill58 3cf54d39a1 Fix #111 2023-12-10 17:33:15 +01:00
Elikill58 187d1212f5 Upgrade to snapshot 2023-12-10 17:27:55 +01:00
Elikill58 d3776e161f Fix #112 2023-12-10 17:27:30 +01:00
Elikill58 010ea46ff2 Add reset color 2023-12-10 11:27:31 +01:00
Elikill58 db8119affd Do not listen on useless thing 2023-11-16 19:28:57 +01:00
Elikill58 484a6b46a0 Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2023-11-06 00:43:33 +01:00
Elikill58 a48f259b99 Fix for 1.20.2 2023-11-06 00:43:27 +01:00
Elikill58 2b9ae264fd Little internal changes 2023-11-05 23:52:00 +01:00
dependabot[bot] 207b066ecb Bump com.github.Auxilor:EcoEnchants from 10.36.1 to 10.39.1 (#105)
Bumps [com.github.Auxilor:EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 10.36.1 to 10.39.1.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/10.36.1...10.39.1)

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-10-30 11:08:13 +01:00
Elikill58 587432269a Upgrade to 2.4.9 2023-10-09 23:36:05 +02:00
dependabot[bot] a080e18571 Bump EcoEnchants 10.36.1 (#99)
Bumps [com.github.Auxilor:EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 10.35.3 to 10.36.1.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/10.35.3...10.36.1)

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-10-09 13:57:20 +02:00
dependabot[bot] 7b758882be Bump ProtocolLib to 5.1.0 (#90)
Bumps com.comphenix.protocol:ProtocolLib from 5.0.0 to 5.1.0.

---
updated-dependencies:
- dependency-name: com.comphenix.protocol:ProtocolLib
  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-10-09 13:57:09 +02:00
dependabot[bot] beafc6a635 Bump com.viaversion:viaversion-api from 4.7.0 to 4.8.1 (#102)
Bumps com.viaversion:viaversion-api from 4.7.0 to 4.8.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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 13:54:52 +02:00
dependabot[bot] 0da4039b70 Bump com.willfp:eco from 6.65.4 to 6.65.5 (#95)
Bumps [com.willfp:eco](https://github.com/Auxilor/eco) from 6.65.4 to 6.65.5.
- [Release notes](https://github.com/Auxilor/eco/releases)
- [Commits](https://github.com/Auxilor/eco/compare/6.65.4...6.65.5)

---
updated-dependencies:
- dependency-name: com.willfp:eco
  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-09-18 08:16:24 +02:00
dependabot[bot] b89e18b149 Bump com.github.Auxilor:EcoEnchants from 10.35.2 to 10.35.3 (#94)
Bumps [com.github.Auxilor:EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 10.35.2 to 10.35.3.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/10.35.2...10.35.3)

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-09-18 08:15:43 +02:00
Elikill58 07243fbf91 Fix wrong key 2023-09-17 21:59:43 +02:00
Elikill58 4b90aaa070 Prevent no end in message 2023-09-17 11:32:53 +02:00
Elikill58 9d74eb067a Fix #93 2023-09-14 15:56:58 +02:00
dependabot[bot] c51f62a9fb Bump com.github.Auxilor:EcoEnchants from 10.26.5 to 10.35.2 (#92)
Bumps [com.github.Auxilor:EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 10.26.5 to 10.35.2.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/10.26.5...10.35.2)

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-09-14 15:51:07 +02:00
Elikill58 badddd29ed Prevent NPE 2023-08-07 13:01:56 +02:00
Elikill58 d188289e84 Add option for broadcast and show, and change for tab 2023-08-07 11:27:11 +02:00
dependabot[bot] 1b9fd3bf90 Bump com.willfp:eco from 6.65.3 to 6.65.4 (#85)
Bumps com.willfp:eco from 6.65.3 to 6.65.4.

---
updated-dependencies:
- dependency-name: com.willfp:eco
  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-08-07 08:34:36 +02:00
dependabot[bot] 0d98b4408e Bump com.github.Auxilor:EcoEnchants from 10.26.2 to 10.26.5 (#87)
Bumps com.github.Auxilor:EcoEnchants from 10.26.2 to 10.26.5.

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-08-07 08:34:27 +02:00
dependabot[bot] 769abab65c Bump com.github.Auxilor:EcoEnchants from 10.25.1 to 10.26.2 (#84)
Bumps com.github.Auxilor:EcoEnchants from 10.25.1 to 10.26.2.

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-07-31 08:14:07 +02:00
Elikill58 78311f60b4 upgrade to snapshot 2023-07-26 19:44:51 +02:00
Elikill58 bd31b5791c Fix for 1.15- players 2023-07-26 19:44:24 +02:00
Elikill58 cd5cfa47ec Fix error with json 2023-07-26 19:27:37 +02:00
Elikill58 d31bdbef68 Remove one import 2023-07-26 19:01:12 +02:00
Elikill58 a82b50b1d0 Fix #78 2023-07-24 11:34:04 +02:00
dependabot[bot] 912bbcf371 Bump com.willfp:eco from 6.65.2 to 6.65.3 (#83)
Bumps com.willfp:eco from 6.65.2 to 6.65.3.

---
updated-dependencies:
- dependency-name: com.willfp:eco
  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-07-24 11:27:03 +02:00
dependabot[bot] af5d63ea93 Bump com.github.Auxilor:EcoEnchants from 10.23.1 to 10.25.1 (#82)
Bumps [com.github.Auxilor:EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 10.23.1 to 10.25.1.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/10.23.1...10.25.1)

---
updated-dependencies:
- dependency-name: com.github.Auxilor: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-07-24 11:26:56 +02:00
Elikill58 69681553c8 Fix 1.18 issue 2023-07-20 20:05:58 +02:00
Elikill58 3f6856ddab Fix invocation error 2023-07-20 19:22:39 +02:00
Elikill58 9d55208563 Change ChatControl support 2023-07-19 20:27:14 +02:00
Elikill58 2b8ce53553 Upgrade to 2.4.8 2023-07-17 21:22:52 +02:00
dependabot[bot] 6b157320c4 Bump eco from 6.65.1 to 6.65.2 (#80)
Bumps [eco](https://github.com/Auxilor/eco) from 6.65.1 to 6.65.2.
- [Release notes](https://github.com/Auxilor/eco/releases)
- [Commits](https://github.com/Auxilor/eco/compare/6.65.1...6.65.2)

---
updated-dependencies:
- dependency-name: com.willfp:eco
  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-07-17 07:53:03 +02:00
dependabot[bot] ba3da92061 Bump HexNicks from 3.1.0 to 3.1.1 (#81)
Bumps [HexNicks](https://github.com/MajekDev/HexNicks) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/MajekDev/HexNicks/releases)
- [Changelog](https://github.com/MajekDev/HexNicks/blob/main/CHANGELOG.md)
- [Commits](https://github.com/MajekDev/HexNicks/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: com.github.MajekDev:HexNicks
  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-07-17 07:52:44 +02:00
Elikill58 dc6ce9c260 Change dep 2023-07-15 20:42:07 +02:00
Elikill58 cf45b8e436 Fix EcoEnchants v10 support 2023-07-15 12:05:00 +02:00
Elikill58 fc8966dab0 Change permissions 2023-06-17 18:18:49 +02:00
Elikill58 c537e72a27 Update versions 2023-06-16 10:26:32 +02:00
Elikill58 dee359a37d Upgrade to snapshot 2023-06-16 09:36:05 +02:00
Elikill58 34f67345e2 Add support for 1.20 2023-06-16 09:35:37 +02:00
Elikill58 d937f5d89e Change discord link in config 2023-06-16 09:09:53 +02:00
Elikill58 856a5f182f Fix error with 1.20 2023-06-16 09:08:52 +02:00
dependabot[bot] 6653b9c057 Bump viaversion-api from 4.6.2 to 4.7.0 (#77)
Bumps viaversion-api from 4.6.2 to 4.7.0.

---
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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-12 17:43:35 +02:00
Elikill58 0b60780fe2 Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2023-06-05 19:59:17 +02:00
Elikill58 a16b2ea462 Don't use one componentManager 2023-06-05 19:59:10 +02:00
Magnetite 05771d975c Add support for hexnicks 3 (#76)
* Add support for hexnicks 3

* Remove empty line
2023-05-31 13:48:25 +02:00
Elikill58 417b63e86d [Include in release] Change default config 2023-05-23 08:12:33 +02:00
Elikill58 01da231510 [Include in release] Quick fix typo for lang 2023-05-23 07:37:17 +02:00
dependabot[bot] 5e2559c1ee Bump ProtocolLib from 5.0.0-SNAPSHOT to 5.0.0 (#75)
Bumps ProtocolLib from 5.0.0-SNAPSHOT to 5.0.0.

---
updated-dependencies:
- dependency-name: com.comphenix.protocol:ProtocolLib
  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-05-15 18:34:59 +02:00
Elikill58 0bb784f7f2 Fix for v2 colors 2023-05-15 18:33:48 +02:00
Elikill58 eef3bf80c8 Fix wrong version check 2023-05-14 21:04:56 +02:00
Elikill58 2d97d5fd45 Upgrade to 2.4.7 2023-05-09 18:53:00 +02:00
Elikill58 32e71bc683 Fix chatitem select 2023-05-09 18:51:59 +02:00
Elikill58 31c08cbb37 Add select of manager 2023-05-06 12:49:11 +02:00
Elikill58 084cc40f88 Fix second message 2023-05-06 11:19:43 +02:00
Elikill58 c322fb2eec Fix double item in chat 2023-05-06 10:30:05 +02:00
Elikill58 4e90d96f48 Fix v1 issue #74 2023-04-30 22:42:14 +02:00
Elikill58 828a8e3824 Add chatmanager support 2023-04-30 22:24:29 +02:00
Elikill58 7da5adf264 Update gitignore 2023-04-30 22:12:01 +02:00
Elikill58 513185de26 Fix unknow version 2023-04-10 11:25:25 +02:00
Elikill58 2f17aa897a Prevent obj can't be created 2023-04-10 11:10:18 +02:00
Elikill58 dd2359f96d Change for TAB 2023-04-10 10:54:43 +02:00
Elikill58 8799aa6fc0 Fix storage 2023-04-10 10:50:18 +02:00
Elikill58 4dfe50038b Fix failed to find lang 2023-04-10 10:46:29 +02:00
Elikill58 51c4311233 Fix for item/block and for chatitem links 2023-04-07 09:30:24 +02:00
Elikill58 72557594eb Fix for not found constructor 2023-04-07 09:24:10 +02:00
Elikill58 708e995ac7 Add items in langs 2023-04-05 22:17:24 +02:00
Elikill58 589318ea8d Re-add EcoEnchant support for v8 2023-04-05 21:55:55 +02:00
Elikill58 17e9edbd53 Add translation into inventory 2023-04-04 22:49:22 +02:00
Elikill58 f5124f749f Add complete translation system 2023-04-04 22:10:01 +02:00
Elikill58 fe10f7ca5b Change readme 2023-04-03 22:24:23 +02:00
dependabot[bot] d590b66630 Bump discordsrv from 1.26.0 to 1.26.2 (#71)
Bumps discordsrv from 1.26.0 to 1.26.2.

---
updated-dependencies:
- dependency-name: com.discordsrv:discordsrv
  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-04-03 22:13:17 +02:00
dependabot[bot] e68b843f73 Bump viaversion-api from 4.6.1 to 4.6.2 (#72)
Bumps viaversion-api from 4.6.1 to 4.6.2.

---
updated-dependencies:
- dependency-name: com.viaversion:viaversion-api
  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-04-03 22:12:56 +02:00
Elikill58 2cf594f9ed Fix PCM 2023-04-02 17:15:21 +02:00
Elikill58 1b33b42e94 Fix error 2023-04-01 14:37:12 +02:00
Elikill58 77ba7e65ce Re-add some managers 2023-04-01 14:31:42 +02:00
Elikill58 7375f970af Fix error while changing packet 2023-03-30 22:46:35 +02:00
Elikill58 870d9052a0 Fix double item 2023-03-28 19:13:33 +02:00
Elikill58 4ea4aa43bf Upgrade kyori's adventure thing 2023-03-26 15:30:45 +02:00
Elikill58 39ffa60e7a Prevent the error 2023-03-21 17:44:39 +01:00
dependabot[bot] fc1c9b0019 Bump EcoEnchants from 9.17.5 to 9.17.7 (#68)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.17.5 to 9.17.7.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.17.5...9.17.7)

---
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-03-20 22:35:04 +01:00
dependabot[bot] ed3ad9db85 Bump viaversion-api from 4.5.1 to 4.6.1 (#69)
Bumps viaversion-api from 4.5.1 to 4.6.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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 22:34:44 +01:00
dependabot[bot] c38d68d081 Bump ChatControl-Free from master-SNAPSHOT to 5.9.5 (#70)
Bumps [ChatControl-Free](https://github.com/kangarko/ChatControl-Free) from master-SNAPSHOT to 5.9.5.
- [Release notes](https://github.com/kangarko/ChatControl-Free/releases)
- [Commits](https://github.com/kangarko/ChatControl-Free/commits/5.9.5)

---
updated-dependencies:
- dependency-name: com.github.kangarko:ChatControl-Free
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 22:34:33 +01:00
Elikill58 352dcb82b7 Add ChatContorl into plugin dep 2023-03-16 21:42:20 +01:00
Elikill58 7981ccaa1e Fix cooldown for v1 and chatcontrol support 2023-03-16 21:41:56 +01:00
Elikill58 e5444216ce Merge branch 'v2' of https://github.com/dadus33-plugins/ChatItem into v2 2023-03-15 23:55:02 +01:00
dependabot[bot] 207159bb17 Bump EcoEnchants from 9.17.3 to 9.17.5 (#67)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.17.3 to 9.17.5.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.17.3...9.17.5)

---
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-03-15 13:55:04 +01:00
dependabot[bot] 32d4d3556d Bump opennbt from 1.4 to 1.5 (#66)
Bumps [opennbt](https://github.com/Steveice10/OpenNBT) from 1.4 to 1.5.
- [Release notes](https://github.com/Steveice10/OpenNBT/releases)
- [Commits](https://github.com/Steveice10/OpenNBT/compare/1.4...1.5)

---
updated-dependencies:
- dependency-name: com.github.GeyserMC:opennbt
  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-03-15 13:54:56 +01:00
Elikill58 9102b6a11f Change default config 2023-03-10 19:00:11 +01:00
Elikill58 587d6bbb93 Fix #16 2023-03-10 18:57:19 +01:00
Elikill58 9ea5d6ffb7 Quick change for SCM 2023-03-10 18:25:14 +01:00
Elikill58 7ac7369a7f Update how bugged clients are managed 2023-03-09 21:18:36 +01:00
Elikill58 d548b68c8a Prevent error for 1.12- version 2023-03-07 21:17:52 +01:00
dependabot[bot] 92f4118015 Bump EcoEnchants from 9.17.1 to 9.17.3 (#64)
Bumps [EcoEnchants](https://github.com/Auxilor/EcoEnchants) from 9.17.1 to 9.17.3.
- [Release notes](https://github.com/Auxilor/EcoEnchants/releases)
- [Commits](https://github.com/Auxilor/EcoEnchants/compare/9.17.1...9.17.3)

---
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-03-07 20:17:00 +01:00
Elikill58 3cae31998e Remove one logger 2023-03-07 18:10:50 +01:00
Elikill58 396b8ccc05 Possible way to remove coloring 2023-03-07 18:10:16 +01:00
Elikill58 70fece6c4f Prevent re-adding content 2023-03-07 17:42:26 +01:00
Elikill58 7ad2f1923e Fix end of message removed 2023-03-05 13:47:10 +01:00
Elikill58 f1796cee43 Add new filter 2023-03-05 10:38:27 +01:00
Elikill58 e460940fcd Fx something not filtered 2023-03-04 20:39:36 +01:00
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
214 changed files with 5298 additions and 3668 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
+3 -1
View File
@@ -6,4 +6,6 @@ target/
dependency-reduced-pom.xml
.classpath
.project
.settings/
.settings/
/.apt_generated/
/.apt_generated_tests/
-2
View File
@@ -1,2 +0,0 @@
language: java
script: "mvn clean package -DskipTests"
+25 -1
View File
@@ -1,5 +1,29 @@
# ChatItem [![Build Status](https://travis-ci.org/dadus33/ChatItem.svg?branch=master)](https://travis-ci.org/dadus33/ChatItem) [![Help Chat](https://img.shields.io/badge/chat-on_discord-7289da.svg)](https://discord.gg/eQJbVJt)
# ChatItem
The official repository of the ChatItem Spigot/Bukkit plugin.
You can:
- [Download latest dev build](https://nightly.link/dadus33-plugins/ChatItem/workflows/build/v2/ChatItem.jar.zip)
- [ ![Come on discord](https://img.shields.io/badge/chat-on_discord-7289da.svg) ](https://discord.gg/yng5PPf62h)
- [Check the wiki](https://github.com/dadus33-plugins/ChatItem/wiki)
# Item not well showed in chat
You can try to do `/chatitem admin` then select different paper item. It will change how the plugin try to add item in chat.
**If you already have issue, please do**:
1) Do `/chatitem admin` then select on "Debug" item at top right
2) Try to use ChatItem in chat
3) Come on discord [here](https://discord.gg/yng5PPf62h) or in private message: `Elikill58#0743`
4) Send the **full file `logs/latest.log`**
PS: Yes you can disable the debug behavior after.
# Building
Building this is simple as we use Maven.
To build it, simply clone this repository and then run `mvn clean install`.
You can add the parameter `export_dir` to set the URL where the JAR will be exported.
-4
View File
@@ -1,4 +0,0 @@
jdk:
- openjdk11
install:
- mvn install
+69 -32
View File
@@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion>
<groupId>me.dadus33</groupId>
<artifactId>chatitem</artifactId>
<version>2.2.1</version>
<artifactId>ChatItem</artifactId>
<version>2.5</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -47,7 +47,6 @@
</repository>
<repository>
<id>dv8tion</id>
<name>m2-dv8tion</name>
<url>https://m2.dv8tion.net/releases</url>
</repository>
<repository>
@@ -71,18 +70,6 @@
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
@@ -98,31 +85,31 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>4.7.0</version>
<version>5.1.0</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.9.2</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>
<version>4.1.58.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.GeyserMC</groupId>
<artifactId>opennbt</artifactId>
<version>1.4</version>
<version>1.5</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -131,16 +118,52 @@
<version>2.2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.MajekDev</groupId>
<artifactId>HexNicks</artifactId>
<version>3.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>4.9.1</version>
<version>4.14.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>4.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.discordsrv</groupId>
<artifactId>discordsrv</artifactId>
<version>1.24.1-SNAPSHOT</version>
<version>1.26.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.willfp</groupId>
<artifactId>EcoEnchants</artifactId>
<version>8.57.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.Auxilor</groupId>
<artifactId>EcoEnchants</artifactId>
<version>12.2.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ryderbelserion</groupId>
<artifactId>ChatManager</artifactId>
<version>3.7.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.willfp</groupId>
<artifactId>eco</artifactId>
<version>6.66.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -151,10 +174,6 @@
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>plugin.yml</include>
<include>config.yml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
@@ -163,7 +182,7 @@
<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>
@@ -172,7 +191,7 @@
<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>
@@ -186,7 +205,25 @@
<pattern>com.google.gson</pattern>
<shadedPattern>me.dadus33.libs.gson</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.steveice10.opennbt</pattern>
<shadedPattern>me.dadus33.libs.opennbt</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>
@@ -194,7 +231,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<outputDirectory>${export_dir}</outputDirectory>
</configuration>
+168 -124
View File
@@ -1,10 +1,13 @@
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;
import java.util.concurrent.CompletableFuture;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandExecutor;
@@ -16,167 +19,208 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.base.Strings;
import me.dadus33.chatitem.chatmanager.ChatEventListener;
import me.dadus33.chatitem.chatmanager.ChatManager;
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.hook.ChatControlSupport;
import me.dadus33.chatitem.hook.ChatManagerSupport;
import me.dadus33.chatitem.hook.ecoenchants.EcoEnchantsSupport;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.listeners.InventoryListener;
import me.dadus33.chatitem.listeners.JoinListener;
import me.dadus33.chatitem.listeners.TranslationInventoryListener;
import me.dadus33.chatitem.playernamer.PlayerNamerManager;
import me.dadus33.chatitem.utils.SemVer;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.utils.Utils;
import me.dadus33.chatitem.utils.Version;
public class ChatItem extends JavaPlugin {
public final static int CFG_VER = 13;
private static ChatItem instance;
private Log4jFilter filter;
private Storage storage;
public static boolean discordSrvSupport = false, hasNewVersion = false;
private List<ChatManager> chatManager = new ArrayList<>();
public final static int CFG_VER = 13;
public static boolean discordSrvSupport = false, hasNewVersion = false;
private static ChatItem instance;
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 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()));
public static void reload(CommandSender sender) {
ChatItem pl = getInstance();
if (pl.getConfig().getKeys(false).isEmpty())
pl.saveDefaultConfig();
pl.reloadConfig();
String oldChatManager = pl.storage.manager;
pl.storage = new Storage(pl.getConfig());
pl.chooseManagers();
Translation.load(pl);
if(sender != null) {
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.");
}
}
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();
pl.reloadConfig();
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.");
}
public static ChatItem getInstance() {
return instance;
}
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'));
}
public static boolean hasDebug() {
return getInstance().getStorage().debug;
}
@Override
public void onEnable() {
//Save the instance (we're basically a singleton)
instance = this;
private void chooseManagers() {
this.chatManager.forEach((cm) -> cm.unload(this));
this.chatManager.clear();
PluginManager pm = getServer().getPluginManager();
String managerName = getStorage().manager;
//Load config
saveDefaultConfig();
storage = new Storage(getConfig());
//Commands
loadCommand(getCommand("cireload"), new CIReloadCommand());
loadCommand(getCommand("chatitem"), new ChatItemCommand());
// events
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new JoinListener(), this);
pm.registerEvents(new InventoryListener(), this);
chooseManagers();
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;
}
//Initialize Log4J filter (remove ugly console messages)
filter = new Log4jFilter(storage);
if(pm.getPlugin("DiscordSRV") != null) {
discordSrvSupport = true;
getLogger().info("Load DiscordSRV support.");
}
if(storage.CHECK_UPDATE) {
getServer().getScheduler().runTaskAsynchronously(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", "ItemsAdder");
}
@Override
public void onEnable() {
// Save the instance (we're basically a singleton)
instance = this;
getLogger().info("Detected server version: " + Version.getVersion().name().toLowerCase());
// Load config
if (!new File(getDataFolder(), "config.yml").exists()) {
getLogger().info("--------------");
getLogger().info("");
getLogger().info("Welcome on ChatItem !");
getLogger().info("If you need help for setup, USE: /chatitem select");
getLogger().info("Then follow steps.");
getLogger().info("");
getLogger().info("--------------");
saveDefaultConfig();
}
storage = new Storage(getConfig());
// Commands
loadCommand(getCommand("cireload"), new CIReloadCommand());
loadCommand(getCommand("chatitem"), new ChatItemCommand());
// events
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new JoinListener(), this);
pm.registerEvents(new InventoryListener(), this);
pm.registerEvents(new TranslationInventoryListener(), this);
pm.registerEvents(new ChatEventListener(), this);
chooseManagers();
StringJoiner plugins = new StringJoiner(", ");
if (pm.isPluginEnabled("DiscordSRV")) {
discordSrvSupport = true;
plugins.add("DiscordSRV");
}
if (pm.isPluginEnabled("ChatControl")) {
ChatControlSupport.init(this);
plugins.add("ChatControl");
}
if (pm.isPluginEnabled("ChatManager")) {
ChatManagerSupport.init(this);
plugins.add("ChatManager");
}
if (pm.isPluginEnabled("EcoEnchants") && EcoEnchantsSupport.load()) {
plugins.add("EcoEnchants");
}
if (plugins.length() > 0)
getLogger().info("Load " + plugins.toString() + " support.");
Translation.load(this);
getServer().getMessenger().registerIncomingPluginChannel(this, brandChannelName, (chan, p, msg) -> ItemPlayer.getPlayer(p).setClientName(new String(msg).substring(1)));
if (storage.checkUpdate) {
CompletableFuture.runAsync(() -> {
String urlName = "https://api.spigotmc.org/legacy/update.php?resource=19064";
String content = Utils.getFromURL(urlName);
if(Strings.isNullOrEmpty(content))
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);
}
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)
if (obj instanceof CommandExecutor)
cmd.setExecutor((CommandExecutor) obj);
if(obj instanceof TabCompleter)
if (obj instanceof TabCompleter)
cmd.setTabCompleter((TabCompleter) obj);
}
public Storage getStorage() {
public Storage getStorage() {
return storage;
}
public List<ChatManager> getChatManager() {
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() {
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().getStorage().DEBUG)
getInstance().getLogger().info("[Debug] " + msg);
}
}
@@ -0,0 +1,43 @@
package me.dadus33.chatitem;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Messages;
public class InventoryShower {
public static void showInventory(Player p, Player cible) {
Inventory inv = Bukkit.createInventory(new CustomInventoryHolder(), 54, Messages.getMessage("inventory.name", "%cible%", cible.getName()));
for(int i = 0; i < 18; i++)
inv.setItem(i, ItemUtils.createItem(ItemUtils.getMaterialWithCompatibility("BROWN_STAINED_GLASS_PANE", "STAINED_GLASS_PANE"), ""));
inv.setItem(2, ItemUtils.createItem(ItemUtils.getMaterialWithCompatibility("EXPERIENCE_BOTTLE", "EXP_BOTTLE"), "", cible.getLevel() == 0 ? 1 : (cible.getLevel() >= 64 ? 64 : cible.getLevel())));
PlayerInventory pi = cible.getInventory();
inv.setItem(4, pi.getHelmet());
inv.setItem(5, pi.getChestplate());
inv.setItem(6, pi.getLeggings());
inv.setItem(7, pi.getBoots());
for(int i = 0; i < pi.getContents().length && i < (54 - 18); i++)
inv.setItem(i + 18, pi.getContents()[i]);
p.openInventory(inv);
}
public static void showEnderchest(Player p, Player cible) {
Inventory ec = cible.getEnderChest();
Inventory inv = Bukkit.createInventory(new CustomInventoryHolder(), ec.getSize(), Messages.getMessage("enderchest.name", "%cible%", cible.getName()));
ItemStack[] items = ec.getContents();
for(int i = 0; i < ec.getSize(); i++)
inv.setItem(i, items[i]);
p.openInventory(inv);
}
}
@@ -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")) || (!getVersion().isNewerOrEquals(Version.V1_15) && Version.getVersion().isNewerOrEquals(Version.V1_16));
}
@Override
public String toString() {
return "ItemPlayer[uuid=" + uuid + ",name=" + (getPlayer() != null ? getPlayer().getName() : "-") + ",version=" + version.name() + ",protocol=" + protocolVersion + ",client=" + clientName + "]";
}
}
@@ -0,0 +1,69 @@
package me.dadus33.chatitem;
import java.util.List;
import me.dadus33.chatitem.chatmanager.ChatManager;
public enum ItemSlot {
HAND(true, "", false),
HELMET(false, "helmet", false),
CHESTPLATE(false, "chestplate", false),
LEGGINGS(false, "leggings", false),
BOOTS(false, "boots", false),
INVENTORY(false, "inventory", true),
ENDERCHEST(false, "enderchest", true);
private final boolean basic, command;
private final String key;
private ItemSlot(boolean basic, String key, boolean command) {
this.basic = basic;
this.command = command;
this.key = key;
}
public boolean isBasic() {
return basic;
}
public boolean isCommand() {
return command;
}
public List<String> getPlaceholders() {
return ChatItem.getInstance().getConfig().getStringList(basic ? "general.placeholders" : "general.other-placeholders." + key + ".keys");
}
public boolean isEnabled() {
return basic || ChatItem.getInstance().getConfig().getBoolean("general.other-placeholders." + key + ".enabled", true);
}
public boolean isDenyIfNoItem() {
return ChatItem.getInstance().getConfig().getBoolean("general" + (basic ? "" : ".other-placeholders." + key) + ".deny-if-no-item", true);
}
public boolean hasPlaceholders(String message) {
for (String rep : getPlaceholders()) {
if (message.contains(rep)) {
return true;
}
}
return false;
}
public String replacePlaceholdersToSeparator(String message) {
for(String rep : getPlaceholders())
message = message.replace(rep, Character.toString(ChatManager.SEPARATOR));
return message;
}
public static ItemSlot getItemSlotFromMessage(String message) {
for(ItemSlot slot : ItemSlot.values()) {
if(slot.isEnabled() && slot.hasPlaceholders(message)) {
return slot;
}
}
return null;
}
}
@@ -0,0 +1,88 @@
package me.dadus33.chatitem;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
public class Storage {
public String handName, nameFormat, amountFormat, commandFormat, manager, permissionName, buggedClientAction, language;
public final String messageNoPermission, messageDeny, messageReload, messageCooldown, messageLimit, messageIgnoredItem;
public final String SECONDS, minutes, hours;
public final String updateMessage, updateHover;
public final List<String> tooltipHand, tooltipBuggedClient, ignoredItems;
public boolean colorIfColored, addAmountForced, letMessageThrough, debug, handDisabled, showNoPermissionMessage, checkUpdate, permissionEnabled, cmdBroadcast, cmdShow, discordSrvSendMsg;
public int configVersion, limit, cooldown;
private FileConfiguration conf;
public Storage(FileConfiguration cnf) {
this.conf = cnf;
configVersion = conf.getInt("config-version", 13);
checkConfigVersion();
this.manager = conf.getString("manager", "auto");
language = conf.getString("general.language", "en_gb");
debug = conf.getBoolean("debug", false);
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);
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());
ignoredItems = conf.getStringList("general.ignored_items");
checkUpdate = conf.getBoolean("general.check-update", true);
cmdShow = conf.getBoolean("general.sub-commands.broadcast", true);
cmdBroadcast = conf.getBoolean("general.sub-commands.show", 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!"));
messageIgnoredItem = color(conf.getString("messages.ignored-item", "&cThis item is not allowed to be showed."));
discordSrvSendMsg = conf.getBoolean("discord-srv-send-our", true);
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 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);
}
}
@@ -0,0 +1,109 @@
package me.dadus33.chatitem;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.utils.Utils;
public class Translation {
private static File folder;
private static YamlConfiguration legacy, allLangsConfig;
private static JsonObject messages;
private static HashMap<String, String> allLangs = new HashMap<>();
public static void load(ChatItem pl) {
folder = new File(pl.getDataFolder(), "lang");
if (!folder.exists())
folder.mkdir();
legacy = Utils.copyLoadFile(folder, "legacy.yml", "lang/legacy.yml");
allLangsConfig = Utils.copyLoadFile(pl.getDataFolder(), "langs.yml", "langs.yml");
allLangsConfig.getStringList("all").forEach(langKey -> {
try {
JsonObject content = JsonParser.parseReader(new InputStreamReader(pl.getResource("lang/" + langKey + ".json"))).getAsJsonObject();
allLangs.put(langKey, content.get("language.name").getAsString() + " (" + content.get("language.region").getAsString() + ")");
} catch (Exception e) {
pl.getLogger().severe("Failed to load lang with key " + langKey + " : " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")");
}
});
allLangs = allLangs.entrySet().stream().sorted(Entry.comparingByValue()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
loadLang(pl.getStorage().language);
}
public static HashMap<String, String> getAllLangs() {
return allLangs;
}
public static JsonObject getMessages() {
return messages;
}
public static void loadLang(String lang) {
ChatItem pl = ChatItem.getInstance();
File langFile = new File(folder, lang + ".json");
if (!langFile.exists()) {
if (pl.getResource("lang/" + lang + ".json") != null) {
Utils.copyFile("lang/" + lang + ".json", langFile);
} else {
pl.getLogger().severe("Failed to find lang file for " + lang);
if(lang != "en_gb")
loadLang("en_gb");
return;
}
}
try {
messages = JsonParser.parseReader(new FileReader(langFile)).getAsJsonObject();
} catch (Exception e) {
e.printStackTrace();
}
pl.getLogger().info("Loaded translation for " + lang + ".");
}
@SuppressWarnings("deprecation")
public static String get(ItemStack item) {
String key = (item.getType().isBlock() ? "block" : "item") + ".minecraft." + item.getType().name().toLowerCase();
if (messages != null && messages.has(key)) {
return messages.get(key).getAsString();
} else
ChatItem.debug("Failed to find translation for " + key);
return legacy.getString(item.getType().name() + "." + item.getDurability(), item.getType().name().toLowerCase().replace("_", " "));
}
protected void thisMethodShouldNotBeUsed_InsteadToUpdateLangFileFromLocalInstall() throws Exception {
File dir = new File("dir/to/result");
File folder = new File("C:\\Dir\\To\\AppData\\Roaming\\.minecraft\\assets");// here we are looking for 1.19
JsonObject json = JsonParser.parseReader(new FileReader(new File(folder, "indexes/1.19.json"))).getAsJsonObject().get("objects").getAsJsonObject();
for (String key : json.keySet()) {
if (key.startsWith("minecraft/lang")) { // only lang files
String lang = key.toString().replace("minecraft/lang/", "");
String hash = json.get(key).getAsJsonObject().get("hash").getAsString();
File langFile = new File(folder, "objects/" + hash.substring(0, 2) + "/" + hash);
JsonObject langs = JsonParser.parseReader(new FileReader(langFile)).getAsJsonObject();
for (String langKey : new ArrayList<>(langs.keySet())) {
if (!(langKey.startsWith("block.") || langKey.startsWith("language"))) { // only what we want
langs.remove(langKey); // removing not needed
}
}
File langDir = new File(dir, lang);
Files.write(langDir.toPath(), Arrays.asList(langs.toString()));
System.out.println("Copied " + lang); // using sysout as it's made for basic java, not mc
}
}
}
}
@@ -0,0 +1,97 @@
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.ItemSlot;
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, ChatAction action) {
return new Chat(actualId++, p, message, action);
}
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;
private final ChatAction action;
public Chat(int id, Player p, String message, ChatAction action) {
this.time = System.currentTimeMillis();
this.id = id;
this.p = p;
this.message = message;
this.action = action;
CHAT.add(this);
}
public long getTime() {
return time;
}
public int getId() {
return id;
}
public Player getPlayer() {
return p;
}
public String getMessage() {
return message;
}
public ItemSlot getSlot() {
return action.getSlot();
}
public ChatAction getAction() {
return action;
}
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 + "}";
}
}
@@ -0,0 +1,41 @@
package me.dadus33.chatitem.chatmanager;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ItemSlot;
public class ChatAction {
private boolean isItem;
private ItemSlot slot;
private String command;
private ItemStack item;
public ChatAction(ItemSlot slot, ItemStack item) {
this.slot = slot;
this.item = item;
this.isItem = true;
}
public ChatAction(ItemSlot slot, String command) {
this.slot = slot;
this.command = command;
this.isItem = false;
}
public ItemSlot getSlot() {
return slot;
}
public boolean isItem() {
return isItem;
}
public String getCommand() {
return command;
}
public ItemStack getItem() {
return item;
}
}
@@ -0,0 +1,53 @@
package me.dadus33.chatitem.chatmanager;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR_END;
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 me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemSlot;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.utils.Utils;
public class ChatEventListener implements Listener {
private Storage getStorage() {
return ChatItem.getInstance().getStorage();
}
@EventHandler(priority = EventPriority.LOWEST)
public void onChat(AsyncPlayerChatEvent e) {
if (ChatManager.isTestingEnabled() && !ChatManager.isTesting("packet"))
return;
if (ChatManager.containsSeparator(e.getMessage())) { // If the BELL character is found, we have to remove it
e.setMessage(ChatManager.removeSeparator(e.getMessage()));
}
Player p = e.getPlayer();
String oldMsg = e.getMessage();
ItemSlot slot = ItemSlot.getItemSlotFromMessage(e.getMessage());
if (slot == null) {
ChatItem.debug("(v1) not found placeholders in: " + e.getMessage());
return;
}
ChatAction action = ChatManager.getChatAction(slot, p);
if(action.isItem() && !ChatManager.canShowItem(p, action.getItem(), slot, e))
return;
String s = slot.replacePlaceholdersToSeparator(e.getMessage());
if (Utils.countMatches(s, Character.toString(ChatManager.SEPARATOR)) > getStorage().limit) {
e.setCancelled(true);
if (!getStorage().messageLimit.isEmpty())
p.sendMessage(getStorage().messageLimit);
return;
}
Chat c = Chat.create(p, oldMsg, action);
ChatItem.debug("(v1) Set placeholder to message " + c);
e.setMessage(s.replace(Character.toString(ChatManager.SEPARATOR), 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,30 +1,314 @@
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.utils.Storage;
import me.dadus33.chatitem.ItemSlot;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.hook.ecoenchants.EcoEnchantsSupport;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Utils;
public abstract class ChatManager {
public static String inTest = null;
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, ItemSlot slot) {
if(slot == null)
return null;
ItemStack item = HandItem.getBetterItem(p, slot).clone();
if(slot.isDenyIfNoItem() && ItemUtils.isEmpty(item))
return null;
if (EcoEnchantsSupport.hasSupport()) {
item = EcoEnchantsSupport.manageItem(item);
}
return item;
}
public static ChatAction getChatAction(ItemSlot slot, Player p) {
if(slot.isCommand()) {
return new ChatAction(slot, "/chatitem seeinv " + slot.name().toLowerCase() + " " + p.getUniqueId());
}
return new ChatAction(slot, getUsableItem(p, slot));
}
/**
* 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;
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);
}
return replacer.replace(NAME, NamerManager.getName(p, item, c));
}
/**
* 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 ItemSlot.HAND.getPlaceholders().get(0);
else
return c.handName;
}
return styleItem(p, item, c);
}
public static String getNameForChatAction(Player p, ChatAction action, Storage c) {
if(action.isItem()) {
ItemStack item = action.getItem();
if (ItemUtils.isEmpty(item)) {
if (c.handDisabled)
return ItemSlot.HAND.getPlaceholders().get(0);
else
return c.handName;
}
return styleItem(p, item, c);
}
return "";
}
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, ItemSlot slot, @Nullable Cancellable e) {
if(item == null)
return false;
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 (slot.isDenyIfNoItem()) {
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;
}
}
}
for (String ignored : c.ignoredItems) {
if (item.getType().name().toLowerCase().contains(ignored.toLowerCase())) {
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);
}
public static boolean isTestingEnabled() {
return inTest != null;
}
public static boolean isTesting(String actual) {
return inTest != null && (inTest == "both" || inTest.equalsIgnoreCase(actual));
}
public static void setTesting(String actual) {
inTest = actual;
}
}
@@ -0,0 +1,38 @@
package me.dadus33.chatitem.chatmanager;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ItemSlot;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Version;
public class HandItem {
@SuppressWarnings("deprecation")
public static ItemStack getBetterItem(Player p, ItemSlot slot) {
switch (slot) {
case HAND:
if(Version.getVersion().isNewerOrEquals(Version.V1_9)) {
ItemStack main = p.getInventory().getItemInMainHand();
if(!ItemUtils.isEmpty(main))
return main;
return p.getInventory().getItemInOffHand();
}
return p.getItemInHand();
case HELMET:
return p.getInventory().getHelmet();
case CHESTPLATE:
return p.getInventory().getChestplate();
case LEGGINGS:
return p.getInventory().getLeggings();
case BOOTS:
return p.getInventory().getBoots();
case ENDERCHEST:
break;
case INVENTORY:
break;
}
return null; // should never happen
}
}
@@ -1,93 +1,139 @@
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.Storage;
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.utils.Storage;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Utils;
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);
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;
}
packetManager = new ChatItemPacketManager(pl);
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 {
Object packet = internalCreateSystemChatPacket(json);
if(packet != null)
return packet;
packet = internalCreateSystemChatPacket(PacketUtils.ICB_FROM_JSON.invoke(null, json));
if(packet != null)
return packet;
ChatItem.getInstance().getLogger().warning("Can't create a new packet for json " + json);
return null;
}
private static Object internalCreateSystemChatPacket(Object obj) throws Exception {
Class<?> packetClass = PacketUtils.getNmsClass("ClientboundPlayerChatPacket", "network.protocol.game.", "ClientboundSystemChatPacket", "PacketPlayOutChat");
Class<?> chatMessageTypeClass = PacketUtils.isClassExist("net.minecraft.network.chat.ChatMessageType") ? PacketUtils.getNmsClass("ChatMessageType", "network.chat.") : null;
Constructor<?> betterOne = null;
Object[] betterParam = null;
for (Constructor<?> cons : packetClass.getDeclaredConstructors()) {
if (!cons.isAccessible())
cons.setAccessible(true);
// check for basic method
if(obj instanceof String) {
if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].equals(String.class) && cons.getParameterTypes()[1].equals(int.class)) { // "string, int"
return cons.newInstance(obj, 1);
} else if (cons.getParameterCount() == 2 && cons.getParameterTypes()[0].equals(String.class) && cons.getParameterTypes()[1].equals(boolean.class)) { // "string, boolean"
return cons.newInstance(obj, false); // false for no overlay
} 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, obj, 1);
else if (secondParam.equals(boolean.class)) // "component", "string", "boolean"
return cons.newInstance(null, obj, false);
}
}
int nbPut = 0;
Object[] params = new Object[cons.getParameterCount()];
for(int i = 0; i < params.length; i++) {
if(cons.getParameterTypes()[i].isAssignableFrom(obj.getClass())) {
params[i] = obj;
nbPut++;
} else if(chatMessageTypeClass != null && cons.getParameterTypes()[i].isAssignableFrom(chatMessageTypeClass)) {
params[i] = getChatMessageType();
} else if(cons.getParameterTypes()[i].isAssignableFrom(boolean.class)) // need to set primitives
params[i] = false;
else if(cons.getParameterTypes()[i].isAssignableFrom(int.class)) // need to set primitives
params[i] = 0;
}
if(nbPut == 1) {
if((betterOne == null && betterParam == null) || betterParam.length > params.length) {
betterOne = cons;
betterParam = params;
if(params.length == 1) // only what we need
break;
continue; // check for something better?
}
} else if(nbPut > 1)
ChatItem.getInstance().getLogger().warning("Some constructor seems to have too many " + obj.getClass().getSimpleName() + ". Class: " + packetClass.getSimpleName());
}
if(betterOne != null && betterParam != null) {
try {
return betterOne.newInstance(betterParam);
} catch (IllegalArgumentException e) {
ChatItem.getInstance().getLogger().warning("Failed to create a new packet to send. " + betterOne.getParameterCount() + " (" + Utils.arrayToString(betterOne.getParameterTypes()) + "). Params: " + Utils.arrayToString(betterParam));
return null;
}
}
return null;
}
private static Object getChatMessageType() throws Exception {
Class<?> c = PacketUtils.getNmsClass("ChatMessageType", "network.chat.");
return ReflectionUtils.getMethod(c, c, byte.class).invoke(null, (byte) 0);
}
}
@@ -0,0 +1,130 @@
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.Storage;
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.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, String json, Storage c) throws Exception {
String message;
if (Utils.isBeforeChatJson(p))
message = JSONManipulator.getInstance().parseEmpty(json, ChatManager.styleItem(chat.getPlayer(), item, c), ChatManager.getMaxLinesFromItem(p, item), chat.getPlayer());
else
message = JSONManipulator.getInstance().parse(chat, json, chat.getAction(), ChatManager.styleItem(chat.getPlayer(), item, c));
if (message != null) {
ChatItem.debug("(v1) Writing message: " + message);
writeJson(packet, message);
}
return packet.getPacket();
}
default Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, String json, Storage c) {
String message = JSONManipulator.getInstance().parseEmpty(json, 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 id != "" && Utils.isInteger(id) && Chat.getChat(Integer.parseInt(id)).isPresent();
}
}
}
@@ -0,0 +1,148 @@
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.JsonParseException;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatAction;
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.hook.DiscordSrvSupport;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.PacketUtils;
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.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.TextColor;
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 (Throwable 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;
try {
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;
} catch (JsonParseException e) { // ignore this and just let skip this
return null;
}
}
@Override
public Object manageItem(Player p, Chat chat, ChatItemPacket packet, ItemStack item, String json, Storage c) throws Exception {
ChatAction action = chat.getAction();
if (action.isItem()) {
String itemName = ChatManager.getNameOfItem(chat.getPlayer(), item, c);
ChatItem.debug("NBT tag: " + PacketUtils.getNbtTag(item));
return manage(p, chat, packet, itemName, HoverEvent.showItem(Key.key(item.getType().getKey().getKey()), item.getAmount(), BinaryTagHolder.of(PacketUtils.getNbtTag(item))), null);
}
return manage(p, chat, packet, Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName()),
HoverEvent.showText(Component.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName()))),
ClickEvent.runCommand(action.getCommand()));
}
@Override
public Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, String json, Storage c) {
Component builder = Component.text("");
c.tooltipHand.forEach(s -> builder.append(Component.text(s)));
Player sender = chat.getPlayer();
ChatAction action = chat.getAction();
if (action.isItem()) {
String handName = c.handName.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName());
return manage(p, chat, packet, handName, HoverEvent.showText(builder), null);
}
return manage(p, chat, packet, Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName()),
HoverEvent.showText(Component.text(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName()))),
ClickEvent.runCommand(action.getCommand()));
}
private Object manage(Player p, Chat chat, ChatItemPacket packet, String replacement, HoverEvent<?> hover, ClickEvent click) {
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, click, replacement, chat);
if(ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage())
DiscordSrvSupport.sendChatMessage(p, comp, null);
ChatItem.debug("Result: " + GsonComponentSerializer.gson().serialize(comp));
packet.getContent().getSpecificModifier(Component.class).write(0, comp);
/*try {
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(GsonComponentSerializer.gson().serialize(comp)));
} catch (Exception e) {
e.printStackTrace();
}*/
return packet.getPacket();
}
private Component checkComponent(Component comp, HoverEvent<?> hover, ClickEvent click, 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);
TextColor color = tc.color();
comp = tc.content(ChatManager.replaceSeparator(chat, tc.content(), itemName)).hoverEvent(hover);
if (click != null)
comp.clickEvent(click);
comp.append(Component.text("").color(color)); // reset color
} 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, click, 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, click, itemName, chat));
}
return comp.children(next);
}
}
@@ -0,0 +1,46 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import com.google.gson.JsonParser;
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.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().getChatComponents().readSafely(0);
if (chatBaseComp != null) {
try {
Object o = PacketUtils.CHAT_SERIALIZER.getMethod("a", PacketUtils.COMPONENT_CLASS).invoke(null, chatBaseComp);
if(o != null && o instanceof String && JsonParser.parseString((String) o).isJsonObject()) {
return (String) o;
}
} catch (Exception exc) {
exc.printStackTrace();
}
}
return null;
}
@Override
public void writeJson(ChatItemPacket packet, String json) {
// Not compatible with that for now
//if(ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage())
// DiscordSrvSupport.sendChatMessage(p, comp, null);
try {
PacketUtils.printPacketToDebug(packet.getPacket());
PacketUtils.printPacketToDebug(PacketEditingChatManager.createSystemChatPacket(json));
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json));
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,56 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.lang.reflect.Method;
import me.dadus33.chatitem.ChatItem;
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.PacketUtils;
public class IChatBaseComponentManager implements IComponentManager {
private Method serializerGetJson;
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 {
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(json));
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,68 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.lang.reflect.Constructor;
import java.util.Arrays;
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.ContentModifier;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
public class PCMComponentManager implements IComponentManager {
@Override
public boolean hasConditions() {
try {
for (String cl : Arrays.asList("net.minecraft.network.chat.PlayerChatMessage"))
Class.forName(cl);
} catch (Exception e) { // can't support this
ChatItem.debug("Can't load PCMComponentManager : " + e.getMessage());
return false;
}
return true;
}
@Override
public String getBaseComponentAsJSON(ChatItemPacket packet) {
Class<?> pcmClass = PacketUtils.getNmsClass("PlayerChatMessage", "network.chat.");
Object pcm = packet.getContent().getSpecificModifier(pcmClass).readSafely(0);
if (pcm != null) {
try {
Object chatBaseComp = ReflectionUtils.getMethod(pcmClass, PacketUtils.COMPONENT_CLASS).invoke(pcm);
if(chatBaseComp != null)
ChatItem.debug("[PCMManager] Founded " + chatBaseComp.getClass().getSimpleName());
return chatBaseComp == null ? null : 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 {
Object chatComp = PacketUtils.CHAT_SERIALIZER.getMethod("a", String.class).invoke(null, json);
Class<?> pcmClass = PacketUtils.getNmsClass("PlayerChatMessage", "network.chat.");
ContentModifier<Object> pcmModifier = packet.getContent().getSpecificModifier((Class<Object>) pcmClass);
Object pcm = ReflectionUtils.getMethod(pcmClass, pcmClass, PacketUtils.COMPONENT_CLASS).invoke(pcmModifier.readSafely(0), chatComp);
for(Constructor<?> cons : packet.getPacket().getClass().getConstructors()) {
if(cons.getParameterCount() <= 1)
continue;
Object[] params = new Object[cons.getParameterCount()];
for(int i = 0; i < params.length; i++) {
Class<?> cls = cons.getParameterTypes()[i];
if(cls.equals(pcmClass)) {
params[i] = pcm;
} else
params[i] = packet.getContent().getSpecificModifier(cls).readSafely(0);
}
packet.setPacket(cons.newInstance(params));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,157 @@
package me.dadus33.chatitem.chatmanager.v1.basecomp.hook;
import java.util.Arrays;
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.Storage;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatAction;
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.hook.DiscordSrvSupport;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.Utils;
import net.md_5.bungee.api.chat.BaseComponent;
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.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, String json, Storage c) throws Exception {
ChatAction action = chat.getAction();
if (action.isItem())
return manage(p, chat, packet, ChatManager.getNameOfItem(chat.getPlayer(), item, c), Utils.createItemHover(item, p), null);
else
return manage(p, chat, packet, ChatManager.getNameOfItem(chat.getPlayer(), item, c),
Utils.createTextHover(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName())),
Utils.createRunCommand(action.getCommand()));
}
@Override
public Object manageEmpty(Player p, Chat chat, ChatItemPacket packet, String json, Storage c) {
ComponentBuilder builder = new ComponentBuilder("");
c.tooltipHand.forEach(s -> builder.append(s));
Player sender = chat.getPlayer();
HoverEvent hover;
ClickEvent click;
String rep;
ChatAction action = chat.getAction();
if (action.isItem()) {
hover = Utils.createTextHover(builder.create());
rep = c.handName.replace("{name}", sender.getName()).replace("{display-name}", sender.getDisplayName());
click = null;
} else {
hover = Utils.createTextHover(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover", "%cible%", chat.getPlayer().getName()));
rep = Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", chat.getPlayer().getName());
click = Utils.createRunCommand(action.getCommand());
}
return manage(p, chat, packet, rep, hover, click);
}
private Object manage(Player p, Chat chat, ChatItemPacket packet, String replacement, HoverEvent hover, ClickEvent click) {
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();
}
ChatItem.debug("[StringComponentManager] Using JSON " + json);
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, click, replacement, chat));
if(ChatItem.discordSrvSupport && DiscordSrvSupport.isSendingMessage())
DiscordSrvSupport.sendChatMessage(p, TextComponent.toLegacyText(components), null);
try {
packet.setPacket(PacketEditingChatManager.createSystemChatPacket(ComponentSerializer.toString(components)));
} catch (Exception e) {
e.printStackTrace();
}
return packet.getPacket();
}
private void checkComponent(BaseComponent comp, HoverEvent hover, ClickEvent click, String itemName, Chat chat) {
if (comp instanceof TextComponent) {
TextComponent tc = (TextComponent) comp;
if (ChatManager.containsSeparator(tc.getText())) {
String oldText = tc.getText();
ChatItem.debug("Changing text " + oldText + " to " + itemName + ", extra: " + (tc.getExtra() == null ? "-" : tc.getExtra().size()));
tc.setText(ChatManager.replaceSeparator(chat, oldText, itemName));
tc.setHoverEvent(hover);
if (click != null)
tc.setClickEvent(click);
} 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, click, itemName, chat);
}
}
}
}
@@ -1,14 +1,296 @@
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.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.Chat;
import me.dadus33.chatitem.chatmanager.ChatAction;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
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 JsonArray classicTooltip;
public String parse(Chat chat, String json, ChatAction action, String replacement) throws Exception {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
JsonObject wrapper = new JsonObject(); // Create a wrapper object for the whole array
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();
if (action.isItem()) {
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(action.getItem()));
} else {
hover.addProperty("action", "show_text");
// Get the JSON representation of the item (well, not really JSON, but rather a
// string representation of NBT data)
hover.addProperty("value", parseEmpty(json, replacement, Arrays.asList(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover")), chat.getPlayer()));
JsonObject click = new JsonObject();
click.addProperty("action", "run_command");
click.addProperty("value", action.getCommand());
wrapper.add("clickEvent", click);
}
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);
if (obj.size() == 1 && obj.has("text")) {
wrapper.add("text", obj.get("text"));
ChatItem.debug("[JsonManipulator] Parsed quick: " + obj.toString() + ", wrapper: " + wrapper);
return ChatManager.replaceSeparator(chat, wrapper.toString(), replacement);
}
obj.add("extra", parseArray(obj.has("extra") ? obj.getAsJsonArray("extra") : new JsonArray(), wrapper));
if (!obj.has("text")) {
obj.addProperty("text", "");
}
ChatItem.debug("Parsed array for item: " + obj.toString() + ", wrapper: " + wrapper);
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) {
if(ChatManager.containsSeparator(element.getAsString())) {
addParsedStringToArray(element.getAsString(), replacer, element, tooltip);
} else
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,946 +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", "deprecation"})
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;
}
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,282 +0,0 @@
package me.dadus33.chatitem.chatmanager.v1.listeners;
import static me.dadus33.chatitem.chatmanager.ChatManager.SEPARATOR;
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 me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.PacketEditingChatManager;
import me.dadus33.chatitem.utils.Storage;
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) {
this.manage = manage;
}
public Storage getStorage() {
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
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);
}
boolean found = false;
final String oldMsg = e.getMessage();
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");
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) {
s = s.replace(placeholder, firstPlaceholder);
}
int occurrences = countOccurrences(firstPlaceholder, s);
if (occurrences > getStorage().LIMIT) {
e.setCancelled(true);
ChatItem.debug("(v1) Reach message limit");
if (getStorage().LIMIT_MESSAGE.isEmpty()) {
return;
}
e.getPlayer().sendMessage(getStorage().LIMIT_MESSAGE);
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);
}
}
}
@@ -1,14 +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.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
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;
@@ -18,269 +18,184 @@ 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.Storage;
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.PCMComponentManager;
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;
import net.md_5.bungee.api.chat.BaseComponent;
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 ComponentNMSManager(), new PCMComponentManager())) {
tryRegister(getter);
}
try {
Class.forName("net.kyori.adventure.text.Component");
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);
else
ChatItem.debug("Component " + getter.getClass().getSimpleName() + " doesn't answer conditions");
}
@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;
}
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)) {
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
}
} 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
}
}
boolean usesBaseComponents = false;
if(ChatManager.isTestingEnabled() && !ChatManager.isTesting("packet"))
return;
if (lastSentPacket != null && lastSentPacket == e.getPacket())
return; // prevent infinite loop
ChatItem.debug("Checking: " + e.getPacket().getClass().getSimpleName() + " to " + e.getPlayername());
PacketContent packet = e.getContent();
Version version = Version.getVersion();
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) {
Object chatBaseComp = packet.getSpecificModifier(PacketUtils.COMPONENT_CLASS).readSafely(0);
if(chatBaseComp == null) {
ChatItem.debug("No base components, without chat base comp");
return;
} else {
ChatItem.debug("No base components, with chatbasecomp: " + chatBaseComp);
try {
json = PacketUtils.CHAT_SERIALIZER.getMethod("a", PacketUtils.COMPONENT_CLASS).invoke(null, e.getPacket()).toString();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} else
json = ComponentSerializer.toString(components);
usesBaseComponents = true;
} else {
try {
json = (String) serializerGetJson.invoke(null, packet.getChatComponents().readSafely(0));
} catch (Exception exc) {
exc.printStackTrace();
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
} else
ChatItem.debug("Null JSON for manager " + getters.getClass().getSimpleName());
}
}
boolean found = false;
for (String rep : getStorage().PLACEHOLDERS) {
if (json.contains(rep)) {
found = true;
break;
}
if (json == null || choosedGetter == null) {
ChatItem.debug("Can't find valid json getter or json itself");
ChatItem.debug("String: " + packet.getStrings().getContent());
PacketUtils.printPacketToDebug(e.getPacket());
return; // can't find something
}
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
return;
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;
}
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)
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 itemPlayer = chat.getPlayer();
if (getStorage().cooldown > 0 && !itemPlayer.hasPermission("chatitem.ignore-cooldown"))
ChatManager.applyCooldown(itemPlayer);
IComponentManager getter = choosedGetter;
String fjson = json;
ChatItem.debug("Final json used: " + fjson);
e.setCancelled(true); // We cancel the packet as we're going to resends it anyways
CompletableFuture.runAsync(() -> {
Player p = e.getPlayer();
String message = null;
try {
if (!ItemUtils.isEmpty(p.getItemInHand())) {
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, chat.getSlot());
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(message != null) {
getter.writeJson(e, message);
}
lastSentPacket = e.getPacket();
}
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, fjson, 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, fjson, 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);
} catch (Exception e) {
e.printStackTrace();
}
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) {
@@ -300,7 +215,6 @@ public class ChatPacketManager extends PacketHandler {
i.setItemMeta(im);
}
public Storage getStorage() {
return manager.getStorage();
}
@@ -1,33 +0,0 @@
package me.dadus33.chatitem.chatmanager.v1.listeners;
import org.bukkit.Bukkit;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
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.utils.Version;
public class HandshakeListener extends PacketAdapter {
public HandshakeListener(ChatItem pl) {
super(pl, ListenerPriority.MONITOR, PacketType.Handshake.Client.SET_PROTOCOL);
}
@Override
public void onPacketReceiving(final PacketEvent e){
if(e.isPlayerTemporary() || e.getPlayer() == null)
return;
PacketType.Protocol p = e.getPacket().getProtocols().read(0);
if(p == PacketType.Protocol.STATUS || p == PacketType.Protocol.LEGACY){
return;
}
final int version = e.getPacket().getIntegers().readSafely(0);
//Delay the mapping to make sure the true address of the player was received when using bungeecord or other types of proxies
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), () ->
DefaultVersionHook.PROTOCOL_PER_ADDRESS.put(Version.stringifyAdress(e.getPlayer().getAddress()), version), 10L);
}
}
@@ -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,7 @@ public class PacketContent {
} else {
content.put(key, value);
try {
key.setAccessible(true);
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
@@ -1,8 +1,8 @@
package me.dadus33.chatitem.chatmanager.v1.packets.custom;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -39,11 +39,11 @@ public class CustomPacketManager extends PacketManager implements Listener {
pl.getServer().getPluginManager().registerEvents(this, pl);
// we wait the start server
Bukkit.getScheduler().runTaskLater(pl, () -> {
CompletableFuture.runAsync(() -> {
isStarted = true;
for(Player p : Utils.getOnlinePlayers())
addPlayer(p);
}, 20);
});
}
public Plugin getPlugin() {
@@ -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,7 +26,6 @@ public class INC2Channel extends ChannelAbstract {
private final ChannelInboundHandler boundHandler;
private ChannelPipeline pipeline;
@SuppressWarnings("unchecked")
public INC2Channel(CustomPacketManager customPacketManager) {
super(customPacketManager);
boundHandler = new ChannelInboundHandler(customPacketManager);
@@ -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)");
@@ -93,8 +87,8 @@ 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);
Object networkManager = ReflectionUtils.getFirstWith(playerConnection, PacketUtils.getNmsClass("NetworkManager", "network."));
return ReflectionUtils.getFirstWith(networkManager, 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.getObject(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;
@@ -12,7 +13,6 @@ import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.listeners.HandshakeListener;
import me.dadus33.chatitem.chatmanager.v1.packets.ChatItemPacket;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketManager;
import me.dadus33.chatitem.chatmanager.v1.packets.PacketType;
@@ -23,21 +23,28 @@ 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());
}
});
protocolManager.addPacketListener(new HandshakeListener(pl));
}
@Override
@@ -1,22 +0,0 @@
package me.dadus33.chatitem.chatmanager.v1.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.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);
}
}
@@ -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<>();
@@ -3,11 +3,12 @@ package me.dadus33.chatitem.chatmanager.v2;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -16,37 +17,31 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.ItemPlayer;
import me.dadus33.chatitem.ItemSlot;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.chatmanager.Chat;
import me.dadus33.chatitem.chatmanager.ChatAction;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.dadus33.chatitem.hook.DiscordSrvSupport;
import me.dadus33.chatitem.itemnamer.NamerManager;
import me.dadus33.chatitem.playernamer.PlayerNamerManager;
import me.dadus33.chatitem.utils.ColorManager;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ReflectionUtils;
import me.dadus33.chatitem.utils.Storage;
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 {
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;
private boolean shouldUseAppendMethod = false;
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.");
@@ -66,59 +61,38 @@ public class ChatListener implements Listener {
} catch (Exception e) {
}
String appendMethodMsg = shouldUseAppendMethod ? "Use ComponentBuilder's method."
: "Use own ComponentBuilder append method.";
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. " + appendMethodMsg);
log.info("Failed to find save method. Using default system. " + appendMethodMsg);
else
ChatItem.getInstance().getLogger()
.info("Save method founded: " + saveMethod.getName() + ". " + appendMethodMsg);
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.MONITOR)
public void onChat(AsyncPlayerChatEvent e) {
if(ChatManager.isTestingEnabled() && !ChatManager.isTesting("chat"))
return;
Storage c = getStorage();
if (e.isCancelled()) {
if (ChatItem.getInstance().getChatManager().size() == 1) { // only chat
String msg = e.getMessage().toLowerCase();
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");
return;
for(ItemSlot slot : ItemSlot.values()) {
for (String rep : slot.getPlaceholders()) {
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");
return;
}
}
}
}
@@ -126,232 +100,160 @@ public class ChatListener implements Listener {
return;
}
Player p = e.getPlayer();
boolean found = false, hasv1 = false;
for (String rep : c.PLACEHOLDERS) {
// v1 try to manage it, but the message have not been changed by another plugin
if (e.getMessage().contains(rep + ChatManager.SEPARATOR + p.getName())) {
hasv1 = true;
found = true;
ChatItem.debug("Found v1 placeholders in v2");
break;
}
if (e.getMessage().contains(rep)) {
found = true;
break;
}
if(ChatManager.containsSeparator(e.getMessage())) { // fix for v1
Chat chat = Chat.getFrom(e.getMessage());
if(chat != null)
e.setMessage(ChatManager.replaceSeparator(chat, e.getMessage(), chat.getSlot().getPlaceholders().get(0)));
}
if (!found) {
ItemSlot slot = ItemSlot.getItemSlotFromMessage(e.getMessage());
if (slot == null) { // if not found
ChatItem.debug("(v2) Can't found placeholder in: " + e.getMessage() + " > " + PlayerNamerManager.getPlayerNamer().getName(p));
return;
}
if (c.PERMISSION_ENABLED && !p.hasPermission(c.PERMISSION_NAME)) {
if (!getStorage().LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!c.NO_PERMISSION_MESSAGE.isEmpty() && c.SHOW_NO_PERM_NORMAL) {
p.sendMessage(c.NO_PERMISSION_MESSAGE);
}
ChatAction action = ChatManager.getChatAction(slot, p);
if(action.isItem() && !ChatManager.canShowItem(p, action.getItem(), slot, e))
return;
}
if (p.getItemInHand().getType().equals(Material.AIR)) {
if (c.DENY_IF_NO_ITEM) {
e.setCancelled(true);
if (!c.DENY_MESSAGE.isEmpty())
e.getPlayer().sendMessage(c.DENY_MESSAGE);
return;
}
if (c.HAND_DISABLED) {
return;
}
}
if (c.COOLDOWN > 0 && !p.hasPermission("chatitem.ignore-cooldown")) { // use 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 (!c.LET_MESSAGE_THROUGH) {
e.setCancelled(true);
}
if (!c.COOLDOWN_MESSAGE.isEmpty()) {
long left = (start + c.COOLDOWN) - current;
p.sendMessage(c.COOLDOWN_MESSAGE.replace(LEFT, calculateTime(left)));
}
return;
}
}
COOLDOWNS.put(p.getName(), System.currentTimeMillis() / 1000);
}
e.setCancelled(true);
String format = e.getFormat();
String msg, defMsg = e.getMessage();
for (String rep : c.PLACEHOLDERS) {
if (hasv1)
defMsg = defMsg.replace(rep + ChatManager.SEPARATOR + p.getName(), ChatManager.SEPARATOR + ""); // remove
// v1
// char
else
defMsg = defMsg.replace(rep, ChatManager.SEPARATOR + "");
String defMsg = slot.replacePlaceholdersToSeparator(e.getMessage());
if (Utils.countMatches(defMsg, Character.toString(ChatManager.SEPARATOR)) > getStorage().limit) {
if (!getStorage().messageLimit.isEmpty())
p.sendMessage(getStorage().messageLimit);
return;
}
String msg;
if (format.contains("%1$s") || format.contains("%2$s")) {
ChatItem.debug("Begin def msg: " + defMsg + "");
msg = (format.contains("%2$s") ? String.format(format, p.getDisplayName(), defMsg)
: String.format(format, p.getDisplayName()));
msg = (format.contains("%2$s") ? String.format(format, p.getDisplayName(), defMsg) : String.format(format, p.getDisplayName()));
} else {
msg = format.replace(e.getMessage(), defMsg);
}
ItemStack item = p.getItemInHand();
String itemName = ItemUtils.isEmpty(item) ? (c.HAND_DISABLED ? c.PLACEHOLDERS.get(0) : c.HAND_NAME)
: styleItem(p, item, c);
String loggedMessage = msg.replace(ChatManager.SEPARATOR + "", itemName).replace("{name}", p.getName())
.replace("{display-name}", p.getDisplayName());
String itemName = ChatManager.getNameForChatAction(p, action, 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, loggedMessage);
ChatItem.debug("Msg: " + msg.replace(ChatColor.COLOR_CHAR, '&') + ", format: " + format);
e.getRecipients().forEach((pl) -> showItem(pl, p, item, msg));
DiscordSrvSupport.sendChatMessage(p, defMsg.replace(ChatManager.SEPARATOR + "", itemName).replace("{name}", p.getName()).replace("{display-name}", p.getDisplayName()), e);
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, action, msg));
if (c.cooldown > 0 && !p.hasPermission("chatitem.ignore-cooldown"))
ChatManager.applyCooldown(p);
}
private void showItem(Player to, Player origin, ItemStack item, String msg) {
public static void showItem(Player to, Player origin, ChatAction action, String msg) {
ComponentBuilder builder = new ComponentBuilder("");
ChatColor color = ChatColor.RESET;
ChatColor color = ChatColor.WHITE;
String colorCode = "", text = "";
boolean waiting = false, isHex = false;
boolean waiting = false, removing = false;
for (char args : msg.toCharArray()) {
if (args == '§') { // begin of color
if (colorCode.isEmpty() && !text.isEmpty()) { // text before this char
ChatItem.debug("Append " + text);
appendToComponentBuilder(builder, new ComponentBuilder(text).color(color).create());
ChatItem.debug("Append '" + text.replace(ChatColor.COLOR_CHAR, '&') + "' (len: " + text.length() + ")");
if(text.length() > 2 && text.startsWith("§") && text.substring(2) == ChatColor.stripColor(text)
&& color != null && color != ChatColor.WHITE) {
text = text.substring(2); // remove some code which should not be here
}
appendToComponentBuilder(builder, createComponent(to, text, color, action));
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()) {
if (args == 'r' && colorCode.isEmpty()) {
color = ChatColor.RESET;
continue;
} else if(args == 'x') {
if(!colorCode.isEmpty()) {
color = ColorManager.getColor(colorCode);
colorCode = ""; // clean for previous things
}
}
if(args == 'x' && colorCode.isEmpty())
isHex = true;
colorCode += args; // a color by itself
colorCode += args;
} else {
waiting = false;
if(!colorCode.isEmpty()) {
if(isHex && colorCode.length() >= 7)
color = ColorManager.getColor(colorCode);
else if(colorCode.length() == 1) // if only one color code
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
&& (!getStorage().HAND_DISABLED || (item != null && item.hasItemMeta()))) {
if (args == ChatManager.SEPARATOR) {
// here put the item
appendToComponentBuilder(builder, new ComponentBuilder(text).color(color).create());
addItem(builder, to, origin, item);
appendToComponentBuilder(builder, fixColorComponent(to, text, color, action));
if(action.isItem())
addItem(builder, to, origin, action.getItem(), action);
else
addCommand(builder, to, origin, action.getCommand(), action);
text = "";
} else {
if(ChatManager.containsSeparatorEnd(msg))
removing = true;
} else if(args == ChatManager.SEPARATOR_END) {
removing = false;
} else if(!removing) { // not removing content
// basic text, not waiting for code after '§'
text += args;
}
}
}
if(!text.isEmpty())
appendToComponentBuilder(builder, new ComponentBuilder(text).color(color).create());
if (!text.isEmpty())
appendToComponentBuilder(builder, createComponent(to, text, color, action));
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();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void addItem(ComponentBuilder builder, Player to, Player origin, ItemStack item) {
public static void addItem(ComponentBuilder builder, Player to, Player origin, ItemStack item, ChatAction action) {
Storage c = ChatItem.getInstance().getStorage();
if (!ItemUtils.isEmpty(item)) {
ComponentBuilder itemComponent = new ComponentBuilder(ChatListener.styleItem(to, item, getStorage()));
String itemJson = convertItemStackToJson(item);
itemComponent.event(new HoverEvent(Action.SHOW_ITEM, new ComponentBuilder(itemJson).create()));
ComponentBuilder itemComponent = new ComponentBuilder("");
appendToComponentBuilder(itemComponent, fixColorComponent(to, ChatManager.getNameOfItem(to, item, c), ChatColor.WHITE, action));
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 = getStorage().HAND_NAME;
String handName = c.handName;
ComponentBuilder handComp = new ComponentBuilder("");
ComponentBuilder handTooltip = new ComponentBuilder("");
int stay = getStorage().HAND_TOOLTIP.size();
for (String line : getStorage().HAND_TOOLTIP) {
int stay = c.tooltipHand.size();
for (String line : c.tooltipHand) {
stay--;
handTooltip.append(
line.replace("{name}", origin.getName()).replace("{display-name}", origin.getDisplayName()));
handTooltip.append(ColorManager.fixColor(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\\}");
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("{display-name}", origin.getDisplayName()));
handComp.append(handName.replace("{name}", origin.getName()));
appendToComponentBuilder(builder, handComp.create());
}
}
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, "");
}
} else {
amount = amount.replace(TIMES, String.valueOf(item.getAmount()));
replacer = replacer.replace(AMOUNT, amount);
}
replacer = replacer.replace(NAME, NamerManager.getName(p, item, c));
return replacer;
public static void addCommand(ComponentBuilder builder, Player to, Player origin, String command, ChatAction action) {
ComponentBuilder itemComponent = new ComponentBuilder("");
appendToComponentBuilder(itemComponent, fixColorComponent(to, Messages.getMessage(action.getSlot().name().toLowerCase() + ".chat", "%cible%", origin.getName()), ChatColor.WHITE, action));
appendToComponentBuilder(builder, itemComponent.create());
}
@SuppressWarnings({ "unchecked" })
public void appendToComponentBuilder(ComponentBuilder builder, BaseComponent[] comps) {
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.");
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 {
@@ -366,4 +268,69 @@ public class ChatListener implements Listener {
}
}
}
public static BaseComponent[] fixColorComponent(Player to, String message, ChatColor color, ChatAction action) {
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(to, ColorManager.isHexColor(color) ? ColorManager.removeColorAtBegin(text) : text, color, action));
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(to, text, color, action));
}
return builder.create();
}
private static BaseComponent[] createComponent(Player to, String text, ChatColor color, ChatAction action) {
ComponentBuilder littleBuilder = new ComponentBuilder(text);
if(color != null && color != ChatColor.RESET) // don't add reset thing
littleBuilder.color(color);
if (action.isItem())
littleBuilder.event(Utils.createItemHover(action.getItem(), to));
else {
littleBuilder.event(Utils.createTextHover(Messages.getMessage(action.getSlot().name().toLowerCase() + ".hover")));
littleBuilder.event(Utils.createRunCommand(action.getCommand()));
}
return littleBuilder.create();
}
}
@@ -4,19 +4,15 @@ import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Storage;
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;
@@ -4,67 +4,172 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
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.InventoryShower;
import me.dadus33.chatitem.ItemSlot;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.chatmanager.ChatAction;
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;
import me.dadus33.chatitem.utils.Utils;
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;
public class ChatItemCommand implements CommandExecutor, TabExecutor {
@SuppressWarnings("deprecation")
private static final List<String> orders = Arrays.asList("packet", "chat", "both");
@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") && p.hasPermission("chatitem.reload")) {
InventoryListener.open(p);
} else if (args[0].equalsIgnoreCase("reload") && p.hasPermission("chatitem.reload")) {
ChatItem.reload(sender);
} else if (args[0].equalsIgnoreCase("show") && ChatItem.getInstance().getStorage().cmdShow) {
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, ItemSlot.HAND);
ChatListener.showItem(p, cible, new ChatAction(ItemSlot.HAND, item), c.commandFormat.replace("%name%", cible.getName()).replace("%item%", ChatManager.SEPARATOR + ""));
} else if (args[0].equalsIgnoreCase("broadcast") && ChatItem.getInstance().getStorage().cmdBroadcast) {
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, ItemSlot.HAND);
for(Player all : Bukkit.getOnlinePlayers())
ChatListener.showItem(all, cible, new ChatAction(ItemSlot.HAND, 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(Utils.createTextHover(hover));
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 if (args[0].equalsIgnoreCase("select") && p.hasPermission("chatitem.reload")) {
if(args.length == 1) {
p.sendMessage(ChatColor.GRAY + "----------" + ChatColor.GOLD + " ChatItem - Setup " + ChatColor.GRAY + "----------");
p.sendMessage(ChatColor.AQUA + "Welcome in the help of setup." + ChatColor.YELLOW + " Please follow step by simply answer to test.");
sendCheckSelectMessage(p, orders.get(0));
} else {
String tested = args[1];
if(!orders.contains(tested)) {
p.sendMessage(ChatColor.RED + "Unknow test for " + tested + ".");
return false;
}
if(args.length == 2) {
p.sendMessage(ChatColor.RED + "Can't find if it works");
return false;
}
if(args[2].equalsIgnoreCase("yes")) {
ChatManager.setTesting(null);
InventoryListener.setInConfig("manager", tested);
p.sendMessage(ChatColor.GREEN + "Perfect ! Updating config ...");
ChatItem.reload(p);
} else if(args[2].equalsIgnoreCase("no")) {
int index = orders.indexOf(tested);
if(orders.size() == (index + 1)) {
p.sendMessage(ChatColor.RED + "Sad. Sorry but nothing is available. I suggest you to come on discord for more help. Do '/chatitem link' for all links.");
ChatManager.setTesting(null);
} else {
p.sendMessage(ChatColor.RED + "Sad. Checking for next manager ...");
sendCheckSelectMessage(p, orders.get(index + 1));
}
} else {
p.sendMessage(ChatColor.RED + "Can't find if it works");
}
}
} else if (args[0].equalsIgnoreCase("seeinv")) {
if(args.length == 3 && Utils.isUUID(args[2])) {
Player cible = Bukkit.getPlayer(UUID.fromString(args[2]));
if(cible == null || !cible.isOnline()) {
Messages.sendMessage(p, "player-not-found", "%arg%", args[2]);
return false;
}
if(args[1].equalsIgnoreCase("inventory")) {
InventoryShower.showInventory(p, cible);
} else if(args[1].equalsIgnoreCase("enderchest")) {
InventoryShower.showEnderchest(p, cible);
}
} // else just ignore
} else {
Messages.sendMessage(p, "chatitem-cmd.help");
}
return false;
}
private void sendCheckSelectMessage(Player p, String testing) {
ChatManager.setTesting(testing);
p.chat("Checking for " + testing + ": [i]");
Bukkit.getScheduler().runTaskLater(ChatItem.getInstance(), () -> {
TextComponent text = new TextComponent(ChatColor.GOLD + "Did it worked fine? ");
TextComponent agree = new TextComponent(ChatColor.GREEN + "Yes");
agree.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/chatitem select " + testing + " yes"));
agree.setHoverEvent(Utils.createTextHover(ChatColor.GRAY + "Click to say it worked fine"));
text.addExtra(agree);
text.addExtra(" ");
TextComponent decline = new TextComponent(ChatColor.RED + "No");
decline.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/chatitem select " + testing + " no"));
decline.setHoverEvent(Utils.createTextHover(ChatColor.GRAY + "Click to say it's not working as expected"));
text.addExtra(decline);
p.spigot().sendMessage(text);
}, 2);
}
@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))
list.add(s);
return list.isEmpty() ? null : list;
if(arg.length <= 2) {
if(sender.hasPermission("chatitem.reload")) {
for (String s : Arrays.asList("admin", "reload", "select"))
if (prefix.isEmpty() || s.startsWith(prefix))
list.add(s);
}
if (ChatItem.getInstance().getStorage().cmdShow && (prefix.isEmpty() || "show".startsWith(prefix)))
list.add("show");
if (ChatItem.getInstance().getStorage().cmdBroadcast && (prefix.isEmpty() || "broadcast".startsWith(prefix)))
list.add("broadcast");
for (String s : Arrays.asList("help", "link"))
if (prefix.isEmpty() || s.startsWith(prefix))
list.add(s);
}
return list;
}
}
@@ -1,81 +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.ChatManager;
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(ChatManager.SEPARATOR + p.getName())) {
return Result.DENY;
}
}
}
}
return Result.NEUTRAL;
}
public void setStorage(Storage nst) {
this.c = nst;
}
}
@@ -0,0 +1,18 @@
package me.dadus33.chatitem.hook;
import me.dadus33.chatitem.ChatItem;
public class ChatControlSupport {
public static void init(ChatItem pl) {
try {
Class<?> clz = Class.forName("org.mineacademy.chatcontrol.settings.Settings$Chat$Grammar");
clz.getField("CAPITALIZE").setBoolean(null, false);
clz.getField("INSERT_DOT").setBoolean(null, false);
pl.getLogger().info("Loaded ChatControl support by disabling 2 options in 'Chat.Grammar' config.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,16 @@
package me.dadus33.chatitem.hook;
import java.util.List;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.ChatManager;
import me.h1dd3nxn1nja.chatmanager.Main;
public class ChatManagerSupport {
public static void init(ChatItem pl) {
List<String> whitelist = Main.settings.getConfig().getStringList("Anti_Unicode.Whitelist");
whitelist.add(ChatManager.SEPARATOR_STR);
whitelist.add(ChatManager.SEPARATOR_END_STR);
}
}
@@ -1,16 +1,31 @@
package me.dadus33.chatitem.hook;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import github.scarsz.discordsrv.DiscordSRV;
import me.dadus33.chatitem.ChatItem;
import net.kyori.adventure.text.Component;
public class DiscordSrvSupport {
public static boolean isSendingMessage() {
return ChatItem.getInstance().getStorage().discordSrvSendMsg;
}
public static void sendchatMessage(Player p, String message) {
public static void sendChatMessage(Player p, String message, Event e) {
DiscordSRV pl = DiscordSRV.getPlugin();
if (DiscordSRV.config().getBooleanElse("UseModernPaperChatEvent", false) && pl.isModernChatEventAvailable()) {
return;
}
pl.processChatMessage(p, message, pl.getOptionalChannel("global"), false);
pl.processChatMessage(p, message, pl.getOptionalChannel("global"), false, e);
}
public static void sendChatMessage(Player p, Component message, Event e) {
DiscordSRV pl = DiscordSRV.getPlugin();
if (DiscordSRV.config().getBooleanElse("UseModernPaperChatEvent", false) && pl.isModernChatEventAvailable()) {
return;
}
pl.processChatMessage(p, message, pl.getOptionalChannel("global"), false, e);
}
}
@@ -0,0 +1,56 @@
package me.dadus33.chatitem.hook.ecoenchants;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import me.dadus33.chatitem.ChatItem;
public class EcoEnchantsSupport {
private static int supportedVersion = 0;
public static boolean hasSupport() {
return supportedVersion > 0;
}
public static boolean load() {
String ver = Bukkit.getPluginManager().getPlugin("EcoEnchants").getDescription().getVersion();
if(ver.startsWith("8."))
supportedVersion = 8;
else if(ver.startsWith("10."))
supportedVersion = 10;
else if(ver.startsWith("11."))
supportedVersion = 11;
else if(ver.startsWith("12."))
supportedVersion = 12;
else {
ChatItem.getInstance().getLogger().warning("Failed to find support version for EcoEnchants " + ver);
return false;
}
return true;
}
public static ItemStack manageItem(ItemStack item) {
if(supportedVersion == 8) {
List<String> addLore = EcoEnchantsV8Support.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");
} else if(supportedVersion >= 10) {
EcoEnchantsV10Support.display(item);
}
return item;
}
}
@@ -0,0 +1,35 @@
package me.dadus33.chatitem.hook.ecoenchants;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.willfp.eco.core.display.DisplayProperties;
import com.willfp.ecoenchants.EcoEnchantsPlugin;
import com.willfp.ecoenchants.display.EnchantDisplay;
public class EcoEnchantsV10Support {
private static EnchantDisplay enchantDisplay;
public static EnchantDisplay getEnchantDisplay() {
if (enchantDisplay == null) {
try {
enchantDisplay = EnchantDisplay.class.getConstructor(EcoEnchantsPlugin.class).newInstance(Bukkit.getPluginManager().getPlugin("EcoEnchants"));
} catch (Exception e) {
e.printStackTrace();
}
}
return enchantDisplay;
}
public static void display(ItemStack item) {
try {
DisplayProperties display = DisplayProperties.class.getDeclaredConstructor(boolean.class, boolean.class, ItemStack.class).newInstance(false, false, item);
getEnchantDisplay().display(item, (Player) null, display, new Object[] { false });
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,21 @@
package me.dadus33.chatitem.hook.ecoenchants;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.inventory.ItemStack;
import com.willfp.ecoenchants.display.EnchantmentCache;
import com.willfp.ecoenchants.enchantments.util.EnchantChecks;
public class EcoEnchantsV8Support {
public static List<String> getLores(ItemStack item) {
List<String> lores = new ArrayList<>();
EnchantChecks.getEnchantsOnItem(item).forEach((en, lvl) -> {
lores.add(EnchantmentCache.getEntry(en).getNameWithLevel(lvl));
});
return lores;
}
}
@@ -7,7 +7,7 @@ import java.util.stream.Collectors;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.utils.Storage;
import me.dadus33.chatitem.Storage;
public interface INamer {
@@ -30,7 +30,7 @@ public interface INamer {
*/
String getName(Player p, ItemStack item, Storage storage);
public static enum Priority {
public 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());
}
}
}
@@ -11,12 +11,12 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginManager;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.itemnamer.INamer.Priority;
import me.dadus33.chatitem.itemnamer.hook.ChatItemTranslationNamer;
import me.dadus33.chatitem.itemnamer.hook.DefaultNamer;
import me.dadus33.chatitem.itemnamer.hook.ItemDisplayNamer;
import me.dadus33.chatitem.itemnamer.hook.LangUtilsNamer;
import me.dadus33.chatitem.utils.Storage;
public class NamerManager {
@@ -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) {
@@ -1,12 +1,11 @@
package me.dadus33.chatitem.itemnamer.hook;
import java.util.HashMap;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.Translation;
import me.dadus33.chatitem.itemnamer.INamer;
import me.dadus33.chatitem.utils.Storage;
public class ChatItemTranslationNamer implements INamer {
@@ -17,15 +16,7 @@ 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());
if (translationSection != null) {
@SuppressWarnings("deprecation")
String translated = translationSection.get(item.getDurability());
if (translated != null) {
return translated;
}
}
return null;
return Translation.get(item);
}
}
@@ -5,8 +5,8 @@ import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.itemnamer.INamer;
import me.dadus33.chatitem.utils.Storage;
public class DefaultNamer implements INamer {
@@ -4,8 +4,8 @@ import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.itemnamer.INamer;
import me.dadus33.chatitem.utils.Storage;
public class ItemDisplayNamer implements INamer {
@@ -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;
}
@@ -5,8 +5,8 @@ import org.bukkit.inventory.ItemStack;
import com.meowj.langutils.lang.LanguageHelper;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.itemnamer.INamer;
import me.dadus33.chatitem.utils.Storage;
public class LangUtilsNamer implements INamer {
@@ -12,19 +12,31 @@ import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Storage;
import me.dadus33.chatitem.Translation;
import me.dadus33.chatitem.listeners.holder.AdminHolder;
import me.dadus33.chatitem.listeners.holder.CustomInventoryHolder;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Messages;
import me.dadus33.chatitem.utils.Storage;
public class InventoryListener implements Listener {
@EventHandler
public void onClick(InventoryClickEvent e) {
if(e.getClickedInventory() == null || !(e.getWhoClicked() instanceof Player) || e.getCurrentItem() == null
|| !(e.getClickedInventory().getHolder() instanceof ChatItemAdminHolder))
if(e.getClickedInventory() == null || !(e.getWhoClicked() instanceof Player) || e.getCurrentItem() == null)
return;
InventoryHolder holder = e.getClickedInventory().getHolder();
if(holder == null)
return;
if(holder instanceof CustomInventoryHolder) {
e.setCancelled(true);
return;
}
if(!(holder instanceof AdminHolder))
return;
e.setCancelled(true);
Player p = (Player) e.getWhoClicked();
@@ -33,51 +45,52 @@ public class InventoryListener implements Listener {
Storage c = ChatItem.getInstance().getStorage();
if(type.equals(ItemUtils.MATERIAL_CLOSE)) {
p.closeInventory();
} else if(type.equals(Material.BOOK)) {
TranslationInventoryListener.open(p, 0);
} else if(type.equals(Material.PAPER)) {
ChatItemAdminHolder holder = (ChatItemAdminHolder) e.getClickedInventory().getHolder();
String key = holder.keyBySlot.get(e.getSlot());
String key = ((AdminHolder) holder).keyBySlot.get(e.getSlot());
if(key != null) {
setInConfig("manager", key);
p.closeInventory();
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);
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.color-if-already-colored", c.colorIfColored = !c.colorIfColored);
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.BLAZE_ROD)) {
setInConfig("general.check-update", c.checkUpdate = !c.checkUpdate);
open(p);
} else if(type.equals(ItemUtils.FIREWORK_CHARGE)) {
setInConfig("debug", c.DEBUG = !c.DEBUG);
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);
}
}
private void setInConfig(String key, Object val) {
public static void setInConfig(String key, Object val) {
ChatItem pl = ChatItem.getInstance();
pl.getConfig().set(key, val);
pl.saveConfig();
}
public static void open(Player p) {
ChatItemAdminHolder holder = new ChatItemAdminHolder();
AdminHolder holder = new AdminHolder();
Storage c = ChatItem.getInstance().getStorage();
Inventory inv = Bukkit.createInventory(holder, 27, Messages.getMessage("admin-inv.name"));
for(int i = 0; i < inv.getSize(); i ++)
@@ -88,15 +101,17 @@ 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(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(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.BLAZE_ROD, "check-update", c.checkUpdate));
inv.setItem(24, createItem(Material.BOOK, Messages.getMessage("admin-inv.language.name"),
Messages.getMessage("admin-inv.language.lore", "%name%", Translation.getMessages().get("language.name").getAsString())));
inv.setItem(26, createItem(ItemUtils.MATERIAL_CLOSE, Messages.getMessage("admin-inv.close")));
p.openInventory(inv);
@@ -4,16 +4,16 @@ 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 me.dadus33.chatitem.utils.Utils;
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;
public class JoinListener implements Listener {
@SuppressWarnings("deprecation")
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player p = e.getPlayer();
@@ -21,10 +21,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(Utils.createTextHover(pl.getStorage().updateHover));
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());
}
}
@@ -0,0 +1,95 @@
package me.dadus33.chatitem.listeners;
import static me.dadus33.chatitem.utils.ItemUtils.createItem;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Translation;
import me.dadus33.chatitem.listeners.holder.TranslationHolder;
import me.dadus33.chatitem.utils.ItemUtils;
import me.dadus33.chatitem.utils.Messages;
public class TranslationInventoryListener implements Listener {
@EventHandler
public void onClick(InventoryClickEvent e) {
if(e.getClickedInventory() == null || !(e.getWhoClicked() instanceof Player) || e.getCurrentItem() == null
|| !(e.getClickedInventory().getHolder() instanceof TranslationHolder))
return;
e.setCancelled(true);
Player p = (Player) e.getWhoClicked();
ItemStack item = e.getCurrentItem();
Material type = item.getType();
TranslationHolder holder = (TranslationHolder) e.getClickedInventory().getHolder();
if(type.equals(Material.ARROW)) {
if(e.getSlot() == 0)
InventoryListener.open(p);
else if(e.getSlot() == 3)
open(p, holder.getPage() - 1);
else if(e.getSlot() == 5)
open(p, holder.getPage() + 1);
} else if(type.equals(ItemUtils.MATERIAL_CLOSE))
p.closeInventory();
else if(type.equals(Material.PAPER)) {
String lang = holder.langBySlot.get(e.getSlot());
if(lang == null)
return;
p.closeInventory();
ChatItem pl = ChatItem.getInstance();
pl.getStorage().language = lang;
pl.getConfig().set("general.language", lang);
pl.saveConfig();
Translation.loadLang(lang);
p.sendMessage(ChatColor.GREEN + "Language changed to " + Translation.getMessages().get("language.name").getAsString());
}
}
public static void open(Player p, int page) {
int perPage = 45;
List<String> langs = new ArrayList<>(Translation.getAllLangs().keySet());
TranslationHolder holder = new TranslationHolder(page);
Inventory inv = Bukkit.createInventory(holder, 54, "Change language - " + ChatColor.GOLD + " Page " + (page + 1) + " / " + ((langs.size() / perPage) + 1));
for(int i = 0; i < 9; i ++)
inv.setItem(i, new ItemStack(ItemUtils.GRAY_STAINED_GLASS_PANE));
inv.setItem(0, createItem(Material.ARROW, ChatColor.GRAY + "Back"));
if(page > 0)
inv.setItem(3, createItem(Material.ARROW, ChatColor.RED + "Previous page"));
if(langs.size() > (perPage * (page + 1)))
inv.setItem(5, createItem(Material.ARROW, ChatColor.GREEN + "Next page"));
inv.setItem(8, createItem(ItemUtils.MATERIAL_CLOSE, Messages.getMessage("admin-inv.close")));
int slot = 9;
for(int i = (page * perPage); i < langs.size() && (i < ((page + 1) * perPage)); i++) {
String lang = langs.get(i);
holder.langBySlot.put(slot, lang);
ItemStack item = createItem(Material.PAPER, ChatColor.GOLD + Translation.getAllLangs().get(lang), ChatColor.GRAY + "Clic to select this language");
if(lang.equalsIgnoreCase(ChatItem.getInstance().getStorage().language)) {
item.addUnsafeEnchantment(Enchantment.DURABILITY, 1);
ItemMeta meta = item.getItemMeta();
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
item.setItemMeta(meta);
}
inv.setItem(slot++, item);
}
p.openInventory(inv);
}
}
@@ -1,11 +1,11 @@
package me.dadus33.chatitem.listeners;
package me.dadus33.chatitem.listeners.holder;
import java.util.HashMap;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
public class ChatItemAdminHolder implements InventoryHolder {
public class AdminHolder implements InventoryHolder {
public final HashMap<Integer, String> keyBySlot = new HashMap<>();
@@ -0,0 +1,13 @@
package me.dadus33.chatitem.listeners.holder;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
public class CustomInventoryHolder implements InventoryHolder {
@Override
public Inventory getInventory() {
return null;
}
}
@@ -0,0 +1,25 @@
package me.dadus33.chatitem.listeners.holder;
import java.util.HashMap;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
public class TranslationHolder implements InventoryHolder {
public final HashMap<Integer, String> langBySlot = new HashMap<>();
private final int page;
public TranslationHolder(int page) {
this.page = page;
}
public int getPage() {
return page;
}
@Override
public Inventory getInventory() {
return null;
}
}
@@ -1,10 +1,12 @@
package me.dadus33.chatitem.playernamer;
import me.dadus33.chatitem.playernamer.hook.HexNicksV3PlayerNamer;
import org.bukkit.Bukkit;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.playernamer.hook.DefaultPlayerNamer;
import me.dadus33.chatitem.playernamer.hook.HexNicksPlayerNamer;
import me.dadus33.chatitem.playernamer.hook.HexNicksV2PlayerNamer;
import org.bukkit.plugin.Plugin;
public class PlayerNamerManager {
@@ -17,11 +19,24 @@ public class PlayerNamerManager {
}
public static void load(ChatItem pl) {
if(Bukkit.getPluginManager().getPlugin("HexNicks") != null) {
setPlayerNamer(new HexNicksPlayerNamer());
pl.getLogger().info("Enable support for HexNicks plugin !");
} else {
setPlayerNamer(new DefaultPlayerNamer());
Plugin plugin = Bukkit.getPluginManager().getPlugin("HexNicks");
if (plugin != null) {
char majorVersion = plugin.getDescription().getVersion().charAt(0);
if (majorVersion == '3')
setPlayerNamer(new HexNicksV3PlayerNamer());
else
setPlayerNamer(new HexNicksV2PlayerNamer());
pl.getLogger().info("Enable support for HexNicks plugin v" + majorVersion);
return;
}
setPlayerNamer(new DefaultPlayerNamer());
}
}
@@ -7,7 +7,7 @@ import me.dadus33.chatitem.playernamer.IPlayerNamer;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
public class HexNicksPlayerNamer implements IPlayerNamer {
public class HexNicksV2PlayerNamer implements IPlayerNamer {
@Override
public BaseComponent[] getName(Player p) {
@@ -0,0 +1,17 @@
package me.dadus33.chatitem.playernamer.hook;
import dev.majek.hexnicks.HexNicks;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.playernamer.IPlayerNamer;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
public class HexNicksV3PlayerNamer implements IPlayerNamer {
@Override
public BaseComponent[] getName(Player p) {
return BungeeComponentSerializer.get().serialize(HexNicks.api().getStoredNick(p).join());
}
}
@@ -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;
}
}
@@ -0,0 +1,14 @@
package me.dadus33.chatitem.playerversion.hooks;
import org.bukkit.entity.Player;
import me.dadus33.chatitem.playerversion.IPlayerVersion;
import me.dadus33.chatitem.utils.Version;
public class DefaultVersionHook implements IPlayerVersion {
@Override
public int getProtocolVersion(Player p) {
return 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,45 +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;
public class ColorManager {
public static String getColorString(String input) {
if(input == null || input.isEmpty())
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("#");
}
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 "";
String str = "";
if(Version.getVersion().isNewerOrEquals(Version.V1_16) && input.startsWith("x")) { // x mean it's an hex
ChatItem.debug("Removing char x at begin: " + input.substring(1));
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 += ChatColor.of("#" + input.substring(0, 6)); // get first hex color code
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 += getColorString(input.substring(6)); // get color for after
return 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());
} else
ChatItem.debug("1.15 - for : " + input);
}
// not hex
for(char c : input.toCharArray())
str += ChatColor.getByChar(c);
return str;
for (char c : input.toCharArray())
str.append(ChatColor.getByChar(c));
return str.toString();
}
public static ChatColor getColor(String input) {
if(input == null || input.isEmpty())
if (input == null || input.isEmpty())
return ChatColor.RESET;
if(Version.getVersion().isNewerOrEquals(Version.V1_16) && input.startsWith("x")) { // x mean it's an hex
ChatItem.debug("Removing char x at begin: " + input.substring(1));
if(input.length() >= 7) { // at least hex, and 7 because we count the "x"
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());
} else
ChatItem.debug("1.15 - for : " + input);
}
// 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;
}
}
@@ -7,6 +7,7 @@ import java.util.stream.Collectors;
import org.bukkit.command.CommandSender;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.Storage;
public class Messages {
@@ -18,7 +19,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)
@@ -1,101 +1,108 @@
package me.dadus33.chatitem.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
public class PacketUtils {
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",")
.split(",")[3];
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
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;
public static final Method ICB_FROM_JSON;
/**
* 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 + ".";
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");
ICB_FROM_JSON = getMethod("a", CHAT_SERIALIZER, String.class);
}
/**
* 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)
* @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 : "");
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 +111,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,16 +136,13 @@ public class PacketUtils {
public static Object getPlayerConnection(Player p) {
try {
Object entityPlayer = getEntityPlayer(p);
if(Version.getVersion().isNewerOrEquals(Version.V1_17))
return entityPlayer.getClass().getField("b").get(entityPlayer);
else
return entityPlayer.getClass().getField("playerConnection").get(entityPlayer);
return ReflectionUtils.getFirstWith(entityPlayer, entityPlayer.getClass(), getNmsClass("PlayerConnection", "server.network."));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Get NMS entity player of specified one
*
@@ -148,8 +151,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 +161,76 @@ 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();
}
}
private static Method getNbtMethod;
/**
* 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 {
if (getNbtMethod == null) {
Class<?> itemClass = getNmsClass("ItemStack", "world.item.");
Version v = Version.getVersion();
if (v.isNewerOrEquals(Version.V1_20))
getNbtMethod = itemClass.getDeclaredMethod("w");
else if (v.equals(Version.V1_19))
getNbtMethod = itemClass.getDeclaredMethod("u");
else if (v.equals(Version.V1_18))
getNbtMethod = itemClass.getDeclaredMethod("t");
else
getNbtMethod = itemClass.getDeclaredMethod("getTag");
getNbtMethod.setAccessible(true);
}
Object tag = getNbtMethod.invoke(JSONManipulator.AS_NMS_COPY.invoke(null, item));
return tag == null ? "{}" : tag.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "{}";
}
private static Method getMethod(String name, Class<?> clazz, Class<?>... params) {
try {
return clazz.getDeclaredMethod(name, params);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void printPacketToDebug(Object packet) {
if(!ChatItem.hasDebug())
return;
if(packet == null) {
ChatItem.debug("Packet is null");
return;
}
ChatItem.debug("Packet with Class: " + packet.getClass().getSimpleName());
for (Field f : packet.getClass().getDeclaredFields()) {
f.setAccessible(true);
try {
ChatItem.debug(f.getName() + ": " + f.get(packet));
} catch (Exception exc) {
exc.printStackTrace();
}
}
}
}
@@ -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 {
@@ -28,15 +78,22 @@ public class ReflectionUtils {
* @param field the name of the field
* @return the requested object of the field
*/
public static Object getObject(Object source, String field) {
public static Object getObject(Object source, String... field) {
try {
Field f = source.getClass().getDeclaredField(field);
f.setAccessible(true);
return f.get(source);
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;
}
return null;
}
/**
@@ -73,6 +130,40 @@ 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<T> searchingFor) throws Exception {
return getFirstWith(from, from.getClass(), searchingFor);
}
/**
* 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);
}
}
if(!clazz.getSuperclass().equals(Object.class))
return getFirstWith(from, clazz.getSuperclass(), searchingFor);
return null;
}
/**
* Get the first field which have the searching for class type
*
@@ -82,12 +173,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,121 +0,0 @@
package me.dadus33.chatitem.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
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;
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, DEBUG,
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 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))));
}
TRANSLATIONS.put(key, entry);
}
DEBUG = conf.getBoolean("debug", false);
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);
}
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!");
}
}
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)));
}
}
}
@@ -1,7 +1,9 @@
package me.dadus33.chatitem.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.HttpURLConnection;
@@ -9,26 +11,107 @@ import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
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.ChatManager;
import me.dadus33.chatitem.chatmanager.v1.json.JSONManipulator;
import me.dadus33.chatitem.playerversion.PlayerVersionManager;
import net.md_5.bungee.api.chat.BaseComponent;
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.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 static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
private static final TreeMap<Integer, String> ROMAN_KEYS = new TreeMap<>();
private static final 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 +124,139 @@ 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;
}
public static boolean isBeforeChatJson(Player p) {
return !PlayerVersionManager.getPlayerVersionAdapter().getPlayerVersion(p).isNewerOrEquals(Version.V1_16) && Version.getVersion().isNewerOrEquals(Version.V1_16);
}
@SuppressWarnings("deprecation")
public static HoverEvent createItemHover(ItemStack item, Player to) {
if(isBeforeChatJson(to)) {
ComponentBuilder comp = new ComponentBuilder("");
for(String line : ChatManager.getMaxLinesFromItem(to, item))
comp.append(line + "\n");
return createTextHover(comp.create());
}
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 ClickEvent createRunCommand(String command) {
return new ClickEvent(ClickEvent.Action.RUN_COMMAND, command);
}
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;
}
}
public static boolean isUUID(String s) {
return s != null && UUID_PATTERN.matcher(s.toLowerCase()).matches();
}
public static YamlConfiguration copyLoadFile(File folder, String filename, String baseFile) {
File legacyConfig = new File(folder, filename);
if(!legacyConfig.exists())
copyFile(baseFile, legacyConfig);
return YamlConfiguration.loadConfiguration(legacyConfig);
}
public static void copyFile(String fileName, File dir) {
try (InputStream stream = ChatItem.getInstance().getResource(fileName)) {
Files.copy(stream, dir.toPath());
} catch(Exception e) {
e.printStackTrace();
}
}
public static String arrayToString(Object[] a) {
StringJoiner sj = new StringJoiner(", ");
for(Object o : a)
sj.add(o == null ? "null" : o.toString());
return sj.toString();
}
}
@@ -4,22 +4,25 @@ import java.net.InetSocketAddress;
import org.bukkit.Bukkit;
import me.dadus33.chatitem.ChatItem;
public enum Version {
// http://wiki.vg/Protocol_version_numbers
V1_7(0, 5, 0),
V1_8(6, 47, 1),
V1_9(49, 110, 2), // 1.9.X - Starts with 49 as 48 was an april fools update
V1_10(201, 210, 3), // 1.10.X - Starts with 201 because why not.
V1_11(301, 316, 4),
V1_12(317, 340, 5),
V1_13(341, 440, 6),
V1_14(100, 441, 500),
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_7(0, 5, 7),
V1_8(6, 47, 8),
V1_9(49, 110, 9), // 1.9.X - Starts with 49 as 48 was an april fools update
V1_10(201, 210, 10), // 1.10.X - Starts with 201 because why not.
V1_11(301, 316, 11),
V1_12(317, 340, 12),
V1_13(341, 440, 13),
V1_14(441, 500, 14),
V1_15(550, 578, 15),
V1_16(700, 754, 16),
V1_17(755, 756, 17),
V1_18(757, 758, 18),
V1_19(759, 762, 19),
V1_20(763, 1000, 20),
HIGHER(Integer.MAX_VALUE, -1, Integer.MAX_VALUE);
// Latest version should always have the upper limit set to Integer.MAX_VALUE so
@@ -67,11 +70,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;
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Bruin Terracotta","block.minecraft.lapis_ore":"Lasuurerts","item.minecraft.gray_dye":"Grys Kleurstof","block.minecraft.banner.base.yellow":"Ten volle geel veld","block.minecraft.terracotta":"Terracotta","item.minecraft.stray_spawn_egg":"Nagelaate Kuit Eier","block.minecraft.banner.base.pink":"Ten volle pienk veld","item.minecraft.potion.effect.weakness":"Swakheid Doepa","block.minecraft.dark_prismarine_slab":"Donker Prismaryn blad","item.minecraft.splash_potion.effect.thick":"Dik Spatdoepa","item.minecraft.cooked_cod":"Gaar Kabeljou","block.minecraft.red_nether_brick_slab":"Rooi Laer Baksteen Blad","block.minecraft.yellow_terracotta":"Geel Terracotta","block.minecraft.observer":"Waarnemer","block.minecraft.banner.stripe_bottom.cyan":"Siaan Basis","block.minecraft.banner.creeper.purple":"Pers Creeper Gelaai","block.minecraft.banner.straight_cross.cyan":"Siaan Kruis","block.minecraft.banner.half_horizontal_bottom.brown":"Omgekeerde Bruin Dwarsstreep","item.minecraft.firework_star.shape.large_ball":"Groot Bal","block.minecraft.prismarine_brick_slab":"Prismaryn Baksteen Blad","block.minecraft.jungle_trapdoor":"Oerwoudhout Valdeur","block.minecraft.sculk_sensor":"Sculk Sensor","block.minecraft.banner.creeper.orange":"Oranje Creeper Gelaai","block.minecraft.banner.triangles_top.lime":"Lemmetjie Groen Ingekeepde Hoof","item.minecraft.charcoal":"Houtskool","item.minecraft.tipped_arrow.effect.night_vision":"Pyl van Nagsig","block.minecraft.stone_brick_slab":"Klipsteenblad","block.minecraft.banner.mojang.cyan":"Siaan Ding","block.minecraft.white_stained_glass":"Wit Glas","item.minecraft.bowl":"Hout Bak","block.minecraft.banner.diagonal_up_left.magenta":"Magenta Per draai omgekeerde","block.minecraft.banner.square_top_right.light_gray":"Ligte Grys Hoof Sinistere Kanton","block.minecraft.dead_brain_coral_fan":"Dooie Gespreide Breinkoraal","block.minecraft.banner.flower.white":"Wit Blom Lading","item.minecraft.bone_meal":"Beenmeel","block.minecraft.banner.triangle_bottom.red":"Rooi Chevron","block.minecraft.cyan_carpet":"Siaan Mat","block.minecraft.oak_door":"Eikehout Deur","block.minecraft.flowering_azalea_leaves":"Blomdraende Azalea Blare","item.minecraft.prismarine_crystals":"Prismaryn Kristalle","block.minecraft.banner.diagonal_left.cyan":"Siaan Per draai Sinister","block.minecraft.banner.stripe_bottom.light_blue":"Ligte Blou Basis","item.minecraft.tipped_arrow.effect.slow_falling":"Pyl van Stadig Val","block.minecraft.end_stone":"Endsteen","block.minecraft.potted_white_tulip":"Gopotte Wit Tulp","block.minecraft.warped_door":"Vreemde Deur","block.minecraft.banner.square_top_left.light_gray":"Ligte Grys Hoof Dexter Kanton","item.minecraft.splash_potion.effect.fire_resistance":"Brandbestandheid Spatdoepa","block.minecraft.banner.half_vertical_right.pink":"Omgekeerde Paars Per Bleek","item.minecraft.furnace_minecart":"Koekepan Enjin","block.minecraft.banner.triangles_bottom.light_gray":"Ligte Grys Ingekeepde Basis","item.minecraft.shield.red":"Rooi Skild","block.minecraft.quartz_pillar":"Kwarts Pilaar","block.minecraft.prismarine_slab":"Prismaryn Blad","block.minecraft.nether_portal":"Laer Ingang","item.minecraft.diamond_sword":"Diamant Swaard","block.minecraft.oak_planks":"Eikehout Planke","item.minecraft.amethyst_shard":"Ametis Skerf","block.minecraft.purple_banner":"Pers Vlag","block.minecraft.structure_void":"Struktuur Leemte","block.minecraft.purple_shulker_box":"Pers Shulker Boks","block.minecraft.potatoes":"Aartappels","block.minecraft.light_blue_bed":"Ligte blou Bed","block.minecraft.yellow_banner":"Geel Banier","item.modifiers.head":"Wanneer dit op die kop is:","item.minecraft.potion.effect.swiftness":"Snelheid Doepa","block.minecraft.glass_pane":"Glaspaneel","block.minecraft.clay":"Klei","block.minecraft.banner.diagonal_right.cyan":"Cyan Per draai","block.minecraft.cut_copper_slab":"Gesnyde Koper Blad","block.minecraft.polished_diorite_slab":"Gepoleerde Dioriet Blad","block.minecraft.banner.piglin.green":"Groen Snoet","item.minecraft.splash_potion.effect.slow_falling":"Spat Doepa van Stadig Val","item.minecraft.book":"Boek","block.minecraft.banner.gradient.brown":"Bruin Gradiënt","block.minecraft.banner.cross.magenta":"Magenta Skuinskruis","block.minecraft.cobblestone_slab":"Steengruisblad","block.minecraft.banner.diagonal_right.purple":"Pers Per draai","block.minecraft.banner.curly_border.gray":"Grys Ingekeepde Borduur","block.minecraft.big_dripleaf":"Groot Drupblaar","block.minecraft.black_shulker_box":"Swart Shulker Boks","block.minecraft.banner.straight_cross.purple":"Pers Kruis","block.minecraft.blackstone_stairs":"Swartsteentrappe","block.minecraft.banner.triangles_top.blue":"Blou Ingekeepde Hoof","block.minecraft.deepslate_tile_slab":"Leisteenteëlblad","block.minecraft.banner.square_top_left.blue":"Blou Hoof Dexter Kanton","block.minecraft.banner.stripe_center.yellow":"Geen Paal","item.minecraft.piglin_banner_pattern.desc":"Snoet","item.minecraft.firework_star.cyLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"طين النضيج البني","block.minecraft.lapis_ore":"خام اللازورد","item.minecraft.gray_dye":"صبغة رمادية","block.minecraft.banner.base.yellow":"حقل أصفر كامل","block.minecraft.terracotta":"طين النضيج","item.minecraft.stray_spawn_egg":"بيضة الضال","block.minecraft.banner.base.pink":"حقل وردي كامل","item.minecraft.potion.effect.weakness":"جرعة الضعف","block.minecraft.dark_prismarine_slab":"بلاطة البريسمارين الداكن","item.minecraft.splash_potion.effect.thick":"رشة الجرعة الكثيفة","item.minecraft.cooked_cod":"سمك قد مطبوخ","block.minecraft.red_nether_brick_slab":"بلاطة طوب النذر الأحمر","block.minecraft.yellow_terracotta":"طين النضيج الأصفر","block.minecraft.observer":"المراقب","block.minecraft.banner.stripe_bottom.cyan":"شريط سفلي سماوي","block.minecraft.banner.creeper.purple":"شعار كريبر بنفسجي","block.minecraft.banner.straight_cross.cyan":"صليب سماوي","block.minecraft.banner.half_horizontal_bottom.brown":"النصف الأسفل ملون بني","item.minecraft.firework_star.shape.large_ball":"كرة كبيرة","block.minecraft.prismarine_brick_slab":"بلاطة طوب البريسمارين","block.minecraft.jungle_trapdoor":"باب أرضي من خشب الأدغال","block.minecraft.sculk_sensor":"مستشعر السكالك","block.minecraft.banner.creeper.orange":"شعار كريبر برتقالي","block.minecraft.banner.triangles_top.lime":"مثلثات علوية ليمونية","item.minecraft.charcoal":"فحم نباتي","item.minecraft.tipped_arrow.effect.night_vision":"سهم الرؤية الليلية","block.minecraft.stone_brick_slab":"بلاطة طوب حجري","block.minecraft.banner.mojang.cyan":"شيء سماوي","block.minecraft.white_stained_glass":"زجاج ابيض","item.minecraft.bowl":"زبدية","block.minecraft.banner.diagonal_up_left.magenta":"النصف السفلي الأيسر أرجواني","block.minecraft.banner.square_top_right.light_gray":"مربع رأسي أيمن رمادي فاتح","block.minecraft.dead_brain_coral_fan":"شعاب مرجان عقلي ميت","block.minecraft.banner.flower.white":"شعار زهرة أبيض","item.minecraft.bone_meal":"مسحوق العظام","block.minecraft.banner.triangle_bottom.red":"مثلث أحمر","block.minecraft.cyan_carpet":"سجاد سماوي","block.minecraft.oak_door":"باب البلوط","block.minecraft.flowering_azalea_leaves":"أوراق الأزاليا المزهرة","item.minecraft.prismarine_crystals":"بلورات البرسمارين","block.minecraft.banner.diagonal_left.cyan":"النصف العلوي الأيسر سماوي","block.minecraft.banner.stripe_bottom.light_blue":"شريط سفلي أزرق فاتح","item.minecraft.tipped_arrow.effect.slow_falling":"سهم السقوط البطيء","block.minecraft.end_stone":"حجر الاند","block.minecraft.potted_white_tulip":"توليب أبيض في وعاء","block.minecraft.warped_door":"باب عجيب","block.minecraft.banner.square_top_left.light_gray":"مربع رأسي أيسر رمادي فاتح","item.minecraft.splash_potion.effect.fire_resistance":"رشة جرعة مقاومة النار","block.minecraft.banner.half_vertical_right.pink":"النصف اليميني ملون وردي","item.minecraft.furnace_minecart":"عربة منجم بفرن","block.minecraft.banner.triangles_bottom.light_gray":"مثلثات سفلية رمادية فاتحة","item.minecraft.shield.red":"درس أحمر","block.minecraft.quartz_pillar":"عمود كوارتز","block.minecraft.prismarine_slab":"بلاطة بريسمارين","block.minecraft.nether_portal":"بوابة النذر","item.minecraft.diamond_sword":"سيف ألماسي","block.minecraft.oak_planks":"ألواح خشب البلوط","item.minecraft.amethyst_shard":"شظية جمشت","block.minecraft.purple_banner":"راية بنفسجية","block.minecraft.structure_void":"فراغ الهيكل","block.minecraft.purple_shulker_box":"صندوق شلكر بنفسجي","block.minecraft.potatoes":"بطاطا","block.minecraft.light_blue_bed":"سرير أزرق فاتح","block.minecraft.yellow_banner":"راية صفراء","item.modifiers.head":"عندما يكون على الرأس:","item.minecraft.potion.effect.swiftness":"جرعة السرعة","block.minecraft.glass_pane":"لوح زجاجي","block.minecraft.clay":"صلصال","block.minecraft.banner.diagonal_right.cyan":"النصف العلوي الأيمن سماوي","block.minecraft.cut_copper_slab":"بلاطة نحاس مقطع","block.minecraft.polished_diorite_slab":"بلاطة ديوريت مصقول","block.minecraft.banner.piglin.green":"أنف أخضر","item.minecraft.splash_potion.effect.slow_falling":"رشة جرعة السقوط البطيء","item.minecraft.book":"كتاب","blockLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Terracota marrón","block.minecraft.lapis_ore":"Veta de llapislázuli","item.minecraft.gray_dye":"Tiñe buxu","block.minecraft.banner.base.yellow":"Estandarte en mariello","block.minecraft.terracotta":"Terracota","item.minecraft.stray_spawn_egg":"Güevu qu'apruz a un vagamundu","block.minecraft.banner.base.pink":"Estandarte en rosa","item.minecraft.potion.effect.weakness":"Brebaxe de badea","block.minecraft.dark_prismarine_slab":"Llábana de prismarín escuro","item.minecraft.splash_potion.effect.thick":"Brebaxe espesu refundizu","item.minecraft.cooked_cod":"Bacalláu cocináu","block.minecraft.red_nether_brick_slab":"Llábana de lladriyos coloraos del Nether","block.minecraft.yellow_terracotta":"Terracota mariello","block.minecraft.observer":"Observador","block.minecraft.banner.stripe_bottom.cyan":"Base ciana","block.minecraft.banner.creeper.purple":"Dibuxu moráu de Creeper","block.minecraft.banner.straight_cross.cyan":"Cruz ciana","block.minecraft.banner.half_horizontal_bottom.brown":"Metá baxera en marrón","item.minecraft.firework_star.shape.large_ball":"Bola grande","block.minecraft.prismarine_brick_slab":"Llábana de lladriyos de prismarín","block.minecraft.jungle_trapdoor":"Trapiella de madera de la xungla","block.minecraft.sculk_sensor":"Sensor Sculk","block.minecraft.banner.creeper.orange":"Dibuxu naranxa de Creeper","block.minecraft.banner.triangles_top.lime":"Dentáu llima cimeru","item.minecraft.charcoal":"Carbón vexetal","item.minecraft.tipped_arrow.effect.night_vision":"Flecha de visión nocherniego","block.minecraft.stone_brick_slab":"Llábana de lladriyos de piedra","block.minecraft.banner.mojang.cyan":"Llogotipu cianu","block.minecraft.white_stained_glass":"Vidru tintao en blanco","item.minecraft.bowl":"Escudiella","block.minecraft.banner.diagonal_up_left.magenta":"Triángulu baxeru a mandrecha en maxenta","block.minecraft.banner.square_top_right.light_gray":"Cuadráu cimeru a manzorga en buxo claro","block.minecraft.dead_brain_coral_fan":"Gorgonia de cerebru muerto","block.minecraft.banner.flower.white":"Flor blanca","item.minecraft.bone_meal":"Fariña óseo","block.minecraft.banner.triangle_bottom.red":"Chebrón coloráu","block.minecraft.cyan_carpet":"Moqueta ciana","block.minecraft.oak_door":"Puerta de carbayu","block.minecraft.flowering_azalea_leaves":"Fueyes de rododentru florecío","item.minecraft.prismarine_crystals":"Cristales de prismarín","block.minecraft.banner.diagonal_left.cyan":"Triángulu cimeru a manzorga en ciano","block.minecraft.banner.stripe_bottom.light_blue":"Base azul claro","item.minecraft.tipped_arrow.effect.slow_falling":"Flecha de cayida lenta","block.minecraft.end_stone":"Piedra del End","block.minecraft.potted_white_tulip":"Tiestu con un tulipán blancu","block.minecraft.warped_door":"Puerta distorsionada","block.minecraft.banner.square_top_left.light_gray":"Cuadráu cimeru a mandrecha en buxo claro","item.minecraft.splash_potion.effect.fire_resistance":"Brebaxe refundizu de resistencia al fueu","block.minecraft.banner.half_vertical_right.pink":"Metá a mandrecha en rosa","item.minecraft.furnace_minecart":"Vagoneta con un fornu","block.minecraft.banner.triangles_bottom.light_gray":"Dentáu buxu claru baxeru","item.minecraft.shield.red":"Escudu coloráu","block.minecraft.quartz_pillar":"Pilar de cuarzu","block.minecraft.prismarine_slab":"Llábana de prismarín","block.minecraft.nether_portal":"Portal al Nether","item.minecraft.diamond_sword":"Espada de diamante","block.minecraft.oak_planks":"Tables de carbayu","item.minecraft.amethyst_shard":"Cachu d'amatista","block.minecraft.purple_banner":"Estandarte moráu","block.minecraft.structure_void":"Vacíu de cadarma","block.minecraft.purple_shulker_box":"Caxa morada de shulker","block.minecraft.potatoes":"Pataques","block.minecraft.light_blue_bed":"Cama azul claro","block.minecraft.yellow_banner":"Estandarte mariellu","item.minecraft.potion.effect.swiftness":"Brebaxe de rapidez","block.minecraft.glass_pane":"Panel de vidru","block.minecraft.clay":"Barru santo","block.minecraft.banner.diagonal_right.cyan":"Triángulu cimeru a mandrecha en ciano","block.minecraft.cut_copper_slab":"Llábana de cobre cortao","block.minecraft.polished_diorite_slab":"Llábana de diorita pulío","block.minecraft.banner.piglin.green":"Focicu verde","item.minecraft.splash_potion.effect.slow_falling":"Brebaxe refundizu de cayida lenta","item.minecraft.book":"Llibru","block.minecraft.banner.gradient.brown":"Dilíu marrón dende lo cimero","block.minecraft.banner.cross.magenta":"Nasa maxenta","block.minecraft.cobblestone_slab":"Llábana de llastra","block.minecraft.banner.diagonal_right.purple":"Triángulu cimeru a mandrecha en morao","block.minecraft.banner.curly_border.gray":"Berbesu dentáu en buxo","block.minecraft.big_dripleaf":"Plantaforma grande","block.minecraft.black_shulker_box":"Caxa prieta de shulker","block.minecraft.banner.straight_cross.purple":"Cruz morada","block.minecraft.blackstone_sLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Qəhvəyi Terrakotta","block.minecraft.lapis_ore":"Lapis Lazuli Filizi","item.minecraft.gray_dye":"Boz Boya","block.minecraft.banner.base.yellow":"Tam sarı sahə","block.minecraft.terracotta":"Terrakotta","item.minecraft.stray_spawn_egg":"Strey çağırma yumurtası","block.minecraft.banner.base.pink":"Tam çəhrayı sahə","item.minecraft.potion.effect.weakness":"Zəiflik Eliksiri","block.minecraft.dark_prismarine_slab":"Qara prizmarin pillə","item.minecraft.splash_potion.effect.thick":"Atıla Bilən Sıx Eliksir","item.minecraft.cooked_cod":"Bişmiş Treska","block.minecraft.red_nether_brick_slab":"Qırmızı Nezer kərpici pilləsi","block.minecraft.yellow_terracotta":"Sarı terrakotta","block.minecraft.observer":"Gözləmçi","block.minecraft.banner.stripe_bottom.cyan":"Altdan Mavi Sətir","block.minecraft.banner.creeper.purple":"Bənövşəyi Creeper Şəkli","block.minecraft.banner.straight_cross.cyan":"Mavi Xaç","block.minecraft.banner.half_horizontal_bottom.brown":"Qəhvəyi Alt Yarı","item.minecraft.firework_star.shape.large_ball":"Böyük top","block.minecraft.prismarine_brick_slab":"Prizmarin kərpici pillə","block.minecraft.jungle_trapdoor":"Cəngəllik Ağacı Tələ Qapısı","block.minecraft.sculk_sensor":"Skalk sensoru","block.minecraft.banner.creeper.orange":"Narıncı Creeper Şəkli","block.minecraft.banner.triangles_top.lime":"Üstdən Açıq Yaşıl Mişar Dişi","item.minecraft.charcoal":"Odun Kömürü","item.minecraft.tipped_arrow.effect.night_vision":"Gecə Görüşü Oxu","block.minecraft.stone_brick_slab":"Daş Kərpic Pillə","block.minecraft.banner.mojang.cyan":"Mavi Şey","block.minecraft.white_stained_glass":"Ağ Rəngli Şüşə","item.minecraft.bowl":"Qab","block.minecraft.banner.diagonal_up_left.magenta":"Magenta Sol Alt Üçbucaq","block.minecraft.banner.square_top_right.light_gray":"Açıq Boz Sağ Üst Dördbucaq","block.minecraft.dead_brain_coral_fan":"Ölü beyin mərcan fanatı","block.minecraft.banner.flower.white":"Ağ Çiçək Şəkli","item.minecraft.bone_meal":"Sümük Tozu","block.minecraft.banner.triangle_bottom.red":"Altdan Qırmızı Üçbucaq","block.minecraft.cyan_carpet":"Mavi Xalça","block.minecraft.oak_door":"Palıd Qapı","block.minecraft.flowering_azalea_leaves":"Çiçəkləyən azaliya yarpaqları","item.minecraft.prismarine_crystals":"Prizmarin Kristalı","block.minecraft.banner.diagonal_left.cyan":"Mavi Sol Üst Üçbucaq","block.minecraft.banner.stripe_bottom.light_blue":"Altdan Açıq Göy Sətir","item.minecraft.tipped_arrow.effect.slow_falling":"Yavaş Eniş Oxu","block.minecraft.end_stone":"End Daşı","block.minecraft.potted_white_tulip":"Dibçəkli Ağ Lalə","block.minecraft.warped_door":"Əyri qapı","block.minecraft.banner.square_top_left.light_gray":"Açıq Boz Sol Üst Dördbucaq","item.minecraft.splash_potion.effect.fire_resistance":"Atıla Bilən Alov Müqaviməti Eliksiri","block.minecraft.banner.half_vertical_right.pink":"Çəhrayı Sağ Yarı","item.minecraft.furnace_minecart":"Sobalı Vaqon","block.minecraft.banner.triangles_bottom.light_gray":"Altdan Açıq Boz Mişar Dişi","item.minecraft.shield.red":"Qırmızı Qalxan","block.minecraft.quartz_pillar":"Kvars sütun","block.minecraft.prismarine_slab":"Prizmarin pillə","block.minecraft.nether_portal":"Nezer portalı","item.minecraft.diamond_sword":"Almaz Qılınc","block.minecraft.oak_planks":"Palıd Taxta","item.minecraft.amethyst_shard":"Ametist parçası","block.minecraft.purple_banner":"Bənövşəyi Bayraq","block.minecraft.structure_void":"Struktur Boşluğu","block.minecraft.purple_shulker_box":"Bənövşəyi Shulker Qutusu","block.minecraft.potatoes":"Kartoflar","block.minecraft.light_blue_bed":"Açıq göy çarpayı","block.minecraft.yellow_banner":"Sarı Bayraq","item.modifiers.head":"Başda ikən:","item.minecraft.potion.effect.swiftness":"Çeviklik Eliksiri","block.minecraft.glass_pane":"İncə Şüşə","block.minecraft.clay":"Gil","block.minecraft.banner.diagonal_right.cyan":"Mavi Sağ Üst Üçbucaq","block.minecraft.cut_copper_slab":"Kəsilmiş mis pillə","block.minecraft.polished_diorite_slab":"Cilalanmış Diorit Pillə","block.minecraft.banner.piglin.green":"Yaşıl burun","item.minecraft.splash_potion.effect.slow_falling":"Atıla Bilən Yavaş Eniş Eliksiri","item.minecraft.book":"Kitab","block.minecraft.banner.gradient.brown":"Yuxarıdan Aşağı Qəhvəyi Keçiş","block.minecraft.banner.cross.magenta":"Magenta Çarpı","block.minecraft.cobblestone_slab":"Qırıq Daş Pillə","block.minecraft.banner.diagonal_right.purple":"Bənövşəyi Sağ Üst Üçbucaq","block.minecraft.banner.curly_border.gray":"Boz Mişar Dişi Çərçivə","block.minecraft.big_dripleaf":"Böyük damcıyarpaq","block.minecraft.black_shulker_box":"Qara Shulker Qutusu","block.minecraft.banner.straight_cross.purple":"Bənövşəyi Xaç","block.minecraft.blackstone_stairs":"Qaradaş pilləkən","block.minecraft.banner.triangles_top.blue":"ÜstdLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Көрән яндырығашы","block.minecraft.lapis_ore":"Рәжүәрт мәғдәне","item.minecraft.gray_dye":"Һоро буяу","block.minecraft.banner.base.yellow":"Тулыһынса һары","block.minecraft.terracotta":"Терракота","item.minecraft.stray_spawn_egg":"Сырғыя саҡырыу йомортҡаһы","block.minecraft.banner.base.pink":"Тулыһынса алһыу","item.minecraft.potion.effect.weakness":"Көсһеҙлек эсемлеге","block.minecraft.dark_prismarine_slab":"Ҡара призмарин плитаһы","item.minecraft.splash_potion.effect.thick":"Шарлай торған ҡуйы эсемлеге","item.minecraft.cooked_cod":"Ҡурылған тәрәс","block.minecraft.red_nether_brick_slab":"Ҡыҙыл неҙер кирбес плитаһы","block.minecraft.yellow_terracotta":"Һары яндырығашы","block.minecraft.observer":"Күҙәтеүсе","block.minecraft.banner.stripe_bottom.cyan":"Фирүзә нигеҙ","block.minecraft.banner.creeper.purple":"Шәмәхә крипер","block.minecraft.banner.straight_cross.cyan":"Фирүзә тәре","block.minecraft.banner.half_horizontal_bottom.brown":"Көрән аҫҡы яҡ","item.minecraft.firework_star.shape.large_ball":"Оло йомғаҡ","block.minecraft.prismarine_brick_slab":"Призмарин кирбес плитаһы","block.minecraft.jungle_trapdoor":"Тропик ағас люгы","block.minecraft.sculk_sensor":"Скалк сенсор","block.minecraft.banner.creeper.orange":"Ҡыҙғылт һары крипер","block.minecraft.banner.triangles_top.lime":"Йәшкелт тешле баш","item.minecraft.charcoal":"Ағас күмере","item.minecraft.tipped_arrow.effect.night_vision":"Төн күреү уғы","block.minecraft.stone_brick_slab":"Таш кирбес плитаһы","block.minecraft.banner.mojang.cyan":"Фирүзә бер нәмә","block.minecraft.white_stained_glass":"Аҡ быяла","item.minecraft.bowl":"Туҫтаҡ","block.minecraft.banner.diagonal_up_left.magenta":"Ҡуйы ҡыҙыл ауҙарылған киҫелеше","block.minecraft.banner.square_top_right.light_gray":"Аҡһыл һоро өҫкө һул мөйөш","block.minecraft.dead_brain_coral_fan":"Үле елпеүесле мейе мәрйен","block.minecraft.banner.flower.white":"Аҡ сәскә","item.minecraft.bone_meal":"Һөйәк оно","block.minecraft.banner.triangle_bottom.red":"Ҡыҙыл осо","block.minecraft.cyan_carpet":"Фирүзә келәм","block.minecraft.oak_door":"Имән ишеге","block.minecraft.flowering_azalea_leaves":"Гөлләгән азалия япраҡтары","item.minecraft.prismarine_crystals":"Призмарин кристалы","block.minecraft.banner.diagonal_left.cyan":"Фирүзә һулға киселеш","block.minecraft.banner.stripe_bottom.light_blue":"Зәңгәр нигеҙ","item.minecraft.tipped_arrow.effect.slow_falling":"Талғын йығылыу уғы","block.minecraft.end_stone":"Эндерташ","block.minecraft.potted_white_tulip":"Ултыртылған аҡ ләлә","block.minecraft.warped_door":"Боҙолған ишек","block.minecraft.banner.square_top_left.light_gray":"Аҡһыл һоро өҫкө уң мөйөш","item.minecraft.splash_potion.effect.fire_resistance":"Шарлай торған утҡа сыҙамлылыҡ эсемлеге","block.minecraft.banner.half_vertical_right.pink":"Алһыу уң яҡ","item.minecraft.furnace_minecart":"Вагонетка мейес менән","block.minecraft.banner.triangles_bottom.light_gray":"Аҡһыл һоро тешле нигеҙ","item.minecraft.shield.red":"Ҡыҙыл ҡалҡан","block.minecraft.quartz_pillar":"Кварц бағанаһы","block.minecraft.prismarine_slab":"Призмарин плитаһы","block.minecraft.nether_portal":"Неҙер порталы","item.minecraft.diamond_sword":"Алмас ҡылыс","block.minecraft.oak_planks":"Имән таҡталары","item.minecraft.amethyst_shard":"Аметист ярсығы","block.minecraft.purple_banner":"Шәмәхә байраҡ","block.minecraft.structure_void":"Буш ҡорамаһы","block.minecraft.purple_shulker_box":"Шәмәхә шалкер тартмаһы","block.minecraft.potatoes":"Бәрәңге","block.minecraft.light_blue_bed":"Зәңгәр карауат","block.minecraft.yellow_banner":"Һары байраҡ","item.modifiers.head":"Башта:","item.minecraft.potion.effect.swiftness":"Тиҙлек эсемлеге","block.minecraft.glass_pane":"Биҙәкле быяла","block.minecraft.clay":"Балсыҡ","block.minecraft.banner.diagonal_right.cyan":"Фирүзә киҫелеше","block.minecraft.cut_copper_slab":"Һырлы баҡыр плитаһы","block.minecraft.polished_diorite_slab":"Шымартылған диорит плитаһы","block.minecraft.banner.piglin.green":"Йәшел томшоLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Brauns Keramik","block.minecraft.lapis_ore":"Lapislazulierz","item.minecraft.gray_dye":"Graua Foabstoff","block.minecraft.banner.base.yellow":"Voiständig gejbs Feld","block.minecraft.terracotta":"Keramik","item.minecraft.stray_spawn_egg":"Eiswondera-Spawn-Oa","block.minecraft.banner.base.pink":"Voiständig rosa Feld","item.minecraft.potion.effect.weakness":"Trank da Schwäche","block.minecraft.dark_prismarine_slab":"Dunkle Prismarinstufe","item.minecraft.splash_potion.effect.thick":"Dickflüssiga Wurftrank","item.minecraft.cooked_cod":"Gebranter Kabeljau","block.minecraft.red_nether_brick_slab":"Rode Netherzieglschdiang","block.minecraft.yellow_terracotta":"Gejbs Keramik","block.minecraft.observer":"Beobachta","block.minecraft.banner.stripe_bottom.cyan":"Türkisa Bannerfuaß","block.minecraft.banner.creeper.purple":"Violetta Creeper","block.minecraft.banner.straight_cross.cyan":"Türkis' Kreiz","block.minecraft.banner.half_horizontal_bottom.brown":"Unten braun g'teilt","item.minecraft.firework_star.shape.large_ball":"Große Kugl","block.minecraft.prismarine_brick_slab":"Prismarinzieglstufe","block.minecraft.jungle_trapdoor":"Tropnhoizklappdierl","block.minecraft.sculk_sensor":"Sculk-Sensor","block.minecraft.banner.creeper.orange":"Oranga Creeper","block.minecraft.banner.triangles_top.lime":"Giftgreans gspickelta Bannerhaupt","item.minecraft.charcoal":"Hoizkuin","item.minecraft.tipped_arrow.effect.night_vision":"Nachtsichtpfeil","block.minecraft.stone_brick_slab":"Stoaziegelstufe","block.minecraft.banner.mojang.cyan":"Türkis' Mojang-Logo","block.minecraft.white_stained_glass":"Weißes Glas","item.minecraft.bowl":"Schüssl","block.minecraft.banner.diagonal_up_left.magenta":"Magenta schrägrechts geteilt (Invertiert)","block.minecraft.banner.square_top_right.light_gray":"Höigraues linkes Obaeck","block.minecraft.dead_brain_coral_fan":"Dooda Hirnkorallnfächa","block.minecraft.banner.flower.white":"Weiße Bleame","item.minecraft.bone_meal":"Boanenmej","block.minecraft.banner.triangle_bottom.red":"Roude hoibe Spitze","block.minecraft.cyan_carpet":"Türkisa Teppich","block.minecraft.oak_door":"Oachenhoiztia","block.minecraft.flowering_azalea_leaves":"Blühende Azaleenbladl","item.minecraft.prismarine_crystals":"Prismarinkristalle","block.minecraft.banner.diagonal_left.cyan":"Türkis schräglinks geteilt","block.minecraft.banner.stripe_bottom.light_blue":"Höiblaua Bannerfuaß","item.minecraft.tipped_arrow.effect.slow_falling":"Pfeil des sanften Falls","block.minecraft.end_stone":"Endstoa","block.minecraft.potted_white_tulip":"Eidopfte weiße Tulpe","block.minecraft.warped_door":"Wirrtia","block.minecraft.banner.square_top_left.light_gray":"Höigraues rechtes Obaeck","item.minecraft.splash_potion.effect.fire_resistance":"Wurftrank da Feiaresistenz","block.minecraft.banner.half_vertical_right.pink":"Links rosa g'spaltn","item.minecraft.furnace_minecart":"Ontriebslore","block.minecraft.banner.triangles_bottom.light_gray":"Höigraua gspickelta Bannerfuaß","item.minecraft.shield.red":"Roude Schuidl","block.minecraft.quartz_pillar":"Quarzsäule","block.minecraft.prismarine_slab":"Prismarinstufe","block.minecraft.nether_portal":"Netherportal","item.minecraft.diamond_sword":"Diamantschwert","block.minecraft.oak_planks":"Oachenhoizbretta","item.minecraft.amethyst_shard":"Amethystscherbe","block.minecraft.purple_banner":"Lila Banner","block.minecraft.structure_void":"Konstruktionsleere","block.minecraft.purple_shulker_box":"Violette Shulker-Kiste","block.minecraft.potatoes":"Eadäpfe","block.minecraft.light_blue_bed":"Höiblaues Bett","block.minecraft.yellow_banner":"Gelba Banner","item.modifiers.head":"Af dem Schädl:","item.minecraft.potion.effect.swiftness":"Trank da Schnelligkeit","block.minecraft.glass_pane":"Glasscheibe","block.minecraft.clay":"Ton","block.minecraft.banner.diagonal_right.cyan":"Türkis schrägrechts geteilt","block.minecraft.cut_copper_slab":"Geschnittene Kupfastufe","block.minecraft.polished_diorite_slab":"Polierte Dioritstufe","block.minecraft.banner.piglin.green":"Greane Schnauze","item.minecraft.splash_potion.effect.slow_falling":"Wurftrank des sanftn Fois","item.minecraft.book":"Buach","block.minecraft.banner.gradient.brown":"Brauna Foabverlaff","block.minecraft.banner.cross.magenta":"Magenta Andreaskreiz","block.minecraft.cobblestone_slab":"Bruchstoastufe","block.minecraft.banner.diagonal_right.purple":"Violett schrägrechts geteilt","block.minecraft.banner.curly_border.gray":"Graua Spicklbord","block.minecraft.big_dripleaf":"Groußes Dropfbladl","block.minecraft.black_shulker_box":"Schwoaze Shulker-Kiste","block.minecraft.banner.straight_cross.purple":"Violetts Kreiz","block.minecraft.blackstone_stairs":"Schwoazstoaschdiang","block.minecraft.banner.triangles_top.blue":"Blaus gspickelta Bannerhaupt","block.minecraft.deepslate_tile_slab":"Diafnschiefafliesnstufe","block.minecraft.banner.square_top_left.blue":"Blaus rechtes Obaeck","block.minecraft.bannerLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Карычневая кераміка","block.minecraft.lapis_ore":"Лазурытавая руда","item.minecraft.gray_dye":"Шэры фарбавальнік","block.minecraft.banner.base.yellow":"Цалкам жоўтае поле","block.minecraft.terracotta":"Кераміка","item.minecraft.stray_spawn_egg":"Яйка прызыву - Бадзяга","block.minecraft.banner.base.pink":"Цалкам ружовае поле","item.minecraft.potion.effect.weakness":"Зелле кволасці","block.minecraft.dark_prismarine_slab":"Пліта з цёмнага прызмарыну","item.minecraft.splash_potion.effect.thick":"Густое выбухное зелле","item.minecraft.cooked_cod":"Смажаная траска","block.minecraft.red_nether_brick_slab":"Пліта з чырвонай нэдарскай цэглы","block.minecraft.yellow_terracotta":"Жоўтая кераміка","block.minecraft.observer":"Назіральнік","block.minecraft.banner.stripe_bottom.cyan":"Бірузовы падножак","block.minecraft.banner.creeper.purple":"Фіялетавая фігура крыпера","block.minecraft.banner.straight_cross.cyan":"Бірузовы крыж","block.minecraft.banner.half_horizontal_bottom.brown":"Карычневая ніжняя палова","item.minecraft.firework_star.shape.large_ball":"Вялікі шар","block.minecraft.prismarine_brick_slab":"Пліта з прызмарынавай цэглы","block.minecraft.jungle_trapdoor":"Люк з трапічнай драўніны","block.minecraft.sculk_sensor":"Скалкавы сэнсар","block.minecraft.banner.creeper.orange":"Аранжавая фігура крыпера","block.minecraft.banner.triangles_top.lime":"Лаймавая зубчастая вяршыня","item.minecraft.charcoal":"Драўняны вугаль","item.minecraft.tipped_arrow.effect.night_vision":"Страла начнога зроку","block.minecraft.stone_brick_slab":"Пліта з каменнай цэглы","block.minecraft.banner.mojang.cyan":"Бірузовы лагатып Mojang","block.minecraft.white_stained_glass":"Белае шкло","item.minecraft.bowl":"Міска","block.minecraft.banner.diagonal_up_left.magenta":"Пурпурная ніжняя левая палова","block.minecraft.banner.square_top_right.light_gray":"Светла-шэры верхні кут справа","block.minecraft.dead_brain_coral_fan":"Мёртвы веерны мазгавы карал","block.minecraft.banner.flower.white":"Белая фігура кветкі","item.minecraft.bone_meal":"Касцявая мука","block.minecraft.banner.triangle_bottom.red":"Чырвонае скарочанае вастрыё","block.minecraft.cyan_carpet":"Бірузовы дыван","block.minecraft.oak_door":"Дубовыя дзверы","block.minecraft.flowering_azalea_leaves":"Лісце квітнеючай азаліі","item.minecraft.prismarine_crystals":"Крышталі прызмарыну","block.minecraft.banner.diagonal_left.cyan":"Бірузовая верхняя левая палова","block.minecraft.banner.stripe_bottom.light_blue":"Блакітны падножак","item.minecraft.tipped_arrow.effect.slow_falling":"Страла павольнага падзення","block.minecraft.end_stone":"Камень Энда","block.minecraft.potted_white_tulip":"Белы цюльпан у гаршку","block.minecraft.warped_door":"Скажоныя дзверы","block.minecraft.banner.square_top_left.light_gray":"Светла-шэры верхні кут злева","item.minecraft.splash_potion.effect.fire_resistance":"Выбухное зелле вогнеўстойлівасці","block.minecraft.banner.half_vertical_right.pink":"Ружовая правая палова","item.minecraft.furnace_minecart":"Ваганетка з печкай","block.minecraft.banner.triangles_bottom.light_gray":"Светла-шэры зубчасты падножак","item.minecraft.shield.red":"Чырвоны шчыт","block.minecraft.quartz_pillar":"Кварцавая калона","block.minecraft.prismarine_slab":"Пліта з прызмарыну","block.minecraft.nether_portal":"Партал у Нэдар","item.minecraft.diamond_sword":"Дыяментавы меч","block.minecraft.oak_planks":"Дубовыя дошкі","item.minecraft.amethyst_shard":"Асколак аметысту","block.minecraft.purple_banner":"Фіялетавы сцяг","block.minecraft.structure_void":"Пустата","block.minecraft.purple_shulker_box":"Фіялетавая шалкеравая скрыня","block.minecraft.potatoes":"Бульба","block.minecraft.light_blue_bed":"Блакітны ложак","block.minecraft.yellow_banner":"Жоўты сцяг","item.modifiers.head":"Калі апранута на галаву:","item.minecraft.potion.effect.swiftness":"Зелле хуткасці"Line truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Кафява теракота","block.minecraft.lapis_ore":"Лазуритна руда","item.minecraft.gray_dye":"Сива боя","block.minecraft.banner.base.yellow":"Напълно жълт плат","block.minecraft.terracotta":"Теракота","item.minecraft.stray_spawn_egg":"Яйце на скелет скитник","block.minecraft.banner.base.pink":"Напълно розов плат","item.minecraft.potion.effect.weakness":"Отвара на слабостта","block.minecraft.dark_prismarine_slab":"Плоча от тъмен призмарин","item.minecraft.splash_potion.effect.thick":"Гъста разплискваща се отвара","item.minecraft.cooked_cod":"Печена треска","block.minecraft.red_nether_brick_slab":"Плоча от червени тухли от Недъра","block.minecraft.yellow_terracotta":"Жълта теракота","block.minecraft.observer":"Наблюдател","block.minecraft.banner.stripe_bottom.cyan":"Синьозелена хоризонтална лента","block.minecraft.banner.creeper.purple":"Лилава фигура на крийпър","block.minecraft.banner.straight_cross.cyan":"Синьозелен кръст","block.minecraft.banner.half_horizontal_bottom.brown":"Кафяво долно пресичане","item.minecraft.firework_star.shape.large_ball":"Голяма топка","block.minecraft.prismarine_brick_slab":"Плоча от призмаринови тухли","block.minecraft.jungle_trapdoor":"Джунглов люк","block.minecraft.sculk_sensor":"Скълк сензор","block.minecraft.banner.creeper.orange":"Оранжева фигура на крийпър","block.minecraft.banner.triangles_top.lime":"Жълтозелени горни зъбци","item.minecraft.charcoal":"Дървени въглища","item.minecraft.tipped_arrow.effect.night_vision":"Стрела на нощното виждане","block.minecraft.stone_brick_slab":"Плоча от каменни тухли","block.minecraft.banner.mojang.cyan":"Синьозелено нещо","block.minecraft.white_stained_glass":"Бяло стъкло","item.minecraft.bowl":"Купа","block.minecraft.banner.diagonal_up_left.magenta":"Пурпурно обърнато скосяване","block.minecraft.banner.square_top_right.light_gray":"Светлосив ляв горен кантон","block.minecraft.dead_brain_coral_fan":"Мъртъв мозъчен мек корал","block.minecraft.banner.flower.white":"Бяла фигура на цвете","item.minecraft.bone_meal":"Стрити кости","block.minecraft.banner.triangle_bottom.red":"Червен шеврон","block.minecraft.cyan_carpet":"Синьозелен килим","block.minecraft.oak_door":"Дъбова врата","block.minecraft.flowering_azalea_leaves":"Цъфтящи азалиеви листа","item.minecraft.prismarine_crystals":"Призмаринови кристали","block.minecraft.banner.diagonal_left.cyan":"Синьозелено скосяване наляво","block.minecraft.banner.stripe_bottom.light_blue":"Светлосиня хоризонтална лента","item.minecraft.tipped_arrow.effect.slow_falling":"Стрела на бавното падане","block.minecraft.end_stone":"Камък от Края","block.minecraft.potted_white_tulip":"Саксия с бяло лале","block.minecraft.warped_door":"Шантава врата","block.minecraft.banner.square_top_left.light_gray":"Светлосив десен горен кантон","item.minecraft.splash_potion.effect.fire_resistance":"Разплискваща се отвара на огнената устойчивост","block.minecraft.banner.half_vertical_right.pink":"Розово ляво разсичане","item.minecraft.furnace_minecart":"Вагонетка с пещ","block.minecraft.banner.triangles_bottom.light_gray":"Светлосиви долни зъбци","item.minecraft.shield.red":"Червен щит","block.minecraft.quartz_pillar":"Кварцова колона","block.minecraft.prismarine_slab":"Призмаринова плоча","block.minecraft.nether_portal":"Портал към Недъра","item.minecraft.diamond_sword":"Диамантен меч","block.minecraft.oak_planks":"Дъбови дъски","item.minecraft.amethyst_shard":"Късче аметист","block.minecraft.purple_banner":"Лилаво знаме","block.minecraft.structure_void":"Конструкционна празнота","block.minecraft.purple_shulker_box":"Лилава шулкърова кутия","block.minecraft.potatoes":"Картофи","block.minecraft.light_blue_bed":"Светлосиньо легло","block.minecraft.yellow_banner":"Жълто знаме","item.modifiers.head":"Когато на Главата:","item.minecraft.potion.effect.swiftness":"Отвара на скоростта","block.minecraft.glass_pane":"СтLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Pri poazh gell","block.minecraft.lapis_ore":"Kailh Lapis Lazuli","item.minecraft.gray_dye":"Livadur griz","block.minecraft.terracotta":"Pri poazh","item.minecraft.stray_spawn_egg":"Vi ganerez kantreerien","item.minecraft.potion.effect.weakness":"Braou gwander","block.minecraft.dark_prismarine_slab":"Dar prismarine teñval","item.minecraft.splash_potion.effect.thick":"Braou tev taoladus","item.minecraft.cooked_cod":"Moru poazh","block.minecraft.red_nether_brick_slab":"Dar brikenn ruz an nether","block.minecraft.yellow_terracotta":"Pri poazh melen","block.minecraft.observer":"Arvester","block.minecraft.banner.stripe_bottom.cyan":"Tostal sian","block.minecraft.banner.creeper.purple":"Penn Creeper mouk","block.minecraft.banner.straight_cross.cyan":"Kroaz sian","block.minecraft.banner.half_horizontal_bottom.brown":"Troc'het, gell da eil","item.minecraft.firework_star.shape.large_ball":"Bolotenn vras","block.minecraft.prismarine_brick_slab":"Dar brikenn Prismarine","block.minecraft.jungle_trapdoor":"Trap koad janglenn","block.minecraft.banner.creeper.orange":"Penn Creeper aouraval","block.minecraft.banner.triangles_top.lime":"Milginoù geoted sklaer ouzh kab","item.minecraft.charcoal":"Glaou koad","item.minecraft.tipped_arrow.effect.night_vision":"Bir gwelet en noz","block.minecraft.stone_brick_slab":"Dar brikenn vaen","block.minecraft.banner.mojang.cyan":"Arouez sian","block.minecraft.white_stained_glass":"Gwer tarchet gwenn","item.minecraft.bowl":"Bolenn","block.minecraft.banner.diagonal_up_left.magenta":"Benet, limestra da eil","block.minecraft.banner.square_top_right.light_gray":"Konk arc'hant griz ouzh kab kleiz","block.minecraft.dead_brain_coral_fan":"Aveler koural empenn marv","block.minecraft.banner.flower.white":"Bleunienn ac'hant","item.minecraft.bone_meal":"Poultr eskern","block.minecraft.banner.triangle_bottom.red":"Mantellet en gul","block.minecraft.cyan_carpet":"Pallenn sian","block.minecraft.oak_door":"Dor zerv","item.minecraft.prismarine_crystals":"Strink Prismarine","block.minecraft.banner.diagonal_left.cyan":"Skejet, sian e kentañ","block.minecraft.banner.stripe_bottom.light_blue":"Tostal glazur sklaer","item.minecraft.tipped_arrow.effect.slow_falling":"Bir kouezhañ gorrek","block.minecraft.end_stone":"Roc'h an End","block.minecraft.potted_white_tulip":"Podad tulipezenn wenn","block.minecraft.banner.square_top_left.light_gray":"Konk arc'hant griz ouzh kab dehoù","item.minecraft.splash_potion.effect.fire_resistance":"Braou dalc'husted d'an tan taoladus","block.minecraft.banner.half_vertical_right.pink":"Rannet, en-gwirion da eil","item.minecraft.furnace_minecart":"Bagon vengleuz gant ur forn","block.minecraft.banner.triangles_bottom.light_gray":"Milginoù arc'hant griz ouzh beg","item.minecraft.shield.red":"Skoed ruz","block.minecraft.quartz_pillar":"Peul kouarz","block.minecraft.prismarine_slab":"Dar prismarine","block.minecraft.nether_portal":"Dor-dal an Nether","item.minecraft.diamond_sword":"Kleze diamant","block.minecraft.oak_planks":"Plankennoù derv","block.minecraft.purple_banner":"Banniel mouk","block.minecraft.structure_void":"Goullonder frammad","block.minecraft.purple_shulker_box":"Boest Shulker Limestra","block.minecraft.potatoes":"Avaloù-douar","block.minecraft.light_blue_bed":"Gwele glas sklaer","block.minecraft.yellow_banner":"Banniel melen","item.minecraft.potion.effect.swiftness":"Braou primder","block.minecraft.glass_pane":"Gwerenn","block.minecraft.clay":"Pri","block.minecraft.banner.diagonal_right.cyan":"Benet, sian e kentañ","block.minecraft.polished_diorite_slab":"Dar diorit lufret","item.minecraft.splash_potion.effect.slow_falling":"Braou strink kouezhañ gorrek","item.minecraft.book":"Levr","block.minecraft.banner.gradient.brown":"Ilrezenn gell","block.minecraft.banner.cross.magenta":"Lammell limestra","block.minecraft.cobblestone_slab":"Dar maen","block.minecraft.banner.diagonal_right.purple":"Benet, mouk e kentañ","block.minecraft.banner.curly_border.gray":"Bevenn korzennek griz","block.minecraft.black_shulker_box":"Boest Shulker Du","block.minecraft.banner.straight_cross.purple":"Kroaz mouk","block.minecraft.banner.triangles_top.blue":"Milginoù glazur ouzh kab","block.minecraft.banner.square_top_left.blue":"Konk glazur ouzh kab dehoù","block.minecraft.banner.stripe_center.yellow":"Peul aour","item.minecraft.firework_star.cyan":"Sian","block.minecraft.brick_slab":"Dar brikenn","block.minecraft.banner.triangle_top.lime":"Mantellet geoted sklaer c'hweniet","block.minecraft.potted_dead_bush":"Podad bochad gwez marv","block.minecraft.banner.half_horizontal.brown":"Troc'het, gell da gentañ","item.minecraft.apple":"Aval","block.minecraft.brown_wool":"Gloan gell","item.minecraft.splash_potion.effect.water":"Boutailhad dour taoladus","block.minecraft.banner.diagonal_right.red":"Benet, en gul e kentañ","item.minecraft.bone":"Askorn","block.minecraft.polished_andesite":"Andezit lufret","block.minecraft.banner.straight_cross.orange":Line truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Brèùn terracotta","block.minecraft.lapis_ore":"Lapis lazuli-erts","item.minecraft.gray_dye":"Grèèze koleurstobber","block.minecraft.banner.base.yellow":"Gèèl veld","block.minecraft.terracotta":"Terracotta","item.minecraft.stray_spawn_egg":"Verdwaoldespawnei","block.minecraft.banner.base.pink":"Raaze veld","item.minecraft.potion.effect.weakness":"Draank der zwakhèèd","block.minecraft.dark_prismarine_slab":"Doenkerprismarienplôat","item.minecraft.splash_potion.effect.thick":"Spattende stroperège draank","item.minecraft.cooked_cod":"Gebakken kabeljauw","block.minecraft.red_nether_brick_slab":"Rooie Netherbakstienen plôat","block.minecraft.yellow_terracotta":"Gèèl terracotta","block.minecraft.observer":"Observeerder","block.minecraft.banner.stripe_bottom.cyan":"Cyaan Basis","block.minecraft.banner.creeper.purple":"Péérs Creeperwapen","block.minecraft.banner.straight_cross.cyan":"Cyaan kruis","block.minecraft.banner.half_horizontal_bottom.brown":"Bruin omgekeerd gebalkt","item.minecraft.firework_star.shape.large_ball":"Groewte bal","block.minecraft.prismarine_brick_slab":"Prismarienblokstiene plôat","block.minecraft.jungle_trapdoor":"Oerwoudhoutere vaalluuk","block.minecraft.sculk_sensor":"Sculksensor","block.minecraft.banner.creeper.orange":"Oranje Creeper symbool","block.minecraft.banner.triangles_top.lime":"Lichtgroen-gegolfd hoofd","item.minecraft.charcoal":"Houtskôol","item.minecraft.tipped_arrow.effect.night_vision":"Pèèl der nachtzicht","block.minecraft.stone_brick_slab":"Blokstiene plôat","block.minecraft.banner.mojang.cyan":"Cyaan ding","block.minecraft.white_stained_glass":"Wietgekleurd glaos","item.minecraft.bowl":"Kom","block.minecraft.banner.diagonal_up_left.magenta":"Magenta omgekeerd schuin-rechts verdeeld","block.minecraft.banner.square_top_right.light_gray":"Lichtgrijs hoofd sinister kanton","block.minecraft.dead_brain_coral_fan":"Dooie hersenkoraalwaojer","block.minecraft.banner.flower.white":"Witte bloem","item.minecraft.bone_meal":"Beendermeel","block.minecraft.banner.triangle_bottom.red":"Rode keper","block.minecraft.cyan_carpet":"Turquoise tapijt","block.minecraft.oak_door":"Èèkehoutere deur","block.minecraft.flowering_azalea_leaves":"Bloeiende azaleabloajer","item.minecraft.prismarine_crystals":"Prismarienkristalle","block.minecraft.banner.diagonal_left.cyan":"Cyaan schuin-links verdeeld","block.minecraft.banner.stripe_bottom.light_blue":"Lichtblauwe basis","item.minecraft.tipped_arrow.effect.slow_falling":"Pèèl der valvertraoging","block.minecraft.end_stone":"Endstien","block.minecraft.potted_white_tulip":"Opgepotte wiete tullep","block.minecraft.warped_door":"Spoèkaetige houtere deure","block.minecraft.banner.square_top_left.light_gray":"Lichtgrijs hoofd dexter kanton","item.minecraft.splash_potion.effect.fire_resistance":"Spattende draank der vuurbestendeghèèd","block.minecraft.banner.half_vertical_right.pink":"Roze omgekeerd gebalkt","item.minecraft.furnace_minecart":"Mijnkar meej oove","block.minecraft.banner.triangles_bottom.light_gray":"Lichtgrijs-gegolfde basis","item.minecraft.shield.red":"Rooi schild","block.minecraft.quartz_pillar":"Kwertspeleer","block.minecraft.prismarine_slab":"Prismarienplôat","block.minecraft.nether_portal":"Netherpertaol","item.minecraft.diamond_sword":"Diamanten zwaord","block.minecraft.oak_planks":"Èèkehoutere plaank","item.minecraft.amethyst_shard":"Amethistscherf","block.minecraft.purple_banner":"Péérse banier","block.minecraft.structure_void":"Konstruksieleegte","block.minecraft.purple_shulker_box":"Péérse shulkerdoâs","block.minecraft.potatoes":"Aerpels","block.minecraft.light_blue_bed":"Liechtblaaw bed","block.minecraft.yellow_banner":"Gele banier","item.modifiers.head":"Hoeneer op ut hoofd:","item.minecraft.potion.effect.swiftness":"Draank der vlothèèd","block.minecraft.glass_pane":"Glaoze rute","block.minecraft.clay":"Klaai","block.minecraft.banner.diagonal_right.cyan":"Cyaan schuin-rechts verdeeld","block.minecraft.cut_copper_slab":"Gesneje kopere plôat","block.minecraft.polished_diorite_slab":"Gepolèèste diorietplôat","block.minecraft.banner.piglin.green":"Grijze snuit","item.minecraft.splash_potion.effect.slow_falling":"Spattende draank der valvertraoging","item.minecraft.book":"Buuk","block.minecraft.banner.gradient.brown":"Bruin gradiënt","block.minecraft.banner.cross.magenta":"Magenta andreaskruis","block.minecraft.cobblestone_slab":"Keistienen plôat","block.minecraft.banner.diagonal_right.purple":"Péérse per band","block.minecraft.banner.curly_border.gray":"Grijs ingesprongen borduursel","block.minecraft.big_dripleaf":"Groewt drèùpblad","block.minecraft.black_shulker_box":"Zwerte shulkerdoâs","block.minecraft.banner.straight_cross.purple":"Péérs kruis","block.minecraft.blackstone_stairs":"Zwertstienen trep","block.minecraft.banner.triangles_top.blue":"Blauw-gegolfd hoofd","block.minecraft.deepslate_tile_slab":"Wrevelstienen tegelplôat","block.minecraft.Line truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Braon Terakota","block.minecraft.lapis_ore":"Ruda Lapiza","item.minecraft.gray_dye":"Sivi pigment","block.minecraft.banner.base.yellow":"Potpuno žuto polje","block.minecraft.terracotta":"Terakota","item.minecraft.stray_spawn_egg":"Jaje lutalice","block.minecraft.banner.base.pink":"Potpuno ružičasto polje","item.minecraft.potion.effect.weakness":"Napitak slabosti","block.minecraft.dark_prismarine_slab":"Ploča od tamnog prizmarina","item.minecraft.splash_potion.effect.thick":"Gusti rasprskujući napitak","item.minecraft.cooked_cod":"Isprženi bakalar","block.minecraft.red_nether_brick_slab":"Crvena Ploča Od Neder Cigle","block.minecraft.yellow_terracotta":"Žuta Terakota","block.minecraft.observer":"Posmatrač","block.minecraft.banner.stripe_bottom.cyan":"Cijan donji dio","block.minecraft.banner.creeper.purple":"Ljubičasti kriper","block.minecraft.banner.straight_cross.cyan":"Cijan krst","block.minecraft.banner.half_horizontal_bottom.brown":"Braon obrnuta puna pruga","item.minecraft.firework_star.shape.large_ball":"Velika lopta","block.minecraft.prismarine_brick_slab":"Prizmarinsko Ciglasta Ploča","block.minecraft.jungle_trapdoor":"Poklopac od džungle","block.minecraft.sculk_sensor":"Sculk senzor","block.minecraft.banner.creeper.orange":"Narandžasti kriper","block.minecraft.banner.triangles_top.lime":"Svijetlo zeleni uvučeni vrh","item.minecraft.charcoal":"Drveni ugalj","item.minecraft.tipped_arrow.effect.night_vision":"Strelica noćnog vida","block.minecraft.stone_brick_slab":"Ploča od kamene cigle","block.minecraft.banner.mojang.cyan":"Cijan stvar","block.minecraft.white_stained_glass":"Bijelo staklo","item.minecraft.bowl":"Posuda","block.minecraft.banner.diagonal_up_left.magenta":"Purpurnocrvena obrnuta puna dijagonala","block.minecraft.banner.square_top_right.light_gray":"Svijetlo sivi gornji lijevi kanton","block.minecraft.dead_brain_coral_fan":"Lepeza od mrtvog mozgastog korala","block.minecraft.banner.flower.white":"Bijeli cvijet","item.minecraft.bone_meal":"Koštano brašno","block.minecraft.banner.triangle_bottom.red":"Crveni trougao","block.minecraft.cyan_carpet":"Cijan tepih","block.minecraft.oak_door":"Vrata od hrasta","block.minecraft.flowering_azalea_leaves":"Cvatući azaleja listovi","item.minecraft.prismarine_crystals":"Kristal prizmarina","block.minecraft.banner.diagonal_left.cyan":"Cijan lijeva puna dijagonala","block.minecraft.banner.stripe_bottom.light_blue":"Svijetlo plavi donji dio","item.minecraft.tipped_arrow.effect.slow_falling":"Strijela sporog padanja","block.minecraft.end_stone":"Enderski Kamen","block.minecraft.potted_white_tulip":"Bijeli tulipan u saksiji","block.minecraft.warped_door":"Izopačena vrata","block.minecraft.banner.square_top_left.light_gray":"Svijetlo sivi gornji desni kanton","item.minecraft.splash_potion.effect.fire_resistance":"Rasprskujući napitak otpornosti na vatru","block.minecraft.banner.half_vertical_right.pink":"Roza obrnuta puna traka","item.minecraft.furnace_minecart":"Vagon sa Peći","block.minecraft.banner.triangles_bottom.light_gray":"Svijetlo siva uvučena osnova","item.minecraft.shield.red":"Crveni štit","block.minecraft.quartz_pillar":"Kvarcni stub","block.minecraft.prismarine_slab":"Ploča od prizmarina","block.minecraft.nether_portal":"Pakleni Portal","item.minecraft.diamond_sword":"Dijamantski Mač","block.minecraft.oak_planks":"Daska od hrasta","item.minecraft.amethyst_shard":"Krhotina ametista","block.minecraft.purple_banner":"Ljubičasta zastava","block.minecraft.structure_void":"Strukturna praznina","block.minecraft.purple_shulker_box":"Ljubičasta kutija shulkera","block.minecraft.potatoes":"Krompiri","block.minecraft.light_blue_bed":"Svijetlo plavi krevet","block.minecraft.yellow_banner":"Žuta zastava","item.modifiers.head":"Kada je na glavi:","item.minecraft.potion.effect.swiftness":"Napitak brzine","block.minecraft.glass_pane":"Staklena ploča","block.minecraft.clay":"Glina","block.minecraft.banner.diagonal_right.cyan":"Cijan puna dijagonala","block.minecraft.cut_copper_slab":"Ploča od rezanog bakra","block.minecraft.polished_diorite_slab":"Glatka ploča od diorita","block.minecraft.banner.piglin.green":"Zelena njuška","item.minecraft.splash_potion.effect.slow_falling":"Rasprskujući napitak sporog padanja","item.minecraft.book":"Knjiga","block.minecraft.banner.gradient.brown":"Braon gradijent","block.minecraft.banner.cross.magenta":"Purpurnocrvena saltira","block.minecraft.cobblestone_slab":"Kamena ploča","block.minecraft.banner.diagonal_right.purple":"Ljubičasta puna dijagonala","block.minecraft.banner.curly_border.gray":"Sivi uvučeni okvir","block.minecraft.big_dripleaf":"Veliki kaplist","block.minecraft.black_shulker_box":"Crna Kutija Shulkera","block.minecraft.banner.straight_cross.purple":"Ljubičasti krst","block.minecraft.blackstone_stairs":"Stepenice od crnog kamena","block.minecraft.banner.triangles_top.blue":"Plavi uvučeni vrh","block.minecraft.deepslate_tile_slab":"PlLine truncated
+1
View File
@@ -0,0 +1 @@
{"block.minecraft.brown_terracotta":"Terracota marró","block.minecraft.lapis_ore":"Mena de lapislàtzuli","item.minecraft.gray_dye":"Tint gris","block.minecraft.banner.base.yellow":"Camp d'or","block.minecraft.terracotta":"Terracota","item.minecraft.stray_spawn_egg":"Generar esquelet extraviat","block.minecraft.banner.base.pink":"Camp rosa","item.minecraft.potion.effect.weakness":"Poció debilitant","block.minecraft.dark_prismarine_slab":"Llosa de prismarina fosca","item.minecraft.splash_potion.effect.thick":"Poció densa llancívola","item.minecraft.cooked_cod":"Bacallà cuit","block.minecraft.red_nether_brick_slab":"Llosa de maons del Nether vermells","block.minecraft.yellow_terracotta":"Terracota groga","block.minecraft.observer":"Observador","block.minecraft.banner.stripe_bottom.cyan":"Peu cian","block.minecraft.banner.creeper.purple":"Cara de creeper porpra","block.minecraft.banner.straight_cross.cyan":"Creu cian","block.minecraft.banner.half_horizontal_bottom.brown":"Truncat, 2n marró","item.minecraft.firework_star.shape.large_ball":"Esfera gran","block.minecraft.prismarine_brick_slab":"Llosa de maons de prismarina","block.minecraft.jungle_trapdoor":"Trapa de jungla","block.minecraft.sculk_sensor":"Sensor sculk","block.minecraft.banner.creeper.orange":"Cara de creeper ataronjada","block.minecraft.banner.triangles_top.lime":"Cap dentat llima","item.minecraft.charcoal":"Carbó vegetal","item.minecraft.tipped_arrow.effect.night_vision":"Fletxa de visió nocturna","block.minecraft.stone_brick_slab":"Llosa de maons de roca","block.minecraft.banner.mojang.cyan":"Emblema cian","block.minecraft.white_stained_glass":"Vidre tenyit de blanc","item.minecraft.bowl":"Bol","block.minecraft.banner.diagonal_up_left.magenta":"Trinxat, 2n magenta","block.minecraft.banner.square_top_right.light_gray":"Cantó sinistre del cap d'argent","block.minecraft.dead_brain_coral_fan":"Gorgònia de cervell morta","block.minecraft.banner.flower.white":"Flor blanca","item.minecraft.bone_meal":"Farina d'ossos","block.minecraft.banner.triangle_bottom.red":"Gaiat a la punta de gules","block.minecraft.cyan_carpet":"Catifa cian","block.minecraft.oak_door":"Porta de pomer","block.minecraft.flowering_azalea_leaves":"Fulles d'azalea florida","item.minecraft.prismarine_crystals":"Cristalls de prismarina","block.minecraft.banner.diagonal_left.cyan":"Tallat, 1r cian","block.minecraft.banner.stripe_bottom.light_blue":"Peu blau cel","item.minecraft.tipped_arrow.effect.slow_falling":"Fletxa de caiguda lenta","block.minecraft.end_stone":"Roca de l'End","block.minecraft.potted_white_tulip":"Test amb tulipà blanc","block.minecraft.warped_door":"Porta guerxa","block.minecraft.banner.square_top_left.light_gray":"Cantó destre del cap d'argent","item.minecraft.splash_potion.effect.fire_resistance":"Poció de resistència ígnia llancívola","block.minecraft.banner.half_vertical_right.pink":"Partit, 2n rosa","item.minecraft.furnace_minecart":"Vagoneta amb forn","block.minecraft.banner.triangles_bottom.light_gray":"Peu dentat d'argent","item.minecraft.shield.red":"Escut vermell","block.minecraft.quartz_pillar":"Pilar de quars","block.minecraft.prismarine_slab":"Llosa de prismarina","block.minecraft.nether_portal":"Portal del Nether","item.minecraft.diamond_sword":"Espasa de diamant","block.minecraft.oak_planks":"Fusta de pomer","item.minecraft.amethyst_shard":"Fragment d\u2019ametista","block.minecraft.purple_banner":"Estendard de porpra","block.minecraft.structure_void":"Buit estructural","block.minecraft.purple_shulker_box":"Caixa de shulker lila","block.minecraft.potatoes":"Patates","block.minecraft.light_blue_bed":"Llit blau cel","block.minecraft.yellow_banner":"Estendard d'or","item.modifiers.head":"Al cap:","item.minecraft.potion.effect.swiftness":"Poció de velocitat","block.minecraft.glass_pane":"Panell de vidre","block.minecraft.clay":"Argila","block.minecraft.banner.diagonal_right.cyan":"Trinxat, 1r cian","block.minecraft.cut_copper_slab":"Llosa de coure tallat","block.minecraft.polished_diorite_slab":"Llosa de diorita polida","block.minecraft.banner.piglin.green":"Morro de sinople","item.minecraft.splash_potion.effect.slow_falling":"Poció llancívola de caiguda lenta","item.minecraft.book":"Llibre","block.minecraft.banner.gradient.brown":"Degradat marró","block.minecraft.banner.cross.magenta":"Sautor magenta","block.minecraft.cobblestone_slab":"Llosa de pedra","block.minecraft.banner.diagonal_right.purple":"Trinxat, 1r de porpra","block.minecraft.banner.curly_border.gray":"Bordura dentada grisa","block.minecraft.big_dripleaf":"Degotadora gran","block.minecraft.black_shulker_box":"Caixa de shulker negra","block.minecraft.banner.straight_cross.purple":"Creu de porpra","block.minecraft.blackstone_stairs":"Escales de roca negra","block.minecraft.banner.triangles_top.blue":"Cap dentat d'atzur","block.minecraft.deepslate_tile_slab":"Llosa de rajoles de pissarra","block.minecraft.banner.square_top_left.blue":"Cantó destre del cap d'atzur","blockLine truncated
Loaded 100 of 214 files, more files were not shown because too many files have changed in this diff. Show more