9
0
mirror of https://github.com/HibiscusMC/HMCCosmetics.git synced 2025-12-19 15:09:19 +00:00

Compare commits

...

250 Commits

Author SHA1 Message Date
LoJoSho
4a1a631557 chore: update HibiscusCommons 2025-06-26 15:42:58 -05:00
LoJoSho
ad282a9efe feat: overhaul to new Hibiscus commons system 2025-06-26 15:24:54 -05:00
LoJoSho
86ef4d0efa chore: update test server to 1.21.6 2025-06-24 14:23:19 -05:00
LoJoSho
da09a542f1 chore: update luckperms on test server 2025-06-24 14:14:45 -05:00
LoJoSho
62f32cc03d version bump (2.7.10) 2025-06-24 11:14:37 -05:00
lucian929
ff1addfd65 chore: change defaultmenu configurations for new gui 2025-06-24 11:57:38 -04:00
lucian929
73f013bf1f chore: change defaultmenu for new gui 2025-06-24 08:46:48 -04:00
lucian929
204fee4456 chore: change shading pattern for new gui 2025-06-24 08:43:31 -04:00
LoJoSho
e7ea62a4d2 chore: update adventure dependencies 2025-06-22 14:02:58 -05:00
LoJoSho
42802e41b4 fix: dyeable dye click not defaulting to correct value 2025-06-10 10:08:20 -05:00
LoJoSho
7e7d81d0f8 fix: CosmeticUser not handling null entities 2025-06-10 09:21:37 -05:00
LoJoSho
b07c3c9878 fix: Actions not handling nulls properly 2025-06-09 10:53:27 -05:00
LoJoSho
a19d564460 fix: UNDEFINED DISPLAY ITEM using paper-only methods 2025-06-08 10:21:31 -05:00
LoJoSho
b3408143f0 fix: HMCColor integrate (remove legacy formatting, clean dyeclicktype) 2025-05-31 10:22:30 -05:00
LoJoSho
3c1539285d feat: translations no longer go through legacy formatting 2025-05-31 09:35:41 -05:00
LoJoSho
a642d88af2 chore: update luckperms on test server 2025-05-31 09:11:24 -05:00
LoJoSho
36d4009f5e version bump (2.7.9) 2025-05-31 09:07:45 -05:00
LoJoSho
bebee807bc fix: fix possible database memory leak (as well as improvements in code) 2025-05-29 14:59:57 -05:00
LoJoSho
26c579b69f chore: add cosmetic passengers to dump command 2025-05-25 14:02:04 -05:00
LoJoSho
ef665e7e83 fix: improper call to getEntity when not needed 2025-05-23 13:22:29 -05:00
LoJoSho
7a6475c467 chore: update LuckPerms 2025-05-22 21:07:12 -05:00
LoJoSho
63963cccc3 clean: server listener priorities 2025-05-21 23:56:30 -05:00
Logan
7cf6a3c75c Merge pull request #182 from HibiscusMC/refactorio
refactor: improve worldguard listener
2025-05-18 08:33:37 -05:00
Boy0000
22a5bb4cf1 refactor: improve worldguard listener 2025-05-18 13:22:38 +02:00
Logan
148d163d9c Merge pull request #181 from DebitCardz/fix-add-user
add user to pre unload
2025-05-16 14:50:22 -05:00
Tech
ef36e66c51 add user to pre unload 2025-05-16 15:13:38 -04:00
Logan
e5fda588c3 Merge pull request #179 from DebitCardz/constructor
expose constructor
2025-05-11 18:46:12 -05:00
Logan
3baf2694be Merge pull request #177 from DebitCardz/connection-update
add unload
2025-05-11 15:08:25 -05:00
Tech
a1dafdee5b expose constructor 2025-05-11 14:40:08 -04:00
Tech
e3a42d8b4a add unload 2025-05-10 10:40:30 -04:00
Boy0000
b366f5930b fix: dyed cosmetic item not updated 2025-05-10 00:07:19 +02:00
lojosho
45eb1fa668 chore: update HibiscusCommons 2025-05-09 11:35:13 -05:00
Logan
c466405a81 Merge pull request #176 from HibiscusMC/le-epic-minor-tweaks-again-we-love-it
feat: dyeable click-type & color changes
2025-05-09 10:56:31 -05:00
Boy0000
172ffc0333 refactor: swap to commons color api 2025-05-09 16:00:26 +02:00
Boy0000
41ac857a11 feat: determine color based on new HMCColor API to allow any Material to be dyable 2025-05-09 14:32:29 +02:00
Boy0000
737d63642c feat: add dye-click to settings 2025-05-09 13:46:12 +02:00
Boy
7b9b7678a3 chore: crucial typo fix 2025-05-09 11:42:45 +02:00
Boy
fe88d0c608 fix: bump hmccolor 2025-05-09 11:42:45 +02:00
lojosho
e14935af7b feat: add new processItemMeta implementation that respects MiniMessage/Components as best it can 2025-05-07 22:22:16 -05:00
lojosho
3e83d370f8 chore: update HibiscusCommons 2025-05-03 09:55:01 -05:00
lojosho
874a7f5624 fix: menu packet changes in 1.21.5 2025-05-02 10:50:21 -05:00
lojosho
3af992a291 chore: remove default emote in defaultcosmetics.yml 2025-05-02 10:43:17 -05:00
Logan
9ef7791998 Merge pull request #174 from HibiscusMC/minor-tweaks
Minor tweaks
2025-04-26 09:39:00 -05:00
Boy
1cbe17ddd4 chore: bump triumph-gui 2025-04-26 13:53:09 +02:00
Boy
2841742af9 fix: allow id to be specified in menu-config, default to filename 2025-04-26 12:16:41 +02:00
LoJoSho
6e2f333404 chore: add more debugging for balloon updating 2025-04-19 16:44:03 -05:00
lojosho
af8949b713 chore: remove emotes 2025-04-14 16:35:25 -05:00
lojosho
d6f7d0fcb3 version bump (2.7.8) 2025-04-14 16:34:48 -05:00
lojosho
a8f035bbe2 chore: update API equipCosmetic to use addCosmetic method 2025-03-20 15:29:22 -05:00
lojosho
301fd6a349 chore: move console commands to addCosmetic 2025-03-20 15:27:30 -05:00
lojosho
90b71e7dc9 clean: mark addPlayerCosmetic for removal 2025-03-20 15:27:06 -05:00
lojosho
e6827cdf72 clean: remove version checks on startup for deprecated emotes 2025-03-20 15:22:23 -05:00
lojosho
1212ab2025 chore: update to latest HibiscusCommons; getNMSVersion api adjusted to new enums 2025-03-18 20:42:23 -05:00
lojosho
e31f000de6 chore: add javadocs to MenuTypes; ids menu item types must now be unique 2025-03-17 12:44:13 -05:00
lojosho
70028598d5 fix: menu type not defaulting to empty when not provided 2025-03-17 12:37:49 -05:00
Andre Roldan
07b772d228 Merge pull request #172 from yusshu/remapped
Micro-optimization on methods that are called a lot of times
2025-03-14 09:46:04 -05:00
Andre Roldan
065e48c125 Merge branch 'HibiscusMC:remapped' into remapped 2025-03-11 02:32:34 -05:00
yusshu
49eb1d61ef perf: remove repeated logic when getting location viewers
PacketManager#getViewers already performs the distance <= 0 check
2025-03-10 20:02:55 -05:00
yusshu
9e1a30025f perf: cache some variables in CosmeticBackpackType#update 2025-03-10 19:57:21 -05:00
yusshu
76429ed041 perf: avoid creating unnecessary collection copies 2025-03-10 19:48:30 -05:00
yusshu
f5a01c0104 perf: remove unnecessary null-check 2025-03-10 19:46:02 -05:00
yusshu
545f258f90 perf: avoid creating an ImmutableCollection copy every time updateCosmetics() is called
micro-optimizations, also we avoid calling Map#get again and using cosmetic.update(this) instead
2025-03-10 19:30:00 -05:00
yusshu
720437212b perf: do not double call Map get (microoptimization) 2025-03-10 19:26:50 -05:00
yusshu
d932732d9b feat: add getVelocity() method to UserBalloonManager 2025-03-10 19:24:30 -05:00
yusshu
1118be1153 fix: set velocity after setting the location
otherwise the velocity would be set to zero after teleporting the balloon
2025-03-10 19:24:12 -05:00
Logan
1dc549d645 Merge pull request #171 from yusshu/remapped
feat(api): add CosmeticHolder interface
2025-03-02 23:09:12 -06:00
yusshu
4136d19396 *: go back to 2.7.7, add @NotNull and @Nullable annotations for CosmeticHolder interface 2025-03-03 00:05:19 -05:00
yusshu
52de7425e4 fix: fix compiling error 2025-03-01 18:14:25 -05:00
yusshu
f470e55142 chore: bump up minor version 2025-03-01 18:12:27 -05:00
yusshu
470de3b749 feat(api): add CosmeticHolder interface
allows plugins to implement their custom cosmetic holders and open menus for them, will also allow to open the cosmetics menu of a player to another player (for administration purposes maybe)
2025-03-01 18:05:54 -05:00
LoJoSho
ea72499826 fix: adjust several methods to properly use entity rather than assuming all entities are players 2025-02-28 11:34:21 -06:00
LoJoSho
6b19bf442a chore: update adventure depends to 4.19.0 2025-02-25 19:17:47 -06:00
LoJoSho
436de38102 version bump (2.7.6) 2025-02-25 19:16:45 -06:00
LoJoSho
4bb00071d4 Merge remote-tracking branch 'origin/remapped' into remapped 2025-02-25 10:45:39 -06:00
LoJoSho
650cf75168 chore: improvements to HookBetterHud 2025-02-25 10:45:25 -06:00
lucian929
0d07e8a267 chore: change Oraxen references to Nexo
Oraxen support is being deprecated
2025-02-25 11:17:17 -05:00
LoJoSho
b7ec587d7d feat: add BetterHud as a soft depend 2025-02-22 21:37:51 -06:00
LoJoSho
e807c7e2f7 fix: respect settings about HUDs 2025-02-22 21:36:47 -06:00
LoJoSho
15e1f0aaa9 fix: BetterCommand not at a proper version; moved to 1.3 2025-02-22 20:56:39 -06:00
LoJoSho
f1e975f940 feat: add BetterHUD support for huds in wardrobes 2025-02-22 20:47:34 -06:00
LoJoSho
89fba800a4 clean: do not include qodana file 2025-02-14 23:54:26 -06:00
LoJoSho
863275a2ce feat: add Nexo comments to the default config 2025-02-14 23:53:56 -06:00
LoJoSho
b516cfced4 fix: color being passed to item cosmetic from previous cosmetic 2025-01-31 12:18:02 -06:00
LoJoSho
28034318ac fix: check if player is online before running wardrobe 2025-01-30 09:35:20 -06:00
LoJoSho
c2e4764ace feat: add async listeners to WINDOW_ITEMS and WINDOW_CLICK packets 2025-01-30 09:29:25 -06:00
LoJoSho
948bfb17f5 clean: update Paper repo 2025-01-30 09:28:17 -06:00
LoJoSho
6c98b7696a Merge pull request #168 from DebitCardz/fix/tick-task
Force Tick Task to Dispatch On CosmeticUser Create
2025-01-27 15:35:10 -06:00
Tech
2c4638fa47 fix broken java doc 2025-01-27 16:27:47 -05:00
Tech
ced2fe7b03 force tick task to dispatch on create 2025-01-27 16:22:52 -05:00
LoJoSho
3a56f074fa Merge pull request #167 from DebitCardz/misc/dl-sources
Include javadoc and sources
2025-01-27 11:56:55 -06:00
Tech
dca5abe4ec include javadoc and sources 2025-01-27 12:24:21 -05:00
LoJoSho
1dd54ea1cb fix: loading user data not properly checking disabled worlds 2025-01-26 17:02:48 -06:00
LoJoSho
b81af97573 Merge pull request #166 from DebitCardz/feat/cosmetic-provider
cosmetic provider & cleanup
2025-01-26 16:33:48 -06:00
LoJoSho
74d64b16d2 fix: readd toString for CosmeticSlot 2025-01-26 11:42:06 -06:00
Tech
2174ec6124 cosmetic provider & cleanup 2025-01-26 11:57:08 -05:00
LoJoSho
1de84bce6f Merge pull request #163 from DebitCardz/refactor/initialize
Allow Custom Implementations of CosmeticUser Initialization
2025-01-25 21:30:51 -06:00
LoJoSho
3aa5939225 clean: simplify logic surrounding new initialize logic 2025-01-25 21:13:38 -06:00
Tech
44650250c5 initialize method 2025-01-25 12:18:32 -05:00
LoJoSho
49fff9b650 Merge remote-tracking branch 'origin/remapped' into remapped 2025-01-24 19:34:36 -06:00
LoJoSho
190f66a990 feat: rewrite CosmeticSlot to allow for a consumers to run 2025-01-24 19:34:21 -06:00
LoJoSho
8a34f100d3 clean: annotate Menus to be more clean about returns and arguments 2025-01-23 14:47:13 -06:00
LoJoSho
79687a22fc feat: add usage for PlayerMenuCloseEvent, closes #158 2025-01-23 13:58:51 -06:00
LoJoSho
f5fac4e048 Merge pull request #162 from Craftinators/remapped
Cleanup previous PR changes
2025-01-23 12:21:59 -06:00
Craftinators
eac0812dbb refactor(PlayerConnectionListener): change Slf4j logging for internal logger 2025-01-23 12:22:04 -05:00
Craftinators
93f5bfbb2a docs(HMCCosmeticsAPI): remove unused imports and minor javadocs changes 2025-01-23 12:21:35 -05:00
Craftinators
94cba225a6 docs(CosmeticUsers): remove unused imports and small typo 2025-01-23 12:21:09 -05:00
Craftinators
ab614d8b07 docs(CosmeticUserProvider): add nullability annotations for methods 2025-01-23 12:10:34 -05:00
LoJoSho
e7fd39a077 Merge pull request #161 from DebitCardz/docs/api-note
Add API Note
2025-01-22 18:48:12 -06:00
Tech
530cdb282b add further docs 2025-01-22 19:46:54 -05:00
LoJoSho
97534f6916 Merge pull request #160 from DebitCardz/feat/player-provider
Implement Custom Player Providers
2025-01-22 18:40:10 -06:00
Tech
22fb52acc6 create user without data 2025-01-22 17:22:05 -05:00
Tech
cf0da580e0 expose getting cosmetic user provider 2025-01-22 17:21:58 -05:00
Tech
64a590b581 check against correct provider 2025-01-22 17:09:07 -05:00
Tech
afb3218bc1 cosmetic user provider impl 2025-01-22 17:01:14 -05:00
LoJoSho
170911a6a1 Merge pull request #157 from DebitCardz/fix/recursive-register
fix recursive registration
2025-01-22 14:57:19 -06:00
LoJoSho
ea5b878f74 Merge pull request #159 from Craftinators/remapped
Javadoc changes to `api` directory
2025-01-22 14:52:54 -06:00
Craftinators
88af1cd68e Merge branch 'HibiscusMC:remapped' into remapped 2025-01-22 15:43:31 -05:00
Craftinators
34237e0a45 docs: Minor javadoc changes to most of the api directory 2025-01-22 15:28:26 -05:00
Craftinators
a037487497 docs(PlayerCosmeticPostEquipEvent): add missing period 2025-01-22 11:06:36 -05:00
Craftinators
e7b1fda73e docs(PlayerCosmeticPostEquipEvent): improve Javadocs 2025-01-22 11:05:56 -05:00
Craftinators
c591641754 docs(PlayerCosmeticHideEvent): improve Javadocs 2025-01-22 11:03:40 -05:00
Craftinators
2a0aa1593a docs(PlayerCosmeticEvent): add link to CosmeticUser 2025-01-22 11:00:10 -05:00
Craftinators
330723a45c docs(PlayerCosmeticEquipEvent): improve Javadocs 2025-01-22 10:59:00 -05:00
Craftinators
f6a1438299 docs(PlayerEvent): improve Javadocs 2025-01-22 10:55:04 -05:00
Craftinators
1f0f8e5f70 docs(PlayerCosmeticEvent): improve Javadocs 2025-01-22 10:54:52 -05:00
Craftinators
216c05ed9b docs(HMCCosmeticSetupEvent): Add missing period 2025-01-22 10:50:31 -05:00
Craftinators
89fbacafac docs(CosmeticTypeRegisterEvent): Improved Javadocs and added annotations 2025-01-22 10:48:29 -05:00
Tech
8c45bfc76b fix recursive registration 2025-01-22 05:21:59 -05:00
LoJoSho
4ad3c02d88 Merge pull request #156 from Craftinators/remapped
Additional Javadoc Changes to `HMCCosmeticsAPI`
2025-01-21 23:42:19 -06:00
Craftinators
477729242b Merge remote-tracking branch 'origin/remapped' into remapped 2025-01-22 00:41:17 -05:00
Craftinators
e96d06892a docs(HMCCosmeticsAPI): lowercase "ID" 2025-01-22 00:40:52 -05:00
Craftinators
5b1b91f119 Merge branch 'HibiscusMC:remapped' into remapped 2025-01-22 00:37:20 -05:00
Craftinators
446e629474 docs(HMCCosmeticsAPI): remove unnecessary documentation 2025-01-22 00:35:13 -05:00
LoJoSho
57c2cd0719 Merge pull request #155 from Craftinators/remapped
`HMCCosmeticsAPI` Javadoc Changes
2025-01-21 23:35:02 -06:00
Craftinators
8f2a01b348 refactor(HMCCosmeticsAPI): private constructor on HMCCosmeticsAPI 2025-01-22 00:07:38 -05:00
Craftinators
6fe5817fd7 docs(HMCCosmeticsAPI): improve javadocs for utility methods 2025-01-21 23:56:04 -05:00
LoJoSho
663b3d1647 chore: add priorities and ignore cancelled for PaperPlayerGameListener events 2025-01-21 13:36:05 -06:00
LoJoSho
bf0a372edd feat: add api events relating to loading/unloading users (PlayerLoadEvent, PlayerPreLoadEvent, PlayerUnloadEvent) 2025-01-21 13:19:48 -06:00
LoJoSho
5d0237e28c feat: add config option about backpack darkness option 2025-01-21 11:58:49 -06:00
LoJoSho
349311cb58 feat: move default-menu to defaultmenu subcommand 2025-01-21 11:51:55 -06:00
LoJoSho
a1098641b5 feat: add cosmetic slot API methods 2025-01-21 11:49:09 -06:00
LoJoSho
8c0ca5083d feat: add default menu set setting message 2025-01-21 11:40:31 -06:00
LoJoSho
c42ecadd90 Merge remote-tracking branch 'origin/remapped' into remapped 2025-01-21 11:29:22 -06:00
LoJoSho
735386718e Revert "feat: begin migrating over to the new getViewers method"
This reverts commit c31d2e1aee.
2025-01-20 16:17:39 -06:00
LoJoSho
95459cc2d2 chore: use new TriumphGUI method 2025-01-19 13:39:08 -06:00
LoJoSho
fe52edd833 clean: more documentation with the CosmeticSlot registry 2025-01-18 16:34:47 -06:00
LoJoSho
d659128ae4 feat: add set default menu to setWardrobeSetting command 2025-01-17 15:39:08 -06:00
LoJoSho
397eebf38f Merge pull request #154 from HibiscusMC/cosmeticslot_registry
Migrate CosmeticSlot to a Registry
2025-01-17 15:24:58 -06:00
LoJoSho
e18690496f clean: clean HMCCInventoryUtils with new static variables 2025-01-17 14:57:43 -06:00
LoJoSho
c522581d46 feat: migrate over to using a registry for CosmeticSlot than enums 2025-01-17 14:45:08 -06:00
LoJoSho
c31d2e1aee feat: begin migrating over to the new getViewers method 2025-01-17 14:06:40 -06:00
LoJoSho
9879c82d40 clean: minor format adjustment in build.gradle.kts 2025-01-17 13:19:45 -06:00
LoJoSho
1873f5b9b5 feat: hook into hooks to check invisibility 2025-01-16 20:53:05 -06:00
LoJoSho
68d94be743 chore: remove unused hasClass method (use HibiscusCommons method instead) 2025-01-16 13:26:59 -06:00
LoJoSho
14e38e7974 chore: remove old, unused Backpack ModelEngine 4 2025-01-16 13:19:40 -06:00
LoJoSho
5cc19ab2db chore: move getNearbyPlayers from HMCCPlayerUtils to getViewers HMCCPacketManager 2025-01-16 13:11:30 -06:00
LoJoSho
93b1c20c40 chore: remove old Utils class 2025-01-16 12:59:20 -06:00
LoJoSho
49435436cb chore: move from deprecated spigot event to bukkit event 2025-01-16 12:54:40 -06:00
LoJoSho
0477e801a6 chore: move away from internally deprecated methods 2025-01-16 12:45:53 -06:00
LoJoSho
5779d278a9 chore: update paper api (1.20.4) & lombok (1.18.36) 2025-01-16 12:11:36 -06:00
LoJoSho
0a8821d3e8 chore: update test server to 1.21.4 2025-01-14 00:03:10 -06:00
LoJoSho
e96e9e00bb feat: use HibiscusHooksAllActiveEvent for reloading plugins that active their items later 2025-01-14 00:02:37 -06:00
LoJoSho
217fb5d332 fix: HookHMCC not setting itself as active 2025-01-14 00:01:49 -06:00
LoJoSho
6636cc9548 chore: add more documentation to entering and leaving wardrobes 2025-01-10 14:14:02 -06:00
LoJoSho
c3fcf760d7 clean: move setWardrobeStatus to Lombok; make wardrobe update method private 2025-01-10 14:05:08 -06:00
LoJoSho
7116767e22 clean: remove unused caching user items 2025-01-10 14:01:35 -06:00
LoJoSho
0877165f9f clean: adjust distance check in wardrobes 2025-01-10 13:57:08 -06:00
LoJoSho
b43466a793 clean: remove old ProtocolLib code 2024-12-29 17:18:21 -06:00
LoJoSho
401e6170e6 version bump (2.7.5) 2024-12-29 15:40:22 -06:00
LoJoSho
782eb4c464 chore: update adventure dependencies 2024-12-29 15:40:09 -06:00
LoJoSho
1ef2c6b631 chore: update gradle (8.12) & run-paper (2.3.1) 2024-12-28 19:49:48 -06:00
LoJoSho
c7667b2dc2 chore: improve version handling 2024-12-28 18:20:09 -06:00
LoJoSho
e4c4933d46 chore: more debug in passenger listener 2024-12-16 13:27:13 -06:00
LoJoSho
1f94192772 chore: update LP in runServer 2024-12-16 13:26:45 -06:00
LoJoSho
8ebcea5465 feat: if player is hidden from another player, their cosmetics are no longer seen 2024-12-06 13:36:49 -06:00
LoJoSho
4c7ccc06ca feat: version now has commit hash with it 2024-12-04 08:55:39 -06:00
LoJoSho
667f58ff4b fix: mount packet has bad if test 2024-11-25 13:22:58 -06:00
LoJoSho
69d318c4b0 feat: add Nexo support 2024-11-23 20:35:19 -06:00
LoJoSho
0414f3be90 clean: remove first person backpack update message (it is spammy) 2024-11-23 20:27:21 -06:00
LoJoSho
402203b4c2 feat: add passenger listener to better ensure backpacks stay on 2024-11-23 20:26:57 -06:00
LoJoSho
6dcaf06ebe feat: add defaultmenu to specific wardrobes 2024-11-19 20:43:31 -06:00
LoJoSho
1b6adca00e fix: balloon pufferfish getting wrong viewers 2024-11-16 10:57:31 -06:00
LoJoSho
0dce5822e3 feat: overhaul of getting player data 2024-11-15 21:59:32 -06:00
LoJoSho
0f1b75f09e feat: update to Hibiscus Commons 0.5 2024-11-15 20:21:04 -06:00
LoJoSho
19192c46a5 feat: add config options to avoid certain item processing if desired 2024-10-30 10:14:29 -05:00
LoJoSho
62a9e7d1ac chore: define variable nullability for getUserCosmeticItem 2024-10-30 09:21:27 -05:00
LoJoSho
06077201f9 fix: not checking if a null variable is null before usage in balloon handling in the wardrobe 2024-10-30 09:15:14 -05:00
LoJoSho
b2795a705e fix: not checking if itemstack has meta data before modification of meta data 2024-10-27 19:54:55 -05:00
LoJoSho
1e6734bf6f feat: console can now apply any cosmetic to a player 2024-10-24 20:34:17 -05:00
LoJoSho
ad382e5d9e chore: update ProtocolLib to newest version 2024-10-21 12:28:39 -05:00
LoJoSho
6458a1e316 chore: add downloadPlugins to runServer task 2024-10-13 17:38:11 -05:00
LoJoSho
279d6edc34 fix: mainhand showing even if invisible 2024-10-12 12:34:17 -05:00
LoJoSho
439dc85aa3 feat: add Hibiscus Commons / GSit compatibility 2024-10-10 22:50:58 -05:00
LoJoSho
60e23411dc fix: fixed cosmetic applying owner skull npe? (Should have already been checked but is now fully checked) 2024-10-02 22:24:04 -05:00
LoJoSho
33fb680c22 fix: Possible null in getEquipSlot 2024-10-01 23:58:44 -05:00
LoJoSho
536b7ebdec clean: remove jeff repo (moved to Hibiscus Commons) 2024-09-20 17:54:23 -05:00
LoJoSho
5da95f2f5b fix: finish the full update to Java 21 2024-09-20 17:50:51 -05:00
LoJoSho
30f4a84241 feat: menu command not having menu id will now open default menu 2024-09-20 17:13:54 -05:00
LoJoSho
f34e126c85 chore: bring test-server to 1.21.1 2024-09-20 17:11:49 -05:00
LoJoSho
d7d0f27e49 chore: fix misspelled relocated paths 2024-08-26 13:16:33 -05:00
LoJoSho
f42937a6d0 fix: Model Engine coloring throwing class not found (version bump 2.7.4-DEV) 2024-08-26 12:57:23 -05:00
LoJoSho
c8b7430998 clean: update gradle wrapper 2024-08-16 10:11:33 -05:00
LoJoSho
42de76d84d version bump (2.7.3) 2024-08-16 09:33:26 -05:00
LoJoSho
5102fd77b7 Merge remote-tracking branch 'origin/remapped' into remapped 2024-08-09 10:03:11 -05:00
LoJoSho
9c66d4ee81 fix: entering wardrobe not activating if allow cosmetics set to allow 2024-08-09 10:02:59 -05:00
LoJoSho
7ade2d9227 fix: ProtocolLib body part changed in newest versions 2024-08-05 21:27:13 -05:00
LoJoSho
7b43b42740 Revert "feat: customize backpack light emination"
This reverts commit 3cf265f231.
2024-08-01 18:31:05 -05:00
LoJoSho
25f050f387 Revert "feat: add user cosmetic item caching"
This reverts commit 34b02574b2.
2024-08-01 18:27:38 -05:00
Boy
05c13e8990 fix: swapping hotbar-slot resetting NBT of previous-item 2024-07-22 02:24:59 +02:00
LoJoSho
34b02574b2 feat: add user cosmetic item caching 2024-07-21 11:04:06 -05:00
LoJoSho
f81d350a2e clean: update depends 2024-07-11 21:36:50 -05:00
LoJoSho
be86314daf feat: add none database type 2024-07-11 21:23:51 -05:00
LoJoSho
345f903113 clean: remove duplicate emote folder check 2024-07-11 21:14:54 -05:00
LoJoSho
3cf265f231 feat: customize backpack light emination 2024-07-08 18:03:12 -05:00
LoJoSho
d26e7df2ca Merge remote-tracking branch 'origin/remapped' into remapped 2024-07-02 19:43:17 -05:00
LoJoSho
e5dc3f6774 feat: update to Java 21 2024-07-02 19:42:45 -05:00
LoJoSho
fdc9893a60 Merge pull request #147 from MineInAbyss/tweaks
refactor: make hidden-cosmetics message only show when player has cos…
2024-06-15 21:54:15 -05:00
Boy
e8694076b8 refactor: make hidden-cosmetics message only show when player has cosmetics equipped 2024-06-16 01:11:06 +02:00
LoJoSho
1acf536080 fix: ending wardrobe getting illegal argument (same as previous commit) 2024-06-15 09:41:34 -05:00
LoJoSho
9d3ad0b54b fix: 1.20.6 shooting error illegal arguments on equipment slot update 2024-06-15 08:33:05 -05:00
LoJoSho
0b2ade1598 clean: remove old 1.18.2 and 1.19.1/2/3 old packet code 2024-06-14 17:29:03 -05:00
LoJoSho
83651b7250 clean: change our onPlayerLook to onPlayerMove to better describe what it listens to 2024-06-14 17:21:56 -05:00
LoJoSho
6818c09a69 chore: add documentation to CosmeticTypeRegisterEvent 2024-06-14 17:19:46 -05:00
LoJoSho
dc72b677de Merge pull request #144 from MineInAbyss/remapped
feat: Third-party CosmeticTypes, & minor API methods
2024-06-08 17:43:46 -05:00
Boy
5ff1a63eaa feat: add WardrobeManager#lastOpenMenu 2024-06-08 21:30:47 +02:00
LoJoSho
8300a86225 chore: update adventure dependencies 2024-06-08 14:20:21 -05:00
LoJoSho
9e8084194a chore: update triumph gui to 3.1.10 (this was not marked as the latest version) 2024-06-08 14:16:02 -05:00
LoJoSho
c0ea4d5a5b chore: update triumph gui to 3.1.8 2024-06-08 14:15:02 -05:00
Boy
5a963391f8 feat: add locked-equipped-item 2024-06-07 17:36:16 +02:00
Boy
6c4586a6b9 fix: nullpointer due to CUSTOM cosmeticslot 2024-06-07 17:36:16 +02:00
Boy
4cc0a6f968 feat: add CosmeticTypeRegisterEvent to allow for third-party CosmeticTypes 2024-06-07 17:36:16 +02:00
LoJoSho
ab8656ad1a feat: add more logic for dealing with closed connections, closes #140 2024-06-06 19:38:53 -05:00
LoJoSho
ca5e0f96c2 clean: change require-empty in default config to false 2024-06-02 19:58:31 -05:00
LoJoSho
5cddd24097 feat: add HibiscusPlayerEmote events; bumped Hibiscus Commons to 0.4.1 2024-05-29 12:51:21 -05:00
LoJoSho
656e539ae3 feat: add menu clicking cooldown 2024-05-27 21:28:31 -05:00
LoJoSho
862b7c9ee6 fix: Backpacks not appearing after respawning in a different world 2024-05-26 15:31:19 -05:00
LoJoSho
c632174de8 clean: update debug message for menu updateItem 2024-05-24 17:36:34 -05:00
LoJoSho
1e96303765 fix: second NMS check for emotes not updated 2024-05-22 20:20:28 -05:00
LoJoSho
1a6d587ee0 feat: add hidden placeholder 2024-05-22 20:11:02 -05:00
LoJoSho
adcb6de5e4 fix: lang instead of lang3 import for StringUtils 2024-05-22 20:06:03 -05:00
LoJoSho
c36e263a95 feat: bump api version to 1.19 2024-05-22 20:02:16 -05:00
LoJoSho
de1e5bf100 fix: check if entity is null after offhand swap event 2024-05-20 11:09:45 -05:00
LoJoSho
ea25dcf208 fix: dye menu not accepting fireworks 2024-05-20 09:54:11 -05:00
LoJoSho
e3c73d0bfe feat: add firework item effect support 2024-05-19 19:16:53 -05:00
LoJoSho
91b24bfa82 fix: data loading not checking disabled boolean for disabled gamemodes 2024-05-16 20:29:24 -05:00
LoJoSho
28bf5ba2b6 fix: backpacks sometimes still spawned after being hidden 2024-05-15 16:29:09 -05:00
LoJoSho
0249d6abdb fix: player animator attempting to start on 1.20.6 2024-05-12 13:43:51 -05:00
LoJoSho
cb32f635d0 feat: rework of slot options (config reworked for slot options for enchants and showing) 2024-05-11 14:33:46 -05:00
LoJoSho
3bfdde4281 fix: not checking player before checking world 2024-04-30 16:28:31 -05:00
LoJoSho
8daa2709f3 feat: process PAPI placeholders in wardrobe bossbar 2024-04-29 14:32:15 -05:00
115 changed files with 3120 additions and 3021 deletions

1
.gitignore vendored
View File

@@ -115,3 +115,4 @@ run/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
/qodana.yaml

View File

@@ -2,13 +2,13 @@ import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
plugins {
id("java")
id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-paper") version "2.0.0"
id("com.gradleup.shadow") version "8.3.2"
id("xyz.jpenilla.run-paper") version "2.3.1"
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
}
group = "com.hibiscusmc"
version = "2.7.3-DEV"
version = "2.8.0${getGitCommitHash()}"
allprojects {
apply(plugin = "java")
@@ -16,16 +16,16 @@ allprojects {
repositories {
mavenCentral()
mavenLocal()
// Paper Repo
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://oss.sonatype.org/content/repositories/snapshots")
// Jitpack
maven("https://jitpack.io")
// ProtocolLib repo
maven("https://repo.dmulloy2.net/repository/public/") //ProtocolLib Repo, constantly down
// Geary
maven("https://repo.mineinabyss.com/releases/")
maven("https://repo.mineinabyss.com/snapshots/")
@@ -49,9 +49,6 @@ allprojects {
}
}
// UpdateChecker
maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/")
// ParticleHelper
maven("https://repo.bytecode.space/repository/maven-public/")
@@ -67,6 +64,9 @@ allprojects {
// Eco-Suite/Auxilor Repo
maven("https://repo.auxilor.io/repository/maven-public/")
// Triumph GUI
maven("https://repo.triumphteam.dev/snapshots")
// Hibiscus Commons
maven("https://repo.hibiscusmc.com/releases")
}
@@ -75,31 +75,47 @@ allprojects {
compileOnly(fileTree("${project.rootDir}/lib") { include("*.jar") })
compileOnly("com.mojang:authlib:1.5.25")
//compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0")
compileOnly("me.clip:placeholderapi:2.11.3")
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.2")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
compileOnly("it.unimi.dsi:fastutil:8.5.11")
compileOnly("org.projectlombok:lombok:1.18.2")
compileOnly("me.lojosho:HibiscusCommons:0.2.2")
compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:24.1.0")
compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.6")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.12") {
exclude(group = "org.bukkit")
exclude(group = "com.google.guava")
exclude(group = "com.google.code.gson")
exclude(group = "it.unimi.dsi")
exclude(group = "com.sk89q.jnbt")
}
compileOnly("io.github.toxicity188:BetterHud-standard-api:1.12") //Standard api
compileOnly("io.github.toxicity188:BetterHud-bukkit-api:1.12") //Platform api
compileOnly("io.github.toxicity188:BetterCommand:1.3") //BetterCommand library
//compileOnly("it.unimi.dsi:fastutil:8.5.14")
compileOnly("org.projectlombok:lombok:1.18.34")
compileOnly("me.lojosho:HibiscusCommons:0.7.0-d301221e")
// Handled by Spigot Library Loader
compileOnly("net.kyori:adventure-api:4.15.0")
compileOnly("net.kyori:adventure-text-minimessage:4.15.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.3.2")
compileOnly("net.kyori:adventure-api:4.23.0")
compileOnly("net.kyori:adventure-text-minimessage:4.23.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.4.0")
annotationProcessor("org.projectlombok:lombok:1.18.28")
testCompileOnly("org.projectlombok:lombok:1.18.28")
testAnnotationProcessor("org.projectlombok:lombok:1.18.28")
annotationProcessor("org.projectlombok:lombok:1.18.36")
testCompileOnly("org.projectlombok:lombok:1.18.36")
testAnnotationProcessor("org.projectlombok:lombok:1.18.36")
implementation("dev.triumphteam:triumph-gui:3.1.7") {
implementation("dev.triumphteam:triumph-gui:3.2.0-SNAPSHOT") {
exclude("net.kyori") // Already have adventure API
}
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.7")
}
tasks {
javadoc {
// javadoc spec has these added.
(options as StandardJavadocDocletOptions)
.tags("apiNote:a:API:", "implSpec:a:Implementation Requirements", "implNote:a:Implementation Note:")
}
}
}
dependencies {
@@ -110,7 +126,7 @@ tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
options.release.set(21)
}
javadoc {
@@ -123,15 +139,20 @@ tasks {
}
runServer {
minecraftVersion("1.20.4")
minecraftVersion("1.21.6")
downloadPlugins {
hangar("PlaceholderAPI", "2.11.6")
url("https://download.luckperms.net/1593/bukkit/loader/LuckPerms-Bukkit-5.5.8.jar")
}
}
shadowJar {
mergeServiceFiles()
relocate("dev.triumphteam.gui", "com.hisbiscusmc.hmccosmetics.gui")
relocate("com.owen1212055.particlehelper", "com.hisbiscusmc.hmccosmetics.particlehelper")
relocate("com.ticxo.playeranimator", "com.hisbiscusmc.hmccosmetics.playeranimator")
relocate("dev.triumphteam.gui", "com.hibiscusmc.hmccosmetics.shaded.gui")
relocate("com.owen1212055.particlehelper", "com.hibiscusmc.hmccosmetics.shaded.particlehelper")
relocate("com.ticxo.playeranimator", "com.hibiscusmc.hmccosmetics.shaded.playeranimator")
archiveFileName.set("HMCCosmeticsRemapped-${project.version}.jar")
dependencies {
@@ -156,10 +177,10 @@ tasks {
bukkit {
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
main = "com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin"
apiVersion = "1.18"
apiVersion = "1.20"
authors = listOf("LoJoSho")
depend = listOf("HibiscusCommons", "ProtocolLib")
softDepend = listOf("ModelEngine", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen", "MMOItems", "Eco")
depend = listOf("HibiscusCommons")
softDepend = listOf("Nexo", "BetterHud", "ModelEngine", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen", "MMOItems", "Eco")
version = "${project.version}"
loadBefore = listOf(
"Cosmin" // Fixes an issue with Cosmin loading before and taking /cosmetic, when messing with what we do.
@@ -257,6 +278,28 @@ bukkit {
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17
))
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
withJavadocJar()
withSourcesJar()
}
fun getGitCommitHash(): String {
var includeHash = true
val includeHashVariable = System.getenv("HMCC_INCLUDE_HASH")
if (!includeHashVariable.isNullOrEmpty()) includeHash = includeHashVariable.toBoolean()
if (includeHash) {
return try {
val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD")
.redirectErrorStream(true)
.start()
process.inputStream.bufferedReader().use { "-" + it.readLine().trim() }
} catch (e: Exception) {
"-unknown" // Fallback if Git is not available or an error occurs
}
}
return ""
}

View File

@@ -4,8 +4,10 @@ plugins {
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17
))
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
withJavadocJar()
withSourcesJar()
}
publishing {

View File

@@ -1,6 +1,5 @@
package com.hibiscusmc.hmccosmetics;
import com.hibiscusmc.hmccosmetics.api.HMCCosmeticsAPI;
import com.hibiscusmc.hmccosmetics.api.events.HMCCosmeticSetupEvent;
import com.hibiscusmc.hmccosmetics.command.CosmeticCommand;
import com.hibiscusmc.hmccosmetics.command.CosmeticCommandTabComplete;
@@ -10,21 +9,22 @@ import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.emotes.EmoteManager;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.hooks.items.HookHMCCosmetics;
import com.hibiscusmc.hmccosmetics.hooks.misc.HookBetterHud;
import com.hibiscusmc.hmccosmetics.hooks.placeholders.HMCPlaceholderExpansion;
import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGHook;
import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGListener;
import com.hibiscusmc.hmccosmetics.listener.PaperPlayerGameListener;
import com.hibiscusmc.hmccosmetics.listener.PlayerConnectionListener;
import com.hibiscusmc.hmccosmetics.listener.PlayerGameListener;
import com.hibiscusmc.hmccosmetics.listener.ServerListener;
import com.hibiscusmc.hmccosmetics.packets.CosmeticPacketInterface;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.TranslationUtil;
import com.ticxo.playeranimator.PlayerAnimatorImpl;
import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin;
import me.lojosho.hibiscuscommons.HibiscusPlugin;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
@@ -51,6 +51,7 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
public HMCCosmeticsPlugin() {
super(13873, 1879);
new HookHMCCosmetics();
new HookBetterHud();
}
@Override
@@ -65,13 +66,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
if (!Path.of(getDataFolder().getPath() + "/cosmetics/").toFile().exists()) saveResource("cosmetics/defaultcosmetics.yml", false);
if (!Path.of(getDataFolder().getPath() + "/menus/").toFile().exists()) saveResource("menus/defaultmenu.yml", false);
// Emote folder setup
File emoteFile = new File(getDataFolder().getPath() + "/emotes");
if (!emoteFile.exists()) emoteFile.mkdir();
// Player Animator
if (!HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R2") && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R3")) PlayerAnimatorImpl.initialize(this); // PlayerAnimator does not support 1.20.2 yet
// Configuration Sync
final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile();
final File messageFile = Path.of(getInstance().getDataFolder().getPath(), "messages.yml").toFile();
@@ -90,6 +84,7 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
// Setup
setup();
setPacketInterface(new CosmeticPacketInterface());
// Commands
getServer().getPluginCommand("cosmetic").setExecutor(new CosmeticCommand());
@@ -98,7 +93,8 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
// Listener
getServer().getPluginManager().registerEvents(new PlayerConnectionListener(), this);
getServer().getPluginManager().registerEvents(new PlayerGameListener(), this);
// Taken from PaperLib
getServer().getPluginManager().registerEvents(new ServerListener(), this);
if (HibiscusCommonsPlugin.isOnPaper()) {
getServer().getPluginManager().registerEvents(new PaperPlayerGameListener(), this);
}
@@ -125,9 +121,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
for (Player player : Bukkit.getOnlinePlayers()) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) continue;
if (user.getUserEmoteManager().isPlayingEmote()) {
player.setInvisible(false);
}
if (user.isInWardrobe()) {
user.leaveWardrobe(true);
}
@@ -229,8 +222,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
}
}
if (Settings.isEmotesEnabled() && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R2") && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R3")) EmoteManager.loadEmotes(); // PlayerAnimator does not support 1.20.2 yet
getInstance().getLogger().info("Successfully Enabled HMCCosmetics");
getInstance().getLogger().info(Cosmetics.values().size() + " Cosmetics Successfully Setup");
getInstance().getLogger().info(Menus.getMenuNames().size() + " Menus Successfully Setup");

View File

@@ -2,116 +2,216 @@ package com.hibiscusmc.hmccosmetics.api;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticProvider;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUserProvider;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import me.lojosho.hibiscuscommons.nms.MinecraftVersion;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Color;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiConsumer;
public class HMCCosmeticsAPI {
/**
* Attempts to get a cosmetic from HMCCosmetics
*
* @param cosmetic Cosmetic Id
* @return A {@link Cosmetic} if exists or null if it does not
*/
@Nullable
public static Cosmetic getCosmetic(@NotNull String cosmetic) {
return Cosmetics.getCosmetic(cosmetic);
/**
* The main API class for HMCCosmetics. This class provides methods to interact with the plugin.
*/
public final class HMCCosmeticsAPI {
private HMCCosmeticsAPI() {
throw new UnsupportedOperationException("This class cannot be instantiated.");
}
/**
* Attempts to get the CosmeticUser from an online user. If a player is offline it will return null.
* A player maybe online but not have a CosmeticUser attached to them, either from delay specified in the config
* or from a /reload. Always check if it's null!
*
* @param uuid Player Unique ID
* @return A {@link CosmeticUser} if exists or null if it does not
* Retrieves a {@link Cosmetic} associated with the specified id.
* <p>
* This method attempts to fetch a {@link Cosmetic} using the given id. If no {@link Cosmetic} exists
* with the specified id, it will return {@code null}.
* </p>
* @param id the id of the {@link Cosmetic} to retrieve
* @return the {@link Cosmetic} if it exists, or {@code null} if no cosmetic is associated with the given id
*/
@Nullable
public static CosmeticUser getUser(@NotNull UUID uuid) {
public static @Nullable Cosmetic getCosmetic(@NotNull String id) {
return Cosmetics.getCosmetic(id);
}
/**
* Retrieves the {@link CosmeticUser} associated with the specified player's {@link UUID}.
* <p>
* This method attempts to fetch a {@link CosmeticUser} for an online player. If the player is offline,
* or if no {@link CosmeticUser} is currently associated with them, it will return {@code null}.
* </p>
* Note that a player may be online but not have a {@link CosmeticUser} attached due to:
* <ul>
* <li>A delay specified in the configuration</li>
* <li>A recent server reload (e.g., via the {@code /reload} command)</li>
* </ul>
* Always perform a {@code null} check before using the returned object to ensure safe operation.
*
* @param uuid the {@link UUID} of the player whose {@link CosmeticUser} is being retrieved
* @return the {@link CosmeticUser} if it exists, or {@code null} if the player is offline or unassociated
*/
public static @Nullable CosmeticUser getUser(@NotNull UUID uuid) {
return CosmeticUsers.getUser(uuid);
}
/**
* Attempts to get a HMCCosmetics Menu. Returns null if no menu exists under that id.
* Retrieves a {@link Menu} associated with the specified id, or {@code null} if no menu exists with the given id.
*
* @param id Menu ID
* @return A {@link Menu} if exists or null if it does not
* @param id the id of the menu to retrieve
* @return the {@link Menu} if it exists, or {@code null} if no menu is associated with the given id
*/
@Nullable
public static Menu getMenu(@NotNull String id) {
public static @Nullable Menu getMenu(@NotNull String id) {
return Menus.getMenu(id);
}
/**
* Equips a cosmetic to a player. You can use getUser and getCosmetic to get the CosmeticUser and Cosmetic to equip.
* @param user CosmeticUser to equip cosmetic to
* @param cosmetic Cosmetic to equip
* Equips a {@link Cosmetic} to a player. To retrieve the necessary {@code CosmeticUser} and {@code Cosmetic}, use the {@link #getUser}
* and {@link #getCosmetic} methods respectively.
*
* @param user the {@link CosmeticUser} to equip the cosmetic to
* @param cosmetic the {@link Cosmetic} to equip
*/
public static void equipCosmetic(@NotNull CosmeticUser user, @NotNull Cosmetic cosmetic) {
equipCosmetic(user, cosmetic, null);
}
/**
* Equips a cosmetic to a player with a color. You can use getUser and getCosmetic to get the CosmeticUser and Cosmetic to equip.
* @param user CosmeticUser to equip cosmetic to
* @param cosmetic Cosmetic to equip
* @param color Color to apply to cosmetic
* Equips a {@link Cosmetic} to a player with an optional color customization. To retrieve the necessary
* {@code CosmeticUser} and {@code Cosmetic}, use the {@link #getUser} and {@link #getCosmetic} methods
* respectively.
*
* @param user the {@link CosmeticUser} to equip the cosmetic to
* @param cosmetic the {@link Cosmetic} to equip
* @param color the color to apply to the cosmetic, or {@code null} if the cosmetic does not support color
* customization
*/
public static void equipCosmetic(@NotNull CosmeticUser user, @NotNull Cosmetic cosmetic, @Nullable Color color) {
user.addPlayerCosmetic(cosmetic, color);
user.addCosmetic(cosmetic, color);
}
/**
* Removes a cosmetic in cosmeticslot.
* @param user The user to remove the cosmetic from
* @param slot The slot to remove the cosmetic from
* Removes a cosmetic from a specified slot for the given user.
*
* @param user the {@link CosmeticUser} from whom the cosmetic will be removed
* @param slot the {@link CosmeticSlot} from which the cosmetic will be removed
*/
public static void unequipCosmetic(@NotNull CosmeticUser user, @NotNull CosmeticSlot slot) {
user.removeCosmeticSlot(slot);
}
/**
* Gets all Cosmetics that are currently registered with HMCC. This list is immutable!
* @return A list of all registered cosmetics
* Retrieves a list of all cosmetics currently registered with HMCC.
*
* @return an {@code immutable} list containing all registered {@link Cosmetic} object
*/
public static List<Cosmetic> getAllCosmetics() {
public static @NotNull List<Cosmetic> getAllCosmetics() {
return List.copyOf(Cosmetics.values());
}
/**
* Gets all CosmeticUsers that are currently registered with HMCC. This list is immutable!
* @return A list of all registered CosmeticUsers
* Retrieves a list of all cosmetic users currently registered with HMCC.
*
* @return an immutable list containing all registered {@link CosmeticUser} objects
*/
public static List<CosmeticUser> getAllCosmeticUsers() {
public static @NotNull List<CosmeticUser> getAllCosmeticUsers() {
return List.copyOf(CosmeticUsers.values());
}
/**
* This returns the NMS version of the server as recognized by HMCCosmetics. This will be null until HMCC setup has been completed.
* @return The NMS version of the server in String format
* Retrieves a map of all cosmetic slots currently registered with HMCC.
*
* @return an immutable {@link Map} containing all registered cosmetic slots
*/
@Nullable
public static String getNMSVersion() {
return NMSHandlers.getVersion();
public static @NotNull Map<String, CosmeticSlot> getAllCosmeticSlots() {
return Map.copyOf(CosmeticSlot.values());
}
/**
* This returns the HMCCosmetics version.
* @return The HMCCosmetics version in String format
* Registers a new cosmetic slot with the specified id. If a slot with the same id already exists,
* the existing slot will be returned.
*
* <p>
* The provided id will automatically be converted to uppercase when registering the slot.
* </p>
*
* @param id the id for the cosmetic slot
* @return the {@link CosmeticSlot} associated with the given id
* @apiNote this should be done in your {@link JavaPlugin#onLoad()} or it may error.
*/
@NotNull
public static String getHMCCVersion() {
public static @NotNull CosmeticSlot registerCosmeticSlot(@NotNull String id) {
return CosmeticSlot.register(id);
}
/**
* Registers a new cosmetic user provider to use for constructing {@link CosmeticUser} instances.
*
* @param provider the provider to register
* @throws IllegalArgumentException if another plugin has already registered a provider
* @apiNote this should be done in your {@link JavaPlugin#onLoad()} or it may error.
*/
public static void registerCosmeticUserProvider(@NotNull CosmeticUserProvider provider) {
CosmeticUsers.registerProvider(provider);
}
/**
* Retrieves the current {@link CosmeticUserProvider} that is in use.
*
* @return the current {@link CosmeticUserProvider}
*/
public static @NotNull CosmeticUserProvider getCosmeticUserProvider() {
return CosmeticUsers.getProvider();
}
/**
* Registers a new cosmetic user provider to use for constructing {@link Cosmetic} instances.
*
* @param provider the provider to register
* @throws IllegalArgumentException if another plugin has already registered a provider
* @apiNote this should be done in your {@link JavaPlugin#onLoad()} or it may error.
*/
public static void registerCosmeticProvider(@NotNull CosmeticProvider provider) {
Cosmetics.registerProvider(provider);
}
/**
* Retrieves the current {@link CosmeticProvider} that is in use.
*
* @return the current {@link CosmeticProvider}
*/
public static @NotNull CosmeticProvider getCosmeticProvider() {
return Cosmetics.getProvider();
}
/**
* Retrieves the NMS version of the server as recognized by HMCCosmetics.
*
* <p>This value will be {@code null} until the HMCC setup has been completed. Ensure setup is finished
* before attempting to access this version.</p>
*
* @return the NMS version of the server in string format, or {@code null} if setup is not complete.
*/
public static @Nullable String getNMSVersion() {
MinecraftVersion version = NMSHandlers.getVersion();
if (version == null) return null;
return version.toString();
}
/**
* Retrieves the version of HMCCosmetics currently in use.
*
* @return the HMCCosmetics version in string format
*/
public static @NotNull String getHMCCVersion() {
return HMCCosmeticsPlugin.getInstance().getDescription().getVersion();
}
}

View File

@@ -0,0 +1,55 @@
package com.hibiscusmc.hmccosmetics.api.events;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when an attempt is made to register a cosmetic type that is not part of the default HMCC cosmetics.
* <p>
* For example, if a user specifies "test" in the config slot, and it is not a default cosmetic, this event will be
* triggered.
* </p>
*/
public class CosmeticTypeRegisterEvent extends Event {
private static final HandlerList HANDLER_LIST = new HandlerList();
private final String id;
private final ConfigurationNode config;
public CosmeticTypeRegisterEvent(@NotNull String id, @NotNull ConfigurationNode config) {
this.id = id;
this.config = config;
}
/**
* Returns the id of the cosmetic attempting to be registered.
*
* @return the id of the cosmetic. This is the key in the cosmetic configuration.
*/
public @NotNull String getId() {
return id;
}
/**
* Retrieves the {@link ConfigurationNode} for the cosmetic that was attempted to be registered.
* <p>
* This node is nested below the id in the configuration.
* </p>
*
* @return the configuration node for the cosmetic in the cosmetic configuration
*/
public @NotNull ConfigurationNode getConfig() {
return config;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -5,19 +5,17 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when the plugin is set up and/or reloaded
* Called when the plugin is set up and/or reloaded.
*/
public class HMCCosmeticSetupEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -7,22 +7,24 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player equips a cosmetic
* Called when a player equips a {@link Cosmetic}.
*/
public class PlayerCosmeticEquipEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private static final HandlerList HANDLER_LIST = new HandlerList();
private Cosmetic cosmetic;
private boolean cancel = false;
public PlayerCosmeticEquipEvent(@NotNull CosmeticUser who, @NotNull Cosmetic cosmetic) {
super(who);
this.cosmetic = cosmetic;
}
/**
* Gets the {@link Cosmetic} being equipped in this event
* Gets the {@link Cosmetic} being equipped in this event.
*
* @return The {@link Cosmetic} which is being equipped in this event
* @return the cosmetic which is being equipped in this event
*/
@NotNull
public Cosmetic getCosmetic() {
@@ -30,9 +32,9 @@ public class PlayerCosmeticEquipEvent extends PlayerCosmeticEvent implements Can
}
/**
* Sets the {@link Cosmetic} that the player will equip
* Sets the {@link Cosmetic} that the player will equip.
*
* @param cosmetic The {@link Cosmetic} that the player will equip
* @param cosmetic the cosmetic that the player will equip
*/
public void setCosmetic(@NotNull Cosmetic cosmetic) {
this.cosmetic = cosmetic;
@@ -43,28 +45,17 @@ public class PlayerCosmeticEquipEvent extends PlayerCosmeticEvent implements Can
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from equipping the cosmetic
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -5,22 +5,22 @@ import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
/**
* Represents a cosmetic user related event
* Represents an event related to a {@link CosmeticUser}.
*/
public abstract class PlayerCosmeticEvent extends Event {
protected CosmeticUser user;
public abstract class PlayerCosmeticEvent extends PlayerEvent {
protected final CosmeticUser user;
public PlayerCosmeticEvent(@NotNull final CosmeticUser who) {
public PlayerCosmeticEvent(@NotNull CosmeticUser who) {
super(who.getUniqueId());
user = who;
}
/**
* Returns the user involved in this event
* Returns the {@link CosmeticUser} involved in this event.
*
* @return User who is involved in this event
* @return the user who is involved in this event
*/
@NotNull
public final CosmeticUser getUser() {
public final @NotNull CosmeticUser getUser() {
return user;
}
}

View File

@@ -6,25 +6,26 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when cosmetics are hidden from a player
* Called when cosmetics are hidden from a player.
*/
public class PlayerCosmeticHideEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private static final HandlerList HANDLER_LIST = new HandlerList();
private final CosmeticUser.HiddenReason reason;
private boolean cancel = false;
public PlayerCosmeticHideEvent(@NotNull CosmeticUser who, @NotNull CosmeticUser.HiddenReason reason) {
super(who);
this.reason = reason;
}
/**
* Gets the {@link CosmeticUser.HiddenReason} as to why cosmetics are being hidden for the player
* Gets the {@link CosmeticUser.HiddenReason} as to why cosmetics are being hidden for the player.
*
* @return The {@link CosmeticUser.HiddenReason} why cosmetics are being hidden for the player
* @return the reason why cosmetics are being hidden for the player
*/
@NotNull
public CosmeticUser.HiddenReason getReason() {
public @NotNull CosmeticUser.HiddenReason getReason() {
return reason;
}
@@ -33,28 +34,17 @@ public class PlayerCosmeticHideEvent extends PlayerCosmeticEvent implements Canc
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from hiding cosmetics
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -5,8 +5,12 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player has equipped a {@link Cosmetic}.
*/
public class PlayerCosmeticPostEquipEvent extends PlayerCosmeticEvent {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private Cosmetic cosmetic;
public PlayerCosmeticPostEquipEvent(@NotNull CosmeticUser who, @NotNull Cosmetic cosmetic) {
@@ -15,32 +19,29 @@ public class PlayerCosmeticPostEquipEvent extends PlayerCosmeticEvent {
}
/**
* Gets the {@link Cosmetic} being equipped in this event
* Gets the {@link Cosmetic} being equipped in this event.
*
* @return The {@link Cosmetic} which is being equipped in this event
* @return the cosmetic which is being equipped in this event
*/
@NotNull
public Cosmetic getCosmetic() {
public @NotNull Cosmetic getCosmetic() {
return cosmetic;
}
/**
* Sets the {@link Cosmetic} that the player will equip
* Sets the {@link Cosmetic} that the player will equip.
*
* @param cosmetic The {@link Cosmetic} that the player will equip
* @param cosmetic the cosmetic that the player will equip
*/
public void setCosmetic(@NotNull Cosmetic cosmetic) {
this.cosmetic = cosmetic;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -7,22 +7,24 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player removes a cosmetic
* Called when a player removes a {@link Cosmetic}.
*/
public class PlayerCosmeticRemoveEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private static final HandlerList HANDLER_LIST = new HandlerList();
private final Cosmetic cosmetic;
private boolean cancel = false;
public PlayerCosmeticRemoveEvent(@NotNull CosmeticUser who, @NotNull Cosmetic cosmetic) {
super(who);
this.cosmetic = cosmetic;
}
/**
* Gets the {@link Cosmetic} being removed in this event
* Gets the {@link Cosmetic} being removed in this event.
*
* @return The {@link Cosmetic} which is being removed in this event
* @return the cosmetic which is being removed in this event
*/
public Cosmetic getCosmetic() {
return cosmetic;
@@ -33,27 +35,17 @@ public class PlayerCosmeticRemoveEvent extends PlayerCosmeticEvent implements Ca
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from removing the cosmetic
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -6,10 +6,11 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when cosmetics are shown from a player
* Called when cosmetics are shown from a player.
*/
public class PlayerCosmeticShowEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancel = false;
public PlayerCosmeticShowEvent(@NotNull CosmeticUser who) {
@@ -21,28 +22,17 @@ public class PlayerCosmeticShowEvent extends PlayerCosmeticEvent implements Canc
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from showing cosmetics
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -1,61 +0,0 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player starts playing an emote
*/
public class PlayerEmoteStartEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private final String animationId;
public PlayerEmoteStartEvent(@NotNull CosmeticUser who, @NotNull String animationId) {
super(who);
this.animationId = animationId;
}
/**
* Gets the animation id of the emote the player started playing
* @implNote The returned string of this method may be an invalid animation id. Make sure to validate it before use
*
* @return The animation id of the emote which the player started playing
*/
@NotNull
public String getAnimationId() {
return animationId;
}
@Override
public boolean isCancelled() {
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from playing the emote
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -1,74 +0,0 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player stops playing an emote
*/
public class PlayerEmoteStopEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancel = false;
private final UserEmoteManager.StopEmoteReason reason;
public PlayerEmoteStopEvent(@NotNull CosmeticUser who, @NotNull UserEmoteManager.StopEmoteReason reason) {
super(who);
this.reason = reason;
}
/**
* Gets the {@link UserEmoteManager.StopEmoteReason} as to why the emote has stopped playing
*
* @return The {@link UserEmoteManager.StopEmoteReason} why the emote has stopped playing
* @deprecated As of release 2.2.5+, replaced by {@link #getReason()}
*/
@Deprecated
@NotNull
public UserEmoteManager.StopEmoteReason getStopEmoteReason() {
return reason;
}
/**
* Gets the {@link UserEmoteManager.StopEmoteReason} as to why the emote has stopped playing
*
* @return The {@link UserEmoteManager.StopEmoteReason} why the emote has stopped playing
* @since 2.2.5
*/
@NotNull
public UserEmoteManager.StopEmoteReason getReason() {
return reason;
}
@Override
public boolean isCancelled() {
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from stopping the emote
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -0,0 +1,26 @@
package com.hibiscusmc.hmccosmetics.api.events;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Represents an event related to a {@link org.bukkit.entity.Player}.
*/
public abstract class PlayerEvent extends Event {
protected final UUID player;
public PlayerEvent(@NotNull UUID uuid) {
this.player = uuid;
}
/**
* Returns the {@link UUID} of the player involved in this event.
*
* @return the UUID of the player who is involved in this event
*/
public final @NotNull UUID getUniqueId() {
return player;
}
}

View File

@@ -0,0 +1,25 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player's cosmetic data is loaded.
*/
public class PlayerLoadEvent extends PlayerCosmeticEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
public PlayerLoadEvent(@NotNull CosmeticUser who) {
super(who);
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -3,26 +3,35 @@ package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when a menu is closed by a player
* Called when a {@link Menu} is closed by a player.
*/
public class PlayerMenuCloseEvent extends PlayerMenuEvent {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private final InventoryCloseEvent.Reason reason;
public PlayerMenuCloseEvent(@NotNull CosmeticUser who, @NotNull Menu menu) {
public PlayerMenuCloseEvent(@NotNull CosmeticUser who, @NotNull Menu menu, @NotNull InventoryCloseEvent.Reason reason) {
super(who, menu);
this.reason = reason;
}
/**
* Gets the {@link InventoryCloseEvent.Reason} why the menu was closed.
* @return The reason why the menu was closed.
*/
public InventoryCloseEvent.Reason getReason() {
return reason;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -5,10 +5,10 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.jetbrains.annotations.NotNull;
/**
* Represents a menu related event
* Represents an event related to a player's interaction with a {@link Menu}.
*/
public abstract class PlayerMenuEvent extends PlayerCosmeticEvent {
protected Menu menu;
protected final Menu menu;
public PlayerMenuEvent(@NotNull CosmeticUser who, @NotNull Menu menu) {
super(who);
@@ -16,12 +16,11 @@ public abstract class PlayerMenuEvent extends PlayerCosmeticEvent {
}
/**
* Gets the {@link Menu} involved with this event
* Gets the {@link Menu} involved with this event.
*
* @return The {@link Menu} which is involved with the event
* @return the menu involved in this event
*/
@NotNull
public final Menu getMenu() {
public @NotNull final Menu getMenu() {
return menu;
}
}

View File

@@ -7,10 +7,11 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a menu is opened by a player
* Called when a {@link Menu} is opened by a player.
*/
public class PlayerMenuOpenEvent extends PlayerMenuEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancel = false;
public PlayerMenuOpenEvent(@NotNull CosmeticUser who, @NotNull Menu menu) {
@@ -22,28 +23,17 @@ public class PlayerMenuOpenEvent extends PlayerMenuEvent implements Cancellable
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from opening a {@link Menu}
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -0,0 +1,44 @@
package com.hibiscusmc.hmccosmetics.api.events;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Called before a player's data is loaded into the plugin.
*
* <p>
* If this event is cancelled, the player's data will not be loaded,
* and the player will not be able to interact with the plugin.
* </p>
*/
public class PlayerPreLoadEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancelled = false;
public PlayerPreLoadEvent(@NotNull UUID id) {
super(id);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -0,0 +1,43 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called before a player's data is un-loaded from the plugin.
*
* <p>
* If this event is cancelled, the player's data will not be un-loaded,
* and will be kept in memory.
* </p>
*/
public class PlayerPreUnloadEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancelled = false;
public PlayerPreUnloadEvent(@NotNull CosmeticUser who) {
super(who);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -0,0 +1,25 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a players data is unloaded from the plugin. This is called when a player leaves the server.
*/
public class PlayerUnloadEvent extends PlayerCosmeticEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
public PlayerUnloadEvent(@NotNull CosmeticUser who) {
super(who);
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -2,19 +2,18 @@ package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.config.Wardrobe;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player enters their wardrobe
* Called when a player enters their {@link Wardrobe}.
*/
public class PlayerWardrobeEnterEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancel = false;
@Getter @Setter
private Wardrobe wardrobe;
public PlayerWardrobeEnterEvent(@NotNull CosmeticUser who, @NotNull Wardrobe wardrobe) {
@@ -22,33 +21,38 @@ public class PlayerWardrobeEnterEvent extends PlayerCosmeticEvent implements Can
this.wardrobe = wardrobe;
}
/**
* Get the {@link Wardrobe} the player is entering.
* @return The wardrobe being entered
*/
public Wardrobe getWardrobe() {
return wardrobe;
}
/**
* Set the {@link Wardrobe} the player is entering.
* @param wardrobe the wardrobe being entered
*/
public void setWardrobe(Wardrobe wardrobe) {
this.wardrobe = wardrobe;
}
@Override
public boolean isCancelled() {
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from entering their wardrobe
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -6,10 +6,11 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player leaves their wardrobe
* Called when a player leaves their {@link com.hibiscusmc.hmccosmetics.config.Wardrobe}.
*/
public class PlayerWardrobeLeaveEvent extends PlayerCosmeticEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private static final HandlerList HANDLER_LIST = new HandlerList();
private boolean cancel = false;
public PlayerWardrobeLeaveEvent(@NotNull CosmeticUser who) {
@@ -21,28 +22,17 @@ public class PlayerWardrobeLeaveEvent extends PlayerCosmeticEvent implements Can
return cancel;
}
/**
* Sets the cancellation state of this event
*
* <p>
* Canceling this event will prevent the player from leaving their wardrobe
* </p>
*
* @param cancel true if you wish to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
this.cancel = cancel;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
public @NotNull HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View File

@@ -10,9 +10,7 @@ import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticEmoteType;
import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.emotes.EmoteManager;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu;
@@ -23,7 +21,6 @@ import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.OfflinePlayer;
@@ -43,10 +40,14 @@ public class CosmeticCommand implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) {
boolean silent = false;
boolean console = false;
if (!(sender instanceof Player)) {
console = true;
}
if (args.length == 0) {
if (!(sender instanceof Player)) {
// Console
if (console) {
return true;
}
if (!sender.hasPermission("hmccosmetics.cmd.default")) {
@@ -140,7 +141,12 @@ public class CosmeticCommand implements CommandExecutor {
CosmeticUser user = CosmeticUsers.getUser(player);
if (!user.canEquipCosmetic(cosmetic)) {
if (user == null) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-player");
return true;
}
if (!user.canEquipCosmetic(cosmetic) && !console) {
if (!silent) MessagesUtil.sendMessage(player, "no-cosmetic-permission");
return true;
}
@@ -148,11 +154,11 @@ public class CosmeticCommand implements CommandExecutor {
TagResolver placeholders =
TagResolver.resolver(Placeholder.parsed("cosmetic", cosmetic.getId()),
TagResolver.resolver(Placeholder.parsed("player", player.getName())),
TagResolver.resolver(Placeholder.parsed("cosmeticslot", cosmetic.getSlot().name())));
TagResolver.resolver(Placeholder.parsed("cosmeticslot", cosmetic.getSlot().toString())));
if (!silent) MessagesUtil.sendMessage(player, "equip-cosmetic", placeholders);
user.addPlayerCosmetic(cosmetic, color);
user.addCosmetic(cosmetic, color);
user.updateCosmetic(cosmetic.getSlot());
return true;
}
@@ -183,11 +189,12 @@ public class CosmeticCommand implements CommandExecutor {
if (args[1].equalsIgnoreCase("all")) {
cosmeticSlots = user.getSlotsWithCosmetics();
} else {
if (!EnumUtils.isValidEnum(CosmeticSlot.class, args[1].toUpperCase())) {
String rawSlot = args[1].toUpperCase();
if (!CosmeticSlot.contains(rawSlot)) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-slot");
return true;
}
cosmeticSlots = Set.of(CosmeticSlot.valueOf(args[1].toUpperCase()));
cosmeticSlots = Set.of(CosmeticSlot.valueOf(rawSlot));
}
for (CosmeticSlot cosmeticSlot : cosmeticSlots) {
@@ -199,7 +206,7 @@ public class CosmeticCommand implements CommandExecutor {
TagResolver placeholders =
TagResolver.resolver(Placeholder.parsed("cosmetic", user.getCosmetic(cosmeticSlot).getId()),
TagResolver.resolver(Placeholder.parsed("player", player.getName())),
TagResolver.resolver(Placeholder.parsed("cosmeticslot", cosmeticSlot.name())));
TagResolver.resolver(Placeholder.parsed("cosmeticslot", cosmeticSlot.toString())));
if (!silent) MessagesUtil.sendMessage(player, "unequip-cosmetic", placeholders);
@@ -239,20 +246,24 @@ public class CosmeticCommand implements CommandExecutor {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user.isInWardrobe()) {
user.leaveWardrobe();
user.leaveWardrobe(false);
} else {
user.enterWardrobe(false, wardrobe);
user.enterWardrobe(wardrobe, false);
}
return true;
}
// cosmetic menu exampleMenu playerName
case ("menu") -> {
if (args.length == 1) return true;
if (!sender.hasPermission("hmccosmetics.cmd.menu")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
Menu menu = Menus.getMenu(args[1]);
Menu menu;
if (args.length == 1) {
menu = Menus.getDefaultMenu();
} else {
menu = Menus.getMenu(args[1]);
}
if (sender instanceof Player) player = ((Player) sender).getPlayer();
if (sender.hasPermission("hmccosmetics.cmd.menu.other")) {
@@ -298,11 +309,12 @@ public class CosmeticCommand implements CommandExecutor {
return true;
}
if (!EnumUtils.isValidEnum(CosmeticSlot.class, args[1])) {
String rawSlot = args[1];
if (!CosmeticSlot.contains(rawSlot)) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-slot");
return true;
}
CosmeticSlot slot = CosmeticSlot.valueOf(args[1]);
CosmeticSlot slot = CosmeticSlot.valueOf(rawSlot);
Cosmetic cosmetic = user.getCosmetic(slot);
if (args.length >= 3) {
@@ -315,7 +327,7 @@ public class CosmeticCommand implements CommandExecutor {
if (!silent) MessagesUtil.sendMessage(player, "invalid-color");
return true;
}
user.addPlayerCosmetic(cosmetic, color); // #FFFFFF
user.addCosmetic(cosmetic, color); // #FFFFFF
} else {
DyeMenu.openMenu(user, cosmetic);
}
@@ -334,7 +346,7 @@ public class CosmeticCommand implements CommandExecutor {
}
Wardrobe wardrobe = WardrobeSettings.getWardrobe(args[1]);
if (wardrobe == null) {
wardrobe = new Wardrobe(args[1], new WardrobeLocation(null, null, null), null, -1);
wardrobe = new Wardrobe(args[1], new WardrobeLocation(null, null, null), null, -1, null);
WardrobeSettings.addWardrobe(wardrobe);
//MessagesUtil.sendMessage(player, "no-wardrobes");
//return true;
@@ -369,6 +381,11 @@ public class CosmeticCommand implements CommandExecutor {
if (!silent) MessagesUtil.sendMessage(player, "set-wardrobe-distance");
return true;
}
if (args[2].equalsIgnoreCase("defaultmenu")) {
WardrobeSettings.setWardrobeDefaultMenu(wardrobe, args[3]);
if (!silent) MessagesUtil.sendMessage(player, "set-wardrobe-menu");
return true;
}
}
}
case ("dump") -> {
@@ -383,6 +400,7 @@ public class CosmeticCommand implements CommandExecutor {
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) {
player.sendMessage("Backpack Location -> " + user.getUserBackpackManager().getEntityManager().getLocation());
}
player.sendMessage("Cosmetic Passengers -> " + user.getUserBackpackManager().getAreaEffectEntityId());
player.sendMessage("Cosmetics -> " + user.getCosmetics());
player.sendMessage("EntityId -> " + player.getEntityId());
return true;
@@ -444,59 +462,6 @@ public class CosmeticCommand implements CommandExecutor {
if (!silent) MessagesUtil.sendMessage(sender, "debug-enabled");
}
}
case ("emote") -> {
if (!sender.hasPermission("hmccosmetics.cmd.emote")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (sender.hasPermission("hmccosmetics.cmd.emote.other")) {
if (args.length >= 2) player = Bukkit.getPlayer(args[1]);
}
if (player == null) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-player");
return true;
}
CosmeticUser user = CosmeticUsers.getUser(player);
if (!user.hasCosmeticInSlot(CosmeticSlot.EMOTE)) {
if (!silent) MessagesUtil.sendMessage(sender, "emote-none");
return true;
}
CosmeticEmoteType cosmeticEmoteType = (CosmeticEmoteType) user.getCosmetic(CosmeticSlot.EMOTE);
cosmeticEmoteType.run(user);
return true;
}
case ("playemote") -> {
// /cosmetic playEmote <emoteId> [playerName]
if (!sender.hasPermission("hmccosmetics.cmd.playemote")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (args.length < 2) {
if (!silent) MessagesUtil.sendMessage(player, "not-enough-args");
return true;
}
if (!EmoteManager.has(args[1])) {
MessagesUtil.sendDebugMessages("Did not contain " + args[1]);
if (!silent) MessagesUtil.sendMessage(sender, "emote-invalid");
return true;
}
if (sender.hasPermission("hmccosmetics.cmd.playemote.other")) {
if (args.length >= 3) player = Bukkit.getPlayer(args[2]);
}
if (player == null) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-player");
return true;
}
CosmeticUser user = CosmeticUsers.getUser(player);
user.getUserEmoteManager().playEmote(args[1]);
return true;
}
case "disableall" -> {
if (!sender.hasPermission("hmccosmetics.cmd.disableall")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");

View File

@@ -6,7 +6,6 @@ import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.emotes.EmoteManager;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
@@ -44,8 +43,6 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (hasPermission(sender, "hmccosmetics.cmd.hide")) completions.add("hide");
if (hasPermission(sender, "hmccosmetics.cmd.show")) completions.add("show");
if (hasPermission(sender, "hmccosmetics.cmd.debug")) completions.add("debug");
if (hasPermission(sender, "hmccosmetics.cmd.emote")) completions.add("emote");
if (hasPermission(sender, "hmccosmetics.cmd.playemote")) completions.add("playemote");
if (hasPermission(sender, "hmccosmetics.cmd.disableall")) completions.add("disableall");
if (hasPermission(sender, "hmccosmetics.cmd.hiddenreasons")) completions.add("hiddenreasons");
if (hasPermission(sender, "hmccosmetics.cmd.clearhiddenreasons")) completions.add("clearhiddenreasons");
@@ -74,7 +71,7 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (menu.canOpen(user.getPlayer())) completions.add(menu.getId());
}
}
case "dataclear", "hide", "show", "emote", "hiddenreasons", "clearhiddenreasons" -> {
case "dataclear", "hide", "show", "hiddenreasons", "clearhiddenreasons" -> {
for (Player player : Bukkit.getOnlinePlayers()) {
completions.add(player.getName());
}
@@ -94,7 +91,7 @@ public class CosmeticCommandTabComplete implements TabCompleter {
}
case "dye" -> {
for (CosmeticSlot slot : user.getDyeableSlots()) {
completions.add(slot.name());
completions.add(slot.toString());
}
}
case "setwardrobesetting" -> {
@@ -102,7 +99,6 @@ public class CosmeticCommandTabComplete implements TabCompleter {
completions.add(wardrobe.getId());
}
}
case "playemote" -> completions.addAll(EmoteManager.getAllNames());
}
StringUtil.copyPartialMatches(args[1], completions, finalCompletions);
}
@@ -112,7 +108,7 @@ public class CosmeticCommandTabComplete implements TabCompleter {
case "dye" -> {
completions.add("#FFFFFF");
}
case "menu", "wardrobe", "apply", "unapply", "playemote" -> {
case "menu", "wardrobe", "apply", "unapply" -> {
for (Player player : Bukkit.getOnlinePlayers()) {
completions.add(player.getName());
}
@@ -123,6 +119,7 @@ public class CosmeticCommandTabComplete implements TabCompleter {
completions.add("leavelocation");
completions.add("permission");
completions.add("distance");
completions.add("defaultmenu");
}
}
StringUtil.copyPartialMatches(args[2], completions, finalCompletions);
@@ -135,6 +132,11 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (Hooks.isActiveHook("HMCColor")) completions.addAll(HMCColorContextKt.getHmcColor().getConfig().getColors().keySet());
completions.add("#FFFFFF");
}
case "setwardrobesetting" -> {
if (args[2].equalsIgnoreCase("defaultmenu")) {
completions.addAll(Menus.getMenuNames());
}
}
}
StringUtil.copyPartialMatches(args[3], completions, finalCompletions);
}

View File

@@ -9,6 +9,7 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
@@ -29,36 +30,30 @@ public class Settings {
private static final String UNAPPLY_DEATH_PATH = "unapply-on-death";
private static final String FORCE_PERMISSION_JOIN_PATH = "force-permission-join";
private static final String FORCE_SHOW_COSMETICS_PATH = "force-show-join";
private static final String ITEM_PROCESSING_PATH = "item-processing";
private static final String ITEM_PROCESS_DISPLAY_NAME_PATH = "display-name";
private static final String ITEM_PROCESS_LORE_PATH = "lore";
private static final String DISABLED_GAMEMODE_PATH = "disabled-gamemode";
private static final String DISABLED_GAMEMODE_GAMEMODES_PATH = "gamemodes";
private static final String EMOTE_DISTANCE_PATH = "emote-distance";
private static final String HOOK_SETTING_PATH = "hook-settings";
private static final String HOOK_ITEMADDER_PATH = "itemsadder";
private static final String HOOK_NEXO_PATH = "nexo";
private static final String HOOK_RELOAD_CHANGE_PATH = "reload-on-change";
private static final String HOOK_WORLDGUARD_PATH = "worldguard";
private static final String HOOK_WG_MOVE_CHECK_PATH = "player-move-check";
private static final String HOOK_WG_MOVE_CHECK_PATH_LEGACY = "player_move_check";
private static final String COSMETIC_EMOTE_ENABLE = "emote-enable";
private static final String COSMETIC_EMOTE_CHECK_PATH = "emote-block-check";
private static final String COSMETIC_EMOTE_AIR_CHECK_PATH = "emote-air-check";
private static final String COSMETIC_EMOTE_DAMAGE_PATH = "emote-damage-leave";
private static final String COSMETIC_EMOTE_INVINCIBLE_PATH = "emote-invincible";
private static final String COSMETIC_EMOTE_CAMERA_PATH = "emote-camera";
private static final String COSMETIC_EMOTE_MOVE_CHECK_PATH = "emote-move";
private static final String COSMETIC_DISABLED_WORLDS_PATH = "disabled-worlds";
private static final String COSMETIC_PACKET_ENTITY_TELEPORT_COOLDOWN_PATH = "entity-cooldown-teleport-packet";
private static final String COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH = "backpack-force-riding-packet";
private static final String COSMETIC_FORCE_OFFHAND_COSMETIC_SHOW_PATH = "offhand-always-show";
private static final String COSMETIC_ADD_ENCHANTS_HELMET_PATH = "helmet-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_CHESTPLATE_PATH = "chest-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_LEGGINGS_PATH = "leggings-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_BOOTS_PATH = "boots-add-enchantments";
private static final String COSMETIC_DESTROY_LOOSE_COSMETIC_PATH = "destroy-loose-cosmetics";
private static final String COSMETIC_BALLOON_HEAD_FORWARD_PATH = "balloon-head-forward";
private static final String MENU_SETTINGS_PATH = "menu-settings";
private static final String MENU_CLICK_COOLDOWN_PATH = "click-cooldown";
private static final String MENU_CLICK_COOLDOWN_TIME_PATH = "time";
private static final String COSMETIC_TYPE_SETTINGS_PATH = "cosmetic-type";
private static final String EQUIP_CLICK_TYPE = "equip-click";
private static final String UNEQUIP_CLICK_TYPE = "unequip-click";
private static final String DYE_CLICK_TYPE = "dye-click";
private static final String SHADING_PATH = "shading";
private static final String FIRST_ROW_SHIFT_PATH = "first-row-shift";
private static final String SEQUENT_ROW_SHIFT_PATH = "sequent-row-shift";
@@ -69,6 +64,10 @@ public class Settings {
private static final String EQUIPABLE_COSMETIC_COLOR_PATH = "equipable-cosmetic-color";
private static final String LOCKED_COSMETIC_COLOR_PATH = "locked-cosmetic-color";
private static final String ENABLED_PATH = "enabled";
private static final String SLOT_OPTIONS_PATH = "slot-options";
private static final String BACKPACK_PREVENT_DARKNESS_PATH = "backpack-prevent-darkness";
private static final String BETTER_HUD_PATH = "betterhud";
private static final String BETTER_HUD_HIDE_IN_WARDROBE_PATH = "wardrobe-hide";
@Getter
private static String defaultMenu;
@@ -89,38 +88,27 @@ public class Settings {
@Getter
private static boolean forceShowOnJoin;
@Getter
private static boolean itemProcessingDisplayName;
@Getter
private static boolean itemProcessingLore;
@Getter
private static boolean itemsAdderChangeReload;
@Getter
private static boolean nexoChangeReload;
@Getter
private static boolean worldGuardMoveCheck;
@Getter
private static boolean cosmeticEmoteBlockCheck;
@Getter
private static boolean addHelmetEnchants;
@Getter
private static boolean addChestplateEnchants;
@Getter
private static boolean addLeggingEnchants;
@Getter
private static boolean addBootsEnchants;
@Getter
private static boolean emoteAirCheck;
@Getter
private static boolean emoteDamageLeave;
@Getter
private static boolean emoteInvincible;
private static final HashMap<EquipmentSlot, SlotOptionConfig> slotOptions = new HashMap<>();
@Getter
private static boolean destroyLooseCosmetics;
@Getter
private static boolean backpackForceRidingEnabled;
@Getter
private static boolean cosmeticForceOffhandCosmeticShow;
@Getter
private static boolean emotesEnabled;
@Getter
private static boolean disabledGamemodesEnabled;
@Getter
private static boolean balloonHeadForward;
@Getter
private static boolean backpackPreventDarkness;
@Getter
private static List<String> disabledGamemodes;
@Getter
private static List<String> disabledWorlds;
@@ -131,6 +119,10 @@ public class Settings {
@Getter
private static int packetEntityTeleportCooldown;
@Getter
private static Long defaultMenuCooldown;
@Getter
private static boolean menuClickCooldown;
@Getter
private static double emoteDistance;
@Getter
private static Vector balloonOffset;
@@ -139,6 +131,8 @@ public class Settings {
@Getter
private static String cosmeticUnEquipClickType;
@Getter
private static String cosmeticDyeClickType;
@Getter
private static boolean defaultShading;
@Getter
private static String firstRowShift;
@@ -156,12 +150,10 @@ public class Settings {
private static String equipableCosmeticColor;
@Getter
private static String lockedCosmeticColor;
@Getter
private static boolean emoteCameraEnabled;
@Getter
private static boolean emoteMoveCheck;
@Getter @Setter
private static boolean allPlayersHidden;
@Getter
private static boolean wardrobeHideHud;
public static void load(ConfigurationNode source) {
@@ -191,31 +183,39 @@ public class Settings {
disabledWorlds = new ArrayList<>();
}
ConfigurationNode itemProcessingSettings = cosmeticSettings.node(ITEM_PROCESSING_PATH);
itemProcessingDisplayName = itemProcessingSettings.node(ITEM_PROCESS_DISPLAY_NAME_PATH).getBoolean(true);
itemProcessingLore = itemProcessingSettings.node(ITEM_PROCESS_LORE_PATH).getBoolean(true);
unapplyOnDeath = cosmeticSettings.node(UNAPPLY_DEATH_PATH).getBoolean(false);
forcePermissionJoin = cosmeticSettings.node(FORCE_PERMISSION_JOIN_PATH).getBoolean(false);
forceShowOnJoin = cosmeticSettings.node(FORCE_SHOW_COSMETICS_PATH).getBoolean(false);
emotesEnabled = cosmeticSettings.node(COSMETIC_EMOTE_ENABLE).getBoolean(true);
emoteDistance = cosmeticSettings.node(EMOTE_DISTANCE_PATH).getDouble(-3);
cosmeticEmoteBlockCheck = cosmeticSettings.node(COSMETIC_EMOTE_CHECK_PATH).getBoolean(true);
emoteAirCheck = cosmeticSettings.node(COSMETIC_EMOTE_AIR_CHECK_PATH).getBoolean(true);
emoteDamageLeave = cosmeticSettings.node(COSMETIC_EMOTE_DAMAGE_PATH).getBoolean(false);
emoteInvincible = cosmeticSettings.node(COSMETIC_EMOTE_INVINCIBLE_PATH).getBoolean(false);
destroyLooseCosmetics = cosmeticSettings.node(COSMETIC_DESTROY_LOOSE_COSMETIC_PATH).getBoolean(false);
backpackForceRidingEnabled = cosmeticSettings.node(COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH).getBoolean(false);
addHelmetEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_HELMET_PATH).getBoolean(false);
addChestplateEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_CHESTPLATE_PATH).getBoolean(false);
addLeggingEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_LEGGINGS_PATH).getBoolean(false);
addBootsEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_BOOTS_PATH).getBoolean(false);
cosmeticSettings.node(SLOT_OPTIONS_PATH).childrenMap().forEach((key, value) -> {
EquipmentSlot slot = convertConfigToEquipment(key.toString().toLowerCase());
if (slot == null) {
MessagesUtil.sendDebugMessages("Invalid slot option: " + key, Level.WARNING);
return;
}
boolean addEnchantments = value.node("add-enchantments").getBoolean(false);
boolean requireEmpty = value.node("require-empty").getBoolean(false);
slotOptions.put(slot, new SlotOptionConfig(slot, addEnchantments, requireEmpty));
});
tickPeriod = cosmeticSettings.node(TICK_PERIOD_PATH).getInt(-1);
viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt(-3);
emoteCameraEnabled = cosmeticSettings.node(COSMETIC_EMOTE_CAMERA_PATH).getBoolean(true);
emoteMoveCheck = cosmeticSettings.node(COSMETIC_EMOTE_MOVE_CHECK_PATH).getBoolean(false);
packetEntityTeleportCooldown = cosmeticSettings.node(COSMETIC_PACKET_ENTITY_TELEPORT_COOLDOWN_PATH).getInt(-1);
cosmeticForceOffhandCosmeticShow = cosmeticSettings.node(COSMETIC_FORCE_OFFHAND_COSMETIC_SHOW_PATH).getBoolean(false);
balloonHeadForward = cosmeticSettings.node(COSMETIC_BALLOON_HEAD_FORWARD_PATH).getBoolean(false);
backpackPreventDarkness = cosmeticSettings.node(BACKPACK_PREVENT_DARKNESS_PATH).getBoolean(true);
ConfigurationNode menuSettings = source.node(MENU_SETTINGS_PATH);
ConfigurationNode clickCooldownSettings = menuSettings.node(MENU_CLICK_COOLDOWN_PATH);
menuClickCooldown = clickCooldownSettings.node(ENABLED_PATH).getBoolean(true);
defaultMenuCooldown = clickCooldownSettings.node(MENU_CLICK_COOLDOWN_TIME_PATH).getLong(1000L);
ConfigurationNode shadingSettings = menuSettings.node(SHADING_PATH);
defaultShading = shadingSettings.node(ENABLED_PATH).getBoolean();
firstRowShift = shadingSettings.node(FIRST_ROW_SHIFT_PATH).getString();
@@ -228,8 +228,9 @@ public class Settings {
lockedCosmeticColor = shadingSettings.node(LOCKED_COSMETIC_COLOR_PATH).getString();
ConfigurationNode cosmeticTypeSettings = menuSettings.node(COSMETIC_TYPE_SETTINGS_PATH);
cosmeticEquipClickType = cosmeticTypeSettings.node(EQUIP_CLICK_TYPE).getString("ALL");
cosmeticUnEquipClickType = cosmeticTypeSettings.node(UNEQUIP_CLICK_TYPE).getString("ALL");
cosmeticEquipClickType = cosmeticTypeSettings.node(EQUIP_CLICK_TYPE).getString("ANY");
cosmeticUnEquipClickType = cosmeticTypeSettings.node(UNEQUIP_CLICK_TYPE).getString("ANY");
cosmeticDyeClickType = cosmeticTypeSettings.node(DYE_CLICK_TYPE).getString("ANY");
final var balloonSection = cosmeticSettings.node(BALLOON_OFFSET);
balloonOffset = loadVector(balloonSection);
@@ -241,9 +242,16 @@ public class Settings {
dyeMenuOutputSlot = dyeMenuSettings.node(DYE_MENU_OUTPUT_SLOT).getInt(25);
ConfigurationNode hookSettings = source.node(HOOK_SETTING_PATH);
ConfigurationNode itemsAdderSettings = hookSettings.node(HOOK_ITEMADDER_PATH);
itemsAdderChangeReload = itemsAdderSettings.node(HOOK_RELOAD_CHANGE_PATH).getBoolean(false);
ConfigurationNode nexoSettings = hookSettings.node(HOOK_NEXO_PATH);
nexoChangeReload = nexoSettings.node(HOOK_RELOAD_CHANGE_PATH).getBoolean(true);
ConfigurationNode betterHudSettings = hookSettings.node(BETTER_HUD_PATH);
wardrobeHideHud = betterHudSettings.node(BETTER_HUD_HIDE_IN_WARDROBE_PATH).getBoolean(true);
ConfigurationNode worldGuardSettings = hookSettings.node(HOOK_WORLDGUARD_PATH);
worldGuardMoveCheck = worldGuardSettings.node(HOOK_WG_MOVE_CHECK_PATH).getBoolean(true);
// I messed up in release 2.2.6 and forgot to change player_move_check to player-move-check.
@@ -257,24 +265,9 @@ public class Settings {
return new Vector(config.node("x").getDouble(), config.node("y").getDouble(), config.node("z").getDouble());
}
public static boolean getShouldAddEnchants(EquipmentSlot slot) {
switch (slot) {
case HEAD -> {
return addHelmetEnchants;
}
case CHEST -> {
return addChestplateEnchants;
}
case LEGS -> {
return addLeggingEnchants;
}
case FEET -> {
return addBootsEnchants;
}
default -> {
return false;
}
}
public static SlotOptionConfig getSlotOption(EquipmentSlot slot) {
if (!slotOptions.containsKey(slot)) slotOptions.put(slot, new SlotOptionConfig(slot, false, false));
return slotOptions.get(slot);
}
public static void setDebugMode(boolean newSetting) {
@@ -286,4 +279,16 @@ public class Settings {
plugin.saveConfig();
}
private static EquipmentSlot convertConfigToEquipment(String slot) {
return switch (slot) {
case "helmet" -> EquipmentSlot.HEAD;
case "chestplate" -> EquipmentSlot.CHEST;
case "leggings" -> EquipmentSlot.LEGS;
case "boots" -> EquipmentSlot.FEET;
case "offhand" -> EquipmentSlot.OFF_HAND;
case "mainhand" -> EquipmentSlot.HAND;
default -> null;
};
}
}

View File

@@ -0,0 +1,20 @@
package com.hibiscusmc.hmccosmetics.config;
import lombok.Getter;
import org.bukkit.inventory.EquipmentSlot;
public class SlotOptionConfig {
@Getter
private final EquipmentSlot slot;
@Getter
private final boolean addEnchantments;
@Getter
private final boolean requireEmpty;
public SlotOptionConfig(EquipmentSlot slot, boolean addEnchantments, boolean requireEmpty) {
this.slot = slot;
this.addEnchantments = addEnchantments;
this.requireEmpty = requireEmpty;
}
}

View File

@@ -14,10 +14,12 @@ public class Wardrobe {
private final String id;
@Getter @Setter
private int distance;
@Getter @Setter
@Getter @Setter @Nullable
private String permission;
@Getter @Setter
private WardrobeLocation location;
@Getter @Setter @Nullable
private String defaultMenu;
/**
* This creates a Wardrobe object with all the information that a user will need when entering.
@@ -25,12 +27,14 @@ public class Wardrobe {
* @param location The 3 locations of the Wardrobe, if any of these 3 locations are null, the wardrobe will not work
* @param permission The permission required to enter the wardrobe, if null, no permission is required
* @param distance The distance from the wardrobe that the player can be to enter, if -1, the player can enter from any distance
* @param defaultMenu The default menu that the player will open when entering the wardrobe.
*/
public Wardrobe(@NotNull String id, @NotNull WardrobeLocation location, @Nullable String permission, int distance) {
public Wardrobe(@NotNull String id, @NotNull WardrobeLocation location, @Nullable String permission, int distance, @Nullable String defaultMenu) {
this.id = id;
this.location = location;
this.distance = distance;
if (permission != null) this.permission = permission;
if (defaultMenu != null) this.defaultMenu = defaultMenu;
}
/**
@@ -50,7 +54,7 @@ public class Wardrobe {
Location wardrobeLocation = location.getNpcLocation();
Location location = user.getEntity().getLocation();
if (wardrobeLocation == null) return false;
if (distance == -1) return true;
if (distance <= 0) return true;
if (!wardrobeLocation.getWorld().equals(location.getWorld())) return false;
return wardrobeLocation.distanceSquared(location) <= distance * distance;
}

View File

@@ -2,7 +2,6 @@ package com.hibiscusmc.hmccosmetics.config;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.Utils;
import lombok.Getter;
import me.lojosho.hibiscuscommons.config.serializer.LocationSerializer;
import me.lojosho.shaded.configurate.ConfigurationNode;
@@ -45,6 +44,7 @@ public class WardrobeSettings {
private static final String WARDROBES_PATH = "wardrobes";
private static final String PERMISSION_PATH = "permission";
private static final String DISTANCE_PATH = "distance";
private static final String WARDROBE_DEFAULT_MENU = "default-menu";
private static final String BOSSBAR_PATH = "bossbar";
private static final String BOSSBAR_ENABLE_PATH = "enabled";
private static final String BOSSBAR_TEXT_PATH = "text";
@@ -169,14 +169,16 @@ public class WardrobeSettings {
MessagesUtil.sendDebugMessages("Wardrobe Location: " + npcLocation);
Location viewerLocation = LocationSerializer.INSTANCE.deserialize(Location.class, wardrobesNode.node(VIEWER_LOCATION_PATH));
MessagesUtil.sendDebugMessages("Viewer Location: " + viewerLocation);
Location leaveLocation = Utils.replaceIfNull(LocationSerializer.INSTANCE.deserialize(Location.class, wardrobesNode.node(LEAVE_LOCATION_PATH)), viewerLocation);
Location leaveLocation = LocationSerializer.INSTANCE.deserialize(Location.class, wardrobesNode.node(LEAVE_LOCATION_PATH));
if (leaveLocation == null) leaveLocation = viewerLocation;
MessagesUtil.sendDebugMessages("Leave Location: " + leaveLocation);
WardrobeLocation wardrobeLocation = new WardrobeLocation(npcLocation, viewerLocation, leaveLocation);
String permission = wardrobesNode.node(PERMISSION_PATH).getString();
String defaultMenu = wardrobesNode.node(WARDROBE_DEFAULT_MENU).getString();
int distance = wardrobesNode.node(DISTANCE_PATH).getInt(-1);
Wardrobe wardrobe = new Wardrobe(id, wardrobeLocation, permission, distance);
Wardrobe wardrobe = new Wardrobe(id, wardrobeLocation, permission, distance, defaultMenu);
addWardrobe(wardrobe);
} catch (Exception e) {
MessagesUtil.sendDebugMessages("Unable to create wardrobe " + id, Level.SEVERE);
@@ -280,4 +282,14 @@ public class WardrobeSettings {
plugin.saveConfig();
}
public static void setWardrobeDefaultMenu(Wardrobe wardrobe, String defaultMenu) {
wardrobe.setDefaultMenu(defaultMenu);
HMCCosmeticsPlugin plugin = HMCCosmeticsPlugin.getInstance();
plugin.getConfig().set("wardrobe.wardrobes." + wardrobe.getId() + ".default-menu", defaultMenu);
plugin.saveConfig();
}
}

View File

@@ -2,33 +2,61 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.logging.Level;
@Getter
@Setter
public abstract class Cosmetic {
protected static ItemStack UNDEFINED_DISPLAY_ITEM_STACK;
@Getter @Setter
static {
UNDEFINED_DISPLAY_ITEM_STACK = new ItemStack(Material.BARRIER);
ItemMeta meta = UNDEFINED_DISPLAY_ITEM_STACK.getItemMeta();
if (meta != null) {
// Legacy methods for Spigot >:(
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&cUndefined Item Display"));
meta.setLore(List.of(
ChatColor.translateAlternateColorCodes('&', "&cPlease check your configurations & console to"),
ChatColor.translateAlternateColorCodes('&', "&censure there are no errors.")));
}
UNDEFINED_DISPLAY_ITEM_STACK.setItemMeta(meta);
}
/** Identifier of the cosmetic. */
private String id;
@Getter @Setter
private String permission;
private ItemStack item;
@Getter @Setter
private String material;
@Getter @Setter
private CosmeticSlot slot;
@Getter @Setter
private boolean dyable;
protected Cosmetic(String id, @NotNull ConfigurationNode config) {
/** Permission to use the cosmetic. */
private String permission;
/** The display {@link ItemStack} of the cosmetic. */
@Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
private ItemStack item;
/** The material string of the cosmetic. */
private String material;
/** The {@link CosmeticSlot} this cosmetic occupies. */
private CosmeticSlot slot;
/** Whether the cosmetic is dyeable or not. */
private boolean dyeable;
protected Cosmetic(@NotNull String id, @NotNull ConfigurationNode config) {
this.id = id;
if (!config.node("permission").virtual()) {
@@ -39,23 +67,49 @@ public abstract class Cosmetic {
if (!config.node("item").virtual()) {
this.material = config.node("item", "material").getString();
this.item = generateItemStack(config.node("item"));
try {
this.item = generateItemStack(config.node("item"));
} catch(Exception ex) {
MessagesUtil.sendDebugMessages("Forcing %s to use undefined display".formatted(getId()));
this.item = UNDEFINED_DISPLAY_ITEM_STACK;
}
}
MessagesUtil.sendDebugMessages("Slot: " + config.node("slot").getString());
this.slot = CosmeticSlot.valueOf(config.node("slot").getString());
setSlot(CosmeticSlot.valueOf(config.node("slot").getString()));
setDyable(config.node("dyeable").getBoolean(false));
this.dyeable = config.node("dyeable").getBoolean(false);
MessagesUtil.sendDebugMessages("Dyeable " + dyeable);
}
MessagesUtil.sendDebugMessages("Dyeable " + dyable);
Cosmetics.addCosmetic(this);
protected Cosmetic(String id, String permission, ItemStack item, String material, CosmeticSlot slot, boolean dyeable) {
this.id = id;
this.permission = permission;
this.item = item;
this.material = material;
this.slot = slot;
this.dyeable = dyeable;
}
public boolean requiresPermission() {
return permission != null;
}
public abstract void update(CosmeticUser user);
/**
* Dispatched when an update is requested upon the cosmetic.
* @param user the user to preform the update against
*/
public final void update(CosmeticUser user) {
this.doUpdate(user);
}
/**
* Action preformed on the update.
* @param user the user to preform the update against
*/
protected void doUpdate(final CosmeticUser user) {
// NO-OP.
}
@Nullable
public ItemStack getItem() {
@@ -63,6 +117,11 @@ public abstract class Cosmetic {
return item.clone();
}
/**
* Generate an {@link ItemStack} from a {@link ConfigurationNode}.
* @param config the configuration node
* @return the {@link ItemStack}
*/
protected ItemStack generateItemStack(ConfigurationNode config) {
try {
ItemStack item = ItemSerializer.INSTANCE.deserialize(ItemStack.class, config);

View File

@@ -0,0 +1,75 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
import com.google.common.collect.ImmutableCollection;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Color;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Represents any object that can wear/hold cosmetics,
* users, for example.
*/
public interface CosmeticHolder {
@Nullable Cosmetic getCosmetic(@NotNull CosmeticSlot slot);
@NotNull ImmutableCollection<Cosmetic> getCosmetics();
void addCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color);
default void addCosmetic(@NotNull Cosmetic cosmetic) {
addCosmetic(cosmetic, null);
}
default void removeCosmetics() {
// Small optimization could be made, but Concurrent modification prevents us from both getting and removing
for (CosmeticSlot slot : CosmeticSlot.values().values()) {
removeCosmeticSlot(slot);
}
}
void removeCosmeticSlot(@NotNull CosmeticSlot slot);
default void removeCosmeticSlot(@NotNull Cosmetic cosmetic) {
removeCosmeticSlot(cosmetic.getSlot());
}
default boolean hasCosmeticInSlot(@NotNull CosmeticSlot slot) {
return getCosmetic(slot) != null;
}
default boolean hasCosmeticInSlot(@NotNull Cosmetic cosmetic) {
final var existingCosmetic = getCosmetic(cosmetic.getSlot());
if (existingCosmetic == null) return false;
return Objects.equals(cosmetic.getId(), existingCosmetic.getId());
}
default boolean canEquipCosmetic(@NotNull Cosmetic cosmetic) {
return canEquipCosmetic(cosmetic, false);
}
boolean canEquipCosmetic(@NotNull Cosmetic cosmetic, boolean ignoreWardrobe);
void updateCosmetic(@NotNull CosmeticSlot slot);
/**
* Just for backwards compatibility, ensures that the given viewer and the given cosmetic holder
* represent the same user.
*
* @param viewer the viewer
* @param cosmeticHolder the cosmetic holder
*/
@ApiStatus.Internal
static @NotNull CosmeticUser ensureSingleCosmeticUser(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder) {
if (!(cosmeticHolder instanceof CosmeticUser user) || !user.getUniqueId().equals(viewer.getUniqueId())) {
throw new IllegalStateException("This method does not support having a different viewer than" +
" the same cosmetic holder. Needs to be updated to support the overload that takes a viewer and" +
" a cosmetic holder instead of a single CosmeticUser.");
}
return user;
}
}

View File

@@ -0,0 +1,72 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.types.*;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.extern.slf4j.Slf4j;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.function.BiFunction;
/**
* Allow custom implementations of a {@link Cosmetic}.
*/
@Slf4j
public abstract class CosmeticProvider {
protected static final Map<CosmeticSlot, BiFunction<String, ConfigurationNode, Cosmetic>> MAPPINGS = Map.ofEntries(
Map.entry(CosmeticSlot.HELMET, CosmeticArmorType::new),
Map.entry(CosmeticSlot.CHESTPLATE, CosmeticArmorType::new),
Map.entry(CosmeticSlot.LEGGINGS, CosmeticArmorType::new),
Map.entry(CosmeticSlot.BOOTS, CosmeticArmorType::new),
Map.entry(CosmeticSlot.OFFHAND, CosmeticArmorType::new),
Map.entry(CosmeticSlot.MAINHAND, CosmeticMainhandType::new),
Map.entry(CosmeticSlot.BACKPACK, CosmeticBackpackType::new),
Map.entry(CosmeticSlot.BALLOON, CosmeticBalloonType::new)
);
private static final String EXCEPTION_MESSAGE = "Unknown slot %s provided for mapping, if you registered your own CosmeticSlot please ensure that you've also registered a custom CosmeticProvider! Or if you have already registered a custom CosmeticProvider ensure it is registered in your plugins `onLoad` method instead of `onEnable`!";
/**
* Construct the {@link Cosmetic}.
* @param id the cosmetic id
* @param config the configuration node of the cosmetic
* @param slot the occupying slot of the cosmetic
* @return the {@link Cosmetic}
* @throws IllegalArgumentException if the provided cosmetic could not be mapped
*/
public @NotNull Cosmetic createCosmetic(String id, ConfigurationNode config, CosmeticSlot slot) throws IllegalArgumentException {
final var mapper = MAPPINGS.get(slot);
if(mapper == null) {
throw new IllegalArgumentException(
EXCEPTION_MESSAGE.formatted(slot)
);
}
return mapper.apply(id, config);
}
/**
* Represents the plugin that is providing this {@link CosmeticProvider}
* @return the plugin
*/
public abstract Plugin getProviderPlugin();
/**
* Default Implementation.
*/
static class Default extends CosmeticProvider {
public static final CosmeticProvider INSTANCE = new Default();
@Override
public Plugin getProviderPlugin() {
return HMCCosmeticsPlugin.getInstance();
}
}
}

View File

@@ -1,13 +1,81 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
public enum CosmeticSlot {
HELMET,
CHESTPLATE,
LEGGINGS,
BOOTS,
MAINHAND,
OFFHAND,
BACKPACK,
BALLOON,
EMOTE
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Getter
public class CosmeticSlot {
private static final ConcurrentHashMap<String, CosmeticSlot> REGISTRY = new ConcurrentHashMap<>();
public static final CosmeticSlot HELMET = register("HELMET");
public static final CosmeticSlot CHESTPLATE = register("CHESTPLATE");
public static final CosmeticSlot LEGGINGS = register("LEGGINGS");
public static final CosmeticSlot BOOTS = register("BOOTS");
public static final CosmeticSlot MAINHAND = register("MAINHAND");
public static final CosmeticSlot OFFHAND = register("OFFHAND");
public static final CosmeticSlot BACKPACK = register("BACKPACK");
public static final CosmeticSlot BALLOON = register("BALLOON");
private final String name;
private CosmeticSlot(@NotNull String name) {
this.name = name;
}
/**
* Registers a new slot with the given name. If a slot with the given name already exists, it will be returned.
* @param name The name of the slot (This will automatically be converted into all UPPERCASE)
* @return The slot that was registered or already exists.
* @throws IllegalArgumentException if a cosmetic slot by that name has already been registered
*/
@NotNull
public static CosmeticSlot register(@NotNull String name) {
final String upperName = name.toUpperCase();
if(REGISTRY.containsKey(upperName)) {
throw new IllegalArgumentException("A cosmetic slot with name '" + name + "' is already registered.");
}
final CosmeticSlot slot = new CosmeticSlot(upperName);
REGISTRY.put(upperName, slot);
return slot;
}
/**
* @return An unmodifiable map of all the slots that have been registered.
*/
@NotNull
public static Map<String, CosmeticSlot> values() {
return Collections.unmodifiableMap(REGISTRY);
}
/**
* Gets the slot with the given name.
* @param name The name of the slot to get. This is automatically converted to all UPPERCASE.
* @return The slot with the given name, or null if it does not exist.
*/
@Nullable
public static CosmeticSlot valueOf(@NotNull String name) {
final String upperName = name.toUpperCase();
return REGISTRY.get(upperName);
}
/**
* Checks if the registry contains a slot with the given name.
* @param name The name of the slot to check for. This is automatically converted to all UPPERCASE.
* @return True if the slot exists, false otherwise.
*/
public static boolean contains(@NotNull String name) {
final String upperName = name.toUpperCase();
return REGISTRY.containsKey(upperName);
}
@Override
public String toString() {
return name;
}
}

View File

@@ -2,14 +2,12 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.google.common.collect.HashBiMap;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.types.*;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.extern.slf4j.Slf4j;
import me.lojosho.shaded.configurate.CommentedConfigurationNode;
import me.lojosho.shaded.configurate.ConfigurateException;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.yaml.YamlConfigurationLoader;
import org.apache.commons.lang3.EnumUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,10 +19,12 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Stream;
@Slf4j
public class Cosmetics {
private static final HashBiMap<String, Cosmetic> COSMETICS = HashBiMap.create();
private static CosmeticProvider PROVIDER = CosmeticProvider.Default.INSTANCE;
public static void addCosmetic(Cosmetic cosmetic) {
COSMETICS.put(cosmetic.getId(), cosmetic);
}
@@ -34,7 +34,7 @@ public class Cosmetics {
}
public static void removeCosmetic(Cosmetic cosmetic) {
COSMETICS.remove(cosmetic);
COSMETICS.remove(cosmetic.getId());
}
@Nullable
@@ -91,29 +91,51 @@ public class Cosmetics {
}
}
/**
* Register a custom {@link CosmeticProvider} to provide your own user implementation to
* be used and queried.
* @param provider the provider to register
* @throws IllegalArgumentException if the provider is already registered by another plugin
*/
public static void registerProvider(final CosmeticProvider provider) {
if(PROVIDER != CosmeticProvider.Default.INSTANCE) {
throw new IllegalArgumentException("CosmeticProvider already registered by %s, this conflicts with %s attempting to register their own.".formatted(
PROVIDER.getProviderPlugin().getName(),
provider.getProviderPlugin().getName()
));
}
PROVIDER = provider;
}
/**
* Fetch the current {@link CosmeticProvider} being used.
* @return the current {@link CosmeticProvider} being used
*/
public static CosmeticProvider getProvider() {
return PROVIDER;
}
private static void setupCosmetics(@NotNull CommentedConfigurationNode config) {
for (ConfigurationNode cosmeticConfig : config.childrenMap().values()) {
String id = cosmeticConfig.key().toString();
MessagesUtil.sendDebugMessages("Attempting to add " + id);
ConfigurationNode slotNode = cosmeticConfig.node("slot");
if (slotNode.virtual()) {
MessagesUtil.sendDebugMessages("Unable to create " + id + " because there is no slot defined!", Level.WARNING);
continue;
}
String slot = slotNode.getString("");
CosmeticSlot cosmeticSlot = CosmeticSlot.valueOf(slot);
if (cosmeticSlot == null) {
MessagesUtil.sendDebugMessages("Unable to create " + id + " because " + slotNode.getString() + " is not a valid slot!", Level.WARNING);
continue;
}
try {
String id = cosmeticConfig.key().toString();
MessagesUtil.sendDebugMessages("Attempting to add " + id);
ConfigurationNode slotNode = cosmeticConfig.node("slot");
if (slotNode.virtual()) {
MessagesUtil.sendDebugMessages("Unable to create " + id + " because there is no slot defined!", Level.WARNING);
continue;
}
if (!EnumUtils.isValidEnum(CosmeticSlot.class, slotNode.getString())) {
MessagesUtil.sendDebugMessages("Unable to create " + id + " because " + slotNode.getString() + " is not a valid slot!", Level.WARNING);
continue;
}
switch (CosmeticSlot.valueOf(cosmeticConfig.node("slot").getString())) {
case BALLOON -> new CosmeticBalloonType(id, cosmeticConfig);
case BACKPACK -> new CosmeticBackpackType(id, cosmeticConfig);
case MAINHAND -> new CosmeticMainhandType(id, cosmeticConfig);
case EMOTE -> new CosmeticEmoteType(id, cosmeticConfig);
default -> new CosmeticArmorType(id, cosmeticConfig);
}
} catch (Exception e) {
if (Settings.isDebugMode()) e.printStackTrace();
addCosmetic(PROVIDER.createCosmetic(id, cosmeticConfig, cosmeticSlot));
} catch(Exception ex) {
log.error("Unable to construct cosmetic for {}, skipping processing it.", id, ex);
}
}
}

View File

@@ -22,17 +22,22 @@ public class CosmeticArmorType extends Cosmetic {
public CosmeticArmorType(String id, ConfigurationNode config) {
super(id, config);
this.equipSlot = HMCCInventoryUtils.getEquipmentSlot(getSlot());
EquipmentSlot slot = HMCCInventoryUtils.getEquipmentSlot(getSlot());
if (slot == null) {
// Hypothetically it shouldn't be null, but it was happening on some random servers? Adding this just in case
throw new IllegalArgumentException("Invalid slot for cosmetic armor type: " + getSlot() + " in " + id + " cosmetic config.");
}
this.equipSlot = slot;
}
@Override
public void update(@NotNull CosmeticUser user) {
if (user.getUserEmoteManager().isPlayingEmote() || user.isInWardrobe()) return;
protected void doUpdate(@NotNull CosmeticUser user) {
if (user.isInWardrobe()) return;
Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return;
if (!Settings.isCosmeticForceOffhandCosmeticShow()
&& equipSlot.equals(EquipmentSlot.OFF_HAND)
&& ((user.getEntity() instanceof Player) && !user.getPlayer().getInventory().getItemInOffHand().getType().isAir())) return;
if (Settings.getSlotOption(equipSlot).isRequireEmpty() && entity instanceof HumanEntity humanEntity) {
if (!humanEntity.getInventory().getItem(equipSlot).getType().isAir()) return;
}
ItemStack item = getItem(user);
if (item == null) return;
PacketManager.equipmentSlotUpdate(entity.getEntityId(), equipSlot, item, HMCCPacketManager.getViewers(entity.getLocation()));
@@ -44,7 +49,7 @@ public class CosmeticArmorType extends Cosmetic {
public ItemStack getItem(@NotNull CosmeticUser user, ItemStack cosmeticItem) {
if (!(user.getEntity() instanceof HumanEntity humanEntity)) return null;
if (Settings.getShouldAddEnchants(equipSlot)) {
if (Settings.getSlotOption(equipSlot).isAddEnchantments()) {
ItemStack equippedItem = humanEntity.getInventory().getItem(equipSlot);
cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments());
}
@@ -52,6 +57,7 @@ public class CosmeticArmorType extends Cosmetic {
return cosmeticItem;
}
@NotNull
public EquipmentSlot getEquipSlot() {
return this.equipSlot;
}

View File

@@ -3,6 +3,8 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserEntity;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
@@ -24,8 +26,6 @@ import java.util.logging.Level;
public class CosmeticBackpackType extends Cosmetic {
@Getter
private final String modelName;
@Getter
private int height = -1;
private ItemStack firstPersonBackpack;
@@ -33,8 +33,6 @@ public class CosmeticBackpackType extends Cosmetic {
public CosmeticBackpackType(String id, ConfigurationNode config) {
super(id, config);
modelName = config.node("model").getString();
if (!config.node("firstperson-item").virtual()) {
this.firstPersonBackpack = generateItemStack(config.node("firstperson-item"));
this.height = config.node("height").getInt(5);
@@ -42,30 +40,40 @@ public class CosmeticBackpackType extends Cosmetic {
}
@Override
public void update(@NotNull CosmeticUser user) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
protected void doUpdate(@NotNull CosmeticUser user) {
Entity entity = user.getEntity();
if (entity == null) return;
Location loc = entity.getLocation().clone().add(0, 2, 0);
Location entityLocation = entity.getLocation();
Location loc = entityLocation.clone().add(0, 2, 0);
if (user.isInWardrobe() || !user.isBackpackSpawned()) return;
// This needs to be moved to purely packet based, there are far to many plugin doing dumb stuff that prevents spawning armorstands ignoring our spawn reason.
List<Player> outsideViewers = user.getUserBackpackManager().getEntityManager().refreshViewers(loc);
if (user.isHidden()) {
// Sometimes the backpack is not despawned when the player is hidden (weird ass logic happening somewhere)
user.despawnBackpack();
return;
}
user.getUserBackpackManager().getEntityManager().teleport(loc);
user.getUserBackpackManager().getEntityManager().setRotation((int) loc.getYaw(), isFirstPersonCompadible());
UserBackpackManager backpackManager = user.getUserBackpackManager();
UserEntity entityManager = backpackManager.getEntityManager();
int firstArmorStandId = backpackManager.getFirstArmorStandId();
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), user.getUserBackpackManager().getFirstArmorStandId(), EntityType.ARMOR_STAND, UUID.randomUUID(), outsideViewers);
HMCCPacketManager.sendArmorstandMetadata(user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), outsideViewers);
List<Player> outsideViewers = entityManager.refreshViewers(loc);
entityManager.teleport(loc);
entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible());
HMCCPacketManager.sendEntitySpawnPacket(entityLocation, firstArmorStandId, EntityType.ARMOR_STAND, UUID.randomUUID(), outsideViewers);
HMCCPacketManager.sendArmorstandMetadata(firstArmorStandId, outsideViewers);
PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), outsideViewers);
// If true, it will send the riding packet to all players. If false, it will send the riding packet only to new players
if (Settings.isBackpackForceRidingEnabled()) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), user.getUserBackpackManager().getEntityManager().getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
if (Settings.isBackpackForceRidingEnabled()) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, entityManager.getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, outsideViewers);
if (!user.isInWardrobe() && isFirstPersonCompadible() && user.getPlayer() != null) {
List<Player> owner = List.of(user.getPlayer());
ArrayList<Integer> particleCloud = user.getUserBackpackManager().getAreaEffectEntityId();
ArrayList<Integer> particleCloud = backpackManager.getAreaEffectEntityId();
for (int i = 0; i < particleCloud.size(); i++) {
if (i == 0) {
HMCCPacketManager.sendRidingPacket(entity.getEntityId(), particleCloud.get(i), owner);
@@ -73,16 +81,16 @@ public class CosmeticBackpackType extends Cosmetic {
HMCCPacketManager.sendRidingPacket(particleCloud.get(i - 1), particleCloud.get(i) , owner);
}
}
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), user.getUserBackpackManager().getFirstArmorStandId(), owner);
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), firstArmorStandId, owner);
if (!user.isHidden()) {
//if (loc.getPitch() < -70) NMSHandlers.getHandler().equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, new ItemStack(Material.AIR), owner);
//else NMSHandlers.getHandler().equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, firstPersonBackpack, owner);
PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
}
MessagesUtil.sendDebugMessages("First Person Backpack Update[owner=" + user.getUniqueId() + ",player_location=" + loc + "]!", Level.INFO);
//MessagesUtil.sendDebugMessages("First Person Backpack Update[owner=" + user.getUniqueId() + ",player_location=" + loc + "]!", Level.INFO);
}
user.getUserBackpackManager().showBackpack();
backpackManager.showBackpack();
}
public boolean isFirstPersonCompadible() {

View File

@@ -4,6 +4,7 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import me.lojosho.shaded.configurate.ConfigurationNode;
@@ -22,7 +23,7 @@ public class CosmeticBalloonType extends Cosmetic {
@Getter
private final String modelName;
@Getter
private List<String> dyableParts;
private List<String> dyeableParts;
@Getter
private final boolean showLead;
@Getter
@@ -41,8 +42,8 @@ public class CosmeticBalloonType extends Cosmetic {
balloonOffset = Settings.loadVector(balloonOffsetNode);
try {
if (!config.node("dyable-parts").virtual()) {
dyableParts = config.node("dyable-parts").getList(String.class);
if (!config.node("dyeable-parts").virtual()) {
dyeableParts = config.node("dyeable-parts").getList(String.class);
}
} catch (SerializationException e) {
// Seriously?
@@ -53,7 +54,7 @@ public class CosmeticBalloonType extends Cosmetic {
}
@Override
public void update(@NotNull CosmeticUser user) {
protected void doUpdate(@NotNull CosmeticUser user) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
UserBalloonManager userBalloonManager = user.getBalloonManager();
@@ -79,8 +80,13 @@ public class CosmeticBalloonType extends Cosmetic {
}
Vector velocity = newLocation.toVector().subtract(currentLocation.toVector());
userBalloonManager.setVelocity(velocity.multiply(1.1));
userBalloonManager.setLocation(newLocation);
userBalloonManager.setVelocity(velocity.multiply(1.1));
MessagesUtil.sendDebugMessages("Balloon Cosmetic Update for " + user.getEntity().getName());
MessagesUtil.sendDebugMessages("Ballon previous location is " + currentLocation);
MessagesUtil.sendDebugMessages("Balloon location set to " + newLocation);
MessagesUtil.sendDebugMessages("Balloon velocity set to " + velocity);
HMCCPacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
HMCCPacketManager.sendLeashPacket(userBalloonManager.getPufferfishBalloonId(), entity.getEntityId(), viewer);
@@ -95,10 +101,10 @@ public class CosmeticBalloonType extends Cosmetic {
}
}
public boolean isDyablePart(String name) {
public boolean isDyeablePart(String name) {
// If player does not define parts, dye whole model
if (dyableParts == null) return true;
if (dyableParts.isEmpty()) return true;
return dyableParts.contains(name);
if (dyeableParts == null) return true;
if (dyeableParts.isEmpty()) return true;
return dyeableParts.contains(name);
}
}

View File

@@ -1,38 +0,0 @@
package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.jetbrains.annotations.NotNull;
public class CosmeticEmoteType extends Cosmetic {
private final String animationId;
private final String text;
public CosmeticEmoteType(String id, ConfigurationNode config) {
super(id, config);
animationId = config.node("animation").getString();
text = config.node("text").getString();
MessagesUtil.sendDebugMessages("CosmeticEmoteType Animation id " + animationId);
}
@Override
public void update(CosmeticUser user) {
// Nothing
}
public void run(@NotNull CosmeticUser user) {
user.getUserEmoteManager().playEmote(this);
}
public String getAnimationId() {
return animationId;
}
public String getText() {
return text;
}
}

View File

@@ -15,9 +15,9 @@ public class CosmeticMainhandType extends Cosmetic {
}
@Override
public void update(@NotNull CosmeticUser user) {
protected void doUpdate(@NotNull CosmeticUser user) {
Player player = user.getPlayer();
HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), user, getSlot(), HMCCPlayerUtils.getNearbyPlayers(player));
HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), user, getSlot(), HMCCPacketManager.getViewers(player.getLocation()));
}
}

View File

@@ -3,6 +3,7 @@ package com.hibiscusmc.hmccosmetics.database;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.database.types.Data;
import com.hibiscusmc.hmccosmetics.database.types.MySQLData;
import com.hibiscusmc.hmccosmetics.database.types.NoneData;
import com.hibiscusmc.hmccosmetics.database.types.SQLiteData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
@@ -11,6 +12,8 @@ import lombok.Getter;
import org.bukkit.entity.Player;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
public class Database {
@@ -18,18 +21,25 @@ public class Database {
private static Data data;
private static final MySQLData MYSQL_DATA = new MySQLData();
private static final SQLiteData SQLITE_DATA = new SQLiteData();
private static final NoneData NONE_DATA = new NoneData();
public Database() {
String databaseType = DatabaseSettings.getDatabaseType();
data = SQLITE_DATA; // default
if (databaseType.equalsIgnoreCase("MySQL")) {
data = MYSQL_DATA;
data = SQLITE_DATA; // default to SQLite, then check if it's anything different
switch (databaseType.toLowerCase()) {
case "mysql":
data = MYSQL_DATA;
break;
case "sqlite":
// already the default
break;
case "none":
data = NONE_DATA;
MessagesUtil.sendDebugMessages("Database is set to none. Data will not be saved.", Level.WARNING);
break;
default:
MessagesUtil.sendDebugMessages("Invalid database type. Defaulting to SQLite.", Level.WARNING);
}
/* SQLite is the default database. Might change in the future, so keep code here in case.
if (databaseType.equalsIgnoreCase("sqlite")) {
data = SQLITE_DATA;
}
*/
MessagesUtil.sendDebugMessages("Database is " + data);
setup();
@@ -47,7 +57,7 @@ public class Database {
data.save(CosmeticUsers.getUser(player));
}
public static CosmeticUser get(UUID uniqueId) {
public static CompletableFuture<UserData> get(UUID uniqueId) {
return data.get(uniqueId);
}

View File

@@ -0,0 +1,37 @@
package com.hibiscusmc.hmccosmetics.database;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class UserData {
@Getter
private UUID owner;
@Setter
@Getter
private HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> cosmetics;
@Getter
private ArrayList<CosmeticUser.HiddenReason> hiddenReasons;
public UserData(UUID owner) {
this.owner = owner;
this.cosmetics = new HashMap<>();
this.hiddenReasons = new ArrayList<>();
}
public void addCosmetic(CosmeticSlot slot, Cosmetic cosmetic, Integer color) {
cosmetics.put(slot, Map.entry(cosmetic, color));
}
public void addHiddenReason(CosmeticUser.HiddenReason reason) {
hiddenReasons.add(reason);
}
}

View File

@@ -5,6 +5,7 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.apache.commons.lang3.EnumUtils;
@@ -14,6 +15,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public abstract class Data {
@@ -22,7 +24,7 @@ public abstract class Data {
public abstract void save(CosmeticUser user);
@Nullable
public abstract CosmeticUser get(UUID uniqueId);
public abstract CompletableFuture<UserData> get(UUID uniqueId);
public abstract void clear(UUID uniqueId);
@@ -48,13 +50,9 @@ public abstract class Data {
return data.toString();
}
public final Map<CosmeticSlot, Map<Cosmetic, Color>> deserializeData(CosmeticUser user, @NotNull String raw) {
return deserializeData(user, raw, Settings.isForcePermissionJoin());
}
@NotNull
public final Map<CosmeticSlot, Map<Cosmetic, Color>> deserializeData(CosmeticUser user, @NotNull String raw, boolean permissionCheck) {
Map<CosmeticSlot, Map<Cosmetic, Color>> cosmetics = new HashMap<>();
public final HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> deserializeData(@NotNull String raw) {
HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> cosmetics = new HashMap<>();
String[] rawData = raw.split(",");
ArrayList<CosmeticUser.HiddenReason> hiddenReason = new ArrayList<>();
@@ -76,59 +74,14 @@ public abstract class Data {
String[] colorSplitData = splitData[1].split("&");
if (Cosmetics.hasCosmetic(colorSplitData[0])) cosmetic = Cosmetics.getCosmetic(colorSplitData[0]);
if (slot == null || cosmetic == null) continue;
if (permissionCheck && cosmetic.requiresPermission()) {
if (user.getPlayer() != null && !user.getPlayer().hasPermission(cosmetic.getPermission())) {
continue;
}
}
cosmetics.put(slot, Map.of(cosmetic, Color.fromRGB(Integer.parseInt(colorSplitData[1]))));
cosmetics.put(slot, Map.entry(cosmetic, Integer.parseInt(colorSplitData[1])));
} else {
if (Cosmetics.hasCosmetic(splitData[1])) cosmetic = Cosmetics.getCosmetic(splitData[1]);
if (slot == null || cosmetic == null) continue;
if (permissionCheck && cosmetic.requiresPermission()) {
if (user.getPlayer() != null && !user.getPlayer().hasPermission(cosmetic.getPermission())) {
continue;
}
}
HashMap<Cosmetic, Color> cosmeticColorHashMap = new HashMap<>();
cosmeticColorHashMap.put(cosmetic, null);
cosmetics.put(slot, cosmeticColorHashMap);
cosmetics.put(slot, Map.entry(cosmetic, -1));
}
}
MessagesUtil.sendDebugMessages("Hidden Reason: " + hiddenReason);
// if else this, if else that, if else I got to deal with this anymore i'll lose my mind
if (!hiddenReason.isEmpty()) {
for (CosmeticUser.HiddenReason reason : hiddenReason) user.silentlyAddHideFlag(reason);
} else {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// Handle gamemode check
if (user.getPlayer() != null && Settings.getDisabledGamemodes().contains(user.getPlayer().getGameMode().toString())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to gamemode");
user.hideCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
return;
} else {
if (user.isHidden(CosmeticUser.HiddenReason.GAMEMODE)) {
MessagesUtil.sendDebugMessages("Join Gamemode Check: Showing Cosmetics");
user.showCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
return;
}
}
// Handle world check
if (Settings.getDisabledWorlds().contains(user.getPlayer().getWorld().getName())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to world");
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else {
if (user.isHidden(CosmeticUser.HiddenReason.WORLD)) {
MessagesUtil.sendDebugMessages("Join World Check: Showing Cosmetics");
user.showCosmetics(CosmeticUser.HiddenReason.WORLD);
}
}
if (Settings.isAllPlayersHidden()) {
user.hideCosmetics(CosmeticUser.HiddenReason.DISABLED);
}
});
}
return cosmetics;
}

View File

@@ -13,6 +13,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
public class MySQLData extends SQLData {
@@ -38,10 +39,12 @@ public class MySQLData extends SQLData {
try {
openConnection();
if (connection == null) throw new NullPointerException("Connection is null");
connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
try (PreparedStatement preparedStatement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
"(UUID varchar(36) PRIMARY KEY, " +
"COSMETICS MEDIUMTEXT " +
");").execute();
");")) {
preparedStatement.execute();
}
} catch (SQLException | NullPointerException e) {
plugin.getLogger().severe("");
plugin.getLogger().severe("");
@@ -59,17 +62,11 @@ public class MySQLData extends SQLData {
@Override
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
try (PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;")) {
preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
});
}
@@ -132,7 +129,14 @@ public class MySQLData extends SQLData {
public PreparedStatement preparedStatement(String query) {
PreparedStatement ps = null;
if (!isConnectionOpen()) MessagesUtil.sendDebugMessages("Connection is not open");
if (!isConnectionOpen()) {
MessagesUtil.sendDebugMessages("The MySQL database connection is not open (Could the database been idle for to long?). Reconnecting...", Level.WARNING);
try {
openConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
try {
if (connection == null) throw new NullPointerException("Connection is null");

View File

@@ -0,0 +1,30 @@
package com.hibiscusmc.hmccosmetics.database.types;
import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class NoneData extends Data {
@Override
public void setup() {
// Nothing
}
@Override
public void save(CosmeticUser user) {
// Nothing
}
@Override
public @Nullable CompletableFuture<UserData> get(UUID uniqueId) {
return CompletableFuture.completedFuture(new UserData(uniqueId));
}
@Override
public void clear(UUID uniqueId) {
// Nothing
}
}

View File

@@ -3,6 +3,7 @@ package com.hibiscusmc.hmccosmetics.database.types;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Bukkit;
import org.bukkit.Color;
@@ -13,65 +14,41 @@ import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public abstract class SQLData extends Data {
@Override
@SuppressWarnings({"resource"}) // Duplicate is from deprecated InternalData
public CosmeticUser get(UUID uniqueId) {
CosmeticUser user = new CosmeticUser(uniqueId);
public CompletableFuture<UserData> get(UUID uniqueId) {
return CompletableFuture.supplyAsync(() -> {
UserData data = new UserData(uniqueId);
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedStatement = null;
try {
preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;");
try (PreparedStatement preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;")){
preparedStatement.setString(1, uniqueId.toString());
ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) {
String rawData = rs.getString("COSMETICS");
Map<CosmeticSlot, Map<Cosmetic, Color>> cosmetics = deserializeData(user, rawData);
// Load cosmetics, put them into the addedCosmetic hashmap
HashMap<Cosmetic, Color> addedCosmetics = new HashMap<>();
for (Map<Cosmetic, Color> cosmeticColors : cosmetics.values()) {
for (Cosmetic cosmetic : cosmeticColors.keySet()) {
addedCosmetics.put(cosmetic, cosmeticColors.get(cosmetic));
}
try (ResultSet rs = preparedStatement.executeQuery()) {
if (rs.next()) {
String rawData = rs.getString("COSMETICS");
HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> cosmetics = deserializeData(rawData);
data.setCosmetics(cosmetics);
}
// Run a task on the main thread, adding the cosmetics to the player
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// This can not be async.
for (Cosmetic cosmetic : addedCosmetics.keySet()) {
user.addPlayerCosmetic(cosmetic, addedCosmetics.get(cosmetic));
}
});
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null) preparedStatement.close();
} catch (SQLException e) {}
}
return data;
});
return user;
}
@Override
@SuppressWarnings("resource")
public void save(CosmeticUser user) {
Runnable run = () -> {
PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);");
try (PreparedStatement preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);")) {
preparedSt.setString(1, user.getUniqueId().toString());
preparedSt.setString(2, serializeData(user));
preparedSt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
};
if (!HMCCosmeticsPlugin.getInstance().isDisabled()) {

View File

@@ -35,10 +35,12 @@ public class SQLiteData extends SQLData {
connection = DriverManager.getConnection("jdbc:sqlite:" + dataFolder);
openConnection();
connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
try (PreparedStatement preparedStatement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
"(UUID varchar(36) PRIMARY KEY, " +
"COSMETICS MEDIUMTEXT " +
");").execute();
");")) {
preparedStatement.execute();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
@@ -48,17 +50,11 @@ public class SQLiteData extends SQLData {
@SuppressWarnings("resource")
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
try (PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;")){
preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
});
}

View File

@@ -1,85 +0,0 @@
package com.hibiscusmc.hmccosmetics.emotes;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.ticxo.playeranimator.api.PlayerAnimator;
import com.ticxo.playeranimator.api.animation.pack.AnimationPack;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Manages Emotes
*/
@SuppressWarnings("SpellCheckingInspection")
public class EmoteManager {
private static final @NotNull Map<String, String> emotes = new HashMap<>();
/**
* Loads all BlockBench animations from the emotes folder and puts it into the animation manager registry and local registry
*/
public static void loadEmotes() {
// Clear the PlayerAnimator and local registries
PlayerAnimator.api.getAnimationManager().clearRegistry();
emotes.clear();
// Get the emote directory and check if it exists
File emoteDir = new File(HMCCosmeticsPlugin.getInstance().getDataFolder().getPath() + "/emotes/");
if (!emoteDir.exists()) return;
// Get all the files inside the directory and check if it isn't 0
File[] emoteFiles = emoteDir.listFiles();
if (emoteFiles == null || emoteFiles.length == 0) return;
// Remove any files that don't have the file extension ".bbmodel" and check if there are still resulting files
emoteFiles = Arrays.stream(emoteFiles).filter(file -> file.getPath().endsWith(".bbmodel")).distinct().toArray(File[]::new);
if (emoteFiles.length == 0) return;
// Loop through all files, importing all block bench animations into the registry
for (File animationFile : emoteFiles) {
String animationKey = FilenameUtils.removeExtension(animationFile.getName());
PlayerAnimator.api.getAnimationManager().importAnimations(animationKey, animationFile);
}
// Loops through all the entries in the registries and unpacks any animation packs to ensure if there were multiple animations
// inside a singular file, that they are added to the local registry individually for tab completion
for (Map.Entry<String, AnimationPack> packEntry : PlayerAnimator.api.getAnimationManager().getRegistry().entrySet()) {
packEntry.getValue().getAnimations().keySet().forEach(animationName -> {
// API key is the format "animationKey.animationFileName.animationName"
String apiKey = packEntry.getKey().replace(":", ".") + "." + animationName;
emotes.put(animationName, apiKey);
});
}
}
/**
* Returns true if there is an animation with the specified name
* @param animationName Name whose presence is to be tested
* @return True if this registry contains a mapping for the specified name
*/
public static boolean has(@NotNull String animationName) {
return emotes.containsKey(animationName);
}
/**
* Returns the {@code API key} to which the specified name is mapped, or {@code null} if this map contains no mapping for the name.
* @param animationName Name whose {@code API key} is to be fetched
* @return The {@code API key} of the specified name or {@code null} if there was no animation name found
*/
public static @Nullable String get(@NotNull String animationName) {
return emotes.get(animationName);
}
/**
* Gets a set of all the laoded animation names
* @return A set of all loaded animation names
*/
public static @NotNull Set<String> getAllNames() {
return emotes.keySet();
}
}

View File

@@ -1,9 +1,11 @@
package com.hibiscusmc.hmccosmetics.gui;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.PlayerMenuCloseEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerMenuOpenEvent;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.gui.type.Type;
import com.hibiscusmc.hmccosmetics.gui.type.Types;
@@ -11,6 +13,8 @@ import com.hibiscusmc.hmccosmetics.gui.type.types.TypeCosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import dev.triumphteam.gui.builder.item.ItemBuilder;
import dev.triumphteam.gui.components.GuiType;
import dev.triumphteam.gui.components.InventoryProvider;
import dev.triumphteam.gui.guis.Gui;
import dev.triumphteam.gui.guis.GuiItem;
import lombok.Getter;
@@ -24,6 +28,7 @@ import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -40,6 +45,8 @@ public class Menu {
@Getter
private final int rows;
@Getter
private final Long cooldown;
@Getter
private final ConfigurationNode config;
@Getter
private final String permissionNode;
@@ -50,11 +57,12 @@ public class Menu {
private final boolean shading;
public Menu(String id, @NotNull ConfigurationNode config) {
this.id = id;
this.id = config.node("id").getString(id);
this.config = config;
title = config.node("title").getString("chest");
rows = config.node("rows").getInt(1);
cooldown = config.node("click-cooldown").getLong(Settings.getDefaultMenuCooldown());
permissionNode = config.node("permission").getString("");
refreshRate = config.node("refresh-rate").getInt(-1);
shading = config.node("shading").getBoolean(Settings.isDefaultShading());
@@ -90,7 +98,8 @@ public class Menu {
try {
item = ItemSerializer.INSTANCE.deserialize(ItemStack.class, config.node("item"));
} catch (SerializationException e) {
throw new RuntimeException(e);
MessagesUtil.sendDebugMessages("Unable to get valid item for " + config.key().toString() + " " + e.getMessage());
continue;
}
if (item == null) {
@@ -100,8 +109,7 @@ public class Menu {
int priority = config.node("priority").getInt(1);
Type type = null;
Type type = Types.getDefaultType();
if (!config.node("type").virtual()) {
String typeId = config.node("type").getString("");
if (Types.isType(typeId)) type = Types.getType(typeId);
@@ -115,7 +123,7 @@ public class Menu {
menuItems.sort(priorityCompare);
items.put(slot, menuItems);
} else {
items.put(slot, new ArrayList<>(Arrays.asList(menuItem)));
items.put(slot, new ArrayList<>(List.of(menuItem)));
}
}
}
@@ -128,16 +136,25 @@ public class Menu {
public void openMenu(@NotNull CosmeticUser user, boolean ignorePermission) {
Player player = user.getPlayer();
if (player == null) return;
openMenu(player, user, ignorePermission);
}
public void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder) {
openMenu(viewer, cosmeticHolder, false);
}
public void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, boolean ignorePermission) {
if (!ignorePermission && !permissionNode.isEmpty()) {
if (!player.hasPermission(permissionNode) && !player.isOp()) {
MessagesUtil.sendMessage(player, "no-permission");
if (!viewer.hasPermission(permissionNode) && !viewer.isOp()) {
MessagesUtil.sendMessage(viewer, "no-permission");
return;
}
}
final Component component = AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(player, this.title));
final Component component = AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, this.title));
Gui gui = Gui.gui()
.title(component)
.rows(this.rows)
.type(GuiType.CHEST)
.inventory((title, owner, type) -> Bukkit.createInventory(owner, rows * 9, title))
.create();
gui.setDefaultClickAction(event -> event.setCancelled(true));
@@ -149,7 +166,7 @@ public class Menu {
Bukkit.getScheduler().cancelTask(taskid.get());
}
updateMenu(user, gui);
updateMenu(viewer, cosmeticHolder, gui);
};
if (refreshRate != -1) {
@@ -160,22 +177,29 @@ public class Menu {
});
gui.setCloseGuiAction(event -> {
if (cosmeticHolder instanceof CosmeticUser user) {
PlayerMenuCloseEvent closeEvent = new PlayerMenuCloseEvent(user, this, event.getReason());
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> Bukkit.getPluginManager().callEvent(closeEvent));
}
if (taskid.get() != -1) Bukkit.getScheduler().cancelTask(taskid.get());
});
// API
PlayerMenuOpenEvent event = new PlayerMenuOpenEvent(user, this);
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> Bukkit.getPluginManager().callEvent(event));
if (event.isCancelled()) return;
if (cosmeticHolder instanceof CosmeticUser user) {
PlayerMenuOpenEvent event = new PlayerMenuOpenEvent(user, this);
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> Bukkit.getPluginManager().callEvent(event));
if (event.isCancelled()) return;
}
// Internal
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
gui.open(player);
updateMenu(user, gui); // fixes shading? I know I do this twice but it's easier than writing a whole new class to deal with this shit
gui.open(viewer);
updateMenu(viewer, cosmeticHolder, gui); // fixes shading? I know I do this twice but it's easier than writing a whole new class to deal with this shit
});
}
private void updateMenu(CosmeticUser user, Gui gui) {
private void updateMenu(Player viewer, CosmeticHolder cosmeticHolder, Gui gui) {
StringBuilder title = new StringBuilder(this.title);
int row = 0;
@@ -199,15 +223,15 @@ public class Menu {
// Handles the items
List<MenuItem> menuItems = items.get(i);
MenuItem item = menuItems.get(0);
updateItem(user, gui, i);
updateItem(viewer, cosmeticHolder, gui, i);
if (item.type() instanceof TypeCosmetic) {
Cosmetic cosmetic = Cosmetics.getCosmetic(item.itemConfig().node("cosmetic").getString(""));
if (cosmetic == null) continue;
if (user.hasCosmeticInSlot(cosmetic)) {
if (cosmeticHolder.hasCosmeticInSlot(cosmetic)) {
title.append(Settings.getEquippedCosmeticColor());
} else {
if (user.canEquipCosmetic(cosmetic, true)) {
if (cosmeticHolder.canEquipCosmetic(cosmetic, true)) {
title.append(Settings.getEquipableCosmeticColor());
} else {
title.append(Settings.getLockedCosmeticColor());
@@ -223,34 +247,45 @@ public class Menu {
}
}
MessagesUtil.sendDebugMessages("Updated menu with title " + title);
gui.updateTitle(StringUtils.parseStringToString(Hooks.processPlaceholders(user.getPlayer(), title.toString())));
gui.updateTitle(AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, title.toString())));
} else {
for (int i = 0; i < gui.getInventory().getSize(); i++) {
if (items.containsKey(i)) {
updateItem(user, gui, i);
updateItem(viewer, cosmeticHolder, gui, i);
}
}
}
}
private void updateItem(CosmeticUser user, Gui gui, int slot) {
private void updateItem(Player viewer, CosmeticHolder cosmeticHolder, Gui gui, int slot) {
if (!items.containsKey(slot)) return;
List<MenuItem> menuItems = items.get(slot);
if (menuItems.isEmpty()) return;
for (MenuItem item : menuItems) {
Type type = item.type();
ItemStack modifiedItem = getMenuItem(user, type, item.itemConfig(), item.item().clone(), slot);
ItemStack modifiedItem = getMenuItem(viewer, cosmeticHolder, type, item.itemConfig(), item.item().clone(), slot);
if (modifiedItem.getType().isAir()) continue;
GuiItem guiItem = ItemBuilder.from(modifiedItem).asGuiItem();
guiItem.setAction(event -> {
MessagesUtil.sendDebugMessages("Selected slot " + slot);
UUID uuid = viewer.getUniqueId();
if (Settings.isMenuClickCooldown()) {
Long userCooldown = Menus.getCooldown(uuid);
if (userCooldown != 0 && (System.currentTimeMillis() - Menus.getCooldown(uuid) <= getCooldown())) {
MessagesUtil.sendDebugMessages("Cooldown for " + viewer.getUniqueId() + " System time: " + System.currentTimeMillis() + " Cooldown: " + Menus.getCooldown(viewer.getUniqueId()) + " Difference: " + (System.currentTimeMillis() - Menus.getCooldown(viewer.getUniqueId())));
MessagesUtil.sendMessage(viewer, "on-click-cooldown");
return;
} else {
Menus.addCooldown(uuid, System.currentTimeMillis());
}
}
MessagesUtil.sendDebugMessages("Updated Menu Item in slot number " + slot);
final ClickType clickType = event.getClick();
if (type != null) type.run(user, item.itemConfig(), clickType);
updateMenu(user, gui);
if (type != null) type.run(viewer, cosmeticHolder, item.itemConfig(), clickType);
updateMenu(viewer, cosmeticHolder, gui);
});
MessagesUtil.sendDebugMessages("Added " + slot + " as " + guiItem + " in the menu");
MessagesUtil.sendDebugMessages("Set an item in slot " + slot + " in the menu of " + getId());
gui.updateItem(slot, guiItem);
break;
}
@@ -282,11 +317,11 @@ public class Menu {
return slots;
}
@Contract("_, _, _, _, _ -> param2")
@Contract("_, _, _, _, _, _ -> param4")
@NotNull
private ItemStack getMenuItem(CosmeticUser user, Type type, ConfigurationNode config, ItemStack itemStack, int slot) {
private ItemStack getMenuItem(Player viewer, CosmeticHolder cosmeticHolder, Type type, ConfigurationNode config, ItemStack itemStack, int slot) {
if (!itemStack.hasItemMeta()) return itemStack;
return type.setItem(user, config, itemStack, slot);
return type.setItem(viewer, cosmeticHolder, config, itemStack, slot);
}
public boolean canOpen(Player player) {

View File

@@ -3,9 +3,10 @@ package com.hibiscusmc.hmccosmetics.gui;
import com.hibiscusmc.hmccosmetics.gui.type.Type;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public record MenuItem(List<Integer> slots, ItemStack item, Type type, int priority, ConfigurationNode itemConfig) {
public record MenuItem(@NotNull List<Integer> slots, @NotNull ItemStack item, Type type, int priority, ConfigurationNode itemConfig) {
}

View File

@@ -3,31 +3,33 @@ package com.hibiscusmc.hmccosmetics.gui;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.shaded.configurate.CommentedConfigurationNode;
import me.lojosho.shaded.configurate.ConfigurateException;
import me.lojosho.shaded.configurate.yaml.YamlConfigurationLoader;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Stream;
public class Menus {
private static final HashMap<String, Menu> MENUS = new HashMap<>();
private static final HashMap<UUID, Long> COOLDOWNS = new HashMap<>();
public static void addMenu(Menu menu) {
public static void addMenu(@NotNull Menu menu) {
MENUS.put(menu.getId().toUpperCase(), menu);
}
@Nullable
public static Menu getMenu(@NotNull String id) {
return MENUS.get(id.toUpperCase());
}
@@ -42,11 +44,18 @@ public class Menus {
return MENUS.containsKey(id.toUpperCase());
}
public static boolean hasMenu(Menu menu) {
public static boolean hasMenu(@NotNull Menu menu) {
return MENUS.containsValue(menu);
}
public static Menu getDefaultMenu() { return Menus.getMenu(Settings.getDefaultMenu()); }
public static boolean hasDefaultMenu() {
return MENUS.containsKey(Settings.getDefaultMenu());
}
@Nullable
public static Menu getDefaultMenu() {
return Menus.getMenu(Settings.getDefaultMenu());
}
@NotNull
public static List<String> getMenuNames() {
@@ -63,8 +72,21 @@ public class Menus {
return MENUS.values();
}
public static void addCooldown(UUID uuid, long time) {
COOLDOWNS.put(uuid, time);
}
public static Long getCooldown(UUID uuid) {
return COOLDOWNS.getOrDefault(uuid, 0L);
}
public static void removeCooldown(UUID uuid) {
COOLDOWNS.remove(uuid);
}
public static void setup() {
MENUS.clear();
COOLDOWNS.clear();
File cosmeticFolder = new File(HMCCosmeticsPlugin.getInstance().getDataFolder() + "/menus");
if (!cosmeticFolder.exists()) cosmeticFolder.mkdir();

View File

@@ -1,6 +1,8 @@
package com.hibiscusmc.hmccosmetics.gui.action;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public abstract class Action {
@@ -16,5 +18,13 @@ public abstract class Action {
return this.id;
}
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
run(CosmeticHolder.ensureSingleCosmeticUser(viewer, cosmeticHolder), raw);
}
/**
* @deprecated Override {@link #run(Player, CosmeticHolder, String)} instead.
*/
@Deprecated
public abstract void run(CosmeticUser user, String raw);
}

View File

@@ -1,13 +1,16 @@
package com.hibiscusmc.hmccosmetics.gui.action;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.actions.*;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
@SuppressWarnings("unused")
public class Actions {
@@ -28,7 +31,6 @@ public class Actions {
private static final ActionCosmeticHide ACTION_HIDE = new ActionCosmeticHide();
private static final ActionCosmeticToggle ACTION_TOGGLE = new ActionCosmeticToggle();
public static Action getAction(@NotNull String id) {
return actions.get(id.toUpperCase());
}
@@ -41,16 +43,20 @@ public class Actions {
actions.put(action.getId().toUpperCase(), action);
}
public static void runActions(CosmeticUser user, @NotNull List<String> raw) {
public static void runActions(Player viewer, CosmeticHolder cosmeticHolder, @NotNull List<String> raw) {
for (String a : raw) {
String id = StringUtils.substringBetween(a, "[", "]").toUpperCase();
String id = StringUtils.substringBetween(a, "[", "]");
String message = StringUtils.substringAfter(a, "] ");
MessagesUtil.sendDebugMessages("ID is " + id + " // Raw Data is " + message);
if (isAction(id)) {
getAction(id).run(user, message);
if (id != null && isAction(id.toUpperCase())) {
getAction(id).run(viewer, cosmeticHolder, message);
} else {
MessagesUtil.sendDebugMessages("Possible ids: " + actions.keySet());
MessagesUtil.sendDebugMessages("Invalid Action ID (" + id + ") used in menus (Full raw: '" + a + "'). Make sure all actions are properly typed out. Here are all possible actions: " + actions.keySet(), Level.WARNING);
}
}
}
public static void runActions(CosmeticUser user, @NotNull List<String> raw) {
runActions(user.getPlayer(), user, raw);
}
}

View File

@@ -1,7 +1,9 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionCloseMenu extends Action {
@@ -10,8 +12,13 @@ public class ActionCloseMenu extends Action {
super("close");
}
@Override
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
viewer.closeInventory();
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
user.getPlayer().closeInventory();
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,10 +1,12 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionConsoleCommand extends Action {
@@ -13,8 +15,15 @@ public class ActionConsoleCommand extends Action {
super("console-command");
}
@Override
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
// todo: some of these generalizations may require more specific implementations, for example,
// todo: what if we wanted to execute console commands only for the cosmetic holder?
HMCCosmeticsPlugin.getInstance().getServer().dispatchCommand(Bukkit.getConsoleSender(), Hooks.processPlaceholders(viewer, raw));
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
HMCCosmeticsPlugin.getInstance().getServer().dispatchCommand(Bukkit.getConsoleSender(), Hooks.processPlaceholders(user.getPlayer(), raw));
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,7 +1,9 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionCosmeticHide extends Action {
@@ -11,8 +13,14 @@ public class ActionCosmeticHide extends Action {
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
if (!(cosmeticHolder instanceof CosmeticUser user)) return;
if (user.isHidden()) return;
user.hideCosmetics(CosmeticUser.HiddenReason.ACTION);
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,7 +1,9 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionCosmeticShow extends Action {
@@ -11,11 +13,17 @@ public class ActionCosmeticShow extends Action {
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
if (!(cosmeticHolder instanceof CosmeticUser user)) return;
if (!user.isHidden()) return;
// Do not hide if it's already off for WG
if (!user.isHidden(CosmeticUser.HiddenReason.ACTION) && !user.isHidden(CosmeticUser.HiddenReason.COMMAND)) return;
user.showCosmetics(CosmeticUser.HiddenReason.ACTION);
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,7 +1,9 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionCosmeticToggle extends Action {
@@ -11,7 +13,8 @@ public class ActionCosmeticToggle extends Action {
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
if (!(cosmeticHolder instanceof CosmeticUser user)) return;
if (user.isHidden()) {
if (!user.isHidden(CosmeticUser.HiddenReason.ACTION) && !user.isHidden(CosmeticUser.HiddenReason.COMMAND)) return;
user.showCosmetics(CosmeticUser.HiddenReason.ACTION);
@@ -20,4 +23,9 @@ public class ActionCosmeticToggle extends Action {
user.hideCosmetics(CosmeticUser.HiddenReason.ACTION);
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,9 +1,11 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.entity.Player;
public class ActionEquip extends Action {
@@ -12,10 +14,15 @@ public class ActionEquip extends Action {
}
@Override
public void run(CosmeticUser user, String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
Cosmetic cosmetic = Cosmetics.getCosmetic(raw);
if (cosmetic == null) return;
user.addPlayerCosmetic(cosmetic);
cosmeticHolder.addCosmetic(cosmetic);
}
@Override
public void run(CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,10 +1,12 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.bukkit.entity.Player;
import java.util.logging.Level;
@@ -15,7 +17,7 @@ public class ActionMenu extends Action {
}
@Override
public void run(CosmeticUser user, String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
boolean ignorePermission = false;
raw = raw.replaceAll(" ", ""); // Removes all spaces
@@ -32,6 +34,11 @@ public class ActionMenu extends Action {
Menu menu = Menus.getMenu(raw);
MessagesUtil.sendDebugMessages(raw + " | " + ignorePermission);
menu.openMenu(user, ignorePermission);
menu.openMenu(viewer, cosmeticHolder, ignorePermission);
}
@Override
public void run(CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,8 +1,10 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionMessage extends Action {
@@ -11,8 +13,13 @@ public class ActionMessage extends Action {
super("message");
}
@Override
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
MessagesUtil.sendMessageNoKey(viewer, raw);
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
MessagesUtil.sendMessageNoKey(user.getPlayer(), raw);
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,5 +1,6 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -24,7 +25,7 @@ public class ActionParticle extends Action {
@Override
@SuppressWarnings("ConstantConditions")
public void run(CosmeticUser user, @NotNull String raw) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
String[] rawString = raw.split(" ");
ParticleType<?, ?> particleType = Particles.fromKey(NamespacedKey.minecraft(rawString[0].toLowerCase()));
if (particleType == null) {
@@ -43,9 +44,14 @@ public class ActionParticle extends Action {
}
particle = HMCCServerUtils.addParticleValues(particle, rawString);
Location location = user.getPlayer().getLocation();
Location location = viewer.getLocation();
for (Player player : HMCCPacketManager.getViewers(location)) {
particle.compile().send(player, location);
}
}
@Override
public void run(CosmeticUser user, @NotNull String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,9 +1,11 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ActionPlayerCommand extends Action {
@@ -12,8 +14,14 @@ public class ActionPlayerCommand extends Action {
super("player-command");
}
@Override
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
// todo: what if we wanted the cosmetic holder to execute the command instead
viewer.performCommand(MessagesUtil.processStringNoKeyString(viewer, Hooks.processPlaceholders(viewer, raw)));
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
user.getPlayer().performCommand(MessagesUtil.processStringNoKeyString(user.getPlayer(), Hooks.processPlaceholders(user.getPlayer(), raw)));
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,5 +1,6 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -16,8 +17,7 @@ public class ActionSound extends Action {
}
@Override
public void run(@NotNull CosmeticUser user, @NotNull String raw) {
Player player = user.getPlayer();
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
String[] processedString = raw.split(" ");
String soundName = processedString[0];
@@ -31,6 +31,11 @@ public class ActionSound extends Action {
MessagesUtil.sendDebugMessages("Attempting to play " + soundName, Level.INFO);
player.playSound(player.getLocation(), soundName, volume, pitch);
viewer.playSound(viewer.getLocation(), soundName, volume, pitch);
}
@Override
public void run(@NotNull CosmeticUser user, @NotNull String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -1,9 +1,10 @@
package com.hibiscusmc.hmccosmetics.gui.action.actions;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.gui.action.Action;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.entity.Player;
public class ActionUnequip extends Action {
@@ -12,10 +13,15 @@ public class ActionUnequip extends Action {
}
@Override
public void run(CosmeticUser user, String raw) {
if (!EnumUtils.isValidEnum(CosmeticSlot.class, raw)) return;
public void run(Player viewer, CosmeticHolder cosmeticHolder, String raw) {
if (!CosmeticSlot.contains(raw)) return;
CosmeticSlot slot = CosmeticSlot.valueOf(raw);
user.removeCosmeticSlot(slot);
cosmeticHolder.removeCosmeticSlot(slot);
}
@Override
public void run(CosmeticUser user, String raw) {
run(user.getPlayer(), user, raw);
}
}

View File

@@ -6,64 +6,62 @@ import com.hibiscusmc.hmccolor.shaded.gui.guis.GuiItem;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.AdventureUtils;
import me.lojosho.hibiscuscommons.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DyeMenu {
public static void openMenu(@NotNull CosmeticUser user, Cosmetic cosmetic) {
Player player = user.getPlayer();
if (player == null) return;
public static void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, Cosmetic cosmetic) {
if (!Hooks.isActiveHook("HMCColor")) {
addCosmetic(user, cosmetic, null);
addCosmetic(viewer, cosmeticHolder, cosmetic, null);
return;
}
ItemStack originalItem = user.getUserCosmeticItem(cosmetic);
if (originalItem == null || !cosmetic.isDyable()) return;
ItemStack originalItem = cosmetic.getItem();
if (originalItem == null || !cosmetic.isDyeable()) return;
Gui gui = HMCColorApi.createColorMenu(player);
gui.updateTitle(Hooks.processPlaceholders(player, StringUtils.parseStringToString(Settings.getDyeMenuName())));
Gui gui = HMCColorApi.createColorMenu(viewer);
gui.updateTitle(AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, Settings.getDyeMenuName())));
gui.setItem(Settings.getDyeMenuInputSlot(), new GuiItem(originalItem));
gui.setDefaultTopClickAction(event -> {
if (event.getSlot() == Settings.getDyeMenuOutputSlot()) {
ItemStack item = event.getInventory().getItem(Settings.getDyeMenuOutputSlot());
if (item == null) return;
ItemMeta meta = item.getItemMeta();
if (meta == null) return;
Color color = meta instanceof LeatherArmorMeta leatherMeta ? leatherMeta.getColor() :
meta instanceof PotionMeta potionMeta ? potionMeta.getColor() :
meta instanceof MapMeta mapMeta ? mapMeta.getColor() : null;
Color color = NMSHandlers.getHandler().getUtilHandler().getColor(item);
if (color == null) return;
addCosmetic(user, cosmetic, color);
addCosmetic(viewer, cosmeticHolder, cosmetic, color);
event.setCancelled(true);
} else event.setCancelled(true);
});
gui.setPlayerInventoryAction(event -> event.setCancelled(true));
gui.setCloseGuiAction(event -> {});
gui.open(player);
gui.open(viewer);
}
private static void addCosmetic(@NotNull CosmeticUser user, Cosmetic cosmetic, Color color) {
public static void openMenu(@NotNull CosmeticUser user, Cosmetic cosmetic) {
Player player = user.getPlayer();
user.addPlayerCosmetic(cosmetic, color);
player.setItemOnCursor(new ItemStack(Material.AIR));
if (player == null) return;
openMenu(player, user, cosmetic);
}
private static void addCosmetic(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic, @Nullable Color color) {
cosmeticHolder.addCosmetic(cosmetic, color);
viewer.setItemOnCursor(new ItemStack(Material.AIR));
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
player.closeInventory();
user.updateCosmetic(cosmetic.getSlot());
viewer.closeInventory();
cosmeticHolder.updateCosmetic(cosmetic.getSlot());
}, 2);
}
}

View File

@@ -1,9 +1,23 @@
package com.hibiscusmc.hmccosmetics.gui.type;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.shaded.configurate.ConfigurationNode;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public abstract class Type {
@@ -18,11 +32,87 @@ public abstract class Type {
return this.id;
}
public void run(CosmeticUser user, ConfigurationNode config) {
run(user, config, null);
public void run(Player viewer, CosmeticHolder cosmeticHolder, ConfigurationNode config) {
run(viewer, cosmeticHolder, config, null);
}
public void run(Player viewer, CosmeticHolder cosmeticHolder, ConfigurationNode config, ClickType clickType) {
run(CosmeticHolder.ensureSingleCosmeticUser(viewer, cosmeticHolder), config, clickType);
}
public void run(CosmeticUser user, ConfigurationNode config) {
final var player = user.getPlayer();
if (player == null) return;
run(player, user, config, null);
}
/**
* @deprecated Override {@link #run(Player, CosmeticHolder, ConfigurationNode, ClickType)} instead.
*/
@Deprecated
public abstract void run(CosmeticUser user, ConfigurationNode config, ClickType clickType);
public ItemStack setItem(Player viewer, CosmeticHolder cosmeticHolder, ConfigurationNode config, ItemStack itemStack, int slot) {
return setItem(CosmeticHolder.ensureSingleCosmeticUser(viewer, cosmeticHolder), config, itemStack, slot);
}
/**
* @deprecated Override {@link #setItem(Player, CosmeticHolder, ConfigurationNode, ItemStack, int)} instead.
*/
public abstract ItemStack setItem(CosmeticUser user, ConfigurationNode config, ItemStack itemStack, int slot);
@Contract("_, _ -> param2")
@NotNull
@SuppressWarnings("Duplicates")
protected ItemMeta processItemMeta(Player viewer, @NotNull ItemMeta itemMeta) {
// New implementation - Paper and forks
// I know this is a kinda batshit way to do it (with serializing and deserializing MiniMessage)
// But currently I can't think of another good way of doing it without a big refactor. I'll come back to this
// At a later date.
if (HibiscusCommonsPlugin.isOnPaper()) {
List<Component> processedLore = new ArrayList<>();
if (itemMeta.hasDisplayName()) {
String displayName = MiniMessage.miniMessage().serialize(itemMeta.displayName());
displayName = Hooks.processPlaceholders(viewer, displayName);
itemMeta.displayName(MiniMessage.miniMessage().deserialize(displayName).decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE));
}
if (itemMeta.hasLore()) {
for (Component loreLine : itemMeta.lore()) {
String loreStringLine = MiniMessage.miniMessage().serialize(loreLine);
loreStringLine = Hooks.processPlaceholders(viewer, loreStringLine);
processedLore.add(MiniMessage.miniMessage().deserialize(loreStringLine).decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE));
}
}
if (itemMeta instanceof SkullMeta skullMeta) {
if (skullMeta.hasOwner() && skullMeta.getOwner() != null) {
skullMeta.setOwner(Hooks.processPlaceholders(viewer, skullMeta.getOwner()));
}
}
itemMeta.lore(processedLore);
} else {
// Legacy implementation - Spigot
List<String> processedLore = new ArrayList<>();
if (itemMeta.hasDisplayName()) {
itemMeta.setDisplayName(Hooks.processPlaceholders(viewer, itemMeta.getDisplayName()));
}
if (itemMeta.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
processedLore.add(Hooks.processPlaceholders(viewer, loreLine));
}
}
if (itemMeta instanceof SkullMeta skullMeta) {
if (skullMeta.hasOwner() && skullMeta.getOwner() != null) {
skullMeta.setOwner(Hooks.processPlaceholders(viewer, skullMeta.getOwner()));
}
}
itemMeta.setLore(processedLore);
}
return itemMeta;
}
}

View File

@@ -10,18 +10,43 @@ public class Types {
private static final HashMap<String, Type> types = new HashMap<>();
private static TypeCosmetic TYPE_COSMETIC = new TypeCosmetic();
private static TypeEmpty TYPE_EMPTY = new TypeEmpty();
private static final TypeCosmetic TYPE_COSMETIC = new TypeCosmetic();
private static final TypeEmpty TYPE_EMPTY = new TypeEmpty();
/**
* Get's a Menu Item type. Add custom menu item types with {@link #addType(Type)}
* @param id A non-case sensitive ID
* @return The type of Menu Item
*/
public static Type getType(@NotNull String id) {
return types.get(id.toUpperCase());
}
/**
* Checks if a type is valid. Add custom menu item types with {@link #addType(Type)}
* @param id A non-case sensitive ID
* @return True if exists, False if not.
*/
public static boolean isType(@NotNull String id) {
return types.containsKey(id.toUpperCase());
}
public static void addType(Type type) {
types.put(type.getId().toUpperCase(), type);
/**
* Adds a Menu Item Type to the types HashMap for reference. Menu Types will automatically be added using this method.
* @param type A non-null {@link Type} that'll be added. ID should be unique; can't be duplicated
*/
public static boolean addType(@NotNull Type type) {
String id = type.getId().toUpperCase();
if (types.containsKey(id)) return false;
types.put(id, type);
return true;
}
/**
* Gets the default menu item; {@link TypeEmpty}
* @return The empty menu type.
*/
public static TypeEmpty getDefaultType() {
return TYPE_EMPTY;
}
}

View File

@@ -3,6 +3,7 @@ package com.hibiscusmc.hmccosmetics.gui.type.types;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.gui.action.Actions;
@@ -19,9 +20,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -38,7 +36,7 @@ public class TypeCosmetic extends Type {
}
@Override
public void run(CosmeticUser user, @NotNull ConfigurationNode config, ClickType clickType) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, ConfigurationNode config, ClickType clickType) {
MessagesUtil.sendDebugMessages("Running Cosmetic Click Type");
if (config.node("cosmetic").virtual()) {
MessagesUtil.sendDebugMessages("Cosmetic Config Field Virtual");
@@ -46,32 +44,33 @@ public class TypeCosmetic extends Type {
}
String cosmeticName = config.node("cosmetic").getString();
Cosmetic cosmetic = Cosmetics.getCosmetic(cosmeticName);
Player player = user.getPlayer();
if (cosmetic == null) {
MessagesUtil.sendDebugMessages("No Cosmetic Found");
MessagesUtil.sendMessage(player, "invalid-cosmetic");
MessagesUtil.sendMessage(viewer, "invalid-cosmetic");
return;
}
if (!user.canEquipCosmetic(cosmetic)) {
if (!cosmeticHolder.canEquipCosmetic(cosmetic)) {
MessagesUtil.sendDebugMessages("No Cosmetic Permission");
MessagesUtil.sendMessage(player, "no-cosmetic-permission");
MessagesUtil.sendMessage(viewer, "no-cosmetic-permission");
return;
}
boolean isUnEquippingCosmetic = false;
if (user.getCosmetic(cosmetic.getSlot()) == cosmetic) isUnEquippingCosmetic = true;
if (cosmeticHolder.getCosmetic(cosmetic.getSlot()) == cosmetic) isUnEquippingCosmetic = true;
String dyeClick = Settings.getCosmeticDyeClickType();
String requiredClick;
if (isUnEquippingCosmetic) requiredClick = Settings.getCosmeticUnEquipClickType();
else requiredClick = Settings.getCosmeticEquipClickType();
MessagesUtil.sendDebugMessages("Required click type: " + requiredClick);
MessagesUtil.sendDebugMessages("Click type: " + clickType.name());
if (!requiredClick.equalsIgnoreCase("ANY") && !requiredClick.equalsIgnoreCase(clickType.name())) {
MessagesUtil.sendMessage(user.getPlayer(), "invalid-click-type");
return;
}
final boolean isRequiredClick = requiredClick.equalsIgnoreCase("ANY") || requiredClick.equalsIgnoreCase(clickType.name());
final boolean isDyeClick = dyeClick.equalsIgnoreCase("ANY") || dyeClick.equalsIgnoreCase(clickType.name());
if (!isRequiredClick) isUnEquippingCosmetic = false;
List<String> actionStrings = new ArrayList<>();
ConfigurationNode actionConfig = config.node("actions");
@@ -99,25 +98,25 @@ public class TypeCosmetic extends Type {
if (isUnEquippingCosmetic) {
if (!actionConfig.node("on-unequip").virtual()) actionStrings.addAll(actionConfig.node("on-unequip").getList(String.class));
MessagesUtil.sendDebugMessages("on-unequip");
user.removeCosmeticSlot(cosmetic);
cosmeticHolder.removeCosmeticSlot(cosmetic);
} else {
if (!actionConfig.node("on-equip").virtual()) actionStrings.addAll(actionConfig.node("on-equip").getList(String.class));
MessagesUtil.sendDebugMessages("on-equip");
// TODO: Redo this
if (cosmetic.isDyable() && Hooks.isActiveHook("HMCColor")) {
DyeMenu.openMenu(user, cosmetic);
} else {
user.addPlayerCosmetic(cosmetic);
if (cosmetic.isDyeable() && isDyeClick && Hooks.isActiveHook("HMCColor")) {
DyeMenu.openMenu(viewer, cosmeticHolder, cosmetic);
} else if (isRequiredClick) {
cosmeticHolder.addCosmetic(cosmetic);
}
}
Actions.runActions(user, actionStrings);
Actions.runActions(viewer, cosmeticHolder, actionStrings);
} catch (SerializationException e) {
e.printStackTrace();
}
// Fixes issue with offhand cosmetics not appearing. Yes, I know this is dumb
Runnable run = () -> user.updateCosmetic(cosmetic.getSlot());
Runnable run = () -> cosmeticHolder.updateCosmetic(cosmetic.getSlot());
if (cosmetic instanceof CosmeticArmorType) {
if (((CosmeticArmorType) cosmetic).getEquipSlot().equals(EquipmentSlot.OFF_HAND)) {
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), run, 1);
@@ -128,8 +127,19 @@ public class TypeCosmetic extends Type {
}
@Override
public ItemStack setItem(CosmeticUser user, @NotNull ConfigurationNode config, ItemStack itemStack, int slot) {
itemStack.setItemMeta(processLoreLines(user, itemStack.getItemMeta()));
public void run(CosmeticUser user, @NotNull ConfigurationNode config, ClickType clickType) {
run(user.getPlayer(), user, config, clickType);
}
@Override
public ItemStack setItem(CosmeticUser user, ConfigurationNode config, ItemStack itemStack, int slot) {
return setItem(user.getPlayer(), user, config, itemStack, slot);
}
@Override
public ItemStack setItem(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull ConfigurationNode config, @NotNull ItemStack itemStack, int slot) {
if (itemStack.hasItemMeta()) itemStack.setItemMeta(processItemMeta(viewer, itemStack.getItemMeta()));
else MessagesUtil.sendDebugMessages("ItemStack has no ItemMeta?");
if (config.node("cosmetic").virtual()) {
return itemStack;
@@ -140,9 +150,9 @@ public class TypeCosmetic extends Type {
return itemStack;
}
if (user.hasCosmeticInSlot(cosmetic) && !config.node("equipped-item").virtual()) {
if (cosmeticHolder.hasCosmeticInSlot(cosmetic) && (!config.node("equipped-item").virtual() || !config.node("locked-equipped-item").virtual())) {
MessagesUtil.sendDebugMessages("GUI Equipped Item");
ConfigurationNode equippedItem = config.node("equipped-item");
ConfigurationNode equippedItem = config.node(cosmeticHolder.canEquipCosmetic(cosmetic, true) && !config.node("equipped-item").virtual() ? "equipped-item" : "locked-equipped-item");
try {
if (equippedItem.node("material").virtual()) equippedItem.node("material").set(config.node("item", "material").getString());
} catch (SerializationException e) {
@@ -153,11 +163,12 @@ public class TypeCosmetic extends Type {
} catch (SerializationException e) {
throw new RuntimeException(e);
}
itemStack.setItemMeta(processLoreLines(user, itemStack.getItemMeta()));
if (itemStack.hasItemMeta()) itemStack.setItemMeta(processItemMeta(viewer, itemStack.getItemMeta()));
else MessagesUtil.sendDebugMessages("ItemStack has no ItemMeta in equipped item?");
return itemStack;
}
if (!user.canEquipCosmetic(cosmetic, true) && !config.node("locked-item").virtual()) {
if (!cosmeticHolder.canEquipCosmetic(cosmetic, true) && !config.node("locked-item").virtual()) {
MessagesUtil.sendDebugMessages("GUI Locked Item");
ConfigurationNode lockedItem = config.node("locked-item");
try {
@@ -170,34 +181,10 @@ public class TypeCosmetic extends Type {
} catch (SerializationException e) {
throw new RuntimeException(e);
}
itemStack.setItemMeta(processLoreLines(user, itemStack.getItemMeta()));
if (itemStack.hasItemMeta()) itemStack.setItemMeta(processItemMeta(viewer, itemStack.getItemMeta()));
else MessagesUtil.sendDebugMessages("ItemStack has no ItemMeta in locked item?");
return itemStack;
}
return itemStack;
}
@Contract("_, _ -> param2")
@NotNull
@SuppressWarnings("Duplicates")
private ItemMeta processLoreLines(CosmeticUser user, @NotNull ItemMeta itemMeta) {
List<String> processedLore = new ArrayList<>();
if (itemMeta.hasDisplayName()) {
itemMeta.setDisplayName(Hooks.processPlaceholders(user.getPlayer(), itemMeta.getDisplayName()));
}
if (itemMeta.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
processedLore.add(Hooks.processPlaceholders(user.getPlayer(), loreLine));
}
}
if (itemMeta instanceof SkullMeta skullMeta) {
if (skullMeta.hasOwner()) {
skullMeta.setOwner(Hooks.processPlaceholders(user.getPlayer(), skullMeta.getOwner()));
}
}
itemMeta.setLore(processedLore);
return itemMeta;
}
}

View File

@@ -1,15 +1,15 @@
package com.hibiscusmc.hmccosmetics.gui.type.types;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.action.Actions;
import com.hibiscusmc.hmccosmetics.gui.type.Type;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -23,9 +23,10 @@ public class TypeEmpty extends Type {
// This is an empty type, meaning, when a menu item has a type of "empty" it will run the code in the method run.
}
// This is the code that's run when the item is clicked.
// This is the code that's run when the item is clicked. The item is clicked by the "viewer" player in a menu for the
// given "cosmeticHolder". They're the same player by default, but it's not guaranteed.
@Override
public void run(CosmeticUser user, @NotNull ConfigurationNode config, ClickType clickType) {
public void run(Player viewer, CosmeticHolder cosmeticHolder, @NotNull ConfigurationNode config, ClickType clickType) {
List<String> actionStrings = new ArrayList<>(); // List where we keep the actions the server will execute.
ConfigurationNode actionConfig = config.node("actions"); // Configuration node that actions are under.
@@ -52,36 +53,32 @@ public class TypeEmpty extends Type {
}
// We run the actions once we got the raw strings from the config.
Actions.runActions(user, actionStrings);
Actions.runActions(viewer, cosmeticHolder, actionStrings);
} catch (SerializationException e) {
throw new RuntimeException(e);
}
}
// backward-compatibility method, will not be required in the future
@Override
public void run(CosmeticUser user, ConfigurationNode config, ClickType clickType) {
final var player = user.getPlayer();
if (player == null) return;
run(player, user, config, clickType);
}
// backward-compatibility method, will not be required in the future
@Override
public ItemStack setItem(CosmeticUser user, ConfigurationNode config, ItemStack itemStack, int slot) {
return setItem(user.getPlayer(), user, config, itemStack, slot);
}
@Override
@SuppressWarnings("Duplicates")
public ItemStack setItem(CosmeticUser user, ConfigurationNode config, @NotNull ItemStack itemStack, int slot) {
List<String> processedLore = new ArrayList<>();
public ItemStack setItem(Player viewer, CosmeticHolder cosmeticHolder, ConfigurationNode config, @NotNull ItemStack itemStack, int slot) {
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta.hasDisplayName()) {
itemMeta.setDisplayName(Hooks.processPlaceholders(user.getPlayer(), itemMeta.getDisplayName()));
}
if (itemMeta.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
processedLore.add(Hooks.processPlaceholders(user.getPlayer(), loreLine));
}
}
if (itemMeta instanceof SkullMeta skullMeta) {
if (skullMeta.hasOwner()) {
skullMeta.setOwner(Hooks.processPlaceholders(user.getPlayer(), skullMeta.getOwner()));
}
}
itemMeta.setLore(processedLore);
itemStack.setItemMeta(itemMeta);
itemStack.setItemMeta(processItemMeta(viewer, itemMeta));
return itemStack;
}

View File

@@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
public class HookHMCCosmetics extends Hook {
public HookHMCCosmetics() {
super("HMCCosmetics", HookFlag.ITEM_SUPPORT);
setActive(true);
}
/**
@@ -24,5 +25,4 @@ public class HookHMCCosmetics extends Hook {
if (cosmetic == null) return null;
return cosmetic.getItem();
}
}
}

View File

@@ -0,0 +1,39 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.hibiscusmc.hmccosmetics.api.events.PlayerWardrobeEnterEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerWardrobeLeaveEvent;
import com.hibiscusmc.hmccosmetics.config.Settings;
import kr.toxicity.hud.api.BetterHud;
import kr.toxicity.hud.api.player.HudPlayer;
import me.lojosho.hibiscuscommons.hooks.Hook;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class HookBetterHud extends Hook {
public HookBetterHud() {
super("BetterHUD");
setActive(true);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerEnterWardrobe(@NotNull PlayerWardrobeEnterEvent event) {
if (!Settings.isWardrobeHideHud()) return;
UUID uuid = event.getUniqueId();
HudPlayer hudPlayer = BetterHud.getInstance().getPlayerManager().getHudPlayer(uuid);
if (hudPlayer == null) return;
hudPlayer.setHudEnabled(false);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerLeaveWardrobe(@NotNull PlayerWardrobeLeaveEvent event) {
if (!Settings.isWardrobeHideHud()) return;
UUID uuid = event.getUniqueId();
HudPlayer hudPlayer = BetterHud.getInstance().getPlayerManager().getHudPlayer(uuid);
if (hudPlayer == null) return;
hudPlayer.setHudEnabled(true);
}
}

View File

@@ -122,7 +122,8 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
if (placeholderArgs.size() >= 2) {
String args1 = placeholderArgs.get(1);
if (EnumUtils.isValidEnum(CosmeticSlot.class, args1.toUpperCase())) {
String rawSlot = args1.toUpperCase();
if (CosmeticSlot.contains(rawSlot)) {
return TranslationUtil.getTranslation("equipped-cosmetic", String.valueOf(user.getCosmetic(CosmeticSlot.valueOf(args1.toUpperCase())) != null));
}
@@ -150,7 +151,7 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
if (placeholderArgs.size() >= 2) {
String args1 = placeholderArgs.get(1).toUpperCase(); // changes offhand to OFFHAND
if (!EnumUtils.isValidEnum(CosmeticSlot.class, args1)) return null;
if (!CosmeticSlot.contains(args1)) return null;
CosmeticSlot slot = CosmeticSlot.valueOf(args1);
int amount = 0;
@@ -167,6 +168,8 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
} else {
return TranslationUtil.getTranslation("amount-cosmetic", String.valueOf(Cosmetics.values().size()));
}
case "hidden":
return TranslationUtil.getTranslation("hidden", String.valueOf(user.isHidden()));
case "wardrobe-enabled":
return TranslationUtil.getTranslation("in-wardrobe", String.valueOf(user.isInWardrobe()));
}

View File

@@ -1,6 +1,5 @@
package com.hibiscusmc.hmccosmetics.hooks.worldguard;
import com.hibiscusmc.hmccosmetics.api.events.PlayerEmoteStartEvent;
import com.hibiscusmc.hmccosmetics.config.Wardrobe;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
@@ -8,6 +7,7 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import com.sk89q.worldguard.protection.regions.RegionQuery;
@@ -20,34 +20,45 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Contains {@link com.sk89q.worldguard.WorldGuard WorldGuard} related event listeners
*/
public class WGListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerMove(@NotNull PlayerMoveEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
Player player = event.getPlayer();
Location from = event.getFrom();
Location to = event.getTo();
if (from.getBlockX() == to.getBlockX() && from.getBlockY() == to.getBlockY() && from.getBlockZ() == to.getBlockZ()) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
Location location = event.getPlayer().getLocation();
Location location = player.getLocation();
ApplicableRegionSet set = getRegions(location);
if (user.isHidden()) {
if (set.getRegions().isEmpty()) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
if (user.isHidden() && set.getRegions().isEmpty()) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
Set<String> wardrobeNames = WardrobeSettings.getWardrobeNames();
for (ProtectedRegion protectedRegion : set.getRegions()) {
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticEnableFlag())) {
if (protectedRegion.getFlags().get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
Map<Flag<?>, Object> flags = protectedRegion.getFlags();
if (flags.containsKey(WGHook.getCosmeticEnableFlag())) {
if (flags.get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
return;
} else {
user.hideCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
user.hideCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
return;
}
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticWardrobeFlag())) {
if (!WardrobeSettings.getWardrobeNames().contains(protectedRegion.getFlags().get(WGHook.getCosmeticWardrobeFlag()).toString())) return;
Wardrobe wardrobe = WardrobeSettings.getWardrobe(protectedRegion.getFlags().get(WGHook.getCosmeticWardrobeFlag()).toString());
user.enterWardrobe(true, wardrobe);
if (flags.containsKey(WGHook.getCosmeticWardrobeFlag())) {
String wardrobeName = flags.getOrDefault(WGHook.getCosmeticWardrobeFlag(), "").toString();
if (wardrobeName.isEmpty() || !wardrobeNames.contains(wardrobeName)) return;
Wardrobe wardrobe = WardrobeSettings.getWardrobe(wardrobeName);
if (wardrobe == null) return;
user.enterWardrobe(wardrobe, true);
}
}
}
@@ -75,24 +86,7 @@ public class WGListener implements Listener {
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticWardrobeFlag())) {
if (!WardrobeSettings.getWardrobeNames().contains(protectedRegion.getFlags().get(WGHook.getCosmeticWardrobeFlag()).toString())) return;
Wardrobe wardrobe = WardrobeSettings.getWardrobe(protectedRegion.getFlags().get(WGHook.getCosmeticWardrobeFlag()).toString());
user.enterWardrobe(true, wardrobe);
}
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerEmote(PlayerEmoteStartEvent event) {
Player player = event.getUser().getPlayer();
if (player == null) return;
Location location = player.getLocation();
ApplicableRegionSet set = getRegions(location);
for (ProtectedRegion protectedRegion : set.getRegions()) {
if (protectedRegion.getFlags().containsKey(WGHook.getEmotesEnableFlag())) {
if (protectedRegion.getFlags().get(WGHook.getEmotesEnableFlag()).toString().equalsIgnoreCase("DENY")) {
event.setCancelled(true);
return;
}
return;
user.enterWardrobe(wardrobe, true);
}
}
}

View File

@@ -1,15 +1,17 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
public class PaperPlayerGameListener implements Listener {
@EventHandler
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerArmorEquip(PlayerArmorChangeEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
@@ -17,6 +19,14 @@ public class PaperPlayerGameListener implements Listener {
user.updateCosmetic(slotTypeToCosmeticType(event.getSlotType()));
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerRespawn(PlayerPostRespawnEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
if (user.isInWardrobe()) return;
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) user.respawnBackpack();
}
private CosmeticSlot slotTypeToCosmeticType(PlayerArmorChangeEvent.SlotType slotType) {
return switch (slotType) {
case HEAD -> CosmeticSlot.HELMET;

View File

@@ -1,14 +1,18 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.PlayerLoadEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerPreLoadEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerPreUnloadEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerUnloadEvent;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -16,57 +20,92 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerConnectionListener implements Listener {
import java.util.UUID;
public class PlayerConnectionListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(@NotNull PlayerJoinEvent event) {
if (event.getPlayer().isOp() || event.getPlayer().hasPermission("hmccosmetics.notifyupdate")) {
if (!HMCCosmeticsPlugin.getInstance().getLatestVersion().equalsIgnoreCase(HMCCosmeticsPlugin.getInstance().getDescription().getVersion()) && HMCCosmeticsPlugin.getInstance().getLatestVersion().isEmpty())
MessagesUtil.sendMessageNoKey(
event.getPlayer(),
"<br>" +
"<GRAY>There is a new version of <light_purple><Bold>HMCCosmetics<reset><gray> available!<br>" +
"<GRAY>Current version: <red>" + HMCCosmeticsPlugin.getInstance().getDescription().getVersion() + " <GRAY>| Latest version: <light_purple>" + HMCCosmeticsPlugin.getInstance().getLatestVersion() + "<br>" +
"<GRAY>Download it on <gold><click:OPEN_URL:'https://www.spigotmc.org/resources/100107/'>Spigot<reset> <gray>or <gold><click:OPEN_URL:'https://polymart.org/resource/1879'>Polymart<reset><gray>!" +
"<br>"
);
}
Runnable run = () -> {
if (!event.getPlayer().isOnline()) return; // If a player is no longer online, don't run this.
CosmeticUser user = Database.get(event.getPlayer().getUniqueId());
CosmeticUsers.addUser(user);
MessagesUtil.sendDebugMessages("Run User Join");
// And finally, launch an update for the cosmetics they have.
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (user.getPlayer() == null) return;
user.updateCosmetic();
}, 4);
};
if (DatabaseSettings.isEnabledDelay()) {
MessagesUtil.sendDebugMessages("Delay Enabled with " + DatabaseSettings.getDelayLength() + " ticks");
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), run, DatabaseSettings.getDelayLength());
Bukkit.getScheduler().runTaskLater(
HMCCosmeticsPlugin.getInstance(),
() -> this.loadUserData(event.getPlayer()),
DatabaseSettings.getDelayLength()
);
} else {
run.run();
this.loadUserData(event.getPlayer());
}
}
private void loadUserData(final Player player) {
if(!player.isOnline()) return;
final UUID playerId = player.getUniqueId();
PlayerPreLoadEvent preLoadEvent = new PlayerPreLoadEvent(playerId);
Bukkit.getPluginManager().callEvent(preLoadEvent);
if (preLoadEvent.isCancelled()) return;
Database.get(playerId).thenAccept(userData -> {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
CosmeticUser cosmeticUser = CosmeticUsers.getProvider()
.createCosmeticUser(playerId)
.initialize(userData);
cosmeticUser.startTicking();
CosmeticUsers.addUser(cosmeticUser);
MessagesUtil.sendDebugMessages("Run User Join for " + playerId);
PlayerLoadEvent playerLoadEvent = new PlayerLoadEvent(cosmeticUser);
Bukkit.getPluginManager().callEvent(playerLoadEvent);
// And finally, launch an update for the cosmetics they have.
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (cosmeticUser.getPlayer() == null) return;
cosmeticUser.updateCosmetic();
}, 4);
});
}).exceptionally(ex -> {
MessagesUtil.sendDebugMessages("Unable to load Cosmetic User " + playerId + ". Exception: " + ex.getMessage());
return null;
});
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(@NotNull PlayerQuitEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return; // Player never initialized, don't do anything
PlayerPreUnloadEvent preUnloadEvent = new PlayerPreUnloadEvent(user);
Bukkit.getPluginManager().callEvent(preUnloadEvent);
if (preUnloadEvent.isCancelled()) return;
PlayerUnloadEvent playerUnloadEvent = new PlayerUnloadEvent(user);
Bukkit.getPluginManager().callEvent(playerUnloadEvent);
if (user.isInWardrobe()) {
user.leaveWardrobe(true);
user.getPlayer().setInvisible(false);
}
if (user.getUserEmoteManager().isPlayingEmote()) {
user.getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.CONNECTION);
event.getPlayer().setInvisible(false);
final Player player = user.getPlayer();
if(player != null) player.setInvisible(false);
}
Menus.removeCooldown(event.getPlayer().getUniqueId()); // Removes any menu cooldowns a player might have
Database.save(user);
user.destroy();
CosmeticUsers.removeUser(user.getUniqueId());
}
@EventHandler(priority = EventPriority.MONITOR)
public void notifyAdminUpdate(final PlayerJoinEvent event) {
if (event.getPlayer().isOp() || event.getPlayer().hasPermission("hmccosmetics.notifyupdate")) {
if (!HMCCosmeticsPlugin.getInstance().getLatestVersion().equalsIgnoreCase(HMCCosmeticsPlugin.getInstance().getDescription().getVersion()) && HMCCosmeticsPlugin.getInstance().getLatestVersion().isEmpty())
MessagesUtil.sendMessageNoKey(
event.getPlayer(),
"<br>" +
"<GRAY>There is a new version of <light_purple><Bold>HMCCosmetics<reset><gray> available!<br>" +
"<GRAY>Current version: <red>" + HMCCosmeticsPlugin.getInstance().getDescription().getVersion() + " <GRAY>| Latest version: <light_purple>" + HMCCosmeticsPlugin.getInstance().getLatestVersion() + "<br>" +
"<GRAY>Download it on <gold><click:OPEN_URL:'https://www.spigotmc.org/resources/100107/'>Spigot<reset> <gray>or <gold><click:OPEN_URL:'https://polymart.org/resource/1879'>Polymart<reset><gray>!" +
"<br>"
);
}
}
}

View File

@@ -1,13 +1,5 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.Pair;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.PlayerCosmeticPostEquipEvent;
import com.hibiscusmc.hmccosmetics.config.Settings;
@@ -17,20 +9,17 @@ import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticEmoteType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import me.lojosho.hibiscuscommons.api.events.HibiscusHookReload;
import me.lojosho.hibiscuscommons.api.events.HibiscusPlayerUnVanishEvent;
import me.lojosho.hibiscuscommons.api.events.HibiscusPlayerVanishEvent;
import me.lojosho.hibiscuscommons.hooks.items.HookItemAdder;
import me.lojosho.hibiscuscommons.api.events.*;
import me.lojosho.hibiscuscommons.nms.MinecraftVersion;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -53,27 +42,11 @@ import org.bukkit.persistence.PersistentDataType;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spigotmc.event.entity.EntityDismountEvent;
import org.spigotmc.event.entity.EntityMountEvent;
import java.util.*;
public class PlayerGameListener implements Listener {
public PlayerGameListener() {
registerInventoryClickListener();
registerMenuChangeListener();
registerEntityStatusListener();
registerPlayerEquipmentListener();
registerPlayerArmListener();
registerEntityUseListener();
registerSlotChangeListener();
//registerLookMovement();
//registerMoveListener();
//registerTeleportMovement();
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerClick(@NotNull InventoryClickEvent event) {
// || !event.getClickedInventory().getType().equals(InventoryType.PLAYER)
@@ -106,14 +79,10 @@ public class PlayerGameListener implements Listener {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer().getUniqueId());
if (user == null) return;
if (event.isSneaking()) {
user.getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.SNEAK);
}
if (!event.isSneaking()) return;
if (!user.isInWardrobe()) return;
user.leaveWardrobe();
user.leaveWardrobe(false);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@@ -127,7 +96,7 @@ public class PlayerGameListener implements Listener {
}
if (user.isInWardrobe()) {
user.leaveWardrobe();
user.leaveWardrobe(false);
}
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
@@ -147,9 +116,6 @@ public class PlayerGameListener implements Listener {
}, 2);
if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) || event.getCause().equals(PlayerTeleportEvent.TeleportCause.END_PORTAL)) return;
if (user.getUserEmoteManager().isPlayingEmote()) {
user.getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.TELEPORT);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
@@ -191,32 +157,20 @@ public class PlayerGameListener implements Listener {
if (!(event.getEntity() instanceof Player player)) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.getUserEmoteManager().isPlayingEmote()) {
if (Settings.isEmoteInvincible()) {
event.setCancelled(true);
}
if (Settings.isEmoteDamageLeave()) {
user.getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.DAMAGE);
}
}
if (user.isInWardrobe()) {
if (WardrobeSettings.isPreventDamage()) {
event.setCancelled(true);
return;
}
if (WardrobeSettings.isDamagedKicked()) user.leaveWardrobe();
if (WardrobeSettings.isDamagedKicked()) user.leaveWardrobe(false);
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerLook(PlayerMoveEvent event) {
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (!Settings.isEmoteMoveCheck() && user.getUserEmoteManager().isPlayingEmote()) {
event.setCancelled(true);
return;
}
user.updateCosmetic(CosmeticSlot.BACKPACK);
user.updateCosmetic(CosmeticSlot.BALLOON);
}
@@ -280,13 +234,8 @@ public class PlayerGameListener implements Listener {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer().getUniqueId());
if (user == null) return;
// Really need to look into optimization of this
if (user.hasCosmeticInSlot(CosmeticSlot.EMOTE) && event.getPlayer().isSneaking() && event.getPlayer().hasPermission("hmccosmetics.emote.shiftrun")) {
CosmeticEmoteType cosmeticEmoteType = (CosmeticEmoteType) user.getCosmetic(CosmeticSlot.EMOTE);
cosmeticEmoteType.run(user);
event.setCancelled(true);
return;
}
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (user.getEntity() == null) return; // Player has likely logged off
user.updateCosmetic(CosmeticSlot.OFFHAND);
List<Player> viewers = HMCCPacketManager.getViewers(user.getEntity().getLocation());
if (viewers.isEmpty()) return;
@@ -325,11 +274,12 @@ public class PlayerGameListener implements Listener {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
event.getPlayer().getInventory().setItem(event.getPreviousSlot(), event.getPlayer().getInventory().getItem(event.getPreviousSlot()));
//NMSHandlers.getHandler().slotUpdate(event.getPlayer(), event.getPreviousSlot());
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
user.updateCosmetic(CosmeticSlot.MAINHAND);
}, 2);
if (user.hasCosmeticInSlot(CosmeticSlot.MAINHAND)) {
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
user.updateCosmetic(CosmeticSlot.MAINHAND);
}, 2);
}
// #84, Riptides mess with backpacks
ItemStack currentItem = event.getPlayer().getInventory().getItem(event.getNewSlot());
@@ -345,7 +295,7 @@ public class PlayerGameListener implements Listener {
CosmeticUser user = CosmeticUsers.getUser(event.getEntity());
if (user == null) return;
if (user.isInWardrobe()) user.leaveWardrobe();
if (user.isInWardrobe()) user.leaveWardrobe(false);
if (Settings.isUnapplyOnDeath() && !event.getEntity().hasPermission("hmccosmetics.unapplydeath.bypass")) {
user.removeCosmetics();
@@ -379,6 +329,10 @@ public class PlayerGameListener implements Listener {
public void onPlayerCosmeticEquip(PlayerCosmeticPostEquipEvent event) {
CosmeticUser user = event.getUser();
if (user.isInWardrobe() && event.getCosmetic().getSlot().equals(CosmeticSlot.BALLOON)) {
if (user.getBalloonManager() == null) {
MessagesUtil.sendDebugMessages("Balloon Manager is null? " + user.getEntity().getName());
return;
}
CosmeticBalloonType cosmetic = (CosmeticBalloonType) event.getCosmetic();
Location npclocation = user.getWardrobeManager().getNpcLocation().clone().add(cosmetic.getBalloonOffset());
// We know that no other entity besides a regular player will be in the wardrobe
@@ -425,288 +379,42 @@ public class PlayerGameListener implements Listener {
user.showCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onHookReload(HibiscusHookReload event) {
if (event.getHook() instanceof HookItemAdder hook) {
switch (event.getReloadType()) {
case INITIAL -> {
HMCCosmeticsPlugin.setup();
}
case RELOAD -> {
if (!Settings.isItemsAdderChangeReload()) return;
HMCCosmeticsPlugin.setup();
}
}
}
// These emote mostly handles emotes from other plugins, such as ItemsAdder
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPlayEmote(HibiscusPlayerEmotePlayEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.EMOTE);
}
private void registerInventoryClickListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.WINDOW_CLICK) {
@Override
public void onPacketReceiving(PacketEvent event) {
Player player = event.getPlayer();
int invTypeClicked = event.getPacket().getIntegers().read(0);
int slotClicked = event.getPacket().getIntegers().read(2);
// Must be a player inventory.
if (invTypeClicked != 0) return;
// -999 is when a player clicks outside their inventory. https://wiki.vg/Inventory#Player_Inventory
if (slotClicked == -999) return;
if (event.getPlayer() == null) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.isInWardrobe()) return;
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slotClicked);
if (cosmeticSlot == null) return;
if (!user.hasCosmeticInSlot(cosmeticSlot)) return;
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> user.updateCosmetic(cosmeticSlot), 1);
MessagesUtil.sendDebugMessages("Packet fired, updated cosmetic " + cosmeticSlot);
}
});
@EventHandler(priority = EventPriority.LOW)
public void onPlayerEndEmote(HibiscusPlayerEmoteEndEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.showCosmetics(CosmeticUser.HiddenReason.EMOTE);
}
private void registerMenuChangeListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.WINDOW_ITEMS) {
@Override
public void onPacketSending(PacketEvent event) {
MessagesUtil.sendDebugMessages("Menu Initial ");
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
int windowID = event.getPacket().getIntegers().read(0);
List<ItemStack> slotData = event.getPacket().getItemListModifier().read(0);
if (windowID != 0) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
HashMap<Integer, ItemStack> items = new HashMap<>();
if (!user.isInWardrobe()) {
for (Cosmetic cosmetic : user.getCosmetics()) {
if ((cosmetic instanceof CosmeticArmorType cosmeticArmorType)) {
items.put(HMCCInventoryUtils.getPacketArmorSlot(cosmeticArmorType.getEquipSlot()), user.getUserCosmeticItem(cosmeticArmorType));
}
}
}
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
packet.getIntegers().write(0, 0);
for (int slot = 0; slot < 46; slot++) {
if ((slot >= 5 && slot <= 8) || slot == 45) {
if (!items.containsKey(slot)) continue;
slotData.set(slot, items.get(slot));
MessagesUtil.sendDebugMessages("Set " + slot + " as " + items.get(slot));
}
}
packet.getItemListModifier().write(0, slotData);
packet.getItemModifier().write(0, event.getPacket().getItemModifier().read(0));
event.setPacket(packet);
MessagesUtil.sendDebugMessages("Menu Fired, updated cosmetics " + " on slotdata " + windowID + " with " + slotData.size());
/*
for (Cosmetic cosmetic : user.getCosmetic()) {
if ((cosmetic instanceof CosmeticArmorType) || (cosmetic instanceof CosmeticMainhandType)) {
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
user.updateCosmetic(cosmetic);
}, 1);
}
}
*/
}
});
@EventHandler(priority = EventPriority.LOW)
public void onPlayerHibiscusPose(HibiscusPlayerPoseEvent event) {
if (event.isGettingUp()) return;
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
private void registerSlotChangeListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.SET_SLOT) {
@Override
public void onPacketSending(PacketEvent event) {
MessagesUtil.sendDebugMessages("SetSlot Initial ");
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
int windowID = event.getPacket().getIntegers().read(0);
if (windowID != 0) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.isInWardrobe()) return;
int slot = event.getPacket().getIntegers().read(2);
MessagesUtil.sendDebugMessages("SetSlot Slot " + slot);
if (slot == 45 && user.hasCosmeticInSlot(CosmeticSlot.OFFHAND) && player.getInventory().getItemInOffHand().getType().isAir()) {
event.getPacket().getItemModifier().write(0, user.getUserCosmeticItem(CosmeticSlot.OFFHAND));
}
}
});
@EventHandler(priority = EventPriority.LOW)
public void onPlayerHibiscusGetUpPose(HibiscusPlayerPoseEvent event) {
if (!event.isGettingUp()) return;
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.showCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
private void registerPlayerEquipmentListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.ENTITY_EQUIPMENT) {
@Override
public void onPacketSending(PacketEvent event) {
Player player = event.getPlayer(); // Player that's sent
int entityID = event.getPacket().getIntegers().read(0);
// User
CosmeticUser user = CosmeticUsers.getUser(entityID);
if (user == null) return;
if (user.isInWardrobe()) return;
List<com.comphenix.protocol.wrappers.Pair<EnumWrappers.ItemSlot, ItemStack>> armor = event.getPacket().getSlotStackPairLists().read(0);
for (int i = 0; i < armor.size(); i++) {
com.comphenix.protocol.wrappers.Pair<EnumWrappers.ItemSlot, ItemStack> pair = armor.get(i);
switch (pair.getFirst()) {
case MAINHAND -> {
if (user.getPlayer() == event.getPlayer()) continue; // When a player scrolls real fast, it messes up the mainhand. This fixes it
armor.set(i, new Pair<>(pair.getFirst(), user.getPlayer().getInventory().getItemInMainHand()));
}
case OFFHAND -> {
if (Settings.isCosmeticForceOffhandCosmeticShow() && user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) {
ItemStack item = user.getUserCosmeticItem(CosmeticSlot.OFFHAND);
if (item == null) continue;
Pair<EnumWrappers.ItemSlot, ItemStack> offhandPair = new Pair<>(EnumWrappers.ItemSlot.OFFHAND, item);
armor.set(i, offhandPair);
}
}
default -> {
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(HMCCInventoryUtils.getItemSlotToCosmeticSlot(pair.getFirst()));
if (cosmeticArmor == null) continue;
ItemStack item = user.getUserCosmeticItem(cosmeticArmor);
if (item == null) continue;
Pair<EnumWrappers.ItemSlot, ItemStack> armorPair = new Pair<>(HMCCInventoryUtils.itemBukkitSlot(cosmeticArmor.getEquipSlot()), item);
armor.set(i, armorPair);
}
}
}
event.getPacket().getSlotStackPairLists().write(0, armor);
MessagesUtil.sendDebugMessages("Equipment for " + user.getPlayer().getName() + " has been updated for " + player.getName());
}
});
}
private void registerEntityStatusListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Server.ENTITY_STATUS) {
@Override
public void onPacketSending(PacketEvent event) {
int entityid = event.getPacket().getIntegers().read(0);
byte status = event.getPacket().getBytes().read(0);
MessagesUtil.sendDebugMessages("EntityStatus Initial " + entityid + " - " + status);
if (status != 55) return;
CosmeticUser user = CosmeticUsers.getUser(entityid);
if (user == null) {
MessagesUtil.sendDebugMessages("EntityStatus User is null");
return;
}
if (!user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) return;
event.setCancelled(true);
}
});
}
private void registerPlayerArmListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.ARM_ANIMATION) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (event.getPlayer() == null) return;
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.getUserEmoteManager().isPlayingEmote()) {
event.setCancelled(true);
return;
}
if (!user.isInWardrobe()) return;
if (!user.getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return;
Menu menu = Menus.getDefaultMenu();
if (menu == null) return;
menu.openMenu(user);
event.setCancelled(true);
}
});
}
private void registerEntityUseListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.USE_ENTITY) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (event.getPlayer() == null) return;
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
if (user.getUserEmoteManager().isPlayingEmote() || user.isInWardrobe()) {
event.setCancelled(true);
}
}
});
}
private void registerLookMovement() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.LOOK) {
@Override
public void onPacketReceiving(PacketEvent event) {
// TODO: Finish
MessagesUtil.sendDebugMessages("Look Packet ");
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.isBackpackSpawned()) {
user.getUserBackpackManager().getEntityManager().setRotation(Math.round(event.getPacket().getFloat().read(0)));
}
}
});
}
private void registerMoveListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.POSITION) {
@Override
public void onPacketReceiving(PacketEvent event) {
// TODO: Finish
MessagesUtil.sendDebugMessages("Position Packet ");
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.isBackpackSpawned()) {
// The yaw follows the head, which makes it look weird and do weird things when moving around
user.getUserBackpackManager().getEntityManager().teleport(new Location(player.getWorld(), event.getPacket().getDoubles().read(0), event.getPacket().getDoubles().read(1), event.getPacket().getDoubles().read(2), event.getPacket().getFloat().read(0), event.getPacket().getFloat().read(1)));
}
}
});
}
private void registerTeleportMovement() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.POSITION_LOOK) {
@Override
public void onPacketReceiving(PacketEvent event) {
// TODO: Finish
MessagesUtil.sendDebugMessages("Teleport Packet ");
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
if (user.isBackpackSpawned()) {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> user.updateCosmetic(CosmeticSlot.BACKPACK));
}
}
});
}
@Nullable
private EquipmentSlot getArmorSlot(final Material material) {
for (final EquipmentSlot slot : EquipmentSlot.values()) {
final Set<Material> armorItems = ARMOR_ITEMS.get(slot);
if (armorItems == null) continue;
if (material == null) continue;
if (armorItems.contains(material)) return slot;
}
return null;

View File

@@ -0,0 +1,40 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import me.lojosho.hibiscuscommons.api.events.HibiscusHookReload;
import me.lojosho.hibiscuscommons.api.events.HibiscusHooksAllActiveEvent;
import me.lojosho.hibiscuscommons.hooks.Hook;
import me.lojosho.hibiscuscommons.hooks.items.HookItemAdder;
import me.lojosho.hibiscuscommons.hooks.items.HookNexo;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
public class ServerListener implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onHookReload(@NotNull HibiscusHookReload event) {
final Hook hook = event.getHook();
final HibiscusHookReload.ReloadType reloadType = event.getReloadType();
if (hook instanceof HookItemAdder) {
if (reloadType == HibiscusHookReload.ReloadType.RELOAD) {
if (!Settings.isItemsAdderChangeReload()) return;
HMCCosmeticsPlugin.setup();
}
}
if (hook instanceof HookNexo) {
if (reloadType == HibiscusHookReload.ReloadType.RELOAD) {
if (!Settings.isNexoChangeReload()) return;
HMCCosmeticsPlugin.setup();
}
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void onAllHooksReady(@NotNull HibiscusHooksAllActiveEvent event) {
HMCCosmeticsPlugin.setup();
}
}

View File

@@ -0,0 +1,195 @@
package com.hibiscusmc.hmccosmetics.packets;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import me.lojosho.hibiscuscommons.packets.PacketAction;
import me.lojosho.hibiscuscommons.packets.PacketInterface;
import me.lojosho.hibiscuscommons.packets.wrapper.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class CosmeticPacketInterface implements PacketInterface {
@Override
public PacketAction writeContainerContent(@NotNull Player player, @NotNull ContainerContentWrapper wrapper) {
int windowId = wrapper.getWindowId();
if (windowId != 0) return PacketAction.NOTHING;
List<ItemStack> slotData = wrapper.getSlotData();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return PacketAction.NOTHING;
HashMap<Integer, ItemStack> items = new HashMap<>();
if (!user.isInWardrobe()) for (Cosmetic cosmetic : user.getCosmetics()) if (cosmetic instanceof CosmeticArmorType armorType) {
boolean requireEmpty = Settings.getSlotOption(armorType.getEquipSlot()).isRequireEmpty();
boolean isAir = user.getPlayer().getInventory().getItem(armorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("Menu Fired (Checks) - " + armorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
items.put(HMCCInventoryUtils.getPacketArmorSlot(armorType.getEquipSlot()), user.getUserCosmeticItem(armorType));
}
for (int slot = 0; slot < 46; slot++) {
if ((slot >= 5 && slot <= 8) || slot == 45) {
if (!items.containsKey(slot)) continue;
slotData.set(slot, items.get(slot));
if (Settings.isDebugMode()) MessagesUtil.sendDebugMessages("Set " + slot + " as " + items.get(slot));
}
}
wrapper.setSlotData(slotData);
MessagesUtil.sendDebugMessages("Menu Fired, updated cosmetics " + " on slotdata " + windowId + " with " + slotData.size());
return PacketAction.CHANGED;
}
@Override
public PacketAction writeSlotContent(@NotNull Player player, @NotNull SlotContentWrapper wrapper) {
int windowId = wrapper.getWindowId();
int slot = wrapper.getSlot();
ItemStack itemStack = wrapper.getItemStack();
MessagesUtil.sendDebugMessages("SetSlot Initial ");
if (windowId != 0) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
MessagesUtil.sendDebugMessages("SetSlot Slot " + slot);
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slot);
EquipmentSlot equipmentSlot = HMCCInventoryUtils.getPacketArmorSlot(slot);
if (cosmeticSlot == null || equipmentSlot == null) return PacketAction.NOTHING;
if (!user.hasCosmeticInSlot(cosmeticSlot)) return PacketAction.NOTHING;
if (Settings.getSlotOption(equipmentSlot).isRequireEmpty()) {
if (!player.getInventory().getItem(equipmentSlot).getType().isAir()) return PacketAction.NOTHING;
}
wrapper.setItemStack(user.getUserCosmeticItem(cosmeticSlot));
return PacketAction.CHANGED;
}
@Override
public PacketAction writeEquipmentContent(@NotNull Player player, @NotNull EntityEquipmentWrapper wrapper) {
if (player.getEntityId() != wrapper.getEntityId()) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
Map<EquipmentSlot, ItemStack> armor = wrapper.getArmor();
for (Map.Entry<EquipmentSlot, ItemStack> armorSlot : armor.entrySet()) {
EquipmentSlot slot = armorSlot.getKey();
if (slot == EquipmentSlot.HAND) {
if (user.getPlayer().getUniqueId() == player.getUniqueId())
continue; // When a player scrolls real fast, it messes up the mainhand. This fixes it
if (user.getPlayer() != null && user.getPlayer().isInvisible())
continue; // Fixes integration with GSit still showing mainhand even when hidden
armor.put(slot, player.getInventory().getItemInMainHand());
} else {
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.BukkitCosmeticSlot(slot);
if (cosmeticSlot == null) continue;
if (Settings.getSlotOption(slot).isRequireEmpty() && player.getInventory().getItem(slot).getType().isAir())
continue;
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(cosmeticSlot);
if (cosmeticArmor == null) continue;
ItemStack item = user.getUserCosmeticItem(cosmeticSlot);
if (item == null) continue;
armor.put(slot, item);
}
}
wrapper.setArmor(armor);
MessagesUtil.sendDebugMessages("Equipment for " + user.getPlayer().getName() + " has been updated for " + player.getName());
return PacketAction.CHANGED;
}
@Override
public PacketAction writePassengerContent(@NotNull Player player, @NotNull PassengerWrapper wrapper) {
CosmeticUser viewerUser = CosmeticUsers.getUser(player);
if (viewerUser == null || viewerUser.isInWardrobe()) return PacketAction.NOTHING;
int ownerId = wrapper.getOwner();
List<Integer> originalPassengers = wrapper.getPassengers();
MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId);
Optional<CosmeticUser> optionalCosmeticUser = CosmeticUsers.values().stream().filter(user -> user.getPlayer() != null).filter(user -> ownerId == user.getPlayer().getEntityId()).findFirst();
if (optionalCosmeticUser.isEmpty()) return PacketAction.NOTHING;
Player entity = optionalCosmeticUser.get().getPlayer();
CosmeticUser user = CosmeticUsers.getUser(entity.getUniqueId());
if (user == null) return PacketAction.NOTHING;
MessagesUtil.sendDebugMessages("Mount Packet Sent - " + user.getUniqueId());
if (!user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) return PacketAction.NOTHING;
if (user.getUserBackpackManager() == null) return PacketAction.NOTHING;
List<Integer> passengers = new ArrayList<>(user.getUserBackpackManager().getEntityManager().getIds());
for (int passenger : originalPassengers) passengers.add(passenger);
wrapper.setPassengers(passengers);
return PacketAction.CHANGED;
}
@Override
public PacketAction readInventoryClick(@NotNull Player player, @NotNull InventoryClickWrapper wrapper) {
int clickType = wrapper.getClickType();
int slotNumber = wrapper.getSlotNumber();
if (clickType != 0 || slotNumber == -999) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slotNumber);
if (cosmeticSlot == null || !user.hasCosmeticInSlot(cosmeticSlot)) return PacketAction.NOTHING;
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> user.updateCosmetic(cosmeticSlot), 1);
MessagesUtil.sendDebugMessages("Packet fired, updated cosmetic " + cosmeticSlot);
return PacketAction.NOTHING;
}
@Override
public PacketAction readPlayerAction(@NotNull Player player, @NotNull PlayerActionWrapper wrapper) {
String actionType = wrapper.getActionType();
MessagesUtil.sendDebugMessages("EntityStatus Initial " + player.getEntityId() + " - " + actionType);
// If it's not SWAP_ITEM_WITH_OFFHAND, ignore
if (!actionType.equalsIgnoreCase("SWAP_ITEM_WITH_OFFHAND")) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) {
MessagesUtil.sendDebugMessages("EntityStatus User is null");
return PacketAction.NOTHING;
}
if (!user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) return PacketAction.NOTHING;
return PacketAction.CANCELLED;
}
@Override
public PacketAction readPlayerArm(@NotNull Player player) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe() || !user.getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return PacketAction.NOTHING;
Menu menu = user.getWardrobeManager().getLastOpenMenu();
if (menu == null) return PacketAction.NOTHING;
menu.openMenu(user);
return PacketAction.CANCELLED;
}
@Override
public PacketAction readEntityHandle(@NotNull Player player) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe()) return PacketAction.NOTHING;
else return PacketAction.CANCELLED;
}
}

View File

@@ -8,95 +8,216 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.config.Wardrobe;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticMainhandType;
import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.modelengine.api.nms.NMSHandler;
import lombok.Getter;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.InventoryUtils;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.logging.Level;
public class CosmeticUser {
public class CosmeticUser implements CosmeticHolder {
@Getter
private final UUID uniqueId;
private int taskId;
private int taskId = -1;
private final HashMap<CosmeticSlot, Cosmetic> playerCosmetics = new HashMap<>();
private UserWardrobeManager userWardrobeManager;
private UserBalloonManager userBalloonManager;
@Getter
private UserBackpackManager userBackpackManager;
@Getter
private final UserEmoteManager userEmoteManager;
// Cosmetic Settings/Toggles
private final ArrayList<HiddenReason> hiddenReason = new ArrayList<>();
private final HashMap<CosmeticSlot, Color> colors = new HashMap<>();
public CosmeticUser(UUID uuid) {
this.uniqueId = uuid;
userEmoteManager = new UserEmoteManager(this);
tick();
/**
* Use {@link #CosmeticUser(UUID)} instead and use {@link #initialize(UserData)} to populate the user with data.
* @param uuid
* @param data
*/
@Deprecated(forRemoval = true, since = "2.7.5")
public CosmeticUser(UUID uuid, UserData data) {
this(uuid);
initialize(data);
}
private void tick() {
// Occasionally updates the entity cosmetics
Runnable run = () -> {
MessagesUtil.sendDebugMessages("Tick[uuid=" + uniqueId + "]", Level.INFO);
updateCosmetic();
if (isHidden() && !getUserEmoteManager().isPlayingEmote()) MessagesUtil.sendActionBar(getPlayer(), "hidden-cosmetics");
};
public CosmeticUser(@NotNull UUID uuid) {
this.uniqueId = uuid;
}
/**
* Initialize the {@link CosmeticUser}.
* @param userData the associated {@link UserData}
* @return the {@link CosmeticUser}
* @apiNote Initialize is called after {@link CosmeticUserProvider#createCosmeticUser(UUID)} so it is possible to
* populate an extending version of {@link CosmeticUser} with data then override this method to apply your
* own state.
*/
public CosmeticUser initialize(final @Nullable UserData userData) {
if(userData != null) {
// CosmeticSlot -> Entry<Cosmetic, Integer>
for(final Map.Entry<CosmeticSlot, Map.Entry<Cosmetic, Integer>> entry : userData.getCosmetics().entrySet()) {
final Cosmetic cosmetic = entry.getValue().getKey();
final Integer colorRGBInt = entry.getValue().getValue();
if (!this.canApplyCosmetic(cosmetic)) {
MessagesUtil.sendDebugMessages("Cannot apply cosmetic[id=" + cosmetic.getId() + "]");
continue;
}
Color color = null;
if (colorRGBInt != -1) color = Color.fromRGB(colorRGBInt); // -1 is defined as no color; anything else is a color
this.addPlayerCosmetic(cosmetic, color);
}
this.applyHiddenState(userData.getHiddenReasons());
}
return this;
}
/**
* This method is only called from {@link #initialize(UserData)} and can't be called directly.
* This is used to help hooking plugins apply custom logic to the user.
*/
protected boolean applyCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color) {
this.addPlayerCosmetic(cosmetic, color);
return true;
}
/**
* This method is only called from {@link #initialize(UserData)} and can't be called directly.
* This is used to help hooking plugins apply custom logic to the user.
*/
protected boolean canApplyCosmetic(@NotNull Cosmetic cosmetic) {
return canEquipCosmetic(cosmetic, false);
}
/**
* This method is only called from {@link #initialize(UserData)} and can't be called directly.
* This is used to help hooking plugins apply custom logic to the user.
*/
protected void applyHiddenState(@NotNull List<HiddenReason> hiddenReasons) {
if(!hiddenReason.isEmpty()) {
for(final HiddenReason reason : this.hiddenReason) {
this.silentlyAddHideFlag(reason);
}
return;
}
Player bukkitPlayer = getPlayer();
if (bukkitPlayer != null && Settings.isDisabledGamemodesEnabled() && Settings.getDisabledGamemodes().contains(bukkitPlayer.getGameMode().toString())) {
MessagesUtil.sendDebugMessages("Hiding cosmetics due to gamemode");
hideCosmetics(HiddenReason.GAMEMODE);
} else if (this.isHidden(HiddenReason.GAMEMODE)) {
MessagesUtil.sendDebugMessages("Showing cosmetics for gamemode");
showCosmetics(HiddenReason.GAMEMODE);
}
if (bukkitPlayer != null && Settings.getDisabledWorlds().contains(bukkitPlayer.getLocation().getWorld().getName())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to world");
hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else if (this.isHidden(HiddenReason.WORLD)) {
MessagesUtil.sendDebugMessages("Showing Cosmetics due to world");
showCosmetics(HiddenReason.WORLD);
}
if (Settings.isAllPlayersHidden()) {
hideCosmetics(HiddenReason.DISABLED);
}
for (final HiddenReason reason : hiddenReasons) {
this.silentlyAddHideFlag(reason);
}
}
/**
* Start ticking against the {@link CosmeticUser}.
* @implNote The tick-rate is determined by the tick period specified in the configuration, if it is less-than or equal to 0
* there will be no {@link BukkitTask} created, and the {@link CosmeticUser#taskId} will be -1
*/
public final void startTicking() {
int tickPeriod = Settings.getTickPeriod();
if (tickPeriod > 0) {
BukkitTask task = Bukkit.getScheduler().runTaskTimer(HMCCosmeticsPlugin.getInstance(), run, 0, tickPeriod);
taskId = task.getTaskId();
if(tickPeriod <= 0) {
MessagesUtil.sendDebugMessages("CosmeticUser tick is disabled.");
return;
}
final BukkitTask task = Bukkit.getScheduler().runTaskTimer(HMCCosmeticsPlugin.getInstance(), this::tick, 0, tickPeriod);
this.taskId = task.getTaskId();
}
/**
* Dispatch an operation to happen against this {@link CosmeticUser}
* at a pre-determined tick-rate.
* The tick-rate is determined by the tick period specified in the configuration.
*/
protected void tick() {
MessagesUtil.sendDebugMessages("Tick[uuid=" + uniqueId + "]", Level.INFO);
if (Hooks.isInvisible(uniqueId)) {
this.hideCosmetics(HiddenReason.VANISH);
} else {
this.showCosmetics(HiddenReason.VANISH);
}
this.updateCosmetic();
if(isHidden() && !playerCosmetics.isEmpty()) {
MessagesUtil.sendActionBar(getPlayer(), "hidden-cosmetics");
}
}
public void destroy() {
Bukkit.getScheduler().cancelTask(taskId);
if(this.taskId != -1) { // ensure we're actually ticking this user.
Bukkit.getScheduler().cancelTask(taskId);
}
despawnBackpack();
despawnBalloon();
}
public Cosmetic getCosmetic(CosmeticSlot slot) {
@Override
public Cosmetic getCosmetic(@NotNull CosmeticSlot slot) {
return playerCosmetics.get(slot);
}
public ImmutableCollection<Cosmetic> getCosmetics() {
@Override
public @NotNull ImmutableCollection<Cosmetic> getCosmetics() {
return ImmutableList.copyOf(playerCosmetics.values());
}
public void addPlayerCosmetic(Cosmetic cosmetic) {
addPlayerCosmetic(cosmetic, null);
}
public void addPlayerCosmetic(Cosmetic cosmetic, Color color) {
@Override
public void addCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color) {
// API
PlayerCosmeticEquipEvent event = new PlayerCosmeticEquipEvent(this, cosmetic);
Bukkit.getPluginManager().callEvent(event);
@@ -128,15 +249,24 @@ public class CosmeticUser {
Bukkit.getPluginManager().callEvent(postEquipEvent);
}
public void removeCosmetics() {
// Small optimization could be made, but Concurrent modification prevents us from both getting and removing
for (CosmeticSlot slot : CosmeticSlot.values()) {
removeCosmeticSlot(slot);
}
/**
* @deprecated Use {@link #addCosmetic(Cosmetic)} instead
*/
@Deprecated(since = "2.7.7", forRemoval = true)
public void addPlayerCosmetic(@NotNull Cosmetic cosmetic) {
addCosmetic(cosmetic);
}
/**
* @deprecated Use {@link #addCosmetic(Cosmetic, Color)} instead
*/
@Deprecated(since = "2.7.7", forRemoval = true)
public void addPlayerCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color) {
addCosmetic(cosmetic, color);
}
public void removeCosmeticSlot(CosmeticSlot slot) {
@Override
public void removeCosmeticSlot(@NotNull CosmeticSlot slot) {
// API
PlayerCosmeticRemoveEvent event = new PlayerCosmeticRemoveEvent(this, getCosmetic(slot));
Bukkit.getPluginManager().callEvent(event);
@@ -150,38 +280,26 @@ public class CosmeticUser {
if (slot == CosmeticSlot.BALLOON) {
despawnBalloon();
}
if (slot == CosmeticSlot.EMOTE) {
if (getUserEmoteManager().isPlayingEmote()) getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.UNEQUIP);
}
colors.remove(slot);
playerCosmetics.remove(slot);
removeArmor(slot);
}
public void removeCosmeticSlot(Cosmetic cosmetic) {
removeCosmeticSlot(cosmetic.getSlot());
}
public boolean hasCosmeticInSlot(CosmeticSlot slot) {
@Override
public boolean hasCosmeticInSlot(@NotNull CosmeticSlot slot) {
return playerCosmetics.containsKey(slot);
}
public boolean hasCosmeticInSlot(Cosmetic cosmetic) {
if (getCosmetic(cosmetic.getSlot()) == null) return false;
return Objects.equals(cosmetic.getId(), getCosmetic(cosmetic.getSlot()).getId());
}
public Set<CosmeticSlot> getSlotsWithCosmetics() {
return Set.copyOf(playerCosmetics.keySet());
}
public void updateCosmetic(CosmeticSlot slot) {
if (getCosmetic(slot) == null) {
return;
@Override
public void updateCosmetic(@NotNull CosmeticSlot slot) {
Cosmetic cosmetic = playerCosmetics.get(slot);
if (cosmetic != null) {
cosmetic.update(this);
}
getCosmetic(slot).update(this);
return;
}
public void updateCosmetic(Cosmetic cosmetic) {
@@ -192,19 +310,23 @@ public class CosmeticUser {
MessagesUtil.sendDebugMessages("updateCosmetic (All) - start");
HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for (Cosmetic cosmetic : getCosmetics()) {
for (Cosmetic cosmetic : playerCosmetics.values()) {
if (cosmetic instanceof CosmeticArmorType armorType) {
if (getUserEmoteManager().isPlayingEmote() || isInWardrobe()) return;
if (!Settings.isCosmeticForceOffhandCosmeticShow()
&& armorType.getEquipSlot().equals(EquipmentSlot.OFF_HAND)
&& !getPlayer().getInventory().getItemInOffHand().getType().isAir()) continue;
if (isInWardrobe()) return;
if (!(getEntity() instanceof HumanEntity humanEntity)) return;
boolean requireEmpty = Settings.getSlotOption(armorType.getEquipSlot()).isRequireEmpty();
boolean isAir = humanEntity.getInventory().getItem(armorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("updateCosmetic (All) - " + armorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
items.put(HMCCInventoryUtils.getEquipmentSlot(armorType.getSlot()), armorType.getItem(this));
continue;
} else {
cosmetic.update(this);
}
updateCosmetic(cosmetic.getSlot());
}
if (items.isEmpty() || getEntity() == null) return;
PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), items, HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation()));
PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), items, HMCCPacketManager.getViewers(getEntity().getLocation()));
MessagesUtil.sendDebugMessages("updateCosmetic (All) - end - " + items.size());
}
@@ -214,7 +336,7 @@ public class CosmeticUser {
return getUserCosmeticItem(cosmetic);
}
public ItemStack getUserCosmeticItem(Cosmetic cosmetic) {
public ItemStack getUserCosmeticItem(@NotNull Cosmetic cosmetic) {
ItemStack item = null;
if (!hiddenReason.isEmpty()) {
if (cosmetic instanceof CosmeticBackpackType || cosmetic instanceof CosmeticBalloonType) return new ItemStack(Material.AIR);
@@ -237,7 +359,7 @@ public class CosmeticUser {
}
@SuppressWarnings("deprecation")
public ItemStack getUserCosmeticItem(Cosmetic cosmetic, ItemStack item) {
public ItemStack getUserCosmeticItem(@NotNull Cosmetic cosmetic, @Nullable ItemStack item) {
if (item == null) {
//MessagesUtil.sendDebugMessages("GetUserCosemticUser Item is null");
return new ItemStack(Material.AIR);
@@ -268,33 +390,32 @@ public class CosmeticUser {
itemMeta = skullMeta;
}
List<String> processedLore = new ArrayList<>();
if (itemMeta.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
processedLore.add(Hooks.processPlaceholders(getPlayer(), loreLine));
if (Settings.isItemProcessingDisplayName()) {
if (itemMeta.hasDisplayName()) {
String displayName = itemMeta.getDisplayName();
itemMeta.setDisplayName(Hooks.processPlaceholders(getPlayer(), displayName));
}
}
if (itemMeta.hasDisplayName()) {
String displayName = itemMeta.getDisplayName();
itemMeta.setDisplayName(Hooks.processPlaceholders(getPlayer(), displayName));
}
itemMeta.setLore(processedLore);
if (colors.containsKey(cosmetic.getSlot())) {
Color color = colors.get(cosmetic.getSlot());
if (itemMeta instanceof LeatherArmorMeta leatherMeta) {
leatherMeta.setColor(color);
} else if (itemMeta instanceof PotionMeta potionMeta) {
potionMeta.setColor(color);
} else if (itemMeta instanceof MapMeta mapMeta) {
mapMeta.setColor(color);
if (Settings.isItemProcessingLore()) {
List<String> processedLore = new ArrayList<>();
if (itemMeta.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
processedLore.add(Hooks.processPlaceholders(getPlayer(), loreLine));
}
}
itemMeta.setLore(processedLore);
}
itemMeta.getPersistentDataContainer().set(HMCCInventoryUtils.getCosmeticKey(), PersistentDataType.STRING, cosmetic.getId());
itemMeta.getPersistentDataContainer().set(InventoryUtils.getOwnerKey(), PersistentDataType.STRING, getEntity().getUniqueId().toString());
item.setItemMeta(itemMeta);
if (colors.containsKey(cosmetic.getSlot())) {
Color color = colors.get(cosmetic.getSlot());
item = NMSHandlers.getHandler().getUtilHandler().setColor(item, color);
}
}
return item;
}
@@ -307,7 +428,22 @@ public class CosmeticUser {
return userWardrobeManager;
}
public void enterWardrobe(boolean ignoreDistance, Wardrobe wardrobe) {
/**
* Use {@link #enterWardrobe(Wardrobe, boolean)} instead.
* @param ignoreDistance
* @param wardrobe
*/
@Deprecated(forRemoval = true, since = "2.7.5")
public void enterWardrobe(boolean ignoreDistance, @NotNull Wardrobe wardrobe) {
enterWardrobe(wardrobe, ignoreDistance);
}
/**
* This method is used to enter a wardrobe. You can listen to the {@link PlayerWardrobeEnterEvent} to cancel the event or modify any data.
* @param wardrobe The wardrobe to enter. Use {@link WardrobeSettings#getWardrobe(String)} to get pre-existing wardrobe or use your own by {@link Wardrobe}.
* @param ignoreDistance If true, the player can enter the wardrobe from any distance. If false, the player must be within the distance set in the wardrobe (If wardrobe has a distance of 0 or lower, the player can enter from any distance).
*/
public void enterWardrobe(@NotNull Wardrobe wardrobe, boolean ignoreDistance) {
if (wardrobe.hasPermission() && !getPlayer().hasPermission(wardrobe.getPermission())) {
MessagesUtil.sendMessage(getPlayer(), "no-permission");
return;
@@ -333,10 +469,18 @@ public class CosmeticUser {
}
}
/**
* Use {@link #leaveWardrobe(boolean)} instead.
*/
@Deprecated(forRemoval = true, since = "2.7.5")
public void leaveWardrobe() {
leaveWardrobe(false);
}
/**
* Causes the player to leave the wardrobe. If a player is not in the wardrobe, this will do nothing, use (@{@link #isInWardrobe()} to check if they are).
* @param ejected If true, the player was ejected from the wardrobe (Skips transition). If false, the player left the wardrobe normally.
*/
public void leaveWardrobe(boolean ejected) {
PlayerWardrobeLeaveEvent event = new PlayerWardrobeLeaveEvent(this);
Bukkit.getPluginManager().callEvent(event);
@@ -347,6 +491,7 @@ public class CosmeticUser {
if (!getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return;
getWardrobeManager().setWardrobeStatus(UserWardrobeManager.WardrobeStatus.STOPPING);
getWardrobeManager().setLastOpenMenu(Menus.getDefaultMenu());
if (WardrobeSettings.isEnabledTransition() && !ejected) {
MessagesUtil.sendTitle(
@@ -366,6 +511,10 @@ public class CosmeticUser {
}
}
/**
* This checks if the player is in a wardrobe. If they are, it will return true, else false. See {@link #getWardrobeManager()} to get the wardrobe manager.
* @return If the player is in a wardrobe.
*/
public boolean isInWardrobe() {
return userWardrobeManager != null;
}
@@ -407,10 +556,6 @@ public class CosmeticUser {
public void despawnBalloon() {
if (this.userBalloonManager == null) return;
List<Player> sentTo = HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation());
HMCCPacketManager.sendEntityDestroyPacket(userBalloonManager.getPufferfishBalloonId(), sentTo);
this.userBalloonManager.remove();
this.userBalloonManager = null;
}
@@ -437,9 +582,9 @@ public class CosmeticUser {
EquipmentSlot equipmentSlot = HMCCInventoryUtils.getEquipmentSlot(slot);
if (equipmentSlot == null) return;
if (getPlayer() != null) {
PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), equipmentSlot, getPlayer().getInventory().getItem(equipmentSlot), HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation()));
PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), equipmentSlot, getPlayer().getInventory().getItem(equipmentSlot), HMCCPacketManager.getViewers(getEntity().getLocation()));
} else {
HMCCPacketManager.equipmentSlotUpdate(getEntity().getEntityId(), this, slot, HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation()));
HMCCPacketManager.equipmentSlotUpdate(getEntity().getEntityId(), this, slot, HMCCPacketManager.getViewers(getEntity().getLocation()));
}
}
@@ -458,7 +603,7 @@ public class CosmeticUser {
* @return Entity
*/
public Entity getEntity() {
return Bukkit.getEntity(uniqueId);
return getPlayer();
}
public Color getCosmeticColor(CosmeticSlot slot) {
@@ -466,25 +611,27 @@ public class CosmeticUser {
}
public List<CosmeticSlot> getDyeableSlots() {
ArrayList<CosmeticSlot> dyableSlots = new ArrayList<>();
ArrayList<CosmeticSlot> dyeableSlots = new ArrayList<>();
for (Cosmetic cosmetic : getCosmetics()) {
if (cosmetic.isDyable()) dyableSlots.add(cosmetic.getSlot());
for (Cosmetic cosmetic : playerCosmetics.values()) {
if (cosmetic.isDyeable()) dyeableSlots.add(cosmetic.getSlot());
}
return dyableSlots;
return dyeableSlots;
}
public boolean canEquipCosmetic(Cosmetic cosmetic) {
return canEquipCosmetic(cosmetic, false);
}
public boolean canEquipCosmetic(Cosmetic cosmetic, boolean ignoreWardrobe) {
@Override
public boolean canEquipCosmetic(@NotNull Cosmetic cosmetic, boolean ignoreWardrobe) {
if (!cosmetic.requiresPermission()) return true;
if (isInWardrobe() && !ignoreWardrobe) {
if (WardrobeSettings.isTryCosmeticsInWardrobe() && userWardrobeManager.getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return true;
}
return getPlayer().hasPermission(cosmetic.getPermission());
final Player player = getPlayer();
if (player != null) return player.hasPermission(cosmetic.getPermission());
// This sucks, but basically if we can find a player, use that. If not, try to find the entity. If it can't find the entity, just return false.
final Entity entity = getEntity();
if (entity != null) return entity.hasPermission(cosmetic.getPermission());
return false;
}
public void hidePlayer() {
@@ -548,7 +695,7 @@ public class CosmeticUser {
if (!isBalloonSpawned()) respawnBalloon();
CosmeticBalloonType balloonType = (CosmeticBalloonType) getCosmetic(CosmeticSlot.BALLOON);
getBalloonManager().addPlayerToModel(this, balloonType);
List<Player> viewer = HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation());
List<Player> viewer = HMCCPacketManager.getViewers(getEntity().getLocation());
HMCCPacketManager.sendLeashPacket(getBalloonManager().getPufferfishBalloonId(), getPlayer().getEntityId(), viewer);
}
if (hasCosmeticInSlot(CosmeticSlot.BACKPACK)) {
@@ -591,6 +738,7 @@ public class CosmeticUser {
NONE,
WORLDGUARD,
PLUGIN,
VANISH,
POTION,
ACTION,
COMMAND,

View File

@@ -0,0 +1,44 @@
package com.hibiscusmc.hmccosmetics.user;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Allow custom implementations of a {@link CosmeticUser}.
*/
public abstract class CosmeticUserProvider {
/**
* Construct the custom {@link CosmeticUser}.
* @param playerId the player uuid
* @return the {@link CosmeticUser}
* @apiNote This method is called during the {@link PlayerJoinEvent}.
*/
public abstract @NotNull CosmeticUser createCosmeticUser(@NotNull UUID playerId);
/**
* Represents the plugin that is providing this {@link CosmeticUserProvider}
* @return the plugin
*/
public abstract Plugin getProviderPlugin();
/**
* Default implementation.
*/
static class Default extends CosmeticUserProvider {
public static CosmeticUserProvider INSTANCE = new Default();
@Override
public @NotNull CosmeticUser createCosmeticUser(@NotNull UUID playerId) {
return new CosmeticUser(playerId);
}
@Override
public Plugin getProviderPlugin() {
return HMCCosmeticsPlugin.getInstance();
}
}
}

View File

@@ -1,6 +1,5 @@
package com.hibiscusmc.hmccosmetics.user;
import com.google.common.collect.HashBiMap;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -9,10 +8,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class CosmeticUsers {
private static final HashBiMap<UUID, CosmeticUser> COSMETIC_USERS = HashBiMap.create();
private static final ConcurrentHashMap<UUID, CosmeticUser> COSMETIC_USERS = new ConcurrentHashMap<>();
private static CosmeticUserProvider PROVIDER = CosmeticUserProvider.Default.INSTANCE;
/**
* Adds a user to the Hashmap of stored CosmeticUsers. This will not override an entry if it already exists. If you need to override, delete then add.
@@ -52,7 +54,7 @@ public class CosmeticUsers {
/**
* This method allows you to get a CosmeticUser from just using the player class. This just allows you to have a bit less boilerplate.
* @param player The player to lookup (will take their UUID from the class)
* @return Returns the user if there is a vlaid user, returns null if not.
* @return Returns the user if there is a valid user, returns null if not.
*/
@Nullable
public static CosmeticUser getUser(@NotNull Player player) {
@@ -72,12 +74,38 @@ public class CosmeticUsers {
return COSMETIC_USERS.get(player.getUniqueId());
}
/**
* Register a custom {@link CosmeticUserProvider} to provide your own user implementation to
* be used and queried.
* @param provider the provider to register
* @throws IllegalArgumentException if the provider is already registered by another plugin
*/
public static void registerProvider(final CosmeticUserProvider provider) {
if(PROVIDER != CosmeticUserProvider.Default.INSTANCE) {
throw new IllegalArgumentException("CosmeticUserProvider already registered by %s, this conflicts with %s attempting to register their own.".formatted(
PROVIDER.getProviderPlugin().getName(),
provider.getProviderPlugin().getName()
));
}
PROVIDER = provider;
}
/**
* Fetch the current {@link CosmeticUserProvider} being used.
* @return the current {@link CosmeticUserProvider} being used
*/
public static CosmeticUserProvider getProvider() {
return PROVIDER;
}
/**
* Gets all the values for CosmeticUsers to allow you to iterate over everyone.
* @return CosmeticUsers in a set. This will never be null, but might be empty.
*/
@NotNull
public static Set<CosmeticUser> values() {
return COSMETIC_USERS.values();
// fix this later; this is a temporary fix. It was originally a set, now it's a collection
return Set.copyOf(COSMETIC_USERS.values());
}
}

View File

@@ -27,7 +27,7 @@ public class UserBackpackManager {
@Getter
private boolean backpackHidden;
@Getter
private int invisibleArmorStand;
private final int invisibleArmorStand;
private ArrayList<Integer> particleCloud = new ArrayList<>();
@Getter
private final CosmeticUser user;
@@ -84,26 +84,12 @@ public class UserBackpackManager {
if (i == 0) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), particleCloud.get(i), owner);
else HMCCPacketManager.sendRidingPacket(particleCloud.get(i - 1), particleCloud.get(i) , owner);
}
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), user.getUserBackpackManager().getFirstArmorStandId(), owner);
HMCCPacketManager.sendRidingPacket(particleCloud.getLast(), user.getUserBackpackManager().getFirstArmorStandId(), owner);
if (!user.isHidden()) PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(cosmeticBackpackType, cosmeticBackpackType.getFirstPersonBackpack()), owner);
}
PacketManager.equipmentSlotUpdate(getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(cosmeticBackpackType), outsideViewers);
HMCCPacketManager.sendRidingPacket(entity.getEntityId(), passengerIDs, outsideViewers);
// No one should be using ME because it barely works but some still use it, so it's here
if (cosmeticBackpackType.getModelName() != null && Hooks.isActiveHook("ModelEngine")) {
if (ModelEngineAPI.getBlueprint(cosmeticBackpackType.getModelName()) == null) {
MessagesUtil.sendDebugMessages("Invalid Model Engine Blueprint " + cosmeticBackpackType.getModelName(), Level.SEVERE);
return;
}
/* TODO: Readd ModelEngine support
ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(new PacketBaseEntity(getFirstArmorStandId(), UUID.randomUUID(), entity.getLocation()));
ActiveModel model = ModelEngineAPI.createActiveModel(ModelEngineAPI.getBlueprint(cosmeticBackpackType.getModelName()));
model.setCanHurt(false);
modeledEntity.addModel(model, false);
*/
}
MessagesUtil.sendDebugMessages("spawnBackpack Bukkit - Finish");
}

View File

@@ -30,16 +30,17 @@ import java.util.logging.Level;
public class UserBalloonManager {
private CosmeticUser user;
private final CosmeticUser user;
@Getter
private BalloonType balloonType;
private CosmeticBalloonType cosmeticBalloonType;
@Getter
private UserBalloonPufferfish pufferfish;
private final ArmorStand modelEntity;
public UserBalloonManager(CosmeticUser user, @NotNull Location location) {
this.user = user;
this.pufferfish = new UserBalloonPufferfish(user.getUniqueId(), NMSHandlers.getHandler().getNextEntityId(), UUID.randomUUID());
this.pufferfish = new UserBalloonPufferfish(user.getUniqueId(), NMSHandlers.getHandler().getUtilHandler().getNextEntityId(), UUID.randomUUID());
this.modelEntity = location.getWorld().spawn(location, ArmorStand.class, (e) -> {
e.setInvisible(true);
e.setGravity(false);
@@ -80,9 +81,9 @@ public class UserBalloonManager {
if (color != null) {
modeledEntity.getModels().forEach((d, singleModel) -> {
if (cosmeticBalloonType.isDyablePart(d)) {
if (cosmeticBalloonType.isDyeablePart(d)) {
singleModel.setDefaultTint(color);
singleModel.getModelRenderer().sendToClient();
singleModel.getModelRenderer().sendToClient(ModelEngineAPI.getNMSHandler().createParsers());
}
});
}
@@ -98,6 +99,7 @@ public class UserBalloonManager {
}
public void remove() {
pufferfish.destroyPufferfish();
if (balloonType == BalloonType.MODELENGINE) {
final ModeledEntity entity = ModelEngineAPI.getModeledEntity(modelEntity);
if (entity == null) {
@@ -156,6 +158,7 @@ public class UserBalloonManager {
public int getPufferfishBalloonId() {
return pufferfish.getPufferFishEntityId();
}
public UUID getPufferfishBalloonUniqueId() {
return pufferfish.getUuid();
}
@@ -176,6 +179,10 @@ public class UserBalloonManager {
this.getModelEntity().teleport(location);
}
public Vector getVelocity() {
return getModelEntity().getVelocity();
}
public void setVelocity(Vector vector) {
this.getModelEntity().setVelocity(vector);
}

View File

@@ -3,7 +3,10 @@ package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@@ -14,8 +17,11 @@ import java.util.UUID;
public class UserBalloonPufferfish extends UserEntity {
private int pufferFishEntityId;
private UUID uuid;
@Getter
private final int pufferFishEntityId;
@Getter
private final UUID uuid;
private boolean destroyed = false;
public UserBalloonPufferfish(UUID owner, int pufferFishEntityId, UUID uuid) {
super(owner);
@@ -23,14 +29,6 @@ public class UserBalloonPufferfish extends UserEntity {
this.uuid = uuid;
}
public int getPufferFishEntityId() {
return pufferFishEntityId;
}
public UUID getUuid() {
return uuid;
}
public void hidePufferfish() {
HMCCPacketManager.sendEntityDestroyPacket(pufferFishEntityId, getViewers());
getViewers().clear();
@@ -41,35 +39,15 @@ public class UserBalloonPufferfish extends UserEntity {
HMCCPacketManager.sendInvisibilityPacket(pufferFishEntityId, sendTo);
}
public void destroyPufferfish() {
HMCCPacketManager.sendEntityDestroyPacket(pufferFishEntityId, getViewers());
getViewers().clear();
destroyed = true;
}
@Override
public List<Player> refreshViewers(Location location) {
if (System.currentTimeMillis() - getViewerLastUpdate() <= 1000) return List.of(); //Prevents mass refreshes
ArrayList<Player> newPlayers = new ArrayList<>();
ArrayList<Player> removePlayers = new ArrayList<>();
List<Player> players = HMCCPlayerUtils.getNearbyPlayers(location);
for (Player player : players) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user != null && getOwner() != user.getUniqueId() && user.isInWardrobe()) { // Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
removePlayers.add(player);
HMCCPacketManager.sendEntityDestroyPacket(getPufferFishEntityId(), List.of(player));
continue;
}
if (!getViewers().contains(player)) {
getViewers().add(player);
newPlayers.add(player);
continue;
}
// bad loopdy loops
for (Player viewerPlayer : getViewers()) {
if (!players.contains(viewerPlayer)) {
removePlayers.add(viewerPlayer);
HMCCPacketManager.sendEntityDestroyPacket(getPufferFishEntityId(), List.of(viewerPlayer));
}
}
}
getViewers().removeAll(removePlayers);
setViewerLastUpdate(System.currentTimeMillis());
return newPlayers;
if (destroyed) return List.of(); //Prevents refreshing a destroyed entity
return super.refreshViewers(location);
}
}

View File

@@ -1,94 +0,0 @@
package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.api.events.PlayerEmoteStartEvent;
import com.hibiscusmc.hmccosmetics.api.events.PlayerEmoteStopEvent;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticEmoteType;
import com.hibiscusmc.hmccosmetics.emotes.EmoteManager;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
public class UserEmoteManager {
private CosmeticUser user;
private UserEmoteModel model;
private Entity textEntity;
public UserEmoteManager(CosmeticUser user) {
this.user = user;
}
public void playEmote(String animationId) {
MessagesUtil.sendDebugMessages("playEmote " + animationId);
playEmote(EmoteManager.get(animationId), null);
}
public void playEmote(@NotNull CosmeticEmoteType cosmeticEmoteType) {
MessagesUtil.sendDebugMessages("playEmote " + cosmeticEmoteType.getAnimationId());
playEmote(EmoteManager.get(cosmeticEmoteType.getAnimationId()), cosmeticEmoteType.getText());
}
public void playEmote(String emoteAnimation, String text) {
if (isPlayingEmote()) return;
if (user.isInWardrobe()) return;
// API
PlayerEmoteStartEvent event = new PlayerEmoteStartEvent(user, emoteAnimation);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// Internal
try {
model = new UserEmoteModel(user);
// Play animation id
if (emoteAnimation != null) {
model.playAnimation(emoteAnimation);
}
// Show the text
if (text != null && textEntity == null) {
// removed in 2.7.0
//textEntity = HMCCNMSHandlers.getHandler().spawnDisplayEntity(user.getPlayer().getLocation().add(0, 3, 0), text);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isPlayingEmote() {
if (model == null) return false;
return model.isPlayingAnimation();
}
public void stopEmote(StopEmoteReason emoteReason) {
if (!isPlayingEmote()) return;
// API
PlayerEmoteStopEvent event = new PlayerEmoteStopEvent(user, emoteReason);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
// Internal
model.stopAnimation();
if (textEntity != null) {
textEntity.remove();
textEntity = null;
}
}
public void despawnTextEntity() {
if (textEntity != null) {
textEntity.remove();
textEntity = null;
}
}
public enum StopEmoteReason {
SNEAK,
DAMAGE,
CONNECTION,
TELEPORT,
UNEQUIP
}
}

View File

@@ -1,134 +0,0 @@
package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.playeranimator.api.model.player.PlayerModel;
import me.lojosho.hibiscuscommons.util.ServerUtils;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
public class UserEmoteModel extends PlayerModel {
private final CosmeticUser user;
private String emotePlaying;
private final int armorStandId;
private GameMode originalGamemode;
public UserEmoteModel(@NotNull CosmeticUser user) {
super(user.getPlayer());
this.user = user;
armorStandId = ServerUtils.getNextEntityId();
getRangeManager().setRenderDistance(Settings.getViewDistance());
}
@Override
public void playAnimation(@NotNull String id) {
super.playAnimation(id);
emotePlaying = id;
// Add config option that either allows player to move or forces them into a spot.
Player player = user.getPlayer();
List<Player> viewer = Collections.singletonList(user.getPlayer());
List<Player> outsideViewers = HMCCPacketManager.getViewers(player.getLocation());
// Send equipment packet to the player as well (Fixes Optifine still rendering armor when emoting)
HMCCPacketManager.equipmentSlotUpdate(player, true, outsideViewers);
outsideViewers.remove(player);
user.getPlayer().setInvisible(true);
user.hideCosmetics(CosmeticUser.HiddenReason.EMOTE);
originalGamemode = player.getGameMode();
if (Settings.isEmoteCameraEnabled()) {
Location newLocation = player.getLocation().clone();
newLocation.setPitch(0);
double DISTANCE = Settings.getEmoteDistance();
Location thirdPersonLocation = newLocation.add(newLocation.getDirection().normalize().multiply(DISTANCE));
if (DISTANCE > 0) {
MessagesUtil.sendDebugMessages("Yaw " + (int) thirdPersonLocation.getYaw());
MessagesUtil.sendDebugMessages("New Yaw " + ServerUtils.getNextYaw((int) thirdPersonLocation.getYaw(), 180));
thirdPersonLocation.setYaw(ServerUtils.getNextYaw((int) thirdPersonLocation.getYaw(), 180));
}
if (Settings.isCosmeticEmoteBlockCheck() && thirdPersonLocation.getBlock().getType().isOccluding()) {
stopAnimation();
MessagesUtil.sendMessage(player, "emote-blocked");
return;
}
// Check if block below player is an air block
if (Settings.isEmoteAirCheck() && newLocation.clone().subtract(0, 1, 0).getBlock().getType().isAir()) {
stopAnimation();
MessagesUtil.sendMessage(player, "emote-blocked");
}
HMCCPacketManager.sendEntitySpawnPacket(thirdPersonLocation, armorStandId, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer);
HMCCPacketManager.sendInvisibilityPacket(armorStandId, viewer);
HMCCPacketManager.sendLookPacket(armorStandId, thirdPersonLocation, viewer);
HMCCPacketManager.gamemodeChangePacket(player, 3);
HMCCPacketManager.sendCameraPacket(armorStandId, viewer);
}
MessagesUtil.sendDebugMessages("playAnimation run");
}
@Override
public boolean update() {
if (super.getAnimationProperty() == null) {
stopAnimation();
return false;
}
boolean update = (super.update() && isPlayingAnimation());
if (!update) {
stopAnimation();
}
return update;
}
public void stopAnimation() {
emotePlaying = null;
despawn();
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
Player player = user.getPlayer();
if (player == null) return;
List<Player> viewer = Collections.singletonList(player);
List<Player> outsideViewers = HMCCPacketManager.getViewers(player.getLocation());
// Send Equipment packet to all (Fixes Optifine Issue)
HMCCPacketManager.equipmentSlotUpdate(player, false, outsideViewers);
outsideViewers.remove(player);
int entityId = player.getEntityId();
HMCCPacketManager.sendCameraPacket(entityId, viewer);
HMCCPacketManager.sendEntityDestroyPacket(armorStandId, viewer);
if (this.originalGamemode != null) {
HMCCPacketManager.gamemodeChangePacket(player, HMCCServerUtils.convertGamemode(this.originalGamemode));
player.setGameMode(this.originalGamemode);
}
if (user.getPlayer() != null) player.setInvisible(false);
user.getUserEmoteManager().despawnTextEntity();
user.showPlayer();
user.showCosmetics(CosmeticUser.HiddenReason.EMOTE);
});
}
public boolean isPlayingAnimation() {
return emotePlaying != null;
}
}

View File

@@ -4,10 +4,13 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.ArrayList;
@@ -41,11 +44,16 @@ public class UserEntity {
if (System.currentTimeMillis() - viewerLastUpdate <= 1000) return List.of(); //Prevents mass refreshes
ArrayList<Player> newPlayers = new ArrayList<>();
ArrayList<Player> removePlayers = new ArrayList<>();
List<Player> players = HMCCPlayerUtils.getNearbyPlayers(location);
List<Player> players = HMCCPacketManager.getViewers(location);
Entity ownerPlayer = Bukkit.getEntity(owner);
if (ownerPlayer == null) {
MessagesUtil.sendDebugMessages("Owner is null (refreshViewers), returning empty list");
return List.of();
}
for (Player player : players) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user != null && owner != user.getUniqueId() && user.isInWardrobe()) { // Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
if (user != null && owner != user.getUniqueId() && user.isInWardrobe() && !player.canSee(ownerPlayer)) { // Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
removePlayers.add(player);
HMCCPacketManager.sendEntityDestroyPacket(ids, List.of(player));
continue;
@@ -91,7 +99,7 @@ public class UserEntity {
// First person backpacks need both packets to rotate properly, otherwise they look off
// Regular backpacks just need the look packet
if (additonalPacket) HMCCPacketManager.sendRotationPacket(entity, yaw, false, getViewers());
HMCCPacketManager.sendLookPacket(entity, location, getViewers());
HMCCPacketManager.sendRotateHeadPacket(entity, location, getViewers());
}
}
}

View File

@@ -10,10 +10,12 @@ import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import net.kyori.adventure.audience.Audience;
@@ -62,8 +64,12 @@ public class UserWardrobeManager {
private BossBar bossBar;
@Getter
private boolean active;
@Setter
@Getter
private WardrobeStatus wardrobeStatus;
@Getter
@Setter
private Menu lastOpenMenu;
public UserWardrobeManager(CosmeticUser user, Wardrobe wardrobe) {
NPC_ID = me.lojosho.hibiscuscommons.util.ServerUtils.getNextEntityId();
@@ -78,6 +84,10 @@ public class UserWardrobeManager {
this.viewingLocation = wardrobeLocation.getViewerLocation();
this.npcLocation = wardrobeLocation.getNpcLocation();
String defaultMenu = wardrobe.getDefaultMenu();
if (defaultMenu != null && Menus.hasMenu(defaultMenu)) this.lastOpenMenu = Menus.getMenu(defaultMenu);
else this.lastOpenMenu = Menus.getDefaultMenu();
wardrobeStatus = WardrobeStatus.SETUP;
}
@@ -99,15 +109,22 @@ public class UserWardrobeManager {
MessagesUtil.sendMessage(player, "opened-wardrobe");
Runnable run = () -> {
if (!player.isOnline()) {
end();
return;
}
// Armorstand
HMCCPacketManager.sendEntitySpawnPacket(viewingLocation, ARMORSTAND_ID, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer);
HMCCPacketManager.sendArmorstandMetadata(ARMORSTAND_ID, viewer);
HMCCPacketManager.sendLookPacket(ARMORSTAND_ID, viewingLocation, viewer);
NMSHandlers.getHandler().getPacketHandler().sendTeleportPacket(ARMORSTAND_ID, viewingLocation.getX(), viewingLocation.getY(), viewingLocation.getZ(), viewingLocation.getYaw(), viewingLocation.getPitch(), false, viewer);
//NMSHandlers.getHandler().getPacketHandler().sendLookAtPacket(ARMORSTAND_ID, viewingLocation, viewer);
HMCCPacketManager.sendRotateHeadPacket(ARMORSTAND_ID, viewingLocation, viewer);
// Player
user.getPlayer().teleport(viewingLocation, PlayerTeleportEvent.TeleportCause.PLUGIN);
user.getPlayer().setInvisible(true);
HMCCPacketManager.gamemodeChangePacket(player, 3);
player.teleport(viewingLocation, PlayerTeleportEvent.TeleportCause.PLUGIN);
player.setInvisible(true);
HMCCPacketManager.gamemodeChangePacket(player, GameMode.SPECTATOR);
HMCCPacketManager.sendCameraPacket(ARMORSTAND_ID, viewer);
// NPC
@@ -123,11 +140,11 @@ public class UserWardrobeManager {
HMCCPacketManager.sendFakePlayerSpawnPacket(npcLocation, WARDROBE_UUID, NPC_ID, viewer);
HMCCPacketManager.sendPlayerOverlayPacket(NPC_ID, viewer);
MessagesUtil.sendDebugMessages("Spawned Fake Player on " + npcLocation);
NMSHandlers.getHandler().hideNPCName(player, npcName);
NMSHandlers.getHandler().getPacketHandler().sendScoreboardHideNamePacket(player, npcName);
}, 4);
// Location
HMCCPacketManager.sendLookPacket(NPC_ID, npcLocation, viewer);
HMCCPacketManager.sendRotateHeadPacket(NPC_ID, npcLocation, viewer);
HMCCPacketManager.sendRotationPacket(NPC_ID, npcLocation, true, viewer);
// Misc
@@ -158,7 +175,7 @@ public class UserWardrobeManager {
if (WardrobeSettings.isEnabledBossbar()) {
float progress = WardrobeSettings.getBossbarProgress();
Component message = MessagesUtil.processStringNoKey(WardrobeSettings.getBossbarMessage());
Component message = MessagesUtil.processStringNoKey(player, WardrobeSettings.getBossbarMessage());
bossBar = BossBar.bossBar(message, progress, WardrobeSettings.getBossbarColor(), WardrobeSettings.getBossbarOverlay());
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
@@ -232,11 +249,11 @@ public class UserWardrobeManager {
if (WardrobeSettings.isForceExitGamemode()) {
MessagesUtil.sendDebugMessages("Force Exit Gamemode " + WardrobeSettings.getExitGamemode());
player.setGameMode(WardrobeSettings.getExitGamemode());
HMCCPacketManager.gamemodeChangePacket(player, HMCCServerUtils.convertGamemode(WardrobeSettings.getExitGamemode())); // Success
HMCCPacketManager.gamemodeChangePacket(player, WardrobeSettings.getExitGamemode()); // Success
} else {
MessagesUtil.sendDebugMessages("Original Gamemode " + this.originalGamemode);
player.setGameMode(this.originalGamemode);
HMCCPacketManager.gamemodeChangePacket(player, HMCCServerUtils.convertGamemode(this.originalGamemode)); // Success
HMCCPacketManager.gamemodeChangePacket(player, this.originalGamemode); // Success
}
user.showPlayer();
@@ -253,7 +270,7 @@ public class UserWardrobeManager {
player.teleport(Objects.requireNonNullElseGet(exitLocation, () -> player.getWorld().getSpawnLocation()), PlayerTeleportEvent.TeleportCause.PLUGIN);
HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for (EquipmentSlot slot : EquipmentSlot.values()) {
for (EquipmentSlot slot : HMCCInventoryUtils.getPlayerArmorSlots()) {
ItemStack item = player.getInventory().getItem(slot);
items.put(slot, item);
}
@@ -275,7 +292,7 @@ public class UserWardrobeManager {
run.run();
}
public void update() {
private void update() {
final AtomicInteger data = new AtomicInteger();
BukkitRunnable runnable = new BukkitRunnable() {
@@ -296,15 +313,17 @@ public class UserWardrobeManager {
int yaw = data.get();
location.setYaw(yaw);
HMCCPacketManager.sendLookPacket(NPC_ID, location, viewer);
HMCCPacketManager.sendRotateHeadPacket(NPC_ID, location, viewer);
user.hidePlayer();
int rotationSpeed = WardrobeSettings.getRotationSpeed();
location.setYaw(HMCCServerUtils.getNextYaw(yaw - 30, rotationSpeed));
HMCCPacketManager.sendRotationPacket(NPC_ID, location, true, viewer);
int newYaw = HMCCServerUtils.getNextYaw(yaw - 30, rotationSpeed);
location.setYaw(newYaw);
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(NPC_ID, newYaw, 0, false, viewer);
HMCCPacketManager.sendRotationPacket(NPC_ID, newYaw, true, viewer);
int nextyaw = HMCCServerUtils.getNextYaw(yaw, rotationSpeed);
data.set(nextyaw);
for (CosmeticSlot slot : CosmeticSlot.values()) {
for (CosmeticSlot slot : CosmeticSlot.values().values()) {
HMCCPacketManager.equipmentSlotUpdate(NPC_ID, user, slot, viewer);
}
@@ -337,10 +356,6 @@ public class UserWardrobeManager {
runnable.runTaskTimer(HMCCosmeticsPlugin.getInstance(), 0, 2);
}
public void setWardrobeStatus(WardrobeStatus status) {
this.wardrobeStatus = status;
}
public enum WardrobeStatus {
SETUP,
STARTING,

View File

@@ -1,6 +1,5 @@
package com.hibiscusmc.hmccosmetics.util;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import org.bukkit.NamespacedKey;
@@ -11,22 +10,21 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HMCCInventoryUtils {
/**
* Converts from the Bukkit item slots to ProtocolLib item slots. Will produce a null if an improper bukkit item slot is sent through
* @param slot The BUKKIT item slot to convert.
* @return The ProtocolLib item slot that is returned
*/
public static EnumWrappers.ItemSlot itemBukkitSlot(final EquipmentSlot slot) {
return switch (slot) {
case HEAD -> EnumWrappers.ItemSlot.HEAD;
case CHEST -> EnumWrappers.ItemSlot.CHEST;
case LEGS -> EnumWrappers.ItemSlot.LEGS;
case FEET -> EnumWrappers.ItemSlot.FEET;
case HAND -> EnumWrappers.ItemSlot.MAINHAND;
case OFF_HAND -> EnumWrappers.ItemSlot.OFFHAND;
};
private static final Map<CosmeticSlot, EquipmentSlot> SLOT_MAP = new HashMap<>();
static {
SLOT_MAP.put(CosmeticSlot.HELMET, EquipmentSlot.HEAD);
SLOT_MAP.put(CosmeticSlot.CHESTPLATE, EquipmentSlot.CHEST);
SLOT_MAP.put(CosmeticSlot.LEGGINGS, EquipmentSlot.LEGS);
SLOT_MAP.put(CosmeticSlot.BOOTS, EquipmentSlot.FEET);
SLOT_MAP.put(CosmeticSlot.OFFHAND, EquipmentSlot.OFF_HAND);
SLOT_MAP.put(CosmeticSlot.MAINHAND, EquipmentSlot.HAND);
}
public static int getPacketArmorSlot(final EquipmentSlot slot) {
@@ -52,17 +50,6 @@ public class HMCCInventoryUtils {
};
}
public static CosmeticSlot getItemSlotToCosmeticSlot(final EnumWrappers.ItemSlot slot) {
return switch (slot) {
case HEAD -> CosmeticSlot.HELMET;
case CHEST -> CosmeticSlot.CHESTPLATE;
case LEGS -> CosmeticSlot.LEGGINGS;
case FEET -> CosmeticSlot.BOOTS;
case OFFHAND -> CosmeticSlot.OFFHAND;
case MAINHAND -> CosmeticSlot.MAINHAND;
};
}
public static CosmeticSlot BukkitCosmeticSlot(EquipmentSlot slot) {
return switch (slot) {
case HAND -> CosmeticSlot.MAINHAND;
@@ -128,29 +115,7 @@ public class HMCCInventoryUtils {
@Contract(pure = true)
@Nullable
public static EquipmentSlot getEquipmentSlot(@NotNull CosmeticSlot slot) {
switch (slot) {
case HELMET -> {
return EquipmentSlot.HEAD;
}
case CHESTPLATE -> {
return EquipmentSlot.CHEST;
}
case LEGGINGS -> {
return EquipmentSlot.LEGS;
}
case BOOTS -> {
return EquipmentSlot.FEET;
}
case OFFHAND -> {
return EquipmentSlot.OFF_HAND;
}
case MAINHAND -> {
return EquipmentSlot.HAND;
}
default -> {
return null;
}
}
return SLOT_MAP.get(slot);
}
public static boolean isCosmeticItem(ItemStack itemStack) {
@@ -163,4 +128,12 @@ public class HMCCInventoryUtils {
public static NamespacedKey getCosmeticKey() {
return new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmetic");
}
/**
* This returns all the slots a player can have on them. In 1.20.6+, the enum includes BODY, which is not a valid slot for a player.
* @return A list of all the slots a player can have on them
*/
public static List<EquipmentSlot> getPlayerArmorSlots() {
return Arrays.asList(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.OFF_HAND, EquipmentSlot.HAND);
}
}

View File

@@ -1,35 +1,33 @@
package com.hibiscusmc.hmccosmetics.util;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.hibiscusmc.hmccosmetics.config.Settings;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class HMCCPlayerUtils {
@Nullable
public static WrappedSignedProperty getSkin(Player player) {
WrappedSignedProperty skinData = WrappedGameProfile.fromPlayer(player).getProperties()
.get("textures").stream().findAny().orElse(null);
if (skinData == null) {
return null;
}
return new WrappedSignedProperty("textures", skinData.getValue(), skinData.getSignature());
}
/**
* Get nearby players. {@link com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager#getViewers(Location)}
* @param player
* @return
*/
@NotNull
@Deprecated(since = "2.7.5", forRemoval = true)
public static List<Player> getNearbyPlayers(@NotNull Player player) {
return getNearbyPlayers(player.getLocation());
}
/**
* Get nearby players. {@link com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager#getViewers(Location)}
* @param location
* @return
*/
@NotNull
@Deprecated(since = "2.7.5", forRemoval = true)
public static List<Player> getNearbyPlayers(@NotNull Location location) {
return PacketManager.getViewers(location, Settings.getViewDistance());
}

View File

@@ -33,7 +33,7 @@ public class HMCCServerUtils {
}
public static org.bukkit.entity.Entity getEntity(int entityId) {
return NMSHandlers.getHandler().getEntity(entityId);
return NMSHandlers.getHandler().getUtilHandler().getEntity(entityId);
}
/**
@@ -157,13 +157,4 @@ public class HMCCServerUtils {
}
return nextYaw;
}
public static boolean hasClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}

View File

@@ -32,7 +32,7 @@ public class TranslationUtil {
public static String getTranslation(String key, String message) {
List<TranslationPair> pairs = keys.get(key);
for (TranslationPair pair : pairs) {
if (pair.key().equals(message)) return StringUtils.parseStringToString(pair.value());
if (pair.key().equals(message)) return pair.value();
}
return message;

View File

@@ -1,118 +0,0 @@
package com.hibiscusmc.hmccosmetics.util.misc;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class Utils {
/**
* @param original Object to be checked if null
* @param replacement Object returned if original is null
* @return original if not null, otherwise replacement
*/
public static <T> T replaceIfNull(final @Nullable T original, final @NotNull T replacement) {
return replaceIfNull(original, replacement, t -> {
});
}
@SafeVarargs
public static <T> T replaceIf(final @Nullable T original, final T replacement, final @Nullable T... checks) {
for (final T check : checks) {
if (original == check) return replacement;
}
return original;
}
public static <T> T replaceIf(final @Nullable T original, final T replacement, final @NotNull Predicate<T> predicate) {
if (predicate.test(original)) return replacement;
return original;
}
/**
* @param original Object to be checked if null
* @param replacement Object returned if original is null
* @param consumer accepts the original object, can be used for logging
* @return original if not null, otherwise replacement
*/
public static <T> T replaceIfNull(final @Nullable T original, final T replacement,
final @NotNull Consumer<T> consumer) {
if (original == null) {
consumer.accept(replacement);
return replacement;
}
consumer.accept(original);
return original;
}
/**
* @param t object being checked
* @param consumer accepted if t is not null
* @param <T> type
*/
public static <T> void doIfNotNull(final @Nullable T t, final @NotNull Consumer<T> consumer) {
if (t == null) {
return;
}
consumer.accept(t);
}
/**
* @param t object being checked
* @param function applied if t is not null
* @param <T> type
* @return
*/
public static <T> Optional<T> returnIfNotNull(final @Nullable T t,
final @NotNull Function<T, T> function) {
if (t == null) {
return Optional.empty();
}
return Optional.of(function.apply(t));
}
/**
* @param enumAsString Enum value as a string to be parsed
* @param enumClass enum type enumAsString is to be converted to
* @param defaultEnum default value to be returned
* @return enumAsString as an enum, or default enum if it could not be parsed
*/
public static <E extends Enum<E>> E stringToEnum(final @NotNull String enumAsString,
final @NotNull Class<E> enumClass,
E defaultEnum) {
return stringToEnum(enumAsString, enumClass, defaultEnum, e -> {
});
}
/**
* @param enumAsString Enum value as a string to be parsed
* @param enumClass enum type enumAsString is to be converted to
* @param defaultEnum default value to be returned
* @param consumer accepts the returned enum, can be used for logging
* @return enumAsString as an enum, or default enum if it could not be parsed
*/
public static <E extends Enum<E>> E stringToEnum(final @NotNull String enumAsString,
@NotNull final Class<E> enumClass,
final E defaultEnum,
final @NotNull Consumer<E> consumer) {
try {
final E value = Enum.valueOf(enumClass, enumAsString);
consumer.accept(value);
return value;
} catch (final IllegalArgumentException exception) {
consumer.accept(defaultEnum);
return defaultEnum;
}
}
}

View File

@@ -1,33 +1,30 @@
package com.hibiscusmc.hmccosmetics.util.packets;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.*;
import com.google.common.collect.Lists;
import com.hibiscusmc.hmccosmetics.api.HMCCosmeticsAPI;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerNamedEntitySpawn;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerPlayerInfo;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerRelEntityMove;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Display;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.*;
public class HMCCPacketManager extends PacketManager {
private static final List<CosmeticSlot> EQUIPMENT_SLOTS = List.of(CosmeticSlot.HELMET, CosmeticSlot.CHESTPLATE, CosmeticSlot.LEGGINGS, CosmeticSlot.BOOTS, CosmeticSlot.MAINHAND, CosmeticSlot.OFFHAND);
public static void sendEntitySpawnPacket(
final @NotNull Location location,
final int entityId,
@@ -44,16 +41,7 @@ public class HMCCPacketManager extends PacketManager {
final UUID uuid,
final @NotNull List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY);
packet.getModifier().writeDefaults();
packet.getUUIDs().write(0, uuid);
packet.getIntegers().write(0, entityId);
packet.getEntityTypeModifier().write(0, entityType);
packet.getDoubles().
write(0, location.getX()).
write(1, location.getY()).
write(2, location.getZ());
for (Player p : sendTo) sendPacket(p, packet);
NMSHandlers.getHandler().getPacketHandler().sendSpawnEntityPacket(entityId, uuid, entityType, location, sendTo);
}
public static void equipmentSlotUpdate(
@@ -62,7 +50,7 @@ public class HMCCPacketManager extends PacketManager {
List<Player> sendTo
) {
HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for (EquipmentSlot slot : EquipmentSlot.values()) {
for (EquipmentSlot slot : HMCCInventoryUtils.getPlayerArmorSlots()) {
ItemStack item = player.getInventory().getItem(slot);
if (empty) item = new ItemStack(Material.AIR);
items.put(slot, item);
@@ -91,8 +79,7 @@ public class HMCCPacketManager extends PacketManager {
CosmeticSlot cosmeticSlot,
List<Player> sendTo
) {
if (cosmeticSlot == CosmeticSlot.BACKPACK || cosmeticSlot == CosmeticSlot.BALLOON || cosmeticSlot == CosmeticSlot.EMOTE) return;
if (!EQUIPMENT_SLOTS.contains(cosmeticSlot)) return;
equipmentSlotUpdate(entityId, HMCCInventoryUtils.getEquipmentSlot(cosmeticSlot), user.getUserCosmeticItem(cosmeticSlot), sendTo);
}
@@ -100,66 +87,24 @@ public class HMCCPacketManager extends PacketManager {
int entityId,
List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x21);
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x10);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
// 0x21 = Invisible + Fire (Aka, burns to make it not take the light of the block its in, avoiding turning it black)
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x21));
wrappedDataValueList.add(new WrappedDataValue(15, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x10));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (Player p : sendTo) sendPacket(p, packet);
byte mask = (byte) (Settings.isBackpackPreventDarkness() ? 0x21 : 0x20);
Map<Integer, Number> dataValues = Map.of(0, mask, 15, (byte) 0x10);
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, dataValues, sendTo);
}
public static void sendInvisibilityPacket(
int entityId,
List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x20));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (Player p : sendTo) sendPacket(p, packet);
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, Map.of(0, (byte) 0x20), sendTo);
}
public static void sendCloudEffect(
int entityId,
List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20);
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(8, WrappedDataWatcher.Registry.get(Float.class)), 0f);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x20));
wrappedDataValueList.add(new WrappedDataValue(8, WrappedDataWatcher.Registry.get(Float.class), 0f));
//wrappedDataValueList.add(new WrappedDataValue(11, WrappedDataWatcher.Registry.get(Integer.class), 21));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (Player p : sendTo) sendPacket(p, packet);
Map<Integer, Number> dataValues = Map.of(0, (byte) 0x20, 8, 0f);
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, dataValues, sendTo);
}
public static void sendRotationPacket(
@@ -177,16 +122,10 @@ public class HMCCPacketManager extends PacketManager {
@NotNull List<Player> sendTo
) {
float ROTATION_FACTOR = 256.0F / 360.0F;
float yaw = location.getYaw() * ROTATION_FACTOR;
float pitch = location.getPitch() * ROTATION_FACTOR;
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_LOOK);
packet.getIntegers().write(0, entityId);
packet.getBytes().write(0, (byte) yaw);
packet.getBytes().write(1, (byte) pitch);
byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR);
byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR);
//Bukkit.getLogger().info("DEBUG: Yaw: " + (location.getYaw() * ROTATION_FACTOR) + " | Original Yaw: " + location.getYaw());
packet.getBooleans().write(0, onGround);
for (Player p : sendTo) sendPacket(p, packet);
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw, pitch, onGround, sendTo);
}
public static void sendRotationPacket(
@@ -196,18 +135,9 @@ public class HMCCPacketManager extends PacketManager {
@NotNull List<Player> sendTo
) {
float ROTATION_FACTOR = 256.0F / 360.0F;
float yaw2 = yaw * ROTATION_FACTOR;
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_LOOK);
packet.getIntegers().write(0, entityId);
packet.getBytes().write(0, (byte) yaw2);
packet.getBytes().write(1, (byte) 0);
//Bukkit.getLogger().info("DEBUG: Yaw: " + (location.getYaw() * ROTATION_FACTOR) + " | Original Yaw: " + location.getYaw());
packet.getBooleans().write(0, onGround);
for (Player p : sendTo) sendPacket(p, packet);
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw * ROTATION_FACTOR, 0, onGround, sendTo);
}
/**
* Mostly to deal with backpacks, this deals with entities riding other entities.
* @param mountId The entity that is the "mount", ex. a player
@@ -232,12 +162,7 @@ public class HMCCPacketManager extends PacketManager {
final int[] passengerIds,
final @NotNull List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.MOUNT);
packet.getIntegers().write(0, mountId);
packet.getIntegerArrays().write(0, passengerIds);
for (final Player p : sendTo) {
sendPacket(p, packet);
}
NMSHandlers.getHandler().getPacketHandler().sendMountPacket(mountId, passengerIds, sendTo);
}
/**
@@ -267,17 +192,7 @@ public class HMCCPacketManager extends PacketManager {
final int entityId,
final @NotNull List<Player> sendTo
) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R3") || HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R1")) {
WrapperPlayServerNamedEntitySpawn wrapper = new WrapperPlayServerNamedEntitySpawn();
wrapper.setEntityID(entityId);
wrapper.setPlayerUUID(uuid);
wrapper.setPosition(location.toVector());
wrapper.setPitch(location.getPitch());
wrapper.setYaw(location.getYaw());
for (final Player p : sendTo) sendPacket(p, wrapper.getHandle());
return;
}
sendEntitySpawnPacket(location, entityId, EntityType.PLAYER, uuid);
sendEntitySpawnPacket(location, entityId, EntityType.PLAYER, uuid, sendTo);
}
/**
@@ -290,37 +205,10 @@ public class HMCCPacketManager extends PacketManager {
final Player skinnedPlayer,
final int entityId,
final UUID uuid,
final String NPCName,
final String npcName,
final List<Player> sendTo
) {
WrapperPlayServerPlayerInfo info = new WrapperPlayServerPlayerInfo();
info.setAction(EnumWrappers.PlayerInfoAction.ADD_PLAYER);
String name = NPCName;
while (name.length() > 16) {
name = name.substring(16);
}
WrappedGameProfile wrappedGameProfile = new WrappedGameProfile(uuid, name);
WrappedSignedProperty skinData = HMCCPlayerUtils.getSkin(skinnedPlayer);
if (skinData != null) wrappedGameProfile.getProperties().put("textures", skinData);
// For sor some reason <1.19.2 handles it on the 0 field index, newer versions handles it on the 1
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
info.getHandle().getPlayerInfoDataLists().write(0, Collections.singletonList(new PlayerInfoData(
wrappedGameProfile,
0,
EnumWrappers.NativeGameMode.CREATIVE,
WrappedChatComponent.fromText(name)
)));
} else {
info.getHandle().getPlayerInfoDataLists().write(1, Collections.singletonList(new PlayerInfoData(
wrappedGameProfile,
0,
EnumWrappers.NativeGameMode.CREATIVE,
WrappedChatComponent.fromText(name)
)));
}
for (final Player p : sendTo) sendPacket(p, info.getHandle());
NMSHandlers.getHandler().getPacketHandler().sendFakePlayerInfoPacket(skinnedPlayer, entityId, uuid, npcName, sendTo);
}
/**
@@ -344,23 +232,7 @@ public class HMCCPacketManager extends PacketManager {
https://wiki.vg/Entity_metadata#Entity
*/
final byte mask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x40;
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, playerId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(17, WrappedDataWatcher.Registry.get(Byte.class)), mask);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(17, WrappedDataWatcher.Registry.get(Byte.class), mask));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (final Player p : sendTo) {
sendPacket(p, packet);
}
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(playerId, Map.of(17, mask), sendTo);
}
/**
@@ -375,24 +247,7 @@ public class HMCCPacketManager extends PacketManager {
final UUID uuid,
final List<Player> sendTo
) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
WrapperPlayServerPlayerInfo info = new WrapperPlayServerPlayerInfo();
// Remove player is deprecated on 1.19.3+, but we still need to support 1.18.2
info.setAction(EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
String name = "Mannequin-" + player.getEntityId();
while (name.length() > 16) {
name = name.substring(16);
}
info.setData(List.of(new PlayerInfoData(new WrappedGameProfile(uuid, player.getName()), 0, EnumWrappers.NativeGameMode.CREATIVE, WrappedChatComponent.fromText(name))));
for (final Player p : sendTo) sendPacket(p, info.getHandle());
return;
}
PacketContainer packet = new PacketContainer(PacketType.Play.Server.PLAYER_INFO_REMOVE);
packet.getUUIDLists().write(0, List.of(uuid));
for (final Player p : sendTo) sendPacket(p, packet);
NMSHandlers.getHandler().getPacketHandler().sendPlayerInfoRemovePacket(uuid, sendTo);
}
public static void sendLeashPacket(
@@ -418,31 +273,52 @@ public class HMCCPacketManager extends PacketManager {
final boolean onGround,
@NotNull List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.REL_ENTITY_MOVE);
WrapperPlayServerRelEntityMove wrapper = new WrapperPlayServerRelEntityMove(packet);
wrapper.setEntityID(entityId);
wrapper.setDx(to.getX() - from.getX());
wrapper.setDy(to.getY() - from.getY());
wrapper.setDz(to.getZ() - from.getZ());
wrapper.setOnGround(onGround);
for (final Player p : sendTo) {
sendPacket(p, wrapper.getHandle());
}
NMSHandlers.getHandler().getPacketHandler().sendMovePacket(entityId, from, to, onGround, sendTo);
}
// For future transition to display entities
public static void sendDisplayEntityMetadataPacket(
int entityid,
ItemStack backpackItem,
List<Player> sendTo) {
// TODO: Make the default values adjustable
Vector3f translation = new Vector3f(0, 3, 0);
Vector3f scale = new Vector3f(1, 1, 1);
Quaternionf rotationLeft = new Quaternionf();
Quaternionf rotationRight = new Quaternionf();
Display.Billboard billboard = Display.Billboard.FIXED;
int blockLight = 15;
int skylight = 15;
int viewRange = Settings.getViewDistance();
int width = 0;
int height = 0;
ItemDisplay.ItemDisplayTransform transform = ItemDisplay.ItemDisplayTransform.HEAD;
NMSHandlers.getHandler().getPacketHandler().sendItemDisplayMetadata(
entityid,
translation,
scale,
rotationLeft,
rotationRight,
billboard,
blockLight,
skylight,
viewRange,
width,
height,
transform,
backpackItem,
sendTo
);
}
/**
* Gets the nearby players (or viewers) of a location through the view distance set in the config. If the view distance is 0, it will return all players in the world.
* @param location
* @return
*/
@NotNull
public static List<Player> getViewers(Location location) {
ArrayList<Player> viewers = new ArrayList<>();
if (Settings.getViewDistance() <= 0) {
viewers.addAll(location.getWorld().getPlayers());
} else {
viewers.addAll(HMCCPlayerUtils.getNearbyPlayers(location));
}
return viewers;
}
public static void sendPacket(Player player, PacketContainer packet) {
if (player == null) return;
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet, null,false);
public static List<Player> getViewers(@NotNull Location location) {
return PacketManager.getViewers(location, Settings.getViewDistance());
}
}

View File

@@ -1,92 +0,0 @@
package com.hibiscusmc.hmccosmetics.util.packets.wrappers;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.base.Objects;
import org.bukkit.entity.Player;
// Courtesy of Packet Wrapper
public class AbstractPacket {
// The packet we will be modifying
protected PacketContainer handle;
/**
* Constructs a new strongly typed wrapper for the given packet.
*
* @param handle - handle to the raw packet data.
* @param type - the packet type.
*/
protected AbstractPacket(PacketContainer handle, PacketType type) {
// Make sure we're given a valid packet
if (handle == null)
throw new IllegalArgumentException("Packet handle cannot be NULL.");
if (!Objects.equal(handle.getType(), type))
throw new IllegalArgumentException(handle.getHandle()
+ " is not a packet of type " + type);
this.handle = handle;
}
/**
* Retrieve a handle to the raw packet data.
*
* @return Raw packet data.
*/
public PacketContainer getHandle() {
return handle;
}
/**
* Send the current packet to the given receiver.
*
* @param receiver - the receiver.
* @throws RuntimeException If the packet cannot be sent.
*/
public void sendPacket(Player receiver) {
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver,
getHandle());
}
/**
* Send the current packet to all online players.
*/
public void broadcastPacket() {
ProtocolLibrary.getProtocolManager().broadcastServerPacket(getHandle());
}
/**
* Simulate receiving the current packet from the given sender.
*
* @param sender - the sender.
* @throws RuntimeException If the packet cannot be received.
* @deprecated Misspelled. recieve to receive
* @see #receivePacket(Player)
*/
@Deprecated
public void recievePacket(Player sender) {
try {
ProtocolLibrary.getProtocolManager().receiveClientPacket(sender,
getHandle());
} catch (Exception e) {
throw new RuntimeException("Cannot recieve packet.", e);
}
}
/**
* Simulate receiving the current packet from the given sender.
*
* @param sender - the sender.
* @throws RuntimeException if the packet cannot be received.
*/
public void receivePacket(Player sender) {
try {
ProtocolLibrary.getProtocolManager().receiveClientPacket(sender,
getHandle());
} catch (Exception e) {
throw new RuntimeException("Cannot receive packet.", e);
}
}
}

View File

@@ -1,165 +0,0 @@
package com.hibiscusmc.hmccosmetics.util.packets.wrappers;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class WrapperPlayServerNamedEntitySpawn extends AbstractPacket {
public static final PacketType TYPE =
PacketType.Play.Server.NAMED_ENTITY_SPAWN;
public WrapperPlayServerNamedEntitySpawn() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerNamedEntitySpawn(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve Entity ID.
* <p>
* Notes: entity's ID
*
* @return The current Entity ID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Set Entity ID.
*
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the entity of the painting that will be spawned.
*
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity of the painting that will be spawned.
*
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(@NotNull PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Retrieve Player UUID.
* <p>
* Notes: player's UUID
*
* @return The current Player UUID
*/
public UUID getPlayerUUID() {
return handle.getUUIDs().read(0);
}
/**
* Set Player UUID.
*
* @param value - new value.
*/
public void setPlayerUUID(UUID value) {
handle.getUUIDs().write(0, value);
}
/**
* Retrieve the position of the spawned entity as a vector.
*
* @return The position as a vector.
*/
public Vector getPosition() {
return new Vector(getX(), getY(), getZ());
}
/**
* Set the position of the spawned entity using a vector.
*
* @param position - the new position.
*/
public void setPosition(@NotNull Vector position) {
setX(position.getX());
setY(position.getY());
setZ(position.getZ());
}
public double getX() {
return handle.getDoubles().read(0);
}
public void setX(double value) {
handle.getDoubles().write(0, value);
}
public double getY() {
return handle.getDoubles().read(1);
}
public void setY(double value) {
handle.getDoubles().write(1, value);
}
public double getZ() {
return handle.getDoubles().read(2);
}
public void setZ(double value) {
handle.getDoubles().write(2, value);
}
/**
* Retrieve the yaw of the spawned entity.
*
* @return The current Yaw
*/
public float getYaw() {
return (handle.getBytes().read(0) * 360.F) / 256.0F;
}
/**
* Set the yaw of the spawned entity.
*
* @param value - new yaw.
*/
public void setYaw(float value) {
handle.getBytes().write(0, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve the pitch of the spawned entity.
*
* @return The current pitch
*/
public float getPitch() {
return (handle.getBytes().read(1) * 360.F) / 256.0F;
}
/**
* Set the pitch of the spawned entity.
*
* @param value - new pitch.
*/
public void setPitch(float value) {
handle.getBytes().write(1, (byte) (value * 256.0F / 360.0F));
}
}

View File

@@ -1,44 +0,0 @@
package com.hibiscusmc.hmccosmetics.util.packets.wrappers;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.hibiscusmc.hmccosmetics.api.HMCCosmeticsAPI;
import java.util.List;
import java.util.Set;
public class WrapperPlayServerPlayerInfo extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.PLAYER_INFO;
public WrapperPlayServerPlayerInfo() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerPlayerInfo(PacketContainer packet) {
super(packet, TYPE);
}
public PlayerInfoAction getAction() {
return handle.getPlayerInfoAction().read(0);
}
public void setAction(PlayerInfoAction value) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_17_R1") || HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
handle.getPlayerInfoAction().write(0, value);
return;
}
// New way of handling it 1.19.3+
handle.getPlayerInfoActions().write(0, Set.of(value));
}
public List<PlayerInfoData> getData() {
return handle.getPlayerInfoDataLists().read(0);
}
public void setData(List<PlayerInfoData> value) {
handle.getPlayerInfoDataLists().write(0, value);
}
}

View File

@@ -1,170 +0,0 @@
package com.hibiscusmc.hmccosmetics.util.packets.wrappers;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
public class WrapperPlayServerRelEntityMove extends AbstractPacket {
public static final PacketType TYPE =
PacketType.Play.Server.REL_ENTITY_MOVE;
public WrapperPlayServerRelEntityMove() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerRelEntityMove(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve Entity ID.
* <p>
* Notes: entity's ID
*
* @return The current Entity ID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Set Entity ID.
*
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the entity of the painting that will be spawned.
*
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity of the painting that will be spawned.
*
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(@NotNull PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Retrieve DX.
*
* @return The current DX
*/
public double getDx() {
return handle.getShorts().read(0) / 4096D;
}
/**
* Set DX.
*
* @param value - new value.
*/
public void setDx(double value) {
handle.getShorts().write(0, (short) (value * 4096));
}
/**
* Retrieve DY.
*
* @return The current DY
*/
public double getDy() {
return handle.getShorts().read(1) / 4096D;
}
/**
* Set DY.
*
* @param value - new value.
*/
public void setDy(double value) {
handle.getShorts().write(1, (short) (value * 4096));
}
/**
* Retrieve DZ.
*
* @return The current DZ
*/
public double getDz() {
return handle.getShorts().read(2) / 4096D;
}
/**
* Set DZ.
*
* @param value - new value.
*/
public void setDz(double value) {
handle.getShorts().write(2, (short) (value * 4096));
}
/**
* Retrieve the yaw of the current entity.
*
* @return The current Yaw
*/
public float getYaw() {
return (handle.getBytes().read(0) * 360.F) / 256.0F;
}
/**
* Set the yaw of the current entity.
*
* @param value - new yaw.
*/
public void setYaw(float value) {
handle.getBytes().write(0, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve the pitch of the current entity.
*
* @return The current pitch
*/
public float getPitch() {
return (handle.getBytes().read(1) * 360.F) / 256.0F;
}
/**
* Set the pitch of the current entity.
*
* @param value - new pitch.
*/
public void setPitch(float value) {
handle.getBytes().write(1, (byte) (value * 256.0F / 360.0F));
}
/**
* Retrieve On Ground.
*
* @return The current On Ground
*/
public boolean getOnGround() {
return handle.getBooleans().read(0);
}
/**
* Set On Ground.
*
* @param value - new value.
*/
public void setOnGround(boolean value) {
handle.getBooleans().write(0, value);
}
}

Some files were not shown because too many files have changed in this diff Show More