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

Compare commits

...

297 Commits

Author SHA1 Message Date
LoJoSho
6e94d74990 removed Citizens hook
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-21 11:09:56 -05:00
LoJoSho
5e3edd472c Revert previous commit
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-04 14:44:39 -05:00
LoJoSho
791fe53c48 NMS Test
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-04 14:32:08 -05:00
LoJoSho
c9f7762a26 work on ME 3.0
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-03 21:38:22 -05:00
LoJoSho
1be95c78c2 Moved around code
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-03 20:24:26 -05:00
LoJoSho
2be06e3ad9 Debug Logging for Balloons
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-10-03 20:24:12 -05:00
LoJoSho
d4bf6f256b Equipment no longer always sends full slots
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-30 12:29:10 -05:00
LoJoSho
5ffe39cdba Remove debug message
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-25 19:39:25 -05:00
LoJoSho
e6c81f8d1e Merge remote-tracking branch 'origin/plib_switch' into plib_switch 2022-09-25 19:36:23 -05:00
LoJoSho
0378b98967 Packet Overhaul, ME 3.0 Work, Teleport to last location config option
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-25 19:36:03 -05:00
lucian929
a26edbfc9c Add new cosmetics 2022-09-24 12:49:57 -04:00
lucian929
19e8a3bf10 Disable first person backpacks temporarily 2022-09-19 10:07:38 -04:00
LoJoSho
b8aefbacdb version bump (1.12.0-BETA-5)
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-10 21:26:15 -05:00
LoJoSho
7a29aa8927 Disabled Model Engine integration
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-10 21:23:51 -05:00
LoJoSho
482aec27f1 Fix for client disconnect as NPC name was >16 characters
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-10 21:22:52 -05:00
LoJoSho
007e5487e6 Added pumpkin option for wardrobe
Signed-off-by: LoJoSho <contact@lojosho.com>
2022-09-05 20:59:59 -05:00
LoJoSho
e7f077af7a Merge remote-tracking branch 'origin/plib_switch' into plib_switch 2022-09-05 20:26:28 -05:00
LoJoSho
99b1afd15c Changed info packet to be sent earlier 2022-09-05 20:26:10 -05:00
lucian929
3f5acde838 Update libraries
Signed-off-by: lucian929 <lucianfp27091@gmail.com>
2022-09-01 10:49:35 -04:00
LoJoSho
2676505c9a Version Bump (Beta-4) 2022-08-29 19:26:21 -05:00
LoJoSho
f5d1a09d28 Gui Opening + Skins in Wardrobe 2022-08-29 19:24:18 -05:00
LoJoSho
1b9e2ac531 Wardrobe Works! 2022-08-29 18:39:34 -05:00
LoJoSho
b005614881 Bundle of small changes 2022-08-29 14:16:43 -05:00
lucian929
a41fb7df2b Beta-3 2022-08-19 16:23:33 -04:00
LoJoSho
e0fbbc7f76 Fixed issue with armor not showing 2022-08-19 15:21:47 -05:00
LoJoSho
cb09da91fe Removed boolean from packet 2022-08-19 15:21:30 -05:00
LoJoSho
cd7ed29522 remove line 2022-08-19 15:20:29 -05:00
LoJoSho
f5a7c2f9f0 Byte mask apply 2022-08-18 17:47:53 -05:00
LoJoSho
6af8e13dab Removed Debug Messages 2022-08-18 17:36:52 -05:00
LoJoSho
e3f081f1c9 Version Bump (Beta-2) 2022-08-18 17:35:48 -05:00
LoJoSho
c7ba2f179a Update Citizens 2022-08-18 17:35:30 -05:00
LoJoSho
8f012f6c97 Fixed duplicate entity ids causing visual issues 2022-08-18 17:35:18 -05:00
LoJoSho
e95b30131c Bundle of changes 2022-08-18 15:02:21 -05:00
LoJoSho
2dc068a938 Bundle of changes 2022-08-15 17:59:53 -05:00
lucian929
7bdc122cb1 Bump version number (initial beta) 2022-08-15 16:31:09 -04:00
lucian929
a3d57af18d Merge pull request #31 from LoJoSho/lojo_dev
Experimental ProtocolLib Switch
2022-08-15 16:25:20 -04:00
LoJoSho
235c0a9307 Cosmetic Fixes 2022-08-15 15:17:16 -05:00
LoJoSho
4d7e565c23 Latest Commit 2022-08-12 14:34:54 -05:00
LoJoSho
57d3110740 It works! 2022-08-12 09:49:31 -05:00
LoJoSho
61e226b826 Compiling without PacketEvents 2022-08-09 22:16:35 -05:00
LoJoSho
bd7b045c0f Initial ProtocolLib Testing 2022-08-08 13:05:50 -05:00
LoJoSho
1ce28a9f66 Uncommented ProtocolLib 2022-08-08 13:05:04 -05:00
lucian929
70c2b79b6c Bump version number 2022-07-25 18:54:27 -04:00
Boy0000
39d485ddfe remove broadcast (#29) 2022-07-26 00:53:01 +02:00
lucian929
548a6bf4ec Merge pull request #28 from HibiscusMC/1.19_fix
1.19 fix
2022-07-25 18:50:24 -04:00
Boy
fb15919f52 update non-existing packet 2022-07-26 00:45:26 +02:00
lucian929
9a5923bb7d Merge remote-tracking branch 'origin/master' 2022-07-20 18:33:40 -04:00
lucian929
02239396f0 Changes to build.gradle.kts for MEG (temporary fix) 2022-07-20 18:33:20 -04:00
lucian929
942d48adf8 Merge pull request #26 from HibiscusMC/copyjar_task
add copyjar task
2022-07-17 18:06:01 -04:00
Boy
99ae2b765a add copyjar task 2022-07-18 00:04:13 +02:00
lucian929
6b59ba88a5 Bump version number 2022-07-11 13:15:12 -04:00
Fisher2911
4d7dff885a Merge remote-tracking branch 'origin/master' 2022-07-11 13:14:07 -04:00
Fisher2911
f4bc6f1bc3 Fixed particle amounts not working 2022-07-11 13:13:54 -04:00
lucian929
938dfe677d Fix mistake in config 2022-07-08 20:48:08 -04:00
Fisher2911
1c30924410 Merge remote-tracking branch 'origin/master' 2022-07-08 20:26:38 -04:00
lucian929
bd731c8b6b bump version number (1.11.0)! 2022-07-08 20:24:24 -04:00
lucian929
41f4f830d1 Update default configs 2022-07-08 20:22:50 -04:00
Fisher2911
86346583cc Fixed unequipping first person cosmetics 2022-07-08 20:13:43 -04:00
Fisher2911
b13d44536f Fixed rotation for other players 2022-07-08 15:56:46 -04:00
Fisher2911
822422d4a5 First person back hidden mode works 2022-07-08 15:51:51 -04:00
Fisher2911
449fc8a84b Why 2022-07-03 21:10:37 -04:00
Fisher2911
9be234cf11 Why 2022-07-03 21:08:30 -04:00
Fisher2911
08be1d56ac Attempting first person view stuff 2022-07-02 20:21:29 -04:00
lucian929
c6aecaae80 Change dependency info 2022-05-26 15:11:04 -04:00
lucian929
d25336f966 Feature request template (credit Skyslycer) 2022-05-22 10:57:21 -04:00
lucian929
49dfb46cc5 Unshaded packetevents (jar can be downloaded at https://github.com/retrooper/packetevents/actions) 2022-05-13 15:39:47 -04:00
lucian929
4774e2d1d6 build.gradle changes 2022-05-06 19:58:10 -04:00
Fisher2911
31775c5e85 Removed sending packets silently 2022-04-29 21:45:39 -04:00
Fisher2911
59bba0e854 Merge remote-tracking branch 'origin/master' 2022-04-29 21:44:44 -04:00
Fisher2911
74a0d279b0 Added close menu action 2022-04-29 21:44:29 -04:00
lucian929
3d51b77123 Fix look-down-backpack-remove 2022-04-07 00:01:50 -04:00
Fisher2911
fc7b886727 Merge remote-tracking branch 'origin/master' 2022-04-06 23:35:28 -04:00
Fisher2911
4be32d3849 Allow console command for wardrobe 2022-04-06 23:35:19 -04:00
lucian929
e39b56a63e Bump version number 2022-04-05 21:50:57 -04:00
Fisher2911
bc994bfa2f Fixed balloons not being removed in wardrobe 2022-04-05 21:44:03 -04:00
Fisher2911
0ea5c92d86 Fixed issue with not opening wardrobe inventory 2022-04-03 22:27:08 -04:00
Fisher2911
3ed245c95b Improved wardrobe viewing 2022-04-03 21:33:45 -04:00
Fisher2911
7bb4312fee 1.18.2 support, balloon bug fix 2022-04-01 23:04:45 -04:00
Fisher2911
24c06fd12c Fixed files not getting committed 2022-03-29 20:31:43 -04:00
Fisher2911
3a0ff5504e Fixed files not getting committed 2022-03-29 20:28:37 -04:00
Fisher2911
7caeec3fd1 Fixed packet sending 2022-03-29 20:17:28 -04:00
Fisher2911
4e3c0b1c6b Merge remote-tracking branch 'origin/master' 2022-03-22 22:50:57 -04:00
Fisher2911
383ee49d67 Progress so far with switching to PacketEvents 2022-03-22 22:50:32 -04:00
Fisher2911
67e3dbfcf5 Changed to use PacketEvents 2022-03-18 17:14:30 -04:00
lucian929
355920ae8c Update bug-report.yml 2022-03-14 17:52:16 -04:00
lucian929
cd2a8e54e1 Update bug-report.yml 2022-03-14 17:19:03 -04:00
lucian929
a05fde5038 Merge pull request #17 from HibiscusMC/issue-template
Issue template
2022-03-14 17:15:50 -04:00
lucian929
14b0cc6275 Fix YAML syntax error 2022-03-14 17:14:44 -04:00
lucian929
f9ffd91116 New issue template 2022-03-14 17:13:03 -04:00
lucian929
7b063815fc Remove feature template
We handle feature requests on our support discord.
2022-03-14 16:53:38 -04:00
Fisher2911
6653ac6edc Merge remote-tracking branch 'origin/master'
# Conflicts:
#	common/src/main/java/io/github/fisher2911/hmccosmetics/hook/CitizensHook.java
2022-03-12 15:23:54 -05:00
Fisher2911
2beadca574 Removed imports 2022-03-12 15:23:33 -05:00
Fisher2911
844e7c852f Added option to set multiple cosmetics 2022-03-12 13:28:08 -05:00
Fisher2911
6c2363a9fb Allowed sub folders for menus folder 2022-03-12 13:20:10 -05:00
Fisher2911
13212fe26e Fixed ModelEngine bug again 2022-03-12 13:16:09 -05:00
MasterOfTheFish
766eed0387 Fixed Citizens Error 2022-03-11 08:02:36 -05:00
lucian929
a06a5004e1 Bump version number 2022-03-10 21:39:21 -05:00
lucian929
8eec822a8c Merge pull request #16 from Acterax/master
Fix too much packets
2022-03-10 10:09:12 -05:00
Tom
56ca9b2a39 Fix too much packets 2022-03-10 16:02:02 +01:00
lucian929
88b24aefbc Bump version number 2022-03-07 20:10:41 -05:00
Fisher2911
e0044c6d15 Fixed balloons 2022-03-07 17:25:03 -05:00
Fisher2911
6c2049a8d8 Fixed ModelEngine error 2022-03-07 15:49:59 -05:00
lucian929
2ffb791ce1 Bump version number 2022-03-07 10:58:04 -05:00
lucian929
6ced156e23 Merge pull request #14 from KaspianDev/patch-1 2022-03-07 10:57:38 -05:00
Kacper Smoliński
8045a63964 Fix errors 2022-03-07 16:53:50 +01:00
Fisher
49681c7c1d Stopped loading of token if no cosmetic is found 2022-03-07 10:01:36 -05:00
Fisher
1e69dcea89 Fixed always having world name be 'world' 2022-03-07 09:51:07 -05:00
Fisher
2b832c33a4 Added removal of armor stand when not wearing backpack 2022-03-07 08:49:24 -05:00
Fisher2911
8cda481a55 Fixed reload issue with tokens 2022-03-07 00:01:47 -05:00
Fisher
6294a26b1d Delete nms/build directory 2022-03-06 18:34:43 -05:00
Fisher
29b26c29ca Delete common/build directory 2022-03-06 18:34:33 -05:00
Fisher
01230dda3f Delete 1.16/build directory 2022-03-06 18:34:11 -05:00
Fisher
181bd722ac Delete 1.18/build directory 2022-03-06 18:34:01 -05:00
Fisher
4deb586813 Delete 1.17/build directory 2022-03-06 18:33:51 -05:00
Fisher
d478736b5b Delete .idea directory 2022-03-06 18:33:26 -05:00
Fisher2911
d961bd2966 Merge branch 'updates'
# Conflicts:
#	.gitignore
#	1.16/build/classes/java/main/io/github/fisher2911/nms/ArmorStandPackets_1_16_R3.class
#	1.16/build/classes/java/main/io/github/fisher2911/nms/DestroyPacket_1_16_R3.class
#	1.16/build/libs/1.16.jar
#	1.16/build/tmp/compileJava/previous-compilation-data.bin
#	1.17/build/libs/1.17.jar
#	1.17/build/tmp/compileJava/previous-compilation-data.bin
#	1.18/build/libs/1.18.jar
#	1.18/build/tmp/compileJava/previous-compilation-data.bin
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/HMCCosmetics.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/api/CosmeticItem.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/api/HMCCosmeticsAPI.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/api/event/CosmeticChangeEvent.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/api/event/CosmeticItemEvent.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/command/CosmeticsCommand.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/concurrent/Threads.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/ActionSerializer.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/CosmeticSettings$1.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/CosmeticSettings.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/DyeGuiSerializer.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/GuiSerializer.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/ItemSerializer.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/Settings.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/SoundData.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/config/WardrobeSettings.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/cosmetic/CosmeticManager.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/Database.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/DatabaseConverter.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/DatabaseFactory.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/DatabaseType.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/dao/ArmorItemDAO.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/database/dao/UserDAO.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/ArmorItem$1.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/ArmorItem$Type.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/ArmorItem.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/ColorItem.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/CosmeticGui.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/CosmeticsMenu.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/gui/DyeSelectorGui.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/Hook.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/HookManager.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/PAPIHook.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/item/ItemHook.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/item/ItemHooks.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/item/ItemsAdderHook.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/hook/item/OraxenHook.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/inventory/PlayerArmor.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/ClickListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/CosmeticFixListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/JoinListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/MoveListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/PlayerShiftListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/RespawnListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/TeleportListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/listener/WardrobeClickListener.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Adventure.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/ErrorMessages.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Message$Type.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Message.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/MessageHandler$1.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/MessageHandler.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Messages$1.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Messages.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Permission.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Placeholder.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/TitleMessage.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/message/Translation.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/packet/PacketManager.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/DataTask.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/ImmediateTask.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/InfiniteTask.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/SupplierTask.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/SyncedTask.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/Task.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/TaskChain.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/task/TaskManager.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/user/Equipment.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/user/User.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/user/UserManager$1.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/user/UserManager.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/user/Wardrobe.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/Keys.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/StringUtils.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/Utils.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/builder/ColorBuilder.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/builder/ItemBuilder.class
#	common/build/classes/java/main/io/github/fisher2911/hmccosmetics/util/builder/SkullBuilder.class
#	common/build/generated/plugin-yml/Bukkit/plugin.yml
#	common/build/resources/main/config.yml
#	common/build/resources/main/menus/main.yml
#	common/build/resources/main/messages.yml
#	common/build/resources/main/plugin.yml
#	common/build/tmp/compileJava/previous-compilation-data.bin
#	nms/build/libs/nms.jar
#	nms/build/tmp/compileJava/previous-compilation-data.bin
2022-03-06 18:32:10 -05:00
lucian929
58ddceb5f1 Fix typo 2022-03-06 17:59:26 -05:00
lucian929
4be4c5fe2a Update help command to add new commands 2022-03-06 17:58:47 -05:00
lucian929
23c1774f37 Bump version number 2022-03-06 17:56:19 -05:00
lucian929
7c911d1247 Updates messages.yml 2022-03-06 17:40:01 -05:00
lucian929
89a32dcd30 Modified some default messages 2022-03-06 17:27:26 -05:00
Fisher2911
badc2f7b87 Fixed invalid token config 2022-03-06 17:16:30 -05:00
Fisher2911
16d516ef18 Removed sout 2022-03-06 17:03:26 -05:00
Fisher2911
1fcbe27d6a Fixed placeholders 2022-03-06 17:02:48 -05:00
Fisher2911
8da9100dd3 Fixed typo 2022-03-06 16:41:22 -05:00
Fisher2911
1888145ee0 Fixed ProtocolLib enum null error on first call 2022-03-06 16:37:48 -05:00
Fisher2911
84864303fc Finished tokens 2022-03-06 16:07:21 -05:00
Fisher2911
960bb97a04 Added tokens 2022-03-06 15:08:30 -05:00
Fisher2911
a55ad14934 Added 2022-03-06 13:45:53 -05:00
Fisher2911
8b345bc56c Fixed balloon movement 2022-03-05 17:45:26 -05:00
lucian929
4e21945bbb Small changes 2022-02-26 12:34:57 -05:00
MasterOfTheFish
b3aa0b942f Fixed teleporting error with player leaving wardrobe 2022-02-26 00:50:15 -05:00
MasterOfTheFish
607d2ea7bd Fixed issue with dye items not running actions 2022-02-26 00:49:10 -05:00
MasterOfTheFish
23bcd56eac BALLOONS?? 2022-02-26 00:23:33 -05:00
MasterOfTheFish
ba7327dd54 Merge remote-tracking branch 'origin/updates' into updates 2022-02-23 19:39:01 -05:00
MasterOfTheFish
35c6b01f34 Start balloon stuff 2022-02-23 19:38:49 -05:00
lucian929
ee86569f22 Bump Version Number
i forgot to last time
2022-02-23 09:41:04 -05:00
MasterOfTheFish
59dbee34ae Fixed placeholders not appearing on items in GUI menu 2022-02-23 08:53:25 -05:00
MasterOfTheFish
d12a5d090f Fixed concurrent error with citizens hook 2022-02-22 17:20:39 -05:00
MasterOfTheFish
5ba03402a0 Fixed double wardrobe message 2022-02-20 23:15:53 -05:00
MasterOfTheFish
b7c80437e2 Fixed double wardrobe message 2022-02-20 23:15:02 -05:00
MasterOfTheFish
e4cba947d3 Fixed citizens entity null error 2022-02-20 22:25:03 -05:00
MasterOfTheFish
e026739b34 Merge remote-tracking branch 'origin/updates' into updates
# Conflicts:
#	common/build.gradle.kts
2022-02-20 12:16:09 -05:00
MasterOfTheFish
440a106534 Bump version number 2022-02-20 12:15:41 -05:00
MasterOfTheFish
068a147e1e Fixed citizens empty cosmetic overriding armor 2022-02-20 12:12:00 -05:00
MasterOfTheFish
f3b780e730 Fixed concurrent error 2022-02-20 12:05:30 -05:00
MasterOfTheFish
8fa606954e Fixed wardrobe leave / join error 2022-02-20 11:51:07 -05:00
lucian929
9d3ca106c9 Bump version number 2022-02-19 22:31:45 -05:00
MasterOfTheFish
98a6528e50 Fixed formatted placeholder 2022-02-19 22:17:17 -05:00
MasterOfTheFish
a3bce9b766 Stopped sending of blank messages 2022-02-19 21:15:50 -05:00
MasterOfTheFish
d10afc3df3 Fixed placeholder cosmetic items 2022-02-19 21:13:50 -05:00
MasterOfTheFish
be7092b422 Fixed remove items not working 2022-02-19 20:10:38 -05:00
MasterOfTheFish
6ccc40798a Fixed item hooks not working 2022-02-19 19:48:27 -05:00
MasterOfTheFish
8503f3cb39 Allow item hook items to override name and lore 2022-02-19 19:42:45 -05:00
MasterOfTheFish
ffd15345d2 Added citizens support 2022-02-19 19:37:38 -05:00
MasterOfTheFish
a42730dc19 change up how user class works 2022-02-19 02:16:02 -05:00
MasterOfTheFish
363c57141c Added remove cosmetic config option 2022-02-18 20:26:12 -05:00
MasterOfTheFish
cc67eff1f7 Added wardrobe spawn delay 2022-02-18 20:16:20 -05:00
MasterOfTheFish
9b7b5ce1ad Removed glowing of selected item 2022-02-18 20:10:04 -05:00
MasterOfTheFish
ed41b71ff3 Allowed setting of other items in cosmetic slots 2022-02-18 20:06:20 -05:00
Fisher2911
54fe2719d1 Excluded snakeyaml dependency 2022-02-17 21:33:34 -05:00
Fisher2911
a7892ce434 Improved GUI 2022-02-17 19:47:03 -05:00
Fisher2911
39583b3685 Fixed wardrobe always active always stuck bug 2022-02-17 17:10:27 -05:00
Fisher2911
eec995a7f3 More placeholders 2022-02-17 17:05:41 -05:00
Fisher2911
c75182d118 Bump version 2022-02-17 00:36:13 -05:00
Fisher2911
268ccff0db Removed debug messages 2022-02-17 00:33:45 -05:00
Fisher2911
deb7806e78 Added skin overlay on wardrobe 2022-02-17 00:02:15 -05:00
Fisher2911
832980f593 Added skin overlay on wardrobe 2022-02-16 23:51:01 -05:00
lucian929
c8ee8c0c7c Remove some files 2022-02-15 12:40:52 -05:00
lucian929
ce3989edca Fix .gitignore (i think) 2022-02-15 12:30:03 -05:00
lucian929
09e252bd48 Update .gitignore 2022-02-15 12:28:13 -05:00
Fisher2911
f58d328bae update 2022-02-14 22:00:42 -05:00
HeroBrineGoat
2347c5175d Fixed offhand being weird in wardrobe mode 2022-02-06 23:15:40 -05:00
HeroBrineGoat
977b5e388a Added command to open other player's wardrobe 2022-02-06 18:59:55 -05:00
HeroBrineGoat
46c47b0a1f Fixed sound bug 2022-02-06 15:23:34 -05:00
HeroBrineGoat
4b8d2c1517 Added static wardrobe 2022-02-06 14:18:00 -05:00
HeroBrineGoat
4d632c612a Stopped displaying cosmetics if player is hidden 2022-02-06 12:35:45 -05:00
HeroBrineGoat
0b4e2a6966 Stopped displaying of cosmetics if player is hidden 2022-02-06 12:32:57 -05:00
HeroBrineGoat
23a5ffa068 Added PAPI expansion 2022-02-06 12:18:18 -05:00
HeroBrineGoat
56fa927ca6 Fixed needing permissions to view items in wardrobe 2022-02-03 00:01:10 -05:00
HeroBrineGoat
9c16008f29 Forgot to remove debug message 2022-02-02 22:19:35 -05:00
HeroBrineGoat
0dc69241f1 Improved messages 2022-02-02 22:17:43 -05:00
HeroBrineGoat
cf1e94e116 Finished wardrobe 2022-02-02 22:07:20 -05:00
HeroBrineGoat
72f92be6f6 Added wardrobe (Despawning and entity skin not functional) 2022-02-02 18:28:45 -05:00
HeroBrineGoat
39ac2713b7 Merge remote-tracking branch 'origin/master' 2022-02-02 16:12:39 -05:00
HeroBrineGoat
a07eec4ddc Added wardrobe (Need to fix imports) 2022-02-02 16:12:28 -05:00
Skyslycer
231dcc163e bump version 2022-02-02 19:01:49 +01:00
Skyslycer
d22b13fe05 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	build.gradle.kts
#	src/main/java/io/github/fisher2911/hmccosmetics/user/UserManager.java
2022-02-02 18:58:24 +01:00
Skyslycer
0c54f52785 fix async event calling 2022-02-02 18:55:23 +01:00
lucian929
16ede1baab Modify default files 2022-02-02 00:27:47 -05:00
HeroBrineGoat
1ba07b87cf Fixed NPE when not specifying dye 2022-02-01 23:44:59 -05:00
HeroBrineGoat
11baacaa5f Added message config action 2022-02-01 22:35:08 -05:00
HeroBrineGoat
8b231535c9 Improved set cosmetic command to include dye 2022-02-01 22:00:50 -05:00
HeroBrineGoat
b81241a019 Added actions for different click types 2022-02-01 21:51:59 -05:00
HeroBrineGoat
4b64ee1b3e Added sounds to click items (Configs must use new format!) 2022-01-31 22:28:18 -05:00
HeroBrineGoat
d2592809c7 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/java/io/github/fisher2911/hmccosmetics/gui/CosmeticsMenu.java
#	src/main/java/io/github/fisher2911/hmccosmetics/user/UserManager.java
2022-01-31 20:50:58 -05:00
HeroBrineGoat
ffae42c5a7 Added support for multiple dye menus 2022-01-31 20:50:12 -05:00
Skyslycer
7e4d9459ba idk 2022-01-31 16:36:37 +01:00
Skyslycer
30f5278ca9 gradle kotlin = best 2022-01-31 16:34:21 +01:00
Skyslycer
6e3de56071 refactor some stuff 2022-01-29 22:59:25 +01:00
HeroBrineGoat
3d9c006310 Bump version number 2022-01-29 16:42:18 -05:00
HeroBrineGoat
3d8b582a8f Bumped version 2022-01-28 22:24:10 -05:00
HeroBrineGoat
311253aed3 Fixed backpack being removed and not respawned on teleport 2022-01-28 22:21:13 -05:00
HeroBrineGoat
8912ab5b94 Removed paper requirement 2022-01-28 19:19:19 -05:00
HeroBrineGoat
136a5679a6 Bumped version number 2022-01-28 18:11:44 -05:00
HeroBrineGoat
e024d6420b Switched to using Spigot API 2022-01-28 18:10:46 -05:00
HeroBrineGoat
7a7ddf09fb Forgot to remove test listener 2022-01-28 17:29:56 -05:00
HeroBrineGoat
412688eebc Merge remote-tracking branch 'origin/master' 2022-01-28 17:29:36 -05:00
HeroBrineGoat
4aa3ecc147 Added API 2022-01-28 17:29:25 -05:00
lucian929
700ff1aa3f Modify main.yml to add baseball hat 2022-01-28 11:41:45 -05:00
lucian929
929fd84a74 Update to version 1.5.0 2022-01-28 11:41:26 -05:00
lucian929
cc768d8186 Modify main.yml for the lantern cosmetic 2022-01-27 23:43:20 -05:00
HeroBrineGoat
85fc9d9056 Added translations and toggling helmet / off hand requiring empty slots 2022-01-27 22:59:59 -05:00
HeroBrineGoat
538690612a Merge remote-tracking branch 'origin/master' 2022-01-25 23:15:53 -05:00
HeroBrineGoat
998cc02edd Fixed registering permissions 2022-01-25 23:15:09 -05:00
HeroBrineGoat
cfadc69a0d Added registering item permissions 2022-01-25 23:12:57 -05:00
HeroBrineGoat
a29d7f20d0 Added custom dye color command and message 2022-01-25 23:11:56 -05:00
lucian929
4460938dc3 Small changes to default files 2022-01-24 00:27:23 -05:00
lucian929
8a0ce58297 Bump Version Number 2022-01-23 21:50:31 -05:00
HeroBrineGoat
20efcb0b36 Fixed issue with hat disappearing when closing the inventory 2022-01-23 20:13:29 -05:00
HeroBrineGoat
af05a83451 Updated menu items 2022-01-23 18:41:16 -05:00
HeroBrineGoat
aed81b4a13 Added cool down of setting items 2022-01-23 16:37:47 -05:00
HeroBrineGoat
eec23ab54b Improved dye menu 2022-01-23 13:59:50 -05:00
HeroBrineGoat
45c51492a3 Fixed database 2022-01-22 01:10:59 -05:00
HeroBrineGoat
80f6e02598 Changed loading of database to be async 2022-01-21 18:39:45 -05:00
HeroBrineGoat
edc8724e90 Changed loading of database to be async 2022-01-21 18:35:03 -05:00
HeroBrineGoat
f7d8a7205f Changed sending packet to broadcast packet 2022-01-21 18:26:30 -05:00
HeroBrineGoat
3551de2cd3 Removed old database classes 2022-01-21 18:23:14 -05:00
HeroBrineGoat
3da27b0bf4 Added database converter 2022-01-21 18:21:51 -05:00
HeroBrineGoat
b63c130730 Off hand works now, and added some database converter stuff 2022-01-21 17:59:59 -05:00
HeroBrineGoat
81db0cab06 Merge remote-tracking branch 'origin/master' 2022-01-21 13:41:31 -05:00
HeroBrineGoat
f02871871c Fixed more gui stuff 2022-01-21 13:39:26 -05:00
HeroBrineGoat
7207974ada Merge branch 'master' into dev
# Conflicts:
#	src/main/java/io/github/fisher2911/hmccosmetics/gui/CosmeticGui.java
#	src/main/java/io/github/fisher2911/hmccosmetics/gui/DyeSelectorGui.java
2022-01-21 13:31:21 -05:00
HeroBrineGoat
7ea5cdcf46 Improved database handling, and added selecting which item to dye in menu 2022-01-21 13:29:29 -05:00
lucian929
512627d1c7 Bump Version Number 2022-01-20 22:38:08 -05:00
HeroBrineGoat
246fd3f9a6 Fixed (extremely) dumb runnable in GUI 2022-01-20 22:33:50 -05:00
HeroBrineGoat
70ee381f48 More database stuff 2022-01-20 19:09:54 -05:00
HeroBrineGoat
d78bf20ca9 Database stuff (incomplete) 2022-01-20 17:25:20 -05:00
HeroBrineGoat
1c7aa2c672 Cleaned up some code 2022-01-20 16:19:09 -05:00
lucian929
f0a046f434 Merge remote-tracking branch 'origin/master' 2022-01-19 23:15:38 -05:00
lucian929
22c4323a16 Bump Version Number 2022-01-19 23:15:21 -05:00
lucian929
77e913257e Merge pull request #5 from HibiscusMC/hooks
ItemsAdder Hook
2022-01-19 23:11:01 -05:00
HeroBrineGoat
2cc4fcc878 Fixed merging error 2022-01-19 21:21:38 -05:00
HeroBrineGoat
e35eee9937 Merge remote-tracking branch 'origin/hooks' into hooks
# Conflicts:
#	src/main/java/io/github/fisher2911/hmccosmetics/hook/item/ItemsAdderHook.java
2022-01-19 21:16:52 -05:00
HeroBrineGoat
941b82de08 Added support for item adder 2022-01-19 21:16:28 -05:00
Fisher
81bea485a5 Added debug messages 2022-01-19 09:54:13 -05:00
Fisher
cfa36dab4b Update DatabaseFactory.java 2022-01-19 09:48:21 -05:00
Fisher
14d1cf5d19 Added test to try to fix startup error 2022-01-19 08:00:11 -05:00
HeroBrineGoat
8455492322 Fix for backpack color not being set 2022-01-18 20:39:41 -05:00
HeroBrineGoat
c4dba6f9a8 Changed how ItemsAdder listener works 2022-01-18 19:53:33 -05:00
HeroBrineGoat
280018fb9f Changed all ItemAdder things to ItemsAdder 2022-01-18 19:45:02 -05:00
HeroBrineGoat
14617fdaff Changed class name to reflect plugin name 2022-01-18 19:43:13 -05:00
HeroBrineGoat
61f13eb3c1 Fixed ItemsAdder identifier 2022-01-18 19:42:34 -05:00
HeroBrineGoat
39b6a8de67 Fixed ItemsAdder support (Previously done directly on GitHub using a school computer) 2022-01-18 19:25:11 -05:00
lucian929
f19b4d359e Fixes for IA 2022-01-18 15:46:27 -05:00
Fisher
0ca9350ce6 Update HMCCosmetics.java 2022-01-18 12:54:51 -05:00
Fisher
d9f12db6dc Create ItemsAdderListener.java 2022-01-18 12:52:51 -05:00
Fisher
3c302e6c4b Update HMCCosmetics.java 2022-01-18 12:46:57 -05:00
Fisher
e22b776d13 Added ItemAdderHook
The format is "itemadder:item"
2022-01-18 12:05:34 -05:00
Fisher
915285c485 Create ItemAdderHook.java 2022-01-18 12:01:43 -05:00
HeroBrineGoat
02a3c96137 Merge remote-tracking branch 'origin/master' 2022-01-17 23:22:54 -05:00
HeroBrineGoat
7bb8fd79c2 Changed location of armor stand spawn 2022-01-17 23:22:30 -05:00
lucian929
27cab1fb4b Bump version number 2022-01-17 18:40:36 -05:00
HeroBrineGoat
3c8c585634 Added oraxen item support 2022-01-17 18:33:29 -05:00
lucian929
b2465c8b13 Bump version number according to Semver standards 2022-01-17 15:12:35 -05:00
HeroBrineGoat
3cc489cac9 Fixed MySQL issues 2022-01-17 14:45:44 -05:00
HeroBrineGoat
328aacb73d Merge remote-tracking branch 'origin/master' 2022-01-17 14:13:03 -05:00
HeroBrineGoat
3e609dac93 Added SQLite and MySQL support 2022-01-17 14:12:45 -05:00
lucian929
14eb7b8edc Update README.md 2022-01-16 20:34:24 -05:00
lucian929
5c9041acfc Update README.md 2022-01-16 20:33:00 -05:00
lucian929
f40c6fc292 Merge remote-tracking branch 'origin/master' 2022-01-16 20:11:48 -05:00
lucian929
f800ceaed6 Updated messages.yml (again) 2022-01-16 20:11:36 -05:00
HeroBrineGoat
a6c5761636 Merge remote-tracking branch 'origin/master' 2022-01-16 20:09:34 -05:00
HeroBrineGoat
bb812a180f Fixed teleport issue 2022-01-16 20:09:22 -05:00
lucian929
d69dd1afef Updated messages.yml 2022-01-16 19:04:44 -05:00
HeroBrineGoat
4a1eb8a85f Added remove cosmetic command 2022-01-16 16:06:10 -05:00
HeroBrineGoat
d6c052294a Merge branch 'dev' 2022-01-16 15:52:37 -05:00
HeroBrineGoat
32afd0d144 Fixed title PAPI placeholder 2022-01-16 15:52:05 -05:00
HeroBrineGoat
66ff99e657 Added placeholder api 2022-01-16 15:32:44 -05:00
HeroBrineGoat
67cf6d3267 Armor stands work now??? 2022-01-16 14:29:38 -05:00
HeroBrineGoat
1d988ed809 Added command to set other players cosmetics 2022-01-15 21:48:11 -05:00
HeroBrineGoat
22f095f236 Current state of trying to use packets (A giant mess) 2022-01-15 21:29:56 -05:00
HeroBrineGoat
cc0b2d75b7 Possible rotation working 2022-01-14 20:36:46 -05:00
HeroBrineGoat
520b9854f5 Potential sitting fix 2022-01-14 20:16:34 -05:00
HeroBrineGoat
f8bc649799 Fixed issue with odd behaviour when interacting with non-cosmetic helmet with a cosmetic applied 2022-01-14 17:42:40 -05:00
HeroBrineGoat
44c99ae6d2 Forgot to commit UserManager class in the previous commit 2022-01-13 21:14:08 -05:00
HeroBrineGoat
63681ab9cf Trying out armor stand packets 2022-01-13 21:12:50 -05:00
HeroBrineGoat
705664441a Merge remote-tracking branch 'origin/master' 2022-01-13 19:28:30 -05:00
HeroBrineGoat
d7a8cac2e2 Fixed color issue in dye menu 2022-01-13 19:28:02 -05:00
lucian929
3cef8dc0e3 Switched "Loaded GUI:" logger level to INFO 2022-01-13 16:40:33 -05:00
lucian929
b054207012 Merge pull request #4 from HibiscusMC/skyslycer/feature-1
Several features
2022-01-13 16:23:03 -05:00
Skyslycer
1bb80e0fcd Merge branch 'master' into skyslycer/feature-1 2022-01-13 22:12:28 +01:00
Skyslycer
e9694e77d7 update messages.yml 2022-01-13 22:11:05 +01:00
Skyslycer
a8ba081975 add different message for no permission for cosmetics and make the chat thing reload too 2022-01-13 22:08:10 +01:00
lucian929
6843373298 Update messages.yml 2022-01-13 13:35:55 -05:00
lucian929
c97c3650ea Added help command 2022-01-12 20:44:55 -05:00
lucian929
dbdc6a5c90 Added help command 2022-01-12 20:44:24 -05:00
182 changed files with 12578 additions and 2285 deletions

View File

@@ -1,20 +0,0 @@
---
name: Bug Report
about: Create a bug report to help us keep track of all bugs that have to be fixed
title: "[BUG] Bug name"
labels: bug
---
**I have checked...**
- [ ] ...if there are any similar bug reports
- [ ] ...if a bug fix is already planned
**Complete description**
Write your bug description as good as you can.
**Possible solution**
If you have any possible solutions, write them here, if not, leave it blank or put "N/A".
**Error/Server log**
If you have any errors put them in here (from paste.gg or sentry)

62
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: Bug Report
description: Create a bug report to help us keep track of all bugs that have to be fixed
title: "[BUG] <name for bug>"
labels: [bug]
body:
- type: checkboxes
id: i-have-checked
attributes:
label: I have checked...
options:
- label: "I am using the latest version of HMCCosmetics"
required: true
- label: "I am using the latest version of any dependencies"
required: true
- label: "I have checked if any similar bug reports exist"
required: true
- type: textarea
id: description
attributes:
label: Description
description: A full description of the bug
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: Explain how to reproduce this issue step-by-step, in as much detail as possible.
validations:
required: true
- type: textarea
id: hmcc-version
attributes:
label: Plugin Version
description: Run `version HMCCosmetics` in your console and paste the output
validations:
required: true
- type: textarea
id: meg-version
attributes:
label: ModelEngine Version
description: "Run `version ModelEngine` in your console and paste the output. Optional if not using balloons."
validations:
required: false
- type: textarea
id: server-version
attributes:
label: Server Version
description: "Run `version` in your console and paste the output."
validations:
required: true
- type: "dropdown"
id: "type"
attributes:
label: "How breaking is the bug?"
options:
- "Breaking Bug - Plugin unusable"
- "Non-breaking Bug - Plugin still usable, but certain features unavailable"
- "Minor Bug - Plugin completely functional, but features have non-working aspects"
validations:
required: true

View File

@@ -0,0 +1,29 @@
name: Feature Request
description: Create a feature request to help us keep track of all features you want to be added
title: "[FEATURE] <title>"
labels: [feature]
body:
- type: "checkboxes"
id: "i-have-checked"
attributes:
label: "I have checked that..."
options:
- label: "...such a feature does not exist already"
required: true
- label: "...such a feature request has not been submitted already"
required: true
- type: "textarea"
id: "description"
attributes:
label: "Description"
description: "A full description of the feature"
validations:
required: true
- type: "textarea"
id: "config-changes"
attributes:
label: "Config Changes"
description: "The configuration changes your feature should have"
validations:
required: false

View File

@@ -1,19 +0,0 @@
---
name: Feature To-Do
about: Create an issue with this template to keep track of the current development projects.
title: "[FEATURE] Feature name"
labels: enhancement
---
**I have checked...**
- [ ] ...if there are any similar features in other branches
- [ ] ...if there are any similar issues
- [ ] ...if such a feature is already planned
**Complete description**
Write your feature description as good as you can.
**Reason for feature request**
Write your reason for the feature request as good as you can.

9
.gitignore vendored
View File

@@ -1,4 +1,11 @@
# Project exclude paths
/.gradle/
/gradle/
/.idea/
/build/
/build/classes/java/main/
/build/classes/java/main/
/common/build/
/1.16/build/
/1.17/build/
/1.18/build/
/nms/build/

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

6
.idea/compiler.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="16" />
</component>
</project>

7
.idea/discord.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="ASK" />
<option name="description" value="" />
</component>
</project>

17
.idea/gradle.xml generated
View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="HotSwapAgentPluginSettingsProvider">
<option name="agentPath" value="C:\Users\barry\AppData\Roaming\JetBrains\IdeaIC2021.2\plugins\hotswap-agent-intellij-plugin\lib\agent\hotswap-agent-1.4.1.jar" />
</component>
</project>

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="https://repo.extendedclip.com/content/repositories/placeholderapi/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
<option name="name" value="maven" />
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven6" />
<option name="name" value="maven6" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://repo.mattstudios.me/artifactory/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven5" />
<option name="name" value="maven5" />
<option name="url" value="https://repo.leonardobishop.com/releases/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenLocal" />
<option name="name" value="MavenLocal" />
<option name="url" value="file:/$MAVEN_REPOSITORY$/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven7" />
<option name="name" value="maven7" />
<option name="url" value="https://repo.dmulloy2.net/repository/public/" />
</remote-repository>
</component>
</project>

15
.idea/misc.xml generated
View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<list size="1">
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="16" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>PAPER</platformType>
<platformType>MCP</platformType>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
</configuration>
</facet>
</component>
<component name="McpModuleSettings">
<option name="srgType" value="SRG" />
</component>
</module>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
</configuration>
</facet>
</component>
</module>

124
.idea/uiDesigner.xml generated
View File

@@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -10,17 +10,15 @@
### Description
HMCCosmetics is a free, open source cosmetics plugin which allows you to easily give players backpack and hat type cosmetics.
HMCCosmetics is an intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.
### Requirements
- Server running PaperMC (or a fork of PaperMC)
- ProtocolLib
- [packetevents 2.0](https://github.com/retrooper/packetevents)
### Download
Download on the [Releases Page](https://github.com/HibiscusMC/HMCCosmetics/releases)
If you would like to support the development of our plugin, please purchase it on [Polymart](https://polymart.org/resource/hmccosmetics.1879)

View File

@@ -1,51 +0,0 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '6.1.0'
}
group 'io.github.fisher2911'
version '1.0.2'
repositories {
mavenCentral()
mavenLocal()
maven { url = 'https://papermc.io/repo/repository/maven-public/' }
maven { url = 'https://repo.mattstudios.me/artifactory/public/' }
maven { url = 'https://jitpack.io' }
maven { url = 'https://repo.leonardobishop.com/releases/' }
maven { url = 'https://repo.dmulloy2.net/repository/public/' }
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
compileOnly 'io.papermc.paper:paper:1.17.1-R0.1-SNAPSHOT'
compileOnly 'org.jetbrains:annotations:22.0.0'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.7.0'
compileOnly 'net.kyori:adventure-api:4.9.3'
implementation 'net.kyori:adventure-text-minimessage:4.2.0-SNAPSHOT'
implementation 'net.kyori:adventure-platform-bukkit:4.0.0'
implementation 'dev.triumphteam:triumph-gui:3.0.3'
implementation 'me.mattstudios.utils:matt-framework:1.4.6'
implementation 'org.spongepowered:configurate-yaml:4.1.2'
implementation 'org.bstats:bstats-bukkit:2.2.1'
}
test {
useJUnitPlatform()
}
shadowJar {
relocate 'dev.triumphteam.gui', 'io.github.fisher2911.hmccosmetics.gui'
relocate 'me.mattstudios.mf', 'io.github.fisher2911.hmccosmetics.mf'
relocate 'net.kyori.adventure.text.minimessage', 'io.github.fisher2911.hmccosmetics.adventure.minimessage'
relocate 'net.kyori.adventure.platform', 'io.github.fisher2911.hmccosmetics.adventure.platform'
relocate 'org.spongepowered.configurate', 'io.github.fisher2911.hmccosmetics.configurate'
relocate 'org.bstats', 'io.github.fisher2911.hmccosmetics.bstats'
}
shadowJar {
archiveBaseName.set('HMCCosmetics')
archiveClassifier.set('')
archiveVersion.set('')
}

3
build.gradle.kts Normal file
View File

@@ -0,0 +1,3 @@
plugins {
id("java")
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@@ -0,0 +1,2 @@
#Wed Feb 02 16:44:24 EST 2022
gradle.version=7.3.3

Binary file not shown.

Binary file not shown.

View File

168
common/build.gradle.kts Normal file
View File

@@ -0,0 +1,168 @@
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
plugins {
id("java")
id("com.github.johnrengelman.shadow") version "7.1.1"
id("net.minecrell.plugin-yml.bukkit") version "0.5.1"
}
group = "io.github.fisher2911"
version = "1.12.0-BETA-5"
description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
repositories {
mavenCentral()
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://repo.mattstudios.me/artifactory/public/")
maven("https://jitpack.io")
maven("https://repo.dmulloy2.net/repository/public/")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
maven("https://mvnrepository.com/artifact/com.zaxxer/HikariCP")
maven("https://repo.jeff-media.de/maven2/")
maven("https://repo.citizensnpcs.co")
//maven("https://mvn.lumine.io/repository/maven-public")
maven {
url = uri("https://mvn.lumine.io/repository/maven-public")
metadataSources {
artifact()
}
}
maven("https://jitpack.io/")
}
dependencies {
// implementation(project(":1.16"))
// implementation(project(":1.17"))
// implementation(project(":1.18"))
// implementation(project(":nms"))
compileOnly("com.mojang:authlib:1.5.25")
compileOnly("org.spigotmc:spigot:1.16.5-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.1")
compileOnly("com.github.oraxen:oraxen:-SNAPSHOT")
compileOnly("com.github.LoneDev6:API-ItemsAdder:2.5.4")
compileOnly("net.citizensnpcs:citizens-main:2.0.30-SNAPSHOT")
compileOnly("com.ticxo.modelengine:api:R3.0.0")
//compileOnly("com.github.retrooper.packetevents:spigot:2.0-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("me.mattstudios.utils:matt-framework:1.4.6")
implementation("org.spongepowered:configurate-yaml:4.1.2")
implementation("org.bstats:bstats-bukkit:3.0.0")
implementation("com.zaxxer:HikariCP:5.0.1")
implementation("com.j256.ormlite:ormlite-jdbc:6.1")
implementation("com.j256.ormlite:ormlite-core:6.1")
}
tasks {
build {
dependsOn(shadowJar)
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(16)
}
shadowJar {
relocate("dev.triumphteam.gui", "io.github.fisher2911.hmccosmetics.gui")
relocate("me.mattstudios.mf", "io.github.fisher2911.hmccosmetics.mf")
relocate("net.kyori.adventure", "io.github.fisher2911.hmccosmetics.adventure")
relocate("org.spongepowered.configurate", "io.github.fisher2911.hmccosmetics.configurate")
relocate("org.bstats", "io.github.fisher2911.hmccosmetics.bstats")
relocate("com.zaxxer.hikaricp", "io.github.fisher2911.hmccosmetics.hikaricp")
relocate("com.j256.ormlite", "io.github.fisher2911.hmccosmetics.ormlite")
//relocate("com.github.retrooper.packetevents", "io.github.fisher2911.hmccosmetics.packetevents")
//relocate("io.github.retrooper.packetevents", "io.github.fisher2911.hmccosmetics.packetevents")
archiveFileName.set("HMCCosmetics.jar")
dependencies {
exclude(dependency("org.yaml:snakeyaml"))
}
// todo - remove (Testing only)
//destinationDirectory.set(file("D:\\paper-1.18.1\\plugins"))
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
filteringCharset = Charsets.UTF_8.name()
}
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(16
))
}
bukkit {
load = BukkitPluginDescription.PluginLoadOrder.STARTUP
main = "io.github.fisher2911.hmccosmetics.HMCCosmetics"
apiVersion = "1.16"
name = "HMCCosmetics"
authors = listOf("MasterOfTheFish")
softDepend = listOf("Multiverse", "PlaceholderAPI", "Oraxen", "ItemsAdder", "Citizens", "ModelEngine")
depend = listOf("ProtocolLib")
permissions {
register("hmccosmetics.cmd.default") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to execute the default command."
}
register("hmccosmetics.cmd.dye") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to dye armor."
}
register("hmccosmetics.cmd.reload") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to use the reload command."
}
register("hmccosmetics.cmd.set") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to set other users' cosmetics."
}
register("hmccosmetics.cmd.wardrobe.portable") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to use a portable wardrobe"
}
register("hmccosmetics.cmd.wardrobe") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to view the wardrobe"
}
register("hmccosmetics.cmd.wardrobe.other") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to open another player's wardrobe"
}
register("hmccosmetics.cmd.token.give") {
default = BukkitPluginDescription.Permission.Default.OP
description = "Permission to give other players tokens"
}
}
}
val copyJar: String? by project
val pluginPath = project.findProperty("hibiscusmc_plugin_path")
if(copyJar != "false" && pluginPath != null) {
tasks {
register<Copy>("copyJar") {
from(findByName("reobfJar") ?: findByName("shadowJar") ?: findByName("jar"))
into(pluginPath)
doLast {
println("Copied to plugin directory $pluginPath")
}
}
named<DefaultTask>("build") {
dependsOn("copyJar")
}
}
}

BIN
common/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -0,0 +1,254 @@
package io.github.fisher2911.hmccosmetics;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import io.github.fisher2911.hmccosmetics.command.CosmeticsCommand;
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
import io.github.fisher2911.hmccosmetics.config.Settings;
import io.github.fisher2911.hmccosmetics.config.TokenLoader;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.database.Database;
import io.github.fisher2911.hmccosmetics.database.DatabaseFactory;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.CosmeticsMenu;
import io.github.fisher2911.hmccosmetics.gui.Token;
import io.github.fisher2911.hmccosmetics.hook.CitizensHook;
import io.github.fisher2911.hmccosmetics.hook.HookManager;
import io.github.fisher2911.hmccosmetics.hook.item.ItemsAdderHook;
import io.github.fisher2911.hmccosmetics.listener.ClickListener;
import io.github.fisher2911.hmccosmetics.listener.CosmeticFixListener;
import io.github.fisher2911.hmccosmetics.listener.JoinListener;
import io.github.fisher2911.hmccosmetics.listener.PlayerShiftListener;
import io.github.fisher2911.hmccosmetics.listener.RespawnListener;
import io.github.fisher2911.hmccosmetics.listener.TeleportListener;
import io.github.fisher2911.hmccosmetics.listener.WardrobeListener;
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
import io.github.fisher2911.hmccosmetics.message.Messages;
import io.github.fisher2911.hmccosmetics.message.Translation;
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
import io.github.fisher2911.hmccosmetics.task.TaskManager;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import me.mattstudios.mf.base.CommandManager;
import me.mattstudios.mf.base.CompletionHandler;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class HMCCosmetics extends JavaPlugin {
public static final Path PLUGIN_FOLDER = Paths.get("plugins", "HMCCosmetics");
private TaskManager taskManager;
private Settings settings;
private UserManager userManager;
private CosmeticManager cosmeticManager;
private MessageHandler messageHandler;
private CosmeticsMenu cosmeticsMenu;
private TokenLoader tokenLoader;
private CommandManager commandManager;
private Database database;
private BukkitTask saveTask;
private ProtocolManager manager;
/* // commented because PacketEvents is no longer shaded
@Override
public void onLoad() {
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
PacketEvents.getAPI().load();
}
*/
@Override
public void onEnable() {
final int pluginId = 13873;
final Metrics metrics = new Metrics(this, pluginId);
this.taskManager = new TaskManager(this);
this.taskManager.start();
this.settings = new Settings(this);
this.messageHandler = new MessageHandler(this);
this.userManager = new UserManager(this);
this.cosmeticManager = new CosmeticManager(new HashMap<>(), new HashMap<>(), new HashMap<>());
this.cosmeticsMenu = new CosmeticsMenu(this);
this.tokenLoader = new TokenLoader(this);
this.manager = ProtocolLibrary.getProtocolManager();
this.userManager.startTeleportTask();
try {
this.database = DatabaseFactory.create(this);
} catch (final SQLException exception) {
exception.printStackTrace();
}
PacketManager.setupPackets();
this.registerCommands();
this.registerListeners();
if (!HookManager.getInstance().isEnabled(ItemsAdderHook.class)) {
this.load();
}
HookManager.getInstance().init();
this.saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
this,
() -> Threads.getInstance().execute(
() -> this.database.saveAll()
),
20 * 60,
20 * 60
);
}
@Override
public void onDisable() {
//PacketEvents.getAPI().terminate();
this.saveTask.cancel();
this.database.saveAll();
this.messageHandler.close();
this.userManager.removeAll();
Threads.getInstance().onDisable();
this.database.close();
this.taskManager.end();
}
private void registerListeners() {
List.of(
new JoinListener(this),
new ClickListener(this),
new TeleportListener(this),
new RespawnListener(this),
new CosmeticFixListener(this),
new PlayerShiftListener(this),
new WardrobeListener(this)
).
forEach(
listener -> this.getServer().getPluginManager()
.registerEvents(listener, this)
);
}
private void registerCommands() {
this.commandManager = new CommandManager(this, true);
final HookManager hookManager = HookManager.getInstance();
final me.mattstudios.mf.base.MessageHandler messageHandler = this.commandManager.getMessageHandler();
messageHandler.register("cmd.no.console", player ->
this.messageHandler.sendMessage(
player,
Messages.MUST_BE_PLAYER
)
);
messageHandler.register("cmd.no.permission", player ->
this.messageHandler.sendMessage(
player,
Messages.NO_PERMISSION
)
);
messageHandler.register("cmd.no.exists", player ->
this.messageHandler.sendMessage(
player,
Messages.HELP_COMMAND
));
messageHandler.register("cmd.wrong.usage", player ->
this.messageHandler.sendMessage(
player,
Messages.HELP_COMMAND
));
final CompletionHandler completionHandler = this.commandManager.getCompletionHandler();
completionHandler.register("#types",
resolver ->
Arrays.stream(ArmorItem.Type.
values()).
map(ArmorItem.Type::toString).
collect(Collectors.toList())
);
completionHandler.register("#ids",
resolver ->
this.cosmeticManager.getAllArmorItems().stream().map(ArmorItem::getId)
.collect(Collectors.toList()));
completionHandler.register("#tokens",
resolver ->
this.cosmeticManager.getAllTokens().stream().map(Token::getId)
.collect(Collectors.toList()));
completionHandler.register("#menus",
resolver -> new ArrayList<>(this.cosmeticsMenu.getMenus())
);
completionHandler.register("#npc-args",
resolver -> List.of(CosmeticsCommand.NPC_REMOVE, CosmeticsCommand.NPC_APPLY));
completionHandler.register("#npcs", resolver -> {
final List<String> ids = new ArrayList<>();
if (!hookManager.isEnabled(CitizensHook.class)) return ids;
for (final int id : hookManager.getCitizensHook().getAllNPCS()) {
ids.add(String.valueOf(id));
}
return ids;
});
this.commandManager.register(new CosmeticsCommand(this));
}
public void load() {
Bukkit.getScheduler().runTaskLaterAsynchronously(this,
() -> {
this.settings.load();
this.messageHandler.load();
this.cosmeticsMenu.load();
this.tokenLoader.load();
Translation.getInstance().load();
this.database.load();
}, 1);
}
public void reload() {
Bukkit.getScheduler().runTaskAsynchronously(this,
() -> {
this.settings.load();
this.messageHandler.load();
this.cosmeticsMenu.reload();
this.tokenLoader.load();
Translation.getInstance().load();
});
}
public TaskManager getTaskManager() {
return taskManager;
}
public Settings getSettings() {
return settings;
}
public MessageHandler getMessageHandler() {
return messageHandler;
}
public UserManager getUserManager() {
return userManager;
}
public CosmeticManager getCosmeticManager() {
return cosmeticManager;
}
public CosmeticsMenu getCosmeticsMenu() {
return cosmeticsMenu;
}
public Database getDatabase() {
return database;
}
public ProtocolManager getProtocolManager() {
return manager;
}
}

View File

@@ -0,0 +1,110 @@
package io.github.fisher2911.hmccosmetics.api;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
/**
* Wrapper for ArmorItem used internally for convenience and safety
*/
public class CosmeticItem {
private final ArmorItem armorItem;
public CosmeticItem(final ArmorItem armorItem) {
this.armorItem = armorItem;
}
/**
* @param itemStack the {@link org.bukkit.inventory.ItemStack} display item
* @param id the id of the item
* @param type the cosmetic item type
* @param dyeable whether the item can be dyed
* @param rgb from Bukkit's {@link Color#asRGB()}
*/
public CosmeticItem(
final ItemStack itemStack,
final String name,
final String id,
final ItemStack locked,
final ItemStack applied,
final String permission,
final ArmorItem.Type type,
final boolean dyeable,
final int rgb) {
this.armorItem = new ArmorItem(itemStack, name, id, locked, applied, permission, type, dyeable, rgb);
}
/**
* @param material the {@link org.bukkit.Material} display item
* @param id the id of the item
* @param type the cosmetic item type
* @param dyeable whether the item can be dyed
* @param rgb from Bukkit's {@link Color#asRGB()}
*/
public CosmeticItem(
final Material material,
final String name,
final String id,
final Material locked,
final Material applied,
final String permission,
final ArmorItem.Type type,
final boolean dyeable,
final int rgb
) {
this.armorItem = new ArmorItem(material, name, id, new ItemStack(locked), new ItemStack(applied), permission, type, dyeable, rgb);
}
/**
* @param itemStack the {@link org.bukkit.inventory.ItemStack} display item
* @param id the id of the item
* @param type the cosmetic item type
*/
public CosmeticItem(final ItemStack itemStack, final String name, final String id, final ItemStack locked, final ItemStack applied, final ArmorItem.Type type) {
this(itemStack, name, id, locked, applied, "", type, false, -1);
}
/**
* @param material the {@link org.bukkit.Material} display item
* @param id the id of the item
* @param type the cosmetic item type
*/
public CosmeticItem(final Material material, final Material locked, final Material applied, final String name, final String id, final ArmorItem.Type type) {
this(material, name, id, locked, applied, "", type, false, -1);
}
public ItemStack getItemStack(final ArmorItem.Status status) {
return this.armorItem.getItemStack(status);
}
public ItemStack getItemStack() {
return this.armorItem.getItemStack();
}
public String getId() {
return this.armorItem.getId();
}
public ArmorItem.Type getType() {
return this.armorItem.getType();
}
public boolean isDyeable() {
return this.armorItem.isDyeable();
}
public int getColor() {
return this.armorItem.getDye();
}
public ArmorItem getArmorItem() {
return this.armorItem;
}
}

View File

@@ -0,0 +1,80 @@
package io.github.fisher2911.hmccosmetics.api;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID;
public class HMCCosmeticsAPI {
private static final HMCCosmetics plugin;
static {
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
}
/**
* This will attempt to get the {@link CosmeticItem} that
* the user is wearing. It returns an empty {@link CosmeticItem}
* if the user is not found, or if the user is not wearing a cosmetic
*
* @param uuid the uuid of the user
* @param type the type of cosmetic being retrieved
* @return the current cosmetic of the player
*/
public static CosmeticItem getUserCurrentItem(final UUID uuid, final ArmorItem.Type type) {
final Optional<User> userOptional = plugin.getUserManager().get(uuid);
if (userOptional.isEmpty()) {
return new CosmeticItem(ArmorItem.empty(type));
}
return new CosmeticItem(userOptional.get().getPlayerArmor().getItem(type));
}
/**
* @param uuid the uuid of the user whose cosmetic is being set
* @param cosmeticItem the cosmetic being set
* @return true if the cosmetic was set, or else false
*/
public static boolean setCosmeticItem(final UUID uuid, final CosmeticItem cosmeticItem) {
final UserManager userManager = plugin.getUserManager();
final Optional<User> userOptional = userManager.get(uuid);
if (userOptional.isEmpty()) {
return false;
}
userManager.setItem(userOptional.get(), cosmeticItem.getArmorItem(), true);
return true;
}
/**
* @param id the id of the cosmetic item being retrieved
* @return null if the cosmetic was not found, or a copy of the cosmetic item
*/
@Nullable
public static CosmeticItem getCosmeticFromId(final String id) {
final ArmorItem armorItem = plugin.getCosmeticManager().getArmorItem(id);
if (armorItem == null) {
return null;
}
return new CosmeticItem(armorItem.copy());
}
/**
* @param uuid the uuid of the user whose armor stand id is being retrieved
* @return the armor stand id, or -1 if the user is not found
*/
public static int getUserArmorStandId(final UUID uuid) {
final Optional<User> userOptional = plugin.getUserManager().get(uuid);
if (userOptional.isEmpty()) {
return -1;
}
return userOptional.get().getArmorStandId();
}
}

View File

@@ -0,0 +1,42 @@
package io.github.fisher2911.hmccosmetics.api.event;
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
import io.github.fisher2911.hmccosmetics.user.BaseUser;
/**
* Called when a user changes their equipped cosmetic
*/
public class CosmeticChangeEvent extends CosmeticItemEvent {
private final BaseUser<?> user;
private CosmeticItem removed;
public CosmeticChangeEvent(
final CosmeticItem cosmeticItem,
final CosmeticItem removed,
final BaseUser<?> user) {
super(cosmeticItem);
this.removed = removed;
this.user = user;
}
public CosmeticChangeEvent(final boolean isAsync, final CosmeticItem cosmeticItem, final CosmeticItem removed, final BaseUser<?> user) {
super(isAsync, cosmeticItem);
this.removed = removed;
this.user = user;
}
public BaseUser<?> getUser() {
return user;
}
public CosmeticItem getRemoved() {
return removed;
}
public void setRemoved(final CosmeticItem removed) {
this.removed = removed;
}
}

View File

@@ -0,0 +1,52 @@
package io.github.fisher2911.hmccosmetics.api.event;
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public abstract class CosmeticItemEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS = new HandlerList();
private CosmeticItem cosmeticItem;
private boolean cancelled;
public CosmeticItemEvent(final CosmeticItem cosmeticItem) {
this.cosmeticItem = cosmeticItem;
this.cancelled = false;
}
public CosmeticItemEvent(final boolean isAsync, final CosmeticItem cosmeticItem) {
super(isAsync);
this.cosmeticItem = cosmeticItem;
}
public static HandlerList getHandlerList() {
return HANDLERS;
}
public CosmeticItem getCosmeticItem() {
return this.cosmeticItem;
}
public void setCosmeticItem(final CosmeticItem cosmeticItem) {
this.cosmeticItem = cosmeticItem;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(final boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
}

View File

@@ -0,0 +1,469 @@
package io.github.fisher2911.hmccosmetics.command;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.CosmeticSettings;
import io.github.fisher2911.hmccosmetics.config.Settings;
import io.github.fisher2911.hmccosmetics.config.WardrobeSettings;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.CosmeticsMenu;
import io.github.fisher2911.hmccosmetics.gui.Token;
import io.github.fisher2911.hmccosmetics.hook.CitizensHook;
import io.github.fisher2911.hmccosmetics.hook.HookManager;
import io.github.fisher2911.hmccosmetics.message.Message;
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
import io.github.fisher2911.hmccosmetics.message.Messages;
import io.github.fisher2911.hmccosmetics.message.Placeholder;
import io.github.fisher2911.hmccosmetics.task.TaskChain;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import io.github.fisher2911.hmccosmetics.util.StringUtils;
import me.mattstudios.mf.annotations.Command;
import me.mattstudios.mf.annotations.Completion;
import me.mattstudios.mf.annotations.Default;
import me.mattstudios.mf.annotations.Permission;
import me.mattstudios.mf.annotations.SubCommand;
import me.mattstudios.mf.base.CommandBase;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
@Command("cosmetics")
public class CosmeticsCommand extends CommandBase {
private final HMCCosmetics plugin;
private final UserManager userManager;
private final MessageHandler messageHandler;
private final CosmeticsMenu cosmeticsMenu;
private final CosmeticManager cosmeticManager;
private final Settings settings;
private final CosmeticSettings cosmeticSettings;
public CosmeticsCommand(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
this.messageHandler = this.plugin.getMessageHandler();
this.cosmeticsMenu = this.plugin.getCosmeticsMenu();
this.cosmeticManager = this.plugin.getCosmeticManager();
this.settings = this.plugin.getSettings();
this.cosmeticSettings = this.settings.getCosmeticSettings();
}
@Default
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.DEFAULT_COMMAND)
public void defaultCommand(final Player player) {
this.defaultCommand(player, this.cosmeticSettings.getDefaultMenu());
}
@SubCommand("menu")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.DEFAULT_COMMAND)
public void defaultCommand(
final Player player,
@Completion("#menus") @me.mattstudios.mf.annotations.Optional String menu) {
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (menu == null) menu = this.cosmeticSettings.getDefaultMenu();
if (optionalUser.isEmpty()) {
this.cosmeticsMenu.openMenu(menu, player);
return;
}
final User user = optionalUser.get();
final Wardrobe wardrobe = user.getWardrobe();
if (wardrobe.isActive() &&
!this.settings.getWardrobeSettings().inDistanceOfWardrobe(wardrobe.getCurrentLocation(), player.getLocation())) {
wardrobe.setActive(false);
wardrobe.despawnFakePlayer(player, userManager);
this.messageHandler.sendMessage(
player,
Messages.CLOSED_WARDROBE
);
}
this.cosmeticsMenu.openMenu(menu, player);
}
@SubCommand("reload")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.RELOAD_COMMAND)
public void reloadCommand(final CommandSender sender) {
Bukkit.getScheduler().runTaskAsynchronously(
this.plugin,
() -> {
this.plugin.reload();
this.messageHandler.sendMessage(
sender,
Messages.RELOADED
);
}
);
}
@SubCommand("dye")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.DYE_COMMAND)
public void dyeArmor(
final Player player,
@Completion("#types") String typeString,
final @me.mattstudios.mf.annotations.Optional String dyeColor
) {
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) {
return;
}
try {
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeString.toUpperCase());
final User user = optionalUser.get();
if (dyeColor == null) {
this.cosmeticsMenu.openDyeSelectorGui(user, type);
return;
}
final ArmorItem armorItem = user.getPlayerArmor().getItem(type);
this.setDyeColor(dyeColor, armorItem, player);
this.userManager.setItem(user, armorItem, true);
this.messageHandler.sendMessage(
player,
Messages.SET_DYE_COLOR,
Map.of(Placeholder.ITEM, StringUtils.formatArmorItemType(typeString))
);
} catch (final IllegalArgumentException exception) {
this.messageHandler.sendMessage(
player,
Messages.INVALID_TYPE);
}
}
@SubCommand("help") // WORK IN PROGRESS (WIP)
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.HELP_COMMAND)
public void helpCommand(final CommandSender sender) {
this.messageHandler.sendMessage(
sender,
Messages.HELP_COMMAND
);
}
@SubCommand("add")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.SET_COSMETIC_COMMAND)
public void setCommand(
final CommandSender sender,
@Completion("#players") final Player player,
@Completion("#ids") final String id,
final @me.mattstudios.mf.annotations.Optional String dyeColor
) {
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
if (userOptional.isEmpty()) {
this.messageHandler.sendMessage(
sender,
Messages.INVALID_USER
);
return;
}
final User user = userOptional.get();
final ArmorItem armorItem = this.plugin.getCosmeticManager().getArmorItem(id);
if (armorItem == null) {
this.messageHandler.sendMessage(
sender,
Messages.ITEM_NOT_FOUND
);
return;
}
if (dyeColor != null) {
this.setDyeColor(dyeColor, armorItem, player);
}
final Message setMessage = Messages.getSetMessage(armorItem.getType());
final Message setOtherMessage = Messages.getSetOtherMessage(armorItem.getType());
this.userManager.setItem(user, armorItem, true);
this.messageHandler.sendMessage(
player,
setMessage
);
this.messageHandler.sendMessage(
sender,
setOtherMessage,
Map.of(Placeholder.PLAYER, player.getName(),
Placeholder.TYPE, id)
);
}
@SubCommand("remove")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.SET_COSMETIC_COMMAND)
public void removeCommand(
final CommandSender sender,
@Completion("#players") final Player player,
@Completion("#types") String typeString
) {
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
if (userOptional.isEmpty()) {
this.messageHandler.sendMessage(
sender,
Messages.INVALID_USER
);
return;
}
final User user = userOptional.get();
try {
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeString.toUpperCase());
final Message setOtherMessage = Messages.getSetOtherMessage(type);
this.userManager.removeItem(user, type, true);
this.messageHandler.sendMessage(
sender,
setOtherMessage,
Map.of(Placeholder.PLAYER, player.getName(),
Placeholder.TYPE, "none")
);
} catch (final IllegalArgumentException exception) {
this.messageHandler.sendMessage(player, Messages.INVALID_TYPE);
}
}
@SubCommand("wardrobe")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.WARDROBE)
public void openWardrobe(
CommandSender sender,
@me.mattstudios.mf.annotations.Optional final Player other
) {
Player player = null;
if (other != null) {
if (!sender.hasPermission(io.github.fisher2911.hmccosmetics.message.Permission.OPEN_OTHER_WARDROBE)) {
this.messageHandler.sendMessage(
sender,
Messages.NO_PERMISSION
);
return;
}
this.messageHandler.sendMessage(
sender,
Messages.OPENED_OTHER_WARDROBE,
Map.of(Placeholder.PLAYER, other.getName())
);
player = other;
} else if (!(sender instanceof final Player p)) {
this.messageHandler.sendMessage(
sender,
Messages.MUST_BE_PLAYER
);
return;
} else {
player = p;
}
final Optional<User> optionalUser = this.plugin.getUserManager().get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
final Wardrobe wardrobe = user.getWardrobe();
if (wardrobe.isActive()) {
this.messageHandler.sendMessage(
player,
Messages.WARDROBE_ALREADY_OPEN
);
return;
}
final WardrobeSettings settings = this.settings.getWardrobeSettings();
final boolean inDistanceOfStatic = settings.inDistanceOfStatic(player.getLocation());
if (!settings.isPortable() && !inDistanceOfStatic) {
this.messageHandler.sendMessage(
player,
Messages.NOT_NEAR_WARDROBE
);
return;
}
if (settings.isPortable() && !inDistanceOfStatic) {
if (!player.hasPermission(io.github.fisher2911.hmccosmetics.message.Permission.PORTABLE_WARDROBE)) {
this.messageHandler.sendMessage(
player,
Messages.CANNOT_USE_PORTABLE_WARDROBE
);
return;
}
wardrobe.setCurrentLocation(null);
}
settings.playOpenSound(player);
final Player finalPlayer = player;
new TaskChain(this.plugin).
chain(() -> wardrobe.spawnFakePlayer(finalPlayer), true).
chain(() -> {
// this.cosmeticsMenu.openDefault(finalPlayer);
this.messageHandler.sendMessage(
finalPlayer,
Messages.OPENED_WARDROBE
);
}).execute();
}
public static final String NPC_APPLY = "apply";
public static final String NPC_REMOVE = "remove";
@SubCommand("npc")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.SET_COSMETIC_COMMAND)
public void applyNpc(
final CommandSender sender,
@Completion("#npc-args") final String arg,
@Completion("#npcs") final Integer npcId,
@Completion("#types") final String typeStr,
@me.mattstudios.mf.annotations.Optional @Completion("#ids") final String itemId
) {
final CitizensHook citizensHook = HookManager.getInstance().getCitizensHook();
if (citizensHook == null) {
this.messageHandler.sendMessage(
sender,
Messages.HOOK_NOT_ENABLED,
Map.of(Placeholder.TYPE, "Citizens")
);
return;
}
if (npcId == null) {
this.messageHandler.sendMessage(
sender,
new Message("illegal-npc-id", "<red>" + "Invalid NPC id specified: " + npcId)
);
return;
}
final ArmorItem armorItem = this.plugin.getCosmeticManager().getArmorItem(itemId);
if (armorItem == null) {
this.messageHandler.sendMessage(
sender,
Messages.ITEM_NOT_FOUND
);
return;
}
switch (arg.toLowerCase(Locale.ROOT)) {
case NPC_APPLY -> {
this.setNpcCosmetic(citizensHook, sender, npcId, armorItem);
}
case NPC_REMOVE -> {
try {
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeStr);
this.setNpcCosmetic(citizensHook, sender, npcId, ArmorItem.empty(type, "none"));
} catch (final IllegalArgumentException exception) {
this.messageHandler.sendMessage(
sender,
Messages.INVALID_TYPE,
Map.of(Placeholder.TYPE, typeStr)
);
}
}
}
}
@SubCommand("hide")
public void hide(final Player player) {
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
if (user.isHidden()) {
user.setHidden(false);
this.messageHandler.sendMessage(
player,
Messages.SHOWN_COSMETICS
);
return;
}
user.setHidden(true);
this.messageHandler.sendMessage(
player,
Messages.HID_COSMETICS
);
}
@SubCommand("token")
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.GIVE_TOKEN)
public void token(
final CommandSender sender,
@Completion("#tokens") final String tokenId,
@Completion("#players") @me.mattstudios.mf.annotations.Optional Player giveTo) {
if (!(sender instanceof Player) && giveTo == null) {
this.messageHandler.sendMessage(
sender,
Messages.MUST_BE_PLAYER
);
return;
}
if (giveTo == null) {
giveTo = ((Player) sender);
}
final Token token = this.cosmeticManager.getToken(tokenId);
if (token == null) {
this.messageHandler.sendMessage(
sender,
Messages.ITEM_NOT_FOUND
);
return;
}
giveTo.getInventory().addItem(token.getItemStack().clone());
final String tokenName = token.getArmorItem().getName();
this.messageHandler.sendMessage(
sender,
Messages.GAVE_TOKEN,
Map.of(Placeholder.ID, tokenName,
Placeholder.PLAYER, giveTo.getDisplayName())
);
this.messageHandler.sendMessage(
giveTo,
Messages.RECEIVED_TOKEN,
Map.of(Placeholder.ID, tokenName)
);
}
private void setNpcCosmetic(final CitizensHook hook, final CommandSender sender, final int npcId, final ArmorItem item) {
final boolean isSet = hook.setNpcCosmetic(npcId, item);
if (!isSet) {
this.messageHandler.sendMessage(
sender,
Messages.NPC_NOT_FOUND,
Map.of(Placeholder.ID, String.valueOf(npcId))
);
return;
}
this.messageHandler.sendMessage(
sender,
Messages.SET_NPC_COSMETIC,
Map.of(Placeholder.TYPE, item.getType().toString(),
Placeholder.ITEM, item.getId(),
Placeholder.ID, String.valueOf(npcId))
);
}
private void setDyeColor(final String dyeColor, final ArmorItem armorItem, final CommandSender sender) {
try {
final java.awt.Color awtColor = java.awt.Color.decode(dyeColor);
Color color = Color.fromRGB(awtColor.getRed(), awtColor.getGreen(), awtColor.getBlue());
armorItem.setDye(color.asRGB());
} catch (final NumberFormatException exception) {
this.messageHandler.sendMessage(
sender,
Messages.INVALID_COLOR,
Map.of(Placeholder.ITEM, dyeColor)
);
}
}
}

View File

@@ -0,0 +1,32 @@
package io.github.fisher2911.hmccosmetics.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Threads {
private static final Threads INSTANCE;
static {
INSTANCE = new Threads();
}
private final ExecutorService service;
private Threads() {
this.service = Executors.newFixedThreadPool(1);
}
public static Threads getInstance() {
return INSTANCE;
}
public void execute(final Runnable runnable) {
this.service.execute(runnable);
}
public void onDisable() {
this.service.shutdownNow().forEach(Runnable::run);
}
}

View File

@@ -0,0 +1,292 @@
package io.github.fisher2911.hmccosmetics.config;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.CosmeticGui;
import io.github.fisher2911.hmccosmetics.message.Message;
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
import io.github.fisher2911.hmccosmetics.message.Placeholder;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import io.github.fisher2911.hmccosmetics.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurateException;
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.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class ActionSerializer implements TypeSerializer<List<CosmeticGuiAction>> {
public static final ActionSerializer INSTANCE = new ActionSerializer();
private static final HMCCosmetics plugin;
private static final String OPEN_MENU = "open-menu";
private static final String CLOSE_MENU = "close-menu";
private static final String SET_ITEMS = "set-items";
private static final String REMOVE_COSMETICS = "remove-cosmetics";
private static final String SET_COSMETICS = "set-cosmetics";
private static final String SEND_MESSAGE = "send-message";
private static final String SEND_MESSAGES = "send-messages";
private static final String SEND_COMMAND = "send-command";
private static final String SEND_COMMANDS = "send-commands";
private static final String SOUND = "sound";
static {
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
}
private ActionSerializer() {
}
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
throws SerializationException {
if (!source.hasChild(path)) {
throw new SerializationException(
"Required field " + Arrays.toString(path) + " was not present in node");
}
return source.node(path);
}
@Override
public List<CosmeticGuiAction> deserialize(final Type type, final ConfigurationNode source) {
return this.deserialize(type, new ArrayList<>(), source, CosmeticGuiAction.When.ALL);
}
private List<CosmeticGuiAction> deserialize(
final Type type,
final List<CosmeticGuiAction> consumers,
final ConfigurationNode source,
final CosmeticGuiAction.When when) {
final var children = source.childrenMap();
for (final var entry : children.entrySet()) {
final String clickType = entry.getKey().toString();
try {
final CosmeticGuiAction.When nextWhen = CosmeticGuiAction.When.valueOf(clickType.toUpperCase());
this.deserialize(type, consumers, entry.getValue(), nextWhen);
} catch (final IllegalArgumentException exception) {
consumers.add(this.parseAction(entry.getValue(), clickType.toUpperCase(Locale.ROOT), when));
}
}
return consumers;
}
private CosmeticGuiAction parseAction(
final ConfigurationNode node,
final String clickType,
final CosmeticGuiAction.When when
) {
final ConfigurationNode openMenuNode = node.node(OPEN_MENU);
final ConfigurationNode setItemsNode = node.node(SET_ITEMS);
final ConfigurationNode removeItemsNode = node.node(REMOVE_COSMETICS);
final ConfigurationNode setCosmeticsNode = node.node(SET_COSMETICS);
final ConfigurationNode soundNode = node.node(SOUND);
final boolean closeMenu = node.node(CLOSE_MENU).getBoolean(false);
final String openMenu = openMenuNode.getString();
final List<ArmorItem.Type> removeCosmeticTypes = this.loadRemoveTypes(removeItemsNode);
final int totalRemoveCosmetics = removeCosmeticTypes.size();
final List<String> setCosmetics = this.loadSetCosmetics(setCosmeticsNode);
final int totalSetCosmetics = setCosmetics.size();
final ClickType click = Utils.stringToEnum(clickType, ClickType.class, ClickType.UNKNOWN);
final Map<Integer, GuiItem> setItems = this.loadSetItems(setItemsNode);
final Consumer<Player> messageConsumer = this.loadMessages(node, plugin);
final SoundData soundData = this.loadSoundData(soundNode);
return new CosmeticGuiAction(
when,
event -> {
if (click != ClickType.UNKNOWN && event.getClick() != click) return;
if (!(event.getWhoClicked() instanceof final Player player)) return;
if (soundData != null) {
soundData.play(player);
}
if (openMenu != null) plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
messageConsumer.accept(player);
final UserManager userManager = plugin.getUserManager();
final Optional<User> optionalUser = userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
final CosmeticManager cosmeticManager = plugin.getCosmeticManager();
int index = 0;
for (final String id : setCosmetics) {
index++;
final boolean sendPacket = index == totalSetCosmetics ;
final ArmorItem armorItem = cosmeticManager.getArmorItem(id);
if (armorItem == null) continue;
userManager.setItem(user, armorItem, sendPacket);
}
index = 0;
for (final ArmorItem.Type type : removeCosmeticTypes) {
index++;
final boolean sendPacket = index == totalSetCosmetics ;
userManager.removeItem(user, type, sendPacket);
}
final CosmeticGui gui = user.getOpenGui();
if (gui != null) {
for (final var entry : setItems.entrySet()) {
final GuiItem item = entry.getValue();
gui.updateItem(entry.getKey(), item, user, player);
}
}
if (closeMenu) player.closeInventory();
}
);
}
private Map<Integer, GuiItem> loadSetItems(final ConfigurationNode node) {
if (node.virtual()) return Collections.emptyMap();
final Map<Integer, GuiItem> setItems = new HashMap<>();
try {
for (final var entry : node.childrenMap().entrySet()) {
if (!(entry.getKey() instanceof final Integer slot)) continue;
final var key = entry.getValue();
final GuiItem guiItem = ArmorItemSerializer.INSTANCE.deserialize(GuiItem.class, key);
if (guiItem == null) continue;
setItems.put(slot, guiItem);
}
} catch (final SerializationException exception) {
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().severe(
"Error loading set-items"
);
return Collections.emptyMap();
}
return setItems;
}
private static final String CONSOLE = "console";
private static final String PLAYER = "player";
private Consumer<Player> loadMessages(final ConfigurationNode source, final HMCCosmetics plugin) {
final ConfigurationNode messageNode = source.node(SEND_MESSAGE);
final ConfigurationNode messagesNode = source.node(SEND_MESSAGES);
final ConfigurationNode commandNode = source.node(SEND_COMMAND);
final ConfigurationNode commandsNode = source.node(SEND_COMMANDS);
final List<String> messages = new ArrayList<>();
final List<String> commands = new ArrayList<>();
final String message = messageNode.getString();
if (message != null) messages.add(message);
final String command = commandNode.getString();
if (command != null) commands.add(command);
for (final var node : messagesNode.childrenList()) {
final String listMessage = node.getString();
if (listMessage == null) continue;
messages.add(listMessage);
}
for (final var node : commandsNode.childrenList()) {
final String commandMessage = node.getString();
if (commandMessage == null) continue;
commands.add(commandMessage);
}
return player -> {
final String playerName = player.getName();
final Map<String, String> placeholders = Map.of(Placeholder.PLAYER, playerName);
final MessageHandler messageHandler = plugin.getMessageHandler();
for (final String sendMessage : messages) {
messageHandler.sendMessage(
player,
new Message("", sendMessage),
placeholders
);
}
for (final String sendCommand : commands) {
final String[] parts = sendCommand.split(":");
if (parts.length < 2) {
Bukkit.dispatchCommand(
Bukkit.getConsoleSender(),
sendCommand.replace(Placeholder.PLAYER, playerName)
);
continue;
}
final String sender = parts[0];
final String commandToSend = parts[1];
if (sender.equalsIgnoreCase(CONSOLE)) {
Bukkit.dispatchCommand(
Bukkit.getConsoleSender(),
commandToSend.replace(Placeholder.PLAYER, playerName)
);
continue;
}
player.chat("/" + commandToSend.replace(Placeholder.PLAYER, playerName));
}
};
}
private List<ArmorItem.Type> loadRemoveTypes(final ConfigurationNode node) {
try {
final List<String> typeStrings = node.getList(String.class);
if (typeStrings == null) return new ArrayList<>();
return typeStrings.stream().map(
string -> {
try {
return ArmorItem.Type.valueOf(string.toUpperCase(Locale.ROOT));
} catch (final IllegalArgumentException exception) {
plugin.getLogger().severe(string + " is not a valid cosmetic type.");
}
return null;
}
).
filter(type -> type != null).
collect(Collectors.toList());
} catch (final SerializationException exception) {
exception.printStackTrace();
}
return new ArrayList<>();
}
private SoundData loadSoundData(final ConfigurationNode node) {
try {
return SoundSerializer.INSTANCE.deserialize(SoundData.class, node);
} catch (final ConfigurateException exception) {
return null;
}
}
private List<String> loadSetCosmetics(final ConfigurationNode node) {
try {
return node.getList(String.class);
} catch (final ConfigurateException exception) {
return new ArrayList<>();
}
}
@Override
public void serialize(final Type type, @Nullable final List<CosmeticGuiAction> obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,150 @@
package io.github.fisher2911.hmccosmetics.config;
import dev.triumphteam.gui.components.GuiAction;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.BalloonItem;
import io.github.fisher2911.hmccosmetics.gui.WrappedGuiItem;
import io.github.fisher2911.hmccosmetics.util.StringUtils;
import io.github.fisher2911.hmccosmetics.util.Utils;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
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.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class ArmorItemSerializer implements TypeSerializer<WrappedGuiItem> {
public static final ArmorItemSerializer INSTANCE = new ArmorItemSerializer();
private ArmorItemSerializer() {
}
private static final String NAME = "name";
private static final String LOCKED_LORE = "locked-lore";
private static final String APPLIED_LORE = "applied-lore";
private static final String LOCKED_ITEM = "locked-item";
private static final String APPLIED_ITEM = "applied-item";
private static final String PERMISSION = "permission";
private static final String TYPE = "type";
private static final String ACTION = "action";
private static final String ID = "id";
private static final String DYEABLE = "dyeable";
private static final String BALLOON_MODEL_ID = "balloon";
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
throws SerializationException {
if (!source.hasChild(path)) {
throw new SerializationException(
"Required field " + Arrays.toString(path) + " was not present in node");
}
return source.node(path);
}
@Override
public WrappedGuiItem deserialize(final Type type, final ConfigurationNode source)
throws SerializationException {
final ConfigurationNode nameNode = source.node(NAME);
final ConfigurationNode lockedLoreNode = source.node(LOCKED_LORE);
final ConfigurationNode appliedLoreNode = source.node(APPLIED_LORE);
final ConfigurationNode lockedItemNode = source.node(LOCKED_ITEM);
final ConfigurationNode appliedItemNode = source.node(APPLIED_ITEM);
final ConfigurationNode permissionNode = source.node(PERMISSION);
final ConfigurationNode typeNode = source.node(TYPE);
final ConfigurationNode actionNode = source.node(ACTION);
final ConfigurationNode idNode = source.node(ID);
final ConfigurationNode dyeableNode = source.node(DYEABLE);
final ConfigurationNode balloonModelIdNode = source.node(BALLOON_MODEL_ID);
final ItemStack itemStack = Utils.replaceIfNull(
ItemSerializer.INSTANCE.deserialize(ItemStack.class, source),
new ItemStack(Material.AIR)
);
ItemStack lockedItem = ItemSerializer.INSTANCE.deserialize(ItemStack.class, lockedItemNode);
if (lockedItem == null) {
final List<String> lockedLore = Utils.replaceIfNull(lockedLoreNode.getList(String.class),
new ArrayList<String>()).
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
lockedItem = ItemBuilder.from(itemStack.clone()).lore(lockedLore).build();
}
ItemStack appliedItem = ItemSerializer.INSTANCE.deserialize(ItemStack.class, appliedItemNode);
if (appliedItem == null) {
final List<String> appliedLore = Utils.replaceIfNull(appliedLoreNode.getList(String.class),
new ArrayList<String>()).
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
appliedItem = ItemBuilder.from(itemStack.clone()).lore(appliedLore).build();
}
final boolean dyeable = dyeableNode.getBoolean();
final List<CosmeticGuiAction> actions = ActionSerializer.INSTANCE.deserialize(GuiAction.class, actionNode);
try {
final ArmorItem.Type cosmeticType = ArmorItem.Type.valueOf(
Utils.replaceIfNull(
typeNode.getString(), ""
).toUpperCase(Locale.ROOT)
);
final String permission = permissionNode.getString();
if (cosmeticType == ArmorItem.Type.BALLOON) {
return new BalloonItem(
itemStack,
actions,
Utils.replaceIfNull(nameNode.getString(), ""),
Utils.replaceIfNull(idNode.getString(), ""),
lockedItem,
appliedItem,
permission,
cosmeticType,
dyeable,
-1,
balloonModelIdNode.getString()
);
}
return new ArmorItem(
itemStack,
actions,
Utils.replaceIfNull(nameNode.getString(), ""),
Utils.replaceIfNull(idNode.getString(), ""),
lockedItem,
appliedItem,
permission,
cosmeticType,
dyeable,
-1
);
} catch (final IllegalArgumentException exception) {
final GuiItem guiItem = dev.triumphteam.gui.builder.item.ItemBuilder.from(itemStack).asGuiItem();
final GuiAction<InventoryClickEvent> guiAction = event -> {
for (final CosmeticGuiAction action : actions) {
action.execute(event, CosmeticGuiAction.When.ALL);
}
};
guiItem.setAction(guiAction);
return new WrappedGuiItem(guiItem, guiAction);
}
}
@Override
public void serialize(final Type type, @Nullable final WrappedGuiItem obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,28 @@
package io.github.fisher2911.hmccosmetics.config;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Consumer;
public class CosmeticGuiAction {
private final When when;
private final Consumer<InventoryClickEvent> consumer;
public CosmeticGuiAction(final When when, final Consumer<InventoryClickEvent> consumer) {
this.when = when;
this.consumer = consumer;
}
public void execute(final InventoryClickEvent event, final When when) {
if (this.when != When.ALL && this.when != when) return;
consumer.accept(event);
}
public enum When {
EQUIP,
REMOVE,
ALL
}
}

View File

@@ -0,0 +1,147 @@
package io.github.fisher2911.hmccosmetics.config;
import io.github.fisher2911.hmccosmetics.gui.CosmeticsMenu;
import io.github.fisher2911.hmccosmetics.util.Utils;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.util.Vector;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import java.util.Objects;
@ConfigSerializable
public class CosmeticSettings {
private static final String DEFAULT_MENU = "default-menu";
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 String defaultMenu;
private boolean requireEmptyHelmet;
private boolean requireEmptyOffHand;
private boolean requireEmptyChestPlate;
private boolean requireEmptyPants;
private boolean requireEmptyBoots;
private int lookDownPitch;
private int viewDistance;
private Vector balloonOffset;
private boolean firstPersonBackpackMode;
private int particleCount;
public void load(final FileConfiguration config) {
this.particleCount = config.getInt(PARTICLE_COUNT, 1);
this.defaultMenu = Utils.replaceIf(config.getString(DEFAULT_MENU), CosmeticsMenu.DEFAULT_MAIN_MENU, null, "");
this.requireEmptyHelmet = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_HELMET_PATH);
this.requireEmptyOffHand = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_OFF_HAND_PATH);
this.requireEmptyChestPlate = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_CHEST_PLATE_PATH);
this.requireEmptyPants = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_PANTS_PATH);
this.requireEmptyBoots = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_BOOTS_PATH);
this.lookDownPitch = config.getInt(COSMETIC_SETTINGS_PATH + "." + LOOK_DOWN_PITCH_PATH);
this.viewDistance = config.getInt(COSMETIC_SETTINGS_PATH + "." + VIEW_DISTANCE_PATH);
this.firstPersonBackpackMode = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + FIRST_PERSON_BACKPACK_MODE, false);
final var balloonSection = config.getConfigurationSection(COSMETIC_SETTINGS_PATH + "." + BALLOON_OFFSET);
if (balloonSection != null) {
this.balloonOffset = loadVector(balloonSection);
}
}
public int getParticleCount() {
return particleCount;
}
private Vector loadVector(final ConfigurationSection section) {
return new Vector(section.getDouble("x"), section.getDouble("y"), section.getDouble("z"));
}
public boolean isRequireEmptyHelmet() {
return requireEmptyHelmet;
}
public void setRequireEmptyHelmet(final boolean requireEmptyHelmet) {
this.requireEmptyHelmet = requireEmptyHelmet;
}
public boolean isRequireEmptyOffHand() {
return requireEmptyOffHand;
}
public void setRequireEmptyOffHand(final boolean requireEmptyOffHand) {
this.requireEmptyOffHand = requireEmptyOffHand;
}
public boolean isRequireEmptyChestPlate() {
return requireEmptyChestPlate;
}
public void setRequireEmptyChestPlate(final boolean requireEmptyChestPlate) {
this.requireEmptyChestPlate = requireEmptyChestPlate;
}
public boolean isRequireEmptyPants() {
return requireEmptyPants;
}
public void setRequireEmptyPants(final boolean requireEmptyPants) {
this.requireEmptyPants = requireEmptyPants;
}
public boolean isRequireEmptyBoots() {
return requireEmptyBoots;
}
public void setRequireEmptyBoots(final boolean requireEmptyBoots) {
this.requireEmptyBoots = requireEmptyBoots;
}
public Vector getBalloonOffset() {
return balloonOffset;
}
public int getLookDownPitch() {
return lookDownPitch;
}
public int getViewDistance() {
return viewDistance;
}
public String getDefaultMenu() {
return defaultMenu;
}
public boolean isFirstPersonBackpackMode() {
return firstPersonBackpackMode;
}
public boolean requireEmpty(final EquipmentSlot slot) {
return switch (slot) {
case OFF_HAND -> this.isRequireEmptyOffHand();
case HEAD -> this.isRequireEmptyHelmet();
case CHEST -> this.isRequireEmptyChestPlate();
case LEGS -> this.isRequireEmptyPants();
case FEET -> this.isRequireEmptyBoots();
default -> false;
};
}
public boolean isInViewDistance(final Location location, final Location other) {
if (!Objects.equals(other.getWorld(), location.getWorld())) return false;
return !(other.distanceSquared(location) > this.getViewDistance() * this.getViewDistance());
}
}

View File

@@ -1,10 +1,13 @@
package io.github.fisher2911.hmccosmetics.config;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.ColorItem;
import io.github.fisher2911.hmccosmetics.gui.DyeSelectorGui;
import io.github.fisher2911.hmccosmetics.message.Adventure;
import io.github.fisher2911.hmccosmetics.gui.WrappedGuiItem;
import org.bukkit.Color;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
@@ -13,56 +16,59 @@ import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class DyeGuiSerializer implements TypeSerializer<DyeSelectorGui> {
private static final HMCCosmetics plugin;
static {
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
}
public static final DyeGuiSerializer INSTANCE = new DyeGuiSerializer();
private DyeGuiSerializer() {}
private static final HMCCosmetics plugin;
private static final String TITLE = "title";
private static final String ROWS = "rows";
private static final String ITEMS = "items";
private static final String COSMETICS_SLOTS = "cosmetics-slots";
private static final String SET_COLOR = "set-color";
private static final String RED = "red";
private static final String GREEN = "green";
private static final String BLUE = "blue";
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
static {
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
}
private DyeGuiSerializer() {
}
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
throws SerializationException {
if (!source.hasChild(path)) {
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
throw new SerializationException(
"Required field " + Arrays.toString(path) + " was not present in node");
}
return source.node(path);
}
@Override
public DyeSelectorGui deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
public DyeSelectorGui deserialize(final Type type, final ConfigurationNode source)
throws SerializationException {
final ConfigurationNode titleNode = this.nonVirtualNode(source, TITLE);
final ConfigurationNode rowsNode = this.nonVirtualNode(source, ROWS);
final ConfigurationNode itemsNode = source.node(ITEMS);
final ConfigurationNode cosmeticSlotsNode = source.node(COSMETICS_SLOTS);
final Map<Integer, GuiItem> guiItemMap = new HashMap<>();
final var map = itemsNode.childrenMap();
final var itemMap = itemsNode.childrenMap();
final var cosmeticSlotsMap = cosmeticSlotsNode.childrenMap();
for (final var entry : map.entrySet()) {
for (final var entry : itemMap.entrySet()) {
if (!(entry.getKey() instanceof final Integer slot)) {
continue;
}
final var node = entry.getValue();
final GuiItem guiItem = ItemSerializer.INSTANCE.deserialize(
final WrappedGuiItem guiItem = ArmorItemSerializer.INSTANCE.deserialize(
GuiItem.class,
node
);
@@ -78,19 +84,50 @@ public class DyeGuiSerializer implements TypeSerializer<DyeSelectorGui> {
final int green = colorNode.node(GREEN).getInt();
final int blue = colorNode.node(BLUE).getInt();
guiItemMap.put(slot, new ColorItem(guiItem.getItemStack(), Color.fromRGB(red, green, blue)));
guiItemMap.put(slot,
new ColorItem(guiItem.getItemStack(), guiItem.getAction(), Color.fromRGB(red, green, blue))
);
}
final BiMap<Integer, ArmorItem.Type> cosmeticSlots = HashBiMap.create();
int selectedCosmetic = -1;
for (final var entry : cosmeticSlotsMap.entrySet()) {
if (!(entry.getKey() instanceof final Integer slot)) {
continue;
}
selectedCosmetic = selectedCosmetic == -1 ? slot : selectedCosmetic;
final var node = entry.getValue();
final String typeStr = node.getString();
try {
final ArmorItem.Type itemType = ArmorItem.Type.valueOf(typeStr);
cosmeticSlots.put(slot, itemType);
} catch (final IllegalArgumentException | NullPointerException exception) {
plugin.getLogger().severe(typeStr + " is not a valid ArmorItem type in DyeGui!");
}
}
String title = titleNode.getString();
if (title == null) {
title = "";
}
return new DyeSelectorGui(
plugin,
Adventure.SERIALIZER.serialize(
Adventure.MINI_MESSAGE.parse(titleNode.getString())),
title,
rowsNode.getInt(),
guiItemMap);
guiItemMap,
cosmeticSlots,
selectedCosmetic);
}
@Override
public void serialize(final Type type, @Nullable final DyeSelectorGui obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -3,7 +3,6 @@ package io.github.fisher2911.hmccosmetics.config;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.CosmeticGui;
import io.github.fisher2911.hmccosmetics.message.Adventure;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
@@ -16,43 +15,42 @@ import java.util.Map;
public class GuiSerializer implements TypeSerializer<CosmeticGui> {
public static final GuiSerializer INSTANCE = new GuiSerializer();
private static final HMCCosmetics plugin;
private static final String TITLE = "title";
private static final String ROWS = "rows";
private static final String ITEMS = "items";
static {
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
}
public static final GuiSerializer INSTANCE = new GuiSerializer();
private GuiSerializer() {
}
private GuiSerializer() {}
private static final String TITLE = "title";
private static final String ROWS = "rows";
private static final String ITEMS = "items";
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
throws SerializationException {
if (!source.hasChild(path)) {
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
throw new SerializationException(
"Required field " + Arrays.toString(path) + " was not present in node");
}
return source.node(path);
}
@Override
public CosmeticGui deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
public CosmeticGui deserialize(final Type type, final ConfigurationNode source)
throws SerializationException {
final ConfigurationNode titleNode = this.nonVirtualNode(source, TITLE);
final ConfigurationNode rowsNode = this.nonVirtualNode(source, ROWS);
final ConfigurationNode itemsNode = source.node(ITEMS);
final var childrenMap = source.node(ITEMS).childrenMap();
final var childrenMap = itemsNode.childrenMap();
final Map<Integer, GuiItem> guiItemMap = new HashMap<>();
for (final var entry : childrenMap.entrySet()) {
if (!(entry.getKey() instanceof final Integer slot)) {
continue;
}
final GuiItem guiItem = ItemSerializer.INSTANCE.deserialize(
if (!(entry.getKey() instanceof final Integer slot)) continue;
final GuiItem guiItem = ArmorItemSerializer.INSTANCE.deserialize(
GuiItem.class,
entry.getValue()
);
@@ -60,9 +58,14 @@ public class GuiSerializer implements TypeSerializer<CosmeticGui> {
guiItemMap.put(slot, guiItem);
}
String title = titleNode.getString();
if (title == null) {
title = "";
}
return new CosmeticGui(plugin,
Adventure.SERIALIZER.serialize(
Adventure.MINI_MESSAGE.parse(titleNode.getString())),
title,
rowsNode.getInt(),
guiItemMap);
}
@@ -71,4 +74,5 @@ public class GuiSerializer implements TypeSerializer<CosmeticGui> {
public void serialize(final Type type, @Nullable final CosmeticGui obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -1,16 +1,12 @@
package io.github.fisher2911.hmccosmetics.config;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.message.Adventure;
import io.github.fisher2911.hmccosmetics.hook.HookManager;
import io.github.fisher2911.hmccosmetics.util.Keys;
import io.github.fisher2911.hmccosmetics.util.StringUtils;
import io.github.fisher2911.hmccosmetics.util.Utils;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import io.github.fisher2911.hmccosmetics.util.builder.ColorBuilder;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import io.github.fisher2911.hmccosmetics.util.builder.SkullBuilder;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
@@ -27,24 +23,20 @@ import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class ItemSerializer implements TypeSerializer<GuiItem> {
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 LOCKED_LORE = "locked-lore";
private static final String MODEL_DATA = "model-data";
private static final String ENCHANTS = "enchants";
private static final String ITEM_FLAGS = "item-flags";
@@ -54,32 +46,19 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
private static final String RED = "red";
private static final String GREEN = "green";
private static final String BLUE = "blue";
private static final String PERMISSION = "permission";
private static final String TYPE = "type";
private static final String OPEN_MENU = "open-menu";
private static final String ID = "id";
private static final String DYEABLE = "dyeable";
private ItemSerializer() {
}
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
if (!source.hasChild(path)) {
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
}
return source.node(path);
}
@Override
public GuiItem deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
final ConfigurationNode materialNode = this.nonVirtualNode(source, MATERIAL);
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 lockedLoreNode = source.node(LOCKED_LORE);
final ConfigurationNode modelDataNode = source.node(MODEL_DATA);
final ConfigurationNode enchantsNode = source.node(ENCHANTS);
final ConfigurationNode itemFlagsNode = source.node(ITEM_FLAGS);
@@ -89,33 +68,34 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
final ConfigurationNode redNode = colorNode.node(RED);
final ConfigurationNode greenNode = colorNode.node(GREEN);
final ConfigurationNode blueNode = colorNode.node(BLUE);
final ConfigurationNode permissionNode = source.node(PERMISSION);
final ConfigurationNode typeNode = source.node(TYPE);
final ConfigurationNode openMenuNode = source.node(OPEN_MENU);
final ConfigurationNode idNode = source.node(ID);
final ConfigurationNode dyeableNode = source.node(DYEABLE);
final Material material = Utils.stringToEnum(Utils.replaceIfNull(materialNode.getString(), ""),
Material.class, Material.AIR);
final String materialString = Utils.replaceIfNull(materialNode.getString(), "");
final int amount = amountNode.getInt();
final Component name = StringUtils.parse(nameNode.getString());
// Adventure.MINI_MESSAGE.parse(
// Utils.replaceIfNull(nameNode.getString(), "")
// );
ItemStack itemStack;
try {
itemStack = new ItemStack(Material.valueOf(materialString.toUpperCase()), amount);
} catch (final IllegalArgumentException exception) {
itemStack = HookManager.getInstance().getItemHooks().getItemStack(materialString);
if (itemStack == null) {
return null;
}
}
final String name = StringUtils.parseStringToString(Utils.replaceIfNull(nameNode.getString(), ""));
final boolean unbreakable = unbreakableNode.getBoolean();
final boolean glowing = glowingNode.getBoolean();
final List<String> lore = Utils.replaceIfNull(loreNode.getList(String.class), new ArrayList<String>()).
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
final List<String> lockedLore = Utils.replaceIfNull(lockedLoreNode.getList(String.class), new ArrayList<String>()).
final List<String> lore = Utils.replaceIfNull(loreNode.getList(String.class),
new ArrayList<String>()).
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
final int modelData = modelDataNode.getInt();
final Set<ItemFlag> itemFlags = Utils.replaceIfNull(itemFlagsNode.getList(String.class), new ArrayList<String>()).
final Set<ItemFlag> itemFlags = Utils.replaceIfNull(itemFlagsNode.getList(String.class),
new ArrayList<String>()).
stream().map(flag -> {
try {
return ItemFlag.valueOf(flag.toUpperCase());
@@ -126,14 +106,12 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
final String texture = textureNode.getString();
final String owner = ownerNode.getString();
final boolean dyeable = dyeableNode.getBoolean();
final Color color;
if (colorNode.virtual()) {
color = null;
} else {
color = Color.fromBGR(redNode.getInt(), greenNode.getInt(), blueNode.getInt());
color = Color.fromRGB(redNode.getInt(), greenNode.getInt(), blueNode.getInt());
}
final Map<Enchantment, Integer> enchantments =
@@ -146,9 +124,10 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
return null;
}
final NamespacedKey namespacedKey = NamespacedKey.minecraft(enchantmentString.
split(":")[0].
toLowerCase());
final NamespacedKey namespacedKey = NamespacedKey.minecraft(
enchantmentString.
split(":")[0].
toLowerCase());
return Registry.ENCHANTMENT.get(namespacedKey);
}, enchantmentString -> {
@@ -162,12 +141,10 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
}
}));
final ItemBuilder itemBuilder;
if (material == Material.PLAYER_HEAD) {
itemBuilder = SkullBuilder.
create();
if (itemStack.getType() == Material.PLAYER_HEAD) {
itemBuilder = SkullBuilder.create();
if (texture != null) {
((SkullBuilder) itemBuilder).texture(texture);
@@ -175,64 +152,38 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
final OfflinePlayer player = Bukkit.getOfflinePlayer(owner);
((SkullBuilder) itemBuilder).owner(player);
}
} else if (ColorBuilder.canBeColored(material)) {
itemBuilder = ColorBuilder.from(material);
} else if (ColorBuilder.canBeColored(itemStack)) {
itemBuilder = ColorBuilder.from(itemStack);
if (color != null) {
((ColorBuilder) itemBuilder).color(color);
}
} else {
itemBuilder = ItemBuilder.from(material);
itemBuilder = ItemBuilder.from(itemStack);
}
final ItemStack itemStack = itemBuilder.
if (itemStack.getItemMeta() != null && !itemStack.getItemMeta().hasCustomModelData()) {
itemBuilder.modelData(modelData);
}
if (!lore.isEmpty()) itemBuilder.lore(lore);
if (!name.isBlank()) itemBuilder.name(name);
itemStack = itemBuilder.
amount(amount).
name(name).
unbreakable(unbreakable).
glow(glowing).
lore(lore).
modelData(modelData).
enchants(enchantments, true).
itemFlags(itemFlags).
build();
final String openMenu = openMenuNode.getString(
Utils.replaceIfNull(OPEN_MENU, ""));
Keys.setKey(itemStack);
try {
final ArmorItem.Type cosmeticType = ArmorItem.Type.valueOf(
Utils.replaceIfNull(
typeNode.getString(), ""
).toUpperCase(Locale.ROOT)
);
final String permission = permissionNode.getString();
return new ArmorItem(
itemStack,
event -> {
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
},
Utils.replaceIfNull(idNode.getString(), ""),
lockedLore,
permission,
cosmeticType,
dyeable);
} catch (final IllegalArgumentException exception) {
return dev.triumphteam.gui.builder.item.ItemBuilder.from(
itemStack).
asGuiItem(event -> {
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
});
}
return itemStack;
}
@Override
public void serialize(final Type type, @Nullable final GuiItem obj, final ConfigurationNode node) throws SerializationException {
public void serialize(final Type type, @Nullable final ItemStack obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,46 @@
package io.github.fisher2911.hmccosmetics.config;
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 obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,31 @@
package io.github.fisher2911.hmccosmetics.config;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
public class Settings {
private final HMCCosmetics plugin;
private final CosmeticSettings cosmeticSettings;
private final WardrobeSettings wardrobeSettings;
public Settings(final HMCCosmetics plugin) {
this.plugin = plugin;
this.cosmeticSettings = new CosmeticSettings();
this.wardrobeSettings = new WardrobeSettings(this.plugin);
}
public void load() {
this.plugin.saveDefaultConfig();
this.plugin.reloadConfig();
this.cosmeticSettings.load(this.plugin.getConfig());
this.wardrobeSettings.load();
}
public CosmeticSettings getCosmeticSettings() {
return cosmeticSettings;
}
public WardrobeSettings getWardrobeSettings() {
return wardrobeSettings;
}
}

View File

@@ -0,0 +1,60 @@
package io.github.fisher2911.hmccosmetics.config;
import com.comphenix.protocol.wrappers.EnumWrappers;
import net.minecraft.server.v1_16_R3.MinecraftKey;
import org.bukkit.entity.Player;
public class SoundData {
private final String name;
private final EnumWrappers.SoundCategory soundCategory;
private final float volume;
private final float pitch;
public SoundData(final String name, final EnumWrappers.SoundCategory soundCategory, final float volume, final float pitch) {
this.name = name;
this.soundCategory = soundCategory;
this.volume = volume;
this.pitch = pitch;
}
public String getName() {
return name;
}
public float getVolume() {
return volume;
}
public float getPitch() {
return pitch;
}
public EnumWrappers.SoundCategory getSoundCategory() {
return soundCategory;
}
public void play(final Player player) {
// todo - once packetevents updates
// final PacketContainer soundPacket = PacketManager.getSoundPacket(
// player,
// player.getLocation(),
// this.getKey(this.name),
// this.volume,
// this.pitch,
// this.soundCategory
// );
//
// PacketManager.sendPacket(player, soundPacket);
}
private MinecraftKey getKey(final String string) {
if (!string.contains(":")) {
return new MinecraftKey(string);
}
final String[] parts = string.split(":");
return new MinecraftKey(parts[0], parts[1]);
}
}

View File

@@ -0,0 +1,53 @@
package io.github.fisher2911.hmccosmetics.config;
import com.comphenix.protocol.wrappers.EnumWrappers;
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 SoundSerializer implements TypeSerializer<SoundData> {
public static final SoundSerializer INSTANCE = new SoundSerializer();
private SoundSerializer() {}
private static final String SOUND_NAME = "name";
private static final String SOUND_VOLUME = "volume";
private static final String SOUND_PITCH = "pitch";
private static final String SOUND_CATEGORY = "category";
@Override
public SoundData deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
final ConfigurationNode soundNameNode = node.node(SOUND_NAME);
final ConfigurationNode volumeNode = node.node(SOUND_VOLUME);
final ConfigurationNode pitchNode = node.node(SOUND_PITCH);
final ConfigurationNode categoryNode = node.node(SOUND_CATEGORY);
final SoundData soundData;
final String soundName = soundNameNode.getString();
final String category = categoryNode.getString();
final int volume = volumeNode.getInt();
final int pitch = pitchNode.getInt();
if (soundName == null || category == null) {
soundData = null;
} else {
soundData = new SoundData(
soundName,
EnumWrappers.SoundCategory.valueOf(category),
volume,
pitch
);
}
return soundData;
}
@Override
public void serialize(final Type type, @Nullable final SoundData obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,37 @@
package io.github.fisher2911.hmccosmetics.config;
import io.github.fisher2911.hmccosmetics.gui.CosmeticGui;
import io.github.fisher2911.hmccosmetics.gui.TokenGui;
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 TokenGuiSerializer implements TypeSerializer<TokenGui> {
public static final TokenGuiSerializer INSTANCE = new TokenGuiSerializer();
private static final String TOKEN_SLOT = "token-slot";
private static final String COSMETIC_SLOT = "cosmetic-slot";
private TokenGuiSerializer() {}
@Override
public TokenGui deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
final CosmeticGui cosmeticGui = GuiSerializer.INSTANCE.deserialize(CosmeticGui.class, source);
final ConfigurationNode tokenSlotNode = source.node(TOKEN_SLOT);
final ConfigurationNode cosmeticSlotNode = source.node(COSMETIC_SLOT);
return new TokenGui(
cosmeticGui,
tokenSlotNode.getInt(),
cosmeticSlotNode.getInt()
);
}
@Override
public void serialize(final Type type, @Nullable final TokenGui obj, final ConfigurationNode node) throws SerializationException {
}
}

View File

@@ -0,0 +1,59 @@
package io.github.fisher2911.hmccosmetics.config;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.Token;
import org.bukkit.inventory.ItemStack;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
public class TokenLoader {
private static final String FILE_NAME = "tokens.yml";
private static final String TOKEN_PATH = "tokens";
private static final String ID_PATH = "id";
private static final String COMMANDS_PATH = "commands";
private final HMCCosmetics plugin;
private final CosmeticManager cosmeticManager;
public TokenLoader(final HMCCosmetics plugin) {
this.plugin = plugin;
this.cosmeticManager = this.plugin.getCosmeticManager();
}
public void load() {
final Path path = Path.of(this.plugin.getDataFolder().getPath(), FILE_NAME);
final File file = path.toFile();
if (!file.exists()) {
this.plugin.saveResource(FILE_NAME, false);
}
final YamlConfigurationLoader loader = YamlConfigurationLoader.
builder().
defaultOptions(opts -> opts.serializers(build -> build.register(ItemStack.class, ItemSerializer.INSTANCE))).
path(path).
build();
try {
final ConfigurationNode source = loader.load().node(TOKEN_PATH);
for (final var entry : source.childrenMap().entrySet()) {
final var node = entry.getValue();
final String id = node.node(ID_PATH).getString();
final ItemStack itemStack = node.get(ItemStack.class);
final ArmorItem armorItem = this.cosmeticManager.getArmorItem(id);
if (armorItem == null) {
this.plugin.getLogger().severe("Could not find armor item for token: " + id + " with id: " + id);
continue;
}
final List<String> commands = node.node(COMMANDS_PATH).getList(String.class);
this.cosmeticManager.addToken(new Token(itemStack, armorItem, commands));
}
} catch (final ConfigurateException exception) {
this.plugin.getLogger().severe("Error loading tokens!");
}
}
}

View File

@@ -0,0 +1,166 @@
package io.github.fisher2911.hmccosmetics.config;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.util.Utils;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.nio.file.Path;
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";
private static final String APPLY_COSMETICS_ON_CLOSE = "apply-cosmetics-on-close";
private static final String OPEN_SOUND = "open-sound";
private static final String CLOSE_SOUND = "close-sound";
private static final String STATIC_LOCATION_PATH = "wardrobe-location";
private static final String VIEWER_LOCATION_PATH = "viewer-location";
private static final String LEAVE_LOCATION_PATH = "leave-location";
private static final String EQUIP_PUMPKIN_WARDROBE = "equip-pumpkin";
private static final String RETURN_LAST_LOCATION = "return-last-location";
private final HMCCosmetics plugin;
private boolean disableOnDamage;
private int displayRadius;
private boolean portable;
private boolean alwaysDisplay;
private int staticRadius;
private int rotationSpeed;
private int spawnDelay;
private int despawnDelay;
private boolean applyCosmeticsOnClose;
private boolean equipPumpkin;
private boolean returnLastLocation;
private SoundData openSound;
private SoundData closeSound;
private Location wardrobeLocation;
private Location viewerLocation;
private Location leaveLocation;
public WardrobeSettings(final HMCCosmetics plugin) {
this.plugin = plugin;
}
public void load() {
final File file = Path.of(this.plugin.getDataFolder().getPath(), "config.yml").toFile();
final YamlConfigurationLoader loader = YamlConfigurationLoader.
builder().
path(file.toPath()).
defaultOptions(opts ->
opts.serializers(build -> {
build.register(SoundData.class, SoundSerializer.INSTANCE);
build.register(Location.class, LocationSerializer.INSTANCE);
}))
.build();
try {
final var source = loader.load().node(WARDROBE_PATH);
this.disableOnDamage = source.node(DISABLE_ON_DAMAGE_PATH).getBoolean();
this.displayRadius = source.node(DISPLAY_RADIUS_PATH).getInt();
this.portable = source.node(PORTABLE_PATH).getBoolean();
this.staticRadius = source.node(STATIC_RADIUS_PATH).getInt();
this.alwaysDisplay = source.node(ALWAYS_DISPLAY_PATH).getBoolean();
this.rotationSpeed = source.node(ROTATION_SPEED_PATH).getInt();
this.spawnDelay = source.node(SPAWN_DELAY_PATH).getInt();
this.despawnDelay = source.node(DESPAWN_DELAY_PATH).getInt();
this.applyCosmeticsOnClose = source.node(APPLY_COSMETICS_ON_CLOSE).getBoolean();
this.equipPumpkin = source.node(EQUIP_PUMPKIN_WARDROBE).getBoolean();
this.returnLastLocation = source.node(RETURN_LAST_LOCATION).getBoolean();
this.openSound = source.node(OPEN_SOUND).get(SoundData.class);
this.closeSound = source.node(CLOSE_SOUND).get(SoundData.class);
this.wardrobeLocation = source.node(STATIC_LOCATION_PATH).get(Location.class);
this.viewerLocation = source.node(VIEWER_LOCATION_PATH).get(Location.class);
this.leaveLocation = Utils.replaceIfNull(source.node(LEAVE_LOCATION_PATH).get(Location.class), this.viewerLocation);
} catch (final ConfigurateException exception) {
this.plugin.getLogger().severe("Error loading wardrobe settings");
}
}
public boolean getDisableOnDamage() {
return disableOnDamage;
}
public int getDisplayRadius() {
return displayRadius;
}
public boolean isPortable() {
return portable;
}
public boolean isAlwaysDisplay() {
return alwaysDisplay;
}
public int getStaticRadius() {
return staticRadius;
}
public int getRotationSpeed() {
return rotationSpeed;
}
public int getSpawnDelay() {
return spawnDelay;
}
public int getDespawnDelay() {
return despawnDelay;
}
public boolean isApplyCosmeticsOnClose() {
return applyCosmeticsOnClose;
}
public boolean isEquipPumpkin() {
return equipPumpkin;
}
public boolean isReturnLastLocation() {
return returnLastLocation;
}
public Location getWardrobeLocation() {
return this.wardrobeLocation.clone();
}
public Location getViewerLocation() {
return viewerLocation;
}
public Location getLeaveLocation() {
return leaveLocation;
}
public void playOpenSound(final Player player) {
if (this.openSound == null) return;
this.openSound.play(player);
}
public void playCloseSound(final Player player) {
if (this.closeSound == null) return;
this.closeSound.play(player);
}
public boolean inDistanceOfWardrobe(final Location wardrobeLocation, final Location playerLocation) {
if (this.displayRadius == -1) return true;
if (!wardrobeLocation.getWorld().equals(playerLocation.getWorld())) return false;
return playerLocation.distanceSquared(wardrobeLocation) <= this.displayRadius * this.displayRadius;
}
public boolean inDistanceOfStatic(final Location location) {
if (this.wardrobeLocation == null) return false;
if (this.staticRadius == -1) return false;
if (!this.wardrobeLocation.getWorld().equals(location.getWorld())) return false;
return this.wardrobeLocation.distanceSquared(location) <= this.staticRadius * this.staticRadius;
}
}

View File

@@ -0,0 +1,129 @@
package io.github.fisher2911.hmccosmetics.cosmetic;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.ArmorItemSerializer;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.gui.Token;
import io.github.fisher2911.hmccosmetics.gui.WrappedGuiItem;
import io.github.fisher2911.hmccosmetics.util.Keys;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
public class CosmeticManager {
private final Path ITEMS_PATH = Path.of(HMCCosmetics.getPlugin(HMCCosmetics.class).getDataFolder().getPath(), "items.yml");
private final Map<String, Token> tokenMap;
private final Map<String, ArmorItem> armorItemMap;
private final Map<String, Integer> backpackParticleCounts;
public CosmeticManager(final Map<String, Token> tokenMap, final Map<String, ArmorItem> armorItemMap, final Map<String, Integer> backpackParticleCounts) {
this.tokenMap = tokenMap;
this.armorItemMap = armorItemMap;
this.backpackParticleCounts = backpackParticleCounts;
}
@Nullable
public ArmorItem getArmorItem(final String id) {
return this.armorItemMap.get(id);
}
public void addArmorItem(final ArmorItem armorItem) {
this.armorItemMap.put(armorItem.getId(), armorItem);
}
public Collection<ArmorItem> getAllArmorItems() {
return this.armorItemMap.values();
}
public Map<String, ArmorItem> getArmorItemMap() {
return armorItemMap;
}
@Nullable
public Token getToken(final String id) {
return this.tokenMap.get(id);
}
public void addToken(final Token token) {
this.tokenMap.put(token.getId(), token);
}
public Collection<Token> getAllTokens() {
return this.tokenMap.values();
}
public Map<String, Token> getTokenMap() {
return this.tokenMap;
}
@Nullable
public Token getToken(final ItemStack itemStack) {
final String id = Keys.getValue(itemStack, Keys.TOKEN_KEY, PersistentDataType.STRING);
if (id == null) return null;
return this.tokenMap.get(id);
}
public boolean isToken(final ItemStack itemStack) {
return Keys.hasKey(itemStack, Keys.TOKEN_KEY, PersistentDataType.STRING);
}
public void clearTokens() {
this.tokenMap.clear();
}
public void clearItems() {
this.armorItemMap.clear();
}
public int getBackpackParticleCount(final String id) {
return this.backpackParticleCounts.getOrDefault(id, 0);
}
public int getBackpackParticleCount(final ArmorItem armorItem) {
return this.getBackpackParticleCount(armorItem.getId());
}
private static final String PARTICLE_COUNT = "particle-count";
public void load() {
this.clearItems();
this.backpackParticleCounts.clear();
try {
final File file = ITEMS_PATH.toFile();
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
final YamlConfigurationLoader loader = YamlConfigurationLoader.
builder().
path(ITEMS_PATH).
defaultOptions(opts ->
opts.serializers(build ->
build.register(WrappedGuiItem.class, ArmorItemSerializer.INSTANCE))
)
.build();
for (var node : loader.load().childrenMap().values()) {
final WrappedGuiItem item = ArmorItemSerializer.INSTANCE.deserialize(WrappedGuiItem.class, node);
if (item instanceof ArmorItem armorItem) {
armorItem.setAction(null);
if (armorItem.getType() == ArmorItem.Type.SELF_BACKPACK) {
final int particleCount = node.node(PARTICLE_COUNT).getInt(5);
this.backpackParticleCounts.put(armorItem.getId(), particleCount);
}
this.armorItemMap.put(armorItem.getId(), armorItem);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,122 @@
package io.github.fisher2911.hmccosmetics.dao;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import java.util.Objects;
import org.jetbrains.annotations.Nullable;
@DatabaseTable(tableName = "armor_items")
public class ArmorItemDAO {
@DatabaseField(columnName = "uuid", useGetSet = true, uniqueCombo = true)
private String uuid;
@DatabaseField
private String id;
@DatabaseField(id = true, useGetSet = true, columnName = "artificial_id")
private String artificialId;
@DatabaseField(uniqueCombo = true)
private String type;
@DatabaseField(columnName = "color")
private int rgbDye;
public ArmorItemDAO(final String id, final String type, final int rgbDye) {
this.id = id;
this.artificialId = this.getArtificialId();
this.type = type;
this.rgbDye = rgbDye;
}
public ArmorItemDAO() {
}
public static ArmorItemDAO fromArmorItem(final ArmorItem armorItem) {
return new ArmorItemDAO(armorItem.getId(), armorItem.getType().toString(), armorItem.getDye());
}
@Nullable
public ArmorItem toArmorItem(final CosmeticManager cosmeticManager) {
final ArmorItem armorItem = cosmeticManager.getArmorItem(this.id);
if (armorItem == null) {
return null;
}
final ArmorItem copy = armorItem.copy();
copy.setDye(this.rgbDye);
return copy;
}
public String getUuid() {
return uuid;
}
public void setUuid(final String uuid) {
this.uuid = uuid;
}
/**
* ORMLite does not allow more than one primary key (WHYYYY???????????)
*
* @return
*/
public String getArtificialId() {
return this.uuid + "-" + this.type;
}
public void setArtificialId(final String artificialId) {
this.artificialId = artificialId;
}
public void setId(final String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
public int getRgbDye() {
return rgbDye;
}
public void setRgbDye(final int rgbDye) {
this.rgbDye = rgbDye;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ArmorItemDAO that = (ArmorItemDAO) o;
return Objects.equals(getUuid(), that.getUuid()) && Objects.equals(getType(),
that.getType());
}
@Override
public int hashCode() {
return Objects.hash(getUuid(), getType());
}
@Override
public String toString() {
return "ArmorItemDAO{" +
"uuid='" + uuid + '\'' +
", id='" + id + '\'' +
", type='" + type + '\'' +
", rgbDye=" + rgbDye +
'}';
}
}

View File

@@ -0,0 +1,65 @@
package io.github.fisher2911.hmccosmetics.dao;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.user.Backpack;
import io.github.fisher2911.hmccosmetics.user.EntityIds;
import io.github.fisher2911.hmccosmetics.user.NPCUser;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
@DatabaseTable(tableName = "citizen")
public class CitizenDAO {
@DatabaseField(id = true)
private int citizensId;
public CitizenDAO() {
}
public CitizenDAO(final int citizensId) {
this.citizensId = citizensId;
}
public void setCitizensId(final int citizensId) {
this.citizensId = citizensId;
}
@Nullable
public NPCUser toUser(
final CosmeticManager cosmeticManager,
final EntityIds entityIds,
final List<ArmorItemDAO> armorItems,
Backpack backpack
) {
final PlayerArmor playerArmor = PlayerArmor.empty();
for (final ArmorItemDAO armorItemDao : armorItems) {
final ArmorItem armorItem = armorItemDao.toArmorItem(cosmeticManager);
if (armorItem == null) {
continue;
}
playerArmor.setItem(armorItem);
}
return new NPCUser(this.citizensId, playerArmor, backpack, entityIds);
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final CitizenDAO that = (CitizenDAO) o;
return citizensId == that.citizensId;
}
@Override
public int hashCode() {
return Objects.hash(citizensId);
}
}

View File

@@ -0,0 +1,80 @@
package io.github.fisher2911.hmccosmetics.dao;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.user.Backpack;
import io.github.fisher2911.hmccosmetics.user.EntityIds;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@DatabaseTable(tableName = "user")
public class UserDAO {
@DatabaseField(id = true)
private UUID uuid;
public UserDAO() {
}
public UserDAO(final UUID uuid) {
this.uuid = uuid;
}
public void setUuid(final UUID uuid) {
this.uuid = uuid;
}
@Nullable
public User toUser(
final CosmeticManager cosmeticManager,
final EntityIds entityIds,
final List<ArmorItemDAO> armorItems,
final Backpack backpack,
final Wardrobe wardrobe
) {
final PlayerArmor playerArmor = PlayerArmor.empty();
for (final ArmorItemDAO armorItemDao : armorItems) {
final ArmorItem armorItem = armorItemDao.toArmorItem(cosmeticManager);
if (armorItem == null) {
continue;
}
playerArmor.setItem(armorItem);
}
return new User(this.uuid, playerArmor, backpack, wardrobe, entityIds);
}
@Override
public String toString() {
return "UserDAO{" +
"uuid=" + uuid +
'}';
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final UserDAO userDAO = (UserDAO) o;
return Objects.equals(uuid, userDAO.uuid);
}
@Override
public int hashCode() {
return Objects.hash(uuid);
}
}

View File

@@ -0,0 +1,242 @@
package io.github.fisher2911.hmccosmetics.database;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
import io.github.fisher2911.hmccosmetics.dao.ArmorItemDAO;
import io.github.fisher2911.hmccosmetics.dao.CitizenDAO;
import io.github.fisher2911.hmccosmetics.dao.UserDAO;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.user.Backpack;
import io.github.fisher2911.hmccosmetics.user.EntityIds;
import io.github.fisher2911.hmccosmetics.user.NPCUser;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class Database {
protected final HMCCosmetics plugin;
private final Dao<UserDAO, UUID> userDao;
private final Dao<CitizenDAO, Integer> citizenDao;
private final Dao<ArmorItemDAO, String> armorItemDao;
private final ConnectionSource dataSource;
private final DatabaseType databaseType;
public Database(
final HMCCosmetics plugin,
final ConnectionSource dataSource,
final DatabaseType databaseType) throws SQLException {
this.plugin = plugin;
this.dataSource = dataSource;
this.userDao = DaoManager.createDao(this.dataSource, UserDAO.class);
this.citizenDao = DaoManager.createDao(this.dataSource, CitizenDAO.class);
this.armorItemDao = DaoManager.createDao(this.dataSource, ArmorItemDAO.class);
this.databaseType = databaseType;
}
public void load() {
Threads.getInstance().execute(() -> new DatabaseConverter(this.plugin, this).convert());
}
protected void createTables() {
try {
TableUtils.createTableIfNotExists(this.dataSource, ArmorItemDAO.class);
TableUtils.createTableIfNotExists(this.dataSource, UserDAO.class);
TableUtils.createTableIfNotExists(this.dataSource, CitizenDAO.class);
} catch (final SQLException exception) {
exception.printStackTrace();
}
}
public void loadUser(final Entity entity, final Consumer<User> onComplete) {
final UUID uuid = entity.getUniqueId();
final int armorStandId = getNextEntityId();
final int balloonId = getNextEntityId();
final int wardrobeViewerId = getNextEntityId();
final Wardrobe wardrobe = this.createNewWardrobe(uuid);
Threads.getInstance().execute(
() -> {
try {
UserDAO user = this.userDao.queryForId(uuid);
if (user == null) {
user = this.userDao.createIfNotExists(new UserDAO(uuid));
}
final List<ArmorItemDAO> armorItems = this.armorItemDao.queryForEq("uuid", uuid.toString());
final User actualUser = user.toUser(
this.plugin.getCosmeticManager(),
new EntityIds(
entity.getEntityId(),
armorStandId,
balloonId,
wardrobeViewerId
),
armorItems,
new Backpack(this.plugin, armorStandId),
wardrobe
);
Bukkit.getScheduler().runTask(this.plugin,
() -> onComplete.accept(actualUser)
);
} catch (final SQLException exception) {
exception.printStackTrace();
}
});
onComplete.accept(new User(
uuid,
PlayerArmor.empty(),
new Backpack(this.plugin, armorStandId),
wardrobe,
new EntityIds(entity.getEntityId(), armorStandId, balloonId, wardrobeViewerId)
));
}
public void loadNPCUser(final int id, final Entity entity, final Consumer<NPCUser> onComplete) {
final int armorStandId = getNextEntityId();
final int balloonId = getNextEntityId();
final int wardrobeViewerId = getNextEntityId();
Threads.getInstance().execute(
() -> {
try {
CitizenDAO citizen = this.citizenDao.queryForId(id);
if (citizen == null) {
citizen = this.citizenDao.createIfNotExists(new CitizenDAO(id));
}
final List<ArmorItemDAO> armorItems = this.armorItemDao.queryForEq("uuid", String.valueOf(id));
final NPCUser actualUser = citizen.toUser(
this.plugin.getCosmeticManager(),
new EntityIds(
entity.getEntityId(),
armorStandId,
balloonId,
wardrobeViewerId
),
armorItems,
new Backpack(this.plugin, armorStandId)
);
Bukkit.getScheduler().runTask(this.plugin,
() -> onComplete.accept(actualUser)
);
} catch (final SQLException exception) {
exception.printStackTrace();
}
});
onComplete.accept(new NPCUser(
id,
PlayerArmor.empty(),
new Backpack(this.plugin, armorStandId),
new EntityIds(entity.getEntityId(), armorStandId, balloonId, wardrobeViewerId)
)
);
}
public void saveUser(final User user) {
try {
final UserDAO userDAO = new UserDAO(user.getId());
this.userDao.createOrUpdate(userDAO);
final String uuid = user.getId().toString();
for (final ArmorItem armorItem : user.getPlayerArmor().getArmorItems()) {
final ArmorItemDAO dao = ArmorItemDAO.fromArmorItem(armorItem);
dao.setUuid(uuid);
this.armorItemDao.createOrUpdate(dao);
}
} catch (final SQLException exception) {
exception.printStackTrace();
}
}
public void saveNPCUser(final NPCUser user) {
try {
final CitizenDAO citizenDAO = new CitizenDAO(user.getId());
this.citizenDao.createOrUpdate(citizenDAO);
final String id = user.getId().toString();
for (final ArmorItem armorItem : user.getPlayerArmor().getArmorItems()) {
final ArmorItemDAO dao = ArmorItemDAO.fromArmorItem(armorItem);
dao.setUuid(id);
this.armorItemDao.createOrUpdate(dao);
}
} catch (final SQLException exception) {
exception.printStackTrace();
}
}
public void saveAll() {
for (final User user : this.plugin.getUserManager().getAll()) {
this.saveUser(user);
}
}
public void close() {
try {
this.dataSource.close();
} catch (final Exception exception) {
exception.printStackTrace();
}
}
protected ConnectionSource getDataSource() {
return dataSource;
}
public DatabaseType getDatabaseType() {
return databaseType;
}
public Dao<UserDAO, UUID> getUserDao() {
return userDao;
}
public Dao<ArmorItemDAO, String> getArmorItemDao() {
return armorItemDao;
}
public Wardrobe createNewWardrobe(final UUID ownerUUID) {
final int armorStandId = getNextEntityId();
return new Wardrobe(
this.plugin,
UUID.randomUUID(),
ownerUUID,
PlayerArmor.empty(),
new Backpack(this.plugin, armorStandId),
new EntityIds(
getNextEntityId(),
armorStandId,
getNextEntityId(),
getNextEntityId()
),
false
);
}
public static int getNextEntityId() {
Random random = new Random();
return random.nextInt(999999);
}
}

View File

@@ -0,0 +1,135 @@
package io.github.fisher2911.hmccosmetics.database;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.user.Backpack;
import io.github.fisher2911.hmccosmetics.user.EntityIds;
import io.github.fisher2911.hmccosmetics.user.User;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
public class DatabaseConverter {
private static final int CURRENT_VERSION = 2;
private static final String FILE_NAME = "info.yml";
private final HMCCosmetics plugin;
private final Database database;
public DatabaseConverter(final HMCCosmetics plugin, final Database database) {
this.database = database;
this.plugin = plugin;
}
public void convert() {
final File folder = new File(this.plugin.getDataFolder(), "database");
final File file = Path.of(
folder.getPath(),
FILE_NAME
).toFile();
if (!file.exists()) {
this.plugin.saveResource("database" + File.separator + FILE_NAME, true);
}
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
final int version = config.getInt("version") == 0 ? 1 : config.getInt("version");
final Set<User> users = new HashSet<>();
this.convert(version, users::add);
try {
config.set("version", CURRENT_VERSION);
config.save(file);
} catch (final IOException exception) {
exception.printStackTrace();
}
this.database.createTables();
for (final User user : users) {
database.saveUser(user);
}
}
private void convert(final int version, final Consumer<User> consumer) {
switch (version) {
case 1 -> this.convertVersionOne(consumer);
}
}
private void convertVersionOne(final Consumer<User> consumer) {
final String query = "SELECT * from user";
try (final PreparedStatement statement = this.database.getDataSource()
.getReadOnlyConnection("user").
getUnderlyingConnection().prepareStatement(query)) {
final ResultSet results = statement.executeQuery();
try {
final Map<String, ArmorItem> armorItems = new ConcurrentHashMap<>(
this.plugin.getCosmeticManager().getArmorItemMap());
while (results.next()) {
final PlayerArmor playerArmor = PlayerArmor.empty();
final UUID uuid = UUID.fromString(results.getString(1));
final int armorStandId = Database.getNextEntityId();
final User user = new User(
uuid,
playerArmor,
new Backpack(this.plugin, armorStandId),
this.database.createNewWardrobe(uuid),
new EntityIds(
-1,
armorStandId,
Database.getNextEntityId(),
Database.getNextEntityId()
)
);
final String backpackId = results.getString(2);
final String hatId = results.getString(3);
final int hatDye = results.getInt(4);
final ArmorItem backpack = armorItems.get(backpackId);
final ArmorItem hat = armorItems.get(hatId);
if (backpack != null) {
playerArmor.setItem(backpack);
}
if (hat != null) {
hat.setDye(hatDye);
playerArmor.setItem(hat);
}
consumer.accept(user);
}
} catch (final SQLException exception) {
exception.printStackTrace();
}
} catch (final SQLException exception) {
exception.printStackTrace();
}
try (final PreparedStatement dropStatement = this.database.getDataSource()
.getReadWriteConnection("user").
getUnderlyingConnection().prepareStatement("DROP TABLE user")) {
dropStatement.executeUpdate();
} catch (final SQLException exception) {
exception.printStackTrace();
}
}
}

View File

@@ -0,0 +1,91 @@
package io.github.fisher2911.hmccosmetics.database;
import com.j256.ormlite.jdbc.DataSourceConnectionSource;
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
public class DatabaseFactory {
private static final Path FILE_PATH = HMCCosmetics.PLUGIN_FOLDER.resolve("database.yml");
private static final String TYPE_PATH = "type";
private static final String NAME_PATH = "name";
private static final String USERNAME_PATH = "username";
private static final String PASSWORD_PATH = "password";
private static final String IP_PATH = "ip";
private static final String PORT_PATH = "port";
public static Database create(final HMCCosmetics plugin) throws SQLException {
if (!Files.exists(FILE_PATH)) {
plugin.saveResource(FILE_PATH.getFileName().toString(), false);
}
final FileConfiguration config = YamlConfiguration.loadConfiguration(FILE_PATH.toFile());
final String type = config.getString(TYPE_PATH);
final Logger logger = plugin.getLogger();
if (type == null) {
logger.severe("Database type was null, disabling plugin.");
Bukkit.getPluginManager().disablePlugin(plugin);
throw new NullPointerException();
}
final Database database = switch (type.toLowerCase()) {
case "mysql" -> {
final String name = config.getString(NAME_PATH);
final String username = config.getString(USERNAME_PATH);
final String password = config.getString(PASSWORD_PATH);
final String ip = config.getString(IP_PATH);
final String port = config.getString(PORT_PATH);
final HikariConfig hikari = new HikariConfig();
final String jdbcUrl = "jdbc:mysql://" + ip + ":" + port + "/" + name;
hikari.setJdbcUrl(jdbcUrl);
hikari.setUsername(username);
hikari.setPassword(password);
hikari.setConnectionTimeout(1000000000);
final HikariDataSource source = new HikariDataSource(hikari);
yield new Database(
plugin,
new DataSourceConnectionSource(source, jdbcUrl),
DatabaseType.MYSQL
);
}
case "sqlite" -> {
final File folder = new File(plugin.getDataFolder().getPath(), "database");
folder.mkdirs();
yield new Database(plugin, new JdbcPooledConnectionSource("jdbc:sqlite:" + new File(
folder.getPath(),
"users.db"
).getPath()),
DatabaseType.SQLITE
);
}
default -> null;
};
if (database == null) {
logger.severe(
"Error loading database, type " + type + " is invalid! Disabling plugin.");
Bukkit.getPluginManager().disablePlugin(plugin);
}
return database;
}
}

View File

@@ -0,0 +1,8 @@
package io.github.fisher2911.hmccosmetics.database;
public enum DatabaseType {
MYSQL,
SQLITE
}

View File

@@ -0,0 +1,365 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.components.GuiAction;
import io.github.fisher2911.hmccosmetics.config.CosmeticGuiAction;
import io.github.fisher2911.hmccosmetics.util.builder.ColorBuilder;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ArmorItem extends WrappedGuiItem {
private final String name;
private final String id;
private final ItemStack lockedItem;
private final ItemStack appliedItem;
private final String permission;
private final Type type;
private List<CosmeticGuiAction> actions;
private boolean dyeable;
private int dye;
public ArmorItem(
@NotNull final ItemStack itemStack,
final List<CosmeticGuiAction> actions,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final int dye) {
super(itemStack, null);
this.name = name;
this.id = id;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = actions;
this.permission = permission;
this.type = type;
this.dye = dye;
}
public ArmorItem(
@NotNull final ItemStack itemStack,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final int dye) {
super(itemStack);
this.id = id;
this.name = name;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = new ArrayList<>();
this.permission = permission;
this.type = type;
this.dye = dye;
}
public ArmorItem(
@NotNull final Material material,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final int dye) {
super(material);
this.id = id;
this.name = name;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = new ArrayList<>();
this.permission = permission;
this.type = type;
this.dye = dye;
}
public ArmorItem(
@NotNull final Material material,
final List<CosmeticGuiAction> actions,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final int dye) {
super(material, null);
this.actions = actions;
this.id = id;
this.name = name;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.permission = permission;
this.type = type;
this.dye = dye;
}
public ArmorItem(
@NotNull final ItemStack itemStack,
final List<CosmeticGuiAction> actions,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final boolean dyeable,
final int dye) {
super(itemStack, null);
this.name = name;
this.id = id;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = actions;
this.permission = permission;
this.type = type;
this.dyeable = dyeable;
this.dye = dye;
}
public ArmorItem(
@NotNull final ItemStack itemStack,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final boolean dyeable,
final int dye) {
super(itemStack);
this.name = name;
this.id = id;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = new ArrayList<>();
this.permission = permission;
this.type = type;
this.dyeable = dyeable;
this.dye = dye;
}
public ArmorItem(
@NotNull final Material material,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final boolean dyeable,
final int dye) {
super(material);
this.id = id;
this.name = name;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = new ArrayList<>();
this.permission = permission;
this.type = type;
this.dyeable = dyeable;
this.dye = dye;
}
public ArmorItem(
@NotNull final Material material,
@Nullable final GuiAction<InventoryClickEvent> action,
final String name,
final String id,
final ItemStack lockedItem,
final ItemStack appliedItem,
final String permission,
final Type type,
final boolean dyeable,
final int dye) {
super(material, action);
this.name = name;
this.id = id;
this.lockedItem = lockedItem;
this.appliedItem = appliedItem;
this.actions = new ArrayList<>();
this.permission = permission;
this.type = type;
this.dyeable = dyeable;
this.dye = dye;
}
protected ArmorItem(final ArmorItem armorItem) {
super(armorItem.getItemStack().clone(), null);
this.name = armorItem.getName();
this.id = armorItem.getId();
this.lockedItem = armorItem.getLockedItem().clone();
this.appliedItem = armorItem.getAppliedItem().clone();
this.actions = armorItem.getActions();
this.permission = armorItem.getPermission();
this.type = armorItem.getType();
this.dyeable = armorItem.isDyeable();
this.dye = armorItem.getDye();
}
public static ArmorItem empty(final Type type) {
return empty(type, "");
}
public static ArmorItem empty(final Type type, final String id) {
if (type == Type.BALLOON) {
return new BalloonItem(
new ItemStack(Material.AIR),
id,
id,
new ItemStack(Material.AIR),
new ItemStack(Material.AIR),
"",
type,
-1,
""
);
}
return new ArmorItem(
new ItemStack(Material.AIR),
id,
id,
new ItemStack(Material.AIR),
new ItemStack(Material.AIR),
"",
type,
-1
);
}
public String getId() {
return id;
}
public ItemStack getLockedItem() {
return lockedItem;
}
public ItemStack getAppliedItem() {
return appliedItem;
}
public List<CosmeticGuiAction> getActions() {
return actions;
}
public void setActions(final List<CosmeticGuiAction> actions) {
this.actions.clear();
this.actions.addAll(actions);
}
public String getPermission() {
return permission;
}
public Type getType() {
return type;
}
public boolean isDyeable() {
return dyeable;
}
public int getDye() {
return dye;
}
public void setDye(final int dye) {
this.dye = dye;
}
public ItemStack getItemStack(final Status status) {
return this.color(switch (status) {
case ALLOWED -> super.getItemStack();
case LOCKED -> this.getLockedItem();
case APPLIED -> this.getAppliedItem();
});
}
private ItemStack color(final ItemStack itemStack) {
if (this.dye == -1 || !ColorBuilder.canBeColored(itemStack)) {
return itemStack;
}
return ColorBuilder.from(itemStack).
color(Color.fromRGB(this.dye)).
build();
}
public boolean isEmpty() {
return this.getItemStack().getType() == Material.AIR;
}
public ArmorItem copy() {
if (this instanceof final BalloonItem item) {
return new BalloonItem(item);
}
return new ArmorItem(this);
}
public String getName() {
return this.name;
}
public enum Type {
HAT(EquipmentSlot.HEAD),
BACKPACK(null),
SELF_BACKPACK(null),
BALLOON(null),
OFF_HAND(EquipmentSlot.OFF_HAND),
CHEST_PLATE(EquipmentSlot.CHEST),
PANTS(EquipmentSlot.LEGS),
BOOTS(EquipmentSlot.FEET);
private final EquipmentSlot slot;
Type(final EquipmentSlot slot) {
this.slot = slot;
}
public EquipmentSlot getSlot() {
return slot;
}
@Nullable
public static Type fromWrapper(EquipmentSlot slot) {
return switch (slot) {
case HEAD -> Type.HAT;
case CHEST -> Type.CHEST_PLATE;
case LEGS -> Type.PANTS;
case FEET -> Type.BOOTS;
case OFF_HAND -> Type.OFF_HAND;
default -> null;
};
}
@Nullable
public static Type fromEquipmentSlot(final EquipmentSlot slot) {
for (final Type type : values()) {
if (type.getSlot() == slot) return type;
}
return null;
}
}
public enum Status {
ALLOWED,
LOCKED,
APPLIED
}
}

View File

@@ -0,0 +1,84 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.components.GuiAction;
import io.github.fisher2911.hmccosmetics.config.CosmeticGuiAction;
import org.apache.logging.log4j.util.Strings;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class BalloonItem extends ArmorItem {
private final String modelId;
public BalloonItem(final BalloonItem item) {
this(
item.getItemStack(),
item.getActions(),
item.getName(),
item.getId(),
item.getLockedItem(),
item.getAppliedItem(),
item.getPermission(),
item.getType(),
item.getDye(),
item.getModelId()
);
}
public BalloonItem(final @NotNull ItemStack itemStack, final List<CosmeticGuiAction> actions, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final int dye, final String modelId) {
super(itemStack, actions, name, id, lockedItem, appliedItem, permission, type, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull ItemStack itemStack, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final int dye, final String modelId) {
super(itemStack, name, id, lockedItem, appliedItem, permission, type, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull Material material, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final int dye, final String modelId) {
super(material, name, id, lockedItem, appliedItem, permission, type, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull Material material, final List<CosmeticGuiAction> actions, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final int dye, final String modelId) {
super(material, actions, name, id, lockedItem, appliedItem, permission, type, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull ItemStack itemStack, final List<CosmeticGuiAction> actions, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final boolean dyeable, final int dye, final String modelId) {
super(itemStack, actions, name, id, lockedItem, appliedItem, permission, type, dyeable, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull ItemStack itemStack, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final boolean dyeable, final int dye, final String modelId) {
super(itemStack, name, id, lockedItem, appliedItem, permission, type, dyeable, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull Material material, final String name, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final boolean dyeable, final int dye, final String modelId) {
super(material, name, id, lockedItem, appliedItem, permission, type, dyeable, dye);
this.modelId = modelId;
}
public BalloonItem(final @NotNull Material material, final String name, final @Nullable GuiAction<InventoryClickEvent> action, final String id, final ItemStack lockedItem, final ItemStack appliedItem, final String permission, final Type type, final boolean dyeable, final int dye, final String modelId) {
super(material, action, name, id, lockedItem, appliedItem, permission, type, dyeable, dye);
this.modelId = modelId;
}
public BalloonItem(final ArmorItem armorItem, final String modelId) {
super(armorItem);
this.modelId = modelId;
}
public String getModelId() {
if (this.modelId == null) {
return Strings.EMPTY;
}
return this.modelId;
}
}

View File

@@ -9,11 +9,16 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ColorItem extends GuiItem {
public class ColorItem extends WrappedGuiItem {
private final Color color;
public ColorItem(final @NotNull ItemStack itemStack, final GuiAction<InventoryClickEvent> action, final Color color) {
public ColorItem(final GuiItem item, final GuiAction<InventoryClickEvent> action, final Color color) {
super(item, action);
this.color = color;
}
public ColorItem(final @NotNull ItemStack itemStack, final @Nullable GuiAction<@NotNull InventoryClickEvent> action, final Color color) {
super(itemStack, action);
this.color = color;
}
@@ -28,7 +33,7 @@ public class ColorItem extends GuiItem {
this.color = color;
}
public ColorItem(final @NotNull Material material, final @Nullable GuiAction<InventoryClickEvent> action, final Color color) {
public ColorItem(final @NotNull Material material, final @Nullable GuiAction<@NotNull InventoryClickEvent> action, final Color color) {
super(material, action);
this.color = color;
}

View File

@@ -0,0 +1,254 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.guis.Gui;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.CosmeticGuiAction;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.message.Adventure;
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
import io.github.fisher2911.hmccosmetics.message.Messages;
import io.github.fisher2911.hmccosmetics.message.Placeholder;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class CosmeticGui {
private static final float COOL_DOWN = 0.5f;
protected final HMCCosmetics plugin;
protected final MessageHandler messageHandler;
protected final String title;
protected final int rows;
protected final Map<Integer, ItemStack> itemStackMap;
protected final Map<Integer, GuiItem> guiItemMap;
protected Gui gui;
private long lastClicked;
public CosmeticGui(
final HMCCosmetics plugin,
final String title,
final int rows,
final Map<Integer, GuiItem> guiItemMap) {
this.plugin = plugin;
this.messageHandler = this.plugin.getMessageHandler();
this.title = title;
this.rows = rows;
this.guiItemMap = guiItemMap;
this.itemStackMap = new HashMap<>();
this.guiItemMap.forEach((key, value) -> itemStackMap.put(key, value.getItemStack()));
}
private void setItems(final User user) {
final Player player = user.getPlayer();
if (player == null) {
return;
}
for (final var entry : guiItemMap.entrySet()) {
final int slot = entry.getKey();
final GuiItem guiItem = this.getGuiItem(user, player, slot);
if (guiItem == null) {
continue;
}
this.gui.setItem(slot, guiItem);
}
}
private void setUserArmor(
final HumanEntity human,
final User user,
final ArmorItem armorItem,
final InventoryClickEvent event,
final List<CosmeticGuiAction> actions) {
final long current = System.currentTimeMillis();
if ((current - this.lastClicked) / 1000. < COOL_DOWN) {
return;
}
this.lastClicked = current;
if (!(human instanceof final Player player)) {
return;
}
final ArmorItem.Type type = armorItem.getType();
final User setUser;
if (user.isWardrobeActive()) {
setUser = user.getWardrobe();
} else {
setUser = user;
}
final ArmorItem setTo = this.plugin.getUserManager().setOrUnset(
setUser,
armorItem,
Messages.getRemovedMessage(type),
Messages.getSetMessage(type),
true
);
if (!setTo.isEmpty()) {
executeActions(event, actions, CosmeticGuiAction.When.EQUIP);
} else {
executeActions(event, actions, CosmeticGuiAction.When.REMOVE);
}
final int slot = event.getSlot();
final GuiItem guiItem = this.getGuiItem(user, player, slot);
if (guiItem == null) {
return;
}
this.gui.updateItem(slot, guiItem);
}
private void executeActions(
final InventoryClickEvent event,
final List<CosmeticGuiAction> actions,
final CosmeticGuiAction.When when
) {
for (final CosmeticGuiAction action : actions) {
action.execute(event, when);
}
}
public void open(final User user, final Player player) {
final Component component = Adventure.MINI_MESSAGE.deserialize(Placeholder.applyPapiPlaceholders(user.getPlayer(), this.title));
this.gui = Gui.gui().
title(component).
rows(this.rows).
create();
this.gui.setDefaultClickAction(event -> event.setCancelled(true));
this.gui.setCloseGuiAction(event -> user.setOpenGui(null));
this.setItems(user);
this.gui.open(player);
}
@Nullable
private GuiItem getGuiItem(final User user, final Player player, final int slot) {
final GuiItem guiItem = this.guiItemMap.get(slot);
if (guiItem == null) {
return null;
}
final ItemStack itemStack = this.itemStackMap.get(slot);
if (itemStack == null) return null;
return this.getGuiItem(user, player, guiItem, itemStack);
}
@Nullable
protected GuiItem getGuiItem(final User user, final Player player, final GuiItem guiItem, final ItemStack itemStack) {
if (guiItem instanceof final ArmorItem armorItem) {
final String permission =
armorItem.getPermission() == null ? "" : armorItem.getPermission();
final boolean hasPermission = permission.isBlank() || user.hasPermissionToUse(armorItem);
return new GuiItem(
this.applyPlaceholders(user, player, armorItem, hasPermission),
event -> {
if (!hasPermission) {
this.messageHandler.sendMessage(
player,
Messages.NO_COSMETIC_PERMISSION
);
return;
}
final ArmorItem cosmeticItem = this.plugin.getCosmeticManager()
.getArmorItem(armorItem.getId());
if (cosmeticItem == null) {
return;
}
this.setUserArmor(player, user, cosmeticItem, event, armorItem.getActions());
}
);
}
guiItem.setItemStack(
ItemBuilder.from(itemStack.clone()).papiPlaceholders(player).build()
);
return guiItem;
}
protected ItemStack applyPlaceholders(
final User user,
final Player player,
final ArmorItem armorItem,
final boolean hasPermission
) {
final Map<String, String> placeholders = new HashMap<>();
final PlayerArmor playerArmor = user.getPlayerArmor();
final ArmorItem.Type type = armorItem.getType();
final String id = playerArmor.getItem(type).getId();
placeholders.put(
Placeholder.ENABLED,
String.valueOf(id.equals(armorItem.getId())).
toLowerCase(Locale.ROOT));
placeholders.put(
Placeholder.ALLOWED,
String.valueOf(hasPermission).
toLowerCase(Locale.ROOT));
final ItemStack itemStack;
if (!hasPermission) {
itemStack = armorItem.getItemStack(ArmorItem.Status.LOCKED);
} else {
itemStack = armorItem.getItemStack(ArmorItem.Status.ALLOWED);
}
return ItemBuilder.from(
itemStack
).namePlaceholders(placeholders).
lorePlaceholders(placeholders).
papiPlaceholders(player).
build();
}
public void updateItem(final int slot, final GuiItem guiItem, final User user, final Player player) {
final ItemStack itemStack = guiItem.getItemStack().clone();
this.guiItemMap.put(slot, guiItem);
this.itemStackMap.put(slot, itemStack);
final GuiItem setItem = this.getGuiItem(user, player, guiItem, itemStack);
if (setItem == null) return;
this.gui.updateItem(slot, setItem);
}
public CosmeticGui copy() {
return new CosmeticGui(
this.plugin,
this.title,
this.rows,
new HashMap<>(this.guiItemMap)
);
}
}

View File

@@ -0,0 +1,248 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.ArmorItemSerializer;
import io.github.fisher2911.hmccosmetics.config.CosmeticSettings;
import io.github.fisher2911.hmccosmetics.config.DyeGuiSerializer;
import io.github.fisher2911.hmccosmetics.config.GuiSerializer;
import io.github.fisher2911.hmccosmetics.config.TokenGuiSerializer;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class CosmeticsMenu {
public static final String DEFAULT_MAIN_MENU = "main";
public static final String DEFAULT_DYE_MENU = "dye-menu";
public static final String DEFAULT_TOKEN_MENU = "token-menu";
private final HMCCosmetics plugin;
private final CosmeticSettings settings;
private final CosmeticManager cosmeticManager;
private final Map<String, CosmeticGui> guiMap = new HashMap<>();
private final Set<String> registeredPermissions = new HashSet<>();
public CosmeticsMenu(final HMCCosmetics plugin) {
this.plugin = plugin;
this.settings = this.plugin.getSettings().getCosmeticSettings();
this.cosmeticManager = this.plugin.getCosmeticManager();
}
public void openMenu(final String id, final HumanEntity humanEntity) {
if (!(humanEntity instanceof final Player player)) return;
final CosmeticGui cosmeticGui = this.getGui(id);
final Optional<User> optionalUser = this.plugin.getUserManager().get(humanEntity.getUniqueId());
if (optionalUser.isEmpty()) return;
User user = optionalUser.get();
final Wardrobe wardrobe = user.getWardrobe();
if (wardrobe.isActive()) user = wardrobe;
if (cosmeticGui instanceof final DyeSelectorGui dyeSelectorGui) {
dyeSelectorGui.getGui(user, user.getLastSetItem().getType()).open(humanEntity);
user.setOpenGui(dyeSelectorGui);
return;
}
if (cosmeticGui != null) {
user.setOpenGui(cosmeticGui);
cosmeticGui.open(user, player);
}
}
public Set<String> getMenus() {
return this.guiMap.keySet();
}
public void openDefault(final HumanEntity humanEntity) {
this.openMenu(this.settings.getDefaultMenu(), humanEntity);
}
public void reload() {
for (final ArmorItem armorItem : this.cosmeticManager.getAllArmorItems()) {
Bukkit.getPluginManager().removePermission(new Permission(armorItem.getPermission()));
}
this.load();
}
public void openDyeSelectorGui(
User user,
final ArmorItem.Type type) {
final Player player = user.getPlayer();
if (player == null) {
return;
}
final Wardrobe wardrobe = user.getWardrobe();
if (wardrobe.isActive()) user = wardrobe;
final CosmeticGui gui = this.getGui(this.settings.getDefaultMenu());
if (gui instanceof final DyeSelectorGui dyeSelectorGui) {
dyeSelectorGui.getGui(user, type).open(player);
}
}
@Nullable
private CosmeticGui getGui(final String id) {
final CosmeticGui gui = this.guiMap.get(id);
if (gui == null) return null;
return gui.copy();
}
private static final String GUI_TYPE = "gui-type";
private static final String DYE_TYPE = "dye";
private static final String TOKEN_TYPE = "token";
public void load() {
this.guiMap.clear();
this.cosmeticManager.clearTokens();
this.cosmeticManager.load();
final File file = Path.of(this.plugin.getDataFolder().getPath(),
"menus").toFile();
if (!Path.of(this.plugin.getDataFolder().getPath(),
"menus",
this.settings.getDefaultMenu() + ".yml").toFile().exists()) {
this.plugin.saveResource(
new File("menus", this.settings.getDefaultMenu() + ".yml").getPath(),
false
);
}
if (!Path.of(this.plugin.getDataFolder().getPath(),
"menus",
DEFAULT_DYE_MENU + ".yml").toFile().exists()) {
this.plugin.saveResource(
new File("menus", DEFAULT_DYE_MENU + ".yml").getPath(),
false
);
}
if (!Path.of(this.plugin.getDataFolder().getPath(),
"menus",
DEFAULT_TOKEN_MENU + ".yml").toFile().exists()) {
this.plugin.saveResource(
new File("menus", DEFAULT_TOKEN_MENU + ".yml").getPath(),
false
);
}
if (!file.exists() ||
!file.isDirectory()) {
this.plugin.getLogger().severe("No directory found");
return;
}
final List<File> files = this.getSubFiles(file);
if (files.isEmpty()) {
this.plugin.getLogger().severe("No GUI files found.");
return;
}
for (final File guiFile : files) {
final String id = guiFile.getName().replace(".yml", "");
final YamlConfigurationLoader loader = YamlConfigurationLoader.
builder().
path(Path.of(guiFile.getPath())).
defaultOptions(opts ->
opts.serializers(build -> {
build.register(WrappedGuiItem.class, ArmorItemSerializer.INSTANCE);
build.register(CosmeticGui.class, GuiSerializer.INSTANCE);
build.register(DyeSelectorGui.class, DyeGuiSerializer.INSTANCE);
build.register(TokenGui.class, TokenGuiSerializer.INSTANCE);
}))
.build();
try {
final ConfigurationNode source = loader.load();
final ConfigurationNode typeNode = source.node(GUI_TYPE);
final String type;
if (typeNode != null) {
type = typeNode.getString();
} else {
type = "";
}
if (id.equals(DEFAULT_DYE_MENU) || DYE_TYPE.equals(type)) {
this.guiMap.put(id, DyeGuiSerializer.INSTANCE.deserialize(DyeSelectorGui.class, source));
this.plugin.getLogger().info("Loaded dye gui: " + id);
continue;
}
if (TOKEN_TYPE.equals(type)) {
this.guiMap.put(id, TokenGuiSerializer.INSTANCE.deserialize(TokenGui.class, source));
this.plugin.getLogger().info("Loaded token gui: " + id);
continue;
}
final CosmeticGui gui = source.get(CosmeticGui.class);
if (gui == null) continue;
for (final GuiItem guiItem : gui.guiItemMap.values()) {
if (guiItem instanceof final ArmorItem item) {
final ArmorItem copy = item.copy();
copy.setAction(null);
this.cosmeticManager.addArmorItem(copy);
final String perm = copy.getPermission();
if (perm.isBlank() || this.registeredPermissions.contains(perm)) continue;
this.registeredPermissions.add(perm);
Bukkit.getPluginManager().addPermission(new Permission(perm));
}
}
this.guiMap.put(id, source.get(CosmeticGui.class));
this.plugin.getLogger().info("Loaded gui: " + id);
} catch (final ConfigurateException exception) {
exception.printStackTrace();
}
}
}
private List<File> getSubFiles(final File dir) {
final List<File> files = new ArrayList<>();
if (!dir.isDirectory()) return files;
final File[] arr = dir.listFiles();
if (arr == null) return files;
for (final File file : arr) {
if (file.isDirectory()) {
files.addAll(this.getSubFiles(file));
continue;
}
files.add(file);
}
return files;
}
}

View File

@@ -0,0 +1,227 @@
package io.github.fisher2911.hmccosmetics.gui;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import dev.triumphteam.gui.guis.Gui;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.message.Adventure;
import io.github.fisher2911.hmccosmetics.message.Placeholder;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
public class DyeSelectorGui extends CosmeticGui {
private final BiMap<Integer, ArmorItem.Type> cosmeticsSlots;
private int selectedCosmetic;
public DyeSelectorGui(
final HMCCosmetics plugin,
final String title,
final int rows,
final Map<Integer, GuiItem> guiItemMap,
final BiMap<Integer, ArmorItem.Type> cosmeticsSlots,
final int selectedCosmetic
) {
super(plugin, title, rows, guiItemMap);
this.cosmeticsSlots = cosmeticsSlots;
this.selectedCosmetic = selectedCosmetic;
}
public Gui getGui(final User user) {
return this.getGui(user, null);
}
public Gui getGui(final User user, @Nullable final ArmorItem.Type type) {
final Component component = Adventure.MINI_MESSAGE.deserialize(Placeholder.applyPapiPlaceholders(user.getPlayer(), this.title));
this.gui = Gui.gui().
title(component).
rows(rows).
create();
final Player player = user.getPlayer();
if (type != null) {
final Integer selected = this.cosmeticsSlots.inverse().get(type);
this.selectedCosmetic = selected == null ? this.selectedCosmetic : selected;
}
for (final var entry : this.guiItemMap.entrySet()) {
final GuiItem guiItem = entry.getValue();
final ItemStack itemStack = this.itemStackMap.get(entry.getKey());
if (itemStack == null) {
continue;
}
guiItem.setItemStack(
ItemBuilder.from(itemStack.clone()).papiPlaceholders(player).build()
);
gui.setItem(entry.getKey(), guiItem);
}
for (final var entry : this.cosmeticsSlots.entrySet()) {
final ArmorItem guiItem = user.getPlayerArmor().getItem(entry.getValue()).copy();
final ItemStack itemStack = guiItem.getItemStack();
if (itemStack == null || guiItem.isEmpty()) continue;
guiItem.setItemStack(
ItemBuilder.from(
this.applyPlaceholders(
user, player, guiItem, true
)
).build()
);
gui.setItem(entry.getKey(), guiItem);
}
final PlayerArmor playerArmor = user.getPlayerArmor();
this.select(this.selectedCosmetic, user, player);
gui.setDefaultClickAction(event -> {
event.setCancelled(true);
final ArmorItem armorItem = playerArmor.getItem(
this.cosmeticsSlots.get(this.selectedCosmetic)
);
if (armorItem == null) {
return;
}
final ItemStack itemStack = playerArmor.getItem(type).getItemStack();
if (itemStack == null) {
return;
}
final int slot = event.getSlot();
final ArmorItem.Type clickedType = this.cosmeticsSlots.get(slot);
if (clickedType != null) {
this.select(slot, user, player);
return;
}
if (!armorItem.isDyeable()) {
return;
}
final GuiItem guiItem = this.guiItemMap.get(slot);
if (!(guiItem instanceof ColorItem colorItem)) {
return;
}
armorItem.setDye(colorItem.getColor().asRGB());
if (user.isWardrobeActive()) {
this.plugin.getUserManager().setItem(user.getWardrobe(), armorItem, true);
} else {
this.plugin.getUserManager().setItem(user, armorItem, true);
}
if (colorItem.getAction() != null) {
colorItem.getAction().execute(event);
}
this.updateSelected(user, player);
});
return gui;
}
private void select(final int slot, final User user, final Player player) {
final PlayerArmor playerArmor = user.getPlayerArmor();
final ArmorItem previousArmorItem = playerArmor.getItem(this.cosmeticsSlots.get(this.selectedCosmetic));
final ItemStack previous = this.applyPlaceholders(
user,
player,
previousArmorItem,
true
);
if (previous != null && !previousArmorItem.isEmpty()) {
final ItemStack previousItem = dev.triumphteam.gui.builder.item.ItemBuilder.from(
previous
).build();
this.gui.updateItem(this.selectedCosmetic, previousItem);
} else {
final GuiItem guiItem = this.guiItemMap.get(this.selectedCosmetic);
final ItemStack itemStack = this.itemStackMap.get(this.selectedCosmetic);
if (itemStack != null && guiItem != null) {
final GuiItem setItem = this.getGuiItem(
user,
player,
guiItem,
itemStack
);
if (setItem != null) this.gui.updateItem(this.selectedCosmetic, setItem);
}
}
this.selectedCosmetic = slot;
this.updateSelected(user, player);
}
private void updateSelected(final User user, final Player player) {
final ArmorItem.Type type = this.cosmeticsSlots.get(this.selectedCosmetic);
if (type == null) {
return;
}
final ArmorItem armorItem = user.getPlayerArmor().getItem(type);
if (armorItem.isEmpty()) return;
this.gui.updateItem(
this.selectedCosmetic,
ItemBuilder.from(
this.applyPlaceholders(
user, player, armorItem, true
)
).build());
}
@Override
public void open(final User user, final Player player) {
this.getGui(user, user.getLastSetItem().getType()).open(player);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public DyeSelectorGui copy() {
return new DyeSelectorGui(
this.plugin,
super.title,
super.rows,
new HashMap<>(super.guiItemMap),
HashBiMap.create(this.cosmeticsSlots),
this.selectedCosmetic
);
}
}

View File

@@ -0,0 +1,37 @@
package io.github.fisher2911.hmccosmetics.gui;
import io.github.fisher2911.hmccosmetics.util.Keys;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import java.util.List;
public class Token {
private final ItemStack itemStack;
private final ArmorItem armorItem;
private final List<String> commands;
public Token(final ItemStack itemStack, final ArmorItem armorItem, final List<String> commands) {
this.itemStack = itemStack;
this.armorItem = armorItem;
this.commands = commands;
Keys.setKey(this.itemStack, Keys.TOKEN_KEY, PersistentDataType.STRING, this.armorItem.getId());
}
public String getId() {
return this.armorItem.getId();
}
public ItemStack getItemStack() {
return itemStack;
}
public ArmorItem getArmorItem() {
return armorItem;
}
public List<String> getCommands() {
return commands;
}
}

View File

@@ -0,0 +1,145 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.guis.GuiItem;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
import io.github.fisher2911.hmccosmetics.message.Messages;
import io.github.fisher2911.hmccosmetics.message.Placeholder;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
public class TokenGui extends CosmeticGui {
private final int tokenSlot;
private final int cosmeticSlot;
private final CosmeticManager cosmeticManager;
public TokenGui(final CosmeticGui gui, final int tokenSlot, final int cosmeticSlot) {
this(gui.plugin, gui.title, gui.rows, gui.guiItemMap, tokenSlot, cosmeticSlot);
}
public TokenGui(final HMCCosmetics plugin, final String title, final int rows, final Map<Integer, GuiItem> guiItemMap, final int tokenSlot, final int cosmeticSlot) {
super(plugin, title, rows, guiItemMap);
this.tokenSlot = tokenSlot;
this.cosmeticSlot = cosmeticSlot;
this.cosmeticManager = this.plugin.getCosmeticManager();
}
@Override
public void open(final User user, final Player player) {
super.open(user, player);
this.gui.setDragAction(event -> event.setCancelled(true));
this.gui.setDefaultClickAction(event -> {
final int slot = event.getSlot();
final Inventory inventory = event.getClickedInventory();
if (inventory == null) {
event.setCancelled(true);
return;
}
final ClickType clickType = event.getClick();
if (clickType == ClickType.SHIFT_RIGHT || clickType == ClickType.SHIFT_LEFT) {
event.setCancelled(true);
return;
}
if (event.getClickedInventory().equals(event.getView().getBottomInventory())) return;
ItemStack tokenItem = event.getInventory().getItem(this.tokenSlot);
if (slot != tokenSlot && slot != this.cosmeticSlot) {
event.setCancelled(true);
if (tokenItem == null) {
inventory.setItem(this.cosmeticSlot, new ItemStack(Material.AIR));
}
return;
}
final ItemStack inHand = event.getCursor();
Token token;
if (slot == this.tokenSlot) {
if (inHand == null || inHand.getType() == Material.AIR) {
if (tokenItem != null && tokenItem.getAmount() > 1 && clickType == ClickType.RIGHT) return;
inventory.setItem(this.cosmeticSlot, new ItemStack(Material.AIR));
return;
}
token = this.cosmeticManager.getToken(inHand);
if (token == null) {
event.setCancelled(true);
return;
}
final ArmorItem item = token.getArmorItem();
inventory.setItem(this.cosmeticSlot,
this.applyPlaceholders(
user,
player,
item,
true
)
);
return;
}
if (inHand != null && inHand.getType() != Material.AIR) {
event.setCancelled(true);
return;
}
tokenItem = inventory.getItem(this.tokenSlot);
token = this.cosmeticManager.getToken(tokenItem);
if (tokenItem == null || token == null) {
event.setCancelled(true);
return;
}
final ItemStack clicked = event.getCurrentItem();
final ArmorItem armorItem = token.getArmorItem();
if (clicked == null) return;
if (user.hasPermissionToUse(armorItem)) {
this.messageHandler.sendMessage(
player,
Messages.ALREADY_UNLOCKED,
Map.of(Placeholder.ID, armorItem.getName())
);
event.setCancelled(true);
return;
}
tokenItem.setAmount(tokenItem.getAmount() - 1);
inventory.setItem(this.tokenSlot, tokenItem);
clicked.setAmount(0);
for (final String command : token.getCommands()) {
Bukkit.dispatchCommand(
Bukkit.getConsoleSender(),
command.replace(Placeholder.PLAYER, player.getName())
);
}
this.messageHandler.sendMessage(
player,
Messages.TRADED_TOKEN,
Map.of(Placeholder.ID, armorItem.getName())
);
});
this.gui.setCloseGuiAction(event -> {
final Inventory inventory = event.getInventory();
final ItemStack tokens = inventory.getItem(this.tokenSlot);
if (tokens == null) return;
event.getPlayer().getInventory().addItem(tokens);
user.setOpenGui(null);
});
}
@Override
public TokenGui copy() {
return new TokenGui(
this.plugin,
super.title,
super.rows,
new HashMap<>(super.guiItemMap),
this.tokenSlot,
this.cosmeticSlot
);
}
}

View File

@@ -0,0 +1,50 @@
package io.github.fisher2911.hmccosmetics.gui;
import dev.triumphteam.gui.components.GuiAction;
import dev.triumphteam.gui.guis.GuiItem;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class WrappedGuiItem extends GuiItem {
private GuiAction<InventoryClickEvent> action;
public WrappedGuiItem(final GuiItem item, final GuiAction<InventoryClickEvent> action) {
super(item.getItemStack(), action);
this.action = action;
}
public WrappedGuiItem(final @NotNull ItemStack itemStack, @Nullable final GuiAction<@NotNull InventoryClickEvent> action) {
super(itemStack, action);
this.action = action;
}
public WrappedGuiItem(final @NotNull ItemStack itemStack) {
super(itemStack);
this.action = null;
}
public WrappedGuiItem(final @NotNull Material material) {
super(material);
this.action = null;
}
public WrappedGuiItem(final @NotNull Material material, @Nullable final GuiAction<@NotNull InventoryClickEvent> action) {
super(material, action);
this.action = action;
}
@Nullable
public GuiAction<InventoryClickEvent> getAction() {
return action;
}
@Override
public void setAction(final GuiAction<InventoryClickEvent> action) {
super.setAction(action);
this.action = action;
}
}

View File

@@ -0,0 +1,176 @@
package io.github.fisher2911.hmccosmetics.hook;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
import io.github.fisher2911.hmccosmetics.config.Settings;
import io.github.fisher2911.hmccosmetics.database.Database;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.task.InfiniteTask;
import io.github.fisher2911.hmccosmetics.user.NPCUser;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.*;
import net.citizensnpcs.api.npc.NPC;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class CitizensHook implements Hook, Listener {
private static final String IDENTIFIER = "citizens";
private final HMCCosmetics plugin;
private final Database database;
private final Map<Integer, NPCUser> npcs = new ConcurrentHashMap<>();
public CitizensHook(final HMCCosmetics plugin) {
this.plugin = plugin;
this.database = this.plugin.getDatabase();
final Settings settings = this.plugin.getSettings();
this.plugin.getTaskManager().submit(
new InfiniteTask(() -> {
for (final NPCUser user : this.npcs.values()) {
if (!user.isValid()) {
continue;
}
user.updateOutsideCosmetics(settings);
}
})
);
}
public List<Integer> getAllNPCS() {
final Iterator<NPC> iterator = CitizensAPI.getNPCRegistry().sorted().iterator();
final List<Integer> ids = new ArrayList<>();
while (iterator.hasNext()) {
ids.add(iterator.next().getId());
}
return ids;
}
public int getCitizensId(final Entity entity) {
final NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
if (npc == null) return -1;
return npc.getId();
}
public boolean setNpcCosmetic(final int id, final ArmorItem armorItem) {
final NPC npc = CitizensAPI.getNPCRegistry().getById(id);
if (npc == null) return false;
final NPCUser user = this.npcs.get(npc.getId());
final Entity entity = npc.getEntity();
if (entity == null) return false;
if (user == null) {
Threads.getInstance().execute(() -> {
this.database.loadNPCUser(
npc.getId(),
entity,
npcUser ->
Bukkit.getScheduler().runTask(
this.plugin,
() -> {
this.npcs.put(npc.getId(), npcUser);
this.setNpcCosmetic(npcUser, armorItem);
}
)
);
});
return true;
}
return this.setNpcCosmetic(user, armorItem);
}
public boolean setNpcCosmetic(final NPCUser user, final ArmorItem armorItem) {
if (user == null) return false;
final NPC npc = this.getNPC(user.getId());
if (npc == null) return false;
if (!(npc.getEntity() instanceof final LivingEntity entity)) return false;
user.getPlayerArmor().setItem(armorItem);
final ArmorItem.Type type = armorItem.getType();
if (type != ArmorItem.Type.BACKPACK) {
entity.getEquipment().setItem(
type.getSlot(),
armorItem.getItemStack(ArmorItem.Status.APPLIED)
);
}
return true;
}
@Nullable
public NPC getNPC(final UUID uuid) {
return CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(uuid);
}
@Nullable
public NPC getNPC(final int id) {
return CitizensAPI.getNPCRegistry().getById(id);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onNpcLoad(final PlayerCreateNPCEvent event) {
this.loadNpc(event.getNPC());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onNpcLoad(final NPCSpawnEvent event) {
this.loadNpc(event.getNPC());
}
private void loadNpc(final NPC npc) {
if (Bukkit.getPlayer(npc.getUniqueId()) != null) return;
final Entity entity = npc.getEntity();
if (entity == null) return;
Bukkit.getScheduler().runTaskLater(this.plugin,
() -> Threads.getInstance().execute(() -> this.database.loadNPCUser(
npc.getId(),
entity,
user -> Bukkit.getScheduler().runTask(
this.plugin,
() -> {
this.npcs.put(npc.getId(), user);
for (final ArmorItem.Type type : ArmorItem.Type.values()) {
final ArmorItem armorItem = user.getPlayerArmor().getItem(type);
if (armorItem.isEmpty()) continue;
this.setNpcCosmetic(npc.getId(), armorItem);
}
}
)
)),
1);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onNpcUnload(final NPCDespawnEvent event) {
this.unloadNpc(event.getNPC());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onNpcUnload(final NPCRemoveEvent event) {
this.unloadNpc(event.getNPC());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onNpcUnload(final NPCDeathEvent event) {
this.unloadNpc(event.getNPC());
}
private void unloadNpc(final NPC npc) {
final NPCUser user = this.npcs.remove(npc.getId());
if (user == null) return;
user.despawnAttached();
Threads.getInstance().execute(() -> this.database.saveNPCUser(user));
}
@Override
public String getId() {
return IDENTIFIER;
}
}

View File

@@ -0,0 +1,7 @@
package io.github.fisher2911.hmccosmetics.hook;
public interface Hook {
String getId();
}

View File

@@ -0,0 +1,126 @@
package io.github.fisher2911.hmccosmetics.hook;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.hook.item.ItemHook;
import io.github.fisher2911.hmccosmetics.hook.item.ItemHooks;
import io.github.fisher2911.hmccosmetics.hook.item.ItemsAdderHook;
import io.github.fisher2911.hmccosmetics.hook.item.OraxenHook;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.Nullable;
public class HookManager {
private static final HookManager INSTANCE;
static {
INSTANCE = new HookManager(HMCCosmetics.getPlugin(HMCCosmetics.class));
}
private final HMCCosmetics plugin;
private final ItemHooks itemHooks;
private final PAPIHook papiHook;
private final CitizensHook citizensHook;
private final ModelEngineHook modelEngineHook;
private final Set<Class<? extends Hook>> registeredHooks;
private final Set<Listener> listeners;
private HookManager(final HMCCosmetics plugin) {
this.plugin = plugin;
this.registeredHooks = new HashSet<>();
this.listeners = new HashSet<>();
final PluginManager pluginManager = Bukkit.getPluginManager();
if (pluginManager.getPlugin("PlaceholderApi") != null) {
this.registeredHooks.add(PAPIHook.class);
this.papiHook = new PAPIHook();
} else {
this.papiHook = null;
}
final Map<String, ItemHook> itemHookMap = new HashMap<>();
final OraxenHook oraxenHook = new OraxenHook();
final ItemsAdderHook itemsAdderHook = new ItemsAdderHook();
final CitizensHook citizensHook = new CitizensHook(this.plugin);
if (pluginManager.getPlugin("Oraxen") != null) {
itemHookMap.put(oraxenHook.getIdentifier(), oraxenHook);
}
if (pluginManager.getPlugin("ItemsAdder") != null) {
itemHookMap.put(itemsAdderHook.getIdentifier(), itemsAdderHook);
this.listeners.add(itemsAdderHook);
}
if (pluginManager.getPlugin("Citizens") != null) {
this.citizensHook = null;
/*
this.registerHook(citizensHook.getClass());
this.listeners.add(citizensHook);
this.citizensHook = citizensHook;
this.plugin.getLogger().info("Successfully Hooked into Citizens!");
*/
} else {
this.citizensHook = null;
}
if (pluginManager.getPlugin("ModelEngine") != null) {
this.plugin.getLogger().info("ModelEngine has been detected and has been enabled.");
// 3.0 Model Engine Beta
final ModelEngineHook modelEngineHook = new ModelEngineHook();
this.registerHook(modelEngineHook.getClass());
this.modelEngineHook = modelEngineHook;
} else {
this.modelEngineHook = null;
}
this.itemHooks = new ItemHooks(itemHookMap);
itemHookMap.values().forEach(hook -> this.registerHook(hook.getClass()));
}
public static HookManager getInstance() {
return INSTANCE;
}
protected void registerHook(final Class<? extends Hook> hook) {
this.registeredHooks.add(hook);
}
public boolean isEnabled(final Class<? extends Hook> hook) {
return this.registeredHooks.contains(hook);
}
public void init() {
if (this.isEnabled(PAPIHook.class)) {
new PAPIExpansion(this.plugin).register();
}
this.registerListeners(this.plugin);
}
public void registerListeners(final HMCCosmetics plugin) {
for (final Listener listener : this.listeners) {
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
}
}
@Nullable
public PAPIHook getPapiHook() {
return papiHook;
}
@Nullable
public CitizensHook getCitizensHook() {
return this.citizensHook;
}
@Nullable
public ModelEngineHook getModelEngineHook() {
return modelEngineHook;
}
public ItemHooks getItemHooks() {
return itemHooks;
}
}

View File

@@ -0,0 +1,14 @@
package io.github.fisher2911.hmccosmetics.hook;
public class ModelEngineHook implements Hook {
public ModelEngineHook() {
}
private static final String ID = "model-engine";
@Override
public String getId() {
return ID;
}
}

View File

@@ -0,0 +1,105 @@
package io.github.fisher2911.hmccosmetics.hook;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.message.Translation;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class PAPIExpansion extends PlaceholderExpansion {
private final HMCCosmetics plugin;
private final UserManager userManager;
private static final String IDENTIFIER = "hmccosmetics";
private static final String AUTHOR = "MasterOfTheFish";
public PAPIExpansion(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
}
@Override
public @NotNull String getIdentifier() {
return IDENTIFIER;
}
@Override
public @NotNull String getAuthor() {
return AUTHOR;
}
@Override
public @NotNull String getVersion() {
return this.plugin.getDescription().getVersion();
}
@Override
public @Nullable String onPlaceholderRequest(final Player player, @NotNull final String params) {
final String[] parts = params.split("_");
if (parts.length == 0) {
return null;
}
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return null;
final User user = optionalUser.get();
// %hmccosmetics_using_id%
if (parts[0].equalsIgnoreCase("using")) {
if (parts.length < 2) return null;
final String id = this.getId(parts, 1);
for (final ArmorItem item : user.getPlayerArmor().getArmorItems()) {
if (item.getId().equals(id)) return Translation.translate(Translation.TRUE);
}
return Translation.translate(Translation.FALSE);
}
// %hmccosmetics_current_type%
if (parts[0].startsWith("current")) {
final boolean formatted = parts[0].contains("formatted");
if (parts.length >= 2) {
final String typeStr = getId(parts, 1);
try {
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeStr.toUpperCase());
for (final ArmorItem item : user.getPlayerArmor().getArmorItems()) {
if (item.getType().equals(type)) {
if (formatted) {
final String name = item.getName();
if (name.isBlank()) return item.getId().replace("_", "");
return name;
}
return item.getId();
}
}
return Translation.translate(Translation.NONE);
} catch (final IllegalArgumentException exception) {
return null;
}
}
return null;
}
if (parts[0].equals("wardrobe-enabled")) {
return Translation.translate(String.valueOf(user.getWardrobe().isActive()));
}
return null;
}
private String getId(final String[] parts, final int fromIndex) {
final StringBuilder builder = new StringBuilder();
for (int i = fromIndex; i < parts.length; i++) {
builder.append(parts[i]);
if (i < parts.length - 1) builder.append("_");
}
return builder.toString();
}
}

View File

@@ -0,0 +1,19 @@
package io.github.fisher2911.hmccosmetics.hook;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.entity.Player;
public class PAPIHook implements Hook {
private static final String ID = "PAPI";
@Override
public String getId() {
return ID;
}
public String parse(final Player player, final String string) {
return PlaceholderAPI.setPlaceholders(player, string);
}
}

View File

@@ -0,0 +1,107 @@
package io.github.fisher2911.hmccosmetics.hook.entity;
import com.ticxo.modelengine.api.ModelEngineAPI;
import com.ticxo.modelengine.api.model.ActiveModel;
import com.ticxo.modelengine.api.model.ModeledEntity;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BalloonEntity {
private final int balloonID;
private final MEGEntity megEntity;
public BalloonEntity(int balloonID, Location location) {
this.balloonID = balloonID;
this.megEntity = new MEGEntity(UUID.randomUUID(), balloonID, new Vector(0, 0, 0), location, false);
}
public void updateModel() {
final ModeledEntity model = ModelEngineAPI.api.getModeledEntity(megEntity.getUniqueId());
if (model == null) return;
if (model.getBase() instanceof final MEGEntity e) e.update(this);
}
public void spawnModel(final String id) {
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().info("Attempting Spawning");
if (ModelEngineAPI.api.getModelRegistry().getBlueprint(id) == null) {
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().warning("Invalid Model Engine Blueprint " + id);
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().warning("Possible Blueprints" + ModelEngineAPI.api.getModelRegistry().getAllBlueprintId());
return;
}
final ActiveModel model = ModelEngineAPI.api.createActiveModelImpl(ModelEngineAPI.getBlueprint(id));
ModeledEntity modeledEntity = ModelEngineAPI.api.createModeledEntityImpl(megEntity);
modeledEntity.addModel(model, false);
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().info("Spawned Model");
}
public void remove() {
final ModeledEntity entity = ModelEngineAPI.api.getModeledEntity(megEntity.getUniqueId());
if (entity == null) return;
for (final Player player : entity.getRangeManager().getPlayerInRange()) {
entity.hideFromPlayer(player);
}
//ModelEngineAPI.removeModeledEntity(megEntity.getUniqueId());
entity.destroy();
}
public void addPlayerToModel(final Player player, final String id) {
final ModeledEntity model = ModelEngineAPI.api.getModeledEntity(megEntity.getUniqueId());
if (model == null) {
this.spawnModel(id);
return;
}
if (megEntity.getRangeManager().getPlayerInRange().contains(player)) return;
model.showToPlayer(player);
HMCCosmetics.getPlugin(HMCCosmetics.class).getLogger().info("Added " + player.getName() + " to " + id);
}
public void removePlayerFromModel(final Player player) {
final ModeledEntity model = ModelEngineAPI.api.getModeledEntity(megEntity.getUniqueId());
if (model == null) return;
model.hideFromPlayer(player);
}
public int getBalloonID() {
return balloonID;
}
public UUID getUniqueID() {
return megEntity.getUniqueId();
}
public Location getLocation() {
return this.megEntity.getLocation();
}
public boolean isAlive() {
return this.megEntity.isAlive();
}
public void setLocation(Location location) {
this.megEntity.setLocation(location);
}
public void setVelocity(Vector vector) {
this.megEntity.setVelocity(vector);
}
public void setAlive(boolean alive) {
this.megEntity.setAlive(alive);
}
}

View File

@@ -0,0 +1,242 @@
package io.github.fisher2911.hmccosmetics.hook.entity;
import com.ticxo.modelengine.api.entity.BaseEntity;
import com.ticxo.modelengine.api.generator.Hitbox;
import com.ticxo.modelengine.api.model.IModel;
import com.ticxo.modelengine.api.nms.entity.impl.DefaultBodyRotationController;
import com.ticxo.modelengine.api.nms.entity.impl.EmptyRangeManager;
import com.ticxo.modelengine.api.nms.entity.impl.ManualRangeManager;
import com.ticxo.modelengine.api.nms.entity.wrapper.BodyRotationController;
import com.ticxo.modelengine.api.nms.entity.wrapper.LookController;
import com.ticxo.modelengine.api.nms.entity.wrapper.MoveController;
import com.ticxo.modelengine.api.nms.entity.wrapper.RangeManager;
import com.ticxo.modelengine.api.nms.world.IDamageSource;
import com.ticxo.modelengine.api.utils.data.EntityData;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MEGEntity implements BaseEntity {
private final UUID uuid;
private final int entityId;
private Vector velocity = new Vector(0, 0, 0);
private Location location;
private boolean alive;
private BodyRotationController rotationController;
private List<Entity> passengers;
private RangeManager rangeManager;
protected MEGEntity(final UUID uuid, final int entityId, final Vector velocity, final Location location, final boolean alive) {
this.uuid = uuid;
this.entityId = entityId;
this.velocity = velocity;
this.location = location;
this.alive = alive;
this.rotationController = new DefaultBodyRotationController(this);
this.passengers = new ArrayList<>();
this.rangeManager = new EmptyRangeManager();
this.rangeManager.setRenderDistance(16);
}
protected MEGEntity(final UUID uuid, final int entityId) {
this.uuid = uuid;
this.entityId = entityId;
this.alive = false;
}
public void update(final BalloonEntity entity) {
this.velocity = entity.getLocation().toVector();
this.location = entity.getLocation();
this.alive = entity.isAlive();
}
public void setVelocity(final Vector velocity) {
this.velocity = velocity;
}
public void setLocation(final Location location) {
this.location = location;
}
public void setAlive(final boolean alive) {
this.alive = alive;
}
public boolean isAlive() {
return alive;
}
public EntityData getEntityData() {
return entityData;
}
final EntityData entityData = new EntityData();
@Override
public Object getOriginal() {
return null;
}
@Override
public MoveController wrapMoveControl() {
return null;
}
@Override
public LookController wrapLookControl() {
return null;
}
@Override
public BodyRotationController wrapBodyRotationControl() {
return this.rotationController;
}
@Override
public void wrapNavigation() {
}
@Override
public RangeManager wrapRangeManager(IModel model) {
return new ManualRangeManager(this, model);
}
@Override
public RangeManager getRangeManager() {
if (this.rangeManager == null) {
RangeManager rangeMan = new EmptyRangeManager();
rangeMan.setRenderDistance(16);
return rangeMan;
}
return this.rangeManager;
}
@Override
public boolean onHurt(IDamageSource damageSource, float damage) {
return false;
}
@Override
public void onInteract(Player player, EquipmentSlot hand) {
}
@Override
public void setHitbox(Hitbox hitbox) {
}
@Override
public Hitbox getHitbox() {
return null;
}
@Override
public void setStepHeight(double height) {
}
@Override
public Double getStepHeight() {
return null;
}
@Override
public void setCollidableToLiving(LivingEntity living, boolean isRemove) {
}
@Override
public void broadcastSpawnPacket() {
}
@Override
public void broadcastDespawnPacket() {
}
@Override
public int getEntityId() {
return this.entityId;
}
@Override
public UUID getUniqueId() {
return this.uuid;
}
@Override
public Location getLocation() {
return location;
}
@Override
public World getWorld() {
return this.getWorld();
}
@Override
public boolean isDead() {
return alive;
}
@Override
public boolean isGlowing() {
return false;
}
@Override
public boolean isOnGround() {
return false;
}
@Override
public boolean isMoving() {
return false;
}
@Override
public void setYHeadRot(float rot) {
}
@Override
public float getYHeadRot() {
return 0;
}
@Override
public float getXHeadRot() {
return 0;
}
@Override
public void setYBodyRot(float rot) {
}
@Override
public float getYBodyRot() {
return 0;
}
@Override
public List<Entity> getPassengers() {
return this.passengers;
}
public Vector getVelocity() {
return velocity;
}
}

View File

@@ -0,0 +1,11 @@
package io.github.fisher2911.hmccosmetics.hook.item;
import io.github.fisher2911.hmccosmetics.hook.Hook;
import org.bukkit.inventory.ItemStack;
public interface ItemHook extends Hook {
String getIdentifier();
ItemStack getItem(final String id);
}

View File

@@ -0,0 +1,42 @@
package io.github.fisher2911.hmccosmetics.hook.item;
import java.util.Map;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public class ItemHooks {
private final Map<String, ItemHook> itemHookMap;
public ItemHooks(final Map<String, ItemHook> itemHookMap) {
this.itemHookMap = itemHookMap;
}
@Nullable
public ItemStack getItemStack(final String item) {
final String[] parts = item.split(":");
if (parts.length < 2) {
return null;
}
final String identifier = parts[0];
final StringBuilder itemId = new StringBuilder();
for (int i = 1; i < parts.length; i++) {
itemId.append(parts[i]);
if (i < parts.length - 1) {
itemId.append(":");
}
}
final ItemHook hook = this.itemHookMap.get(identifier);
if (hook == null) {
return null;
}
return hook.getItem(itemId.toString());
}
}

View File

@@ -0,0 +1,41 @@
package io.github.fisher2911.hmccosmetics.hook.item;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
public class ItemsAdderHook implements ItemHook, Listener {
public static final String ID = "ITEM_ADDER";
private static final String IDENTIFIER = "itemsadder";
@EventHandler
public void onItemsAdderLoad(final ItemsAdderLoadDataEvent event) {
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
Bukkit.getScheduler().runTaskAsynchronously(plugin, plugin::load);
}
@Override
public String getId() {
return ID;
}
@Override
public String getIdentifier() {
return IDENTIFIER;
}
@Override
public ItemStack getItem(final String id) {
final CustomStack stack = CustomStack.getInstance(id);
if (stack == null) {
return null;
}
return stack.getItemStack().clone();
}
}

View File

@@ -0,0 +1,31 @@
package io.github.fisher2911.hmccosmetics.hook.item;
import io.th0rgal.oraxen.items.ItemBuilder;
import io.th0rgal.oraxen.items.OraxenItems;
import org.bukkit.inventory.ItemStack;
public class OraxenHook implements ItemHook {
public static final String ID = "ORAXEN";
private static final String IDENTIFIER = "oraxen";
@Override
public String getId() {
return ID;
}
@Override
public String getIdentifier() {
return IDENTIFIER;
}
@Override
public ItemStack getItem(final String id) {
final ItemBuilder itemBuilder = OraxenItems.getItemById(id);
if (itemBuilder == null) {
return null;
}
return itemBuilder.build();
}
}

View File

@@ -0,0 +1,75 @@
package io.github.fisher2911.hmccosmetics.inventory;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
public class PlayerArmor {
private final Map<ArmorItem.Type, ArmorItem> armorItems;
public PlayerArmor(ArmorItem hat, final ArmorItem backpack, final ArmorItem offHand) {
this.armorItems = new EnumMap<>(ArmorItem.Type.class);
this.armorItems.put(hat.getType(), hat);
this.armorItems.put(backpack.getType(), hat);
this.armorItems.put(offHand.getType(), offHand);
}
public PlayerArmor(final Map<ArmorItem.Type, ArmorItem> armorItems) {
this.armorItems = armorItems;
}
public static PlayerArmor empty() {
return new PlayerArmor(
ArmorItem.empty(ArmorItem.Type.HAT),
ArmorItem.empty(ArmorItem.Type.BACKPACK),
ArmorItem.empty(ArmorItem.Type.OFF_HAND)
);
}
public ArmorItem getHat() {
return this.getItem(ArmorItem.Type.HAT);
}
// public ArmorItem getBackpack() {
// return this.getItem(ArmorItem.Type.BACKPACK);
// }
public ArmorItem getOffHand() {
return this.getItem(ArmorItem.Type.OFF_HAND);
}
public ArmorItem getItem(final ArmorItem.Type type) {
ArmorItem armorItem = this.armorItems.get(type);
if (armorItem == null) {
armorItem = ArmorItem.empty(type);
this.armorItems.put(type, armorItem);
}
return armorItem;
}
public ArmorItem setItem(final ArmorItem armorItem) {
if (armorItem.isEmpty() && armorItem.getType() == ArmorItem.Type.BACKPACK) {
this.armorItems.put(ArmorItem.Type.SELF_BACKPACK, armorItem);
}
return this.armorItems.put(armorItem.getType(), armorItem);
}
public Collection<ArmorItem> getArmorItems() {
return this.armorItems.values();
}
public PlayerArmor copy() {
return new PlayerArmor(new HashMap<>(this.armorItems));
}
public void clear() {
for (final ArmorItem.Type type : ArmorItem.Type.values()) {
this.setItem(ArmorItem.empty(type));
}
}
}

View File

@@ -0,0 +1,151 @@
package io.github.fisher2911.hmccosmetics.listener;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.user.Equipment;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.*;
public class ClickListener implements Listener {
private final HMCCosmetics plugin;
private final UserManager userManager;
final Map<EquipmentSlot, Set<Material>> ARMOR_ITEMS = Map.of(
EquipmentSlot.HEAD, EnumSet.of(
Material.LEATHER_HELMET,
Material.CHAINMAIL_HELMET,
Material.IRON_HELMET,
Material.GOLDEN_HELMET,
Material.DIAMOND_HELMET,
Material.NETHERITE_HELMET,
Material.TURTLE_HELMET
),
EquipmentSlot.CHEST, EnumSet.of(
Material.LEATHER_CHESTPLATE,
Material.CHAINMAIL_CHESTPLATE,
Material.IRON_CHESTPLATE,
Material.GOLDEN_CHESTPLATE,
Material.DIAMOND_CHESTPLATE,
Material.NETHERITE_CHESTPLATE,
Material.ELYTRA
),
EquipmentSlot.LEGS, EnumSet.of(
Material.LEATHER_LEGGINGS,
Material.CHAINMAIL_LEGGINGS,
Material.IRON_LEGGINGS,
Material.GOLDEN_LEGGINGS,
Material.DIAMOND_LEGGINGS,
Material.NETHERITE_LEGGINGS
),
EquipmentSlot.FEET, EnumSet.of(
Material.LEATHER_BOOTS,
Material.CHAINMAIL_BOOTS,
Material.IRON_BOOTS,
Material.GOLDEN_BOOTS,
Material.DIAMOND_BOOTS,
Material.NETHERITE_BOOTS
)
);
public ClickListener(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
}
/*
@EventHandler
public void onArmorSlotClick(final InventoryClickEvent event) {
final int slot = event.getSlot();
if (!(event.getWhoClicked() instanceof Player)) return;
if (slot >= 36 && slot <= 40) {
this.fixInventory(((Player) event.getWhoClicked()).getPlayer());
}
}
*/
//
// @EventHandler
// public void onBlockClick(final PlayerInteractEvent event) {
// if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
// final Player player = event.getPlayer();
// final Block block = event.getClickedBlock();
// if (block != null && block.getType().isInteractable() && !player.isSneaking()) return;
// final ItemStack clickedWith = event.getItem();
// if (clickedWith == null) return;
// this.checkFix(player, -1, clickedWith);
// }
//
// @EventHandler
// public void onShiftClick(final InventoryClickEvent event) {
// if (event.getClick() != ClickType.SHIFT_LEFT &&
// event.getClick() != ClickType.SHIFT_RIGHT) return;
// if (!(event.getWhoClicked() instanceof final Player player)) return;
// final ItemStack clicked = event.getCurrentItem();
// if (clicked == null) return;
// this.checkFix(player, -1, clicked);
// }
//
// @EventHandler
// public void onCosmeticClick(final InventoryDragEvent event) {
// final HumanEntity player = event.getWhoClicked();
// if (!(player instanceof Player)) {
// return;
// }
//// this.fixInventory((Player) player);
// }
//
// @EventHandler
// public void onInventoryClose(final InventoryCloseEvent event) {
// final HumanEntity player = event.getPlayer();
// this.userManager.get(player.getUniqueId()).ifPresent(this::doRunnable);
// }
//
/*
private void fixInventory(final Player player) {
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) {
return;
}
this.doRunnable(optionalUser.get());
}
private void doRunnable(final User user) {
Equipment equip = this.userManager.getItemList(user, user.getEquipment(), Collections.emptySet());
Bukkit.getScheduler().runTaskLaterAsynchronously(
this.plugin, () -> this.userManager.sendUpdatePacket(user, equip),
1);
}
*/
// private void checkFix(final Player player, final int clickedSlot, final ItemStack itemStack) {
// final EquipmentSlot slot = this.getArmorSlot(itemStack.getType());
// if (slot == null) return;
// final ItemStack wearing = player.getEquipment().getItem(slot);
// if (wearing == null) return;
// if (wearing.getType() == Material.AIR || (clickedSlot >= 39 && clickedSlot <= 40)) {
// this.fixInventory(player);
// }
// }
//
// @Nullable
// private EquipmentSlot getArmorSlot(final Material material) {
// for (final EquipmentSlot slot : EquipmentSlot.values()) {
// final Set<Material> armorItems = ARMOR_ITEMS.get(slot);
// if (armorItems == null) continue;
// if (material == null) continue;
// if (armorItems.contains(material)) return slot;
// }
// return null;
// }
}

View File

@@ -0,0 +1,376 @@
package io.github.fisher2911.hmccosmetics.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.CosmeticSettings;
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
import io.github.fisher2911.hmccosmetics.packet.wrappers.WrapperPlayClientWindowClick;
import io.github.fisher2911.hmccosmetics.packet.wrappers.WrapperPlayServerWindowItems;
import io.github.fisher2911.hmccosmetics.task.DelayedTask;
import io.github.fisher2911.hmccosmetics.task.TaskManager;
import io.github.fisher2911.hmccosmetics.user.Equipment;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import io.github.fisher2911.hmccosmetics.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.logging.Level;
public class CosmeticFixListener implements Listener {
private final HMCCosmetics plugin;
private final UserManager userManager;
private final CosmeticSettings settings;
private final TaskManager taskManager;
public CosmeticFixListener(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
this.settings = this.plugin.getSettings().getCosmeticSettings();
this.taskManager = this.plugin.getTaskManager();
this.registerPacketListeners();
}
final Map<EquipmentSlot, Set<Material>> ARMOR_ITEMS = Map.of(
EquipmentSlot.HEAD, EnumSet.of(
Material.LEATHER_HELMET,
Material.CHAINMAIL_HELMET,
Material.IRON_HELMET,
Material.GOLDEN_HELMET,
Material.DIAMOND_HELMET,
Material.NETHERITE_HELMET,
Material.TURTLE_HELMET
),
EquipmentSlot.CHEST, EnumSet.of(
Material.LEATHER_CHESTPLATE,
Material.CHAINMAIL_CHESTPLATE,
Material.IRON_CHESTPLATE,
Material.GOLDEN_CHESTPLATE,
Material.DIAMOND_CHESTPLATE,
Material.NETHERITE_CHESTPLATE,
Material.ELYTRA
),
EquipmentSlot.LEGS, EnumSet.of(
Material.LEATHER_LEGGINGS,
Material.CHAINMAIL_LEGGINGS,
Material.IRON_LEGGINGS,
Material.GOLDEN_LEGGINGS,
Material.DIAMOND_LEGGINGS,
Material.NETHERITE_LEGGINGS
),
EquipmentSlot.FEET, EnumSet.of(
Material.LEATHER_BOOTS,
Material.CHAINMAIL_BOOTS,
Material.IRON_BOOTS,
Material.GOLDEN_BOOTS,
Material.DIAMOND_BOOTS,
Material.NETHERITE_BOOTS
)
);
public void registerPacketListeners() {
this.registerMenuChangeListener();
this.registerInventoryClickListener();
}
@EventHandler
public void onHoldItem(final PlayerItemHeldEvent event) {
this.userManager.get(event.getPlayer().getUniqueId()).ifPresent(user -> {
if (user.isWardrobeActive()) event.setCancelled(true);
});
}
@EventHandler
public void onShiftClick(final InventoryClickEvent event) {
if (event.getClick() != ClickType.SHIFT_LEFT && event.getClick() != ClickType.SHIFT_RIGHT) return;
if (!(event.getWhoClicked() instanceof final Player player)) return;
final ItemStack clicked = event.getCurrentItem();
if (clicked == null) return;
final EquipmentSlot slot = this.getArmorSlot(clicked.getType());
if (slot == null) return;
final Optional<User> user = this.userManager.get(player.getUniqueId());
if (user.isEmpty()) return;
final ArmorItem.Type type = ArmorItem.Type.fromWrapper(slot);
if (type == null) return;
this.taskManager.submit(() -> {
final EntityEquipment equipment = player.getEquipment();
final ItemStack current;
if (equipment == null) {
current = new ItemStack(Material.AIR);
} else {
current = equipment.getItem(slot);
}
updateOnClick(
player,
slot,
user.get(),
type,
current
);
});
}
private void registerInventoryClickListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmetics.getPlugin(HMCCosmetics.class), ListenerPriority.NORMAL, PacketType.Play.Client.WINDOW_CLICK) {
@Override
public void onPacketReceiving(PacketEvent event) {
Player player = event.getPlayer();
int invTypeClicked = event.getPacket().getIntegers().read(0);
int slotClicked = event.getPacket().getIntegers().read(2);
// Must be a player inventory.
if (invTypeClicked != 0) return;
// -999 is when a player clicks outside their inventory. https://wiki.vg/Inventory#Player_Inventory
if (slotClicked == -999) return;
if (!(event.getPlayer() instanceof Player)) return;
taskManager.submit(() -> {
final Optional<User> optionalUser = userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
EquipmentSlot slot = getPacketArmorSlot(slotClicked);
if (slot == null) {
return;
}
final EntityEquipment entityEquipment = player.getEquipment();
if (entityEquipment == null) return;
final ItemStack current = Utils.replaceIfNull(entityEquipment.getItem(slot), new ItemStack(Material.AIR));
final ArmorItem.Type type = ArmorItem.Type.fromEquipmentSlot(slot);
if (type == null) return;
updateOnClick(
player,
slot,
user,
type,
current
);
});
}
});
}
private void updateOnClick(final Player player, final EquipmentSlot slot, final User user, final ArmorItem.Type type, final ItemStack current) {
//plugin.getLogger().log(Level.INFO, "updateOnClick (171)");
final Location location = player.getLocation();
final Equipment equipment = new Equipment();
final ItemStack cosmetic = userManager.getCosmeticItem(
user.getPlayerArmor().getItem(type),
current,
ArmorItem.Status.APPLIED,
slot
);
//plugin.getLogger().log(Level.INFO, "Set cosmetic in " + slot + " to " + cosmetic);
if (cosmetic != null && cosmetic.getType() != Material.AIR) equipment.setItem(slot, cosmetic);
//plugin.getLogger().log(Level.INFO, "Set cosmetic in " + slot + " to " + cosmetic + "(done)");
/*
final Equipment items = userManager.getItemList(user, equipment, Collections.emptySet());
for (EquipmentSlot e : items.keys()) {
//final EquipmentSlot s = e.getSlot();
final ArmorItem.Type t = ArmorItem.Type.fromWrapper(e);
ItemStack air = new ItemStack(Material.AIR);
if (t == null) {
//plugin.getLogger().log(Level.INFO, "T is null");
equipment.setItem(e, air);
return;
}
final ArmorItem armorItem = user.getPlayerArmor().getItem(t);
final ItemStack i = equipment.getItem(e);
if (i == null) {
//plugin.getLogger().log(Level.INFO, "I is null");
equipment.setItem(e, air);
return;
}
Boolean remove = armorItem.isEmpty() && i.equals(equipment.getItem(t.getSlot()));
if (remove) {
//plugin.getLogger().log(Level.INFO, "Boolean is true");
equipment.setItem(e, air);
return;
}
return;
}
*/
for (final Player other : Bukkit.getOnlinePlayers()) {
if (!settings.isInViewDistance(location, other.getLocation())) continue;
userManager.sendUpdatePacket(
user,
equipment
);
}
}
private void registerMenuChangeListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmetics.getPlugin(HMCCosmetics.class), ListenerPriority.NORMAL, PacketType.Play.Server.WINDOW_ITEMS) {
@Override
public void onPacketSending(PacketEvent event) {
Player player = event.getPlayer();
if (event.getPlayer() == null) return;
WrapperPlayServerWindowItems wrapper = new WrapperPlayServerWindowItems(event.getPacket());
if (!(event.getPlayer() instanceof Player)) return;
final int windowId = wrapper.getWindowId();
List<ItemStack> items = wrapper.getSlotData();
taskManager.submit(() -> {
final Optional<User> optionalUser = userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
if (windowId != 0) return;
final int size = items.size();
final PlayerArmor playerArmor = user.getPlayerArmor();
final Equipment equip = userManager.getItemList(user);
for (final ArmorItem armorItem : playerArmor.getArmorItems()) {
final ArmorItem.Type type = armorItem.getType();
final EquipmentSlot slot = type.getSlot();
if (slot == null) continue;
final int packetSlot = getPacketArmorSlot(slot);
if (packetSlot == -1) continue;
if (packetSlot >= size) continue;
final ItemStack current = (items.get(packetSlot));
final ItemStack setTo =
(userManager.getCosmeticItem(
armorItem,
current,
ArmorItem.Status.APPLIED,
slot
));
if ((current).equals(setTo)) continue;
equip.setItem(slot, setTo);
}
userManager.sendUpdatePacket(
user,
equip
);
});
}
});
}
private int getPacketArmorSlot(final EquipmentSlot slot) {
return switch (slot) {
case HEAD -> 5;
case CHEST -> 6;
case LEGS -> 7;
case FEET -> 8;
case OFF_HAND -> 45;
default -> -1;
};
}
@Nullable
public EquipmentSlot getPacketArmorSlot(final int slot) {
return switch (slot) {
case 5 -> EquipmentSlot.HEAD;
case 6 -> EquipmentSlot.CHEST;
case 7 -> EquipmentSlot.LEGS;
case 8 -> EquipmentSlot.FEET;
case 45 -> EquipmentSlot.OFF_HAND;
default -> null;
};
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onOffhandSwap(final PlayerSwapHandItemsEvent event) {
final ItemStack offHand = event.getOffHandItem();
if (offHand != null && offHand.getType() != Material.AIR) {
return;
}
final Player player = event.getPlayer();
this.fixOffHand(player, new ItemStack(Material.AIR));
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onBlockPlace(final BlockPlaceEvent event) {
if (event.getHand() != EquipmentSlot.OFF_HAND) {
return;
}
final ItemStack itemStack = event.getItemInHand();
if (itemStack.getAmount() > 1) {
return;
}
this.fixOffHand(event.getPlayer(), new ItemStack(Material.AIR));
}
// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
// public void onShiftInventoryClick(final InventoryClickEvent event) {
// final ClickType clickType = event.getClick();
// if (clickType != ClickType.SHIFT_LEFT && clickType != ClickType.SHIFT_RIGHT) return;
// final ItemStack clicked = event.getCurrentItem();
// if (clicked == null || clicked.getType() == Material.AIR) return;
// final EquipmentSlot slot = this.getArmorSlot(clicked.getType());
// if (slot == null) return;
// if (!(event.getWhoClicked() instanceof final Player player)) return;
// final EntityEquipment entityEquipment = player.getEquipment();
// if (entityEquipment == null) return;
// final Equipment equipment = Equipment.fromEntityEquipment(entityEquipment);
// final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
// if (optionalUser.isEmpty()) return;
// final User user = optionalUser.get();
// player.sendMessage("Sent update packet in listener");
// final var itemList = this.getItemList(user, equipment, Collections.emptySet());
// this.taskManager.submit(() -> this.userManager.sendUpdatePacket(
// player.getEntityId(),
// player,
// itemList
// ));
// }
private void fixOffHand(final Player player, final ItemStack current) {
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
if (optionalUser.isEmpty()) return;
final User user = optionalUser.get();
final ArmorItem.Type type = ArmorItem.Type.OFF_HAND;
final ArmorItem armorItem = user.getPlayerArmor().getItem(type);
this.taskManager.submit(new DelayedTask(() -> this.userManager.sendUpdatePacket(
user,
armorItem,
current,
type
), 1));
}
@Nullable
private EquipmentSlot getArmorSlot(final Material material) {
for (final EquipmentSlot slot : EquipmentSlot.values()) {
final Set<Material> armorItems = ARMOR_ITEMS.get(slot);
if (armorItems == null) continue;
if (material == null) continue;
if (armorItems.contains(material)) return slot;
}
return null;
}
/*
private void fixCosmetics(final Player player) {
Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin,
() -> this.userManager.updateCosmetics(player.getUniqueId()), 2);
}
*/
}

View File

@@ -0,0 +1,75 @@
package io.github.fisher2911.hmccosmetics.listener;
import com.comphenix.protocol.ProtocolLibrary;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.config.WardrobeSettings;
import io.github.fisher2911.hmccosmetics.database.Database;
import io.github.fisher2911.hmccosmetics.task.TaskChain;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitScheduler;
import java.util.Optional;
public class JoinListener implements Listener {
private final HMCCosmetics plugin;
private final Database database;
private final UserManager userManager;
public JoinListener(final HMCCosmetics plugin) {
this.plugin = plugin;
this.database = this.plugin.getDatabase();
this.userManager = this.plugin.getUserManager();
}
@EventHandler
public void onJoin(final PlayerJoinEvent event) {
final Player player = event.getPlayer();
this.database.loadUser(
player,
user -> new TaskChain(this.plugin).chain(
() -> this.userManager.add(user)
).chain(() -> {
final WardrobeSettings settings = this.plugin.getSettings().getWardrobeSettings();
if (settings.isAlwaysDisplay() && settings.getWardrobeLocation() != null) {
final Wardrobe wardrobe = user.getWardrobe();
wardrobe.setCurrentLocation(settings.getWardrobeLocation());
wardrobe.spawnFakePlayer(player);
}
// and finally, resend the cosmetics
Bukkit.getScheduler().runTaskLaterAsynchronously(HMCCosmetics.getPlugin(HMCCosmetics.class),
() -> {
this.userManager.updateCosmetics(user);
}, 20);
}, true).execute());
}
@EventHandler
public void onQuit(final PlayerQuitEvent event) {
final Player player = event.getPlayer();
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
optionalUser.ifPresent(user -> {
final Wardrobe wardrobe = user.getWardrobe();
user.despawnAttached();
user.despawnBalloon();
if (wardrobe.isActive()) {
Bukkit.getScheduler().runTaskAsynchronously(
this.plugin,
() -> wardrobe.despawnFakePlayer(player, userManager)
);
}
});
this.userManager.remove(player.getUniqueId());
}
}

View File

@@ -0,0 +1,46 @@
package io.github.fisher2911.hmccosmetics.listener;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.message.Messages;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import java.util.Optional;
public class PlayerShiftListener implements Listener {
private final HMCCosmetics plugin;
private final UserManager userManager;
public PlayerShiftListener(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
}
@EventHandler
public void onPlayerShift(final PlayerToggleSneakEvent event) {
final Player player = event.getPlayer();
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
if (!event.isSneaking()) return;
if (userOptional.isEmpty()) return;
final User user = userOptional.get();
final Wardrobe wardrobe = user.getWardrobe();
if (!wardrobe.isActive()) return;
wardrobe.despawnFakePlayer(player, userManager);
this.plugin.getSettings().getWardrobeSettings().playCloseSound(player);
this.plugin.getMessageHandler().sendMessage(
player,
Messages.CLOSED_WARDROBE
);
}
}

View File

@@ -26,8 +26,11 @@ public class RespawnListener implements Listener {
Bukkit.getScheduler().runTaskLater(this.plugin, () -> {
final Player player = event.getPlayer();
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
optionalUser.ifPresent(user -> user.setHat(user.getPlayerArmor().getHat(), this.userManager));
optionalUser.ifPresent(user -> {
user.despawnAttached();
this.userManager.updateCosmetics(user);
});
}, 1);
}
}

View File

@@ -1,12 +1,12 @@
package io.github.fisher2911.hmccosmetics.listener;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.user.User;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
public class TeleportListener implements Listener {
@@ -23,7 +23,20 @@ public class TeleportListener implements Listener {
public void onPlayerTeleport(final PlayerTeleportEvent event) {
final Player player = event.getPlayer();
this.userManager.get(player.getUniqueId()).ifPresent(User::despawnAttached);
this.userManager.get(player.getUniqueId()).ifPresent(user -> {
user.despawnAttached();
user.despawnBalloon();
});
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerDeath(final PlayerDeathEvent event) {
final Player player = event.getEntity();
this.userManager.get(player.getUniqueId()).ifPresent(user -> {
user.despawnAttached();
user.despawnBalloon();
});
}
}

View File

@@ -0,0 +1,48 @@
package io.github.fisher2911.hmccosmetics.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
import io.github.fisher2911.hmccosmetics.user.UserManager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
public class WardrobeListener implements Listener {
private final HMCCosmetics plugin;
private final UserManager userManager;
public WardrobeListener(final HMCCosmetics plugin) {
this.plugin = plugin;
this.userManager = this.plugin.getUserManager();
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmetics.getPlugin(HMCCosmetics.class), ListenerPriority.NORMAL, PacketType.Play.Client.ARM_ANIMATION) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (!(event.getPlayer() instanceof Player)) return;
Player player = event.getPlayer();
WardrobeListener.this.userManager.get(player.getUniqueId()).ifPresent(user -> {
if (!user.getWardrobe().isActive()) return;
Bukkit.getScheduler().runTask(plugin, () -> {
WardrobeListener.this.plugin.getCosmeticsMenu().openDefault(player);
});
}
);
}
});
}
@EventHandler
public void onDamage(final EntityDamageEvent event) {
if (!(event.getEntity() instanceof final Player player)) return;
this.userManager.get(player.getUniqueId()).ifPresent(user -> {
if (user.isWardrobeActive()) event.setCancelled(true);
});
}
}

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