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

Compare commits

...

630 Commits

Author SHA1 Message Date
Logan
0e2b2edadd chore: fix not importing annotation in CosmeticBackpackType 2025-12-17 13:03:08 -06:00
Logan
7e384fcd79 Merge pull request #204 from HibiscusMC/itemmodel-placeholder
feat: add itemmodel & itemname placeholders, bump api to 1.21.4 with …
2025-12-17 11:09:09 -06:00
Logan
e88b84610e version bump (2.8.3) 2025-12-17 11:06:30 -06:00
lucian929
223ffa46eb chore: change references to glyphs 2025-12-17 11:48:44 -05:00
Logan
f408108682 chore: remove emote distance still variable in Settings 2025-12-17 10:13:26 -06:00
Logan
b9f9448367 chore: move some comments around 2025-12-16 13:08:56 -06:00
Logan
c40aca9946 feat: remove entity-cooldown-teleport-packet option as it is no longer used 2025-12-16 13:07:03 -06:00
Logan
98d2692def fix: dispatch update also updates location for viewers 2025-12-16 13:03:54 -06:00
Logan
ebbc80c465 chore: add what usage api users should use in javadocs in cosmetic deprecated methods 2025-12-16 12:54:48 -06:00
Logan
775699d9ca chore: define nullability of behavior impl 2025-12-16 12:52:41 -06:00
Logan
b0ba5fc011 chore: CosmeticUser move to non-deprecated internal methods to add cosmetics (and indicate nullability of update movement variables) 2025-12-16 12:49:44 -06:00
Logan
af01ff600b chore: move to paper advneture impl 2025-12-16 12:14:02 -06:00
Logan
2e4619da02 fix: import proper nullable in UserBackpackManager 2025-12-16 12:12:06 -06:00
Logan
b4bd08c249 chore: refactor UserSearchManager to PlayerSearchManager 2025-12-16 12:06:21 -06:00
Logan
19981b33d3 fix: better teleport listening 2025-12-16 12:00:24 -06:00
Logan
c7c4c0e583 chore: add multiverse to test server 2025-12-16 11:59:22 -06:00
Logan
935c157421 chore: remove player animator being implemented? 2025-12-14 13:07:21 -06:00
Boy0000
20a3a508c2 refactor: remove AttributeWrapper 2025-11-11 02:40:25 +01:00
Boy0000
92b75c43ab feat: add itemmodel & itemname placeholders, bump api to 1.21.4 with attribute wrapper 2025-11-11 01:39:33 +01:00
Logan
a6ad2c19aa fix: fix client crashes for wardrobe on 1.21.10 2025-11-10 16:49:41 -06:00
Logan
fe8b4c97ff Merge pull request #201 from SolaraGames/fix-api
fix api
2025-10-13 14:29:51 -05:00
Tech
8c119c78db fix api 2025-10-13 14:58:02 -04:00
Logan
ce33a72fc2 chore: update Hibiscus Commons 2025-10-13 11:25:45 -05:00
Tech
2a8f30636d nullability checks (#200) 2025-10-13 18:06:00 +02:00
Logan
4103c2c232 Merge pull request #199 from SolaraGames/fix-memory-leak
fix memory leak
2025-10-12 15:01:13 -05:00
Tech
fb5c9d205c fix memory leak 2025-10-12 16:00:08 -04:00
Logan
126d576303 Merge pull request #198 from SolaraGames/optimize-viewer
Optimize Cosmetics
2025-10-12 14:37:17 -05:00
Tech
c74b76837b fix npe 2025-10-12 01:49:17 -04:00
Tech
d2c37f8273 optimize movement cosmetics 2025-10-12 01:42:32 -04:00
Logan
dbadbda82f chore: disable passenger packet 2025-10-11 22:22:23 -05:00
Logan
d66aa3b79c chore: update luckperms on test server 2025-10-04 22:53:38 -05:00
Logan
1c5cd7b467 chore: minor refactoring of db code 2025-09-25 20:03:05 -05:00
Logan
10f8dda150 fix: dye menu through command not checking if there is a provider available 2025-09-21 15:00:03 -05:00
Logan
e76aa0783e chore: refactor passenger content code 2025-09-12 19:31:19 -05:00
Logan
0676125f07 chore: refactor backpacks files 2025-09-08 14:58:15 -05:00
Logan
7aef681149 feat: refactor UserEntity refreshViewers 2025-09-07 21:44:44 -05:00
Logan
d5ac55f266 chore: update hibiscus commons 2025-09-07 21:38:11 -05:00
Logan
c2b787c97c feat: tomfollery with backpacks, external and regular backpacks appear to work now, but first-person backpacks are still experiencing jank 2025-09-07 21:35:37 -05:00
Logan
732c3de0d8 feat: use new hibiscus commons method for pufferfish spawning 2025-09-07 21:34:38 -05:00
Logan
3843a28804 feat: reenable passenger packet listener 2025-09-07 14:51:36 -05:00
Logan
a63494ba9f feat: make prevent offhand swapping configurable and is now disabled by default, resolves #192 2025-09-07 14:05:29 -05:00
Logan
c7e6a77eb8 chore: remove ai from balloon armorstand 2025-09-07 13:46:11 -05:00
Logan
075d2b3182 fix: move mob key to be a public value and be more specific 2025-09-07 13:36:31 -05:00
Logan
515de7d2c8 feat: add event for cancelling interactions with balloon armorstand 2025-09-07 09:44:53 -05:00
Logan
429287c9f3 feat: only try running spawning invisible armorstands when there is outside viewers to send it to 2025-09-06 23:44:49 -05:00
Logan
fed13b8ee6 feat: wardrobe npc now respects scale 2025-09-06 23:25:56 -05:00
Logan
8011dda200 feat: use new Hibiscus Commons methods for packets 2025-09-06 23:19:31 -05:00
Logan
7abfb0edf1 chore: turn item processing off by default 2025-09-06 23:18:48 -05:00
Logan
1f8c772712 chore: bump to latest Hibiscus Commons 2025-09-06 23:18:24 -05:00
Logan
7d727bb68f Merge pull request #191 from NoltoxGit/remapped
Reformat config.yml
2025-08-28 16:20:56 -05:00
Logan
007f27f109 chore: nexo reload on change 2025-08-28 16:20:47 -05:00
Poy
e0e0d0c997 Add quotes to string values in config.yml
Updated YAML configuration to use quotes for string values.
2025-08-28 21:56:42 +02:00
Poy
75a1458ae1 Fix config (jd.papermc.io) 2025-08-28 21:55:12 +02:00
Logan
548b15d99d chore: bump HibiscusCommons 2025-08-27 10:56:56 -05:00
Logan
50f04373b7 chore: add gsit to the test server 2025-08-24 12:25:06 -05:00
Logan
27a6c1bd54 feat: better handling of invalid cosmetics for dye subcommand 2025-08-18 20:44:16 -05:00
Logan
bb08fb108c feat: better handling of custom dye implementations with HMCColor 2025-08-18 20:41:26 -05:00
Logan
3907bc5839 version bump (2.8.2) 2025-08-18 20:36:53 -05:00
Logan
1ef7f4759f fix: balloon lead not properly disappearing when you unapply a balloon cosmetic 2025-08-17 16:22:32 -05:00
Logan
937f66e8c5 version bump (2.8.1) 2025-08-17 14:43:59 -05:00
Logan
158f3afdec chore: update test server 2025-08-17 14:43:44 -05:00
Logan
38bdc01e9f Merge remote-tracking branch 'origin/remapped' into remapped 2025-08-16 13:30:16 -05:00
Logan
797992362a feat: allow custom dye menu implementations 2025-08-16 13:30:10 -05:00
Logan
9716a079be Merge pull request #189 from Catnies/dev
fix PlayerMenuOpenEvent can't cancel
2025-08-06 16:30:24 -05:00
LoJoSho
dfe51ba5b8 fix: user initialization not checking potion effects 2025-08-06 16:27:27 -05:00
Catnies
f5e81446a6 fix PlayerMenuOpenEvent can't cancel 2025-08-05 14:34:07 +08:00
LoJoSho
c99a57a6bf chore: update adventure dependencies 2025-08-01 22:01:31 -05:00
LoJoSho
79630263f2 chore: exclude lin-bus from worldguard depend 2025-08-01 21:59:30 -05:00
LoJoSho
478c4280c1 feat: finally fully remove mainhand cosmetic 2025-07-19 15:36:11 -05:00
LoJoSho
4fd439acc4 chore: backpack force riding backpack set on by default 2025-07-12 10:32:38 -05:00
LoJoSho
58c955a00f feat: expose the config for a cosmetic if available 2025-07-09 18:06:22 -05:00
Oak
2f9325b2fb Added scale attribute support to backpacks (#186) 2025-07-05 16:15:01 -05:00
LoJoSho
823270648b Merge remote-tracking branch 'origin/remapped' into remapped 2025-07-04 11:59:44 -05:00
LoJoSho
d5e988261b chore: update to 1.21.7 on test server 2025-07-04 11:59:35 -05:00
Logan
13303096ec chore: shading should be off by default 2025-07-04 10:27:20 -05:00
LoJoSho
3ee79e8443 fix: passenger packet interceptor appears to cause instability, disabling for now 2025-07-01 14:50:42 -05:00
LoJoSho
7785556967 chore: remove unused variable 2025-07-01 14:49:39 -05:00
LoJoSho
1296ca6e92 fix: calculating yaw twice causing bad yaw to be sent in rotations 2025-07-01 13:47:50 -05:00
LoJoSho
f56d5c9093 chore: more debug messages on equip 2025-06-28 17:59:23 -05:00
LoJoSho
bae04fba3f chore: update to latest hibiscus commons 2025-06-28 15:30:47 -05:00
LoJoSho
cbe5404399 fix: hibiscus commons version 2025-06-27 15:47:49 -05:00
LoJoSho
dc4098782a fix: latest crash fixes (with latest hibiscus commons) 2025-06-27 15:44:17 -05:00
LoJoSho
2eb0b26fb3 fix: plugin not properly saving resources 2025-06-27 15:15:48 -05:00
LoJoSho
22159fa9f4 fix: duplicate entity ids in passengers 2025-06-27 10:18:35 -05:00
LoJoSho
539c09801c chore: remove cooldown on teleport packet 2025-06-27 08:53:58 -05:00
Logan
bed5cd7bbb Merge pull request #185 from HibiscusMC/commons07
feat: overhaul to new Hibiscus commons packet system
2025-06-26 15:43:12 -05:00
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
LoJoSho
35260d4abb Merge remote-tracking branch 'origin/remapped' into remapped 2024-04-27 09:06:34 -05:00
LoJoSho
2d44435d53 fix: hmccolor dye menu not processing through minimessage 2024-04-27 09:06:21 -05:00
LoJoSho
3d785bd157 version bump (2.7.3-DEV) 2024-04-27 09:04:39 -05:00
lucian929
c33cfbd302 fix: update default config to use proper input slots for color 2024-04-25 15:24:22 -04:00
LoJoSho
f5ed39e02c Merge remote-tracking branch 'origin/remapped' into remapped 2024-04-25 14:09:44 -05:00
LoJoSho
0c3af0e0cd version bump (2.7.2) 2024-04-25 14:09:22 -05:00
lucian929
f5a1a67e1e chore: remove emotes from defaultmenu 2024-04-25 14:13:47 -04:00
LoJoSho
ddc0a504fd fix: disabled worlds not checked if player teleports through portals 2024-04-25 12:12:27 -05:00
LoJoSho
de108753d5 clean: ignore cancelled teleportations 2024-04-02 22:04:40 -05:00
LoJoSho
b31e8b7a4b chore: more documentation for CosmeticUsers class 2024-04-02 22:02:51 -05:00
LoJoSho
383fdfa7f6 fix: no entity + backpack spawning causing NPE 2024-03-16 12:13:07 -05:00
LoJoSho
54e867ab0b Merge pull request #131 from HibiscusMC/allow-flight
fix: wardrobe kicking player if allowFlight not enabled in server.pro…
2024-03-11 08:40:46 -05:00
LoJoSho
068ed3eb70 fix: backpacks not reattaching after teleporting 2024-03-05 22:26:10 -06:00
LoJoSho
a203c60df1 fix: backpacks turning black when under blocks 2024-03-05 10:58:12 -06:00
LoJoSho
e13c3fccb4 fix: hidden flags being added async causing error 2024-02-25 17:51:06 -06:00
LoJoSho
add72e66c9 feat: hidden reasons now in lists, add disableall command (hides all players cosmetics) 2024-02-25 15:20:32 -06:00
LoJoSho
0e587feff0 fix: multiple schedulers when player has multiple loaded cosmetics 2024-02-21 12:42:57 -06:00
LoJoSho
27be86c419 fix: clean resources after sql usage 2024-02-20 13:53:10 -06:00
Boy
3d940d8468 fix: wardrobe kicking player if allowFlight not enabled in server.properties 2024-02-10 13:20:36 +01:00
LoJoSho
7515cdd137 refactor: getHidden to isHidden in CosmeticUser class, deprecate old method 2024-02-04 20:07:01 -06:00
LoJoSho
8e92f3e689 fix: hidden reasons for gamemodes + world not working, spawning entity cosmetics while hidden 2024-02-04 20:04:33 -06:00
LoJoSho
7c4b833d80 fix: tab autocomplete checks attempted before user loading causing NPE 2024-02-04 19:20:37 -06:00
LoJoSho
b291dc4c9f Merge remote-tracking branch 'origin/remapped' into remapped 2024-01-28 10:57:30 -06:00
LoJoSho
60b91df843 fix: balloons with head models pitch being affected by player 2024-01-28 10:56:49 -06:00
LoJoSho
56f380025d fix: equipped armor not showing after exiting wardrobe 2024-01-17 13:07:01 -06:00
LoJoSho
b3e0acbcbd feat: add config options to prevent damage while in the wardrobe 2024-01-17 12:45:04 -06:00
LoJoSho
e2d334db9d version bump (2.7.2-DEV) 2024-01-17 12:25:03 -06:00
LoJoSho
dffcf6213b fix: check if player is not null before running end wardrobe 2024-01-17 12:24:41 -06:00
Boy
485f5837f4 fix: bump HMCColor & implement API-changes 2024-01-14 01:55:34 +01:00
LoJoSho
442cddb81e version bump (2.7.0) 2024-01-12 11:45:03 -06:00
Boy
1f38d1aa46 chore: bump hmccolor 2024-01-10 01:52:27 +01:00
LoJoSho
ce7dc03350 fix: player dying causing NPE 2024-01-06 11:09:21 -06:00
LoJoSho
9a75fcb55b fix: check if player is still online after join delay 2024-01-05 13:36:12 -06:00
LoJoSho
5522eed2d1 fix: pose changes in wardrobe causes backpack being unattached 2024-01-03 12:38:17 -06:00
LoJoSho
1737330b87 feat: balloons now disappear when hidden 2024-01-02 21:10:38 -06:00
LoJoSho
eff25664f3 clean: move gamemode and world hidden checks to player join 2024-01-02 21:10:06 -06:00
LoJoSho
27d3a1df42 feat: add disabled worlds option 2024-01-02 20:45:18 -06:00
LoJoSho
63bda02869 fix: hidden backpacks still having armorstands spawned 2024-01-02 20:34:25 -06:00
LoJoSho
8c251a8c69 clean: add debug messages for respawning of cosmetics 2024-01-02 11:10:36 -06:00
LoJoSho
4b481ef3ea clean: refactor overlapping Hibiscus Commons util class names 2023-12-29 12:19:00 -06:00
LoJoSho
2d62c96d3d Merge pull request #129 from HibiscusMC/hibiscuscommons
Refactor to Hibiscus Commons Library (2.7.0)
2023-12-29 12:13:49 -06:00
LoJoSho
f8cb436c5b fix: handle IA reloading 2023-12-28 20:49:23 -06:00
LoJoSho
0de31fcd04 chore: update hibiscus commons to 0.2.1 2023-12-28 19:07:59 -06:00
LoJoSho
99edb501a5 fix: itemsadder reload 2023-12-28 19:07:46 -06:00
LoJoSho
66aaed009f fix: players being invisible if disconnect in wardrobe 2023-12-27 10:54:08 -06:00
LoJoSho
4c0b86b127 chore: updates adventure platform to 4.3.2 2023-12-27 10:22:52 -06:00
LoJoSho
155133a2a0 fix: players opening menu in setup phase of wardrobes 2023-12-27 09:50:58 -06:00
LoJoSho
93062d47a8 fix: cosmetic armor happening in wardrobe 2023-12-27 09:46:59 -06:00
LoJoSho
1f0c67a805 clean: remove cmi jars 2023-12-24 21:30:27 -06:00
LoJoSho
74feb112f6 feat: remove nms in HMCC, update to support Hibiscus Commons 0.1.8 2023-12-23 12:37:20 -06:00
LoJoSho
967349f5af version bump (2.7.0-DEV) 2023-12-23 12:01:31 -06:00
LoJoSho
d7fe2475ed Merge branch 'remapped' into hibiscuscommons 2023-12-23 11:58:46 -06:00
Boy
f87bf93641 fix: check instance instead of id for shading 2023-12-23 18:56:17 +01:00
LoJoSho
4b467b4644 fix: check instance instead of id for shading 2023-12-23 11:54:20 -06:00
LoJoSho
15234a904f clean: remove barely used text emote feature 2023-12-22 22:09:22 -06:00
LoJoSho
9ff6d3f60c feat: balloon entities entirely through bukkit 2023-12-22 22:05:09 -06:00
LoJoSho
aeba867e9e chore: update adventure classes 2023-12-22 21:57:30 -06:00
LoJoSho
d21e148f39 chore: update HibiscusCommons to 0.1.7 2023-12-22 21:50:47 -06:00
LoJoSho
51188fdeba feat: move to Hibiscus Commmons library 2023-12-22 21:25:50 -06:00
LoJoSho
dcf072f3de fix: balloons and backpacks being respawned while in wardrobe 2023-12-20 15:38:32 -06:00
LoJoSho
ebf09d8e0f fix: check if user is still in wardrobe before spawning npc 2023-12-20 15:38:02 -06:00
LoJoSho
ca5cb25331 clean: move configurate back to being shaded 2023-12-20 14:02:58 -06:00
LoJoSho
65877bff5b clean: move nms spawn balloon method to CosmeticUser 2023-12-19 19:55:57 -06:00
LoJoSho
4a75c7b333 Merge remote-tracking branch 'origin/remapped' into remapped 2023-12-19 19:48:02 -06:00
Boy
be4f1d6675 chore: add TypeCosmetic-initializer with id-argument for extending class 2023-12-20 02:47:33 +01:00
LoJoSho
55d4f9ae09 clean: move private bulkUpdate method to updateCosmetic since it was just using that method anyways 2023-12-19 19:28:06 -06:00
LoJoSho
88691956ba fix: locked-item not appearing in wardrobes with unchecked cosmetics 2023-12-19 18:39:54 -06:00
LoJoSho
a6133a2b45 clean: remove triumph gui from library loader (was used for testing in last build) 2023-12-19 18:00:15 -06:00
LoJoSho
0aa821e51a feat: move adventure and configurate to Spigots library loader 2023-12-19 15:17:41 -06:00
LoJoSho
fb37ea8af9 clean: removed unused relocations 2023-12-19 14:49:15 -06:00
LoJoSho
0f36803026 feat: add PlayerArmorChangeEvent for Paper servers 2023-12-18 19:40:28 -06:00
LoJoSho
2910540c26 fix: enchants not being passed to cosmetics 2023-12-18 19:23:53 -06:00
LoJoSho
93fb885195 fix: further wardrobe armor fixes for Optifine clients 2023-12-18 19:04:25 -06:00
LoJoSho
2438d5385f clean: add eco as soft depend 2023-12-18 14:51:14 -06:00
LoJoSho
73ce071427 feat: add HookFlags to hooks 2023-12-18 13:35:40 -06:00
LoJoSho
e3485b7733 fix: forgot to reverse order when condensing the method 2023-12-18 13:20:02 -06:00
LoJoSho
7ff4fbb3d7 feat: add support for Eco item lookup system 2023-12-18 13:19:43 -06:00
LoJoSho
de5b9be6ac fix: server-side teleporation causing players to be stuck in wardrobe area 2023-12-18 12:52:35 -06:00
LoJoSho
0c6e8eb160 fix: bad clients failing to removing player model in wardrobe 2023-12-18 12:52:07 -06:00
LoJoSho
9b85fd2d8c feat: player teleport when entering wardrobe, allows better support for long distance wardrobes 2023-12-17 22:41:12 -06:00
LoJoSho
a136b95451 clean: remove deperecated #getCosmetic 2023-12-17 11:24:31 -06:00
LoJoSho
cf5eb64029 feat: priority system for menus 2023-12-16 18:30:58 -06:00
LoJoSho
c4591b030b feat: reduced packets for armor cosmetics 2023-12-16 16:13:52 -06:00
LoJoSho
9dc6eb1dfc version bump (2.6.7-DEV) 2023-12-16 09:52:27 -06:00
LoJoSho
d7c1bf39e2 version bump (2.6.6) 2023-12-16 09:49:40 -06:00
LoJoSho
ae1527fca3 feat: add 1.20.3/4 nms support 2023-12-10 13:02:04 -06:00
LoJoSho
d14698b282 clean: get static context correctly in main plugin class 2023-11-22 17:09:08 -06:00
LoJoSho
800d3be25f clean: removed formatArmorItemType method in StringUtils 2023-11-22 17:04:45 -06:00
LoJoSho
27599030cf clean: optimize imports 2023-11-22 16:59:49 -06:00
LoJoSho
3ee959abd6 feat: add HMCColor support in commands, resolves #114 2023-11-20 17:05:23 -06:00
LoJoSho
617df48cc2 feat: add amount placeholder, resolves #127 2023-11-20 16:09:52 -06:00
LoJoSho
9e290c2dfd version bump (2.6.6-DEV) 2023-11-20 16:07:49 -06:00
LoJoSho
f98614c4ee Merge remote-tracking branch 'origin/remapped' into remapped 2023-11-15 11:41:06 -06:00
LoJoSho
d28bb23f8c version bump (2.6.5) 2023-11-15 11:40:55 -06:00
Boy
502cb533f8 fix: drop runOnOrAfter for GearyHook 2023-11-05 01:05:38 +01:00
LoJoSho
b7fdc2087a fix: removed no longer needed entity id check on damage, caused conflicts with MythicMobs 2023-11-04 08:44:36 -05:00
LoJoSho
10a42a3c96 feat: papi placeholders now work for heads in menus 2023-10-29 14:01:28 -05:00
LoJoSho
51fc52e24b feat: add config option to disable cosmetics in certain gamemodes 2023-10-27 20:34:07 -05:00
LoJoSho
be632d8e8c fix: ME4 balloons not hiding for player 2023-10-27 19:50:34 -05:00
LoJoSho
a732a2b0a0 clean: remove hikari repo, set CommentedConfiguration to specific commit to fix Jitpack jank 2023-10-27 19:44:59 -05:00
Boy
b14a0b5d16 update geary-hook 2023-10-27 16:44:31 +02:00
LoJoSho
50393c62b0 fix: offhand cosmetics not checking if item is air 2023-10-26 13:38:48 -05:00
LoJoSho
dbc4a07895 fix: empty menu type not adding papi placeholders 2023-10-16 11:16:57 -05:00
LoJoSho
ab329e4fbf feat: define what offline and invalid player return in translations 2023-10-15 11:05:29 -05:00
LoJoSho
90ad700d0a feat: define no-cosmetic and none differently in translations 2023-10-15 10:41:45 -05:00
LoJoSho
56529d6111 Merge remote-tracking branch 'origin/remapped' into remapped 2023-10-15 10:32:29 -05:00
LoJoSho
b6a06007e8 Merge remote-tracking branch 'origin/remapped' into remapped 2023-10-15 10:31:54 -05:00
LoJoSho
edccc9ce4e fix: (last commit) forgot to reverse check 2023-10-15 10:28:54 -05:00
LoJoSho
e0b2f0f6b1 fix: improve nms version checker 2023-10-14 14:47:05 -05:00
LoJoSho
57f4d3703c fix: current placeholder returning null when no cosmetics are equipped 2023-10-13 11:47:14 -05:00
LoJoSho
8ef6692198 fix: emotes on lower versions not initializing 2023-10-13 10:41:39 -05:00
LoJoSho
c48830f3ac fix: move to configurate for full yml loading 2023-10-13 10:38:58 -05:00
LoJoSho
734c04c1f4 feat: me4 balloons working? 2023-10-11 21:46:17 -05:00
LoJoSho
b08b4019a9 clean: latest changes to try to get me4 working 2023-10-10 12:32:43 -05:00
LoJoSho
cfb7876b6e fix: player packet merged into entity packet in 1.20.2 2023-10-06 16:13:41 -05:00
LoJoSho
6047d0e3c3 clean: update me to 4.0.2 2023-10-06 15:20:59 -05:00
LoJoSho
880c333df9 Merge branch 'remapped' into me4 2023-10-06 14:56:16 -05:00
LoJoSho
c4d7b657dd feat: add option to disable emotes entirely 2023-10-06 12:44:59 -05:00
LoJoSho
5be3ce8d21 Merge remote-tracking branch 'origin/remapped' into remapped 2023-10-06 12:33:55 -05:00
LoJoSho
33bba631fc feat: model engine 4 2023-10-02 15:55:21 -05:00
LoJoSho
775b9c299d feat: basic 1.20.2 support 2023-09-24 10:59:24 -05:00
LoJoSho
6e02331c13 version bump (2.6.5-DEV) 2023-09-24 10:40:45 -05:00
LoJoSho
b7457cec9c Merge remote-tracking branch 'origin/remapped' into remapped 2023-09-15 16:40:21 -05:00
lucian929
e7288a1910 fixed config issues for vanilla rp config 2023-09-15 17:39:30 -04:00
LoJoSho
26b90bd8bb version bump (2.6.5-DEV) 2023-09-13 11:03:46 -05:00
LoJoSho
24a10b6838 version bump (2.6.4) 2023-09-13 10:58:04 -05:00
LoJoSho
af7bc0dc3f feat: add hmccosmetics and cosmetic aliases 2023-09-09 12:52:53 -05:00
LoJoSho
162d4a6ed6 fix: setting viewlocation now sets from eye level location 2023-09-09 12:34:53 -05:00
LoJoSho
41140f60c5 fix: distances referencing display radius when that no longer exists in config 2023-09-09 12:31:20 -05:00
LoJoSho
a6145a607c clean: move to integer parse 2023-09-09 11:38:52 -05:00
LoJoSho
89c6951a93 fix: getOfflinePlayer always returns a notnull object 2023-09-09 11:38:02 -05:00
LoJoSho
28c466e342 clean: remove old inheritance that no longer matters 2023-09-09 11:35:37 -05:00
LoJoSho
90caa23cd7 clean: remove unneeded if statements 2023-09-09 11:27:49 -05:00
LoJoSho
910f223151 Merge remote-tracking branch 'origin/remapped' into remapped 2023-09-01 18:11:51 -05:00
LoJoSho
ac1b50a957 clean: remove old removal passenger logic from PlayerQuitEvent 2023-08-31 18:29:59 -05:00
LoJoSho
9cb9bad3c8 fix: rework of equipment packet modification to be more vanilla-like 2023-08-30 22:10:25 -05:00
LoJoSho
f68e2633a2 version bump (2.6.4-DEV) 2023-08-30 11:50:54 -05:00
LoJoSho
c8ad5c0881 version bump (2.6.3) 2023-08-30 11:17:24 -05:00
LoJoSho
c93a718799 fix: check if item is null 2023-08-30 09:55:40 -05:00
LoJoSho
b5f781e00f fix: add wardrobe section to ignorable config updater 2023-08-29 21:48:46 -05:00
LoJoSho
f6cd73f436 clean: remove now unused NMS methods relating to backpacks 2023-08-29 21:37:43 -05:00
LoJoSho
8b0fcc5da9 fix: balloon pufferfish not properly being destroyed out of range 2023-08-29 17:41:35 -05:00
LoJoSho
b5787f22bf fix: add distance and permission to default config 2023-08-29 14:50:10 -05:00
LoJoSho
c1c431d914 fix: process PAPI placeholders on player command action 2023-08-28 21:36:06 -05:00
LoJoSho
b41dc66508 fix: hotbar visually messing up if player spun scrolled fast enough 2023-08-28 10:58:44 -05:00
LoJoSho
cfbf74257b feat: add offhand-always-show option 2023-08-27 20:59:56 -05:00
LoJoSho
9b2083b90a version bump (2.6.3-DEV) 2023-08-27 20:59:37 -05:00
LoJoSho
33437cd387 version bump (2.6.2) 2023-08-27 13:52:50 -05:00
LoJoSho
9f4e4616d4 fix: entity metadata being set incorrectly on 1.19.3+ 2023-08-27 13:44:48 -05:00
LoJoSho
01c62bc94e feat: add MMOItems hook 2023-08-27 13:31:59 -05:00
LoJoSho
3be4bdeb6f clean: optimize imports 2023-08-27 13:09:05 -05:00
LoJoSho
145aec9b7f feat: entity cooldown teleportation packet option 2023-08-27 12:44:53 -05:00
LoJoSho
4a2266bbfa clean: a bit of work on packet listeners 2023-08-27 11:51:25 -05:00
LoJoSho
7fa3cd6cb7 clean: removed unused NMS methods 2023-08-27 10:11:59 -05:00
LoJoSho
9c5fe9c426 fix: offhand cosmetic visually going into mainhand for other players when swapping 2023-08-26 14:31:02 -05:00
LoJoSho
0a9d750d3e clean: wardrobe javadocs and Lombok 2023-08-26 10:37:21 -05:00
LoJoSho
da996fb146 version bump (2.6.2-DEV) 2023-08-26 10:17:41 -05:00
LoJoSho
c051b267cf version bump (2.6.1) 2023-08-25 21:51:48 -05:00
LoJoSho
d1fc84b5bc fix: non-thirdperson backpacks interactable 2023-08-25 15:27:42 -05:00
LoJoSho
b47b9d8235 clean: remove deprecated methods relating to static radius distance 2023-08-24 18:48:31 -05:00
LoJoSho
edccc844c9 fix: remove static radius from default config, it's deprecated 2023-08-24 18:42:21 -05:00
LoJoSho
5788b2cce0 version bump (2.6.1-DEV) 2023-08-24 18:39:39 -05:00
LoJoSho
627ebafb79 chore: remove description saying it supports Vanilla and ItemsAdder 2023-08-24 12:16:47 -05:00
lucian929
ef3bf3fc19 remove itemsadder info for menu shading till it works 2023-08-24 13:07:59 -04:00
LoJoSho
97c02883b8 fix: check for empty hand for offhand listener 2023-08-23 12:42:36 -05:00
LoJoSho
ad516e80d1 feat: improve handling of removing armor cosmetic 2023-08-23 11:15:01 -05:00
LoJoSho
317ee261db feat: force backpack riding packets 2023-08-23 11:04:07 -05:00
LoJoSho
5f8fb642a4 fix: deprecated and removal of usage of equipmentSlotUpdate in NMSHandler 2023-08-22 23:29:12 -05:00
LoJoSho
7f4a1bc3f2 clean: supress deprecated in getUserCosmeticItem 2023-08-22 23:28:21 -05:00
LoJoSho
e2a727864e fix: unchecked cosmetics in wardrobe showing unlocked in PAPI, resolves #123 2023-08-22 09:50:23 -05:00
LoJoSho
c0014476fd fix: wardrobe not properly spawning in backpacks 2023-08-22 09:49:19 -05:00
LoJoSho
8ec6a87b94 version bump (2.6.0) 2023-08-21 18:59:34 -05:00
LoJoSho
97cf079b63 fix: invisibility wearing off while swimming with backpack equipped causing NPE 2023-08-21 18:59:21 -05:00
LoJoSho
82f13c349f feat: packet backpacks 2023-08-19 14:30:29 -05:00
LoJoSho
f91c174b20 fix: console command not sending from console 2023-08-19 12:27:20 -05:00
LoJoSho
3ae6a11626 feat: console command now processes placeholders 2023-08-19 12:25:58 -05:00
LoJoSho
f2fab91916 feat: add option to move in emote when out of camera mode 2023-08-18 10:01:19 -05:00
LoJoSho
55890fa4ac feat: add getNMSVersion and getHMCCVersion to the API 2023-08-17 12:38:23 -05:00
LoJoSho
fa2aa2c6dc fix: spawned invalid entity trying to respawn itself after spawning itself 2023-08-17 12:28:33 -05:00
LoJoSho
0b5f986cfc fix: offhand cosmetics flickering 2023-08-17 12:27:59 -05:00
LoJoSho
26361b833f fix: shades not working between empty columns 2023-08-16 13:39:03 -05:00
LoJoSho
28a37848c8 feat: added option to disable emoting third person camera 2023-08-16 12:22:41 -05:00
LoJoSho
7131a45d9c feat: per-balloon cosmetic offsets 2023-08-16 10:30:46 -05:00
LoJoSho
6d9325ed18 feat: add ability to define height of first person backpacks 2023-08-14 12:03:31 -05:00
LoJoSho
0640b33d50 fix: update HMCColor to .8 2023-08-14 11:46:08 -05:00
Boy
8b944b8e29 fix geary 2023-08-14 15:26:03 +02:00
LoJoSho
4481fa1c12 fix: not returning causing NPE in equipped cosmetic placeholder 2023-08-11 09:36:55 -05:00
LoJoSho
de133fa288 clean: bump oraxen to 1.160.0 2023-08-11 09:15:31 -05:00
LoJoSho
20da7797c9 fix: equipped cosmetic placeholder returning untranslated string when no cosmetics is in slot 2023-08-08 20:31:33 -05:00
LoJoSho
2aed727832 fix: first person backpacks not passing color 2023-08-07 10:40:03 -05:00
LoJoSho
b6731ba21a clean: minor stuff in data 2023-08-06 10:49:14 -05:00
LoJoSho
d333527664 clean: move data strings to StringBuilder 2023-08-06 10:41:05 -05:00
LoJoSho
a82bb8183b clean: data to lombok in Database 2023-08-06 10:32:55 -05:00
LoJoSho
1eaeb8ecea clean: renames, missing priority, and ignoredCancelled in PlayerGameListener 2023-08-06 10:31:46 -05:00
LoJoSho
7a9d2f0041 clean spelled onPlayerCosmeticEquip correctly 2023-08-06 10:25:31 -05:00
LoJoSho
6d11deb9aa clean PlayerGameListener moved respawnBackpack method to lamdas 2023-08-06 10:24:53 -05:00
LoJoSho
f5f33f5fe7 clean: item null not showing the location where it occured 2023-08-06 10:21:12 -05:00
LoJoSho
62a1d04040 clean: prevent accidentally passing a null to a notnull method in menu types 2023-08-06 10:10:47 -05:00
LoJoSho
17db498e18 clean: lamdas <3 2023-08-06 10:09:26 -05:00
LoJoSho
0c11e1b1e5 clean: move title updater to StringBuilder 2023-08-06 10:08:54 -05:00
LoJoSho
d20eb11f45 clean: parameter was missing in contract getMenuItem 2023-08-06 10:06:18 -05:00
LoJoSho
51e19d3c36 clean: menu slots are never null, check if empty instead 2023-08-06 10:05:05 -05:00
LoJoSho
8e8d86b94c clean: worldguard listener moved to isEmpty from == 0 2023-08-06 10:01:36 -05:00
LoJoSho
c0caea2447 clean: make hooks final 2023-08-06 09:58:55 -05:00
LoJoSho
33356ea81d clean: move to Lombok for getters (wip) 2023-08-05 22:01:11 -05:00
LoJoSho
a486b13e7e clean: convert MenuItem to record 2023-08-05 21:57:31 -05:00
LoJoSho
938a561d25 feat: add shift left and right click events to action system, resolves #122 2023-08-05 20:04:42 -05:00
LoJoSho
1c61b72624 feat: Lombok + background item cosmetic shading 2023-08-05 19:06:33 -05:00
LoJoSho
46d82b01f0 version bump (2.5.3-DEV) 2023-08-05 10:10:59 -05:00
LoJoSho
c98f132871 version bump (2.5.2) 2023-08-03 11:01:25 -05:00
LoJoSho
554bdf91bd fix: ModelEngine not accepting uppercase 2023-08-02 16:06:03 -05:00
LoJoSho
fced771953 Merge pull request #121 from MomoPewpew/DvZ
Fixed interaction between backpack cosmetics and other passengers
2023-08-02 15:58:53 -05:00
MomoPewpew
6ec47c3f08 Fixed documentation typo 2023-08-02 22:06:45 +02:00
MomoPewpew
2df2646622 Backpack bug fixes
Putting on a backpack will no longer throw off all current riders
Acquiring a new rider will now reattach your backpack
2023-08-02 21:49:19 +02:00
MomoPewpew
e8d1dd1798 Revert "Reattach backpacks after a player is mounted or dismounted"
This reverts commit 2ab59dd2b2.
2023-08-01 20:36:57 +02:00
LoJoSho
59479fc474 clean: translation class more clear 2023-08-01 13:10:25 -05:00
LoJoSho
14b27abe92 clean: change TranslationPair to a record 2023-08-01 13:06:27 -05:00
LoJoSho
8c2c6db81b clean: better for loop 2023-08-01 13:03:14 -05:00
LoJoSho
5696039799 fix: entering wardrobe with riptide on a trident breaking wardrobe 2023-08-01 12:59:15 -05:00
LoJoSho
3068ce5a03 clean: IntelliJ complaining about missing <> 2023-08-01 12:51:28 -05:00
LoJoSho
548d0c3e9a clean: suppress deprecated warning 2023-08-01 12:47:31 -05:00
LoJoSho
a37d6d984b clean: latest version is never null 2023-08-01 12:44:51 -05:00
LoJoSho
d41b385b2a clean: handle IntelliJ warnings in PlayerGameListener 2023-08-01 12:42:58 -05:00
MomoPewpew
2ab59dd2b2 Reattach backpacks after a player is mounted or dismounted 2023-08-01 19:35:09 +02:00
LoJoSho
450083baf0 clean: replace instance check with null check 2023-08-01 12:29:14 -05:00
LoJoSho
0d3129bc3f clean: add proper event priorities 2023-08-01 12:26:08 -05:00
LoJoSho
fe68c43c1f clean: move invalid backpack message to normal debug from warning 2023-08-01 12:12:04 -05:00
LoJoSho
4aa1f412fe feat: add getAllCosmetics and getAllCosmeticUsers as API methods 2023-07-31 15:36:13 -05:00
LoJoSho
e53e0110f9 feat: require specific click type for cosmetic interactions 2023-07-31 15:29:24 -05:00
LoJoSho
f645907ed5 clean: remove unused settings 2023-07-31 15:04:41 -05:00
LoJoSho
af465180c0 version bump (2.5.2-DEV) 2023-07-31 15:04:19 -05:00
LoJoSho
210e6f61d6 version bump (2.5.1) 2023-07-30 22:06:39 -05:00
LoJoSho
14288479f4 fix: looping logic if entity is invalid 2023-07-30 22:05:51 -05:00
LoJoSho
8453a8b20d version bump (2.5.0) 2023-07-30 10:55:25 -05:00
lucian929
e59ee03ac7 feat: add hibiscus flower cosmetic 2023-07-29 19:04:41 -04:00
lucian929
01155f40dd fix: i forgot jetpack 2023-07-29 18:48:39 -04:00
lucian929
fa9f81e5e2 feat: add firstperson-items for cosmetics 2023-07-29 18:34:47 -04:00
LoJoSho
54bcef1a45 Merge pull request #120 from AverageGithub/fixes
Fixes
2023-07-28 10:55:04 -05:00
AverageGithub
8e14899397 Fix to 1.18 & 1.19.1/2 2023-07-28 14:21:30 +02:00
AverageGithub
061718a3b6 Fix title times not being used correctly 2023-07-28 13:05:24 +02:00
AverageGithub
2eea426460 Fix skin layers 2023-07-28 13:00:40 +02:00
LoJoSho
b0136d6076 Merge pull request #119 from AverageGithub/exploit-fix
fix players in wardrobe after teleporting
2023-07-27 09:01:35 -05:00
AverageGithub
d0b45b951c Fix import messup 2023-07-27 10:53:15 +02:00
AverageGithub
e42f5c8c7d Fix exploit 2023-07-27 10:48:08 +02:00
LoJoSho
5d4fb85fec fix: first-person backpack not in correct position in first seconds on join 2023-07-26 15:23:24 -05:00
LoJoSho
04b11a0830 feat: backend recode of the menu system, add refresh rate to auto-update gui 2023-07-26 15:09:25 -05:00
LoJoSho
353086b9c1 fix: not formatting minimessage in translations 2023-07-26 12:46:50 -05:00
LoJoSho
4e40a7cc96 clean: remove unused backpack type 2023-07-25 19:21:25 -05:00
LoJoSho
e2715fe631 fix: remove entities from players 2023-07-25 19:20:41 -05:00
LoJoSho
c7deb756db fix: first-person backpacks in hidden areas 2023-07-25 19:20:20 -05:00
LoJoSho
11f26f8f0a fix: first-person backpacks not showing properly in wardrobes 2023-07-25 19:12:46 -05:00
LoJoSho
6d814d86b3 feat: second iteration of first-person backpacks (focused on other player viewing the backpack) 2023-07-25 15:06:57 -05:00
LoJoSho
12f8b05469 feat: first iteration of first-person backpacks 2023-07-25 14:09:09 -05:00
LoJoSho
b5322bc10b clean: push runserver to 1.20.1 2023-07-25 10:21:37 -05:00
LoJoSho
7a4fd9a98b clean: remove unused utils 2023-07-19 13:39:27 -05:00
LoJoSho
239e13fab2 clean: annotations turned bad 2023-07-19 13:37:58 -05:00
LoJoSho
94b5a1bb3b Merge remote-tracking branch 'origin/remapped' into remapped
# Conflicts:
#	common/src/main/java/com/hibiscusmc/hmccosmetics/api/HMCCosmeticsAPI.java
2023-07-19 13:19:21 -05:00
LoJoSho
71ed820917 feat: slightly expanded api to equip and uneqip cosmetics in main API class 2023-07-19 13:19:04 -05:00
LoJoSho
20532fbaf2 feat: slightly expanded api to equip and remove cosmetics in main API class 2023-07-19 13:18:06 -05:00
LoJoSho
4068af98d2 fix: supervanish dependency 2023-07-19 12:26:50 -05:00
LoJoSho
95e83992de feat: update to gradle 8 2023-07-19 12:25:07 -05:00
LoJoSho
96817d7279 clean: update plugin-yml gradle plugin 2023-07-19 11:09:25 -05:00
LoJoSho
ba7a99247a fix: showing hidden cosmetics actionbar while playing emotes 2023-07-19 10:08:43 -05:00
LoJoSho
f1da6105c0 feat: disable playing emotes in WG region 2023-07-19 10:07:08 -05:00
LoJoSho
c06a4fcede feat: move ModelEngine integration to hook system 2023-07-19 09:54:10 -05:00
LoJoSho
afb20ea0bb clean: update PAPI dependency 2023-07-09 21:44:15 -05:00
LoJoSho
774caf8d91 version bump (2.4.11-DEV) 2023-07-09 21:25:41 -05:00
LoJoSho
a0c2c8a9aa clean: removed unused packet 2023-07-09 21:05:04 -05:00
LoJoSho
5b7f75f7a0 version bump (2.4.10) 2023-07-09 17:53:13 -05:00
LoJoSho
3f7d010dfa clean: optimize imports 2023-07-08 22:48:28 -05:00
LoJoSho
4d84bd681d clean: optimize imports 2023-07-08 22:48:17 -05:00
LoJoSho
0daff3044d feat: move placeholder processing to one method 2023-07-08 22:47:42 -05:00
LoJoSho
ee87338cd4 fix: Cosmin taking up our command >:( 2023-07-08 22:27:06 -05:00
LoJoSho
2b467e63ce feat: remove internal data (deprecated) 2023-07-08 22:11:37 -05:00
LoJoSho
6000cf9c1b clean: clean 2 am coding 2023-07-08 12:04:42 -05:00
LoJoSho
f2b0fb29d3 fix: Leads not properly disappearing teleporting into WG region with hidden cosmetics 2023-07-08 11:40:08 -05:00
LoJoSho
d2962ba5ed version bump (2.4.10-DEV) 2023-07-08 11:39:41 -05:00
LoJoSho
b37083a298 version bump (2.4.9) 2023-06-29 10:00:24 -05:00
LoJoSho
e35a29a13b feat: empty cosmetic type item name go through PAPI 2023-06-29 09:57:08 -05:00
LoJoSho
344aaf32e0 fix: PAPI placeholders not being applied in displaynames in guis 2023-06-28 18:06:58 -05:00
LoJoSho
6498cb43ea version bump (2.4.9-DEV) 2023-06-28 18:06:41 -05:00
LoJoSho
0120720cc3 version bump (2.4.8) 2023-06-27 10:27:43 -05:00
LoJoSho
d1bfa5abbc feat: add force-show-join to show regardless of hidden in database 2023-06-27 10:16:30 -05:00
LoJoSho
71a080a3d5 feat: Option to open menu on wardrobe enter 2023-06-27 09:54:35 -05:00
LoJoSho
78f48703db fix: prevent kicking when message is null/empty 2023-06-27 09:44:11 -05:00
LoJoSho
b9e5096d33 feat: actionbar when player has hidden cosmetics 2023-06-27 09:43:56 -05:00
LoJoSho
d7603b5108 version bump (2.4.8-DEV) 2023-06-27 09:28:03 -05:00
LoJoSho
756e3390a1 clean: remove old code commented out 2023-06-24 20:45:59 -05:00
LoJoSho
8054a35f43 feat: add recursive file lookup 2023-06-23 14:45:27 -05:00
LoJoSho
006319a757 Merge remote-tracking branch 'origin/remapped' into remapped 2023-05-27 10:05:33 -05:00
LoJoSho
a8ff8e6a7a Merge remote-tracking branch 'origin/remapped' into remapped 2023-05-08 09:50:55 -05:00
LoJoSho
8b20207442 Merge remote-tracking branch 'origin/remapped' into remapped 2023-04-24 10:32:56 -05:00
LoJoSho
8bbe12ed84 Merge remote-tracking branch 'origin/remapped' into remapped
# Conflicts:
#	build.gradle.kts
2023-01-30 10:40:00 -06:00
LoJoSho
d23f3e19d2 Moved ProtocolLib Repo 2022-11-16 13:38:02 -06:00
182 changed files with 5890 additions and 7536 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 "7.1.2"
id("xyz.jpenilla.run-paper") version "2.0.0"
id("net.minecrell.plugin-yml.bukkit") version "0.5.2"
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.4.7"
version = "2.8.3${getGitCommitHash()}"
allprojects {
apply(plugin = "java")
@@ -16,25 +16,22 @@ 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/")
// PlaceholderAPI
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
//Hikari
maven("https://mvnrepository.com/artifact/com.zaxxer/HikariCP")
// Citizens & Denizen
maven("https://maven.citizensnpcs.co/repo")
@@ -52,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/")
@@ -63,52 +57,78 @@ allprojects {
// md-5 Repo
maven("https://repo.md-5.net/content/groups/public/")
// MMOItems
maven("https://nexus.phoenixdevt.fr/repository/maven-public/")
// 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")
}
dependencies {
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("org.jetbrains:annotations:23.0.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0")
compileOnly("me.clip:placeholderapi:2.11.1")
compileOnly("com.ticxo:modelengine:R3.0.1")
compileOnly("com.github.oraxen:oraxen:-SNAPSHOT")
compileOnly("com.github.LoneDev6:API-ItemsAdder:3.2.5")
compileOnly("com.mineinabyss:geary-papermc:0.24-SNAPSHOT")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
compileOnly("it.unimi.dsi:fastutil:8.5.11")
compileOnly("com.github.LeonMangler:SuperVanish:6.2.6-4")
//compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.4-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")
exclude(group = "org.enginehub.lin-bus.format")
}
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.8.1-d9fbae1d")
// Handled by Spigot Library Loader ~ Deprecated as of Dec 16, 2025
/*
compileOnly("net.kyori:adventure-api:4.24.0")
compileOnly("net.kyori:adventure-text-minimessage:4.24.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.4.1")
*/
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.2.0-SNAPSHOT") {
exclude("net.kyori") // Already have adventure API
}
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
}
tasks {
javadoc {
// javadoc spec has these added.
(options as StandardJavadocDocletOptions)
.tags("apiNote:a:API:", "implSpec:a:Implementation Requirements", "implNote:a:Implementation Note:")
}
}
}
dependencies {
implementation(project(path = ":common"))
implementation(project(path = ":v1_18_R2", configuration = "reobf"))
implementation(project(path = ":v1_19_R1", configuration = "reobf"))
implementation(project(path = ":v1_19_R2", configuration = "reobf"))
implementation(project(path = ":v1_19_R3", configuration = "reobf"))
implementation(project(path = ":v1_20_R1", configuration = "reobf"))
//compileOnly("com.github.Fisher2911:FisherLib:master-SNAPSHOT")
implementation("net.kyori:adventure-api:4.11.0")
implementation("net.kyori:adventure-text-minimessage:4.11.0")
implementation("net.kyori:adventure-platform-bukkit:4.1.2")
implementation("dev.triumphteam:triumph-gui:3.1.3")
implementation("org.spongepowered:configurate-yaml:4.1.2")
implementation("org.bstats:bstats-bukkit:3.0.0")
implementation("com.jeff_media:SpigotUpdateChecker:3.0.0")
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.7")
implementation("com.github.BG-Software-LLC:CommentedConfiguration:-SNAPSHOT")
//implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5")
}
tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
options.release.set(21)
}
javadoc {
@@ -121,28 +141,23 @@ tasks {
}
runServer {
minecraftVersion("1.19.4")
minecraftVersion("1.21.8")
downloadPlugins {
hangar("PlaceholderAPI", "2.11.6")
hangar("Multiverse-Core", "5.3.4")
url("https://download.luckperms.net/1604/bukkit/loader/LuckPerms-Bukkit-5.5.15.jar")
github("Test-Account666", "PlugManX", "2.4.1", "PlugManX-2.4.1.jar")
//github("gecolay", "GSit", "2.4.3", "GSit-2.4.3.jar")
}
}
shadowJar {
dependsOn(":v1_18_R2:reobfJar")
dependsOn(":v1_19_R1:reobfJar")
dependsOn(":v1_19_R2:reobfJar")
dependsOn(":v1_19_R3:reobfJar")
dependsOn(":v1_20_R1:reobfJar")
mergeServiceFiles()
relocate("dev.triumphteam.gui", "com.hisbiscusmc.hmccosmetics.gui")
relocate("me.mattstudios.mf", "com.hisbiscusmc.hmccosmetics.mf")
relocate("net.kyori.adventure", "com.hisbiscusmc.hmccosmetics.adventure")
relocate("org.spongepowered.configurate", "com.hisbiscusmc.hmccosmetics.configurate")
relocate("org.bstats", "com.hisbiscusmc.hmccosmetics.bstats")
relocate("com.zaxxer.hikaricp", "com.hisbiscusmc.hmccosmetics.hikaricp")
relocate("com.j256.ormlite", "com.hisbiscusmc.hmccosmetics.ormlite")
relocate("com.jeff_media.updatechecker", "com.hisbiscusmc.hmccosmetics.updatechecker")
relocate("com.owen1212055.particlehelper", "com.hisbiscusmc.hmccosmetics.particlehelper")
relocate("com.ticxo.playeranimator", "com.hisbiscusmc.hmccosmetics.playeranimator")
relocate("com.bgsoftware", "com.hisbiscusmc.hmccosmetics.configupdater")
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 {
@@ -167,15 +182,19 @@ tasks {
bukkit {
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
main = "com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin"
apiVersion = "1.18"
apiVersion = "1.20"
authors = listOf("LoJoSho")
depend = listOf("ProtocolLib")
softDepend = listOf("ModelEngine", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen")
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.
)
commands {
register("cosmetic") {
description = "Base Cosmetic Command"
aliases = listOf("hmccosmetics", "cosmetics")
}
}
permissions {
@@ -251,10 +270,41 @@ bukkit {
register("hmccosmetics.unapplydeath.bypass") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.disableall") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.hiddenreasons") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.clearhiddenreasons") {
default = BukkitPluginDescription.Permission.Default.OP
}
}
}
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

@@ -3,43 +3,11 @@ plugins {
id("maven-publish")
}
dependencies {
compileOnly("com.mojang:authlib:1.5.25")
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0")
compileOnly("me.clip:placeholderapi:2.11.1")
compileOnly("com.ticxo:modelengine:R3.0.1")
compileOnly("com.github.oraxen:oraxen:-SNAPSHOT")
compileOnly("com.github.LoneDev6:API-ItemsAdder:3.2.5")
compileOnly("com.mineinabyss:geary-papermc:0.24-SNAPSHOT")
compileOnly("com.hibiscus:hmccolor:0.3-SNAPSHOT")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
compileOnly("it.unimi.dsi:fastutil:8.5.11")
compileOnly("io.lumine:Mythic-Dist:5.2.1")
compileOnly("com.denizenscript:denizen:1.2.7-SNAPSHOT")
compileOnly("com.github.LeonMangler:SuperVanish:6.2.6-4")
compileOnlyApi("LibsDisguises:LibsDisguises:10.0.21") {
exclude("org.spigotmc", "spigot")
}
//compileOnly("com.github.Fisher2911:FisherLib:master-SNAPSHOT")
implementation("net.kyori:adventure-api:4.12.0")
implementation("net.kyori:adventure-text-minimessage:4.12.0")
implementation("net.kyori:adventure-platform-bukkit:4.2.0")
implementation("dev.triumphteam:triumph-gui:3.1.3")
implementation("org.spongepowered:configurate-yaml:4.1.2")
implementation("org.bstats:bstats-bukkit:3.0.0")
implementation("com.jeff_media:SpigotUpdateChecker:3.0.0")
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.7")
implementation("com.github.BG-Software-LLC:CommentedConfiguration:-SNAPSHOT")
//implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.5")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17
))
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
withJavadocJar()
withSourcesJar()
}
publishing {

View File

@@ -1,8 +0,0 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://repo.papermc.io/repository/maven-public/")
}
}
rootProject.name = "HMCCosmetics"

View File

@@ -1,105 +1,83 @@
package com.hibiscusmc.hmccosmetics;
import com.bgsoftware.common.config.CommentedConfiguration;
import com.hibiscusmc.hmccosmetics.api.events.HMCCosmeticSetupEvent;
import com.hibiscusmc.hmccosmetics.command.CosmeticCommand;
import com.hibiscusmc.hmccosmetics.command.CosmeticCommandTabComplete;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.config.serializer.ItemSerializer;
import com.hibiscusmc.hmccosmetics.config.serializer.LocationSerializer;
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.Hooks;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.gui.special.impl.HMCColorDyeMenu;
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.PlayerConnectionListener;
import com.hibiscusmc.hmccosmetics.listener.PlayerGameListener;
import com.hibiscusmc.hmccosmetics.nms.NMSHandlers;
import com.hibiscusmc.hmccosmetics.listener.*;
import com.hibiscusmc.hmccosmetics.packets.CosmeticPacketInterface;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.PlayerSearchManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.TranslationUtil;
import com.jeff_media.updatechecker.UpdateCheckSource;
import com.jeff_media.updatechecker.UpdateChecker;
import com.ticxo.playeranimator.PlayerAnimatorImpl;
import org.bstats.bukkit.Metrics;
import lombok.Getter;
import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin;
import me.lojosho.hibiscuscommons.HibiscusPlugin;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.hibiscuscommons.config.serializer.LocationSerializer;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.shaded.configupdater.common.config.CommentedConfiguration;
import me.lojosho.shaded.configurate.ConfigurateException;
import me.lojosho.shaded.configurate.ConfigurationOptions;
import me.lojosho.shaded.configurate.yaml.NodeStyle;
import me.lojosho.shaded.configurate.yaml.YamlConfigurationLoader;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.java.JavaPlugin;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.ConfigurationOptions;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.nio.file.Path;
public final class HMCCosmeticsPlugin extends JavaPlugin {
public final class HMCCosmeticsPlugin extends HibiscusPlugin {
private static HMCCosmeticsPlugin instance;
private static boolean disable = false;
private static YamlConfigurationLoader configLoader;
private static final int pluginId = 13873;
private static boolean hasModelEngine = false;
private static boolean onLatestVersion = true;
private static String latestVersion = "";
@Getter
private PlayerSearchManager playerSearchManager;
public HMCCosmeticsPlugin() {
super(13873, 1879);
new HookHMCCosmetics();
new HookBetterHud();
}
@Override
public void onEnable() {
public void onStart() {
// Plugin startup logic
instance = this;
// bstats https://bstats.org/plugin/bukkit/HMCCosmetics/13873
Metrics metrics = new Metrics(this, pluginId);
// NMS version check
if (!NMSHandlers.getHandler().getSupported()) {
getLogger().severe("This version is not supported! Consider switching versions?");
getServer().getPluginManager().disablePlugin(this);
return;
}
// Search Service
this.playerSearchManager = new PlayerSearchManager(this);
// Update Checker
UpdateChecker checker = new UpdateChecker(this, UpdateCheckSource.POLYMART, "1879")
.onSuccess((commandSenders, latestVersion) -> {
this.latestVersion = (String) latestVersion;
if (!this.latestVersion.equalsIgnoreCase(getDescription().getVersion())) {
getLogger().info("+++++++++++++++++++++++++++++++++++");
getLogger().info("There is a new update for HMCCosmetics!");
getLogger().info("Please download it as soon as possible for possible fixes and new features.");
getLogger().info("Current Version " + getDescription().getVersion() + " | Latest Version " + latestVersion);
getLogger().info("Spigot: https://www.spigotmc.org/resources/100107/");
getLogger().info("Polymart: https://polymart.org/resource/1879");
getLogger().info("+++++++++++++++++++++++++++++++++++");
}
})
.setNotifyRequesters(false)
.setNotifyOpsOnJoin(false)
.checkEveryXHours(24)
.checkNow();
onLatestVersion = checker.isUsingLatestVersion();
// File setup
saveDefaultConfig();
if (!Path.of(getDataFolder().getPath(), "messages.yml").toFile().exists()) saveResource("messages.yml", false);
if (!Path.of(getDataFolder().getPath(), "translations.yml").toFile().exists()) saveResource("translations.yml", false);
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
PlayerAnimatorImpl.initialize(this);
if (!Path.of(getDataFolder().getPath() + "/menus/").toFile().exists()) {
saveResource("menus/defaultmenu_hats.yml", false);
saveResource("menus/defaultmenu_balloons.yml", false);
saveResource("menus/defaultmenu_hands.yml", false);
saveResource("menus/defaultmenu_backpacks.yml", false);
}
// Configuration Sync
final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile();
@@ -107,15 +85,19 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
final File translationFile = Path.of(getInstance().getDataFolder().getPath(), "translations.yml").toFile();
try {
CommentedConfiguration.loadConfiguration(configFile).syncWithConfig(configFile, getInstance().getResource("config.yml"),
"database-settings", "debug-mode", "wardrobe.viewer-location", "wardrobe.npc-location", "wardrobe.wardrobe-location", "wardrobe.leave-location");
"database-settings", "wardrobe.wardrobes", "debug-mode", "wardrobe.viewer-location", "wardrobe.npc-location", "wardrobe.wardrobe-location", "wardrobe.leave-location");
CommentedConfiguration.loadConfiguration(messageFile).syncWithConfig(messageFile, getInstance().getResource("messages.yml"));
CommentedConfiguration.loadConfiguration(translationFile).syncWithConfig(translationFile, getInstance().getResource("translations.yml"));
} catch (Exception e) {
e.printStackTrace();
}
// Move this over to Hibiscus Commons later
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) new HMCPlaceholderExpansion().register();
// Setup
setup();
setPacketInterface(new CosmeticPacketInterface());
// Commands
getServer().getPluginCommand("cosmetic").setExecutor(new CosmeticCommand());
@@ -124,18 +106,28 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
// Listener
getServer().getPluginManager().registerEvents(new PlayerConnectionListener(), this);
getServer().getPluginManager().registerEvents(new PlayerGameListener(), this);
getServer().getPluginManager().registerEvents(new ServerListener(), this);
getServer().getPluginManager().registerEvents(new PlayerMovementListener(), this);
getServer().getPluginManager().registerEvents(playerSearchManager, this);
if (HibiscusCommonsPlugin.isOnPaper()) {
getServer().getPluginManager().registerEvents(new PaperPlayerGameListener(), this);
}
// Database
new Database();
// ModelEngine
if (Bukkit.getPluginManager().getPlugin("ModelEngine") != null) {
hasModelEngine = true;
// WorldGuard
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null && Settings.isWorldGuardMoveCheck()) {
getServer().getPluginManager().registerEvents(new WGListener(), this);
}
// WorldGuard
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null && Settings.isWorldGuardMoveCheckEnabled()) {
getServer().getPluginManager().registerEvents(new WGListener(), this);
// HMCColor
if (Hooks.isActiveHook("HMCColor")) {
try {
DyeMenuProvider.setDyeMenuProvider(new HMCColorDyeMenu());
} catch (IllegalStateException e) {
getLogger().warning("Unable to set HMCColor as the dye menu. There is likely another plugin registering another dye menu.");
}
}
}
@@ -148,14 +140,13 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
}
@Override
public void onDisable() {
public void onEnd() {
// Plugin shutdown logic
disable = true;
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);
}
Database.save(user);
}
@@ -220,9 +211,6 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
throw new RuntimeException(e);
}
// Misc Hooks setup (like items)
Hooks.setup();
// Cosmetics setup
Cosmetics.setup();
@@ -258,8 +246,6 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
}
}
EmoteManager.loadEmotes();
getInstance().getLogger().info("Successfully Enabled HMCCosmetics");
getInstance().getLogger().info(Cosmetics.values().size() + " Cosmetics Successfully Setup");
getInstance().getLogger().info(Menus.getMenuNames().size() + " Menus Successfully Setup");
@@ -268,31 +254,4 @@ public final class HMCCosmeticsPlugin extends JavaPlugin {
Bukkit.getPluginManager().callEvent(new HMCCosmeticSetupEvent());
}
public static boolean isDisable() {
return disable;
}
public static YamlConfigurationLoader getConfigLoader() {
return configLoader;
}
public static void saveConfig(ConfigurationNode node) {
try {
HMCCosmeticsPlugin.getConfigLoader().save(node);
HMCCosmeticsPlugin.getInstance().getLogger().info("Set new location " + node.path());
} catch (ConfigurateException e) {
throw new RuntimeException(e);
}
}
public static boolean hasModelEngine() {
return hasModelEngine;
}
public static boolean isOnLatestVersion() {
return onLatestVersion;
}
public static String getLatestVersion() {
return latestVersion;
}
}

View File

@@ -1,49 +1,215 @@
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 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;
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(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(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(String id) {
public static @Nullable Menu getMenu(@NotNull String id) {
return Menus.getMenu(id);
}
/**
* 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 {@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.addCosmetic(cosmetic, color);
}
/**
* 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);
}
/**
* Retrieves a list of all cosmetics currently registered with HMCC.
*
* @return an {@code immutable} list containing all registered {@link Cosmetic} object
*/
public static @NotNull List<Cosmetic> getAllCosmetics() {
return List.copyOf(Cosmetics.values());
}
/**
* Retrieves a list of all cosmetic users currently registered with HMCC.
*
* @return an immutable list containing all registered {@link CosmeticUser} objects
*/
public static @NotNull List<CosmeticUser> getAllCosmeticUsers() {
return List.copyOf(CosmeticUsers.values());
}
/**
* Retrieves a map of all cosmetic slots currently registered with HMCC.
*
* @return an immutable {@link Map} containing all registered cosmetic slots
*/
public static @NotNull Map<String, CosmeticSlot> getAllCosmeticSlots() {
return Map.copyOf(CosmeticSlot.values());
}
/**
* 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.
*/
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

@@ -1,26 +1,25 @@
package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
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

@@ -7,11 +7,13 @@ 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;
private Wardrobe wardrobe;
public PlayerWardrobeEnterEvent(@NotNull CosmeticUser who, @NotNull Wardrobe wardrobe) {
@@ -19,41 +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 void setWardrobe(Wardrobe wardrobe) {
this.wardrobe = wardrobe;
}
public Wardrobe getWardrobe() {
return wardrobe;
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

@@ -1,5 +1,7 @@
package com.hibiscusmc.hmccosmetics.command;
import com.hibiscusmc.hmccolor.HMCColorConfig;
import com.hibiscusmc.hmccolor.HMCColorContextKt;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.config.Wardrobe;
@@ -8,19 +10,18 @@ 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;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.ServerUtils;
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;
@@ -40,10 +41,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")) {
@@ -104,7 +109,18 @@ public class CosmeticCommand implements CommandExecutor {
}
if (sender.hasPermission("hmccosmetics.cmd.apply.color")) {
if (args.length >= 4) color = ServerUtils.hex2Rgb(args[3]);
if (args.length >= 4) {
// TODO: Add sub-color support somehow... (and make this neater)
String textColor = args[3];
if (!textColor.contains("#") && Hooks.isActiveHook("HMCColor")) {
HMCColorConfig.Colors colors = HMCColorContextKt.getHmcColor().getConfig().getColors().get(textColor);
if (colors != null) {
color = colors.getBaseColor().getColor();
}
} else {
color = HMCCServerUtils.hex2Rgb(textColor);
}
}
}
if (args.length == 1) {
@@ -126,7 +142,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;
}
@@ -134,11 +155,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;
}
@@ -169,11 +190,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) {
@@ -185,7 +207,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);
@@ -225,20 +247,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")) {
@@ -262,7 +288,6 @@ public class CosmeticCommand implements CommandExecutor {
case ("dataclear") -> {
if (args.length == 1) return true;
OfflinePlayer selectedPlayer = Bukkit.getOfflinePlayer(args[1]);
if (selectedPlayer == null) return true;
if (!sender.hasPermission("hmccosmetics.cmd.dataclear") && !sender.isOp()) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
@@ -285,26 +310,35 @@ public class CosmeticCommand implements CommandExecutor {
return true;
}
if (!EnumUtils.isValidEnum(CosmeticSlot.class, args[1])) {
final String rawSlot = args[1];
if (!CosmeticSlot.contains(rawSlot)) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-slot");
return true;
}
final CosmeticSlot slot = CosmeticSlot.valueOf(rawSlot); // This is checked above. While IDEs may say the slot might be null, it will not be.
final Cosmetic cosmetic = user.getCosmetic(slot);
if (cosmetic == null) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-slot");
return true;
}
CosmeticSlot slot = CosmeticSlot.valueOf(args[1]);
Cosmetic cosmetic = user.getCosmetic(slot);
if (args.length >= 3) {
if (args[2].isEmpty()) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-color");
return true;
}
Color color = ServerUtils.hex2Rgb(args[2]);
Color color = HMCCServerUtils.hex2Rgb(args[2]);
if (color == null) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-color");
return true;
}
user.addPlayerCosmetic(cosmetic, color); // #FFFFFF
user.addCosmetic(cosmetic, color); // #FFFFFF
} else {
DyeMenu.openMenu(user, cosmetic);
if (DyeMenuProvider.hasMenuProvider()) {
DyeMenuProvider.openMenu(player, user, cosmetic);
} else {
if (!silent) MessagesUtil.sendMessage(player, "invalid-color");
}
}
}
case ("setwardrobesetting") -> {
@@ -321,7 +355,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;
@@ -334,7 +368,7 @@ public class CosmeticCommand implements CommandExecutor {
}
if (args[2].equalsIgnoreCase("viewerlocation")) {
WardrobeSettings.setViewerLocation(wardrobe, player.getLocation());
WardrobeSettings.setViewerLocation(wardrobe, player.getEyeLocation());
if (!silent) MessagesUtil.sendMessage(player, "set-wardrobe-viewing");
return true;
}
@@ -352,10 +386,15 @@ public class CosmeticCommand implements CommandExecutor {
return true;
}
if (args[2].equalsIgnoreCase("distance")) {
WardrobeSettings.setWardrobeDistance(wardrobe, Integer.valueOf(args[3]));
WardrobeSettings.setWardrobeDistance(wardrobe, Integer.parseInt(args[3]));
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") -> {
@@ -368,8 +407,9 @@ public class CosmeticCommand implements CommandExecutor {
}
player.sendMessage("Passengers -> " + player.getPassengers());
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) {
player.sendMessage("Backpack Location -> " + user.getUserBackpackManager().getArmorStand().getLocation());
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;
@@ -414,7 +454,7 @@ public class CosmeticCommand implements CommandExecutor {
CosmeticUser user = CosmeticUsers.getUser(player);
if (!silent) MessagesUtil.sendMessage(sender, "show-cosmetic");
user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.COMMAND);
return true;
}
case ("debug") -> {
@@ -423,7 +463,7 @@ public class CosmeticCommand implements CommandExecutor {
return true;
}
if (Settings.getDebugMode()) {
if (Settings.isDebugMode()) {
Settings.setDebugMode(false);
if (!silent) MessagesUtil.sendMessage(sender, "debug-disabled");
} else {
@@ -431,56 +471,60 @@ public class CosmeticCommand implements CommandExecutor {
if (!silent) MessagesUtil.sendMessage(sender, "debug-enabled");
}
}
case ("emote") -> {
if (!sender.hasPermission("hmccosmetics.cmd.emote")) {
case "disableall" -> {
if (!sender.hasPermission("hmccosmetics.cmd.disableall")) {
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 (args.length == 1) {
if (!silent) MessagesUtil.sendMessage(player, "not-enough-args");
return true;
}
if (args[1].equalsIgnoreCase("true")) {
Settings.setAllPlayersHidden(true);
for (CosmeticUser user : CosmeticUsers.values()) user.hideCosmetics(CosmeticUser.HiddenReason.DISABLED);
if (!silent) MessagesUtil.sendMessage(sender, "disabled-all");
} else if (args[1].equalsIgnoreCase("false")) {
Settings.setAllPlayersHidden(false);
for (CosmeticUser user : CosmeticUsers.values()) user.showCosmetics(CosmeticUser.HiddenReason.DISABLED);
if (!silent) MessagesUtil.sendMessage(sender, "enabled-all");
} else {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-args");
}
return true;
}
if (!EmoteManager.has(args[1])) {
MessagesUtil.sendDebugMessages("Did not contain " + args[1]);
if (!silent) MessagesUtil.sendMessage(sender, "emote-invalid");
case "hiddenreasons" -> {
if (!sender.hasPermission("hmccosmetics.cmd.hiddenreasons")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (sender.hasPermission("hmccosmetics.cmd.playemote.other")) {
if (args.length >= 3) player = Bukkit.getPlayer(args[2]);
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);
user.getUserEmoteManager().playEmote(args[1]);
sender.sendMessage(user.getHiddenReasons().toString());
return true;
}
case "clearhiddenreasons" -> {
if (!sender.hasPermission("hmccosmetics.cmd.clearhiddenreasons")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
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);
user.clearHiddenReasons();
return true;
}
}

View File

@@ -1,15 +1,16 @@
package com.hibiscusmc.hmccosmetics.command;
import com.hibiscusmc.hmccolor.HMCColorContextKt;
import com.hibiscusmc.hmccosmetics.config.Wardrobe;
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;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -42,14 +43,16 @@ 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");
StringUtil.copyPartialMatches(args[0], completions, finalCompletions);
}
if (!(sender instanceof Player)) return completions;
CosmeticUser user = CosmeticUsers.getUser(((Player) sender).getUniqueId());
if (user == null) return completions; // User hasn't loaded in yet, can't do proper checks
if (args.length == 2) {
String subcommand = args[0].toLowerCase();
@@ -68,11 +71,15 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (menu.canOpen(user.getPlayer())) completions.add(menu.getId());
}
}
case "dataclear", "hide", "show", "emote" -> {
case "dataclear", "hide", "show", "hiddenreasons", "clearhiddenreasons" -> {
for (Player player : Bukkit.getOnlinePlayers()) {
completions.add(player.getName());
}
}
case "disableall" -> {
completions.add("true");
completions.add("false");
}
case "wardrobe" -> {
for (Wardrobe wardrobe : WardrobeSettings.getWardrobes()) {
if (wardrobe.hasPermission()) {
@@ -84,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" -> {
@@ -92,7 +99,6 @@ public class CosmeticCommandTabComplete implements TabCompleter {
completions.add(wardrobe.getId());
}
}
case "playemote" -> completions.addAll(EmoteManager.getAllNames());
}
StringUtil.copyPartialMatches(args[1], completions, finalCompletions);
}
@@ -102,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());
}
@@ -113,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);
@@ -122,8 +129,14 @@ public class CosmeticCommandTabComplete implements TabCompleter {
String subcommand = args[0].toLowerCase();
switch (subcommand) {
case "apply" -> {
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

@@ -1,10 +1,10 @@
package com.hibiscusmc.hmccosmetics.config;
import org.spongepowered.configurate.ConfigurationNode;
import lombok.Getter;
import me.lojosho.shaded.configurate.ConfigurationNode;
public class DatabaseSettings {
//private static final String DATABASE_SETTINGS_PATH = "cosmetic-settings";
private static final String DATABASE_TYPE_PATH = "type";
private static final String MYSQL_DATABASE_SETTINGS = "mysql";
@@ -17,18 +17,24 @@ public class DatabaseSettings {
private static final String ENABLE_DELAY = "enabled";
private static final String DELAY_LENGTH = "delay";
@Getter
private static String databaseType;
@Getter
private static String database;
@Getter
private static String password;
@Getter
private static String host;
@Getter
private static String username;
@Getter
private static int port;
@Getter
private static boolean enabledDelay;
@Getter
private static int delayLength;
public static void load(ConfigurationNode source) {
//ConfigurationNode databaseSettings = source.node(DATABASE_SETTINGS_PATH);
databaseType = source.node(DATABASE_TYPE_PATH).getString();
ConfigurationNode mySql = source.node(MYSQL_DATABASE_SETTINGS);
@@ -44,36 +50,4 @@ public class DatabaseSettings {
enabledDelay = delay.node(ENABLE_DELAY).getBoolean(false);
delayLength = delay.node(DELAY_LENGTH).getInt(2);
}
public static String getDatabaseType() {
return databaseType;
}
public static String getDatabase() {
return database;
}
public static String getPassword() {
return password;
}
public static String getHost() {
return host;
}
public static String getUsername() {
return username;
}
public static int getPort() {
return port;
}
public static boolean isEnabledDelay() {
return enabledDelay;
}
public static int getDelayLength() {
return delayLength;
}
}

View File

@@ -1,12 +1,16 @@
package com.hibiscusmc.hmccosmetics.config;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.util.Vector;
import org.spongepowered.configurate.ConfigurationNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
public class Settings {
@@ -15,17 +19,8 @@ public class Settings {
private static final String DEFAULT_MENU = "default-menu";
private static final String CONFIG_VERSION = "config-version";
private static final String COSMETIC_SETTINGS_PATH = "cosmetic-settings";
private static final String REQUIRE_EMPTY_HELMET_PATH = "require-empty-helmet";
private static final String REQUIRE_EMPTY_OFF_HAND_PATH = "require-empty-off-hand";
private static final String REQUIRE_EMPTY_CHEST_PLATE_PATH = "require-empty-chest-plate";
private static final String REQUIRE_EMPTY_PANTS_PATH = "require-empty-pants";
private static final String REQUIRE_EMPTY_BOOTS_PATH = "require-empty-boots";
private static final String BALLOON_OFFSET = "balloon-offset";
private static final String FIRST_PERSON_BACKPACK_MODE = "first-person-backpack-mode";
private static final transient String LOOK_DOWN_PITCH_PATH = "look-down-backpack-remove";
private static final String VIEW_DISTANCE_PATH = "view-distance";
private static final String PARTICLE_COUNT = "particle-count";
private static final String DYE_MENU_PATH = "dye-menu";
private static final String DYE_MENU_NAME = "title";
private static final String DYE_MENU_INPUT_SLOT = "input-slot";
@@ -34,52 +29,130 @@ public class Settings {
private static final String TICK_PERIOD_PATH = "tick-period";
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 EMOTE_DISTANCE_PATH = "emote-distance";
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 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_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_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_DISABLED_WORLDS_PATH = "disabled-worlds";
private static final String COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH = "backpack-force-riding-packet";
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 COSMETIC_OFFHAND_PREVENT_SWAPPING = "offhand-prevent-swapping";
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";
private static final String INDIVIDUAL_COLUMN_SHIFT_PATH = "individual-column-shift";
private static final String BACKGROUND_PATH = "background";
private static final String CLEAR_BACKGROUND_PATH = "clear-background";
private static final String EQUIPPED_COSMETIC_COLOR_PATH = "equipped-cosmetic-color";
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;
@Getter
private static String dyeMenuName;
@Getter
private static int dyeMenuInputSlot;
@Getter
private static int dyeMenuOutputSlot;
@Getter
private static int configVersion;
private static boolean requireEmptyHelmet;
private static boolean requireEmptyOffHand;
private static boolean requireEmptyChestPlate;
private static boolean requireEmptyPants;
private static boolean requireEmptyBoots;
@Getter
private static boolean debugMode;
@Getter
private static boolean unapplyOnDeath;
@Getter
private static boolean forcePermissionJoin;
@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;
private static boolean cosmeticEmoteBlockCheck;
private static boolean addHelmetEnchants;
private static boolean addChestplateEnchants;
private static boolean addLeggingEnchants;
private static boolean addBootsEnchants;
private static boolean emoteAirCheck;
private static boolean emoteDamageLeave;
private static boolean emoteInvincible;
private static final HashMap<EquipmentSlot, SlotOptionConfig> slotOptions = new HashMap<>();
@Getter
private static boolean destroyLooseCosmetics;
private static int lookDownPitch;
@Getter
private static boolean preventOffhandSwapping;
@Getter
private static boolean backpackForceRidingEnabled;
@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;
@Getter
private static int viewDistance;
@Getter
private static int tickPeriod;
private static double emoteDistance;
@Getter
private static Long defaultMenuCooldown;
@Getter
private static boolean menuClickCooldown;
@Getter
private static Vector balloonOffset;
@Getter
private static String cosmeticEquipClickType;
@Getter
private static String cosmeticUnEquipClickType;
@Getter
private static String cosmeticDyeClickType;
@Getter
private static boolean defaultShading;
@Getter
private static String firstRowShift;
@Getter
private static String sequentRowShift;
@Getter
private static String individualColumnShift;
@Getter
private static String background;
@Getter
private static String clearBackground;
@Getter
private static String equippedCosmeticColor;
@Getter
private static String equipableCosmeticColor;
@Getter
private static String lockedCosmeticColor;
@Getter @Setter
private static boolean allPlayersHidden;
@Getter
private static boolean wardrobeHideHud;
public static void load(ConfigurationNode source) {
@@ -98,30 +171,66 @@ public class Settings {
ConfigurationNode cosmeticSettings = source.node(COSMETIC_SETTINGS_PATH);
requireEmptyHelmet = cosmeticSettings.node(REQUIRE_EMPTY_HELMET_PATH).getBoolean();
requireEmptyOffHand = cosmeticSettings.node(REQUIRE_EMPTY_OFF_HAND_PATH).getBoolean();
requireEmptyChestPlate = cosmeticSettings.node(REQUIRE_EMPTY_CHEST_PLATE_PATH).getBoolean();
requireEmptyPants = cosmeticSettings.node(REQUIRE_EMPTY_PANTS_PATH).getBoolean();
requireEmptyBoots = cosmeticSettings.node(REQUIRE_EMPTY_BOOTS_PATH).getBoolean();
ConfigurationNode disabledGamemodeSettings = cosmeticSettings.node(DISABLED_GAMEMODE_PATH);
disabledGamemodesEnabled = disabledGamemodeSettings.node(ENABLED_PATH).getBoolean(true);
try {
disabledGamemodes = disabledGamemodeSettings.node(DISABLED_GAMEMODE_GAMEMODES_PATH).getList(String.class);
disabledWorlds = cosmeticSettings.node(COSMETIC_DISABLED_WORLDS_PATH).getList(String.class);
} catch (Exception e) {
disabledGamemodes = new ArrayList<>();
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);
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);
forceShowOnJoin = cosmeticSettings.node(FORCE_SHOW_COSMETICS_PATH).getBoolean(false);
destroyLooseCosmetics = cosmeticSettings.node(COSMETIC_DESTROY_LOOSE_COSMETIC_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);
backpackForceRidingEnabled = cosmeticSettings.node(COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH).getBoolean(false);
preventOffhandSwapping = cosmeticSettings.node(COSMETIC_OFFHAND_PREVENT_SWAPPING).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);
lookDownPitch = cosmeticSettings.node(LOOK_DOWN_PITCH_PATH).getInt();
viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt();
viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt(-3);
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();
sequentRowShift = shadingSettings.node(SEQUENT_ROW_SHIFT_PATH).getString();
individualColumnShift = shadingSettings.node(INDIVIDUAL_COLUMN_SHIFT_PATH).getString();
background = shadingSettings.node(BACKGROUND_PATH).getString();
clearBackground = shadingSettings.node(CLEAR_BACKGROUND_PATH).getString();
equippedCosmeticColor = shadingSettings.node(EQUIPPED_COSMETIC_COLOR_PATH).getString();
equipableCosmeticColor = shadingSettings.node(EQUIPABLE_COSMETIC_COLOR_PATH).getString();
lockedCosmeticColor = shadingSettings.node(LOCKED_COSMETIC_COLOR_PATH).getString();
ConfigurationNode cosmeticTypeSettings = menuSettings.node(COSMETIC_TYPE_SETTINGS_PATH);
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);
ConfigurationNode dyeMenuSettings = source.node(DYE_MENU_PATH);
@@ -131,9 +240,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.
@@ -143,167 +259,13 @@ public class Settings {
}
}
private static Vector loadVector(final ConfigurationNode config) {
public static Vector loadVector(final ConfigurationNode config) {
return new Vector(config.node("x").getDouble(), config.node("y").getDouble(), config.node("z").getDouble());
}
public static boolean isRequireEmptyHelmet() {
return requireEmptyHelmet;
}
public static boolean isRequireEmptyOffHand() {
return requireEmptyOffHand;
}
public static boolean isRequireEmptyChestPlate() {
return requireEmptyChestPlate;
}
public static boolean isRequireEmptyPants() {
return requireEmptyPants;
}
public static boolean isRequireEmptyBoots() {
return requireEmptyBoots;
}
public static boolean getRequireEmpty(CosmeticSlot slot) {
switch (slot) {
case HELMET -> {
return requireEmptyHelmet;
}
case CHESTPLATE -> {
return requireEmptyChestPlate;
}
case LEGGINGS -> {
return requireEmptyPants;
}
case BOOTS -> {
return requireEmptyBoots;
}
case OFFHAND -> {
return requireEmptyOffHand;
}
}
return false;
}
public static boolean getRequireEmpty(EquipmentSlot slot) {
switch (slot) {
case HEAD -> {
return requireEmptyHelmet;
}
case CHEST -> {
return requireEmptyChestPlate;
}
case LEGS -> {
return requireEmptyPants;
}
case FEET -> {
return requireEmptyBoots;
}
case OFF_HAND -> {
return requireEmptyOffHand;
}
}
return false;
}
public static Vector getBalloonOffset() {
if (balloonOffset == null) HMCCosmeticsPlugin.getInstance().getLogger().info("Shits null");
return balloonOffset;
}
public static int getLookDownPitch() {
return lookDownPitch;
}
public static int getViewDistance() {
return viewDistance;
}
public static String getDefaultMenu() {
return defaultMenu;
}
public static int getConfigVersion() {
return configVersion;
}
public static String getDyeMenuName() {
return dyeMenuName;
}
public static int getDyeMenuInputSlot() { return dyeMenuInputSlot; }
public static int getDyeMenuOutputSlot() { return dyeMenuOutputSlot; }
public static boolean isDebugEnabled() {
return debugMode;
}
public static boolean getItemsAdderReloadChange() {
return itemsAdderChangeReload;
}
public static int getTickPeriod() {
return tickPeriod;
}
public static boolean getUnapplyOnDeath() {
return unapplyOnDeath;
}
public static boolean getForcePermissionJoin() {
return forcePermissionJoin;
}
public static boolean getDebugMode() {
return debugMode;
}
public static double getEmoteDistance() {
return emoteDistance;
}
public static boolean getCosmeticEmoteBlockCheck() {
return cosmeticEmoteBlockCheck;
}
public static boolean getEmoteAirCheck() {
return emoteAirCheck;
}
public static boolean isEmoteDamageLeave() {
return emoteDamageLeave;
}
public static boolean isEmoteInvincible() {
return emoteInvincible;
}
public static boolean isWorldGuardMoveCheckEnabled() {
return worldGuardMoveCheck;
}
public static boolean isDestroyLooseCosmetics() {
return destroyLooseCosmetics;
}
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) {
@@ -315,4 +277,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

@@ -1,60 +1,60 @@
package com.hibiscusmc.hmccosmetics.config;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
public class Wardrobe {
private String id;
private int distance = WardrobeSettings.getDefaultDistance();
@Getter
private final String id;
@Getter @Setter
private int distance;
@Getter @Setter @Nullable
private String permission;
@Getter @Setter
private WardrobeLocation location;
@Getter @Setter @Nullable
private String defaultMenu;
public Wardrobe(String id, WardrobeLocation location, @Nullable String permission, int distance) {
/**
* This creates a Wardrobe object with all the information that a user will need when entering.
* @param id The id of the 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, @Nullable String defaultMenu) {
this.id = id;
this.location = location;
if (permission != null) this.permission = permission;
if (distance != -1) this.distance = distance;
}
public String getId() {
return id;
}
public WardrobeLocation getLocation() {
return location;
}
public void setDistance(int distance) {
this.distance = distance;
if (permission != null) this.permission = permission;
if (defaultMenu != null) this.defaultMenu = defaultMenu;
}
public void setPermission(String permission) {
this.permission = permission;
}
/**
* This checks if the wardrobe has a permission. If it's null, no permission is required and will return false. If it's not null, it will return true.
* @return if the wardrobe has a permission
*/
public boolean hasPermission() {
return permission != null;
}
public int getDistance() {
return distance;
}
public String getPermission() {
return permission;
}
public void setLocation(WardrobeLocation location) {
this.location = location;
}
public boolean canEnter(CosmeticUser user) {
/**
* Calculates if a player can enter a wardrobe. Will return true if the player can enter, else false.
* @param user The user that is trying to enter the wardrobe
* @return if the player can enter the wardrobe
*/
public boolean canEnter(@NotNull CosmeticUser user) {
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

@@ -1,45 +1,36 @@
package com.hibiscusmc.hmccosmetics.config;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import org.jetbrains.annotations.Nullable;
public class WardrobeLocation {
@Getter @Setter
private Location npcLocation;
@Getter @Setter
private Location viewerLocation;
@Getter @Setter
private Location leaveLocation;
public WardrobeLocation(Location npcLocation, Location viewerLocation, Location leaveLocation) {
/**
* This creates a WardrobeLocation object with the 3 locations that are required for a wardrobe to work
* @param npcLocation The location of the NPC
* @param viewerLocation The location of the viewer
* @param leaveLocation The location that the player will be teleported to when they leave the wardrobe if return-last-location in the config is false
*/
public WardrobeLocation(@Nullable Location npcLocation, @Nullable Location viewerLocation, @Nullable Location leaveLocation) {
this.npcLocation = npcLocation;
this.viewerLocation = viewerLocation;
this.leaveLocation = leaveLocation;
}
public Location getNpcLocation() {
return npcLocation.clone();
}
public Location getViewerLocation() {
return viewerLocation.clone();
}
public Location getLeaveLocation() {
return leaveLocation.clone();
}
/**
* Checks if any of the locations are null
* @return true if all locations are not null, else false
*/
public boolean hasAllLocations() {
if (npcLocation == null || viewerLocation == null || leaveLocation == null) return false;
return true;
}
public void setNPCLocation(Location wardrobeLocation) {
this.npcLocation = wardrobeLocation;
}
public void setViewerLocation(Location viewerLocation) {
this.viewerLocation = viewerLocation;
}
public void setLeaveLocation(Location leaveLocation) {
this.leaveLocation = leaveLocation;
return npcLocation != null && viewerLocation != null && leaveLocation != null;
}
}

View File

@@ -1,26 +1,25 @@
package com.hibiscusmc.hmccosmetics.config;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.serializer.LocationSerializer;
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;
import net.kyori.adventure.bossbar.BossBar;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.spongepowered.configurate.ConfigurationNode;
import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.logging.Level;
public class WardrobeSettings {
private static final String WARDROBE_PATH = "wardrobe";
private static final String DISABLE_ON_DAMAGE_PATH = "disable-on-damage";
private static final String DISPLAY_RADIUS_PATH = "display-radius";
private static final String PORTABLE_PATH = "portable";
private static final String ALWAYS_DISPLAY_PATH = "always-display";
private static final String STATIC_RADIUS_PATH = "static-radius";
private static final String ROTATION_SPEED_PATH = "rotation-speed";
private static final String SPAWN_DELAY_PATH = "spawn-delay";
private static final String DESPAWN_DELAY_PATH = "despawn-delay";
@@ -33,12 +32,19 @@ public class WardrobeSettings {
private static final String EQUIP_PUMPKIN_WARDROBE = "equip-pumpkin";
private static final String TRY_COSMETICS_WARDROBE = "unchecked-wardrobe-cosmetics";
private static final String RETURN_LAST_LOCATION = "return-last-location";
private static final String DAMAGE_KICK_PATH = "damage-kicked";
private static final String PREVENT_DAMAGE_PATH = "prevent-damage";
private static final String WARDROBE_MENU_OPTIONS = "menu-options";
private static final String WARDROBE_ENTER_OPEN_MENU_PATH = "enter-open-menu";
private static final String GAMEMODE_OPTIONS_PATH = "gamemode-options";
private static final String FORCE_EXIT_GAMEMODE_PATH = "exit-gamemode-enabled";
private static final String EXIT_GAMEMODE_PATH = "exit-gamemode";
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";
@@ -54,40 +60,65 @@ public class WardrobeSettings {
private static final String TRANSITION_FADE_OUT_PATH = "title-fade-out";
private static ConfigurationNode configRoot;
@Getter
private static boolean disableOnDamage;
private static int displayRadius;
@Getter
private static boolean portable;
@Getter
private static boolean alwaysDisplay;
private static int staticRadius;
@Getter
private static int rotationSpeed;
@Getter
private static int spawnDelay;
@Getter
private static int despawnDelay;
@Getter
private static float bossbarProgress;
@Getter
private static boolean applyCosmeticsOnClose;
@Getter
private static boolean tryCosmeticsInWardrobe;
@Getter
private static boolean equipPumpkin;
@Getter
private static boolean returnLastLocation;
@Getter
private static boolean enabledBossbar;
@Getter
private static boolean enterOpenMenu;
@Getter
private static boolean forceExitGamemode;
@Getter
private static boolean damagedKicked;
@Getter
private static boolean preventDamage;
@Getter
private static GameMode exitGamemode;
private static HashMap<String, Wardrobe> wardrobes;
@Getter
private static String bossbarMessage;
@Getter
private static BossBar.Overlay bossbarOverlay;
@Getter
private static BossBar.Color bossbarColor;
@Getter
private static boolean enabledTransition;
@Getter
private static String transitionText;
@Getter
private static int transitionDelay;
@Getter
private static int transitionFadeIn;
@Getter
private static int transitionStay;
@Getter
private static int transitionFadeOut;
public static void load(ConfigurationNode source) {
configRoot = source;
disableOnDamage = source.node(DISABLE_ON_DAMAGE_PATH).getBoolean();
displayRadius = source.node(DISPLAY_RADIUS_PATH).getInt();
portable = source.node(PORTABLE_PATH).getBoolean();
staticRadius = source.node(STATIC_RADIUS_PATH).getInt();
alwaysDisplay = source.node(ALWAYS_DISPLAY_PATH).getBoolean();
rotationSpeed = source.node(ROTATION_SPEED_PATH).getInt();
spawnDelay = source.node(SPAWN_DELAY_PATH).getInt();
@@ -96,6 +127,11 @@ public class WardrobeSettings {
equipPumpkin = source.node(EQUIP_PUMPKIN_WARDROBE).getBoolean();
returnLastLocation = source.node(RETURN_LAST_LOCATION).getBoolean(false);
tryCosmeticsInWardrobe = source.node(TRY_COSMETICS_WARDROBE).getBoolean(false);
damagedKicked = source.node(DAMAGE_KICK_PATH).getBoolean(false);
preventDamage = source.node(PREVENT_DAMAGE_PATH).getBoolean(true);
ConfigurationNode menuOptionsNode = source.node(WARDROBE_MENU_OPTIONS);
enterOpenMenu = menuOptionsNode.node(WARDROBE_ENTER_OPEN_MENU_PATH).getBoolean(false);
ConfigurationNode gamemodeNode = source.node(GAMEMODE_OPTIONS_PATH);
forceExitGamemode = gamemodeNode.node(FORCE_EXIT_GAMEMODE_PATH).getBoolean(false);
@@ -133,69 +169,21 @@ 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 = null;
int distance = -1;
if (!wardrobesNode.node(PERMISSION_PATH).virtual()) permission = wardrobesNode.node(PERMISSION_PATH).getString();
if (!wardrobesNode.node(DISTANCE_PATH).virtual()) distance = wardrobesNode.node(DISTANCE_PATH).getInt();
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);
}
}
//throw new RuntimeException(e);
}
public static int getDefaultDistance() {
return staticRadius;
}
public static boolean getDisableOnDamage() {
return disableOnDamage;
}
public static int getDisplayRadius() {
return displayRadius;
}
public static boolean isPortable() {
return portable;
}
public static boolean isAlwaysDisplay() {
return alwaysDisplay;
}
public static int getStaticRadius() {
return staticRadius;
}
public static int getRotationSpeed() {
return rotationSpeed;
}
public static int getSpawnDelay() {
return spawnDelay;
}
public static int getDespawnDelay() {
return despawnDelay;
}
public static boolean isApplyCosmeticsOnClose() {
return applyCosmeticsOnClose;
}
public static boolean isEquipPumpkin() {
return equipPumpkin;
}
public static boolean isReturnLastLocation() {
return returnLastLocation;
}
public static Wardrobe getWardrobe(String key) {
@@ -218,80 +206,12 @@ public class WardrobeSettings {
wardrobes.remove(id);
}
@Deprecated
public static boolean inDistanceOfWardrobe(final Location wardrobeLocation, final Location playerLocation) {
if (displayRadius == -1) return true;
if (!wardrobeLocation.getWorld().equals(playerLocation.getWorld())) return false;
return playerLocation.distanceSquared(wardrobeLocation) <= displayRadius * displayRadius;
}
@Deprecated
public static boolean inDistanceOfStatic(Wardrobe wardrobe, final Location location) {
Location wardrobeLocation = wardrobe.getLocation().getNpcLocation();
if (wardrobeLocation == null) return false;
if (staticRadius == -1) return true;
if (!wardrobeLocation.getWorld().equals(location.getWorld())) return false;
return wardrobeLocation.distanceSquared(location) <= staticRadius * staticRadius;
}
public static boolean getEnabledBossbar() {
return enabledBossbar;
}
public static float getBossbarProgress() {
return bossbarProgress;
}
public static String getBossbarText() {
return bossbarMessage;
}
public static BossBar.Overlay getBossbarOverlay() {
return bossbarOverlay;
}
public static BossBar.Color getBossbarColor() {
return bossbarColor;
}
public static boolean isEnabledTransition() {
return enabledTransition;
}
public static String getTransitionText() {
return transitionText;
}
public static int getTransitionDelay() {
return transitionDelay;
}
public static int getTransitionFadeIn() {
return transitionFadeIn;
}
public static int getTransitionStay() {
return transitionStay;
}
public static int getTransitionFadeOut() {
return transitionFadeOut;
}
public static boolean isForceExitGamemode() {
return forceExitGamemode;
}
public static GameMode getExitGamemode() {
return exitGamemode;
}
public static boolean isTryCosmeticsInWardrobe() {
return tryCosmeticsInWardrobe;
}
/**
* Sets where the NPC/Mannequin will spawn in the wardrobe
* @param newLocation
*/
public static void setNPCLocation(Wardrobe wardrobe, Location newLocation) {
wardrobe.getLocation().setNPCLocation(newLocation);
wardrobe.getLocation().setNpcLocation(newLocation);
HMCCosmeticsPlugin plugin = HMCCosmeticsPlugin.getInstance();
@@ -362,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

@@ -1,165 +0,0 @@
package com.hibiscusmc.hmccosmetics.config.serializer;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.hooks.Hooks;
import com.hibiscusmc.hmccosmetics.util.InventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.ServerUtils;
import com.hibiscusmc.hmccosmetics.util.builder.ColorBuilder;
import com.hibiscusmc.hmccosmetics.util.misc.StringUtils;
import com.hibiscusmc.hmccosmetics.util.misc.Utils;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.*;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.persistence.PersistentDataType;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class ItemSerializer implements TypeSerializer<ItemStack> {
public static final ItemSerializer INSTANCE = new ItemSerializer();
private static final String MATERIAL = "material";
private static final String AMOUNT = "amount";
private static final String NAME = "name";
private static final String UNBREAKABLE = "unbreakable";
private static final String GLOWING = "glowing";
private static final String LORE = "lore";
private static final String MODEL_DATA = "model-data";
private static final String NBT_TAGS = "nbt-tag";
private static final String ENCHANTS = "enchants";
private static final String ITEM_FLAGS = "item-flags";
private static final String TEXTURE = "texture";
private static final String OWNER = "owner";
private static final String COLOR = "color";
private static final String RED = "red";
private static final String GREEN = "green";
private static final String BLUE = "blue";
private ItemSerializer() {
}
@Override
public ItemStack deserialize(final Type type, final ConfigurationNode source)
throws SerializationException {
final ConfigurationNode materialNode = source.node(MATERIAL);
final ConfigurationNode amountNode = source.node(AMOUNT);
final ConfigurationNode nameNode = source.node(NAME);
final ConfigurationNode unbreakableNode = source.node(UNBREAKABLE);
final ConfigurationNode glowingNode = source.node(GLOWING);
final ConfigurationNode loreNode = source.node(LORE);
final ConfigurationNode modelDataNode = source.node(MODEL_DATA);
final ConfigurationNode nbtNode = source.node(NBT_TAGS);
final ConfigurationNode enchantsNode = source.node(ENCHANTS);
final ConfigurationNode itemFlagsNode = source.node(ITEM_FLAGS);
final ConfigurationNode textureNode = source.node(TEXTURE);
final ConfigurationNode ownerNode = source.node(OWNER);
final ConfigurationNode colorNode = source.node(COLOR);
final ConfigurationNode redNode = colorNode.node(RED);
final ConfigurationNode greenNode = colorNode.node(GREEN);
final ConfigurationNode blueNode = colorNode.node(BLUE);
if (materialNode.virtual()) return null;
String material = materialNode.getString();
ItemStack item = Hooks.getItem(material);
if (item == null) {
HMCCosmeticsPlugin.getInstance().getLogger().severe("Invalid Material -> " + material);
return new ItemStack(Material.AIR);
}
item.setAmount(amountNode.getInt(1));
ItemMeta itemMeta = item.getItemMeta();
if (itemMeta == null) return item;
if (!nameNode.virtual())
itemMeta.setDisplayName(StringUtils.parseStringToString(Utils.replaceIfNull(nameNode.getString(), "")));
if (!unbreakableNode.virtual()) itemMeta.setUnbreakable(unbreakableNode.getBoolean());
if (!glowingNode.virtual()) {
itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
itemMeta.addEnchant(Enchantment.LUCK, 1, true);
}
if (!loreNode.virtual()) itemMeta.setLore(Utils.replaceIfNull(loreNode.getList(String.class),
new ArrayList<String>()).
stream().map(StringUtils::parseStringToString).collect(Collectors.toList()));
if (!modelDataNode.virtual()) itemMeta.setCustomModelData(modelDataNode.getInt());
if (!nbtNode.virtual()) {
for (ConfigurationNode nbtNodes : nbtNode.childrenMap().values()) {
itemMeta.getPersistentDataContainer().set(NamespacedKey.minecraft(nbtNodes.key().toString()), PersistentDataType.STRING, nbtNodes.getString());
}
}
if (!enchantsNode.virtual()) {
for (ConfigurationNode enchantNode : enchantsNode.childrenMap().values()) {
if (Enchantment.getByKey(NamespacedKey.minecraft(enchantNode.key().toString())) == null) continue;
itemMeta.addEnchant(Enchantment.getByKey(NamespacedKey.minecraft(enchantNode.key().toString())), enchantNode.getInt(1), true);
}
}
try {
if (!itemFlagsNode.virtual()) {
for (String itemFlag : itemFlagsNode.getList(String.class)) {
if (!EnumUtils.isValidEnum(ItemFlag.class, itemFlag)) continue;
MessagesUtil.sendDebugMessages("Added " + itemFlag + " to the item!");
itemMeta.addItemFlags(ItemFlag.valueOf(itemFlag));
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (item.getType() == Material.PLAYER_HEAD) {
SkullMeta skullMeta = (SkullMeta) itemMeta;
if (!ownerNode.virtual()) {
String ownerString = ownerNode.getString();
if (ownerString.contains("%")) {
// This means it has PAPI placeholders in it
skullMeta.getPersistentDataContainer().set(InventoryUtils.getSkullOwner(), PersistentDataType.STRING, ownerString);
}
OfflinePlayer player = Bukkit.getOfflinePlayer(ownerString);
skullMeta.setOwningPlayer(player);
}
if (!textureNode.virtual()) {
String textureString = textureNode.getString();
if (textureString.contains("%")) {
// This means it has PAPI placeholders in it
skullMeta.getPersistentDataContainer().set(InventoryUtils.getSkullTexture(), PersistentDataType.STRING, textureString);
}
Bukkit.getUnsafe().modifyItemStack(item, "{SkullOwner:{Id:[I;0,0,0,0],Properties:{textures:[{Value:\""
+ textureString + "\"}]}}}");
itemMeta = skullMeta;
}
}
if (!colorNode.virtual()) {
if (ColorBuilder.canBeColored(item.getType())) {
if (!redNode.virtual()) {
itemMeta = ColorBuilder.color(itemMeta, Color.fromRGB(redNode.getInt(0), greenNode.getInt(0), blueNode.getInt(0)));
} else {
itemMeta = ColorBuilder.color(itemMeta, ServerUtils.hex2Rgb(colorNode.getString("#FFFFFF")));
}
}
}
item.setItemMeta(itemMeta);
return item;
}
@Override
public void serialize(final Type type, @Nullable final ItemStack obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -1,46 +0,0 @@
package com.hibiscusmc.hmccosmetics.config.serializer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
public class LocationSerializer implements TypeSerializer<Location> {
public static final LocationSerializer INSTANCE = new LocationSerializer();
private static final String WORLD = "world";
private static final String X = "x";
private static final String Y = "y";
private static final String Z = "z";
private static final String PITCH = "pitch";
private static final String YAW = "yaw";
private LocationSerializer() {}
@Override
@Nullable
public Location deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
final World world = Bukkit.getWorld(source.node(WORLD).getString());
if (world == null) return null;
return new Location(
world,
source.node(X).getDouble(),
source.node(Y).getDouble(),
source.node(Z).getDouble(),
source.node(YAW).getFloat(),
source.node(PITCH).getFloat()
);
}
@Override
public void serialize(final Type type, @Nullable final Location loc, final ConfigurationNode source) throws SerializationException {
// Empty
}
}

View File

@@ -1,28 +1,69 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.config.serializer.ItemSerializer;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
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.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.List;
import java.util.logging.Level;
@Getter
@Setter
public abstract class Cosmetic {
protected static ItemStack UNDEFINED_DISPLAY_ITEM_STACK;
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;
private String permission;
private ItemStack item;
private String material;
private CosmeticSlot slot;
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;
/** The config for the cosmetic */
private ConfigurationNode config;
protected Cosmetic(@NotNull String id, @NotNull ConfigurationNode config) {
this.id = id;
this.config = config;
if (!config.node("permission").virtual()) {
this.permission = config.node("permission").getString();
@@ -32,66 +73,66 @@ 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));
MessagesUtil.sendDebugMessages("Dyeable " + dyable);
Cosmetics.addCosmetic(this);
this.dyeable = config.node("dyeable").getBoolean(false);
MessagesUtil.sendDebugMessages("Dyeable " + dyeable);
}
public String getId() {
return this.id;
}
public void setId(String id) {
protected Cosmetic(String id, String permission, ItemStack item, String material, CosmeticSlot slot, boolean dyeable) {
this.id = id;
}
public CosmeticSlot getSlot() {
return this.slot;
}
public void setSlot(CosmeticSlot slot) {
this.slot = slot;
}
public String getPermission() {
return this.permission;
}
public void setPermission(String permission) {
this.permission = permission;
this.item = item;
this.material = material;
this.slot = slot;
this.dyeable = dyeable;
}
public boolean requiresPermission() {
return permission != null;
}
public void setDyable(boolean dyable) {
this.dyable = dyable;
/**
* Dispatched when an update is requested upon the cosmetic. Instead, you should use {@link CosmeticUser#updateCosmetic(CosmeticSlot)})}
* @param user the user to preform the update against
*/
@Deprecated(since = "2.8.2")
public void update(CosmeticUser user) {
if(this instanceof CosmeticUpdateBehavior behavior) {
behavior.dispatchUpdate(user);
}
}
public boolean isDyable() {
return this.dyable;
/**
* Action preformed on the update. Instead, you should use {@link CosmeticUser#updateCosmetic(CosmeticSlot)})}
* @param user the user to preform the update against
*/
@Deprecated(since = "2.8.2")
protected void doUpdate(final CosmeticUser user) {
// #update should be the preferred way of interacting with this api now.
this.update(user);
}
public String getMaterial() {
return material;
}
public abstract void update(CosmeticUser user);
@Nullable
public ItemStack getItem() {
if (item == null) return null;
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);
@@ -105,4 +146,14 @@ public abstract class Cosmetic {
throw new RuntimeException(e);
}
}
/**
* While cosmetics registered in HMCC are made through a configuration, cosmetics registered from other plugins
* may not and instead opt for {@link Cosmetic#Cosmetic(String, String, ItemStack, String, CosmeticSlot, boolean)}, which doesn't use a config.
* This should be used only for reference.
*/
@ApiStatus.Experimental
public @Nullable ConfigurationNode getConfig() {
return config;
}
}

View File

@@ -0,0 +1,78 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
import com.google.common.collect.ImmutableCollection;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Color;
import org.bukkit.Location;
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);
boolean updateCosmetic(@NotNull CosmeticSlot slot);
boolean updateMovementCosmetic(@NotNull CosmeticSlot slot, final Location from, final Location to);
/**
* 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,68 @@
package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.types.*;
import lombok.extern.slf4j.Slf4j;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
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.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,26 +2,29 @@ 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 org.apache.commons.lang3.EnumUtils;
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.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
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);
}
@@ -31,7 +34,7 @@ public class Cosmetics {
}
public static void removeCosmetic(Cosmetic cosmetic) {
COSMETICS.remove(cosmetic);
COSMETICS.remove(cosmetic.getId());
}
@Nullable
@@ -68,45 +71,71 @@ public class Cosmetics {
File[] directoryListing = cosmeticFolder.listFiles();
if (directoryListing == null) return;
for (File child : directoryListing) {
if (child.toString().contains(".yml") || child.toString().contains(".yaml")) {
MessagesUtil.sendDebugMessages("Scanning " + child);
// Loads file
YamlConfigurationLoader loader = YamlConfigurationLoader.builder().path(child.toPath()).build();
CommentedConfigurationNode root;
try {
root = loader.load();
} catch (ConfigurateException e) {
throw new RuntimeException(e);
try (Stream<Path> walkStream = Files.walk(cosmeticFolder.toPath())) {
walkStream.filter(p -> p.toFile().isFile()).forEach(child -> {
if (child.toString().contains(".yml") || child.toString().contains(".yaml")) {
MessagesUtil.sendDebugMessages("Scanning " + child);
// Loads file
YamlConfigurationLoader loader = YamlConfigurationLoader.builder().path(child).build();
CommentedConfigurationNode root;
try {
root = loader.load();
} catch (ConfigurateException e) {
throw new RuntimeException(e);
}
setupCosmetics(root);
}
setupCosmetics(root);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 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.isDebugEnabled()) 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

@@ -0,0 +1,16 @@
package com.hibiscusmc.hmccosmetics.cosmetic.behavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
/**
* Updates cosmetics whenever a player moves.
*/
public interface CosmeticMovementBehavior {
void dispatchMove(
@NotNull final CosmeticUser user,
@NotNull final Location from,
@NotNull final Location to
);
}

View File

@@ -0,0 +1,13 @@
package com.hibiscusmc.hmccosmetics.cosmetic.behavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.jetbrains.annotations.NotNull;
/**
* Generic updates that happen every tick or when manually requested to be dispatched.
*/
public interface CosmeticUpdateBehavior {
void dispatchUpdate(
@NotNull final CosmeticUser user
);
}

View File

@@ -2,11 +2,12 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.nms.NMSHandlers;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.InventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.PacketManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
@@ -14,37 +15,51 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
public class CosmeticArmorType extends Cosmetic {
public class CosmeticArmorType extends Cosmetic implements CosmeticUpdateBehavior {
private final EquipmentSlot equipSlot;
public CosmeticArmorType(String id, ConfigurationNode config) {
super(id, config);
this.equipSlot = InventoryUtils.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) {
public void dispatchUpdate(@NotNull CosmeticUser user) {
if (user.isInWardrobe()) return;
Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return;
if (user.getUserEmoteManager().isPlayingEmote()) return; // There has to be a better way of doing this...
ItemStack cosmeticItem = user.getUserCosmeticItem(this);
if (!(entity instanceof HumanEntity humanEntity)) return;
if (equipSlot.equals(EquipmentSlot.OFF_HAND)) {
if (!humanEntity.getInventory().getItemInOffHand().getType().isAir()) return;
if (Settings.getSlotOption(equipSlot).isRequireEmpty() && entity instanceof HumanEntity humanEntity) {
if (!humanEntity.getInventory().getItem(equipSlot).getType().isAir()) return;
}
ItemStack equippedItem = humanEntity.getInventory().getItem(equipSlot);
if (Settings.getShouldAddEnchants(equipSlot)) {
cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments());
}
NMSHandlers.getHandler().equipmentSlotUpdate(entity.getEntityId(), equipSlot, cosmeticItem, PacketManager.getViewers(entity.getLocation()));
//PacketManager.equipmentSlotUpdate(player, getSlot(), PacketManager.getViewers(player.getLocation())); Old method
ItemStack item = getItem(user);
if (item == null) return;
PacketManager.equipmentSlotUpdate(entity.getEntityId(), equipSlot, item, HMCCPacketManager.getViewers(entity.getLocation()));
}
public ItemStack getItem(@NotNull CosmeticUser user) {
return getItem(user, user.getUserCosmeticItem(this));
}
public ItemStack getItem(@NotNull CosmeticUser user, ItemStack cosmeticItem) {
Player player = user.getPlayer();
if (player == null) return null;
if (Settings.getSlotOption(equipSlot).isAddEnchantments()) {
ItemStack equippedItem = player.getInventory().getItem(equipSlot);
cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments());
}
// Basically, if force offhand is off AND there is no item in an offhand slot, then the equipment packet to add the cosmetic
return cosmeticItem;
}
@NotNull
public EquipmentSlot getEquipSlot() {
return this.equipSlot;
}

View File

@@ -1,67 +1,125 @@
package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticMovementBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.PacketManager;
import org.bukkit.Bukkit;
import com.hibiscusmc.hmccosmetics.user.manager.UserEntity;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Location;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
import java.util.logging.Level;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class CosmeticBackpackType extends Cosmetic {
private final String modelName;
private UserBackpackManager.BackpackType backpackType;
@Getter
public class CosmeticBackpackType extends Cosmetic implements CosmeticUpdateBehavior, CosmeticMovementBehavior {
private int height = -1;
private ItemStack firstPersonBackpack;
public CosmeticBackpackType(String id, ConfigurationNode config) {
super(id, config);
modelName = config.node("model").getString();
backpackType = UserBackpackManager.BackpackType.valueOf(config.node("type").getString("NORMAL").toUpperCase());
if (!config.node("firstperson-item").virtual()) {
this.firstPersonBackpack = generateItemStack(config.node("firstperson-item"));
this.height = config.node("height").getInt(5);
}
}
@Override
public void update(@NotNull CosmeticUser user) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return;
Location loc = entity.getLocation().clone().add(0, 2, 0);
if (user.isInWardrobe() || !user.isBackpackSpawned()) return;
if (!user.getUserBackpackManager().IsValidBackpackEntity()) {
MessagesUtil.sendDebugMessages("Invalid Backpack Entity[owner=" + user.getUniqueId() + ",player_location=" + loc + "]!", Level.WARNING);
user.respawnBackpack();
public void dispatchUpdate(@NotNull CosmeticUser user) {
Entity entity = user.getEntity();
if(entity == null) {
return;
}
if (loc.getWorld() != user.getUserBackpackManager().getArmorStand().getWorld()) {
user.getUserBackpackManager().getArmorStand().teleport(loc);
Location entityLocation = entity.getLocation();
Location loc = entityLocation.clone().add(0, 2, 0);
UserBackpackManager backpackManager = user.getUserBackpackManager();
if(backpackManager == null) return;
UserEntity entityManager = backpackManager.getEntityManager();
if(entityManager == null) return;
entityManager.teleport(loc);
entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible());
int firstArmorStandId = backpackManager.getFirstArmorStandId();
List<Player> newViewers = entityManager.refreshViewers(loc);
if(!newViewers.isEmpty()) {
HMCCPacketManager.spawnInvisibleArmorstand(firstArmorStandId, entityLocation, UUID.randomUUID(), newViewers);
PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), newViewers);
if (user.getPlayer() != null) {
AttributeInstance scaleAttribute = user.getPlayer().getAttribute(Attribute.SCALE);
if (scaleAttribute != null) {
HMCCPacketManager.sendEntityScalePacket(user.getUserBackpackManager().getFirstArmorStandId(), scaleAttribute.getValue(), newViewers);
}
}
}
user.getUserBackpackManager().getArmorStand().teleport(loc);
// 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(), firstArmorStandId, entityManager.getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, newViewers);
if (user.getUserBackpackManager().getBackpackType().equals(UserBackpackManager.BackpackType.FIRST_PERSON)) {
user.getUserBackpackManager().teleportEffectEntity(loc);
PacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getAreaEffectEntityId(), loc);
PacketManager.sendRidingPacket(user.getUserBackpackManager().getAreaEffectEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), loc);
} else {
PacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), loc);
if (isFirstPersonCompadible() && !user.isInWardrobe() && user.getPlayer() != null) {
List<Player> owner = List.of(user.getPlayer());
ArrayList<Integer> particleCloud = backpackManager.getAreaEffectEntityId();
for (int i = 0; i < particleCloud.size(); i++) {
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), firstArmorStandId, owner);
if (!user.isHidden()) {
PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
}
}
user.getUserBackpackManager().getArmorStand().setRotation(loc.getYaw(), loc.getPitch());
user.getUserBackpackManager().showBackpack();
backpackManager.showBackpack();
}
public String getModelName() {
return modelName;
@Override
public void dispatchMove(@NotNull CosmeticUser user, @NotNull Location from, @NotNull Location to) {
@SuppressWarnings("DuplicatedCode") // thanks.
Entity entity = user.getEntity();
if(entity == null) {
return;
}
Location entityLocation = entity.getLocation();
Location loc = entityLocation.clone().add(0, 2, 0);
UserBackpackManager backpackManager = user.getUserBackpackManager();
if(backpackManager == null) return;
UserEntity entityManager = backpackManager.getEntityManager();
if(entityManager == null) return;
entityManager.teleport(loc);
entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible());
}
public UserBackpackManager.BackpackType getBackpackType() {
return backpackType;
public boolean isFirstPersonCompadible() {
return firstPersonBackpack != null;
}
}

View File

@@ -2,48 +2,61 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticMovementBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.packets.PacketManager;
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;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.List;
public class CosmeticBalloonType extends Cosmetic {
public class CosmeticBalloonType extends Cosmetic implements CosmeticUpdateBehavior, CosmeticMovementBehavior {
@Getter
private final String modelName;
private List<String> dyableParts;
private boolean showLead;
@Getter
private List<String> dyeableParts;
@Getter
private final boolean showLead;
@Getter
private Vector balloonOffset;
public CosmeticBalloonType(String id, ConfigurationNode config) {
super(id, config);
String modelId = config.node("model").getString();
showLead = config.node("show-lead").getBoolean(true);
ConfigurationNode balloonOffsetNode = config.node("balloon-offset");
if (balloonOffsetNode.virtual())
balloonOffset = Settings.getBalloonOffset();
else
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?
throw new RuntimeException(e);
}
if (modelId != null) modelId = modelId.toLowerCase(); // ME only accepts lowercase
this.modelName = modelId;
}
@Override
public void update(@NotNull CosmeticUser user) {
public void dispatchUpdate(@NotNull CosmeticUser user) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
UserBalloonManager userBalloonManager = user.getBalloonManager();
@@ -56,47 +69,58 @@ public class CosmeticBalloonType extends Cosmetic {
}
Location newLocation = entity.getLocation();
Location currentLocation = user.getBalloonManager().getLocation();
newLocation = newLocation.clone().add(Settings.getBalloonOffset());
newLocation = newLocation.clone().add(getBalloonOffset());
if (Settings.isBalloonHeadForward()) newLocation.setPitch(0);
List<Player> viewer = PacketManager.getViewers(entity.getLocation());
if (!user.isHidden() && showLead) {
List<Player> sendTo = userBalloonManager.getPufferfish().refreshViewers(newLocation);
if (sendTo.isEmpty()) return;
user.getBalloonManager().getPufferfish().spawnPufferfish(newLocation, sendTo);
}
}
@Override
public void dispatchMove(@NotNull CosmeticUser user, @NotNull Location from, @NotNull Location to) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
UserBalloonManager userBalloonManager = user.getBalloonManager();
if (entity == null || userBalloonManager == null) return;
if (user.isInWardrobe()) return;
if (!userBalloonManager.getModelEntity().isValid()) {
return;
}
Location newLocation = entity.getLocation();
Location currentLocation = user.getBalloonManager().getLocation();
newLocation = newLocation.clone().add(getBalloonOffset());
if (Settings.isBalloonHeadForward()) newLocation.setPitch(0);
List<Player> viewer = HMCCPacketManager.getViewers(entity.getLocation());
if (entity.getLocation().getWorld() != userBalloonManager.getLocation().getWorld()) {
userBalloonManager.getModelEntity().teleport(newLocation);
PacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
HMCCPacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
return;
}
Vector velocity = newLocation.toVector().subtract(currentLocation.toVector());
userBalloonManager.setVelocity(velocity.multiply(1.1));
userBalloonManager.setLocation(newLocation);
userBalloonManager.setVelocity(velocity.multiply(1.1));
PacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
PacketManager.sendLeashPacket(userBalloonManager.getPufferfishBalloonId(), entity.getEntityId(), viewer);
if (!user.getHidden() && showLead) {
List<Player> sendTo = userBalloonManager.getPufferfish().refreshViewers(newLocation);
if (sendTo.isEmpty()) return;
PacketManager.sendEntitySpawnPacket(newLocation, userBalloonManager.getPufferfishBalloonId(), EntityType.PUFFERFISH, userBalloonManager.getPufferfishBalloonUniqueId(), sendTo);
PacketManager.sendInvisibilityPacket(userBalloonManager.getPufferfishBalloonId(), sendTo);
}
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);
}
public String getModelName() {
return this.modelName;
}
public List<String> getDyableParts() {
return dyableParts;
}
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);
}
public boolean isShowLead() {
return showLead;
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 org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
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

@@ -1,23 +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.PlayerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.PacketManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
public class CosmeticMainhandType extends Cosmetic {
public CosmeticMainhandType(String id, ConfigurationNode config) {
super(id, config);
}
@Override
public void update(@NotNull CosmeticUser user) {
Player player = user.getPlayer();
PacketManager.equipmentSlotUpdate(player.getEntityId(), user, getSlot(), PlayerUtils.getNearbyPlayers(player));
}
}

View File

@@ -2,37 +2,44 @@ package com.hibiscusmc.hmccosmetics.database;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.database.types.Data;
import com.hibiscusmc.hmccosmetics.database.types.InternalData;
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;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
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 {
@Getter
private static Data data;
@Deprecated
private static InternalData INTERNAL_DATA = new InternalData();
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();
@@ -50,14 +57,10 @@ 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);
}
public static Data getData() {
return data;
}
public static void clearData(UUID uniqueId) {
data.clear(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

@@ -1,21 +1,19 @@
package com.hibiscusmc.hmccosmetics.database.types;
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.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;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public abstract class Data {
@@ -24,41 +22,38 @@ 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);
// BACKPACK=colorfulbackpack&RRGGBB,HELMET=niftyhat,BALLOON=colorfulballoon,CHESTPLATE=niftychestplate
@NotNull
public final String serializeData(@NotNull CosmeticUser user) {
String data = "";
if (user.getHidden()) {
if (shouldHiddenSave(user.getHiddenReason())) {
data = "HIDDEN=" + user.getHiddenReason();
StringBuilder data = new StringBuilder();
if (user.isHidden()) {
for (CosmeticUser.HiddenReason reason : user.getHiddenReasons()) {
if (shouldHiddenSave(reason)) data.append("HIDDEN=").append(reason);
}
}
for (Cosmetic cosmetic : user.getCosmetics()) {
Color color = user.getCosmeticColor(cosmetic.getSlot());
String input = cosmetic.getSlot() + "=" + cosmetic.getId();
if (color != null) input = input + "&" + color.asRGB();
if (data.length() == 0) {
data = input;
if (data.isEmpty()) {
data.append(input);
continue;
}
data = data + "," + input;
data.append(",").append(input);
}
return data;
}
public final Map<CosmeticSlot, Map<Cosmetic, Color>> deserializeData(CosmeticUser user, @NotNull String raw) {
return deserializeData(user, raw, Settings.getForcePermissionJoin());
return data.toString();
}
@NotNull
public final Map<CosmeticSlot, Map<Cosmetic, Color>> deserializeData(CosmeticUser user, @NotNull String raw, boolean checkpermissions) {
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<>();
for (String a : rawData) {
if (a == null || a.isEmpty()) continue;
String[] splitData = a.split("=");
@@ -67,9 +62,8 @@ public abstract class Data {
MessagesUtil.sendDebugMessages("First split (suppose slot) " + splitData[0]);
if (splitData[0].equalsIgnoreCase("HIDDEN")) {
if (EnumUtils.isValidEnum(CosmeticUser.HiddenReason.class, splitData[1])) {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
user.hideCosmetics(CosmeticUser.HiddenReason.valueOf(splitData[1]));
});
if (Settings.isForceShowOnJoin()) continue;
hiddenReason.add(CosmeticUser.HiddenReason.valueOf(splitData[1]));
}
continue;
}
@@ -78,31 +72,20 @@ 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 (checkpermissions && 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 (checkpermissions && 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));
}
}
return cosmetics;
}
private boolean shouldHiddenSave(CosmeticUser.@NotNull HiddenReason reason) {
private boolean shouldHiddenSave(CosmeticUser.HiddenReason reason) {
switch (reason) {
case EMOTE, NONE -> {
case EMOTE, NONE, GAMEMODE, WORLD, DISABLED, POTION -> {
return false;
}
default -> {

View File

@@ -1,66 +0,0 @@
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.user.CosmeticUser;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import java.util.Map;
import java.util.UUID;
@Deprecated
public class InternalData extends Data {
NamespacedKey key = new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmetics");
@Override
public void setup() {
// Nothing
}
@Override
public void save(CosmeticUser user) {
Player player = Bukkit.getPlayer(user.getUniqueId());
player.getPersistentDataContainer().set(key, PersistentDataType.STRING, serializeData(user));
}
@Override
public CosmeticUser get(UUID uniqueId) {
Player player = Bukkit.getPlayer(uniqueId);
CosmeticUser user = new CosmeticUser(uniqueId);
if (!player.getPersistentDataContainer().has(key, PersistentDataType.STRING)) return user;
String rawData = player.getPersistentDataContainer().get(key, PersistentDataType.STRING);
Map<CosmeticSlot, Map<Cosmetic, Color>> a = deserializeData(user, rawData);
for (Map<Cosmetic, Color> cosmeticColors : a.values()) {
for (Cosmetic cosmetic : cosmeticColors.keySet()) {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// This can not be async.
user.addPlayerCosmetic(cosmetic, cosmeticColors.get(cosmetic));
});
}
}
return user;
}
@Override
public void clear(UUID uniqueId) {
OfflinePlayer player = Bukkit.getOfflinePlayer(uniqueId);
if (player.isOnline()) {
Player onlinePlayer = player.getPlayer();
if (onlinePlayer.getPersistentDataContainer().has(key, PersistentDataType.STRING)) {
onlinePlayer.getPersistentDataContainer().remove(key);
}
return;
}
}
}

View File

@@ -2,13 +2,18 @@ package com.hibiscusmc.hmccosmetics.database.types;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
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 {
@@ -33,12 +38,14 @@ public class MySQLData extends SQLData {
HMCCosmeticsPlugin plugin = HMCCosmeticsPlugin.getInstance();
try {
openConnection();
if (connection == null) throw new NullPointerException("Connection is null");
connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
if (connection == null) throw new IllegalStateException("Connection is null");
try (PreparedStatement preparedStatement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
"(UUID varchar(36) PRIMARY KEY, " +
"COSMETICS MEDIUMTEXT " +
");").execute();
} catch (SQLException | NullPointerException e) {
");")) {
preparedStatement.execute();
}
} catch (SQLException | IllegalStateException e) {
plugin.getLogger().severe("");
plugin.getLogger().severe("");
plugin.getLogger().severe("MySQL DATABASE CAN NOT BE REACHED.");
@@ -55,8 +62,7 @@ public class MySQLData extends SQLData {
@Override
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try {
PreparedStatement 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) {
@@ -66,16 +72,10 @@ public class MySQLData extends SQLData {
}
private void openConnection() throws SQLException {
// Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
// ...
// });
// connection = DriverManager.getConnection("jdbc:mysql://" + DatabaseSettings.getHost() + ":" + DatabaseSettings.getPort() + "/" + DatabaseSettings.getDatabase(), setupProperties());
// Connection isn't null AND Connection isn't closed :: return
try {
if (isConnectionOpen()) {
return;
} else if (connection != null) close(); // Close connection if still active
if (isConnectionOpen()) return;
if (connection != null) close(); // Close connection if still active
} catch (RuntimeException e) {
e.printStackTrace(); // If isConnectionOpen() throws error
}
@@ -84,17 +84,15 @@ public class MySQLData extends SQLData {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database, setupProperties());
} catch (SQLException e) {
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public void close() {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try {
if (connection == null) throw new NullPointerException("Connection is null");
if (connection == null) throw new IllegalStateException("Connection is null");
connection.close();
} catch (SQLException | NullPointerException e) {
System.out.println(e.getMessage());
@@ -105,13 +103,12 @@ public class MySQLData extends SQLData {
@NotNull
private Properties setupProperties() {
Properties props = new Properties();
props.put("user", user);
props.put("password", password);
props.put("autoReconnect", "true");
props.setProperty("user", user);
props.setProperty("password", password);
return props;
}
private boolean isConnectionOpen() throws RuntimeException {
private boolean isConnectionOpen() {
try {
return connection != null && !connection.isClosed();
} catch (SQLException e) {
@@ -124,16 +121,21 @@ public class MySQLData extends SQLData {
PreparedStatement ps = null;
if (!isConnectionOpen()) {
HMCCosmeticsPlugin.getInstance().getLogger().info("Connection is not open");
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");
if (connection == null) throw new IllegalStateException("Connection is null");
ps = connection.prepareStatement(query);
} catch (SQLException | NullPointerException e) {
} catch (SQLException | IllegalStateException e) {
e.printStackTrace();
}
return ps;
}
}
}

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,53 +3,46 @@ 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;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
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({"Duplicates", "resource"}) // Duplicate is from deprecated InternalData
public CosmeticUser get(UUID uniqueId) {
CosmeticUser user = new CosmeticUser(uniqueId);
@SuppressWarnings({"resource"}) // Duplicate is from deprecated InternalData
public CompletableFuture<UserData> get(UUID uniqueId) {
return CompletableFuture.supplyAsync(() -> {
UserData data = new UserData(uniqueId);
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try {
PreparedStatement 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);
for (Map<Cosmetic, Color> cosmeticColors : cosmetics.values()) {
for (Cosmetic cosmetic : cosmeticColors.keySet()) {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// This can not be async.
user.addPlayerCosmetic(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);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return data;
});
return user;
}
@Override
@SuppressWarnings("resource")
public void save(CosmeticUser user) {
Runnable run = () -> {
try {
PreparedStatement 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();
@@ -57,7 +50,7 @@ public abstract class SQLData extends Data {
throw new RuntimeException(e);
}
};
if (!HMCCosmeticsPlugin.isDisable()) {
if (!HMCCosmeticsPlugin.getInstance().isDisabled()) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), run);
} else {
run.run();

View File

@@ -6,7 +6,10 @@ import org.bukkit.Bukkit;
import java.io.File;
import java.io.IOException;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
@@ -32,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);
}
@@ -45,8 +50,7 @@ public class SQLiteData extends SQLData {
@SuppressWarnings("resource")
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try {
PreparedStatement 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) {
@@ -56,11 +60,6 @@ public class SQLiteData extends SQLData {
}
private void openConnection() throws SQLException {
// Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
// ...
// });
// connection = DriverManager.getConnection("jdbc:mysql://" + DatabaseSettings.getHost() + ":" + DatabaseSettings.getPort() + "/" + DatabaseSettings.getDatabase(), setupProperties());
if (connection != null && !connection.isClosed()) return;
// Close Connection if still active
@@ -71,7 +70,7 @@ public class SQLiteData extends SQLData {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:" + dataFolder);
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@@ -80,11 +79,12 @@ public class SQLiteData extends SQLData {
@Override
public PreparedStatement preparedStatement(String query) {
PreparedStatement ps = null;
if (!isConnectionOpen()) {
HMCCosmeticsPlugin.getInstance().getLogger().info("Connection is not open");
}
try {
if (!isConnectionOpen()) {
MessagesUtil.sendDebugMessages("Connection is not open");
openConnection();
}
ps = connection.prepareStatement(query);
} catch (SQLException e) {
e.printStackTrace();

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<@NotNull String, @NotNull 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,17 +1,27 @@
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.serializer.ItemSerializer;
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;
import com.hibiscusmc.hmccosmetics.gui.type.types.TypeCosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.Adventure;
import com.hibiscusmc.hmccosmetics.util.misc.Placeholder;
import dev.triumphteam.gui.builder.item.ItemBuilder;
import dev.triumphteam.gui.components.GuiType;
import dev.triumphteam.gui.guis.Gui;
import dev.triumphteam.gui.guis.GuiItem;
import lombok.Getter;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.util.AdventureUtils;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -19,85 +29,48 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Menu {
@Getter
private final String id;
@Getter
private final String title;
@Getter
private final int rows;
@Getter
private final Long cooldown;
@Getter
private final ConfigurationNode config;
@Getter
private final String permissionNode;
private final HashMap<Integer, List<MenuItem>> items;
@Getter
private final int refreshRate;
@Getter
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());
items = new HashMap<>();
setupItems();
Menus.addMenu(this);
}
public String getId() {
return id;
}
public String getTitle() {
return this.title;
}
public int getRows() {
return this.getRows();
}
public void openMenu(CosmeticUser user) {
openMenu(user, false);
}
public void openMenu(@NotNull CosmeticUser user, boolean ignorePermission) {
Player player = user.getPlayer();
if (player == null) return;
if (!ignorePermission && !permissionNode.isEmpty()) {
if (!player.hasPermission(permissionNode) && !player.isOp()) {
MessagesUtil.sendMessage(player, "no-permission");
return;
}
}
final Component component = Adventure.MINI_MESSAGE.deserialize(Placeholder.applyPapiPlaceholders(player, this.title));
Gui gui = Gui.gui().
title(component).
rows(this.rows).
create();
gui.setDefaultClickAction(event -> event.setCancelled(true));
// TODO: Redo this whole gui creation process to allow for all items, possibly implement caching
gui = getItems(user, gui);
final Gui finalGui = gui; // Need to make it final for the runtask
// API
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(), () -> {
finalGui.open(player);
});
}
@Contract("_, _ -> param2")
private Gui getItems(@NotNull CosmeticUser user, Gui gui) {
Player player = user.getPlayer();
private void setupItems() {
for (ConfigurationNode config : config.node("items").childrenMap().values()) {
List<String> slotString;
@@ -113,8 +86,8 @@ public class Menu {
List<Integer> slots = getSlots(slotString);
if (slots == null) {
MessagesUtil.sendDebugMessages("Slot is null for " + config.key().toString());
if (slots.isEmpty()) {
MessagesUtil.sendDebugMessages("Slot is empty for " + config.key().toString());
continue;
}
@@ -122,42 +95,204 @@ public class Menu {
try {
item = ItemSerializer.INSTANCE.deserialize(ItemStack.class, config.node("item"));
} catch (SerializationException e) {
throw new RuntimeException(e);
}
if (item == null) {
MessagesUtil.sendDebugMessages("something went wrong! " + item);
MessagesUtil.sendDebugMessages("Unable to get valid item for " + config.key().toString() + " " + e.getMessage());
continue;
}
Type type = null;
if (item == null) {
MessagesUtil.sendDebugMessages("Something went wrong with the item creation for " + config.key().toString());
continue;
}
int priority = config.node("priority").getInt(1);
Type type = Types.getDefaultType();
if (!config.node("type").virtual()) {
String typeId = config.node("type").getString();
String typeId = config.node("type").getString("");
if (Types.isType(typeId)) type = Types.getType(typeId);
}
for (int slot : slots) {
ItemStack modifiedItem = getMenuItem(user, type, config, item.clone(), slot).clone();
GuiItem guiItem = ItemBuilder.from(modifiedItem).asGuiItem();
Type finalType = type;
guiItem.setAction(event -> {
MessagesUtil.sendDebugMessages("Selected slot " + slot);
final ClickType clickType = event.getClick();
if (finalType != null) finalType.run(user, config, clickType);
// Need to delay the update by a tick so it will actually update with new values
for (int guiSlot : slots) {
gui.updateItem(guiSlot, getMenuItem(user, finalType, config, item.clone(), guiSlot));
}
MessagesUtil.sendDebugMessages("Updated slot " + slot);
});
MessagesUtil.sendDebugMessages("Added " + slots + " as " + guiItem + " in the menu");
gui.setItem(slot, guiItem);
for (Integer slot : slots) {
MenuItem menuItem = new MenuItem(slots, item, type, priority, config);
if (items.containsKey(slot)) {
List<MenuItem> menuItems = items.get(slot);
menuItems.add(menuItem);
menuItems.sort(priorityCompare);
items.put(slot, menuItems);
} else {
items.put(slot, new ArrayList<>(List.of(menuItem)));
}
}
}
return gui;
}
public void openMenu(CosmeticUser user) {
openMenu(user, false);
}
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 (!viewer.hasPermission(permissionNode) && !viewer.isOp()) {
MessagesUtil.sendMessage(viewer, "no-permission");
return;
}
}
final Component component = AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, this.title));
Gui gui = Gui.gui()
.title(component)
.type(GuiType.CHEST)
.inventory((title, owner, type) -> Bukkit.createInventory(owner, rows * 9, title))
.create();
gui.setDefaultClickAction(event -> event.setCancelled(true));
AtomicInteger taskid = new AtomicInteger(-1);
gui.setOpenGuiAction(event -> {
Runnable run = () -> {
if (gui.getInventory().getViewers().isEmpty() && taskid.get() != -1) {
Bukkit.getScheduler().cancelTask(taskid.get());
}
updateMenu(viewer, cosmeticHolder, gui);
};
if (refreshRate != -1) {
taskid.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(HMCCosmeticsPlugin.getInstance(), run, 0, refreshRate));
} else {
run.run();
}
});
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());
});
Runnable openGuiTask = () -> {
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
};
// API
if (cosmeticHolder instanceof CosmeticUser user) {
PlayerMenuOpenEvent event = new PlayerMenuOpenEvent(user, this);
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
openGuiTask.run();
}
});
}
// Internal
else {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), openGuiTask);
}
}
private void updateMenu(Player viewer, CosmeticHolder cosmeticHolder, Gui gui) {
StringBuilder title = new StringBuilder(this.title);
int row = 0;
if (shading) {
for (int i = 0; i < gui.getInventory().getSize(); i++) {
// Handles the title
if (i % 9 == 0) {
if (row == 0) {
title.append(Settings.getFirstRowShift()); // Goes back to the start of the gui
} else {
title.append(Settings.getSequentRowShift());
}
row += 1;
} else {
title.append(Settings.getIndividualColumnShift()); // Goes to the next slot
}
boolean occupied = false;
if (items.containsKey(i)) {
// Handles the items
List<MenuItem> menuItems = items.get(i);
MenuItem item = menuItems.get(0);
updateItem(viewer, cosmeticHolder, gui, i);
if (item.type() instanceof TypeCosmetic) {
Cosmetic cosmetic = Cosmetics.getCosmetic(item.itemConfig().node("cosmetic").getString(""));
if (cosmetic == null) continue;
if (cosmeticHolder.hasCosmeticInSlot(cosmetic)) {
title.append(Settings.getEquippedCosmeticColor());
} else {
if (cosmeticHolder.canEquipCosmetic(cosmetic, true)) {
title.append(Settings.getEquipableCosmeticColor());
} else {
title.append(Settings.getLockedCosmeticColor());
}
}
occupied = true;
}
}
if (occupied) {
title.append(Settings.getBackground().replaceAll("<row>", String.valueOf(row)));
} else {
title.append(Settings.getClearBackground().replaceAll("<row>", String.valueOf(row)));
}
}
MessagesUtil.sendDebugMessages("Updated menu with title " + title);
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(viewer, cosmeticHolder, gui, i);
}
}
}
}
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(viewer, cosmeticHolder, type, item.itemConfig(), item.item().clone(), slot);
if (modifiedItem.getType().isAir()) continue;
GuiItem guiItem = ItemBuilder.from(modifiedItem).asGuiItem();
guiItem.setAction(event -> {
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(viewer, cosmeticHolder, item.itemConfig(), clickType);
updateMenu(viewer, cosmeticHolder, gui);
});
MessagesUtil.sendDebugMessages("Set an item in slot " + slot + " in the menu of " + getId());
gui.updateItem(slot, guiItem);
break;
}
}
@NotNull
@@ -167,8 +302,8 @@ public class Menu {
for (String a : slotString) {
if (a.contains("-")) {
String[] split = a.split("-");
int min = Integer.valueOf(split[0]);
int max = Integer.valueOf(split[1]);
int min = Integer.parseInt(split[0]);
int max = Integer.parseInt(split[1]);
slots.addAll(getSlots(min, max));
} else {
slots.add(Integer.valueOf(a));
@@ -186,19 +321,17 @@ 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);
}
public String getPermissionNode() {
return permissionNode;
return type.setItem(viewer, cosmeticHolder, config, itemStack, slot);
}
public boolean canOpen(Player player) {
if (permissionNode.isEmpty()) return true;
return player.isOp() || player.hasPermission(permissionNode);
}
public static Comparator<MenuItem> priorityCompare = Comparator.comparing(MenuItem::priority).reversed();
}

View File

@@ -0,0 +1,12 @@
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(@NotNull List<Integer> slots, @NotNull ItemStack item, Type type, int priority, ConfigurationNode itemConfig) {
}

View File

@@ -3,28 +3,31 @@ package com.hibiscusmc.hmccosmetics.gui;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
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.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.nio.file.Files;
import java.nio.file.Path;
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());
}
@@ -39,11 +42,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() {
@@ -60,33 +70,48 @@ 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();
File[] directoryListing = cosmeticFolder.listFiles();
if (directoryListing == null) return;
for (File child : directoryListing) {
if (child.toString().contains(".yml") || child.toString().contains(".yaml")) {
MessagesUtil.sendDebugMessages("Scanning " + child);
// Loads file
YamlConfigurationLoader loader = YamlConfigurationLoader.builder().path(child.toPath()).build();
CommentedConfigurationNode root;
try {
root = loader.load();
} catch (ConfigurateException e) {
throw new RuntimeException(e);
// Recursive file lookup
try (Stream<Path> walkStream = Files.walk(cosmeticFolder.toPath())) {
walkStream.filter(p -> p.toFile().isFile()).forEach(child -> {
if (child.toString().endsWith("yml") || child.toString().endsWith("yaml")) {
MessagesUtil.sendDebugMessages("Scanning " + child);
// Loads file
YamlConfigurationLoader loader = YamlConfigurationLoader.builder().path(child).build();
CommentedConfigurationNode root;
try {
root = loader.load();
} catch (ConfigurateException e) {
throw new RuntimeException(e);
}
try {
new Menu(FilenameUtils.removeExtension(child.getFileName().toString()), root);
} catch (Exception e) {
MessagesUtil.sendDebugMessages("Unable to create menu in " + child.getFileName().toString(), Level.WARNING);
if (Settings.isDebugMode()) e.printStackTrace();
}
}
try {
new Menu(FilenameUtils.removeExtension(child.getName()), root);
} catch (Exception e) {
MessagesUtil.sendDebugMessages("Unable to create menu in " + child, Level.WARNING);
if (Settings.isDebugEnabled()) e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

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,8 +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 {
@@ -11,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(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) {
if (user.getHidden()) return;
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) {
if (!user.getHidden()) return;
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.getHiddenReason() != CosmeticUser.HiddenReason.ACTION && user.getHiddenReason() != CosmeticUser.HiddenReason.COMMAND) return;
user.showCosmetics();
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,13 +13,19 @@ public class ActionCosmeticToggle extends Action {
}
@Override
public void run(@NotNull CosmeticUser user, String raw) {
if (user.getHidden()) {
if (user.getHiddenReason() != CosmeticUser.HiddenReason.ACTION && user.getHiddenReason() != CosmeticUser.HiddenReason.COMMAND) return;
user.showCosmetics();
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);
return;
}
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,11 +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.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;
@@ -16,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
@@ -33,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,10 +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 com.hibiscusmc.hmccosmetics.util.ServerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.PacketManager;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.owen1212055.particlehelper.api.particle.types.BlockDataParticle;
import com.owen1212055.particlehelper.api.particle.types.DestinationParticle;
import com.owen1212055.particlehelper.api.particle.types.velocity.VelocityParticle;
@@ -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) {
@@ -42,10 +43,15 @@ public class ActionParticle extends Action {
return;
}
particle = ServerUtils.addParticleValues(particle, rawString);
Location location = user.getPlayer().getLocation();
for (Player player : PacketManager.getViewers(location)) {
particle = HMCCServerUtils.addParticleValues(particle, rawString);
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,8 +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 {
@@ -11,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(), 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

@@ -1,69 +1,20 @@
package com.hibiscusmc.hmccosmetics.gui.special;
import com.hibiscusmc.hmccolor.HMCColorApi;
import com.hibiscusmc.hmccolor.gui.guis.Gui;
import com.hibiscusmc.hmccolor.gui.guis.GuiItem;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.hooks.Hooks;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.misc.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
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;
public class DyeMenu {
public interface DyeMenu {
public static void openMenu(@NotNull CosmeticUser user, Cosmetic cosmetic) {
Player player = user.getPlayer();
if (player == null) return;
if (!Hooks.isActiveHook("HMCColor")) {
addCosmetic(user, cosmetic, null);
return;
}
ItemStack originalItem = user.getUserCosmeticItem(cosmetic);
if (originalItem == null || !cosmetic.isDyable()) return;
/**
* Overrideable method that is called when a player wishing to dye a menu.
* After the method is called, the menu plugin itself is supposed to handle everything else, including adding the cosmetic to the CosmeticHolder
*
* @param viewer The player that is viewing the menu
* @param cosmeticHolder The CosmeticHolder that is being dyed (Can be different from the viewer)
* @param cosmetic (The cosmetic that is wished to be dyed)
*/
void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic);
Gui gui = HMCColorApi.INSTANCE.colorMenu();
gui.updateTitle(Placeholder.applyPapiPlaceholders(player, 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;
if (color == null) return;
addCosmetic(user, cosmetic, color);
event.setCancelled(true);
} else event.setCancelled(true);
});
gui.setPlayerInventoryAction(event -> event.setCancelled(true));
gui.setCloseGuiAction(event -> {});
gui.open(player);
}
private static void addCosmetic(@NotNull CosmeticUser user, Cosmetic cosmetic, Color color) {
Player player = user.getPlayer();
user.addPlayerCosmetic(cosmetic, color);
player.setItemOnCursor(new ItemStack(Material.AIR));
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
player.closeInventory();
user.updateCosmetic(cosmetic.getSlot());
}, 2);
}
}

View File

@@ -0,0 +1,46 @@
package com.hibiscusmc.hmccosmetics.gui.special;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class DyeMenuProvider {
private static DyeMenu instance = null;
/**
* Sets the provider of the DyeMenu. Check {@link DyeMenuProvider#hasMenuProvider()} before attempting to set this,
* it is locked once a dye menu has been set!
* @param dyeMenu The dye menu implementation that wishes to be the provider.
* @throws IllegalStateException IllegalStateException will be thrown if a dye menu provider already is set by another plugin.
*/
public static void setDyeMenuProvider(@NotNull DyeMenu dyeMenu) throws IllegalStateException {
if (instance != null) {
throw new IllegalStateException("DyeMenu Implementation has already been set by another plugin.");
}
instance = dyeMenu;
}
/**
* Called when wishing to dye a cosmetic to hand it off to the dye menu implementation
* @param viewer The viewer of the menu
* @param cosmeticHolder The cosmetic holder that the player viewer wishing to modify (could be themselves or another CosmeticHolder)
* @param cosmetic The cosmetic the user wishes to dye
* @throws IllegalStateException IllegalStateException will be thrown if the dye menu instance is null (Check {@link DyeMenuProvider#hasMenuProvider()} before calling)
*/
public static void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic) throws IllegalStateException {
if (instance == null) {
throw new IllegalStateException("Unable to open a dye menu without instance of it.");
}
instance.openMenu(viewer, cosmeticHolder, cosmetic);
}
/**
* Does HMCC have a dye menu provider already set?
* @return True if it is already set and locked; false if none have been set.
*/
public static boolean hasMenuProvider() {
return instance != null;
}
}

View File

@@ -0,0 +1,58 @@
package com.hibiscusmc.hmccosmetics.gui.special.impl;
import com.hibiscusmc.hmccolor.HMCColorApi;
import com.hibiscusmc.hmccolor.shaded.gui.guis.Gui;
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.gui.special.DyeMenu;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.AdventureUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class HMCColorDyeMenu implements DyeMenu {
@Override
public void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic) {
ItemStack originalItem = cosmetic.getItem();
if (originalItem == null || !cosmetic.isDyeable()) return;
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;
Color color = NMSHandlers.getHandler().getUtilHandler().getColor(item);
if (color == null) return;
addCosmetic(viewer, cosmeticHolder, cosmetic, color);
event.setCancelled(true);
} else event.setCancelled(true);
});
gui.setPlayerInventoryAction(event -> event.setCancelled(true));
gui.setCloseGuiAction(event -> {});
gui.open(viewer);
}
private 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(), () -> {
viewer.closeInventory();
cosmeticHolder.updateCosmetic(cosmetic.getSlot());
}, 2);
}
}

View File

@@ -1,10 +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.spongepowered.configurate.ConfigurationNode;
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 {
@@ -19,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

@@ -1,60 +1,83 @@
package com.hibiscusmc.hmccosmetics.gui.type.types;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.serializer.ItemSerializer;
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;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.gui.type.Type;
import com.hibiscusmc.hmccosmetics.hooks.Hooks;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.StringUtils;
import com.hibiscusmc.hmccosmetics.util.misc.Utils;
import me.clip.placeholderapi.PlaceholderAPI;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.Bukkit;
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.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.lang.invoke.TypeDescriptor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class TypeCosmetic extends Type {
public TypeCosmetic(String id) {
super(id);
}
public TypeCosmetic() {
super("cosmetic");
}
@Override
public void run(CosmeticUser user, @NotNull ConfigurationNode config, ClickType clickType) {
if (config.node("cosmetic").virtual()) return;
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");
return;
}
String cosmeticName = config.node("cosmetic").getString();
Cosmetic cosmetic = Cosmetics.getCosmetic(cosmeticName);
Player player = user.getPlayer();
if (cosmetic == null) {
MessagesUtil.sendMessage(player, "invalid-cosmetic");
MessagesUtil.sendDebugMessages("No Cosmetic Found");
MessagesUtil.sendMessage(viewer, "invalid-cosmetic");
return;
}
if (!user.canEquipCosmetic(cosmetic)) {
MessagesUtil.sendMessage(player, "no-cosmetic-permission");
if (!cosmeticHolder.canEquipCosmetic(cosmetic)) {
MessagesUtil.sendDebugMessages("No Cosmetic Permission");
MessagesUtil.sendMessage(viewer, "no-cosmetic-permission");
return;
}
boolean isUnEquippingCosmetic = false;
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());
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");
MessagesUtil.sendDebugMessages("Running Actions");
try {
if (!actionConfig.node("any").virtual()) actionStrings.addAll(actionConfig.node("any").getList(String.class));
@@ -65,41 +88,61 @@ public class TypeCosmetic extends Type {
if (clickType.isRightClick()) {
if (!actionConfig.node("right-click").virtual()) actionStrings.addAll(actionConfig.node("right-click").getList(String.class));
}
}
if (user.getCosmetic(cosmetic.getSlot()) == cosmetic) {
if (!actionConfig.node("on-unequip").virtual()) actionStrings.addAll(actionConfig.node("on-unequip").getList(String.class));
MessagesUtil.sendDebugMessages("on-unequip");
user.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 (clickType.equals(ClickType.SHIFT_LEFT)) {
if (!actionConfig.node("shift-left-click").virtual()) actionStrings.addAll(actionConfig.node("shift-left-click").getList(String.class));
}
if (clickType.equals(ClickType.SHIFT_RIGHT)) {
if (!actionConfig.node("shift-right-click").virtual()) actionStrings.addAll(actionConfig.node("shift-right-click").getList(String.class));
}
}
Actions.runActions(user, actionStrings);
if (isUnEquippingCosmetic) {
if (!actionConfig.node("on-unequip").virtual()) actionStrings.addAll(actionConfig.node("on-unequip").getList(String.class));
MessagesUtil.sendDebugMessages("on-unequip");
cosmeticHolder.removeCosmeticSlot(cosmetic);
} else {
if (!actionConfig.node("on-equip").virtual()) actionStrings.addAll(actionConfig.node("on-equip").getList(String.class));
MessagesUtil.sendDebugMessages("on-equip");
MessagesUtil.sendDebugMessages("Preparing for on-equip with the following checks:");
MessagesUtil.sendDebugMessages("CosmeticDyeable? " + cosmetic.isDyeable() + " / isDyeClick? " + isDyeClick + " / isHMCColorActive? " + Hooks.isActiveHook("HMCColor"));
// TODO: Redo this
if (cosmetic.isDyeable() && isDyeClick && DyeMenuProvider.hasMenuProvider()) {
DyeMenuProvider.openMenu(viewer, cosmeticHolder, cosmetic);
} else if (isRequiredClick) {
cosmeticHolder.addCosmetic(cosmetic);
}
}
Actions.runActions(viewer, cosmeticHolder, actionStrings);
} catch (SerializationException e) {
throw new RuntimeException(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);
}
}
run.run();
MessagesUtil.sendDebugMessages("Finished Type Click Run");
}
@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;
@@ -110,9 +153,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) {
@@ -123,11 +166,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) && !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 {
@@ -140,25 +184,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.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
if (Hooks.isActiveHook("PlaceholderAPI")) loreLine = PlaceholderAPI.setPlaceholders(user.getPlayer(), loreLine);
processedLore.add(loreLine);
}
}
itemMeta.setLore(processedLore);
return itemMeta;
}
}

View File

@@ -1,16 +1,16 @@
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.hooks.Hooks;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.clip.placeholderapi.PlaceholderAPI;
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.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.List;
@@ -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.
@@ -43,29 +44,41 @@ public class TypeEmpty extends Type {
if (clickType.isRightClick()) {
if (!actionConfig.node("right-click").virtual()) actionStrings.addAll(actionConfig.node("right-click").getList(String.class));
}
if (clickType.equals(ClickType.SHIFT_LEFT)) {
if (!actionConfig.node("shift-left-click").virtual()) actionStrings.addAll(actionConfig.node("shift-left-click").getList(String.class));
}
if (clickType.equals(ClickType.SHIFT_RIGHT)) {
if (!actionConfig.node("shift-right-click").virtual()) actionStrings.addAll(actionConfig.node("shift-right-click").getList(String.class));
}
}
// 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.hasLore()) {
for (String loreLine : itemMeta.getLore()) {
if (Hooks.isActiveHook("PlaceholderAPI"))
loreLine = PlaceholderAPI.setPlaceholders(user.getPlayer(), loreLine);
processedLore.add(loreLine);
}
}
itemStack.setItemMeta(itemMeta);
itemStack.setItemMeta(processItemMeta(viewer, itemMeta));
return itemStack;
}

View File

@@ -1,93 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a hook into other minecraft plugins
*/
public abstract class Hook implements Listener {
private final String id;
private boolean active = false;
private boolean itemHook = false;
public Hook(@NotNull String id) {
this.id = id;
Hooks.addHook(this);
}
/**
* Loads this hook
*
* @implNote By default, this method does nothing. It should be overridden by child classes to implement any necessary loading logic
*/
public void load() { }
/**
* Gets an {@link ItemStack} that is associated with the provided id from the hooked plugin
* @param itemId The id of the {@link ItemStack}
* @return The {@link ItemStack} with the id provided. If an invalid id was provided or if the hook doesn't have any related {@link ItemStack}s then this will return null
* @implNote By default, this method returns null. It should be overridden by child classes if you will to have your hook return a related {@link ItemStack}
*/
@Nullable
public ItemStack getItem(@NotNull String itemId) {
return null;
}
/**
* Gets the id of this hook
*
* @return The unique id for this hook
*/
@NotNull
public final String getId() {
return id;
}
/**
* Gets whether this hook has been activated
* @return true if this hook is active, false otherwise
* @deprecated As of release 2.2.5+, replaced by {@link #isActive()}
*/
@Deprecated
public boolean getActive() {
return this.active;
}
/**
* Gets whether this hook has been activated
* @return true if this hook is active, false otherwise
* @since 2.2.5
*/
public final boolean isActive() {
return this.active;
}
/**
* Sets whether this hook is active
* @param active true to activate the hook, false otherwise
*/
public final void setActive(boolean active) {
this.active = active;
}
/**
* Whether the method {@link #getItem(String)} should return a non-null value
* @return true if {@link #getItem(String)} should return a non-null value, false otherwise
*
* @apiNote Even though this method returns true does not mean that {@link #getItem(String)} won't return null, rather if this returns false then {@link #getItem(String)} should return false everytime
*/
public final boolean hasEnabledItemHook() {
return itemHook;
}
/**
* Sets whether the method {@link #getItem(String)} should return a non-null value
* @param enabled true if {@link #getItem(String)} should return a non-null value, false otherwise
*/
public final void setEnabledItemHook(boolean enabled) {
itemHook = enabled;
}
}

View File

@@ -1,78 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.hooks.items.*;
import com.hibiscusmc.hmccosmetics.hooks.misc.*;
import com.hibiscusmc.hmccosmetics.hooks.placeholders.HookPlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
public class Hooks {
private static final HashMap<String, Hook> hooks = new HashMap<>();
private static HookOraxen ORAXEN_HOOK = new HookOraxen();
private static HookItemAdder ITEMADDER_HOOK = new HookItemAdder();
private static HookGeary GEARY_HOOK = new HookGeary();
private static HookMythic MYTHIC_HOOK = new HookMythic();
private static HookDenizen DENIZEN_HOOK = new HookDenizen();
private static HookHMCCosmetics HMCCOSMETIC_HOOK = new HookHMCCosmetics();
private static HookPlaceholderAPI PAPI_HOOK = new HookPlaceholderAPI();
private static HookPremiumVanish PREMIUM_VANISH_HOOK = new HookPremiumVanish();
private static HookSuperVanish SUPER_VANISH_HOOK = new HookSuperVanish();
private static HookHMCColor HMC_COLOR_HOOK = new HookHMCColor();
private static HookCMI CMI_HOOK = new HookCMI();
private static HookLibsDisguises LIBS_DISGUISES_HOOK = new HookLibsDisguises();
public static Hook getHook(@NotNull String id) {
return hooks.get(id.toLowerCase());
}
public static boolean isItemHook(@NotNull String id) {
return hooks.containsKey(id.toLowerCase());
}
public static void addHook(Hook hook) {
hooks.put(hook.getId().toLowerCase(), hook);
}
public static void setup() {
for (Hook hook : hooks.values()) {
if (Bukkit.getPluginManager().getPlugin(hook.getId()) != null) {
HMCCosmeticsPlugin.getInstance().getServer().getPluginManager().registerEvents(hook, HMCCosmeticsPlugin.getInstance());
hook.setActive(true);
hook.load();
HMCCosmeticsPlugin.getInstance().getLogger().info("Successfully hooked into " + hook.getId());
}
}
}
@Nullable
public static ItemStack getItem(@NotNull String raw) {
if (!raw.contains(":")) {
Material mat = Material.getMaterial(raw.toUpperCase());
if (mat == null) return null;
return new ItemStack(mat);
}
// Ex. Oraxen:BigSword
// split[0] is the plugin name
// split[1] is the item name
String[] split = raw.split(":", 2);
if (!isItemHook(split[0])) return null;
Hook hook = getHook(split[0]);
if (!hook.hasEnabledItemHook()) return null;
if (!hook.isActive()) return null;
return hook.getItem(split[1]);
}
public static boolean isActiveHook(String id) {
Hook hook = getHook(id);
if (hook == null) return false;
return hook.isActive();
}
}

View File

@@ -1,27 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.items;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link com.denizenscript.denizen.Denizen Denizen} to provide custom items
*/
@SuppressWarnings("SpellCheckingInspection")
public class HookDenizen extends Hook {
public HookDenizen() {
super("denizen");
setEnabledItemHook(true);
}
/**
* Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link com.denizenscript.denizen.Denizen Denizen}
*/
@Override
public ItemStack getItem(@NotNull String itemId) {
ItemTag item = ItemTag.valueOf(itemId, CoreUtilities.noDebugContext);
return item == null ? null : item.getItemStack();
}
}

View File

@@ -1,45 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.items;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import com.mineinabyss.geary.addons.GearyPhase;
import com.mineinabyss.geary.modules.GearyModuleKt;
import com.mineinabyss.geary.papermc.tracking.items.ItemTrackingKt;
import com.mineinabyss.geary.prefabs.PrefabKey;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link com.mineinabyss.geary.papermc.GearyPlugin Geary} to provide custom items
*/
@SuppressWarnings("SpellCheckingInspection")
public class HookGeary extends Hook {
private boolean enabled = false;
public HookGeary() {
super("geary");
setEnabledItemHook(true);
}
@Override
public void load() {
GearyModuleKt.getGeary().getPipeline().intercept(GearyPhase.ENABLE, () -> {
enabled = true;
HMCCosmeticsPlugin.setup();
return null;
});
}
/**
* Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link com.mineinabyss.geary.papermc.GearyPlugin Geary}
*/
@Override
public ItemStack getItem(@NotNull String itemId) {
if (enabled) {
PrefabKey prefabKey = PrefabKey.Companion.ofOrNull(itemId);
if (prefabKey == null) return null;
return ItemTrackingKt.getGearyItems().createItem(prefabKey, null);
} else return new ItemStack(Material.AIR);
}
}

View File

@@ -2,7 +2,8 @@ package com.hibiscusmc.hmccosmetics.hooks.items;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import me.lojosho.hibiscuscommons.hooks.Hook;
import me.lojosho.hibiscuscommons.hooks.HookFlag;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -11,8 +12,8 @@ import org.jetbrains.annotations.NotNull;
*/
public class HookHMCCosmetics extends Hook {
public HookHMCCosmetics() {
super("HMCCosmetics");
setEnabledItemHook(true);
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

@@ -1,46 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.items;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link dev.lone.itemsadder.api.ItemsAdder ItemsAdder} to provide custom items
*/
@SuppressWarnings("SpellCheckingInspection")
public class HookItemAdder extends Hook {
private boolean enabled = false;
public HookItemAdder() {
super("itemsadder");
setEnabledItemHook(true);
}
/**
* Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link dev.lone.itemsadder.api.ItemsAdder ItemsAdder}
*/
@Override
public ItemStack getItem(@NotNull String itemId) {
if (enabled) {
CustomStack stack = CustomStack.getInstance(itemId);
if (stack == null) return null;
return stack.getItemStack();
} else {
return new ItemStack(Material.AIR);
}
}
@EventHandler
public void onItemAdderDataLoad(ItemsAdderLoadDataEvent event) {
// By default, it will only run once at startup, if hook setting is enabled
if (enabled && !Settings.getItemsAdderReloadChange()) return;
this.enabled = true;
HMCCosmeticsPlugin.setup();
}
}

View File

@@ -1,25 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.items;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import io.lumine.mythic.bukkit.MythicBukkit;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link io.lumine.mythic.bukkit.MythicBukkit MythicBukkit} to provide custom items
*/
@SuppressWarnings("SpellCheckingInspection")
public class HookMythic extends Hook {
public HookMythic() {
super("mythicmobs");
setEnabledItemHook(true);
}
/**
* Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link io.lumine.mythic.bukkit.MythicBukkit MythicBukkit}
*/
@Override
public ItemStack getItem(@NotNull String itemId) {
return MythicBukkit.inst().getItemManager().getItemStack(itemId);
}
}

View File

@@ -1,28 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.items;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import io.th0rgal.oraxen.api.OraxenItems;
import io.th0rgal.oraxen.items.ItemBuilder;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link io.th0rgal.oraxen.OraxenPlugin OraxenPlugin} to provide custom items
*/
@SuppressWarnings("SpellCheckingInspection")
public class HookOraxen extends Hook {
public HookOraxen() {
super("oraxen");
setEnabledItemHook(true);
}
/**
* Gets a cosmetic {@link ItemStack} that is associated with the provided id from the plugin {@link io.th0rgal.oraxen.OraxenPlugin OraxenPlugin}
*/
@Override
public ItemStack getItem(@NotNull String itemId) {
ItemBuilder builder = OraxenItems.getItemById(itemId);
if (builder == null) return null;
return builder.build();
}
}

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

@@ -1,35 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.Zrips.CMI.events.CMIPlayerUnVanishEvent;
import com.Zrips.CMI.events.CMIPlayerVanishEvent;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link com.Zrips.CMI.CMI CMI}
*/
public class HookCMI extends Hook {
public HookCMI() {
super("CMI");
}
@EventHandler
public void onPlayerVanish(@NotNull CMIPlayerVanishEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler
public void onPlayerShow(@NotNull CMIPlayerUnVanishEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.showCosmetics();
}
}

View File

@@ -1,12 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
/**
* A hook that integrates the plugin {@link com.hibiscusmc.hmccolor.HMCColor HMCColor}
*/
public class HookHMCColor extends Hook {
public HookHMCColor() {
super("HMCColor");
}
}

View File

@@ -1,32 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import me.libraryaddict.disguise.events.DisguiseEvent;
import me.libraryaddict.disguise.events.UndisguiseEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
public class HookLibsDisguises extends Hook {
public HookLibsDisguises() {
super("LibsDisguises");
}
@EventHandler
public void onPlayerVanish(@NotNull DisguiseEvent event) {
if (!(event.getEntity() instanceof Player player)) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler
public void onPlayerShow(@NotNull UndisguiseEvent event) {
if (!(event.getEntity() instanceof Player player)) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.showCosmetics();
}
}

View File

@@ -1,37 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import de.myzelyam.api.vanish.PlayerHideEvent;
import de.myzelyam.api.vanish.PlayerShowEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link de.myzelyam.api.vanish.VanishAPI Supervanish}
*
* @implSpec Supervanish and Premium Vanish both use the same api
*/
public class HookPremiumVanish extends Hook {
public HookPremiumVanish() {
super("PremiumVanish");
}
@EventHandler
public void onPlayerVanish(@NotNull PlayerHideEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler
public void onPlayerShow(@NotNull PlayerShowEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.showCosmetics();
}
}

View File

@@ -1,37 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.misc;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import de.myzelyam.api.vanish.PlayerHideEvent;
import de.myzelyam.api.vanish.PlayerShowEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
/**
* A hook that integrates the plugin {@link de.myzelyam.api.vanish.VanishAPI Supervanish}
*
* @implSpec Supervanish and Premium Vanish both use the same api
*/
public class HookSuperVanish extends Hook {
public HookSuperVanish() {
super("SuperVanish");
}
@EventHandler
public void onPlayerVanish(@NotNull PlayerHideEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler
public void onPlayerShow(@NotNull PlayerShowEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.showCosmetics();
}
}

View File

@@ -9,7 +9,6 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.TranslationUtil;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@@ -54,18 +53,15 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
@Override
public String onRequest(@NotNull OfflinePlayer player, @NotNull String params) {
if (!player.isOnline()) return null;
if (!player.isOnline()) return TranslationUtil.getTranslation("user-cosmetic", "offline");
CosmeticUser user = CosmeticUsers.getUser(player.getPlayer());
if (user == null) return null;
if (user == null) return TranslationUtil.getTranslation("user-cosmetic", "invalid-user");
List<String> placeholderArgs = Arrays.asList(params.split("_", 3));
switch (placeholderArgs.get(0).toLowerCase()) {
case "using":
if (placeholderArgs == null) {
return null;
}
if (placeholderArgs.get(1) != null) {
if (placeholderArgs.size() >= 2) {
Cosmetic cosmetic = Cosmetics.getCosmetic(placeholderArgs.get(1));
if (cosmetic == null) return "INVALID_COSMETIC";
Cosmetic currentCosmetic = user.getCosmetic(cosmetic.getSlot());
@@ -74,43 +70,29 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
return TranslationUtil.getTranslation("using-cosmetic", String.valueOf(false));
}
case "current":
if (placeholderArgs == null) {
return null;
}
if (placeholderArgs.get(1) != null) {
if (placeholderArgs.size() >= 2) {
CosmeticSlot slot = CosmeticSlot.valueOf(placeholderArgs.get(1).toUpperCase());
if (slot == null) return null;
if (user.getCosmetic(slot) == null) return null;
Cosmetic cosmetic = user.getCosmetic(slot);
if (cosmetic == null) return TranslationUtil.getTranslation("current-cosmetic", "no-cosmetic");
if (placeholderArgs.size() == 2) return user.getCosmetic(slot).getId();
String output;
switch (placeholderArgs.get(2).toLowerCase()) {
case "material" -> {
output = getMaterialName(user.getCosmetic(slot));
}
case "custommodeldata" -> {
output = getModelData(user.getCosmetic(slot));
}
case "name" -> {
output = getItemName(user.getCosmetic(slot));
}
case "lore" -> {
output = getItemLore(user.getCosmetic(slot));
}
case "permission" -> {
output = user.getCosmetic(slot).getPermission();
}
default -> {
output = user.getCosmetic(slot).getId();
}
case "material" -> output = getMaterialName(cosmetic);
case "custommodeldata" -> output = getModelData(cosmetic);
case "itemmodel" -> output = getItemModel(cosmetic);
case "itemname" -> output = getItemName(cosmetic);
case "name" -> output = getDisplayName(cosmetic);
case "lore" -> output = getItemLore(cosmetic);
case "permission" -> output = user.getCosmetic(slot).getPermission();
default -> output = user.getCosmetic(slot).getId();
}
return TranslationUtil.getTranslation("current-cosmetic", String.valueOf(output));
if (output == null) output = "none";
return TranslationUtil.getTranslation("current-cosmetic", output);
}
case "unlocked":
if (placeholderArgs == null) {
return null;
}
if (placeholderArgs.get(1) != null) {
if (placeholderArgs.size() >= 2) {
Cosmetic cosmetic = Cosmetics.getCosmetic(placeholderArgs.get(1));
if (cosmetic == null) {
if (placeholderArgs.size() >= 3) {
@@ -124,16 +106,14 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
return "INVALID_COSMETIC";
}
}
return TranslationUtil.getTranslation("unlocked-cosmetic", String.valueOf(user.canEquipCosmetic(cosmetic)));
return TranslationUtil.getTranslation("unlocked-cosmetic", String.valueOf(user.canEquipCosmetic(cosmetic, true)));
}
case "equipped":
if (placeholderArgs == null) {
return null;
}
if (placeholderArgs.get(1) != null) {
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));
}
@@ -152,9 +132,34 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
return "INVALID_COSMETIC";
}
}
if (user.getCosmetic(cosmetic.getSlot()) == null) return "false";
return TranslationUtil.getTranslation("equipped-cosmetic", String.valueOf(cosmetic.getId() == user.getCosmetic(cosmetic.getSlot()).getId()));
Cosmetic equippedCosmetic = user.getCosmetic(cosmetic.getSlot());
if (equippedCosmetic == null) return TranslationUtil.getTranslation("equipped-cosmetic", "false");
return TranslationUtil.getTranslation("equipped-cosmetic", String.valueOf(cosmetic.getId().equals(equippedCosmetic.getId())));
}
// %hmccosmetics_amount_balloon_unlocked%
case "amount":
if (placeholderArgs.size() >= 2) {
String args1 = placeholderArgs.get(1).toUpperCase(); // changes offhand to OFFHAND
if (!CosmeticSlot.contains(args1)) return null;
CosmeticSlot slot = CosmeticSlot.valueOf(args1);
int amount = 0;
boolean checkUnlocked = false;
if (placeholderArgs.size() >= 3) if (placeholderArgs.get(2).equalsIgnoreCase("unlocked")) checkUnlocked = true;
for (Cosmetic cosmetic : Cosmetics.values()) {
if (cosmetic.getSlot() != slot) continue;
if (checkUnlocked && !user.canEquipCosmetic(cosmetic)) continue;
amount += 1;
}
return TranslationUtil.getTranslation("amount-cosmetic", String.valueOf(amount));
} 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()));
}
@@ -203,18 +208,61 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
return String.valueOf(itemMeta.getCustomModelData());
}
/**
* Gets the cosmetic items item model
* @param cosmetic The cosmetic to get its item model
* @return The cosmetic items item model
*/
@Nullable
public String getItemModel(@NotNull Cosmetic cosmetic) {
try {
ItemStack item = cosmetic.getItem();
if (item == null) return null;
if (!item.hasItemMeta()) return null;
ItemMeta itemMeta = item.getItemMeta();
if (itemMeta == null && itemMeta.hasItemModel() ) return null;
return itemMeta.getItemModel().asString();
} catch (Exception e) {
return null;
}
}
/**
* Gets the cosmetic items item name
* @param cosmetic The cosmetic to get its items item name
* @return The cosmetic items item name
*/
@Nullable
public String getItemName(@NotNull Cosmetic cosmetic) {
try {
ItemStack item = cosmetic.getItem();
if (item == null) return null;
if (!item.hasItemMeta()) return null;
ItemMeta itemMeta = item.getItemMeta();
if (itemMeta == null || !itemMeta.hasItemName()) return null;
return itemMeta.getDisplayName();
} catch (Exception e) {
return null;
}
}
/**
* Gets the cosmetic items display name
* @param cosmetic The cosmetic to get its items display name
* @return The cosmetic items display name
*/
@Nullable
public String getItemName(@NotNull Cosmetic cosmetic) {
public String getDisplayName(@NotNull Cosmetic cosmetic) {
ItemStack item = cosmetic.getItem();
if (item == null) return null;
if (!item.hasItemMeta()) return null;
ItemMeta itemMeta = item.getItemMeta();
if (itemMeta == null) return null;
if (!itemMeta.hasDisplayName()) return null;
return itemMeta.getDisplayName();
}

View File

@@ -1,20 +0,0 @@
package com.hibiscusmc.hmccosmetics.hooks.placeholders;
import com.hibiscusmc.hmccosmetics.hooks.Hook;
/**
* A hook that integrates the plugin {@link me.clip.placeholderapi.PlaceholderAPI PlaceholderAPI}
*/
public class HookPlaceholderAPI extends Hook {
public HookPlaceholderAPI() {
super("PlaceholderAPI");
}
/**
* Registers HMCCosmetics Placeholder Expansion
*/
@Override
public void load() {
new HMCPlaceholderExpansion().register();
}
}

View File

@@ -17,21 +17,26 @@ public class WGHook {
/**
* @implNote Please use {@link #getCosmeticEnableFlag()} instead
*/
public static StateFlag COSMETIC_ENABLE_FLAG;
private static StateFlag COSMETIC_ENABLE_FLAG;
private static StateFlag EMOTES_ENABLE_FLAG;
/**
* @implNote Please use {@link #getCosmeticWardrobeFlag()} instead
*/
public static StringFlag COSMETIC_WARDROBE_FLAG;
private static StringFlag COSMETIC_WARDROBE_FLAG;
public WGHook() {
FlagRegistry registry = WorldGuard.getInstance().getFlagRegistry();
try {
StateFlag cosmeticFlag = new StateFlag("cosmetic-enable", false);
StateFlag emoteFlag = new StateFlag("emotes-enable", false);
StringFlag wardrobeFlag = new StringFlag("cosmetic-wardrobe");
registry.register(cosmeticFlag);
registry.register(emoteFlag);
registry.register(wardrobeFlag);
COSMETIC_ENABLE_FLAG = cosmeticFlag;
EMOTES_ENABLE_FLAG = emoteFlag;
COSMETIC_WARDROBE_FLAG = wardrobeFlag;
} catch (FlagConflictException e) {
Flag<?> existing = registry.get("cosmetic-enable");
@@ -53,6 +58,14 @@ public class WGHook {
return COSMETIC_ENABLE_FLAG;
}
/**
* Gets the emotes enable {@link StateFlag}
* @return The emotes enable {@link StateFlag}
*/
public static StateFlag getEmotesEnableFlag() {
return EMOTES_ENABLE_FLAG;
}
/**
* Gets the cosmetic wardrobe {@link StateFlag}
* @return The cosmetic wardrobe {@link StateFlag}

View File

@@ -4,73 +4,79 @@ import com.hibiscusmc.hmccosmetics.config.Wardrobe;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
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;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Set;
/**
* Contains {@link com.sk89q.worldguard.WorldGuard WorldGuard} related event listeners
*/
public class WGListener implements Listener {
@EventHandler
@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();
com.sk89q.worldedit.util.Location loc = BukkitAdapter.adapt(location);
RegionContainer region = WorldGuard.getInstance().getPlatform().getRegionContainer();
RegionQuery query = region.createQuery();
ApplicableRegionSet set = query.getApplicableRegions(loc);
if (user.getHidden()) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD && set.getRegions().size() == 0) {
user.showCosmetics();
}
Location location = player.getLocation();
ApplicableRegionSet set = getRegions(location);
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")) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD) user.showCosmetics();
return;
Map<Flag<?>, Object> flags = protectedRegion.getFlags();
if (flags.containsKey(WGHook.getCosmeticEnableFlag())) {
if (flags.get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
} 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);
}
}
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerTeleport(PlayerTeleportEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
Location location = event.getTo();
com.sk89q.worldedit.util.Location loc = BukkitAdapter.adapt(location);
RegionContainer region = WorldGuard.getInstance().getPlatform().getRegionContainer();
RegionQuery query = region.createQuery();
ApplicableRegionSet set = query.getApplicableRegions(loc);
if (user.getHidden()) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD && set.getRegions().size() == 0) {
user.showCosmetics();
ApplicableRegionSet set = getRegions(location);
if (user.isHidden()) {
if (set.getRegions().isEmpty()) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
}
for (ProtectedRegion protectedRegion : set.getRegions()) {
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticEnableFlag())) {
if (protectedRegion.getFlags().get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD) user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
return;
}
user.hideCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
@@ -79,8 +85,15 @@ 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);
user.enterWardrobe(wardrobe, true);
}
}
}
private ApplicableRegionSet getRegions(Location location) {
com.sk89q.worldedit.util.Location loc = BukkitAdapter.adapt(location);
RegionContainer region = WorldGuard.getInstance().getPlatform().getRegionContainer();
RegionQuery query = region.createQuery();
return query.getApplicableRegions(loc);
}
}

View File

@@ -0,0 +1,40 @@
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(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerArmorEquip(PlayerArmorChangeEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
if (user.isInWardrobe()) return;
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;
case FEET -> CosmeticSlot.BOOTS;
case LEGS -> CosmeticSlot.LEGGINGS;
case CHEST -> CosmeticSlot.CHESTPLATE;
default -> null;
};
}
}

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