262 Commits
Author SHA1 Message Date
XiaoMoMi 0387b30149 add option to force sync tags 2026-04-19 01:24:00 +08:00
XiaoMoMi 797b77c529 26.1 support 2026-04-19 01:02:09 +08:00
XiaoMoMi 2e689cabb1 fix possible NPE 2026-04-17 01:19:48 +08:00
XiaoMoMi 52f244ddf3 fix none uuid 2026-03-26 00:28:13 +08:00
XiaoMoMi 6c0a8d2788 fix cannot find player on typewrite event end 2026-03-24 01:18:59 +08:00
XiaoMoMi 0d75def1b6 add &# hex color support 2026-03-18 22:56:10 +08:00
XiaoMoMi f3c297f6d4 add newline support for calculateTextAdvance 2026-03-16 00:51:40 +08:00
XiaoMoMi ec6ff01e24 change the sequence of arguments 2026-03-10 18:19:56 +08:00
XiaoMoMi 45f8f4fcd4 3.0.38 2026-03-10 18:04:36 +08:00
XiaoMoMi 2f6beff060 add luckperms comaptibility 2026-03-10 18:00:04 +08:00
XiaoMoMi cef568b0b0 Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2026-03-10 17:47:25 +08:00
XiaoMoMi 49fa5d167b add custom command suggestion for bubbles and nameplates 2026-03-10 17:47:22 +08:00
XiaoMoMi d6bd4a1574 Merge pull request #83 from Flestiz/main
Fix ECosmetics support
2026-03-09 20:59:56 +08:00
Flestiz 67a97411b8 Fix ECosmetics support 2026-03-09 00:53:03 +03:00
XiaoMoMi 4a4d1fe979 Merge pull request #80 from jhqwqmc/patch-1
修复hmcc切换帽子高度应用错误
2026-02-22 11:33:30 +08:00
jhqwqmc d106c96280 修复hmcc切换帽子高度应用错误 2026-02-22 00:15:37 +08:00
XiaoMoMi 52331421be should use getDouble 2026-02-16 23:17:46 +08:00
XiaoMoMi 6c38fc03cc 修复竞态下id计数错误 Fix the ID counting error under race conditions. 2026-01-28 20:06:51 +08:00
XiaoMoMi aaf4beead4 fix shift_y 2026-01-21 18:46:20 +08:00
XiaoMoMi 8fb63a90be Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2026-01-17 02:26:17 +08:00
XiaoMoMi bc83aa46c5 zelchat 2026-01-17 02:26:13 +08:00
XiaoMoMi fcc6d2bdc5 Merge pull request #77 from jhqwqmc/main
添加HMCCosmetics支持
2026-01-15 22:37:24 +08:00
jhqwqmc 83f6a0139f 修改为hat-height键 2026-01-15 21:57:22 +08:00
jhqwqmc 9b74a7bb59 添加HMCCosmetics支持 2026-01-15 21:42:45 +08:00
XiaoMoMi 22c5c61144 Merge pull request #75 from mrjimin/main
add ko_kr
2026-01-15 02:15:18 +08:00
mrjimin 741e043b17 add ko_kr 2026-01-14 23:16:58 +09:00
XiaoMoMi a4e730890a try adding ZelChat compatibility 2026-01-12 22:20:07 +08:00
XiaoMoMi 19e30bc29b remove eventLoop.submit 2025-12-29 19:27:24 +08:00
XiaoMoMi 1e5e3bea2c Update BukkitCustomNameplates.java 2025-12-28 02:49:23 +08:00
XiaoMoMi 8e1ba461a6 fix null tracker 2025-12-20 04:07:45 +08:00
XiaoMoMi d573c9063b Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2025-12-18 03:56:31 +08:00
XiaoMoMi e2a5a5564f Update pack.mcmeta 2025-12-18 03:56:29 +08:00
XiaoMoMi 1a2a689c4c Merge pull request #73 from Hokiib/main
patch unknown repository
2025-12-15 22:12:21 +08:00
Hokiib 4be6e27bc1 patch unknown repository 2025-12-14 20:30:26 +01:00
XiaoMoMi efae3f62d6 1.21.11 2025-12-12 17:14:14 +08:00
XiaoMoMi 0f4af0938b fix carbonchat hook 2025-11-22 03:23:40 +08:00
XiaoMoMi 72b1dc8513 Update TagRendererImpl.java 2025-11-19 21:44:58 +08:00
XiaoMoMi c695226515 fix passengers on folia 2025-11-14 14:31:01 +08:00
XiaoMoMi 084f7d1edf fixed is see through 2025-10-16 03:18:18 +08:00
XiaoMoMi dafe373f81 Update gradle.properties 2025-10-15 01:55:32 +08:00
XiaoMoMi e405d1c4f1 improve rendering 2025-10-15 01:37:47 +08:00
XiaoMoMi d9ee1bbb21 1.21.10 2025-10-14 00:43:57 +08:00
XiaoMoMi 8a4b0e1c23 catch more errors 2025-09-28 02:57:50 +08:00
XiaoMoMi d9d129cd97 Update custom-placeholders.yml 2025-09-09 22:34:13 +08:00
XiaoMoMi 12060e9b59 Update NameplatesExtraExpansion.java 2025-09-07 20:28:09 +08:00
XiaoMoMi 491ad32466 fix name() NPE 2025-09-07 03:33:00 +08:00
XiaoMoMi 7932423628 Merge pull request #67 from iqtesterr/main
Add ECosmetics Support
2025-08-21 20:57:13 +08:00
iqtester 2036b13524 Add ECosmetics Support 2025-08-20 17:09:41 -04:00
XiaoMoMi 99a9afb1c7 update itemsadder api version 2025-08-08 03:01:01 +08:00
XiaoMoMi 486b96d232 Update gradle.properties 2025-08-05 21:51:28 +08:00
XiaoMoMi f505d0da34 fix mongodb user & password 2025-08-05 19:04:57 +08:00
XiaoMoMi 9c77cf6878 try fix pet names 2025-08-02 04:13:27 +08:00
XiaoMoMi df5a1faa19 3.0.30 2025-07-19 23:48:06 +08:00
XiaoMoMi 2ebb781721 1.21.6 2025-06-30 02:05:35 +08:00
XiaoMoMi 3cbf4698ed add strip color codes support 2025-06-21 00:20:01 +08:00
XiaoMoMi e01dec757e allow capital letters 2025-05-29 01:18:08 +08:00
XiaoMoMi 857e5bedc9 Merge pull request #60 from Mimexe/patch-1
Remove proxy settings
2025-05-21 16:17:02 +08:00
Mime 4ac11deb07 Remove proxy settings 2025-05-20 22:36:48 +02:00
XiaoMoMi 9f657166ff bump adventure platform version 2025-05-12 03:25:38 +08:00
XiaoMoMi 687908defc fix team visibility on 1.21.5 2025-05-03 15:07:56 +08:00
XiaoMoMi 5520dc3c4e Update gradle.properties 2025-05-01 11:08:34 +08:00
XiaoMoMi 3b6542858c 3.0.26.2 2025-04-26 17:03:13 +08:00
XiaoMoMi 75982b67a1 update chat control hook 2025-04-24 03:44:40 +08:00
XiaoMoMi f1adb436d0 make player not weak reference 2025-04-23 04:49:35 +08:00
XiaoMoMi c25e222187 3.0.26 2025-04-20 16:18:21 +08:00
XiaoMoMi 8f23416ed6 fix zh_cn translation 2025-04-19 16:09:01 +08:00
XiaoMoMi 85a399eda0 3.0.26 2025-04-13 00:01:56 +08:00
XiaoMoMi 01463d554c Update AbstractCNPlayer.java 2025-04-04 16:17:08 +08:00
XiaoMoMi 29de340676 added native adventure component support 2025-03-28 20:11:29 +08:00
XiaoMoMi ebca2deef5 added npex static 2025-03-22 23:05:15 +08:00
XiaoMoMi f5bc4fda2d Remove deprecated CraftEngine integration 2025-03-15 22:06:22 +08:00
XiaoMoMi 0328c534c4 3.0.24 2025-03-09 02:24:09 +08:00
XiaoMoMi 4d0fab7b68 Update NameplatesForcePreviewCommand.java 2025-03-06 21:39:14 +08:00
XiaoMoMi a2f0591e29 Fixed Proxy Settings 2025-03-04 02:29:52 +08:00
XiaoMoMi 5a3c320995 Fixed Placeholders in Chat Prefix/Suffix 2025-03-02 19:34:10 +08:00
XiaoMoMi fd19b99e77 Added smallfont Placeholder 2025-02-24 16:26:48 +08:00
XiaoMoMi 4e5dcad309 Update gradle.properties 2025-02-21 18:51:29 +08:00
XiaoMoMi fd2c810d21 Bump Adventure Version 2025-02-21 18:50:29 +08:00
XiaoMoMi 4bf9a00b32 Fixed spigot mapping 2025-02-21 18:26:27 +08:00
XiaoMoMi 8c0272acc7 delay load 2025-02-18 00:18:51 +08:00
XiaoMoMi f8a8ce0f43 3.0.20 2025-02-14 02:34:48 +08:00
XiaoMoMi 1147deaa73 fix createTextWithImage 2025-02-08 20:50:26 +08:00
XiaoMoMi 1bc4ab6258 fix 2025-01-29 14:59:41 +08:00
XiaoMoMi a95ea99a55 Update build.gradle.kts 2025-01-27 00:05:41 +08:00
XiaoMoMi 6dbc6bf596 Update README.md 2025-01-26 23:27:46 +08:00
XiaoMoMi 63ec5e8a92 Update README.md 2025-01-26 23:24:44 +08:00
XiaoMoMi 8c1a858e2a merge modules 2025-01-26 23:20:27 +08:00
XiaoMoMi 88e4af721b update docs 2025-01-26 21:03:31 +08:00
XiaoMoMi b41e1bd2ab Update gradle.properties 2025-01-25 17:53:49 +08:00
XiaoMoMi 28ccd9130c improved scale support 2025-01-25 17:46:35 +08:00
XiaoMoMi 16976e6347 fix scale 2025-01-24 19:28:39 +08:00
XiaoMoMi c8f8c38cc8 work 2025-01-16 18:17:10 +08:00
XiaoMoMi ddbe549900 Improve data storage 2025-01-16 18:15:28 +08:00
XiaoMoMi b4608394f7 Update gradle-wrapper.properties 2025-01-10 00:20:58 +08:00
XiaoMoMi 7b7fe63364 Update gradle.properties 2025-01-10 00:20:44 +08:00
XiaoMoMi 906390aa78 Update plugin.yml 2025-01-06 17:52:48 +08:00
XiaoMoMi c491a99b1e add zip 2025-01-06 17:28:07 +08:00
XiaoMoMi 5733338584 fix repo 2025-01-03 16:42:06 +08:00
XiaoMoMi 2fb0e311c9 Update BedrockPlayerRequirement.java 2024-12-30 22:37:55 +08:00
XiaoMoMi 44656962ac fix debug stick 2024-12-30 03:21:59 +08:00
XiaoMoMi 87703736c3 Update gradle.properties 2024-12-28 17:40:52 +08:00
XiaoMoMi 1053b36f75 clean up cache 2024-12-28 17:34:30 +08:00
XiaoMoMi 9b26ce4e19 Added craftengine support 2024-12-28 17:04:52 +08:00
XiaoMoMi 0270830517 Added API to take over actionbars 2024-12-26 18:14:06 +08:00
XiaoMoMi 23bde6ab9d Fix npe caused by other plugins 2024-12-22 15:56:12 +08:00
XiaoMoMi 6f0e61ae48 shut down scheduler on disable 2024-12-21 19:39:30 +08:00
XiaoMoMi 26b593950d bump version 3.0.15.2 2024-12-10 16:24:46 +08:00
XiaoMoMi 63896acda6 use snapshot adventure 2024-12-10 16:24:06 +08:00
XiaoMoMi 6eb5dee611 Update custom-placeholders.yml 2024-12-10 16:23:48 +08:00
XiaoMoMi 69869d1cb1 update pack format 2024-12-10 16:02:48 +08:00
XiaoMoMi 2e702d8945 Fix thread safety issue 2024-12-09 03:29:06 +08:00
XiaoMoMi 56c77bd294 3.0.15.1 2024-12-04 15:35:12 +08:00
XiaoMoMi 4d195820a0 improve send delay 2024-11-29 17:40:54 +08:00
XiaoMoMi 2874ab7c4e send bossbar immediately 2024-11-29 17:34:40 +08:00
XiaoMoMi cd1a0bffb6 chatty 2024-11-28 18:49:59 +08:00
XiaoMoMi 20d3919c6b Fix regex 2024-11-22 00:57:24 +08:00
XiaoMoMi fccaa059ff Added generate option for bitmaps 2024-11-21 02:14:49 +08:00
XiaoMoMi ed2fb60748 Update settings.gradle.kts 2024-11-19 18:38:26 +08:00
XiaoMoMi 378dc2e3bc Update gradle.properties 2024-11-19 18:37:38 +08:00
XiaoMoMi 6144423110 Update gradle.properties 2024-11-19 18:33:13 +08:00
XiaoMoMi d21fa8a3f7 work 2024-11-19 18:33:04 +08:00
XiaoMoMi 7e68a6cda7 move packages 2024-11-19 16:52:02 +08:00
XiaoMoMi 3df6d66efb better support 2024-11-19 16:46:01 +08:00
XiaoMoMi 001ecd28ed remove debug 2024-11-18 15:14:05 +08:00
XiaoMoMi 6fe8625722 Update TagRendererImpl.java 2024-11-18 03:06:23 +08:00
XiaoMoMi 43e006f49d 3.0.12 2024-11-18 03:03:45 +08:00
XiaoMoMi 8d63ad9c74 fix bugs 2024-11-18 02:51:49 +08:00
XiaoMoMi 5c2411e420 We need more work 2024-11-18 01:53:08 +08:00
XiaoMoMi a57cfb0842 more work 2024-11-18 01:30:54 +08:00
XiaoMoMi e4d7fb4346 work 2024-11-18 01:22:23 +08:00
XiaoMoMi 9a9865c424 improved default configs 2024-11-14 16:26:11 +08:00
XiaoMoMi f6b8ce253f Fixed advance not instantly updated 2024-11-11 22:11:38 +08:00
XiaoMoMi 144b358768 3.0.10.1 2024-11-11 15:37:37 +08:00
XiaoMoMi 0fd7ac1a79 Update OraxenEmojiProvider.java 2024-11-10 20:32:56 +08:00
XiaoMoMi 67f0e60327 Update README.md 2024-11-10 19:54:00 +08:00
XiaoMoMi d10eb6de67 code clean up 2024-11-10 19:39:00 +08:00
XiaoMoMi 8cfd098be9 add passenger condition 2024-11-10 19:21:24 +08:00
XiaoMoMi e3d81e7c0c optimize 2024-11-10 18:29:25 +08:00
XiaoMoMi 018dc18eee 3.0.9 2024-11-09 22:56:29 +08:00
XiaoMoMi 366cda6bef 3.0.8 2024-11-09 02:22:37 +08:00
XiaoMoMi ca70dfb2b4 3.0.8 2024-11-07 17:59:03 +08:00
XiaoMoMi d59ac96f48 3.0.7.1 2024-11-04 04:20:38 +08:00
XiaoMoMi f5d2d6a0bc 1.20.3 support 2024-11-02 20:12:38 +08:00
XiaoMoMi 7d6fba25e6 bypass other names 2024-10-30 20:00:45 +08:00
XiaoMoMi fcb045e0c8 Update gradle.properties 2024-10-28 20:54:37 +08:00
XiaoMoMi df098a053e update config version to 32 2024-10-27 01:22:11 +08:00
XiaoMoMi 2958b4e1db Merge pull request #49 from BitByLogics/main
Add creative-central resourcepack integration support
2024-10-25 21:25:33 +08:00
Justin 84a37ed619 Add creative-central resourcepack integration support 2024-10-24 22:58:27 -04:00
XiaoMoMi f66c800f3a Update NameplatesExtraExpansion.java 2024-10-24 19:52:17 +08:00
XiaoMoMi 0fb4ae37e4 3.0.6 2024-10-24 03:54:07 +08:00
XiaoMoMi 9a9add1f03 fix reset 2024-10-22 00:12:23 +08:00
XiaoMoMi 5d48530eb6 3.0.5 2024-10-21 03:08:51 +08:00
XiaoMoMi f5e33f5647 3.0.5 2024-10-18 23:43:29 +08:00
XiaoMoMi ffdc7c49ce 3.0.5 2024-10-18 23:43:17 +08:00
XiaoMoMi 46d922ab15 fix folia again 2024-10-15 01:58:53 +08:00
XiaoMoMi aee8ebf9ae increase the delay for folia 2024-10-15 01:40:11 +08:00
XiaoMoMi be086cd91f folia fix 2024-10-15 01:10:25 +08:00
XiaoMoMi 0b96cefcf2 Update BukkitCNPlayer.java 2024-10-14 03:51:13 +08:00
XiaoMoMi 8867b25307 3.0.3 2024-10-13 21:54:40 +08:00
XiaoMoMi bd6caee58f update libs 2024-10-12 21:47:58 +08:00
XiaoMoMi d0b057b391 Update BukkitCustomNameplates.java 2024-10-11 23:35:45 +08:00
XiaoMoMi 2e03248555 3.0.2 2024-10-11 23:31:02 +08:00
XiaoMoMi 5898d8e3d4 3.0.2 2024-10-11 23:11:37 +08:00
XiaoMoMi 8bcb7d3380 to fix teams 2024-10-11 05:30:24 +08:00
XiaoMoMi 59dda019d8 Update PlayerListener.java 2024-10-11 03:19:42 +08:00
XiaoMoMi 7512a97461 fix teleport 2024-10-11 03:15:44 +08:00
XiaoMoMi 63075ad1bb 3.0.1 2024-10-11 02:53:43 +08:00
XiaoMoMi 2c9bdc662a added nametag module 2024-10-10 17:09:28 +08:00
XiaoMoMi 545826801a Update HasBubbleRequirement.java 2024-10-10 16:01:10 +08:00
XiaoMoMi 26c30b8bab Merge pull request #47 from thomasz05/main
Fix HasNameplateRequirement to return false if nameplate module is di…
2024-10-10 15:59:19 +08:00
thomasz_05 c022319b67 Fix HasNameplateRequirement to return false if nameplate module is disabled 2024-10-09 23:41:09 +02:00
XiaoMoMi 37da5df7e6 beta5 2024-10-09 23:17:41 +08:00
XiaoMoMi aa919d18e0 Fix bugs 2024-10-09 22:33:22 +08:00
XiaoMoMi 7eb3296294 beta4 2024-10-09 21:38:05 +08:00
XiaoMoMi d84c9f7031 new event 2024-10-09 00:22:21 +08:00
XiaoMoMi ec840036ac Update PlaceholderManagerImpl.java 2024-10-08 23:23:15 +08:00
XiaoMoMi a168cb8591 modules 2024-10-08 23:14:33 +08:00
XiaoMoMi 8856831a94 code clean up 2024-10-08 22:53:51 +08:00
XiaoMoMi a387cf5127 beta3 2024-10-08 22:26:48 +08:00
XiaoMoMi 6b2bbea6e1 Update build.gradle.kts 2024-10-08 05:46:12 +08:00
XiaoMoMi 67732ecf76 update default configs 2024-10-08 05:39:58 +08:00
XiaoMoMi f361ad1015 remove color 2024-10-08 05:26:29 +08:00
XiaoMoMi 57a1593315 time24 2024-10-08 04:07:09 +08:00
XiaoMoMi a424c3345a fix 2024-10-08 03:32:11 +08:00
XiaoMoMi 047852eed9 beta2 2024-10-08 00:51:42 +08:00
XiaoMoMi 5d2d3e0933 Improve interval system 2024-10-07 22:45:12 +08:00
XiaoMoMi efe90b95b5 Update PlaceholderManagerImpl.java 2024-10-07 22:09:45 +08:00
XiaoMoMi cad0e07411 beta2 2024-10-07 22:08:37 +08:00
XiaoMoMi f6de779090 improve spectator mode 2024-10-07 17:23:57 +08:00
XiaoMoMi 5df341b2a1 Update AdvanceManagerImpl.java 2024-10-07 02:44:23 +08:00
XiaoMoMi 2ba7ad95ba TTF 2024-10-07 01:28:26 +08:00
XiaoMoMi 4b2ddf6cd1 Fix build 2024-10-06 23:12:48 +08:00
XiaoMoMi e392e0fd4d Update AdventureHelper.java 2024-10-06 22:49:49 +08:00
XiaoMoMi 10206e8b2a fix build 2024-10-06 22:48:21 +08:00
XiaoMoMi f935a61958 improve shaders 2024-10-06 22:42:27 +08:00
XiaoMoMi 844e53ff1a API 2024-10-06 01:25:48 +08:00
XiaoMoMi 7209b9772b Improve bubbles 2024-10-05 23:11:55 +08:00
XiaoMoMi 3aa7e5c012 3.0 2024-10-05 22:42:28 +08:00
XiaoMoMi d8324da1d9 Update README.md 2024-09-20 04:27:15 +08:00
XiaoMoMi f66bc23037 Fixed send delay 2024-09-20 04:24:04 +08:00
XiaoMoMi 425a08a57a 2.4.8.1 2024-08-31 02:56:40 +08:00
XiaoMoMi f597e584ee add prefix to team 2024-08-30 15:58:20 +08:00
XiaoMoMi 886a3c53a3 2.4.8 2024-08-30 15:40:43 +08:00
XiaoMoMi 90b07517a7 Update DependencyManagerImpl.java 2024-08-29 22:00:34 +08:00
XiaoMoMi 4ef7da87b4 Update ResourcePackManagerImpl.java 2024-08-15 01:53:20 +08:00
XiaoMoMi a5fd4f237e Fix shaders on 1.20.5+ 2024-08-13 16:49:25 +08:00
XiaoMoMi 5046372177 2.4.6-pre-1 2024-08-11 20:28:22 +08:00
XiaoMoMi df86e4bc33 Merge pull request #38 from DrZoddiak/feature-ignore
[Feature] Support Ignoring for Chat Bubbles
2024-08-10 01:01:07 +08:00
Jesse McKee b5e83ca984 Implements ignoring bubbles
Allows for plugins that allow for ignoring to also ignore chat bubbles.

Carbon was given special attention for this PR, but other plugins will maintain prior behavior.
2024-08-08 01:06:33 -05:00
XiaoMoMi 04bb10cb3d Merge pull request #37 from DrZoddiak/fix-channel-mode
Fix channel-mode
2024-08-08 13:46:41 +08:00
Jesse McKee e7371cc02a Fix JOINED channel-mode for CarbonChatProvider
#selectedChannel only gets the channel current selected by the player if it exists. If a user does NOT select a channel, and is instead put into a default channel, the result is still `null`.

This PR provides a fallback value for channels in this case.
2024-08-08 00:27:00 -05:00
Jesse McKee bee0b26a9f Fix CAN_JOIN channel-mode
the method in question requires 1 argument, and was being passed 0. This error was being swallowed and not shown in console, so it was not immediately obvious.

Reading the JD for #invoke
`If the underlying method is static, then the specified obj argument is ignored. It may be null.`

So in order to pass the arg required, and because the method is indeed static, the first parameter is now null.
2024-08-08 00:21:05 -05:00
XiaoMoMi 343c0e5cb0 Update build.gradle.kts 2024-08-04 16:48:29 +08:00
XiaoMoMi 81d3a888b8 2.4.4 2024-08-04 16:48:02 +08:00
XiaoMoMi 58e16e5376 Fixed nms on 1.18.2 2024-07-27 17:17:42 +08:00
XiaoMoMi cc8c3d6bcd 2.4.2 2024-07-25 22:41:15 +08:00
XiaoMoMi 3000b26bfa Fix async events 2024-07-03 15:56:47 +08:00
XiaoMoMi a800481574 Update NameplateManagerImpl.java 2024-07-03 15:23:46 +08:00
XiaoMoMi 82350ac0c4 Fix some issues 2024-07-03 15:09:39 +08:00
XiaoMoMi 35edd85434 Update en.yml 2024-06-28 22:51:15 +08:00
XiaoMoMi 99bfc28be8 1.21 support 2024-06-28 02:52:20 +08:00
XiaoMoMi 5ee27c126c fix shader on 1.20.5+ 2024-06-28 01:12:39 +08:00
XiaoMoMi 5282d5e8a7 use NMS to send bossbar 2024-06-28 00:21:19 +08:00
XiaoMoMi 0f7a72bf1e Merge pull request #33 from relpia/main
Create kr.yml
2024-06-26 19:45:58 +08:00
XiaoMoMi b36d0c23e1 some changes 2024-06-24 00:14:44 +08:00
Horibin f8219659c4 Add files via upload 2024-06-22 13:01:28 +09:00
XiaoMoMi eb730c8631 Merge pull request #32 from Vondri/patch-2
Create pl.yml
2024-05-25 17:03:59 +08:00
Vondri 12b8b74031 Create pl.yml
Translation for polish
2024-05-18 00:46:15 +02:00
XiaoMoMi 365aae10f5 2.3.3.9 2024-05-07 22:34:39 +08:00
XiaoMoMi 5e299bb0d4 Update build logics 2024-05-04 05:10:53 +08:00
XiaoMoMi 79a0892b09 [Update] Updated dependencies 2024-04-23 03:43:07 +08:00
XiaoMoMi a8bc4d8de5 update shaders 2024-04-22 01:14:48 +08:00
XiaoMoMi 6276d27d57 Merge branch 'main' of https://github.com/Xiao-MoMi/Custom-Nameplates 2024-04-16 23:39:06 +08:00
XiaoMoMi 096e6330d6 2.3.3.8 2024-04-16 23:39:01 +08:00
XiaoMoMi e41686aa31 Merge pull request #30 from Schroddinger/release
Tweaks to Spanish translation
2024-04-16 02:39:05 +08:00
Schroddinger 590b26ac2a Tweaks to Spanish translation 2024-04-14 11:19:13 -05:00
XiaoMoMi a7dc0db15d rename language files 2024-04-14 20:19:37 +08:00
XiaoMoMi c9250fea13 Merge pull request #28 from jhqwqmc/main
small changes
2024-04-07 21:33:26 +08:00
jhqwqmc fa914d52a2 del time-24 2024-04-07 21:12:10 +08:00
jhqwqmc efbf2d3b64 Update config file 2024-04-07 21:03:01 +08:00
jhqwqmc 40672aefb4 small changes
Add a 24-hour time variable
Fix weather detection issue
2024-04-07 21:00:50 +08:00
XiaoMoMi 8fb4b8317d 2.3.3.7
修复旧版颜色相关问题
2024-04-07 01:27:11 +08:00
XiaoMoMi e68a333527 Fix minimessage alias 2024-03-31 03:16:51 +08:00
XiaoMoMi 53317c3e4b better bold support 2024-03-17 17:42:12 +08:00
XiaoMoMi c2c1b703b7 2.3.3.6 2024-03-17 16:26:26 +08:00
XiaoMoMi abcece373f 2.3.3.6 2024-03-13 19:19:18 +08:00
XiaoMoMi be8cf27f37 fix bold 2024-03-10 08:13:34 +08:00
XiaoMoMi 6fafb85cec 2.3.3.3 2024-03-07 23:51:32 +08:00
XiaoMoMi d18bf83ecb Update FoliaSchedulerImpl.java 2024-03-04 15:55:59 +08:00
XiaoMoMi 2c8aad7a75 disguise support 2024-02-27 16:47:36 +08:00
XiaoMoMi 9e8e57c6df adjust priority 2024-02-27 02:55:40 +08:00
XiaoMoMi 1c433d1891 update to gradle 8.6 2024-02-26 12:48:21 +08:00
XiaoMoMi 6e77eb55d0 Update README.md 2024-02-25 01:39:42 +08:00
XiaoMoMi 3afa1bfb58 compatibility with Libsdisguises 2024-02-25 00:50:03 +08:00
XiaoMoMi 39e9d40e3e small changes 2024-02-24 21:16:17 +08:00
XiaoMoMi 2e90d02166 fix some minor issues 2024-02-22 20:18:16 +08:00
XiaoMoMi 9d88ead4e3 remap libs 2024-02-20 04:59:14 +08:00
XiaoMoMi 810b8f0593 version number 2024-02-18 03:23:44 +08:00
XiaoMoMi 930cdf8c00 Fix concurrent modification 2024-02-18 03:16:33 +08:00
XiaoMoMi a26e6dc784 optimize imports 2024-02-10 18:44:22 +08:00
XiaoMoMi e450b1429d channel mode 2024-02-04 18:43:55 +08:00
XiaoMoMi 7811cea007 Update gradle.properties 2024-02-03 03:51:39 +08:00
948 changed files with 42650 additions and 22494 deletions

No files matched your search

+3
View File
@@ -5,6 +5,9 @@ target/
!**/src/main/**/build/
!**/src/test/**/build/
### Unfinished ###
platforms/sponge/
### IntelliJ IDEA ###
.idea
*.iws
+24 -56
View File
@@ -1,79 +1,47 @@
# Custom-Nameplates
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/Xiao-MoMi/Custom-Nameplates)
<a href="https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customnameplates" alt="GitBook">
<img src="https://img.shields.io/badge/docs-gitbook-brightgreen" alt="Gitbook"/>
</a>
[![Scc Count Badge](https://sloc.xyz/github/Xiao-MoMi/Custom-Nameplates/?category=codes)](https://github.com/Xiao-MoMi/Custom-Nameplates/)
![Code Size](https://img.shields.io/github/languages/code-size/Xiao-MoMi/Custom-Nameplates)
![bStats Servers](https://img.shields.io/bstats/servers/16649)
![bStats Players](https://img.shields.io/bstats/players/16649)
![GitHub](https://img.shields.io/github/license/Xiao-MoMi/Custom-Nameplates)
[![](https://jitpack.io/v/Xiao-MoMi/Custom-Nameplates.svg)](https://jitpack.io/#Xiao-MoMi/Custom-Nameplates)
<a href="https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/" alt="GitBook">
<img src="https://img.shields.io/badge/docs-gitbook-brightgreen" alt="Gitbook"/>
</a>
CustomNameplates is a Paper plugin that provides unlimited customization for nametags, bossbars, actionbars and chat bubbles.
## How to build
### Windows
## How to Build
#### Command Line
Install JDK 17 and set the JDK installation path to JAVA_HOME as an environment variable.\
Start powershell and change directory to the project folder.\
Execute ".\gradlew build" and get the jar at /target/CustomNameplates-universe-version.jar.
Install JDK 17 & 21. \
Start terminal and change directory to the project folder.\
Execute ".\gradlew build" and get the artifact under /target folder
#### IDE
Import the project and execute gradle build action.
Import the project and execute gradle build action. \
Get the artifact under /target folder
##### About Proxy
If you are using a proxy, configurate the proxy in gradle.properties. Otherwise comment the lines in gradle.properties.
## How to Contribute
## Support the developer
#### Translations
Clone this project and create a new language file in the /backend/src/main/resources/translations directory. \
Once your changes are ready, open a pull request for review. We appreciate your works!
Polymart: https://polymart.org/resource/customnameplates.2543 \
Afdian: https://afdian.net/@xiaomomi
## Support the Developer
## Use CustomNameplates API
Polymart: https://polymart.org/resource/customnameplates.2543/ \
BuiltByBit: https://builtbybit.com/resources/customnameplates.36359/ \
Afdian: https://afdian.com/@xiaomomi/
### Maven
## CustomNameplates API
```
<repositories>
<repository>
<id>jitpack</id>
<url>https://jitpack.io/</url>
</repository>
</repositories>
```
```
<dependencies>
<dependency>
<groupId>com.github.Xiao-MoMi</groupId>
<artifactId>Custom-Nameplates</artifactId>
<version>{LATEST}</version>
<scope>provided</scope>
</dependency>
</dependencies>
```
### Gradle (Groovy)
```
```kotlin
repositories {
maven { url 'https://jitpack.io' }
maven("https://repo.momirealms.net/releases/")
}
```
```
```kotlin
dependencies {
compileOnly 'com.github.Xiao-MoMi:Custom-Nameplates:{LATEST}'
}
```
### Gradle (Kotlin)
```
repositories {
maven("https://jitpack.io/")
}
```
```
dependencies {
compileOnly("com.github.Xiao-MoMi:Custom-Nameplates:{LATEST}")
compileOnly("net.momirealms:custom-nameplates:3.0.19")
}
```
+88 -5
View File
@@ -1,12 +1,95 @@
plugins {
id("maven-publish")
}
repositories {
maven("https://jitpack.io/")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
implementation(project(":common"))
implementation("net.kyori:adventure-api:4.15.0")
// Adventure
implementation("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}")
compileOnly("net.kyori:adventure-text-serializer-json-legacy-impl:${rootProject.properties["adventure_bundle_version"]}")
// YAML
implementation(files("libs/boosted-yaml-${rootProject.properties["boosted_yaml_version"]}.jar"))
// Cache
compileOnly("com.github.ben-manes.caffeine:caffeine:${rootProject.properties["caffeine_version"]}")
// Netty
compileOnly("io.netty:netty-all:4.1.117.Final")
// GSON
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
// Fast util
compileOnly("it.unimi.dsi:fastutil:${rootProject.properties["fastutil_version"]}")
// Command
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}")
compileOnly("org.incendo:cloud-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
// Logger
compileOnly("org.slf4j:slf4j-api:${rootProject.properties["slf4j_version"]}")
compileOnly("org.apache.logging.log4j:log4j-core:${rootProject.properties["log4j_version"]}")
// Expression
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
// code generator
compileOnly("net.bytebuddy:byte-buddy:${rootProject.properties["byte_buddy_version"]}")
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
withSourcesJar()
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(21)
dependsOn(tasks.clean)
}
tasks {
shadowJar {
archiveClassifier.set("")
archiveFileName = "custom-nameplates-${rootProject.properties["project_version"]}.jar"
relocate ("net.kyori", "net.momirealms.customnameplates.libraries")
relocate("dev.dejvokep", "net.momirealms.customnameplates.libraries")
}
}
}
publishing {
repositories {
maven {
url = uri("https://repo.momirealms.net/releases")
credentials(PasswordCredentials::class) {
username = System.getenv("REPO_USERNAME")
password = System.getenv("REPO_PASSWORD")
}
}
}
publications {
create<MavenPublication>("mavenJava") {
groupId = "net.momirealms"
artifactId = "custom-nameplates"
version = rootProject.properties["project_version"].toString()
artifact(tasks["sourcesJar"])
from(components["shadow"])
pom {
name = "CustomNameplates API"
url = "https://github.com/Xiao-MoMi/Custom-Nameplates"
licenses {
license {
name = "GNU General Public License v3.0"
url = "https://www.gnu.org/licenses/gpl-3.0.html"
distribution = "repo"
}
}
}
}
}
}
Binary file not shown.
@@ -0,0 +1,709 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import io.netty.channel.Channel;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.momirealms.customnameplates.api.feature.Feature;
import net.momirealms.customnameplates.api.feature.TimeStampData;
import net.momirealms.customnameplates.api.feature.tag.TeamView;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.placeholder.PlayerPlaceholder;
import net.momirealms.customnameplates.api.placeholder.RelationalPlaceholder;
import net.momirealms.customnameplates.api.placeholder.SharedPlaceholder;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.storage.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Player instance adapted by CustomNameplates
*/
public abstract class AbstractCNPlayer<P> implements CNPlayer {
/**
* The CustomNameplates plugin
*/
protected final CustomNameplates plugin;
/**
* Player netty channel
*/
protected final Channel channel;
/**
* Platform player instance
*/
protected P player;
protected UUID uuid;
protected int entityId;
protected String name;
private volatile boolean isLoaded = false;
private volatile boolean tempPreviewing = false;
private volatile boolean toggleablePreviewing = false;
private String currentNameplate;
private String nameplateData;
private String currentBubble;
private String bubbleData;
private final TeamView teamView = new TeamView();
// these maps might be visited by other threads through PlaceholderAPI
private final Map<Integer, TimeStampData<String>> cachedValues = new ConcurrentHashMap<>(128);
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<String>>> cachedRelationalValues = new ConcurrentHashMap<>(128);
private final Map<Integer, TimeStampData<Boolean>> cachedRequirements = new ConcurrentHashMap<>(32);
private final Map<Integer, WeakHashMap<CNPlayer, TimeStampData<Boolean>>> cachedRelationalRequirements = new ConcurrentHashMap<>(32);
private final Set<Feature> activeFeatures = new CopyOnWriteArraySet<>();
private final Map<Placeholder, Set<Feature>> placeholder2Features = new ConcurrentHashMap<>();
private final Map<Feature, Set<Placeholder>> feature2Placeholders = new ConcurrentHashMap<>();
private final Map<CNPlayer, Tracker> trackers = new WeakHashMap<>();
private final ReadWriteLock trackerLock = new ReentrantReadWriteLock();
private final Vector<String> otherActionBarFeatures = new Vector<>();
/**
* Creates a player instance
*
* @param plugin CustomNameplates plugin
* @param channel netty channel
*/
protected AbstractCNPlayer(CustomNameplates plugin, Channel channel) {
this.plugin = plugin;
this.channel = channel;
}
@Override
public void acquireActionBar(String id) {
this.otherActionBarFeatures.add(id);
}
@Override
public void releaseActionBar(String id) {
this.otherActionBarFeatures.remove(id);
}
@Override
public boolean shouldCNTakeOverActionBar() {
return otherActionBarFeatures.isEmpty();
}
@Override
public List<Placeholder> activePlaceholdersToRefresh() {
Placeholder[] activePlaceholders = activePlaceholders();
List<Placeholder> placeholderWithChildren = new ObjectArrayList<>();
for (Placeholder placeholder : activePlaceholders) {
childrenFirstList(placeholder, placeholderWithChildren);
}
return placeholderWithChildren.stream().distinct().toList();
}
private String updatePlayerPlaceholder(PlayerPlaceholder placeholder) {
TimeStampData<String> value = getRawPlayerValue(placeholder);
if (value == null) {
value = new TimeStampData<>(placeholder.request(this), MainTask.getTicks(), true);
setPlayerValue(placeholder, value);
return value.data();
}
if (value.ticks() != MainTask.getTicks()) {
String newValue = placeholder.request(this);
value.updateTicks(!value.data().equals(newValue));
value.data(newValue);
}
return value.data();
}
private void updateRelationalPlaceholder(RelationalPlaceholder placeholder, Collection<CNPlayer> others) {
for (CNPlayer another : others) {
updateRelationalPlaceholder(placeholder, another);
}
}
private String updateRelationalPlaceholder(RelationalPlaceholder placeholder, CNPlayer another) {
TimeStampData<String> value = getRawRelationalValue(placeholder, another);
if (value == null) {
value = new TimeStampData<>(placeholder.request(this, another), MainTask.getTicks(), true);
setRelationalValue(placeholder, another, value);
return value.data();
}
if (value.ticks() != MainTask.getTicks()) {
String newValue = placeholder.request(this, another);
value.updateTicks(!value.data().equals(newValue));
value.data(newValue);
}
return value.data();
}
private String updateSharedPlaceholder(SharedPlaceholder placeholder) {
TimeStampData<String> value = getRawSharedValue(placeholder);
if (value == null) {
String latest;
if (MainTask.hasRequested(placeholder.countId())) {
latest = placeholder.getLatestValue();
} else {
latest = placeholder.request();
}
value = new TimeStampData<>(latest, MainTask.getTicks(), true);
setSharedValue(placeholder, value);
return value.data();
}
if (value.ticks() != MainTask.getTicks()) {
String latest;
if (MainTask.hasRequested(placeholder.countId())) {
latest = placeholder.getLatestValue();
} else {
latest = placeholder.request();
}
value.updateTicks(!value.data().equals(latest));
value.data(latest);
}
return value.data();
}
@Override
public void forceUpdatePlaceholders(Set<Placeholder> placeholders, Collection<CNPlayer> others) {
if (placeholders.isEmpty()) return;
List<Placeholder> placeholderWithChildren = new ObjectArrayList<>();
for (Placeholder placeholder : placeholders) {
childrenFirstList(placeholder, placeholderWithChildren);
}
placeholderWithChildren = placeholderWithChildren.stream().distinct().toList();
for (Placeholder placeholder : placeholderWithChildren) {
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
updatePlayerPlaceholder(playerPlaceholder);
} else if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
updateRelationalPlaceholder(relationalPlaceholder, others);
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
updateSharedPlaceholder(sharedPlaceholder);
}
}
}
private void childrenFirstList(Placeholder placeholder, List<Placeholder> list) {
if (placeholder.children().isEmpty()) {
list.add(placeholder);
} else {
for (Placeholder child : placeholder.children()) {
childrenFirstList(child, list);
}
list.add(placeholder);
}
}
private void parentLastList(Placeholder placeholder, List<Placeholder> list) {
if (placeholder.parents().isEmpty()) {
list.add(placeholder);
} else {
list.add(placeholder);
for (Placeholder parent : placeholder.parents()) {
parentLastList(parent, list);
}
}
}
/**
* Reload the player instance, clear caches
*/
public void reload() {
cachedValues.clear();
cachedRelationalValues.clear();
cachedRequirements.clear();
cachedRelationalRequirements.clear();
activeFeatures.clear();
placeholder2Features.clear();
feature2Placeholders.clear();
}
/**
* Sets the platform player instance on join
*
* @param player player
*/
public void setPlayer(P player) {
this.player = player;
}
@Override
public Channel channel() {
return channel;
}
@Override
public Set<Feature> activeFeatures(Placeholder placeholder) {
return placeholder2Features.getOrDefault(placeholder, Collections.emptySet());
}
@Override
public Object player() {
return player;
}
/**
* Sets if the player data is loaded
*
* @param loaded loaded or not
*/
public void setLoaded(boolean loaded) {
isLoaded = loaded;
}
/**
* Sets if the player is temporarily previewing the nameplate
*
* @param previewing is previewing or not
*/
public void setTempPreviewing(boolean previewing) {
this.tempPreviewing = previewing;
}
@Override
public boolean isTempPreviewing() {
return tempPreviewing;
}
/**
* Sets if the player is using toggle command to preview his nameplate
*
* @param previewing is previewing or not
*/
public void setToggleablePreviewing(boolean previewing) {
this.toggleablePreviewing = previewing;
}
@Override
public boolean isToggleablePreviewing() {
return toggleablePreviewing;
}
@Override
public boolean isLoaded() {
return isLoaded;
}
@Override
public void addFeature(Feature feature) {
activeFeatures.add(feature);
Set<Placeholder> allPlaceholders = feature.allPlaceholders();
feature2Placeholders.put(feature, allPlaceholders);
for (Placeholder placeholder : allPlaceholders) {
Set<Feature> featureSet = placeholder2Features.computeIfAbsent(placeholder, k -> new ObjectOpenHashSet<>());
featureSet.add(feature);
}
}
@Override
public void removeFeature(Feature feature) {
activeFeatures.remove(feature);
Set<Placeholder> placeholders = feature2Placeholders.remove(feature);
if (placeholders != null) {
for (Placeholder placeholder : placeholders) {
Set<Feature> featureSet = placeholder2Features.get(placeholder);
featureSet.remove(feature);
if (featureSet.isEmpty()) placeholder2Features.remove(placeholder);
}
}
}
@Override
public void setPlayerValue(PlayerPlaceholder placeholder, TimeStampData<String> value) {
cachedValues.put(placeholder.countId(), value);
}
@Override
public void setSharedValue(SharedPlaceholder placeholder, TimeStampData<String> value) {
cachedValues.put(placeholder.countId(), value);
}
@Override
public void setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, TimeStampData<String> value) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
map.put(another, value);
}
// @Override
// public boolean setPlayerValue(PlayerPlaceholder placeholder, String value) {
// TimeStampData<String> previous = cachedValues.get(placeholder.countId());
// int currentTicks = MainTask.getTicks();
// boolean changed = false;
// if (previous != null) {
// if (previous.ticks() == currentTicks) {
// return false;
// }
// String data = previous.data();
// if (!data.equals(value)) {
// changed = true;
// previous.data(value);
// previous.updateTicks(true);
// }
// } else {
// changed= true;
// previous = new TimeStampData<>(value, currentTicks, true);
// cachedValues.put(placeholder.countId(), previous);
// }
// return changed;
// }
// @Override
// public boolean setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, String value) {
// WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.computeIfAbsent(placeholder.countId(), k -> new WeakHashMap<>());
// TimeStampData<String> previous = map.get(another);
// int currentTicks = MainTask.getTicks();
// boolean changed = false;
// if (previous != null) {
// if (previous.ticks() == currentTicks) {
// return false;
// }
// String data = previous.data();
// if (!data.equals(value)) {
// changed = true;
// previous.data(value);
// previous.updateTicks(true);
// }
// } else {
// changed= true;
// previous = new TimeStampData<>(value, currentTicks, true);
// map.put(another, previous);
// }
// return changed;
// }
@Override
public @NotNull String getCachedSharedValue(SharedPlaceholder placeholder) {
return updateSharedPlaceholder(placeholder);
}
@Override
public @NotNull String getCachedPlayerValue(PlayerPlaceholder placeholder) {
return updatePlayerPlaceholder(placeholder);
}
@Override
public @NotNull String getCachedRelationalValue(RelationalPlaceholder placeholder, CNPlayer another) {
return updateRelationalPlaceholder(placeholder, another);
}
@Nullable
@Override
public TimeStampData<String> getRawPlayerValue(PlayerPlaceholder placeholder) {
return cachedValues.get(placeholder.countId());
}
@Nullable
@Override
public TimeStampData<String> getRawSharedValue(SharedPlaceholder placeholder) {
return cachedValues.get(placeholder.countId());
}
@Nullable
@Override
public TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another) {
WeakHashMap<CNPlayer, TimeStampData<String>> map = cachedRelationalValues.get(placeholder.countId());
if (map == null) {
return null;
}
return map.get(another);
}
@Override
public Placeholder[] activePlaceholders() {
Set<Placeholder> placeholders = new ObjectOpenHashSet<>();
for (Feature feature : activeFeatures) {
placeholders.addAll(feature.activePlaceholders());
}
return placeholders.toArray(new Placeholder[0]);
}
@Override
public boolean isMet(Requirement[] requirements) {
int currentTicks = MainTask.getTicks();
for (Requirement requirement : requirements) {
TimeStampData<Boolean> data = cachedRequirements.get(requirement.countId());
if (data != null) {
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
if (!data.data()) {
return false;
}
} else {
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, this);
} catch (Exception e) {
satisfied = false;
}
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
return false;
}
}
} else {
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, this);
} catch (Exception e) {
satisfied = false;
}
data = new TimeStampData<>(satisfied, currentTicks, true);
cachedRequirements.put(requirement.countId(), data);
if (!satisfied) {
return false;
}
}
}
return true;
}
@Override
public boolean isMet(CNPlayer another, Requirement[] requirements) {
int currentTicks = MainTask.getTicks();
for (Requirement requirement : requirements) {
WeakHashMap<CNPlayer, TimeStampData<Boolean>> innerMap = cachedRelationalRequirements.computeIfAbsent(requirement.countId(), k -> new WeakHashMap<>());
TimeStampData<Boolean> data = innerMap.get(another);
if (data != null) {
if (data.ticks() + requirement.refreshInterval() > currentTicks) {
if (!data.data()) {
return false;
}
} else {
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, another);
} catch (Exception e) {
satisfied = false;
}
data.updateTicks(false);
data.data(satisfied);
if (!satisfied) {
return false;
}
}
} else {
boolean satisfied;
try {
satisfied = requirement.isSatisfied(this, another);
} catch (Exception e) {
satisfied = false;
}
data = new TimeStampData<>(satisfied, currentTicks, true);
innerMap.put(another, data);
if (!satisfied) {
return false;
}
}
}
return true;
}
@Override
public Tracker addPlayerToTracker(CNPlayer another) {
trackerLock.writeLock().lock();
try {
Tracker tracker = trackers.get(another);
if (tracker != null) {
return tracker;
}
tracker = new Tracker(another);
trackers.put(another, tracker);
return tracker;
} finally {
trackerLock.writeLock().unlock();
}
}
@Override
public void removePlayerFromTracker(CNPlayer another) {
trackerLock.writeLock().lock();
try {
trackers.remove(another);
} finally {
trackerLock.writeLock().unlock();
}
}
@Override
public Collection<CNPlayer> nearbyPlayers() {
trackerLock.readLock().lock();
try {
// Create a snapshot of keys to avoid concurrent modification
return new ObjectArrayList<>(trackers.keySet());
} finally {
trackerLock.readLock().unlock();
}
}
@Override
public void trackPassengers(CNPlayer another, int... passengers) {
trackerLock.writeLock().lock();
try {
Tracker tracker = trackers.get(another);
if (tracker != null) {
for (int passenger : passengers) {
tracker.addPassengerID(passenger);
}
}
} finally {
trackerLock.writeLock().unlock();
}
}
@Override
public void untrackPassengers(CNPlayer another, int... passengers) {
trackerLock.writeLock().lock();
try {
Tracker tracker = trackers.get(another);
if (tracker != null) {
for (int passenger : passengers) {
tracker.removePassengerID(passenger);
}
}
} finally {
trackerLock.writeLock().unlock();
}
}
@Override
public Set<Integer> getTrackedPassengerIds(CNPlayer another) {
trackerLock.readLock().lock();
try {
Tracker tracker = trackers.get(another);
return tracker != null ? tracker.getPassengerIDs() : new ObjectOpenHashSet<>();
} finally {
trackerLock.readLock().unlock();
}
}
@Override
public Tracker getTracker(CNPlayer another) {
trackerLock.readLock().lock();
try {
return trackers.get(another);
} finally {
trackerLock.readLock().unlock();
}
}
@Override
public String currentBubble() {
if (currentNameplate == null) return "none";
return currentBubble;
}
@Override
public boolean setCurrentBubble(String bubble) {
if (!isLoaded()) return false;
this.currentBubble = bubble;
return true;
}
@Override
public String bubbleData() {
if (bubbleData == null) return "none";
return bubbleData;
}
@Override
public boolean setBubbleData(String bubble) {
if (!isLoaded()) return false;
this.currentBubble = bubble;
this.bubbleData = bubble;
return true;
}
@Override
public String currentNameplate() {
if (currentNameplate == null) return "none";
return currentNameplate;
}
@Override
public boolean setCurrentNameplate(String nameplate) {
if (!isLoaded()) return false;
if (!nameplate.equals(this.currentNameplate)) {
this.currentNameplate = nameplate;
}
return true;
}
@Override
public String nameplateData() {
return nameplateData;
}
@Override
public boolean setNameplateData(String nameplate) {
if (!isLoaded()) return false;
this.nameplateData = nameplate;
this.currentNameplate = nameplate;
return true;
}
@Override
public void save() {
this.plugin.getStorageManager().dataSource().updatePlayerData(
PlayerData.builder()
.uuid(uuid())
.nameplate(nameplateData())
.bubble(bubbleData())
.previewTags(isToggleablePreviewing())
.build(),
this.plugin.getScheduler().async()
);
}
@Override
public TeamView teamView() {
return teamView;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
AbstractCNPlayer that = (AbstractCNPlayer) object;
return entityID() == that.entityID() && uuid().equals(that.uuid());
}
@Override
public int hashCode() {
return entityID();
}
@Override
public String name() {
return Optional.ofNullable(this.name).orElse("");
}
@Override
public UUID uuid() {
return this.uuid;
}
@Override
public int entityID() {
return this.entityId;
}
}
@@ -0,0 +1,493 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import io.netty.channel.Channel;
import net.momirealms.customnameplates.api.feature.Feature;
import net.momirealms.customnameplates.api.feature.TimeStampData;
import net.momirealms.customnameplates.api.feature.tag.TeamView;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.placeholder.PlayerPlaceholder;
import net.momirealms.customnameplates.api.placeholder.RelationalPlaceholder;
import net.momirealms.customnameplates.api.placeholder.SharedPlaceholder;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Vector3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* CustomNameplates Player
*/
public interface CNPlayer {
/**
* Returns the player's name.
*
* @return the player's name
*/
String name();
/**
* Returns the UUID of the player.
*
* @return the player's UUID
*/
UUID uuid();
/**
* Returns the underlying player object (server-side representation).
*
* @return the player object
*/
Object player();
/**
* Returns the channel of the player
*
* @return the channel
*/
Channel channel();
/**
* Returns the entity ID of the player.
*
* @return the entity ID
*/
int entityID();
/**
* Returns the player's current position as a {@link Vector3}.
*
* @return the player's position
*/
Vector3 position();
/**
* Returns the name of the world the player is in.
*
* @return the world name
*/
String world();
/**
* Checks if the player is currently online.
*
* @return true if the player is online, false otherwise
*/
boolean isOnline();
/**
*
* Checks if the player is on spectator mode
*
* @return true if the player is on spectator mode, false otherwise
*/
boolean isSpectator();
/**
* Returns the scale of the player.
*
* @return the player's scale
*/
double scale();
/**
* Checks if the player is crouching.
*
* @return true if the player is crouching, false otherwise
*/
boolean isCrouching();
/**
* Checks if the player has been fully loaded into the system.
*
* @return true if the player is loaded, false otherwise
*/
boolean isLoaded();
/**
* Checks if the player is currently previewing
*
* @return true if the player is previewing, false otherwise
*/
boolean isTempPreviewing();
/**
* Checks if the player has turned their nameplate on
*
* @return true if the player has turned their nameplate on, false otherwise
*/
boolean isToggleablePreviewing();
/**
* Checks if the player has the specified permission.
*
* @param permission the permission to check
* @return true if the player has the permission, false otherwise
*/
boolean hasPermission(String permission);
/**
* Returns the player's current time
*
* @return the player's time
*/
long playerTime();
/**
* Checks if the player is flying.
*
* @return true if the player is flying, false otherwise
*/
boolean isFlying();
/**
* Returns the remaining air level for the player.
*
* @return the player's remaining air
*/
int remainingAir();
/**
* Retrieves the set of features that are actively using the specified placeholder.
*
* @param placeholder the placeholder to check
* @return the set of active features using the placeholder
*/
Set<Feature> activeFeatures(Placeholder placeholder);
/**
* Returns the placeholders that are actively used by the player's features.
*
* @return an array of active placeholders
*/
Placeholder[] activePlaceholders();
/**
* Acquires the actionbar, preventing CustomNameplates from taking control of it.
*
* @param id The feature ID requesting the actionbar.
*/
void acquireActionBar(String id);
/**
* Releases the actionbar, allowing CustomNameplates to take control again if no other features are active.
*
* @param id The feature ID releasing the actionbar.
*/
void releaseActionBar(String id);
/**
* Checks if CustomNameplates should take control of the actionbar.
*
* @return True if CustomNameplates should take over the actionbar, false otherwise.
*/
boolean shouldCNTakeOverActionBar();
/**
* Retrieves the list of placeholders that need to be refreshed based on their refresh intervals.
*
* @return a list of placeholders to refresh
*/
List<Placeholder> activePlaceholdersToRefresh();
/**
* Forces an update for the specified placeholders and relational placeholders with another player.
*
* @param placeholders the placeholders to update
* @param another the players related to the placeholders
*/
void forceUpdatePlaceholders(Set<Placeholder> placeholders, Collection<CNPlayer> another);
/**
* Retrieves the cached data for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached data as a string
*/
@NotNull
String getCachedSharedValue(SharedPlaceholder placeholder);
/**
* Retrieves the cached data for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached data as a string
*/
@NotNull
String getCachedPlayerValue(PlayerPlaceholder placeholder);
/**
* Retrieves the cached relational data between this player and another for a given placeholder.
*
* @param placeholder the relational placeholder
* @param another the other player
* @return the relational data as a string
*/
@NotNull
String getCachedRelationalValue(RelationalPlaceholder placeholder, CNPlayer another);
/**
* Retrieves the cached {@link TimeStampData} for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached TickStampData, or null if none exists
*/
@Nullable
TimeStampData<String> getRawPlayerValue(PlayerPlaceholder placeholder);
/**
* Retrieves the cached {@link TimeStampData} for a given placeholder.
*
* @param placeholder the placeholder to retrieve data for
* @return the cached TickStampData, or null if none exists
*/
@Nullable
TimeStampData<String> getRawSharedValue(SharedPlaceholder placeholder);
/**
* Retrieves the cached relational {@link TimeStampData} for a given placeholder.
*
* @param placeholder the relational placeholder
* @param another the other player
* @return the cached relational TickStampData, or null if none exists
*/
@Nullable
TimeStampData<String> getRawRelationalValue(RelationalPlaceholder placeholder, CNPlayer another);
/**
* Caches the specified {@link TimeStampData} for the given placeholder.
*
* @param placeholder the placeholder to cache
* @param value the value to cache
*/
void setPlayerValue(PlayerPlaceholder placeholder, TimeStampData<String> value);
/**
* Caches the specified {@link TimeStampData} for the given placeholder.
*
* @param placeholder the placeholder to cache
* @param value the value to cache
*/
void setSharedValue(SharedPlaceholder placeholder, TimeStampData<String> value);
/**
* Caches the specified relational {@link TimeStampData} for a given placeholder and player.
*
* @param placeholder the relational placeholder
* @param another the other player
* @param value the value to cache
*/
void setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, TimeStampData<String> value);
// /**
// * Caches the specified value for the given placeholder.
// *
// * @param placeholder the placeholder to cache
// * @param value the value to cache
// * @return true if the value was changed, false otherwise
// */
// boolean setPlayerValue(PlayerPlaceholder placeholder, String value);
// /**
// * Caches the specified relational value for a given placeholder and player.
// *
// * @param placeholder the relational placeholder
// * @param another the other player
// * @param value the value to cache
// * @return true if the value was changed, false otherwise
// */
// boolean setRelationalValue(RelationalPlaceholder placeholder, CNPlayer another, String value);
/**
* Adds a feature to the player
*
* @param feature the feature to add
*/
void addFeature(Feature feature);
/**
* Removes a feature from the player.
*
* @param feature the feature to remove
*/
void removeFeature(Feature feature);
/**
* Checks if the player meets the specified requirements.
*
* @param requirements the requirements to check
* @return true if all requirements are met, false otherwise
*/
boolean isMet(Requirement[] requirements);
/**
* Checks if the player meets the specified relational requirements with another player.
*
* @param another the other player
* @param requirements the relational requirements to check
* @return true if all requirements are met, false otherwise
*/
boolean isMet(CNPlayer another, Requirement[] requirements);
/**
* Adds a player to be track this player, creating a tracker for relational placeholders.
*
* @param another the player
* @return the tracker instance
*/
Tracker addPlayerToTracker(CNPlayer another);
/**
* Removes a player from tracking this player.
*
* @param another the player to stop tracking
*/
void removePlayerFromTracker(CNPlayer another);
/**
* Retrieves the set of nearby players tracking this player.
*
* @return the set of nearby players
*/
Collection<CNPlayer> nearbyPlayers();
/**
* Adds passenger entities to the tracker for another player.
*
* @param another the player whose passengers to track
* @param passengers the IDs of the passenger entities
*/
void trackPassengers(CNPlayer another, int... passengers);
/**
* Removes passenger entities from the tracker for another player.
*
* @param another the player whose passengers to stop tracking
* @param passengers the IDs of the passenger entities
*/
void untrackPassengers(CNPlayer another, int... passengers);
/**
* Retrieves the IDs of tracked passenger entities for another player.
*
* @param another the viewer
* @return the set of passenger entity IDs
*/
Set<Integer> getTrackedPassengerIds(CNPlayer another);
/**
* Retrieves the IDs of all passenger entities currently associated with this player.
*
* @return the set of passenger entity IDs
*/
Set<Integer> passengers();
/**
* Retrieves the tracker instance for another player.
*
* @param another the viewer
* @return the tracker instance, or null if none exists
*/
Tracker getTracker(CNPlayer another);
/**
* Gets the bubble currently in use (Includes temp bubble used in preview)
*
* @return bubble
*/
String currentBubble();
/**
* Sets the bubble currently in use, which would not be saved
*
* @param bubble id
* @return false if data not loaded
*/
boolean setCurrentBubble(String bubble);
/**
* Sets the bubble data
*
* @param bubble id
* @return false if data not loaded
*/
boolean setBubbleData(String bubble);
/**
* Gets the bubble data
*
* @return bubble id
*/
String bubbleData();
/**
* Gets the nameplate currently in use (Includes temp nameplate used in preview)
*
* @return nameplate
*/
String currentNameplate();
/**
* Sets the nameplate currently in use, which would not be saved
*
* @param nameplate id
* @return false if data not loaded
*/
boolean setCurrentNameplate(String nameplate);
/**
* Gets the nameplate data
*
* @return the nameplate id
*/
String nameplateData();
/**
* Sets the nameplate data
*
* @param nameplate id
* @return false if data not loaded
*/
boolean setNameplateData(String nameplate);
/**
* Save the player's current nameplate/bubble to database
*/
void save();
/**
* Get the player's team view
*
* @return team view
*/
TeamView teamView();
/**
* Check if the player is initialized
*
* @return initialized or not
*/
boolean isInitialized();
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,480 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.momirealms.customnameplates.api.feature.actionbar.ActionBarManager;
import net.momirealms.customnameplates.api.feature.advance.AdvanceManager;
import net.momirealms.customnameplates.api.feature.background.BackgroundManager;
import net.momirealms.customnameplates.api.feature.bossbar.BossBarManager;
import net.momirealms.customnameplates.api.feature.bubble.BubbleManager;
import net.momirealms.customnameplates.api.feature.chat.ChatManager;
import net.momirealms.customnameplates.api.feature.image.ImageManager;
import net.momirealms.customnameplates.api.feature.nameplate.NameplateManager;
import net.momirealms.customnameplates.api.feature.pack.ResourcePackManager;
import net.momirealms.customnameplates.api.feature.tag.UnlimitedTagManager;
import net.momirealms.customnameplates.api.helper.VersionHelper;
import net.momirealms.customnameplates.api.network.PacketSender;
import net.momirealms.customnameplates.api.network.PipelineInjector;
import net.momirealms.customnameplates.api.placeholder.PlaceholderManager;
import net.momirealms.customnameplates.api.requirement.RequirementManager;
import net.momirealms.customnameplates.api.storage.StorageManager;
import net.momirealms.customnameplates.common.dependency.DependencyManager;
import net.momirealms.customnameplates.common.event.EventManager;
import net.momirealms.customnameplates.common.locale.TranslationManager;
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
import net.momirealms.customnameplates.common.plugin.scheduler.SchedulerTask;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Abstract class representing the core plugin management of CustomNameplates.
* Provides access to managers for various features.
*/
public abstract class CustomNameplates implements NameplatesPlugin {
private static CustomNameplates instance;
/**
* Manages the dependencies required by the plugin or system.
*/
protected DependencyManager dependencyManager;
/**
* Handles translations for the plugin, ensuring text is localized based on the player's language.
*/
protected TranslationManager translationManager;
/**
* A debugger function that logs debug information with a "[DEBUG]" prefix.
* It consumes a supplier of strings and logs the result.
*/
protected Consumer<Supplier<String>> debugger = (s) -> getPluginLogger().info("[DEBUG] " + s.get());
/**
* Manages configuration settings, loading and accessing configuration data for the plugin.
*/
protected ConfigManager configManager;
/**
* Responsible for sending packets to clients or other network entities.
*/
protected PacketSender packetSender;
/**
* Injects custom pipelines into the system to modify or handle data processing flows.
*/
protected PipelineInjector pipelineInjector;
/**
* Manages placeholders used for dynamic text replacements in the plugin's output.
*/
protected PlaceholderManager placeholderManager;
/**
* Manages requirements or conditions that must be met for certain actions or events to occur.
*/
protected RequirementManager requirementManager;
/**
* Manages the action bar, responsible for displaying dynamic text to players in the action bar.
*/
protected ActionBarManager actionBarManager;
/**
* Manages the boss bar, which displays a customizable progress bar and messages to players.
*/
protected BossBarManager bossBarManager;
/**
* Manages unlimited tags that can be applied to players, items, or other entities.
*/
protected UnlimitedTagManager unlimitedTagManager;
/**
* Represents the platform on which the plugin or system is running (e.g., Spigot, Bukkit, etc.).
*/
protected Platform platform;
/**
* The main task or process that the plugin or system executes.
*/
protected MainTask mainTask;
/**
* A scheduled task that runs alongside the main task, typically used for periodic or delayed actions.
*/
protected SchedulerTask scheduledMainTask;
/**
* A map that tracks online players by their unique UUID, allowing quick access to player data.
*/
protected Map<UUID, CNPlayer> onlinePlayerMap = new ConcurrentHashMap<>();
/**
* A fast lookup map that associates entity IDs to player data (CNPlayer) for quick access.
*/
protected Map<Integer, CNPlayer> entityIDFastLookup = new ConcurrentHashMap<>();
/**
* Manages advances or progressions for players, such as achievements or level ups.
*/
protected AdvanceManager advanceManager;
/**
* Manages background tasks, likely for asynchronous processing or UI updates.
*/
protected BackgroundManager backgroundManager;
/**
* Manages events and event handling within the plugin or system.
*/
protected EventManager eventManager;
/**
* Manages the plugin's data storage system, including saving and retrieving player data.
*/
protected StorageManager storageManager;
/**
* Manages bubble effects, likely for UI or visual effects displayed to players.
*/
protected BubbleManager bubbleManager;
/**
* Manages chat functionality, including message formatting, commands, and interactions.
*/
protected ChatManager chatManager;
/**
* Manages images, such as textures or images for resource packs or player displays.
*/
protected ImageManager imageManager;
/**
* Manages nameplates displayed above players or entities.
*/
protected NameplateManager nameplateManager;
/**
* Manages resource packs, allowing the plugin to send custom content to players.
*/
protected ResourcePackManager resourcePackManager;
/**
* Provides an API for external access to the plugin's functionality and data.
*/
protected CustomNameplatesAPI api;
private String buildByBit = "%%__BUILTBYBIT__%%";
private String polymart = "%%__POLYMART__%%";
private String time = "%%__TIMESTAMP__%%";
private String user = "%%__USER__%%";
private String username = "%%__USERNAME__%%";
private boolean isLatest = false;
/**
* Creates the CustomNameplates instance
*/
protected CustomNameplates() {
instance = this;
}
/**
* Reloads the plugin
*/
@Override
public abstract void reload();
/**
* Disables the plugin, canceling any scheduled tasks.
*/
@Override
public abstract void disable();
@Override
public void enable() {
boolean downloadFromPolymart = polymart.equals("1");
boolean downloadFromBBB = buildByBit.equals("true");
if (ConfigManager.checkUpdate()) {
VersionHelper.UPDATE_CHECKER.apply(this).thenAccept(result -> {
String link;
if (downloadFromPolymart) {
link = "https://polymart.org/resource/2543/";
} else if (downloadFromBBB) {
link = "https://builtbybit.com/resources/36359/";
} else {
link = "https://github.com/Xiao-MoMi/Custom-Nameplates/";
}
if (!result) {
this.getPluginLogger().info("You are using the latest version.");
isLatest = true;
} else {
this.getPluginLogger().warn("Update is available: " + link);
isLatest = false;
}
});
}
}
@Override
public boolean isUpToDate() {
return isLatest;
}
/**
* Logs debug messages through the provided supplier.
*
* @param supplier a supplier that provides debug messages
*/
@Override
public void debug(Supplier<String> supplier) {
this.debugger.accept(supplier);
}
/**
* Returns the dependency manager for managing external dependencies.
*
* @return the {@link DependencyManager} instance
*/
@Override
public DependencyManager getDependencyManager() {
return dependencyManager;
}
/**
* Returns the translation manager for managing language translations.
*
* @return the {@link TranslationManager} instance
*/
@Override
public TranslationManager getTranslationManager() {
return translationManager;
}
/**
* Returns the configuration manager for managing plugin configurations.
*
* @return the {@link ConfigManager} instance
*/
@Override
public ConfigManager getConfigManager() {
return configManager;
}
/**
* Returns the manager responsible for handling placeholders.
*
* @return the {@link PlaceholderManager} instance
*/
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/**
* Returns the packet sender responsible for sending network packets to players.
*
* @return the {@link PacketSender} instance
*/
public PacketSender getPacketSender() {
return packetSender;
}
/**
* Returns the requirement manager responsible for managing requirements.
*
* @return the {@link RequirementManager} instance
*/
public RequirementManager getRequirementManager() {
return requirementManager;
}
/**
* Returns the action bar manager responsible for managing action bar displays.
*
* @return the {@link ActionBarManager} instance
*/
public ActionBarManager getActionBarManager() {
return actionBarManager;
}
/**
* Returns the manager responsible for handling unlimited tags.
*
* @return the {@link UnlimitedTagManager} instance
*/
public UnlimitedTagManager getUnlimitedTagManager() {
return unlimitedTagManager;
}
/**
* Returns the manager responsible for handling font advances.
*
* @return the {@link AdvanceManager} instance
*/
public AdvanceManager getAdvanceManager() {
return advanceManager;
}
/**
* Returns the background manager responsible for handling background images.
*
* @return the {@link BackgroundManager} instance
*/
public BackgroundManager getBackgroundManager() {
return backgroundManager;
}
/**
* Returns the event manager responsible for managing events.
*
* @return the {@link EventManager} instance
*/
@Override
public EventManager getEventManager() {
return eventManager;
}
/**
* Returns the storage manager responsible for handling data storage.
*
* @return the {@link StorageManager} instance
*/
public StorageManager getStorageManager() {
return storageManager;
}
/**
* Returns the nameplate manager responsible for managing nameplate images.
*
* @return the {@link NameplateManager} instance
*/
public NameplateManager getNameplateManager() {
return nameplateManager;
}
/**
* Returns the image manager responsible for handling images used within the plugin.
*
* @return the {@link ImageManager} instance
*/
public ImageManager getImageManager() {
return imageManager;
}
/**
* Returns the bubble manager responsible for managing chat bubbles.
*
* @return the {@link BubbleManager} instance
*/
public BubbleManager getBubbleManager() {
return bubbleManager;
}
/**
* Returns the chat manager responsible for managing chat-related features.
*
* @return the {@link ChatManager} instance
*/
public ChatManager getChatManager() {
return chatManager;
}
/**
* Returns the resource pack manager responsible for managing custom resource packs.
*
* @return the {@link ResourcePackManager} instance
*/
public ResourcePackManager getResourcePackManager() {
return resourcePackManager;
}
/**
* Get the API class
*
* @return api
*/
public CustomNameplatesAPI getAPI() {
return api;
}
/**
* Returns the platform object for accessing platform-specific functionality.
*
* @return the {@link Platform} instance
*/
public Platform getPlatform() {
return platform;
}
/**
* Returns a collection of all currently online players.
*
* @return a collection of {@link CNPlayer} instances
*/
public Collection<CNPlayer> getOnlinePlayers() {
return new ObjectArrayList<>(onlinePlayerMap.values());
}
/**
* Retrieves a player by their UUID.
*
* @param uuid the UUID of the player
* @return the {@link CNPlayer} instance, or null if not found
*/
public CNPlayer getPlayer(UUID uuid) {
return onlinePlayerMap.get(uuid);
}
/**
* Retrieves a player by their entity ID.
*
* @param entityID the entity ID of the player
* @return the {@link CNPlayer} instance, or null if not found
*/
public CNPlayer getPlayer(int entityID) {
return entityIDFastLookup.get(entityID);
}
/**
* Returns the singleton instance of CustomNameplates.
*
* @return the {@link CustomNameplates} instance
*/
public static CustomNameplates getInstance() {
return instance;
}
@ApiStatus.Experimental
public void addPlayerUnsafe(int entityId, CNPlayer player) {
if (this.entityIDFastLookup.containsKey(entityId)) return;
this.entityIDFastLookup.put(entityId, player);
}
@Nullable
@ApiStatus.Experimental
public CNPlayer removePlayerUnsafe(int entityId) {
return this.entityIDFastLookup.remove(entityId);
}
}
@@ -0,0 +1,169 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import net.momirealms.customnameplates.api.feature.background.Background;
import net.momirealms.customnameplates.api.feature.bubble.Bubble;
import net.momirealms.customnameplates.api.feature.nameplate.Nameplate;
import net.momirealms.customnameplates.api.helper.AdventureHelper;
import net.momirealms.customnameplates.api.placeholder.internal.StaticPosition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID;
/**
* CustomNameplatesAPI
*/
public record CustomNameplatesAPI(CustomNameplates plugin) {
private static CustomNameplatesAPI instance;
public CustomNameplatesAPI(CustomNameplates plugin) {
this.plugin = plugin;
instance = this;
}
/**
* Gets the CustomNameplates plugin instance.
*
* @return the CustomNameplates plugin
*/
@Override
public CustomNameplates plugin() {
return plugin;
}
/**
* Retrieves a player by their UUID.
*
* @param uuid the player's UUID
* @return the CNPlayer object if found, otherwise null
*/
@Nullable
public CNPlayer getPlayer(UUID uuid) {
return plugin.getPlayer(uuid);
}
/**
* Retrieves a Background by its ID.
*
* @param id the background ID
* @return an Optional containing the Background if found, or empty if not
*/
@NotNull
public Optional<Background> getBackground(@NotNull String id) {
return Optional.ofNullable(plugin.getBackgroundManager().backgroundById(id));
}
/**
* Retrieves a Nameplate by its ID.
*
* @param id the nameplate ID
* @return an Optional containing the Nameplate if found, or empty if not
*/
@NotNull
public Optional<Nameplate> getNameplate(@NotNull String id) {
return Optional.ofNullable(plugin.getNameplateManager().nameplateById(id));
}
/**
* Retrieves a Bubble by its ID.
*
* @param id the bubble ID
* @return an Optional containing the Bubble if found, or empty if not
*/
@NotNull
public Optional<Bubble> getBubble(@NotNull String id) {
return Optional.ofNullable(plugin.getBubbleManager().bubbleById(id));
}
/**
* Creates a text string with an image, applying margins around the image.
*
* @param text the text to be displayed
* @param adaptiveImage the image to insert with the text
* @param leftMargin the margin to apply on the left of the image
* @param rightMargin the margin to apply on the right of the image
* @return the resulting string with the image and margins
*/
@NotNull
public String createTextWithImage(@NotNull String text, @NotNull AdaptiveImage adaptiveImage, float leftMargin, float rightMargin) {
if (AdventureHelper.legacySupport) {
text = AdventureHelper.legacyToMiniMessage(text);
}
float advance = plugin.getAdvanceManager().getLineAdvance(text);
return AdventureHelper.surroundWithNameplatesFont(adaptiveImage.createImagePrefix(advance, leftMargin, rightMargin)) + text + AdventureHelper.surroundWithNameplatesFont(adaptiveImage.createImageSuffix(advance, leftMargin, rightMargin));
}
/**
* Gets the width advance (text length in visual representation) for a given text.
*
* @param text the text to measure
* @return the advance width of the text
*/
public float getTextAdvance(@NotNull String text) {
return plugin.getAdvanceManager().getLineAdvance(text);
}
/**
* Creates a statically positioned text, aligning it to the left, right, or middle
* of the specified width.
*
* @param text the text to be positioned
* @param width the total width for the text positioning
* @param position the desired static position (LEFT, RIGHT, MIDDLE)
* @return the resulting string with the appropriate positioning
*/
@NotNull
public String createStaticText(@NotNull String text, int width, @NotNull StaticPosition position) {
float parsedWidth = CustomNameplates.getInstance().getAdvanceManager().getLineAdvance(text);
switch (position) {
case LEFT -> {
return text + AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth));
}
case RIGHT -> {
return AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth)) + text;
}
case MIDDLE -> {
int half = (int) ((width - parsedWidth) / 2);
String left = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(half));
String right = AdventureHelper.surroundWithNameplatesFont(OffsetFont.createOffsets(width - parsedWidth - half));
return left + text + right;
}
default -> {
return "";
}
}
}
/**
* Returns the singleton instance of CustomNameplatesAPI.
* Throws an exception if the API has not been initialized.
*
* @return the CustomNameplatesAPI instance
*/
public static CustomNameplatesAPI getInstance() {
if (instance == null) {
throw new RuntimeException("Nameplates API has not been initialized yet.");
}
return instance;
}
}
@@ -1,141 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.manager.*;
import net.momirealms.customnameplates.api.scheduler.Scheduler;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class CustomNameplatesPlugin extends JavaPlugin {
protected static CustomNameplatesPlugin instance;
protected Scheduler scheduler;
protected StorageManager storageManager;
protected VersionManager versionManager;
protected AdventureManager adventureManager;
protected RequirementManager requirementManager;
protected BossBarManager bossBarManager;
protected ImageManager imageManager;
protected PlaceholderManager placeholderManager;
protected ResourcePackManager resourcePackManager;
protected BackGroundManager backGroundManager;
protected TeamManager teamManager;
protected NameplateManager nameplateManager;
protected ActionBarManager actionBarManager;
protected WidthManager widthManager;
protected BubbleManager bubbleManager;
protected CustomNameplatesPlugin() {
instance = this;
}
/* Get plugin instance */
public static CustomNameplatesPlugin getInstance() {
return instance;
}
/* Get plugin instance */
public static CustomNameplatesPlugin get() {
return instance;
}
/* reload the plugin */
public abstract void reload();
/* Get the scheduler */
public Scheduler getScheduler() {
return scheduler;
}
/* Get the storage manager */
public StorageManager getStorageManager() {
return storageManager;
}
/* Get the requirement manager */
public RequirementManager getRequirementManager() {
return requirementManager;
}
/* Get the image manager */
public ImageManager getImageManager() {
return imageManager;
}
/* Get the background manager */
public BackGroundManager getBackGroundManager() {
return backGroundManager;
}
/* Get the resource pack manager */
public ResourcePackManager getResourcePackManager() {
return resourcePackManager;
}
/* Get the adventure manager */
public AdventureManager getAdventure() {
return adventureManager;
}
/* Get the version manager */
public VersionManager getVersionManager() {
return versionManager;
}
/* Get the bossbar manager */
public BossBarManager getBossBarManager() {
return bossBarManager;
}
/* Get the placeholder manager */
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/* Get the team manager */
public TeamManager getTeamManager() {
return teamManager;
}
/* Get the actionbar manager */
public ActionBarManager getActionBarManager() {
return actionBarManager;
}
/* Get the nameplate manager */
public NameplateManager getNameplateManager() {
return nameplateManager;
}
/* Get the width manager */
public WidthManager getWidthManager() {
return widthManager;
}
/* Get the bubble manager */
public BubbleManager getBubbleManager() {
return bubbleManager;
}
/* debug get config by file name */
public abstract YamlConfiguration getConfig(String file);
/* debug message */
public abstract void debug(String s);
}
@@ -0,0 +1,109 @@
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.Set;
import java.util.UUID;
public class DummyPlayer extends AbstractCNPlayer<Object> {
private final CNPlayer target;
private final int megEntityId;
private final Vector3 position;
public DummyPlayer(CustomNameplates plugin, CNPlayer delegate, int entityId, Vector3 location) {
super(plugin, delegate.channel());
this.target = delegate;
this.megEntityId = entityId;
this.position = location;
}
@Override
public int entityID() {
return this.megEntityId;
}
@Override
public boolean hasPermission(String permission) {
return this.target.hasPermission(permission);
}
@Override
public Vector3 position() {
return this.position;
}
@Override
public String world() {
return this.target.world();
}
@Override
public boolean isOnline() {
return this.target.isOnline();
}
@Override
public boolean isSpectator() {
return false;
}
@Override
public double scale() {
return this.target.scale();
}
@Override
public boolean isCrouching() {
return false;
}
@Override
public long playerTime() {
return this.target.playerTime();
}
@Override
public boolean isFlying() {
return false;
}
@Override
public int remainingAir() {
return this.target.remainingAir();
}
@Override
public Set<Integer> passengers() {
return Set.of();
}
@Override
public boolean isInitialized() {
return false;
}
@Override
public String name() {
return this.target.name();
}
@Override
public UUID uuid() {
return this.target.uuid();
}
@Override
public Object player() {
return this.target.player();
}
@Override
public String currentNameplate() {
return this.target.currentNameplate();
}
@Override
public String currentBubble() {
return this.target.currentBubble();
}
}
@@ -0,0 +1,193 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* MainTask is a periodic task that handles various operations related to the plugin, such as refreshing conditions,
* managing placeholders, and monitoring performance. It runs periodically and executes different plugin managers
* in each cycle to maintain the smooth operation of the system.
*/
public class MainTask implements Runnable {
private static int RUN_TICKS = 0;
private static final Map<Integer, Integer> TIME_1 = new ConcurrentHashMap<>(2048);
private static final Map<Integer, Integer> TIME_2 = new ConcurrentHashMap<>(2048);
private static final Set<Integer> requestedSharedPlaceholders = Collections.synchronizedSet(new ObjectOpenHashSet<>());
private int timer;
private final CustomNameplates plugin;
private boolean state;
/**
* Constructs a new MainTask instance.
*
* @param plugin the plugin instance associated with this task
*/
public MainTask(CustomNameplates plugin) {
this.plugin = plugin;
}
/**
* Returns the total number of ticks the task has executed.
*
* @return the number of ticks
*/
public static int getTicks() {
return RUN_TICKS;
}
/**
* Checks if a shared placeholder request for the specified count ID has already been made.
*
* @param countId the ID to check
* @return true if the request has been made, false otherwise
*/
public static boolean hasRequested(int countId) {
return !requestedSharedPlaceholders.add(countId);
}
/**
* Resets the tick counter to 0.
*/
public static void reset() {
RUN_TICKS = 0;
}
@Override
public void run() {
// we should skip the task if the server is heavily loaded
if (this.state) return;
this.state = true;
try {
RUN_TICKS++;
requestedSharedPlaceholders.clear();
long time1 = System.nanoTime();
plugin.actionBarManager.refreshConditions();
plugin.bossBarManager.onTick();
plugin.unlimitedTagManager.onTick();
long time2 = System.nanoTime();
plugin.placeholderManager.refreshPlaceholders();
long time3 = System.nanoTime();
plugin.actionBarManager.checkHeartBeats();
int diff1 = (int) (time2 - time1);
TIME_1.put(timer, diff1);
int diff2 = (int) (time3 - time2);
TIME_2.put(timer, diff2);
timer++;
if (timer >= 1200) timer = 0;
if (RUN_TICKS < 0) {
CustomNameplates.getInstance().reload();
}
} finally {
this.state = false;
}
}
/**
* Retrieves the performance profile of the task based on the execution time and load.
*
* @return a HealthyProfile object containing the performance statistics
*/
public static HealthyProfile getHealthyProfile() {
long total1 = TIME_1.values().stream().mapToLong(Integer::longValue).sum();
long total2 = TIME_2.values().stream().mapToLong(Integer::longValue).sum();
long total = total1 + total2;
double size = TIME_1.size();
double load = total / size / 50_000_000;
return new HealthyProfile(
load,
(long) (total / size),
(int) (total1 / size),
(int) (total2 / size)
);
}
/**
* Represents the health profile of the task, including performance metrics such as load and execution times.
*/
public static class HealthyProfile {
private final double load;
private final long totalTimeNS;
private final int actionBarConditionNS;
private final int refreshPlaceholderNS;
/**
* Constructs a new HealthyProfile instance with the provided metrics.
*
* @param load the load factor based on execution time
* @param totalTimeNS the total time spent on the task, in nanoseconds
* @param actionBarConditionNS the average time spent on action bar conditions, in nanoseconds
* @param refreshPlaceholderNS the average time spent refreshing placeholders, in nanoseconds
*/
public HealthyProfile(
double load,
long totalTimeNS,
int actionBarConditionNS,
int refreshPlaceholderNS
) {
this.actionBarConditionNS = actionBarConditionNS;
this.refreshPlaceholderNS = refreshPlaceholderNS;
this.load = load;
this.totalTimeNS = totalTimeNS;
}
/**
* Gets the average time spent on action bar condition checks, in nanoseconds.
*
* @return the action bar condition time in nanoseconds
*/
public int getActionBarConditionNS() {
return actionBarConditionNS;
}
/**
* Gets the average time spent refreshing placeholders, in nanoseconds.
*
* @return the placeholder refresh time in nanoseconds
*/
public int getRefreshPlaceholderNS() {
return refreshPlaceholderNS;
}
/**
* Gets the load factor based on the task's execution time.
*
* @return the load factor
*/
public double getLoad() {
return load;
}
/**
* Gets the total time spent on the task, in nanoseconds.
*
* @return the total execution time in nanoseconds
*/
public long getTotalTimeNS() {
return totalTimeNS;
}
}
}
@@ -0,0 +1,232 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api;
import net.momirealms.customnameplates.api.feature.bossbar.BossBar;
import net.momirealms.customnameplates.api.feature.tag.NameTagConfig;
import net.momirealms.customnameplates.api.network.PacketEvent;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
/**
* Platform interface to abstract platform-specific operations for Minecraft components, packets, and placeholders.
*/
public interface Platform {
/**
* Converts a JSON string to a Minecraft component.
*
* @param json the JSON string
* @return the Minecraft component object
*/
Object jsonToMinecraftComponent(String json);
/**
* Converts a Minecraft component to a JSON string.
*
* @param component the Minecraft component
* @return the JSON string representation
*/
String minecraftComponentToJson(Object component);
/**
* Creates a vector object from the specified coordinates.
*
* @param x the X coordinate
* @param y the Y coordinate
* @param z the Z coordinate
* @return a vector object
*/
Object vec3(double x, double y, double z);
/**
* Registers a platform-specific placeholder.
*
* @param id the placeholder ID
* @return the registered {@link Placeholder} object
*/
Placeholder registerPlatformPlaceholder(String id);
/**
* Handles an event triggered when a packet is sent to a player.
*
* @param player the player receiving the packet
* @param event the packet event
*/
void onPacketSend(CNPlayer player, PacketEvent event);
/**
* Creates an action bar text packet for displaying a message in the action bar.
*
* @param component the component containing the text
* @return the action bar packet object
*/
Object setActionBarTextPacket(Object component);
/**
* Creates a boss bar packet for displaying a boss bar to a player.
*
* @param uuid the UUID of the boss bar
* @param component the component containing the boss bar text
* @param progress the boss bar progress (0.0 to 1.0)
* @param overlay the boss bar overlay style
* @param color the boss bar color
* @return the boss bar packet object
*/
Object createBossBarPacket(UUID uuid, Object component, float progress, BossBar.Overlay overlay, BossBar.Color color);
/**
* Creates a packet to remove a boss bar.
*
* @param uuid the UUID of the boss bar to remove
* @return the remove boss bar packet object
*/
Object removeBossBarPacket(UUID uuid);
/**
* Creates a packet to update the name of a boss bar.
*
* @param uuid the UUID of the boss bar
* @param component the component containing the new name
* @return the update boss bar name packet object
*/
Object updateBossBarNamePacket(UUID uuid, Object component);
/**
* Creates packets to display text on a custom text display entity.
*
* @param entityID the entity ID
* @param uuid the entity UUID
* @param position the position of the text
* @param pitch the pitch of the entity
* @param yaw the yaw of the entity
* @param headYaw the head yaw of the entity
* @param interpolationDelay the interpolation delay
* @param transformationInterpolationDuration the transformation interpolation duration
* @param positionRotationInterpolationDuration the position and rotation interpolation duration
* @param component the component containing the text
* @param backgroundColor the background color
* @param opacity the opacity of the text
* @param hasShadow whether the text has a shadow
* @param isSeeThrough whether the text is see-through
* @param useDefaultBackgroundColor whether the default background color is used
* @param alignment the alignment of the text
* @param billboard
* @param viewRange the view range of the text
* @param shadowRadius the shadow radius
* @param shadowStrength the shadow strength
* @param scale the scale of the text
* @param translation the translation of the text
* @param lineWidth the width of the text line
* @param isCrouching whether the entity is crouching
* @return a list of packets for creating the text display
*/
List<Object> createTextDisplayPacket(
int entityID, UUID uuid,
Vector3 position, float pitch, float yaw, double headYaw,
int interpolationDelay, int transformationInterpolationDuration, int positionRotationInterpolationDuration,
Object component, int backgroundColor, byte opacity,
boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment,
Billboard billboard, float viewRange, float shadowRadius, float shadowStrength,
Vector3 scale, Vector3 translation, int lineWidth, boolean isCrouching);
/**
* Creates a modifier for interpolation delay.
*
* @param delay the interpolation delay
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createInterpolationDelayModifier(int delay);
/**
* Creates a modifier for transformation interpolation duration.
*
* @param duration the transformation interpolation duration
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createTransformationInterpolationDurationModifier(int duration);
/**
* Creates a modifier to change the text component of a packet.
*
* @param component the new text component
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createTextComponentModifier(Object component);
/**
* Creates a modifier to change the scale of a text display.
*
* @param scale the new scale
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createScaleModifier(Vector3 scale);
/**
* Creates a modifier to change the translation of a text display.
*
* @param translation the new translation
* @return a consumer that applies the modifier to a list of packets
*/
Consumer<List<Object>> createTranslationModifier(Vector3 translation);
Consumer<List<Object>> createSneakModifier(boolean isSneaking, boolean seeThrough, NameTagConfig config);
/**
* Updates an existing text display entity with modifiers.
*
* @param entityID the entity ID of the text display
* @param modifiers the list of modifiers to apply
* @return the update text display packet object
*/
Object updateTextDisplayPacket(int entityID, List<Consumer<List<Object>>> modifiers);
/**
* Creates a packet to set passengers for a vehicle entity.
*
* @param vehicle the vehicle entity ID
* @param passengers the passenger entity IDs
* @return the set passengers packet object
*/
Object setPassengersPacket(int vehicle, int[] passengers);
/**
* Creates a packet to remove entities from the game world.
*
* @param entityID the entity IDs to remove
* @return the remove entity packet object
*/
Object removeEntityPacket(int... entityID);
/**
* Gets the biome based on location
*
* @param world world
* @param x x
* @param y y
* @param z z
* @return the biome key
*/
String getBiome(String world, int x, int y, int z);
}
@@ -1,58 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.data;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface DataStorageInterface {
/**
* Initialize the data resource
*/
void initialize();
/**
* Close the data resource
*/
void disable();
/**
* Get the storage data source type
*
* @return {@link StorageType}
*/
StorageType getStorageType();
/**
* Get a player's data by uuid
* This player can be an offline one
*
* @param uuid uuid
* @return player data
*/
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData);
CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData);
Set<UUID> getUniqueUsers(boolean legacy);
}
@@ -1,115 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.data;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class OnlineUser {
private final Player player;
private String nameplate;
private String bubble;
public OnlineUser(Player player, PlayerData playerData) {
this.player = player;
this.nameplate = playerData.getNameplate();
this.bubble = playerData.getBubble();
}
public PlayerData toPlayerData() {
return PlayerData.builder()
.setBubble(bubble)
.setNameplate(nameplate)
.build();
}
public UUID getUUID() {
return player.getUniqueId();
}
public Player getPlayer() {
return player;
}
/**
* Get the original nameplate key from data
*/
@NotNull
public String getNameplateKey() {
return nameplate;
}
/**
* Get the original bubble key from data
*/
@NotNull
public String getBubbleKey() {
return bubble;
}
/**
* This value might be inconsistent with the key get by "getNameplateKey()"
* Because if a player doesn't have a nameplate, his nameplate would be the default one
*/
@Nullable
public Nameplate getNameplate() {
String temp = nameplate;
if (temp.equals("none")) {
temp = CustomNameplatesPlugin.get().getNameplateManager().getDefaultNameplate();
}
return CustomNameplatesPlugin.get().getNameplateManager().getNameplate(temp);
}
/**
* This value might be inconsistent with the key get by "getBubbleKey()"
* Because if a player doesn't have a bubble, his bubble would be the default one
*/
@Nullable
public Bubble getBubble() {
String temp = nameplate;
if (temp.equals("none")) {
temp = CustomNameplatesPlugin.get().getBubbleManager().getDefaultBubble();
}
return CustomNameplatesPlugin.get().getBubbleManager().getBubble(temp);
}
/**
* Set nameplate for a player
*
* @param nameplate nameplate
*/
public void setNameplate(String nameplate) {
this.nameplate = nameplate;
}
/**
* Set bubble for a player
*
* @param bubble bubble
*/
public void setBubble(String bubble) {
this.bubble = bubble;
}
}
@@ -1,75 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.data;
import com.google.gson.annotations.SerializedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerData {
@SerializedName("nameplate")
private String nameplate;
@SerializedName("bubble")
private String bubble;
public static Builder builder() {
return new Builder();
}
public static PlayerData empty() {
return new PlayerData.Builder()
.setNameplate("none")
.setBubble("none")
.build();
}
public String getNameplate() {
return nameplate;
}
public String getBubble() {
return bubble;
}
public static class Builder {
private final PlayerData playerData;
public Builder() {
this.playerData = new PlayerData();
}
@NotNull
public Builder setNameplate(@Nullable String nameplate) {
this.playerData.nameplate = nameplate;
return this;
}
@NotNull
public Builder setBubble(@Nullable String bubble) {
this.playerData.bubble = bubble;
return this;
}
@NotNull
public PlayerData build() {
return this.playerData;
}
}
}
@@ -1,94 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* An event triggered when player sends a message
*/
public class BubblesSpawnEvent extends PlayerEvent implements Cancellable {
private boolean cancelled;
private String bubble;
private String text;
private static final HandlerList handlerList = new HandlerList();
public BubblesSpawnEvent(@NotNull Player who, String bubble, String text) {
super(who, true);
this.cancelled = false;
this.bubble = bubble;
this.text = text;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
/**
* Get the bubble's key
*/
public String getBubble() {
return bubble;
}
/**
* Set the bubble
*
* @param bubble bubble's key
*/
public void setBubble(String bubble) {
this.bubble = bubble;
}
/**
* Get the bubble text content
*/
public String getText() {
return text;
}
/**
* Set the bubble text content
*
* @param text text
*/
public void setText(String text) {
this.text = text;
}
}
@@ -1,50 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.event;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Plugin reload event
*/
public class CustomNameplatesReloadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final CustomNameplatesPlugin plugin;
public CustomNameplatesReloadEvent(CustomNameplatesPlugin plugin) {
this.plugin = plugin;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
public CustomNameplatesPlugin getPlugin() {
return plugin;
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.event;
import net.momirealms.customnameplates.api.storage.data.PlayerData;
import net.momirealms.customnameplates.common.event.NameplatesEvent;
import net.momirealms.customnameplates.common.event.Param;
/**
* Represents an event that is triggered when player data is loaded.
* This event provides access to the {@link PlayerData} for further processing.
*/
public interface DataLoadEvent extends NameplatesEvent {
/**
* Returns the {@link PlayerData} associated with this event.
*
* @return the loaded player data
*/
@Param(0)
PlayerData data();
}
@@ -1,69 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.event;
import net.momirealms.customnameplates.api.data.OnlineUser;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Player data loaded event
*/
public class NameplateDataLoadEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
private final UUID uuid;
private final OnlineUser onlineUser;
public NameplateDataLoadEvent(UUID uuid, OnlineUser onlineUser) {
super(true);
this.uuid = uuid;
this.onlineUser = onlineUser;
}
/**
* Get the UUID
*
* @return uuid
*/
public UUID getUUID() {
return uuid;
}
/**
* Get the online user
*
* @return online user
*/
public OnlineUser getOnlineUser() {
return onlineUser;
}
public static HandlerList getHandlerList() {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,19 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.scheduler;
package net.momirealms.customnameplates.api.event;
public interface CancellableTask {
import net.momirealms.customnameplates.common.event.NameplatesEvent;
/**
* Cancel the task
*/
void cancel();
/**
* Get if the task is cancelled or not
*
* @return cancelled or not
*/
boolean isCancelled();
}
/**
* Represents an event that is triggered when the nameplates configuration is reloaded.
*/
public interface NameplatesReloadEvent extends NameplatesEvent {
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
/**
* Interface representing an adaptive image with methods for generating image
* prefixes, suffixes, and the full image string based on specified parameters.
* <p>
* The implementation of this interface should define how the image is adapted
* based on the given margins and advance, which are used for layout and
* positioning purposes.
* </p>
*/
public interface AdaptiveImage {
/**
* Creates the prefix for the image with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image prefix
*/
String createImagePrefix(float advance, float leftMargin, float rightMargin);
/**
* Creates the suffix for the image with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image suffix
*/
String createImageSuffix(float advance, float leftMargin, float rightMargin);
/**
* Creates the full image string with the specified advance and margins.
*
* @param advance the advance for the image
* @param leftMargin the left margin for the image
* @param rightMargin the right margin for the image
* @return the generated image string
*/
String createImage(float advance, float leftMargin, float rightMargin);
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* Represents a piece of carousel text, which cycles through a series of texts with associated requirements and duration.
*/
public class CarouselText {
private final int duration;
private final Requirement[] requirements;
private final String rawText;
private final PreParsedDynamicText preParsedDynamicText;
private final boolean updateOnDisplay;
/**
* Constructs a new CarouselText instance.
*
* @param duration the duration (in ticks) for how long this text is displayed
* @param requirements the requirements for displaying this text
* @param rawText the raw text content
* @param updateOnDisplay whether the text should be updated when displayed
*/
public CarouselText(int duration, Requirement[] requirements, String rawText, boolean updateOnDisplay) {
this.duration = duration;
this.requirements = requirements;
this.rawText = rawText;
this.preParsedDynamicText = new PreParsedDynamicText(rawText);
this.preParsedDynamicText.init();
this.updateOnDisplay = updateOnDisplay;
}
/**
* Returns the duration (in ticks) for how long this text will be displayed.
*
* @return the display duration
*/
public int duration() {
return duration;
}
/**
* Returns the requirements that must be met to display this text.
*
* @return an array of requirements
*/
public Requirement[] requirements() {
return requirements;
}
/**
* Returns the raw text content.
*
* @return the raw text
*/
public String text() {
return rawText;
}
/**
* Returns the pre-parsed dynamic text, which processes placeholders or dynamic content.
*
* @return the pre-parsed dynamic text
*/
public PreParsedDynamicText preParsedDynamicText() {
return preParsedDynamicText;
}
/**
* Checks if the text should be updated each time it is displayed.
*
* @return true if the text updates on display, false otherwise
*/
public boolean updateOnDisplay() {
return updateOnDisplay;
}
}
@@ -15,20 +15,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.character;
package net.momirealms.customnameplates.api.feature;
/**
* Utility class for automatically arranging characters.
* Provides methods to increase, retrieve, and reset the current character.
*/
public class CharacterArranger {
/**
* The current character being managed by the arranger.
*/
public static char currentChar;
/**
* Increases the current character by 1.
*/
public static void increase() {
currentChar = (char) (currentChar + '\u0001');
}
/**
* Get and increase the char arranged automatically by the plugin
* Retrieves the current character and then increases it.
*
* @return char
* @return the current character before increase
*/
public static char getAndIncrease() {
char temp = currentChar;
@@ -37,9 +47,9 @@ public class CharacterArranger {
}
/**
* Increase and get the char arranged automatically by the plugin
* Increases the current character and then retrieves it.
*
* @return char
* @return the current character after increase
*/
public static char increaseAndGet() {
increase();
@@ -47,11 +57,11 @@ public class CharacterArranger {
}
/**
* Reset the initial char
* Resets the current character to the specified value.
*
* @param c char
* @param c the character to reset to
*/
public static void reset(char c) {
currentChar = c;
}
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Represents a listener for player chat events, providing a callback method
* when a player sends a message in a specific channel.
*/
public interface ChatListener {
/**
* Called when a player sends a chat message in a specified channel.
*
* @param player the player who sent the message
* @param message the content of the message
* @param channel the channel where the message was sent
*/
void onPlayerChat(CNPlayer player, String message, String channel);
}
@@ -0,0 +1,166 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CustomNameplates;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
* Represents a configured character with associated image, dimensions, and advance (spacing).
*/
public class ConfiguredCharacter {
private final char character;
private final File imageFile;
private final int height;
private final int ascent;
private final float advance;
/**
* Creates a new ConfiguredCharacter instance using an automatically assigned character.
*
* @param imageFile the image file associated with this character
* @param ascent the ascent value (distance from the baseline to the top of the character)
* @param height the height of the character
* @return a new ConfiguredCharacter instance
*/
public static ConfiguredCharacter create(File imageFile, int ascent, int height) {
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height);
}
/**
* Creates a new ConfiguredCharacter instance using an automatically assigned character and a specified advance value.
*
* @param imageFile the image file associated with this character
* @param ascent the ascent value (distance from the baseline to the top of the character)
* @param height the height of the character
* @param advance the advance (spacing) for this character
* @return a new ConfiguredCharacter instance
*/
public static ConfiguredCharacter create(File imageFile, int ascent, int height, float advance) {
return new ConfiguredCharacter(CharacterArranger.getAndIncrease(), imageFile, ascent, height, advance);
}
/**
* Constructs a new ConfiguredCharacter instance with specified character, image, ascent, height, and advance values.
*
* @param character the character to associate
* @param imageFile the image file
* @param ascent the ascent value
* @param height the height of the character
* @param advance the advance (spacing) for the character
*/
public ConfiguredCharacter(char character, File imageFile, int ascent, int height, float advance) {
this.character = character;
this.imageFile = imageFile;
this.ascent = ascent;
this.height = height;
this.advance = advance;
}
/**
* Constructs a new ConfiguredCharacter instance with automatic advance calculation.
*
* @param character the character to associate
* @param imageFile the image file
* @param ascent the ascent value
* @param height the height of the character
*/
public ConfiguredCharacter(char character, File imageFile, int ascent, int height) {
this.character = character;
this.imageFile = imageFile;
this.ascent = ascent;
this.height = height;
if (this.ascent > this.height) {
CustomNameplates.getInstance().getPluginLogger().severe(String.format(
"Found an issue in the image config. Ascent(%s) is higher than height(%s). %s", ascent, height, imageFile.getAbsolutePath()));
}
try {
BufferedImage bufferedImage = ImageIO.read(imageFile);
int imageHeight = bufferedImage.getHeight();
int imageWidth = bufferedImage.getWidth();
float scale = (float) height / imageHeight;
int i;
outer:
for (i = imageWidth - 1; i >= 0; --i) {
for (int k = 0; k < imageHeight; ++k) {
int rgb = bufferedImage.getRGB(i, k);
int alpha = (rgb >> 24) & 0xff;
if (alpha != 0) {
break outer;
}
}
}
advance = (float) Math.round((i + 1) * scale) + 1f;
} catch (IOException e) {
throw new RuntimeException("Failed to load " + imageFile.toPath(), e);
}
}
/**
* Returns the character associated with this ConfiguredCharacter.
*
* @return the character
*/
public char character() {
return character;
}
/**
* Returns the ascent value of this character.
*
* @return the ascent value
*/
public int ascent() {
return ascent;
}
/**
* Returns the advance (spacing) of this character.
*
* @return the advance value
*/
public float advance() {
return advance;
}
/**
* Returns the height of this character.
*
* @return the character height
*/
public int height() {
return height;
}
/**
* Returns the image file associated with this character.
*
* @return the image file
*/
public File imageFile() {
return imageFile;
}
}
@@ -0,0 +1,80 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
/**
* Represents dynamic text that can be rendered for a specific player, with support for placeholders and custom text functions.
*/
public class DynamicText {
private final String text;
private final List<Function<CNPlayer, String>> texts;
private final Set<Placeholder> placeholders;
/**
* Constructs a new DynamicText instance.
*
* @param text the raw text string
* @param texts a list of functions that generate text dynamically based on the player
* @param placeholders a set of placeholders used in the text
*/
public DynamicText(String text, List<Function<CNPlayer, String>> texts, Set<Placeholder> placeholders) {
this.text = text;
this.texts = texts;
this.placeholders = placeholders;
}
/**
* Returns the set of placeholders associated with this dynamic text.
*
* @return a set of placeholders
*/
public Set<Placeholder> placeholders() {
return placeholders;
}
/**
* Renders the dynamic text for the specified player by applying the text functions.
*
* @param viewer the player for whom the text is being rendered
* @return the rendered text
*/
public String render(CNPlayer viewer) {
StringBuilder builder = new StringBuilder();
for (Function<CNPlayer, String> function : texts) {
builder.append(function.apply(viewer));
}
return builder.toString();
}
/**
* Returns the raw text string.
*
* @return the raw text
*/
public String text() {
return text;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.placeholder.Placeholder;
import java.util.Set;
/**
* Represents a feature that can utilize placeholders and manage updates based on player interaction.
*/
public interface Feature {
/**
* Returns the name of the feature.
*
* @return the feature name
*/
String name();
/**
* Returns the set of placeholders that are currently active within this feature.
*
* @return a set of active placeholders
*/
Set<Placeholder> activePlaceholders();
/**
* Returns the set of all placeholders that this feature can use.
*
* @return a set of all possible placeholders
*/
Set<Placeholder> allPlaceholders();
/**
* Notifies the feature that placeholders for the specified player have been updated.
*
* @param p1 the player whose placeholders have been updated
* @param force if true, forces an update even if no changes are detected
*/
void notifyPlaceholderUpdates(CNPlayer p1, boolean force);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,20 +15,26 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import net.momirealms.customnameplates.api.CNPlayer;
public interface ActionBarManager {
/**
* Listener for handling player join and quit events.
*/
public interface JoinQuitListener {
/**
* Get the actionbar sent by other plugins in MiniMessage format
* Return "" if no other actionbar received
* Called when a player joins the server.
*
* @param player receiver
* @return text
* @param player the player who joined
*/
@NotNull
String getOtherPluginActionBar(Player player);
void onPlayerJoin(CNPlayer player);
/**
* Called when a player quits the server.
*
* @param player the player who quit
*/
void onPlayerQuit(CNPlayer player);
}
@@ -0,0 +1,403 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
/**
* Enum representing different font offsets used for handling character spacing and height.
* The offsets are categorized into positive and negative values, each corresponding to
* a specific advance (horizontal movement) and height (vertical movement).
*/
public enum OffsetFont {
/**
* Represents a font with a character value of '\uf800', horizontal advance of -1, and vertical height of -3.
*/
NEG_1('\uf800', -1, -3),
/**
* Represents a font with a character value of '\uf801', horizontal advance of -2, and vertical height of -4.
*/
NEG_2('\uf801', -2, -4),
/**
* Represents a font with a character value of '\uf802', horizontal advance of -3, and vertical height of -5.
*/
NEG_3('\uf802', -3, -5),
/**
* Represents a font with a character value of '\uf803', horizontal advance of -4, and vertical height of -6.
*/
NEG_4('\uf803', -4, -6),
/**
* Represents a font with a character value of '\uf804', horizontal advance of -5, and vertical height of -7.
*/
NEG_5('\uf804', -5, -7),
/**
* Represents a font with a character value of '\uf805', horizontal advance of -6, and vertical height of -8.
*/
NEG_6('\uf805', -6, -8),
/**
* Represents a font with a character value of '\uf806', horizontal advance of -7, and vertical height of -9.
*/
NEG_7('\uf806', -7, -9),
/**
* Represents a font with a character value of '\uf807', horizontal advance of -8, and vertical height of -10.
*/
NEG_8('\uf807', -8, -10),
/**
* Represents a font with a character value of '\uf808', horizontal advance of -9, and vertical height of -11.
*/
NEG_9('\uf808', -9, -11),
/**
* Represents a font with a character value of '\uf809', horizontal advance of -10, and vertical height of -12.
*/
NEG_10('\uf809', -10, -12),
/**
* Represents a font with a character value of '\uf80a', horizontal advance of -11, and vertical height of -13.
*/
NEG_11('\uf80a', -11, -13),
/**
* Represents a font with a character value of '\uf80b', horizontal advance of -12, and vertical height of -14.
*/
NEG_12('\uf80b', -12, -14),
/**
* Represents a font with a character value of '\uf80c', horizontal advance of -13, and vertical height of -15.
*/
NEG_13('\uf80c', -13, -15),
/**
* Represents a font with a character value of '\uf80d', horizontal advance of -14, and vertical height of -16.
*/
NEG_14('\uf80d', -14, -16),
/**
* Represents a font with a character value of '\uf80e', horizontal advance of -15, and vertical height of -17.
*/
NEG_15('\uf80e', -15, -17),
/**
* Represents a font with a character value of '\uf80f', horizontal advance of -16, and vertical height of -18.
*/
NEG_16('\uf80f', -16, -18),
/**
* Represents a font with a character value of '\uf810', horizontal advance of -24, and vertical height of -26.
*/
NEG_24('\uf810', -24, -26),
/**
* Represents a font with a character value of '\uf811', horizontal advance of -32, and vertical height of -34.
*/
NEG_32('\uf811', -32, -34),
/**
* Represents a font with a character value of '\uf812', horizontal advance of -48, and vertical height of -50.
*/
NEG_48('\uf812', -48, -50),
/**
* Represents a font with a character value of '\uf813', horizontal advance of -64, and vertical height of -66.
*/
NEG_64('\uf813', -64, -66),
/**
* Represents a font with a character value of '\uf814', horizontal advance of -128, and vertical height of -130.
*/
NEG_128('\uf814', -128, -130),
/**
* Represents a font with a character value of '\uf815', horizontal advance of -256, and vertical height of -258.
*/
NEG_256('\uf815', -256, -258),
/**
* Represents a font with a character value of '\uf830', horizontal advance of 1, and vertical height of -1.
*/
POS_1('\uf830', 1, -1),
/**
* Represents a font with a character value of '\uf831', horizontal advance of 2, and vertical height of 1.
*/
POS_2('\uf831', 2, 1),
/**
* Represents a font with a character value of '\uf832', horizontal advance of 3, and vertical height of 2.
*/
POS_3('\uf832', 3, 2),
/**
* Represents a font with a character value of '\uf833', horizontal advance of 4, and vertical height of 3.
*/
POS_4('\uf833', 4, 3),
/**
* Represents a font with a character value of '\uf834', horizontal advance of 5, and vertical height of 4.
*/
POS_5('\uf834', 5, 4),
/**
* Represents a font with a character value of '\uf835', horizontal advance of 6, and vertical height of 5.
*/
POS_6('\uf835', 6, 5),
/**
* Represents a font with a character value of '\uf836', horizontal advance of 7, and vertical height of 6.
*/
POS_7('\uf836', 7, 6),
/**
* Represents a font with a character value of '\uf837', horizontal advance of 8, and vertical height of 7.
*/
POS_8('\uf837', 8, 7),
/**
* Represents a font with a character value of '\uf838', horizontal advance of 9, and vertical height of 8.
*/
POS_9('\uf838', 9, 8),
/**
* Represents a font with a character value of '\uf839', horizontal advance of 10, and vertical height of 9.
*/
POS_10('\uf839', 10, 9),
/**
* Represents a font with a character value of '\uf83a', horizontal advance of 11, and vertical height of 10.
*/
POS_11('\uf83a', 11, 10),
/**
* Represents a font with a character value of '\uf83b', horizontal advance of 12, and vertical height of 11.
*/
POS_12('\uf83b', 12, 11),
/**
* Represents a font with a character value of '\uf83c', horizontal advance of 13, and vertical height of 12.
*/
POS_13('\uf83c', 13, 12),
/**
* Represents a font with a character value of '\uf83d', horizontal advance of 14, and vertical height of 13.
*/
POS_14('\uf83d', 14, 13),
/**
* Represents a font with a character value of '\uf83e', horizontal advance of 15, and vertical height of 14.
*/
POS_15('\uf83e', 15, 14),
/**
* Represents a font with a character value of '\uf83f', horizontal advance of 16, and vertical height of 15.
*/
POS_16('\uf83f', 16, 15),
/**
* Represents a font with a character value of '\uf840', horizontal advance of 24, and vertical height of 23.
*/
POS_24('\uf840', 24, 23),
/**
* Represents a font with a character value of '\uf841', horizontal advance of 32, and vertical height of 31.
*/
POS_32('\uf841', 32, 31),
/**
* Represents a font with a character value of '\uf842', horizontal advance of 48, and vertical height of 47.
*/
POS_48('\uf842', 48, 47),
/**
* Represents a font with a character value of '\uf843', horizontal advance of 64, and vertical height of 63.
*/
POS_64('\uf843', 64, 63),
/**
* Represents a font with a character value of '\uf844', horizontal advance of 128, and vertical height of 127.
*/
POS_128('\uf844', 128, 127),
/**
* Represents a font with a character value of '\uf845', horizontal advance of 256, and vertical height of 255.
*/
POS_256('\uf845', 256, 255);
private static final OffsetFont[] negFastLookup = new OffsetFont[17];
private static final OffsetFont[] posFastLookup = new OffsetFont[17];
static {
for (OffsetFont f : OffsetFont.values()) {
if (f.advance > 0 && f.advance <= 16) {
posFastLookup[f.advance] = f;
} else if (f.advance < 0 && f.advance >= -16) {
negFastLookup[-f.advance] = f;
}
}
}
private final char character;
private final int advance;
private final int height;
/**
* Constructor to initialize the OffsetFont with a specific character, advance, and height.
*
* @param character the character associated with the offset
* @param advance the horizontal movement (positive or negative)
* @param height the vertical movement (positive or negative)
*/
OffsetFont(char character, int advance, int height) {
this.character = character;
this.advance = advance;
this.height = height;
}
/**
* Gets the character associated with this offset font.
*
* @return the character of this offset font
*/
public char character() {
return this.character;
}
/**
* Gets the advance value for this offset font.
*
* @return the advance (horizontal movement) for this offset font
*/
public float advance() {
return this.advance;
}
/**
* Gets the height value for this offset font.
*
* @return the height (vertical movement) for this offset font
*/
public int height() {
return this.height;
}
/**
* Creates a string of offset characters based on the given offset value.
* The result depends on whether the offset is positive or negative.
*
* @param offset the offset value
* @return a string of offset characters
*/
public static String createOffsets(float offset) {
if (offset >= 0) {
return shortestPosChars(offset);
} else {
return shortestNegChars(-offset);
}
}
/**
* Generates a string of the shortest possible negative offset characters
* that sum up to the given advance value.
*
* @param advance the negative advance value
* @return the shortest string of negative offset characters
*/
public static String shortestNegChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
while (n >= 256) {
stringBuilder.append(OffsetFont.NEG_256.character());
n -= 256;
}
if (n - 128 >= 0) {
stringBuilder.append(OffsetFont.NEG_128.character());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_64.character());
n -= 64;
}
if (n - 48 >= 0) {
stringBuilder.append(OffsetFont.NEG_48.character());
n -= 48;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_32.character());
n -= 32;
}
if (n - 24 >= 0) {
stringBuilder.append(OffsetFont.NEG_24.character());
n -= 24;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_16.character());
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(negFastLookup[n].character());
return stringBuilder.toString();
}
/**
* Generates a string of the shortest possible positive offset characters
* that sum up to the given advance value.
*
* @param advance the positive advance value
* @return the shortest string of positive offset characters
*/
public static String shortestPosChars(float advance) {
int n = (int) Math.ceil(advance);
StringBuilder stringBuilder = new StringBuilder();
while (n >= 256) {
stringBuilder.append(OffsetFont.POS_256.character());
n -= 256;
}
if (n - 128 >= 0) {
stringBuilder.append(OffsetFont.POS_128.character());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.POS_64.character());
n -= 64;
}
if (n - 48 >= 0) {
stringBuilder.append(OffsetFont.POS_48.character());
n -= 48;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.POS_32.character());
n -= 32;
}
if (n - 24 >= 0) {
stringBuilder.append(OffsetFont.POS_24.character());
n -= 24;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.POS_16.character());
n -= 16;
}
if (n == 0) return stringBuilder.toString();
stringBuilder.append(posFastLookup[n].character());
return stringBuilder.toString();
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Listener for handling player actions
*/
public interface PlayerListener {
/**
* Called when a player changes the world
*
* @param player the player who changes the world
*/
void onChangeWorld(CNPlayer player);
/**
* Called when a player respawns
*
* @param player the player who respawns
*/
void onRespawn(CNPlayer player);
/**
* Called when a player teleports
*
* @param player the player who respawns
*/
void onTeleport(CNPlayer player);
}
@@ -0,0 +1,162 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.CustomNameplates;
import net.momirealms.customnameplates.api.placeholder.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
/**
* Represents a dynamically parsed text that can contain placeholders.
* The text is parsed at initialization and placeholders are replaced with corresponding values.
* This class provides functionality to manage placeholders and generate dynamic text for players.
*/
public class PreParsedDynamicText {
private final String text;
private final List<Function<CNPlayer, Function<CNPlayer, String>>> textFunctions = new ObjectArrayList<>();
private final Set<Placeholder> set = new ObjectOpenHashSet<>();
private boolean init = false;
/**
* Constructs a PreParsedDynamicText with the given text.
*
* @param text the original text containing placeholders to be parsed
* @throws NullPointerException if the provided text is null
*/
public PreParsedDynamicText(String text) {
this.text = Objects.requireNonNull(text);
}
/**
* Constructs a PreParsedDynamicText with the given text and initializes it (parses placeholders).
*
* @param text the original text containing placeholders to be parsed
* @param init flag indicating whether to initialize the text immediately
* @throws NullPointerException if the provided text is null
*/
public PreParsedDynamicText(String text, boolean init) {
this.text = Objects.requireNonNull(text);
if (init) init();
}
/**
* Initializes the PreParsedDynamicText by parsing the text for placeholders and creating
* corresponding functions for replacing the placeholders with values.
* This method is called automatically if the constructor is provided with `true` for the init flag.
*/
public void init() {
if (init) return;
init = true;
PlaceholderManager manager = CustomNameplates.getInstance().getPlaceholderManager();
List<String> detectedPlaceholders = manager.detectPlaceholders(text);
List<Function<CNPlayer, Function<CNPlayer, String>>> convertor = new ArrayList<>(detectedPlaceholders.size());
List<Placeholder> placeholders = new ArrayList<>(detectedPlaceholders.size());
for (String id : detectedPlaceholders) {
Placeholder placeholder = manager.getPlaceholder(id);
placeholders.add(placeholder);
if (placeholder instanceof RelationalPlaceholder relationalPlaceholder) {
convertor.add((owner) -> (viewer) -> owner.getCachedRelationalValue(relationalPlaceholder, viewer));
} else if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
convertor.add((owner) -> (viewer) -> {
if (owner != null) {
return owner.getCachedPlayerValue(playerPlaceholder);
} else {
return playerPlaceholder.request(null);
}
});
} else if (placeholder instanceof SharedPlaceholder sharedPlaceholder) {
convertor.add((owner) -> (viewer) -> {
if (owner != null) {
return owner.getCachedSharedValue(sharedPlaceholder);
} else {
return sharedPlaceholder.request();
}
});
} else {
convertor.add((owner) -> (viewer) -> id);
}
}
int placeholderSize = placeholders.size();
StringBuilder original0 = new StringBuilder(text);
int lastIndex = 0;
for (int i = 0; i < placeholderSize; i++) {
String id = placeholders.get(i).id();
int index = original0.indexOf(id, lastIndex);
if (index == -1) {
throw new RuntimeException("Placeholder ID not found in text");
}
if (index != lastIndex) {
String textBefore = original0.substring(lastIndex, index);
textFunctions.add((owner) -> (viewer) -> textBefore);
}
textFunctions.add(convertor.get(i));
lastIndex = index + id.length();
}
if (lastIndex < original0.length()) {
String remaining = original0.substring(lastIndex);
textFunctions.add((owner) -> (viewer) -> remaining);
}
// To optimize the tree height
set.addAll(new ObjectArrayList<>(placeholders));
}
/**
* Creates a dynamic text based on the current pre-parsed text, tailored to the given player.
* This method uses the player's data to generate the final text.
*
* @param player the player for whom the dynamic text is being generated
* @return a DynamicText object containing the final text for the player
*/
public DynamicText fastCreate(CNPlayer player) {
List<Function<CNPlayer, String>> functions = new ObjectArrayList<>();
for (Function<CNPlayer, Function<CNPlayer, String>> textFunction : textFunctions) {
functions.add(textFunction.apply(player));
}
return new DynamicText(text, functions, set);
}
/**
* Returns a set of placeholders detected in the text.
*
* @return a set of placeholders used in the text
*/
public Set<Placeholder> placeholders() {
return set;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
PreParsedDynamicText that = (PreParsedDynamicText) object;
return text.equals(that.text);
}
@Override
public int hashCode() {
return text.hashCode();
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Represents a feature that involves relationships between two players and supports placeholder updates for both players.
*/
public interface RelationalFeature extends Feature {
/**
* Notifies the feature that placeholders for the relationship between two players have been updated.
*
* @param p1 the first player
* @param p2 the second player
* @param force if true, forces an update even if no changes are detected
*/
void notifyPlaceholderUpdates(CNPlayer p1, CNPlayer p2, boolean force);
}
@@ -0,0 +1,129 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature;
import net.momirealms.customnameplates.api.MainTask;
/**
* Represents a data structure that stores an object and tracks when it was last updated,
* using packed ticks and a boolean flag to indicate changes.
*
* @param <D> the type of data being stored
*/
public class TimeStampData<D> {
private D data;
private int packedTicks;
/**
* Constructs a new TickStampData instance.
*
* @param data the data to store
* @param ticks the number of ticks to store
* @param changed whether the value has changed
*/
public TimeStampData(D data, int ticks, boolean changed) {
this.data = data;
this.packedTicks = packBooleanAndTicks(changed, ticks);
}
/**
* Updates the stored data.
*
* @param data the new data
*/
public void data(D data) {
this.data = data;
}
/**
* Updates the packed ticks and change status.
*
* @param changed whether the value has changed
*/
public void updateTicks(boolean changed) {
this.packedTicks = packBooleanAndTicks(changed, MainTask.getTicks());
}
/**
* Consume the flag
*/
public void resetChangedFlag() {
this.packedTicks = packedTicks & 0x7FFFFFFF;;
}
/**
* Returns the stored data.
*
* @return the data
*/
public D data() {
return data;
}
/**
* Checks if the value has changed since the last update.
*
* @return true if the value has changed, false otherwise
*/
public boolean hasValueChanged() {
return unpackBoolean(packedTicks);
}
/**
* Returns the stored number of ticks.
*
* @return the number of ticks
*/
public int ticks() {
return unpackTicks(packedTicks);
}
/**
* Packs the boolean change flag and ticks into a single integer.
*
* @param hasValueChanged whether the value has changed
* @param ticks the number of ticks
* @return the packed integer
*/
public static int packBooleanAndTicks(boolean hasValueChanged, int ticks) {
int numberMasked = ticks & 0x7FFFFFFF; // Mask for 31 bits
int booleanBit = hasValueChanged ? 1 << 31 : 0; // Set the highest bit for the boolean flag
return booleanBit | numberMasked;
}
/**
* Unpacks the number of ticks from the packed integer.
*
* @param packed the packed integer
* @return the number of ticks
*/
public static int unpackTicks(int packed) {
return packed & 0x7FFFFFFF; // Extract the lower 31 bits for ticks
}
/**
* Unpacks the boolean change flag from the packed integer.
*
* @param packed the packed integer
* @return true if the value has changed, false otherwise
*/
public static boolean unpackBoolean(int packed) {
return (packed & 0x80000000) != 0; // Check the highest bit for the boolean flag
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.actionbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* ActionBar Config
*/
public interface ActionBarConfig {
/**
* Returns the unique ID of the ActionBar configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the list of requirements for the ActionBar.
*
* @return an array of requirements
*/
Requirement[] requirements();
/**
* Returns the carousel texts used in the ActionBar.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Creates a new builder for constructing an ActionBarConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new ActionBarConfigImpl.BuilderImpl();
}
/**
* Builder for creating an ActionBarConfig.
*/
interface Builder {
/**
* Sets the unique ID for the ActionBar configuration.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the requirements for the ActionBar.
*
* @param requirements an array of requirements
* @return the builder instance
*/
Builder requirement(Requirement[] requirements);
/**
* Sets the carousel texts for the ActionBar.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Builds and returns the ActionBarConfig.
*
* @return the constructed ActionBarConfig
*/
ActionBarConfig build();
}
}
@@ -0,0 +1,85 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.actionbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
/**
* Implementation of ActionBarConfig
*/
public class ActionBarConfigImpl implements ActionBarConfig {
private final String id;
private final Requirement[] requirements;
private final CarouselText[] carouselTexts;
private ActionBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] requirements() {
return requirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
/**
* Builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder requirement(Requirement[] requirements) {
this.requirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public ActionBarConfig build() {
return new ActionBarConfigImpl(id, requirements, carouselTexts);
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.actionbar;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
/**
* Interface representing a manager for handling ActionBars.
*/
public interface ActionBarManager extends Reloadable {
/**
* Refreshes the conditions of all ActionBars.
*/
void refreshConditions();
/**
* Checks heartbeats for any necessary updates or actions related to ActionBars.
*/
void checkHeartBeats();
/**
* Retrieves the ActionBar configuration by its name.
*
* @param name the name of the ActionBar configuration
* @return the corresponding ActionBarConfig, or null if not found
*/
@Nullable
ActionBarConfig configById(String name);
/**
* Returns all available ActionBar configurations.
*
* @return an array of all ActionBarConfig instances
*/
ActionBarConfig[] actionBarConfigs();
/**
* Gets the external ActionBar for a specific player.
*
* @param player the player
* @return the external ActionBar string for the player
*/
@Nullable
String getExternalActionBar(CNPlayer player);
}
@@ -0,0 +1,87 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.advance;
import net.kyori.adventure.key.Key;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import net.momirealms.customnameplates.common.util.Tuple;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Interface that defines methods for managing and calculating text advance data,
*/
public interface AdvanceManager extends Reloadable {
/**
* Retrieves custom font advance data by its ID.
*
* @param id the ID of the custom font
* @return the custom font advance data
*/
@Nullable
ConfigurableFontAdvanceData customFontDataById(String id);
/**
* Retrieves character font advance data by its ID.
*
* @param id the ID of the character font
* @return the character font advance data
*/
@Nullable
CharacterFontAdvanceData templateFontDataById(String id);
/**
* Calculates the total advance (width) for a line of text.
*
* @param text the text to calculate the advance for
* @return the total line advance
*/
float getLineAdvance(String text);
/**
* Calculates the advance (width) for a series of characters with a specific font and style.
*
* @param chars the array of characters
* @param font the font key
* @param bold whether the text is bold
* @return the total character advance
*/
float getCharAdvance(char[] chars, Key font, boolean bold);
/**
* Calculates the number of lines needed to fit the text within a specified width.
*
* @param text the text to calculate the number of lines for
* @param width the maximum width of each line
* @return the number of lines required
*/
int getLines(String text, int width);
/**
* Converts a MiniMessage-formatted string into an iterable list of tuples.
* Each tuple contains text, its corresponding font key, and whether it is bold.
*
* @param text the MiniMessage-formatted string
* @return a list of tuples representing the iterable text parts
*/
@ApiStatus.Internal
List<Tuple<String, Key, Boolean>> miniMessageToIterable(String text);
}
@@ -0,0 +1,113 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.advance;
import com.google.gson.JsonObject;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* Interface representing character font advance data.
*/
public interface CharacterFontAdvanceData {
/**
* Returns the size of the character font advance data, typically the number of characters.
*
* @return the size of the data
*/
int size();
/**
* Retrieves the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @return the advance value for the character, or null if not found
*/
Float getAdvance(int codePoint);
/**
* Returns the map containing the character code points and their corresponding advance values.
*
* @return a map of character code points and their advances
*/
Map<Integer, Float> data();
/**
* Returns the unique identifier for this font advance data.
*
* @return the font advance data ID
*/
String id();
/**
* Generates a list of font provider configurations based on the provided properties.
*
* @param properties a map of properties for font provider configuration
* @return a list of JSON objects representing the font providers
*/
List<JsonObject> fontProvider(Map<String, Object> properties);
/**
* Creates a new builder for constructing CharacterFontAdvanceData.
*
* @return a new builder instance
*/
static Builder builder() {
return new CharacterFontAdvanceDataImpl.BuilderImpl();
}
/**
* Builder for creating CharacterFontAdvanceData.
*/
interface Builder {
/**
* Sets the advance data for the characters.
*
* @param data a map of character code points and their advance values
* @return the builder instance
*/
Builder advance(Map<Integer, Float> data);
/**
* Sets the unique ID for the font advance data.
*
* @param id the ID of the font advance data
* @return the builder instance
*/
Builder id(String id);
/**
* Sets a function to provide the font provider configuration.
*
* @param function a function that takes properties and returns a list of JSON objects representing font providers
* @return the builder instance
*/
Builder fontProviderFunction(Function<Map<String, Object>, List<JsonObject>> function);
/**
* Builds and returns the CharacterFontAdvanceData instance.
*
* @return the constructed CharacterFontAdvanceData
*/
CharacterFontAdvanceData build();
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.advance;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static java.util.Objects.requireNonNull;
/**
* Implementation of the CharacterFontAdvanceData interface.
*/
public class CharacterFontAdvanceDataImpl implements CharacterFontAdvanceData {
private final Map<Integer, Float> data;
private final String id;
private final Function<Map<String, Object>, List<JsonObject>> fontProviderFunction;
/**
* Constructs a new instance of CharacterFontAdvanceDataImpl.
*
* @param id the unique identifier for this font advance data
* @param data a map of character code points and their corresponding advance values
* @param fontProviderFunction a function that generates font provider configurations
*/
private CharacterFontAdvanceDataImpl(String id, Map<Integer, Float> data, Function<Map<String, Object>, List<JsonObject>> fontProviderFunction) {
this.data = data;
this.id = requireNonNull(id);
this.fontProviderFunction = requireNonNull(fontProviderFunction);
}
@Override
public int size() {
return data.size();
}
@Override
public Float getAdvance(int codePoint) {
return data.get(codePoint);
}
@Override
public Map<Integer, Float> data() {
return data;
}
@Override
public String id() {
return id;
}
@Override
public List<JsonObject> fontProvider(Map<String, Object> properties) {
return fontProviderFunction.apply(properties);
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private final Int2FloatOpenHashMap data = new Int2FloatOpenHashMap();
private String id;
private Function<Map<String, Object>, List<JsonObject>> fontProviderFunction = (stringObjectMap -> null);
@Override
public Builder advance(Map<Integer, Float> data) {
this.data.putAll(data);
return this;
}
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder fontProviderFunction(Function<Map<String, Object>, List<JsonObject>> function) {
this.fontProviderFunction = function;
return this;
}
@Override
public CharacterFontAdvanceData build() {
return new CharacterFontAdvanceDataImpl(id, data, fontProviderFunction);
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.advance;
import java.util.List;
/**
* Represents configurable font advance data, including default advance values and per-character advances.
*/
public interface ConfigurableFontAdvanceData {
/**
* Returns the default advance (width) used when no specific value is defined for a character.
*
* @return the default advance width
*/
float defaultAdvance();
/**
* Retrieves the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @return the advance value for the character, or the default advance if not defined
*/
float getAdvance(int codePoint);
/**
* Returns the unique identifier for this configurable font advance data.
*
* @return the font advance data ID
*/
String id();
/**
* Creates a new builder for constructing ConfigurableFontAdvanceData.
*
* @return a new builder instance
*/
static Builder builder() {
return new ConfigurableFontAdvanceDataImpl.BuilderImpl();
}
/**
* Builder for creating ConfigurableFontAdvanceData.
*/
interface Builder {
/**
* Sets the unique ID for the configurable font advance data.
*
* @param id the ID of the font advance data
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the default advance (width) for characters that do not have specific advances.
*
* @param width the default advance width
* @return the builder instance
*/
Builder defaultAdvance(float width);
/**
* Sets the advance (width) for a specific character code point.
*
* @param codePoint the code point of the character
* @param width the advance width for the character
* @return the builder instance
*/
Builder advance(int codePoint, float width);
/**
* Sets the parent fonts used by this configurable font advance data.
*
* @param font a list of parent fonts
* @return the builder instance
*/
Builder parentFont(List<CharacterFontAdvanceData> font);
/**
* Builds and returns the ConfigurableFontAdvanceData instance.
*
* @return the constructed ConfigurableFontAdvanceData
*/
ConfigurableFontAdvanceData build();
}
}
@@ -0,0 +1,114 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.advance;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.*;
import static java.util.Objects.requireNonNull;
/**
* Implementation of ConfigurableFontAdvanceData
*/
public class ConfigurableFontAdvanceDataImpl implements ConfigurableFontAdvanceData {
private final float defaultAdvance;
private final Map<Integer, Float> data = new Int2FloatOpenHashMap();
private final List<CharacterFontAdvanceData> parents = new ObjectArrayList<>();
private final String id;
private ConfigurableFontAdvanceDataImpl(String id, float defaultAdvance, HashMap<Integer, Float> customData, List<CharacterFontAdvanceData> parentFonts) {
this.id = requireNonNull(id);
this.defaultAdvance = defaultAdvance;
for (CharacterFontAdvanceData parent : parentFonts) {
// To optimize memory, especially for those fonts that have over 100,000 characters
if (parent.size() > 2048) {
parents.add(parent);
} else {
data.putAll(parent.data());
}
}
data.putAll(customData);
Collections.reverse(parents);
}
@Override
public float defaultAdvance() {
return defaultAdvance;
}
@Override
public float getAdvance(int codePoint) {
Float width = data.get(codePoint);
if (width == null) {
for (CharacterFontAdvanceData parent : parents) {
width = parent.getAdvance(codePoint);
if (width != null) {
return width;
}
}
return defaultAdvance;
}
return width;
}
@Override
public String id() {
return id;
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private final HashMap<Integer, Float> customData = new HashMap<>();
private final List<CharacterFontAdvanceData> parents = new ArrayList<>();
private float defaultAdvance = 0;
private String id;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder defaultAdvance(float width) {
this.defaultAdvance = width;
return this;
}
@Override
public Builder advance(int codePoint, float width) {
this.customData.put(codePoint, width);
return this;
}
@Override
public Builder parentFont(List<CharacterFontAdvanceData> font) {
this.parents.addAll(font);
return this;
}
@Override
public ConfigurableFontAdvanceData build() {
return new ConfigurableFontAdvanceDataImpl(id, defaultAdvance, customData, parents);
}
}
}
@@ -0,0 +1,214 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.background;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Represents a background configuration
*/
public interface Background extends AdaptiveImage {
/**
* Returns the unique ID of the background configuration.
*
* @return the background ID
*/
String id();
/**
* Returns the configured character for the left side of the background.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for width 1.
*
* @return the configured character for width 1
*/
ConfiguredCharacter width_1();
/**
* Returns the configured character for width 2.
*
* @return the configured character for width 2
*/
ConfiguredCharacter width_2();
/**
* Returns the configured character for width 4.
*
* @return the configured character for width 4
*/
ConfiguredCharacter width_4();
/**
* Returns the configured character for width 8.
*
* @return the configured character for width 8
*/
ConfiguredCharacter width_8();
/**
* Returns the configured character for width 16.
*
* @return the configured character for width 16
*/
ConfiguredCharacter width_16();
/**
* Returns the configured character for width 32.
*
* @return the configured character for width 32
*/
ConfiguredCharacter width_32();
/**
* Returns the configured character for width 64.
*
* @return the configured character for width 64
*/
ConfiguredCharacter width_64();
/**
* Returns the configured character for width 128.
*
* @return the configured character for width 128
*/
ConfiguredCharacter width_128();
/**
* Returns the configured character for the right side of the background.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Creates a new builder for constructing a Background configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new BackgroundImpl.BuilderImpl();
}
/**
* Builder for constructing Background configurations.
*/
interface Builder {
/**
* Sets the unique ID for the background.
*
* @param id the background ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the configured character for the left side of the background.
*
* @param character the configured character for the left side
* @return the builder instance
*/
Builder left(ConfiguredCharacter character);
/**
* Sets the configured character for width 1.
*
* @param character the configured character for width 1
* @return the builder instance
*/
Builder width_1(ConfiguredCharacter character);
/**
* Sets the configured character for width 2.
*
* @param character the configured character for width 2
* @return the builder instance
*/
Builder width_2(ConfiguredCharacter character);
/**
* Sets the configured character for width 4.
*
* @param character the configured character for width 4
* @return the builder instance
*/
Builder width_4(ConfiguredCharacter character);
/**
* Sets the configured character for width 8.
*
* @param character the configured character for width 8
* @return the builder instance
*/
Builder width_8(ConfiguredCharacter character);
/**
* Sets the configured character for width 16.
*
* @param character the configured character for width 16
* @return the builder instance
*/
Builder width_16(ConfiguredCharacter character);
/**
* Sets the configured character for width 32.
*
* @param character the configured character for width 32
* @return the builder instance
*/
Builder width_32(ConfiguredCharacter character);
/**
* Sets the configured character for width 64.
*
* @param character the configured character for width 64
* @return the builder instance
*/
Builder width_64(ConfiguredCharacter character);
/**
* Sets the configured character for width 128.
*
* @param character the configured character for width 128
* @return the builder instance
*/
Builder width_128(ConfiguredCharacter character);
/**
* Sets the configured character for the right side of the background.
*
* @param character the configured character for the right side
* @return the builder instance
*/
Builder right(ConfiguredCharacter character);
/**
* Builds and returns the configured Background instance.
*
* @return the constructed Background
*/
Background build();
}
}
@@ -0,0 +1,242 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.background;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
/**
* Implements the {@link Background} interface, representing the detailed configuration of a background.
*/
@SuppressWarnings("DuplicatedCode")
public record BackgroundImpl(String id, ConfiguredCharacter left, ConfiguredCharacter width_1,
ConfiguredCharacter width_2, ConfiguredCharacter width_4, ConfiguredCharacter width_8,
ConfiguredCharacter width_16, ConfiguredCharacter width_32, ConfiguredCharacter width_64,
ConfiguredCharacter width_128, ConfiguredCharacter right) implements Background {
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
String offset1 = OffsetFont.shortestNegChars(advance + rightMargin + right.advance());
advance = leftMargin + advance + rightMargin;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.character());
while (advance >= 128) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_128.character());
advance -= 128;
}
if (advance - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_64.character());
advance -= 64;
}
if (advance - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_32.character());
advance -= 32;
}
if (advance - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_16.character());
advance -= 16;
}
if (advance - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_8.character());
advance -= 8;
}
if (advance - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_4.character());
advance -= 4;
}
if (advance - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_2.character());
advance -= 2;
}
if (advance - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_1.character());
}
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(right.character());
stringBuilder.append(offset1);
return stringBuilder.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
return OffsetFont.shortestPosChars(rightMargin + right.advance());
}
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
advance = advance + leftMargin + rightMargin + 2;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.character());
while (advance >= 128) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_128.character());
advance -= 128;
}
if (advance - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_64.character());
advance -= 64;
}
if (advance - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_32.character());
advance -= 32;
}
if (advance - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_16.character());
advance -= 16;
}
if (advance - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_8.character());
advance -= 8;
}
if (advance - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_4.character());
advance -= 4;
}
if (advance - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_2.character());
advance -= 2;
}
if (advance - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(width_1.character());
}
stringBuilder.append(OffsetFont.NEG_1.character());
stringBuilder.append(right.character());
return stringBuilder.toString();
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
BackgroundImpl that = (BackgroundImpl) object;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter width_1;
private ConfiguredCharacter width_2;
private ConfiguredCharacter width_4;
private ConfiguredCharacter width_8;
private ConfiguredCharacter width_16;
private ConfiguredCharacter width_32;
private ConfiguredCharacter width_64;
private ConfiguredCharacter width_128;
private ConfiguredCharacter right;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder left(ConfiguredCharacter character) {
this.left = character;
return this;
}
@Override
public Builder width_1(ConfiguredCharacter character) {
this.width_1 = character;
return this;
}
@Override
public Builder width_2(ConfiguredCharacter character) {
this.width_2 = character;
return this;
}
@Override
public Builder width_4(ConfiguredCharacter character) {
this.width_4 = character;
return this;
}
@Override
public Builder width_8(ConfiguredCharacter character) {
this.width_8 = character;
return this;
}
@Override
public Builder width_16(ConfiguredCharacter character) {
this.width_16 = character;
return this;
}
@Override
public Builder width_32(ConfiguredCharacter character) {
this.width_32 = character;
return this;
}
@Override
public Builder width_64(ConfiguredCharacter character) {
this.width_64 = character;
return this;
}
@Override
public Builder width_128(ConfiguredCharacter character) {
this.width_128 = character;
return this;
}
@Override
public Builder right(ConfiguredCharacter character) {
this.right = character;
return this;
}
@Override
public Background build() {
return new BackgroundImpl(id, left, width_1, width_2, width_4, width_8, width_16, width_32, width_64, width_128, right);
}
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.background;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Interface representing a manager for background configurations.
*/
public interface BackgroundManager extends Reloadable {
/**
* Retrieves a Background configuration by its unique ID.
*
* @param id the unique ID of the background
* @return the corresponding Background, or null if not found
*/
@Nullable
Background backgroundById(String id);
/**
* Returns a collection of all available Background configurations.
*
* @return a collection of Background instances
*/
Collection<Background> getBackgrounds();
}
@@ -0,0 +1,126 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bossbar;
import java.util.UUID;
/**
* Represents a BossBar
*/
public interface BossBar {
/**
* Returns the unique UUID of the BossBar.
*
* @return the UUID of the BossBar
*/
UUID uuid();
/**
* Returns the progress value of the BossBar.
* The value should be between 0.0 (empty) and 1.0 (full).
*
* @return the progress value of the BossBar
*/
float progress();
/**
* Returns the color of the BossBar.
*
* @return the color of the BossBar
*/
Color color();
/**
* Returns the overlay style of the BossBar, defining how the bar is divided.
*
* @return the overlay style of the BossBar
*/
Overlay overlay();
/**
* Enum representing the different overlay styles for the BossBar.
* The overlay style determines how the bar is divided, either as a simple progress bar or as notches.
*/
enum Overlay {
/**
* The bar is displayed as a simple progress bar.
*/
PROGRESS,
/**
* The bar is divided into 6 notches.
*/
NOTCHED_6,
/**
* The bar is divided into 10 notches.
*/
NOTCHED_10,
/**
* The bar is divided into 12 notches.
*/
NOTCHED_12,
/**
* The bar is divided into 20 notches.
*/
NOTCHED_20
}
/**
* Enum representing the different colors for the BossBar.
*/
enum Color {
/**
* Blue color for the BossBar.
*/
BLUE,
/**
* Green color for the BossBar.
*/
GREEN,
/**
* Pink color for the BossBar.
*/
PINK,
/**
* Purple color for the BossBar.
*/
PURPLE,
/**
* Red color for the BossBar.
*/
RED,
/**
* White color for the BossBar.
*/
WHITE,
/**
* Yellow color for the BossBar.
*/
YELLOW
}
}
@@ -0,0 +1,150 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bossbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
/**
* Interface for BossBarConfig
*/
public interface BossBarConfig {
/**
* The default overlay style for the BossBar.
*/
BossBar.Overlay DEFAULT_OVERLAY = BossBar.Overlay.PROGRESS;
/**
* The default color for the BossBar.
*/
BossBar.Color DEFAULT_COLOR = BossBar.Color.YELLOW;
/**
* Returns the unique ID for the BossBar configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the requirements for the BossBar.
*
* @return an array of requirements
*/
Requirement[] requirements();
/**
* Returns the carousel texts used in the BossBar.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Returns the overlay style for the BossBar.
*
* @return the overlay style
*/
BossBar.Overlay overlay();
/**
* Returns the color of the BossBar.
*
* @return the BossBar color
*/
BossBar.Color color();
/**
* Returns the progress value of the BossBar.
* The value should be between 0.0 (empty) and 1.0 (full).
*
* @return the progress value
*/
float progress();
/**
* Creates a new builder for constructing a BossBarConfig.
*
* @return a new builder instance
*/
static BossBarConfig.Builder builder() {
return new BossBarConfigImpl.BuilderImpl();
}
/**
* Builder for constructing BossBarConfig instances.
*/
interface Builder {
/**
* Sets the unique ID for the BossBar configuration.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the requirements for the BossBar.
*
* @param requirements an array of requirements
* @return the builder instance
*/
Builder requirement(Requirement[] requirements);
/**
* Sets the carousel texts for the BossBar.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Sets the overlay style for the BossBar.
*
* @param overlay the overlay style
* @return the builder instance
*/
Builder overlay(BossBar.Overlay overlay);
/**
* Sets the color for the BossBar.
*
* @param color the BossBar color
* @return the builder instance
*/
Builder color(BossBar.Color color);
/**
* Sets the progress value for the BossBar.
*
* @param progress the progress value
* @return the builder instance
*/
Builder progress(float progress);
/**
* Builds and returns the configured BossBarConfig instance.
*
* @return the constructed BossBarConfig
*/
BossBarConfig build();
}
}
@@ -0,0 +1,138 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bossbar;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import static java.util.Objects.requireNonNull;
/**
* Implementation of BossBar Config
*/
public class BossBarConfigImpl implements BossBarConfig {
private final String id;
private final Requirement[] requirements;
private final CarouselText[] carouselTexts;
private final BossBar.Overlay overlay;
private final BossBar.Color color;
private final float progress;
/**
* Constructor for creating a new BossBarConfigImpl.
* Ensures that all fields are non-null and properly initialized.
*
* @param id the unique ID of the BossBar configuration
* @param requirements the requirements for the BossBar
* @param carouselTexts the carousel texts associated with the BossBar
* @param overlay the overlay style of the BossBar
* @param color the color of the BossBar
* @param progress the progress value of the BossBar (between 0.0 and 1.0)
*/
private BossBarConfigImpl(String id, Requirement[] requirements, CarouselText[] carouselTexts, BossBar.Overlay overlay, BossBar.Color color, float progress) {
this.id = requireNonNull(id);
this.requirements = requireNonNull(requirements);
this.carouselTexts = requireNonNull(carouselTexts);
this.overlay = requireNonNull(overlay);
this.color = requireNonNull(color);
this.progress = progress;
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] requirements() {
return requirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
@Override
public BossBar.Overlay overlay() {
return overlay;
}
@Override
public BossBar.Color color() {
return color;
}
@Override
public float progress() {
return progress;
}
/**
* Builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] requirements;
private CarouselText[] carouselTexts;
private BossBar.Overlay overlay = DEFAULT_OVERLAY;
private BossBar.Color color = DEFAULT_COLOR;
private float progress = 0f;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder requirement(Requirement[] requirements) {
this.requirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public Builder overlay(BossBar.Overlay overlay) {
this.overlay = overlay;
return this;
}
@Override
public Builder color(BossBar.Color color) {
this.color = color;
return this;
}
@Override
public Builder progress(float progress) {
this.progress = progress;
return this;
}
@Override
public BossBarConfig build() {
return new BossBarConfigImpl(id, requirements, carouselTexts, overlay, color, progress);
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bossbar;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
/**
* Manager interface for handling BossBar configurations and their updates.
*/
public interface BossBarManager extends Reloadable {
/**
* Retrieves the BossBar configuration by its id.
*
* @param id the name of the BossBar configuration
* @return the corresponding BossBarConfig, or null if not found
*/
BossBarConfig configById(String id);
/**
* Returns all available BossBar configurations.
*
* @return an array of all BossBarConfig instances
*/
BossBarConfig[] bossBarConfigs();
/**
* Called on every server tick to update the state of BossBars.
*/
void onTick();
}
@@ -0,0 +1,124 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Bubble
*/
public interface Bubble extends AdaptiveImage {
/**
* Returns the unique ID of the Bubble configuration.
*
* @return the Bubble ID
*/
String id();
/**
* Returns the configured character for the left side of the Bubble.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for the right side of the Bubble.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Returns the configured character for the middle section of the Bubble.
*
* @return the middle configured character
*/
ConfiguredCharacter middle();
/**
* Returns the configured character for the tail section of the Bubble.
*
* @return the tail configured character
*/
ConfiguredCharacter tail();
/**
* Creates a new builder for constructing a Bubble configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new BubbleImpl.BuilderImpl();
}
/**
* Builder for constructing Bubble configurations.
*/
interface Builder {
/**
* Sets the unique ID for the Bubble configuration.
*
* @param id the Bubble ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the configured character for the left side of the Bubble.
*
* @param left the left-side configured character
* @return the builder instance
*/
Builder left(ConfiguredCharacter left);
/**
* Sets the configured character for the right side of the Bubble.
*
* @param right the right-side configured character
* @return the builder instance
*/
Builder right(ConfiguredCharacter right);
/**
* Sets the configured character for the middle section of the Bubble.
*
* @param middle the middle configured character
* @return the builder instance
*/
Builder middle(ConfiguredCharacter middle);
/**
* Sets the configured character for the tail section of the Bubble.
*
* @param tail the tail configured character
* @return the builder instance
*/
Builder tail(ConfiguredCharacter tail);
/**
* Builds and returns the constructed Bubble instance.
*
* @return the constructed Bubble
*/
Bubble build();
}
}
@@ -0,0 +1,232 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
/**
* Bubble configuration
*/
public interface BubbleConfig {
/**
* Returns the unique ID of the Bubble configuration.
*
* @return the configuration ID
*/
String id();
/**
* Returns the command suggestion of the Bubble configuration.
*
* @return the configuration ID
*/
default String commandSuggestion() {
return id();
}
/**
* Returns the background color of the Bubble text.
*
* @return the background color (ARGB) as an integer
*/
int backgroundColor();
/**
* Returns the line width for the Bubble text.
*
* @return the line width
*/
int lineWidth();
/**
* Returns the maximum number of lines for the Bubble text.
*
* @return the maximum number of lines
*/
int maxLines();
/**
* Returns if the bubble has shadow
*
* @return has shadow or not
*/
boolean hasShadow();
/**
* Returns the billboard
*
* @return billboard
*/
Billboard billboard();
/**
* Returns the bubbles used in this configuration.
*
* @return an array of Bubble instances
*/
Bubble[] bubbles();
/**
* Returns the text prefix to be applied before the Bubble content.
*
* @return the text prefix
*/
PreParsedDynamicText textPrefix();
/**
* Returns the text suffix to be applied after the Bubble content.
*
* @return the text suffix
*/
PreParsedDynamicText textSuffix();
/**
* Returns the display name of the Bubble.
*
* @return the display name
*/
String displayName();
/**
* Returns the scale vector for the Bubble.
*
* @return the scale as a Vector3
*/
Vector3 scale();
/**
* Creates a new builder for constructing a BubbleConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new BubbleConfigImpl.BuilderImpl();
}
/**
* Builder for constructing BubbleConfig instances.
*/
interface Builder {
/**
* Sets the unique ID for the BubbleConfig.
*
* @param id the configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the command suggestion for the BubbleConfig.
*
* @param suggestion the command suggestion
* @return the builder instance
*/
Builder commandSuggestion(String suggestion);
/**
* Sets the display name for the BubbleConfig.
*
* @param displayName the display name
* @return the builder instance
*/
Builder displayName(String displayName);
/**
* Sets the background color for the BubbleConfig.
*
* @param backgroundColor the background color
* @return the builder instance
*/
Builder backgroundColor(int backgroundColor);
/**
* Sets the line width for the Bubble text.
*
* @param lineWidth the line width
* @return the builder instance
*/
Builder lineWidth(int lineWidth);
/**
* Sets the maximum number of lines for the Bubble text.
*
* @param maxLines the maximum number of lines
* @return the builder instance
*/
Builder maxLines(int maxLines);
/**
* Sets the bubbles used in this configuration.
*
* @param bubbles an array of Bubble instances
* @return the builder instance
*/
Builder bubbles(Bubble[] bubbles);
/**
* Sets the text prefix for the BubbleConfig.
*
* @param textPrefix the text prefix
* @return the builder instance
*/
Builder textPrefix(String textPrefix);
/**
* Sets the text suffix for the BubbleConfig.
*
* @param textSuffix the text suffix
* @return the builder instance
*/
Builder textSuffix(String textSuffix);
/**
* Sets the scale for the BubbleConfig.
*
* @param scale the scale as a Vector3
* @return the builder instance
*/
Builder scale(Vector3 scale);
/**
* Sets if the text has shadow
*
* @param hasShadow has shadow
* @return the builder instance
*/
Builder hasShadow(boolean hasShadow);
/**
* Sets the billboard
*
* @param billboard billboard
* @return the builder instance
*/
Builder billboard(Billboard billboard);
/**
* Builds and returns the configured BubbleConfig instance.
*
* @return the constructed BubbleConfig
*/
BubbleConfig build();
}
}
@@ -0,0 +1,229 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.PreParsedDynamicText;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.Optional;
import static java.util.Objects.requireNonNull;
/**
* Implementation of the BubbleConfig interface
*/
public class BubbleConfigImpl implements BubbleConfig {
private final String id;
private final String commandSuggestion;
private final int backgroundColor;
private final int lineWidth;
private final int maxLines;
private final Bubble[] bubbles;
private final PreParsedDynamicText textPrefix;
private final PreParsedDynamicText textSuffix;
private final String displayName;
private final Vector3 scale;
private final boolean hasShadow;
private final Billboard billboard;
/**
* Constructs a new BubbleConfigImpl.
*
* @param id the unique ID for the bubble configuration
* @param commandSuggestion the command suggestion for the bubble configuration
* @param displayName the name to be displayed for the bubble configuration
* @param backgroundColor the background color for the bubble (in integer format)
* @param lineWidth the line width for the bubble display
* @param maxLines the maximum number of lines that can be displayed in the bubble
* @param bubbles an array of Bubble objects representing the actual bubbles
* @param textPrefix a prefix that will be added before the text in the bubble
* @param textSuffix a suffix that will be added after the text in the bubble
* @param scale the scale of the bubble display (as a Vector3)
* @param hasShadow has shadow or not
*/
public BubbleConfigImpl(String id, String commandSuggestion, String displayName, int backgroundColor, int lineWidth, int maxLines, Bubble[] bubbles, String textPrefix, String textSuffix, Vector3 scale, boolean hasShadow, Billboard billboard) {
this.backgroundColor = backgroundColor;
this.lineWidth = lineWidth;
this.maxLines = maxLines;
this.id = id;
this.commandSuggestion = commandSuggestion;
this.bubbles = requireNonNull(bubbles);
this.textPrefix = new PreParsedDynamicText(requireNonNull(textPrefix), true);
this.textSuffix = new PreParsedDynamicText(requireNonNull(textSuffix), true);
this.displayName = requireNonNull(displayName);
this.scale = requireNonNull(scale);
this.hasShadow = hasShadow;
this.billboard = billboard;
}
@Override
public String id() {
return this.id;
}
@Override
public String commandSuggestion() {
return this.commandSuggestion;
}
@Override
public int backgroundColor() {
return backgroundColor;
}
@Override
public int lineWidth() {
return lineWidth;
}
@Override
public int maxLines() {
return maxLines;
}
@Override
public Bubble[] bubbles() {
return bubbles;
}
@Override
public PreParsedDynamicText textPrefix() {
return textPrefix;
}
@Override
public PreParsedDynamicText textSuffix() {
return textSuffix;
}
@Override
public String displayName() {
return displayName;
}
@Override
public Vector3 scale() {
return scale;
}
@Override
public boolean hasShadow() {
return hasShadow;
}
@Override
public Billboard billboard() {
return billboard;
}
/**
* Builder implementation for creating BubbleConfigImpl instances.
*/
public static class BuilderImpl implements Builder {
private int backgroundColor;
private int lineWidth;
private int maxLines;
private Bubble[] bubbles;
private String textPrefix;
private String textSuffix;
private String id;
private String commandSuggestion;
private String displayName;
private Vector3 scale;
private boolean hasShadow;
private Billboard billboard;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;
return this;
}
@Override
public Builder commandSuggestion(String commandSuggestion) {
this.commandSuggestion = commandSuggestion;
return this;
}
@Override
public Builder backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
@Override
public Builder lineWidth(int lineWidth) {
this.lineWidth = lineWidth;
return this;
}
@Override
public Builder maxLines(int maxLines) {
this.maxLines = maxLines;
return this;
}
@Override
public Builder bubbles(Bubble[] bubbles) {
this.bubbles = bubbles;
return this;
}
@Override
public Builder textPrefix(String textPrefix) {
this.textPrefix = textPrefix;
return this;
}
@Override
public Builder textSuffix(String textSuffix) {
this.textSuffix = textSuffix;
return this;
}
@Override
public Builder scale(Vector3 scale) {
this.scale = scale;
return this;
}
@Override
public Builder hasShadow(boolean hasShadow) {
this.hasShadow = hasShadow;
return this;
}
@Override
public Builder billboard(Billboard billboard) {
this.billboard = billboard;
return this;
}
@Override
public BubbleConfig build() {
return new BubbleConfigImpl(id, Optional.ofNullable(this.commandSuggestion).orElse(id), displayName, backgroundColor, lineWidth, maxLines, bubbles, textPrefix, textSuffix, scale, hasShadow, billboard);
}
}
}
@@ -0,0 +1,208 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
/**
* Implementation of the Bubble interface
*/
public class BubbleImpl implements Bubble {
private final String id;
private final ConfiguredCharacter left;
private final ConfiguredCharacter right;
private final ConfiguredCharacter middle;
private final ConfiguredCharacter tail;
/**
* Constructs a new BubbleImpl.
*
* @param id the unique ID for the bubble
* @param left the character representing the left part of the bubble
* @param right the character representing the right part of the bubble
* @param middle the character representing the middle part of the bubble
* @param tail the character representing the tail part of the bubble
*/
public BubbleImpl(String id, ConfiguredCharacter left, ConfiguredCharacter right, ConfiguredCharacter middle, ConfiguredCharacter tail) {
this.id = id;
this.left = left;
this.right = right;
this.middle = middle;
this.tail = tail;
}
@Override
public String id() {
return id;
}
@Override
public ConfiguredCharacter left() {
return left;
}
@Override
public ConfiguredCharacter right() {
return right;
}
@Override
public ConfiguredCharacter middle() {
return middle;
}
@Override
public ConfiguredCharacter tail() {
return tail;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
BubbleImpl bubble = (BubbleImpl) object;
return Objects.equals(id, bubble.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
float actualMiddleWidth = 0;
if (mid_amount > 512) return "";
if (mid_amount <= 0) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
actualMiddleWidth = tail.advance() - 1;
} else {
actualMiddleWidth += (middle.advance() - 1) * mid_amount;
actualMiddleWidth += (tail.advance() - 1);
int tailPos = mid_amount / 2;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
if (i == tailPos) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
}
}
}
float exceed = actualMiddleWidth - advance;
sb.append(right.character());
float delta = (right.advance() + rightMargin + advance + exceed / 2);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
float actualMiddleWidth = 0;
actualMiddleWidth += (tail.advance() - 1);
actualMiddleWidth += (middle.advance() - 1) * mid_amount;
float exceed = actualMiddleWidth - advance;
float delta = (right.advance() + rightMargin + exceed / 2);
return OffsetFont.shortestPosChars(delta);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin - (tail.advance() - 1)) / (middle.advance() - 1));
if (mid_amount > 512) return "";
if (mid_amount <= 0) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
} else {
int tailPos = mid_amount / 2;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
if (i == tailPos) {
sb.append(tail.character()).append(OffsetFont.NEG_1.character());
}
}
}
sb.append(right.character());
float delta = (right.advance() + rightMargin - (left.advance() - 1) - leftMargin);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
/**
* Builder implementation for creating BubbleImpl instances.
*/
public static class BuilderImpl implements Builder {
private String id;
private ConfiguredCharacter left;
private ConfiguredCharacter right;
private ConfiguredCharacter middle;
private ConfiguredCharacter tail;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder left(ConfiguredCharacter left) {
this.left = left;
return this;
}
@Override
public Builder right(ConfiguredCharacter right) {
this.right = right;
return this;
}
@Override
public Builder middle(ConfiguredCharacter middle) {
this.middle = middle;
return this;
}
@Override
public Builder tail(ConfiguredCharacter tail) {
this.tail = tail;
return this;
}
@Override
public Bubble build() {
return new BubbleImpl(id, left, right, middle, tail);
}
}
}
@@ -0,0 +1,160 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.bubble;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
/**
* The BubbleManager interface is responsible for managing the configuration and display of Bubbles,
* including retrieving available Bubbles, managing Bubble configurations, and controlling display settings.
*/
public interface BubbleManager extends Reloadable {
/**
* Returns a collection of all available Bubble instances.
*
* @return a collection of Bubble instances
*/
Collection<Bubble> bubbles();
/**
* Returns a collection of all Bubble configurations.
*
* @return a collection of BubbleConfig instances
*/
Collection<BubbleConfig> bubbleConfigs();
/**
* Retrieves a Bubble by its unique ID.
*
* @param id the Bubble ID
* @return the Bubble instance, or null if not found
*/
@Nullable
Bubble bubbleById(String id);
/**
* Retrieves a Bubble configuration by its unique ID.
*
* @param id the BubbleConfig ID
* @return the BubbleConfig instance, or null if not found
*/
@Nullable
BubbleConfig bubbleConfigById(String id);
/**
* Retrieves a Bubble configuration by its command suggestion
*
* @param suggestion command suggestion
* @return the BubbleConfig instance, or null if not found
*/
@Nullable BubbleConfig bubbleConfigByCommand(String suggestion);
/**
* Checks if a player has access to a specific Bubble by its ID.
*
* @param player the player to check
* @param id the Bubble ID
* @return true if the player has the Bubble, false otherwise
*/
boolean hasBubble(CNPlayer player, String id);
/**
* Returns a collection of available Bubbles for the player.
*
* @param player the player to check
* @return a collection of available BubbleConfig instances
*/
Collection<BubbleConfig> availableBubbles(CNPlayer player);
/**
* Returns the set of channels that are blacklisted from displaying Bubbles.
*
* @return a set of blacklisted channel names
*/
Set<String> blacklistChannels();
/**
* Returns the current mode for Bubble channels.
*
* @return the ChannelMode in use
*/
ChannelMode channelMode();
/**
* Returns the default Bubble ID used when no specific Bubble is set.
*
* @return the default Bubble ID
*/
String defaultBubbleId();
/**
* Returns the requirements to send a Bubble.
*
* @return an array of send Bubble requirements
*/
Requirement[] sendBubbleRequirements();
/**
* Returns the requirements to view a Bubble.
*
* @return an array of view Bubble requirements
*/
Requirement[] viewBubbleRequirements();
/**
* Returns the vertical offset for Bubble display.
*
* @return the vertical offset as a double
*/
double verticalOffset();
/**
* Returns the duration (in ticks) for which the Bubble remains visible.
*
* @return the stay duration in ticks
*/
int stayDuration();
/**
* Returns the duration (in ticks) for the Bubble to appear.
*
* @return the appear duration in ticks
*/
int appearDuration();
/**
* Returns the duration (in ticks) for the Bubble to disappear.
*
* @return the disappear duration in ticks
*/
int disappearDuration();
/**
* Returns the view range for Bubbles.
*
* @return the view range as a float
*/
float viewRange();
}
@@ -15,43 +15,23 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.tag.team;
import net.momirealms.customnameplates.api.mechanic.misc.ViewerText;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
public interface TeamTagPlayer extends NameplatePlayer {
package net.momirealms.customnameplates.api.feature.bubble;
/**
* Enum representing the different modes for Bubble channels.
* The mode determines the visibility and access rules for Bubbles in various channels.
*/
public enum ChannelMode {
/**
* Set a player's prefix
*
* @param prefix prefix
* The ALL mode means that Bubbles can be displayed in all channels, regardless of the player's status or permissions.
*/
void setPrefix(String prefix);
ALL,
/**
* Set a player's suffix
*
* @param suffix suffix
* The JOINED mode means that Bubbles can only be displayed in channels where the player is currently a member.
*/
void setSuffix(String suffix);
JOINED,
/**
* Get a player's prefix
*
* @return prefix
* The CAN_JOIN mode means that Bubbles can be displayed in channels that the player can join, even if they are not currently in them.
*/
ViewerText getPrefix();
/**
* Get a player's suffix
*
* @return suffix
*/
ViewerText getSuffix();
/**
* Destroy the tag
*/
void destroy();
}
CAN_JOIN
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.chat;
import net.momirealms.customnameplates.api.CustomNameplates;
/**
* Abstract base class for chat message providers, providing common functionality
* for managing the plugin and chat manager.
*/
public abstract class AbstractChatMessageProvider implements ChatMessageProvider {
/**
* The CustomNameplates plugin
*/
protected CustomNameplates plugin;
/**
* The chat manager
*/
protected ChatManager manager;
/**
* Constructs a new AbstractChatMessageProvider.
*
* @param plugin the CustomNameplates plugin instance
* @param manager the ChatManager instance to handle chat-related operations
*/
public AbstractChatMessageProvider(CustomNameplates plugin, ChatManager manager) {
this.plugin = plugin;
this.manager = manager;
}
/**
* Registers the chat message provider. Intended to be overridden by subclasses if needed.
*/
public void register() {
}
/**
* Unregisters the chat message provider. Intended to be overridden by subclasses if needed.
*/
public void unregister() {
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.chat;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.feature.ChatListener;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
/**
* Manages chat-related functionality, including handling custom chat providers, listeners, and chat events.
*/
public interface ChatManager extends Reloadable {
String replaceEmojis(CNPlayer player, String text);
/**
* Sets a custom chat message provider.
*
* @param provider the custom ChatMessageProvider to set
* @return true if the provider was successfully set, false otherwise
*/
boolean setCustomChatProvider(ChatMessageProvider provider);
/**
* Removes the currently set custom chat message provider.
*
* @return true if the provider was successfully removed, false otherwise
*/
boolean removeCustomChatProvider();
/**
* Registers a chat listener to receive chat events.
*
* @param listener the ChatListener to register
*/
void registerListener(ChatListener listener);
/**
* Unregisters a chat listener, stopping it from receiving chat events.
*
* @param listener the ChatListener to unregister
*/
void unregisterListener(ChatListener listener);
/**
* Returns the current chat message provider.
*
* @return the currently set ChatMessageProvider, or null if none is set
*/
ChatMessageProvider chatProvider();
/**
* Handles a chat message event for the specified player and channel.
*
* @param player the player who sent the message
* @param message the chat message content
* @param channel the chat channel
*/
void onChat(CNPlayer player, String message, String channel);
}
@@ -0,0 +1,53 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.chat;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Provides chat-related functionality, including channel membership and ignore status between players.
*/
public interface ChatMessageProvider {
/**
* Checks if a player has joined a specific chat channel.
*
* @param player the player to check
* @param channelID the ID of the chat channel
* @return true if the player has joined the channel, false otherwise
*/
boolean hasJoinedChannel(CNPlayer player, String channelID);
/**
* Checks if a player is allowed to join a specific chat channel.
*
* @param player the player to check
* @param channelID the ID of the chat channel
* @return true if the player can join the channel, false otherwise
*/
boolean canJoinChannel(CNPlayer player, String channelID);
/**
* Checks if a player is ignoring another player.
*
* @param sender the player sending messages
* @param receiver the player who may be ignoring the sender
* @return true if the receiver is ignoring the sender, false otherwise
*/
boolean isIgnoring(CNPlayer sender, CNPlayer receiver);
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.chat.emoji;
import net.momirealms.customnameplates.api.CNPlayer;
/**
* Interface for providing emoji replacement functionality.
* Allows replacing certain text patterns with corresponding emojis for a given player.
*/
public interface EmojiProvider {
/**
* Replaces specified text patterns in the given string with emojis, based on the player context.
*
* @param player the player for whom the emoji replacement is being processed
* @param text the original text to process
* @return the text with emojis replacing certain patterns
*/
String replace(CNPlayer player, String text);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,16 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.data;
package net.momirealms.customnameplates.api.feature.image;
public enum StorageType {
JSON,
YAML,
H2,
SQLite,
MySQL,
MariaDB,
MongoDB,
Redis
/**
* A record representing an animation with a speed and a number of frames.
*/
public record Animation(int speed, int frames) {
}
@@ -0,0 +1,110 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.image;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import org.jetbrains.annotations.Nullable;
/**
* An interface represents the image
*/
public interface Image {
/**
* Returns the unique ID of the image configuration.
*
* @return the image ID
*/
String id();
/**
* Checks if the image has a shadow effect.
*
* @return true if the image has a shadow, false otherwise
*/
boolean removeShadow();
/**
* Get the animation of the image
*
* @return the animated image
*/
@Nullable
Animation animation();
/**
* Returns the configured character associated with this image.
*
* @return the configured character
*/
ConfiguredCharacter character();
/**
* Creates a new builder for constructing an Image configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new ImageImpl.BuilderImpl();
}
/**
* Builder for constructing Image configurations.
*/
interface Builder {
/**
* Sets the unique ID for the image configuration.
*
* @param id the image ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets whether to remove the shadow of the image
*
* @param remove true if to remove the shadow
* @return the builder instance
*/
Builder removeShadow(boolean remove);
/**
* Sets the animation of the image
*
* @param animation animation
* @return the builder instance
*/
Builder animation(@Nullable Animation animation);
/**
* Sets the configured character associated with this image.
*
* @param character the configured character
* @return the builder instance
*/
Builder character(ConfiguredCharacter character);
/**
* Builds and returns the configured Image instance.
*
* @return the constructed Image
*/
Image build();
}
}
@@ -0,0 +1,112 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.image;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Implementation of Image
*/
public class ImageImpl implements Image {
private final String id;
private final boolean removeShadow;
private final ConfiguredCharacter character;
private final Animation animation;
private ImageImpl(String id, boolean removeShadow, Animation animation, ConfiguredCharacter character) {
this.id = id;
this.removeShadow = removeShadow;
this.character = character;
this.animation = animation;
}
@Override
public String id() {
return id;
}
@Override
public boolean removeShadow() {
return removeShadow;
}
@Override
public @Nullable Animation animation() {
return animation;
}
@Override
public ConfiguredCharacter character() {
return character;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
ImageImpl image = (ImageImpl) object;
return Objects.equals(id, image.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
/**
* The builder Implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private boolean removeShadow;
private ConfiguredCharacter character;
private Animation animation;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder removeShadow(boolean removeShadow) {
this.removeShadow = removeShadow;
return this;
}
@Override
public Builder animation(@Nullable Animation animation) {
this.animation = animation;
return this;
}
@Override
public Builder character(ConfiguredCharacter character) {
this.character = character;
return this;
}
@Override
public Image build() {
return new ImageImpl(id, removeShadow, animation, character);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,32 +15,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature.image;
import net.momirealms.customnameplates.api.mechanic.tag.team.TeamTagPlayer;
import org.bukkit.entity.Player;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.Collection;
public interface TeamTagManager {
/**
* Manages image configurations
*/
public interface ImageManager extends Reloadable {
/**
* Create team tag for a player
* If failed, the return value would be null
* This happens when there already exists a team tag for a player
* Retrieves an Image configuration by its unique ID.
*
* @return team tag
* @param id the unique ID of the image
* @return the Image instance, or null if not found
*/
@Nullable
TeamTagPlayer createTagForPlayer(Player player, String prefix, String suffix);
Image imageById(String id);
/**
* Remove a team tag from map by uuid
* Returns a collection of all available Image configurations.
*
* @param uuid uuid
* @return team tag
* @return a collection of Image instances
*/
@Nullable
TeamTagPlayer removeTeamPlayerFromMap(UUID uuid);
Collection<Image> images();
}
@@ -0,0 +1,156 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.nameplate;
import net.momirealms.customnameplates.api.feature.AdaptiveImage;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
/**
* Nameplate
*/
public interface Nameplate extends AdaptiveImage {
/**
* Returns the unique ID of the nameplate configuration.
*
* @return the nameplate ID
*/
String id();
/**
* Returns the command suggestion of the nameplate configuration.
*
* @return the nameplate ID
*/
default String commandSuggestion() {
return id();
}
/**
* Returns the display name of the nameplate.
*
* @return the display name of the nameplate
*/
String displayName();
/**
* Returns the configured character for the left side of the nameplate.
*
* @return the left-side configured character
*/
ConfiguredCharacter left();
/**
* Returns the configured character for the middle section of the nameplate.
*
* @return the middle configured character
*/
ConfiguredCharacter middle();
/**
* Returns the configured character for the right side of the nameplate.
*
* @return the right-side configured character
*/
ConfiguredCharacter right();
/**
* Gets the min width of the nameplate
*
* @return the min width of the nameplate
*/
int minWidth();
/**
* Creates a new builder for constructing a Nameplate configuration.
*
* @return a new builder instance
*/
static Builder builder() {
return new NameplateImpl.BuilderImpl();
}
/**
* Builder for constructing Nameplate configurations.
*/
interface Builder {
/**
* Sets the unique ID for the nameplate.
*
* @param id the nameplate ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the command suggestion for the nameplate
*
* @param commandSuggestion command suggestion
* @return the builder instance
*/
Builder commandSuggestion(String commandSuggestion);
/**
* Sets the display name for the nameplate.
*
* @param displayName the display name
* @return the builder instance
*/
Builder displayName(String displayName);
/**
* Sets the min width for the nameplate
*
* @param minWidth min width
* @return the builder instance
*/
Builder minWidth(int minWidth);
/**
* Sets the configured character for the left side of the nameplate.
*
* @param left the left-side configured character
* @return the builder instance
*/
Builder left(ConfiguredCharacter left);
/**
* Sets the configured character for the middle section of the nameplate.
*
* @param middle the middle configured character
* @return the builder instance
*/
Builder middle(ConfiguredCharacter middle);
/**
* Sets the configured character for the right side of the nameplate.
*
* @param right the right-side configured character
* @return the builder instance
*/
Builder right(ConfiguredCharacter right);
/**
* Builds and returns the configured Nameplate instance.
*
* @return the constructed Nameplate
*/
Nameplate build();
}
}
@@ -0,0 +1,206 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.nameplate;
import net.momirealms.customnameplates.api.feature.ConfiguredCharacter;
import net.momirealms.customnameplates.api.feature.OffsetFont;
import java.util.Objects;
import java.util.Optional;
/**
* Implementation of Nameplate
*/
public class NameplateImpl implements Nameplate {
private final String id;
private final String commandSuggestion;
private final String displayName;
private final ConfiguredCharacter left;
private final ConfiguredCharacter middle;
private final ConfiguredCharacter right;
private final int minWidth;
private NameplateImpl(String id, String commandSuggestion, String displayName, int minWidth, ConfiguredCharacter left, ConfiguredCharacter middle, ConfiguredCharacter right) {
this.id = id;
this.commandSuggestion = commandSuggestion;
this.displayName = displayName;
this.minWidth = minWidth;
this.left = left;
this.middle = middle;
this.right = right;
}
@Override
public String id() {
return id;
}
@Override
public String displayName() {
return displayName;
}
@Override
public String commandSuggestion() {
return this.commandSuggestion;
}
@Override
public ConfiguredCharacter left() {
return left;
}
@Override
public ConfiguredCharacter middle() {
return middle;
}
@Override
public ConfiguredCharacter right() {
return right;
}
@Override
public int minWidth() {
return minWidth;
}
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
NameplateImpl nameplate = (NameplateImpl) object;
return Objects.equals(id, nameplate.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImagePrefix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
advance = Math.max(minWidth, advance);
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
float exceed = mid_amount * (middle.advance() - 1) - advance - leftMargin - rightMargin;
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
}
sb.append(right.character());
float delta = (right.advance() + rightMargin + advance + (float) Math.floor(exceed / 2));
if (delta != 0) {
sb.append(OffsetFont.shortestNegChars(delta));
}
return sb.toString();
}
@Override
public String createImageSuffix(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
advance = Math.max(minWidth, advance);
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
float exceed = mid_amount * (middle.advance() - 1) - advance - leftMargin - rightMargin;
return OffsetFont.shortestPosChars((float) Math.ceil(exceed / 2) + rightMargin + right.advance());
}
@SuppressWarnings("DuplicatedCode")
@Override
public String createImage(float advance, float leftMargin, float rightMargin) {
if (advance <= 0) return "";
advance = Math.max(minWidth, advance);
StringBuilder sb = new StringBuilder();
sb.append(left.character());
sb.append(OffsetFont.NEG_1.character());
int mid_amount = (int) Math.ceil((advance + leftMargin + rightMargin) / (middle.advance() - 1));
if (mid_amount > 512) return "";
for (int i = 0; i < mid_amount; i++) {
sb.append(middle.character()).append(OffsetFont.NEG_1.character());
}
sb.append(right.character());
float delta = (right.advance() + rightMargin - (left.advance() - 1) - leftMargin);
if (delta != 0) {
sb.append(OffsetFont.createOffsets(-delta));
}
return sb.toString();
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private String commandSuggestion;
private String displayName;
private ConfiguredCharacter left;
private ConfiguredCharacter middle;
private ConfiguredCharacter right;
private int minWidth;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder commandSuggestion(String commandSuggestion) {
this.commandSuggestion = commandSuggestion;
return this;
}
@Override
public Builder displayName(String displayName) {
this.displayName = displayName;
return this;
}
@Override
public Builder minWidth(int minWidth) {
this.minWidth = minWidth;
return this;
}
@Override
public Builder left(ConfiguredCharacter left) {
this.left = left;
return this;
}
@Override
public Builder middle(ConfiguredCharacter middle) {
this.middle = middle;
return this;
}
@Override
public Builder right(ConfiguredCharacter right) {
this.right = right;
return this;
}
@Override
public Nameplate build() {
return new NameplateImpl(id, Optional.ofNullable(commandSuggestion).orElse(id), displayName, minWidth, left, middle, right);
}
}
}
@@ -0,0 +1,87 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.nameplate;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Manages the nameplates system, providing functionality to retrieve, check access,
* and manipulate nameplates associated with players.
*/
public interface NameplateManager extends Reloadable {
/**
* Retrieves a Nameplate by its unique ID.
*
* @param id the unique ID of the nameplate
* @return the Nameplate instance, or null if not found
*/
@Nullable
Nameplate nameplateById(String id);
/**
* Retrieves a Nameplate by command suggestion.
*
* @param suggestion the command suggestion of the nameplate
* @return the Nameplate instance, or null if not found
*/
@Nullable
Nameplate nameplateByCommand(String suggestion);
/**
* Returns a collection of all available nameplates.
*
* @return a collection of Nameplate instances
*/
Collection<Nameplate> nameplates();
/**
* Checks if a player has access to a specific nameplate by its ID.
*
* @param player the player to check
* @param id the ID of the nameplate
* @return true if the player has access, false otherwise
*/
boolean hasNameplate(CNPlayer player, String id);
/**
* Returns a collection of nameplates available to the player.
*
* @param player the player to check
* @return a collection of available Nameplate instances
*/
Collection<Nameplate> availableNameplates(CNPlayer player);
/**
* Returns the ID of the default nameplate to be used when no specific nameplate is set.
*
* @return the default nameplate ID
*/
String defaultNameplateId();
/**
* Returns the player's name tag to be displayed on the nameplate.
*
* @return the player's name tag
*/
String playerNameTag();
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,21 +15,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
package net.momirealms.customnameplates.api.feature.pack;
import java.io.File;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
public interface ResourcePackManager {
/**
* Interface to manager resource packs
*/
public interface ResourcePackManager extends Reloadable {
/**
* Generate the resource pack
* Generates the resource pack.
*/
void generateResourcePack();
/**
* Delete a directory
*
* @param file file
*/
void deleteDirectory(File file);
void generate();
}
@@ -0,0 +1,246 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.CustomNameplates;
import net.momirealms.customnameplates.api.network.Tracker;
import net.momirealms.customnameplates.api.util.SelfIncreaseEntityID;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.Vector;
import java.util.function.Consumer;
/**
* Represents an abstract tag for a {@link CNPlayer} that can be shown to specific viewers.
* This class handles the rendering of the tag, showing and hiding it for specific players,
* and managing tag attributes such as opacity and scale.
*/
public abstract class AbstractTag implements Tag {
/**
* The owner of this tag
*/
protected CNPlayer owner;
/**
* The {@link TagRenderer} responsible for rendering this tag.
*/
protected TagRenderer renderer;
/**
* The unique UUID assigned to this tag.
*/
protected final UUID uuid = UUID.randomUUID();
/**
* The unique entity ID assigned to this tag, used to track visibility and actions.
*/
protected final int entityID = SelfIncreaseEntityID.getAndIncrease();
/**
* A flag indicating whether the tag is currently visible to viewers.
*/
protected boolean isShown = false;
/**
* A list of players who are currently viewing this tag.
*/
protected final Vector<CNPlayer> viewers = new Vector<>();
/**
* An array representation of the viewers, used for optimization.
*/
protected CNPlayer[] viewerArray = new CNPlayer[0];
/**
* Constructs a new {@link AbstractTag} for the given {@link CNPlayer} owner and
* {@link TagRenderer}.
*
* @param owner the {@link CNPlayer} who owns this tag
* @param renderer the {@link TagRenderer} used to render this tag
*/
protected AbstractTag(CNPlayer owner, TagRenderer renderer) {
this.owner = owner;
this.renderer = renderer;
}
public CNPlayer[] viewerArray() {
return this.viewerArray;
}
/**
* Spawns the tag for the given viewer by sending a packet to the viewer.
*
* @param viewer the {@link CNPlayer} who will see the tag
* @return a list of objects representing the spawn packet for the tag
*/
protected abstract List<Object> spawnPacket(CNPlayer viewer);
@Override
public void tick() {
}
@Override
public void init() {
}
@Override
public boolean canShow() {
return true;
}
@Override
public boolean canShow(CNPlayer viewer) {
return true;
}
@Override
public void show() {
if (isShown) return;
this.isShown = true;
for (CNPlayer viewer : viewerArray) {
show(viewer);
}
}
@Override
public void show(CNPlayer viewer) {
if (!renderer.isValid()) return;
if (!isShown()) throw new IllegalStateException("This tag is currently hidden");
viewers.add(viewer);
resetViewerArray();
owner.trackPassengers(viewer, entityID);
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, spawnPacket(viewer));
}
@Override
public void hide() {
if (!isShown()) return;
for (CNPlayer viewer : viewerArray) {
hide(viewer);
}
this.isShown = false;
}
@Override
public void hide(CNPlayer viewer) {
if (!isShown()) return;
boolean removed = viewers.remove(viewer);
if (!removed) return;
resetViewerArray();
owner.untrackPassengers(viewer, entityID);
Object packet = CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID);
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
@Override
public void respawn(CNPlayer viewer) {
ArrayList<Object> packets = new ArrayList<>();
packets.add(CustomNameplates.getInstance().getPlatform().removeEntityPacket(entityID));
packets.addAll(spawnPacket(viewer));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packets);
}
@Override
public void respawn() {
for (CNPlayer viewer : viewerArray) {
respawn(viewer);
}
}
@Override
public void darkTag(boolean dark) {
for (CNPlayer viewer : viewerArray) {
darkTag(viewer, dark);
}
}
@Override
public void onPlayerScaleUpdate(double scale) {
for (CNPlayer viewer : viewerArray) {
onPlayerScaleUpdate(viewer, scale);
}
}
@Override
public void onPlayerScaleUpdate(CNPlayer viewer, double scale) {
Consumer<List<Object>> modifier1 = CustomNameplates.getInstance().getPlatform().createScaleModifier(scale(viewer).multiply(scale));
Consumer<List<Object>> modifier2 = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer).multiply(scale));
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier1, modifier2));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
@Override
public void updateTranslation() {
for (CNPlayer player : viewerArray) {
updateTranslation(player);
}
}
@Override
public void updateTranslation(CNPlayer viewer) {
Tracker tracker = owner.getTracker(viewer);
if (tracker != null) {
Consumer<List<Object>> modifier = CustomNameplates.getInstance().getPlatform().createTranslationModifier(translation(viewer).multiply(tracker.getScale()));
Object packet = CustomNameplates.getInstance().getPlatform().updateTextDisplayPacket(entityID, List.of(modifier));
CustomNameplates.getInstance().getPacketSender().sendPacket(viewer, packet);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AbstractTag that = (AbstractTag) o;
return owner == that.owner && uuid == that.uuid;
}
@Override
public int hashCode() {
return uuid.hashCode();
}
@Override
public int entityID() {
return entityID;
}
@Override
public UUID uuid() {
return uuid;
}
/**
* Resets the viewer array
*/
protected void resetViewerArray() {
this.viewerArray = viewers.toArray(new CNPlayer[0]);
}
@Override
public boolean isShown() {
return isShown;
}
@Override
public boolean isShown(CNPlayer another) {
if (!isShown) return false;
return viewers.contains(another);
}
@Override
public byte opacity() {
return -1;
}
}
@@ -0,0 +1,353 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import net.momirealms.customnameplates.common.util.Tristate;
/**
* NameTag Configuration
*/
public interface NameTagConfig {
/**
* Returns the unique ID of the name tag configuration.
*
* @return the name tag configuration ID
*/
String id();
/**
* Returns the requirements for the name tag owner.
*
* @return an array of owner requirements
*/
Requirement[] ownerRequirements();
/**
* Returns the requirements for the name tag viewer.
*
* @return an array of viewer requirements
*/
Requirement[] viewerRequirements();
/**
* Returns the carousel texts displayed on the name tag.
*
* @return an array of carousel texts
*/
CarouselText[] carouselTexts();
/**
* Returns the opacity level of the name tag.
*
* @return the opacity value as a byte
*/
byte opacity();
/**
* Returns the background color of the name tag.
*
* @return the background color as an integer
*/
int backgroundColor();
/**
* Checks if the name tag has a shadow effect.
*
* @return true if the name tag has a shadow, false otherwise
*/
boolean hasShadow();
/**
* Gets the billboard
*
* @return billboard
*/
Billboard billboard();
/**
* Checks if the name tag is see-through.
*
*/
Tristate isSeeThrough();
/**
* Checks if the default background color is used.
*
* @return true if the default background color is used, false otherwise
*/
boolean useDefaultBackgroundColor();
/**
* Checks if the name tag is affected by the crouching state of the player.
*
* @return true if affected by crouching, false otherwise
*/
boolean affectedByCrouching();
/**
* Checks if the name tag is affected by scaling.
*
* @return true if affected by scaling, false otherwise
*/
boolean affectedByScaling();
/**
* Checks if the name tag is affected by spectator mode.
*
* @return true if affected by spectator mode, false otherwise
*/
boolean affectedBySpectator();
/**
* Returns the alignment of the name tag.
*
* @return the alignment of the name tag
*/
Alignment alignment();
/**
* Returns the view range of the name tag.
*
* @return the view range as a float
*/
float viewRange();
/**
* Returns the shadow radius of the name tag.
*
* @return the shadow radius as a float
*/
float shadowRadius();
/**
* Returns the shadow strength of the name tag.
*
* @return the shadow strength as a float
*/
float shadowStrength();
/**
* Returns the scaling vector of the name tag.
*
* @return the scaling vector as a Vector3
*/
Vector3 scale();
/**
* Returns the translation vector for the name tag.
*
* @return the translation vector as a Vector3
*/
Vector3 translation();
/**
* Returns the maximum line width of the name tag.
*
* @return the line width as an integer
*/
int lineWidth();
/**
* Creates a new builder for constructing a NameTagConfig.
*
* @return a new builder instance
*/
static Builder builder() {
return new NameTagConfigImpl.BuilderImpl();
}
/**
* Builder for constructing NameTagConfig instances with customizable properties.
*/
interface Builder {
/**
* Sets the unique ID for the NameTagConfig.
*
* @param id the name tag configuration ID
* @return the builder instance
*/
Builder id(String id);
/**
* Sets the maximum line width for the name tag.
*
* @param lineWidth the maximum line width
* @return the builder instance
*/
Builder lineWidth(int lineWidth);
/**
* Sets the requirements for the name tag owner.
*
* @param requirements an array of owner requirements
* @return the builder instance
*/
Builder ownerRequirement(Requirement[] requirements);
/**
* Sets the requirements for the name tag viewer.
*
* @param requirements an array of viewer requirements
* @return the builder instance
*/
Builder viewerRequirement(Requirement[] requirements);
/**
* Sets the carousel texts for the name tag.
*
* @param carouselTexts an array of carousel texts
* @return the builder instance
*/
Builder carouselText(CarouselText[] carouselTexts);
/**
* Sets the opacity level for the name tag.
*
* @param opacity the opacity value as a byte
* @return the builder instance
*/
Builder opacity(byte opacity);
/**
* Sets the background color for the name tag.
*
* @param backgroundColor the background color as an integer
* @return the builder instance
*/
Builder backgroundColor(int backgroundColor);
/**
* Sets whether the name tag has a shadow effect.
*
* @param hasShadow true if the name tag should have a shadow, false otherwise
* @return the builder instance
*/
Builder hasShadow(boolean hasShadow);
/**
* Sets whether the name tag is see-through.
*
* @param seeThrough true if the name tag is see-through, false otherwise
* @return the builder instance
*/
Builder seeThrough(Tristate seeThrough);
/**
* Sets whether the name tag uses the default background color.
*
* @param useDefaultBackgroundColor true to use the default background color, false otherwise
* @return the builder instance
*/
Builder useDefaultBackgroundColor(boolean useDefaultBackgroundColor);
/**
* Sets the alignment of the name tag.
*
* @param alignment the alignment setting
* @return the builder instance
*/
Builder alignment(Alignment alignment);
/**
* Sets the billboard of the name tag
*
* @param billboard billboard
* @return the builder instance
*/
Builder billboard(Billboard billboard);
/**
* Sets the view range for the name tag.
*
* @param viewRange the view range as a float
* @return the builder instance
*/
Builder viewRange(float viewRange);
/**
* Sets the shadow radius for the name tag.
*
* @param shadowRadius the shadow radius as a float
* @return the builder instance
*/
Builder shadowRadius(float shadowRadius);
/**
* Sets the shadow strength for the name tag.
*
* @param shadowStrength the shadow strength as a float
* @return the builder instance
*/
Builder shadowStrength(float shadowStrength);
/**
* Sets the scaling factor for the name tag.
*
* @param scale the scaling vector
* @return the builder instance
*/
Builder scale(Vector3 scale);
/**
* Sets the translation vector for the name tag.
*
* @param translation the translation vector
* @return the builder instance
*/
Builder translation(Vector3 translation);
/**
* Sets whether the name tag is affected by crouching.
*
* @param affectedByCrouching true if the name tag is affected by crouching, false otherwise
* @return the builder instance
*/
Builder affectedByCrouching(boolean affectedByCrouching);
/**
* Sets whether the name tag is affected by spectator mode.
*
* @param affectedBySpectator true if the name tag is affected by spectator mode, false otherwise
* @return the builder instance
*/
Builder affectedBySpectator(boolean affectedBySpectator);
/**
* Sets whether the name tag is affected by scaling.
*
* @param affectedByScale true if the name tag is affected by scaling, false otherwise
* @return the builder instance
*/
Builder affectedByScaling(boolean affectedByScale);
/**
* Builds and returns the configured NameTagConfig instance.
*
* @return the constructed NameTagConfig
*/
NameTagConfig build();
}
}
@@ -0,0 +1,325 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.feature.CarouselText;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.util.Alignment;
import net.momirealms.customnameplates.api.util.Billboard;
import net.momirealms.customnameplates.api.util.Vector3;
import net.momirealms.customnameplates.common.util.Tristate;
/**
* Implementation of NameTagConfig
*/
public class NameTagConfigImpl implements NameTagConfig {
private final String id;
private final Requirement[] ownerRequirements;
private final Requirement[] viewerRequirements;
private final CarouselText[] carouselTexts;
private final int lineWidth;
private final byte opacity;
private final int backgroundColor;
private final boolean hasShadow;
private final Tristate isSeeThrough;
private final boolean useDefaultBackgroundColor;
private final Alignment alignment;
private final Billboard billboard;
private final float viewRange;
private final float shadowRadius;
private final float shadowStrength;
private final Vector3 scale;
private final Vector3 translation;
private final boolean affectedByCrouching;
private final boolean affectedByScale;
private final boolean affectedBySpectator;
private NameTagConfigImpl(String id, Requirement[] ownerRequirements, Requirement[] viewerRequirements, CarouselText[] carouselTexts, int lineWidth, byte opacity, int backgroundColor, boolean hasShadow, Tristate isSeeThrough, boolean useDefaultBackgroundColor, Alignment alignment, Billboard billboard, float viewRange, float shadowRadius, float shadowStrength, Vector3 scale, Vector3 translation, boolean affectedByCrouching, boolean affectedByScale, boolean affectedBySpectator) {
this.id = id;
this.ownerRequirements = ownerRequirements;
this.viewerRequirements = viewerRequirements;
this.carouselTexts = carouselTexts;
this.opacity = opacity;
this.backgroundColor = backgroundColor;
this.hasShadow = hasShadow;
this.isSeeThrough = isSeeThrough;
this.useDefaultBackgroundColor = useDefaultBackgroundColor;
this.alignment = alignment;
this.billboard = billboard;
this.viewRange = viewRange;
this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength;
this.scale = scale;
this.translation = translation;
this.lineWidth = lineWidth;
this.affectedByCrouching = affectedByCrouching;
this.affectedByScale = affectedByScale;
this.affectedBySpectator = affectedBySpectator;
}
@Override
public String id() {
return id;
}
@Override
public Requirement[] ownerRequirements() {
return ownerRequirements;
}
@Override
public Requirement[] viewerRequirements() {
return viewerRequirements;
}
@Override
public CarouselText[] carouselTexts() {
return carouselTexts;
}
@Override
public byte opacity() {
return opacity;
}
@Override
public int backgroundColor() {
return backgroundColor;
}
@Override
public boolean hasShadow() {
return hasShadow;
}
@Override
public Billboard billboard() {
return billboard;
}
@Override
public Tristate isSeeThrough() {
return isSeeThrough;
}
@Override
public boolean useDefaultBackgroundColor() {
return useDefaultBackgroundColor;
}
@Override
public boolean affectedByCrouching() {
return affectedByCrouching;
}
@Override
public boolean affectedByScaling() {
return affectedByScale;
}
@Override
public boolean affectedBySpectator() {
return affectedBySpectator;
}
@Override
public Alignment alignment() {
return alignment;
}
@Override
public float viewRange() {
return viewRange;
}
@Override
public float shadowRadius() {
return shadowRadius;
}
@Override
public float shadowStrength() {
return shadowStrength;
}
@Override
public Vector3 scale() {
return scale;
}
@Override
public Vector3 translation() {
return translation;
}
@Override
public int lineWidth() {
return lineWidth;
}
/**
* The builder implementation
*/
public static class BuilderImpl implements Builder {
private String id;
private Requirement[] ownerRequirements;
private Requirement[] viewerRequirements;
private CarouselText[] carouselTexts;
private int lineWidth;
private byte opacity;
private int backgroundColor;
private boolean hasShadow;
private Tristate isSeeThrough;
private boolean useDefaultBackgroundColor;
private Alignment alignment;
private Billboard billboard;
private float viewRange;
private float shadowRadius;
private float shadowStrength;
private Vector3 scale;
private Vector3 translation;
private boolean affectedByCrouching;
private boolean affectedByScale;
private boolean affectedBySpectator;
@Override
public Builder id(String id) {
this.id = id;
return this;
}
@Override
public Builder lineWidth(int lineWidth) {
this.lineWidth = lineWidth;
return this;
}
@Override
public Builder ownerRequirement(Requirement[] requirements) {
this.ownerRequirements = requirements;
return this;
}
@Override
public Builder viewerRequirement(Requirement[] requirements) {
this.viewerRequirements = requirements;
return this;
}
@Override
public Builder carouselText(CarouselText[] carouselTexts) {
this.carouselTexts = carouselTexts;
return this;
}
@Override
public Builder opacity(byte opacity) {
this.opacity = opacity;
return this;
}
@Override
public Builder backgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
@Override
public Builder hasShadow(boolean hasShadow) {
this.hasShadow = hasShadow;
return this;
}
@Override
public Builder seeThrough(Tristate seeThrough) {
this.isSeeThrough = seeThrough;
return this;
}
@Override
public Builder useDefaultBackgroundColor(boolean useDefaultBackgroundColor) {
this.useDefaultBackgroundColor = useDefaultBackgroundColor;
return this;
}
@Override
public Builder alignment(Alignment alignment) {
this.alignment = alignment;
return this;
}
@Override
public Builder billboard(Billboard billboard) {
this.billboard = billboard;
return this;
}
@Override
public Builder viewRange(float viewRange) {
this.viewRange = viewRange;
return this;
}
@Override
public Builder shadowRadius(float shadowRadius) {
this.shadowRadius = shadowRadius;
return this;
}
@Override
public Builder shadowStrength(float shadowStrength) {
this.shadowStrength = shadowStrength;
return this;
}
@Override
public Builder scale(Vector3 scale) {
this.scale = scale;
return this;
}
@Override
public Builder translation(Vector3 translation) {
this.translation = translation;
return this;
}
@Override
public Builder affectedByCrouching(boolean affectedByCrouching) {
this.affectedByCrouching = affectedByCrouching;
return this;
}
@Override
public Builder affectedBySpectator(boolean affectedBySpectator) {
this.affectedBySpectator = affectedBySpectator;
return this;
}
@Override
public Builder affectedByScaling(boolean affectedByScale) {
this.affectedByScale = affectedByScale;
return this;
}
@Override
public NameTagConfig build() {
return new NameTagConfigImpl(id, ownerRequirements, viewerRequirements, carouselTexts, lineWidth, opacity, backgroundColor, hasShadow, isSeeThrough, useDefaultBackgroundColor, alignment, billboard, viewRange, shadowRadius, shadowStrength, scale, translation, affectedByCrouching, affectedByScale, affectedBySpectator);
}
}
}
@@ -0,0 +1,227 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.util.Vector3;
import java.util.UUID;
/**
* Represents a tag
*/
public interface Tag {
/**
* Returns the ID of the tag.
*
* @return the tag ID
*/
String id();
/**
* Returns the entity ID associated with the tag.
*
* @return the entity ID
*/
int entityID();
/**
* Returns the UUID of the tag.
*
* @return the tag UUID
*/
UUID uuid();
/**
* Checks if the tag is affected by crouching.
*
* @return true if affected by crouching, false otherwise
*/
boolean affectedByCrouching();
/**
* Checks if the tag is affected by scaling.
*
* @return true if affected by scaling, false otherwise
*/
boolean affectedByScaling();
/**
* Checks if the tag is affected by spectator mode.
*
* @return true if affected by spectator mode, false otherwise
*/
boolean affectedBySpectator();
/**
* Hides the tag for all viewers.
*/
void hide();
/**
* Hides the tag for a specific viewer.
*
* @param viewer the player for whom the tag will be hidden
*/
void hide(CNPlayer viewer);
/**
* Shows the tag to all viewers.
*/
void show();
/**
* Shows the tag to a specific viewer.
*
* @param viewer the player for whom the tag will be shown
*/
void show(CNPlayer viewer);
/**
* Respawns the tag for all viewers.
*/
void respawn();
/**
* Respawns the tag for a specific viewer.
*
* @param viewer the player for whom the tag will be respawned
*/
void respawn(CNPlayer viewer);
/**
* Returns the opacity of the tag.
*
* @return the opacity value as a byte
*/
byte opacity();
/**
* Checks if the tag can be shown to all viewers.
*
* @return true if the tag can be shown, false otherwise
*/
boolean canShow();
/**
* Checks if the tag can be shown to a specific viewer.
*
* @param viewer the player to check
* @return true if the tag can be shown, false otherwise
*/
boolean canShow(CNPlayer viewer);
/**
* Checks if the tag is currently shown to all viewers.
*
* @return true if the tag is shown, false otherwise
*/
boolean isShown();
/**
* Checks if the tag is currently shown to a specific viewer.
*
* @param viewer the player to check
* @return true if the tag is shown, false otherwise
*/
boolean isShown(CNPlayer viewer);
/**
* Called every tick to update the tag's state.
*/
void tick();
/**
* Initializes the tag.
*/
void init();
/**
* Returns the text height of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the text height
*/
double getTextHeight(CNPlayer viewer);
/**
* Sets the dark mode for the tag.
*
* @param dark whether the tag should be dark
*/
void darkTag(boolean dark);
/**
* Sets the dark mode for the tag for a specific viewer.
*
* @param viewer the player for whom the dark mode should be applied
* @param dark whether the tag should be dark for the specific viewer
*/
void darkTag(CNPlayer viewer, boolean dark);
/**
* Updates the tag scale when the player's scale changes.
*
* @param scale the new scale value
*/
void onPlayerScaleUpdate(double scale);
/**
* Updates the tag scale when the player's scale changes for a specific viewer.
*
* @param viewer the player to update
* @param scale the new scale value
*/
void onPlayerScaleUpdate(CNPlayer viewer, double scale);
/**
* Updates the translation of the tag.
*/
void updateTranslation();
/**
* Updates the translation of the tag for a certain player
*
* @param viewer the player to update
*/
void updateTranslation(CNPlayer viewer);
/**
* Returns the scaling vector of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the scaling vector
*/
Vector3 scale(CNPlayer viewer);
/**
* Returns the translation vector of the tag for a specific viewer.
*
* @param viewer the player to check
* @return the translation vector
*/
Vector3 translation(CNPlayer viewer);
/**
* Returns if the tag has a relative translation
*
* @return has or not
*/
boolean relativeTranslation();
}
@@ -0,0 +1,102 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import java.util.function.Predicate;
/**
* An interface to control the rendering of tags
*/
public interface TagRenderer {
/**
* Returns the offset applied to the tag for positioning a "hat" or similar element above the entity's head.
*
* @return the hat offset value
*/
double hatOffset();
/**
* Sets the offset applied to the tag for positioning a "hat" or similar element above the entity's head.
*
* @param hatOffset the new hat offset value
*/
void hatOffset(double hatOffset);
/**
* Checks if the tag is valid
*
* @return valid or not
*/
boolean isValid();
/**
* Called every tick to update the state of the tags managed by this renderer.
*/
void onTick();
/**
* Destroys the renderer, cleaning up any resources or tags it manages.
*/
void destroy();
/**
* Adds a new tag to be rendered.
*
* @param tag the tag to add
*/
void addTag(Tag tag);
/**
* Returns the array of tags currently managed by this renderer.
*
* @return an array of Tag instances
*/
Tag[] tags();
/**
* Removes tags that match the given predicate.
*
* @param predicate a predicate to test tags for removal
* @return the number of tags removed
*/
int removeTagIf(Predicate<Tag> predicate);
/**
* Returns the index of the specified tag in the renderer's tag list.
*
* @param tag the tag to check
* @return the index of the tag, or -1 if not found
*/
int tagIndex(Tag tag);
/**
* Adds a tag at the specified index in the renderer's tag list.
*
* @param tag the tag to add
* @param index the index at which to insert the tag
*/
void addTag(Tag tag, int index);
/**
* Removes the specified tag from the renderer's tag list.
*
* @param tag the tag to remove
*/
void removeTag(Tag tag);
}
@@ -0,0 +1,86 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Represents a view of teams and their associated members.
* <p>
* This class allows you to manage a collection of teams, with each team having a set of member names.
* You can add or remove members from teams, retrieve the list of members for a specific team,
* or remove entire teams.
* </p>
*/
public class TeamView {
/**
* A map that stores the team names as keys and their associated members as values.
* The members are stored as a set of strings to avoid duplicates.
*/
private final Map<String, Set<String>> teamMembers = new Object2ObjectOpenHashMap<>();
/**
* Retrieves the members of a given team.
*
* @param team the name of the team
* @return a set of member names, or {@code null} if the team does not exist
*/
@Nullable
public Set<String> getTeamMembers(String team) {
return teamMembers.get(team);
}
/**
* Adds a collection of members to a team. If the team does not exist, it will be created.
*
* @param team the name of the team
* @param members the collection of members to add
*/
public void addTeamMembers(String team, Collection<String> members) {
teamMembers.computeIfAbsent(team, k -> new ObjectOpenHashSet<>(members));
}
/**
* Removes a collection of members from a team. If the team exists, the members will be removed
* from the team's member set.
*
* @param team the name of the team
* @param members the collection of members to remove
*/
public void removeTeamMembers(String team, Collection<String> members) {
Set<String> membersSet = teamMembers.get(team);
if (membersSet != null) {
membersSet.removeAll(members);
}
}
/**
* Removes an entire team and all its members.
*
* @param team the name of the team to remove
*/
public void removeTeam(String team) {
this.teamMembers.remove(team);
}
}
@@ -0,0 +1,137 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.feature.tag;
import net.momirealms.customnameplates.api.CNPlayer;
import net.momirealms.customnameplates.api.feature.JoinQuitListener;
import net.momirealms.customnameplates.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
/**
* An interface manages unlimited tags
*/
public interface UnlimitedTagManager extends Reloadable, JoinQuitListener {
/**
* Called every tick to update the state of tags.
*/
void onTick();
/**
* Checks if name tags should always be shown.
*
* @return true if name tags are always shown, false otherwise
*/
boolean isAlwaysShow();
/**
* Retrieves the name tag configuration by its id.
*
* @param id the id of the tag configuration
* @return the corresponding NameTagConfig
*/
NameTagConfig configById(String id);
/**
* Returns all available name tag configurations.
*
* @return an array of all NameTagConfig instances
*/
NameTagConfig[] nameTagConfigs();
/**
* Sets whether a player is in preview mode for tags.
*
* @param player the player to update
* @param preview true to enable preview mode, false to disable
*/
void setTempPreviewing(CNPlayer player, boolean preview);
/**
* Sets whether a player can always see their tags
*
* @param player the player to update
* @param preview true to enable preview mode, false to disable
*/
void togglePreviewing(CNPlayer player, boolean preview);
/**
* Returns the duration (in ticks) for which a tag preview is shown.
*
* @return the preview duration in ticks
*/
int previewDuration();
/**
* Returns the TagRenderer responsible for rendering tags for a specific owner.
*
* @param owner the owner of the tags
* @return the TagRenderer for the owner
*/
@Nullable
TagRenderer getTagRender(CNPlayer owner);
/**
* Internal method for handling when a player is added to the owner's viewer list.
*
* @param owner the player who owns the tags
* @param added the player who is added to the viewer list
*/
@ApiStatus.Internal
void onAddPlayer(CNPlayer owner, CNPlayer added);
/**
* Internal method for handling when a player is removed from the owner's viewer list.
*
* @param owner the player who owns the tags
* @param removed the player who is removed from the viewer list
*/
@ApiStatus.Internal
void onRemovePlayer(CNPlayer owner, CNPlayer removed);
/**
* Internal method for updating a player's crouching state.
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param isCrouching true if the player is crouching, false otherwise
*/
@ApiStatus.Internal
void onPlayerDataSet(CNPlayer owner, CNPlayer viewer, boolean isCrouching);
/**
* Internal method for updating a player's scale attributes.
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param scale the new scale value
*/
@ApiStatus.Internal
void onPlayerAttributeSet(CNPlayer owner, CNPlayer viewer, double scale);
/**
* Internal method for updating a player's game mode
*
* @param owner the player who owns the tags
* @param viewer the player viewing the tags
* @param isSpectator true if the player is a spectator, false otherwise
*/
@ApiStatus.Internal
void onPlayerGameModeChange(CNPlayer owner, CNPlayer viewer, boolean isSpectator);
}
@@ -0,0 +1,394 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.helper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.json.JSONOptions;
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
import net.momirealms.customnameplates.api.ConfigManager;
import net.momirealms.customnameplates.api.CustomNameplates;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Helper class for handling Adventure components and related functionalities.
*/
public class AdventureHelper {
/**
* Whether to enable legacy color code support
*/
public static boolean legacySupport = false;
private final MiniMessage miniMessage;
private final MiniMessage miniMessageStrict;
private final GsonComponentSerializer gsonComponentSerializer;
private final Cache<String, Component> miniMessageToComponentCache;
private final Cache<String, Object> miniMessageToMinecraftComponentCache;
private final Cache<Object, String> minecraftComponentToMiniMessageCache;
private final Cache<String, String> jsonToMiniMessageCache;
private AdventureHelper() {
this.miniMessage = MiniMessage.builder().build();
this.miniMessageStrict = MiniMessage.builder().strict(true).build();
GsonComponentSerializer.Builder builder = GsonComponentSerializer.builder();
if (!VersionHelper.isVersionNewerThan1_20_5()) {
builder.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get());
builder.editOptions((b) -> b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, false));
}
if (!VersionHelper.isVersionNewerThan1_21_5()) {
builder.editOptions((b) -> {
b.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE);
b.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE);
b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true);
});
}
this.gsonComponentSerializer = builder.build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setName("nameplates-cache-scheduler");
return thread;
});
executor.setRemoveOnCancelPolicy(true);
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
this.miniMessageToComponentCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(1024)
.build();
this.miniMessageToMinecraftComponentCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(1024)
.build();
this.minecraftComponentToMiniMessageCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(256)
.build();
this.jsonToMiniMessageCache =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.executor(executor)
.maximumSize(256)
.build();
}
/**
* Clear cache
*/
public static void clearCache() {
AdventureHelper instance = getInstance();
instance.miniMessageToMinecraftComponentCache.cleanUp();
instance.miniMessageToComponentCache.cleanUp();
instance.jsonToMiniMessageCache.cleanUp();
instance.minecraftComponentToMiniMessageCache.cleanUp();
}
private static class SingletonHolder {
private static final AdventureHelper INSTANCE = new AdventureHelper();
}
/**
* Retrieves the singleton instance of AdventureHelper.
*
* @return the singleton instance
*/
public static AdventureHelper getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* Converts a MiniMessage string to a Component.
*
* @param miniMessage the MiniMessage string
* @return the resulting Component
*/
public static Component miniMessage(String miniMessage) {
AdventureHelper instance = getInstance();
return instance.miniMessageToComponentCache.get(miniMessage, (text) -> {
if (legacySupport) {
return miniMessage().deserialize(legacyToMiniMessage(text));
} else {
return miniMessage().deserialize(text);
}
});
}
/**
* Converts a json string to a MiniMessage string.
*
* @param json the JSON string
* @return the MiniMessage string representation
*/
public static String jsonToMiniMessage(String json) {
AdventureHelper instance = getInstance();
return instance.jsonToMiniMessageCache.get(json, (rawJson) ->
instance.miniMessageStrict.serialize(instance.gsonComponentSerializer.deserialize(json))
);
}
/**
* Converts a MiniMessage string to a Minecraft component object.
*
* @param miniMessage the MiniMessage string
* @return the Minecraft component object
*/
public static Object miniMessageToMinecraftComponent(String miniMessage) {
AdventureHelper instance = getInstance();
return instance.miniMessageToMinecraftComponentCache.get(miniMessage, (text) -> {
String json = instance.gsonComponentSerializer.serialize(miniMessage(text));
return CustomNameplates.getInstance().getPlatform().jsonToMinecraftComponent(json);
});
}
/**
* Converts a MiniMessage string with a score component to a Minecraft component object.
*
* @param miniMessage the MiniMessage string
* @param name the name used in the score component
* @param objective the objective used in the score component
* @return the Minecraft component object
*/
public static Object miniMessageToMinecraftComponent(String miniMessage, String name, String objective) {
AdventureHelper instance = getInstance();
return instance.miniMessageToMinecraftComponentCache.get(miniMessage, (text) -> {
String json = instance.gsonComponentSerializer.serialize(Component.score().name(name).objective(objective).build().append(miniMessage(text)));
return CustomNameplates.getInstance().getPlatform().jsonToMinecraftComponent(json);
});
}
/**
* Converts a Minecraft component object to a MiniMessage string.
*
* @param component the Minecraft component object
* @return the MiniMessage string representation
*/
public static String minecraftComponentToMiniMessage(Object component) {
AdventureHelper instance = getInstance();
return instance.minecraftComponentToMiniMessageCache.get(component, (object) -> {
String json = CustomNameplates.getInstance().getPlatform().minecraftComponentToJson(object);
return instance.miniMessageStrict.serialize(instance.gsonComponentSerializer.deserialize(json));
});
}
/**
* Retrieves the MiniMessage instance.
*
* @return the MiniMessage instance
*/
public static MiniMessage miniMessage() {
return getInstance().miniMessage;
}
/**
* Retrieves the GsonComponentSerializer instance.
*
* @return the GsonComponentSerializer instance
*/
public static GsonComponentSerializer gson() {
return getInstance().gsonComponentSerializer;
}
/**
* Surrounds the provided text with the default nameplates font.
*
* @param text the text to surround
* @return the text surrounded by the default nameplates font tag
*/
public static String surroundWithNameplatesFont(String text) {
return surroundWithMiniMessageFont(text, ConfigManager.namespace() + ":" + ConfigManager.font());
}
/**
* Removes shadow from the provided text using a specific color code trick.
*
* @param text the text to modify
* @return the text wrapped in a color tag to remove shadows
*/
public static String removeShadowTricky(String text) {
return "<#FFFEFD>" + text + "</#FFFEFD>";
}
/**
* Removes shadow from the provided text using a specific color code.
*
* @param text the text to modify
* @return the text wrapped in a color tag to remove shadows
*/
public static String removeShadow(String text) {
return "<shadow:#00000000><#F0F0F0>" + text + "</#F0F0F0></shadow>";
}
/**
* Surrounds text with a MiniMessage font tag.
*
* @param text the text to surround
* @param font the font as a {@link Key}
* @return the text surrounded by the MiniMessage font tag
*/
public static String surroundWithMiniMessageFont(String text, Key font) {
return "<font:" + font.asString() + ">" + text + "</font>";
}
/**
* Surrounds text with a MiniMessage font tag.
*
* @param text the text to surround
* @param font the font as a {@link String}
* @return the text surrounded by the MiniMessage font tag
*/
public static String surroundWithMiniMessageFont(String text, String font) {
return "<font:" + font + ">" + text + "</font>";
}
/**
* Checks if a character is a legacy color code.
*
* @param c the character to check
* @return true if the character is a color code, false otherwise
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean isLegacyColorCode(char c) {
return c == '§' || c == '&';
}
/**
* Strips the minimessage tags
*
* @param text text
* @return the stripped texts
*/
public static String stripTags(String text) {
return getInstance().miniMessage.stripTags(text);
}
/**
* Converts a legacy color code string to a MiniMessage string.
*
* @param legacy the legacy color code string
* @return the MiniMessage string representation
*/
public static String legacyToMiniMessage(String legacy) {
StringBuilder stringBuilder = new StringBuilder();
char[] chars = legacy.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (!isLegacyColorCode(chars[i])) {
stringBuilder.append(chars[i]);
continue;
}
if (i + 1 >= chars.length) {
stringBuilder.append(chars[i]);
continue;
}
switch (chars[i+1]) {
case '0' -> stringBuilder.append("<black>");
case '1' -> stringBuilder.append("<dark_blue>");
case '2' -> stringBuilder.append("<dark_green>");
case '3' -> stringBuilder.append("<dark_aqua>");
case '4' -> stringBuilder.append("<dark_red>");
case '5' -> stringBuilder.append("<dark_purple>");
case '6' -> stringBuilder.append("<gold>");
case '7' -> stringBuilder.append("<gray>");
case '8' -> stringBuilder.append("<dark_gray>");
case '9' -> stringBuilder.append("<blue>");
case 'a', 'A' -> stringBuilder.append("<green>");
case 'b', 'B' -> stringBuilder.append("<aqua>");
case 'c', 'C' -> stringBuilder.append("<red>");
case 'd', 'D' -> stringBuilder.append("<light_purple>");
case 'e', 'E' -> stringBuilder.append("<yellow>");
case 'f', 'F' -> stringBuilder.append("<white>");
case 'r', 'R' -> stringBuilder.append("<reset>");
case 'l', 'L' -> stringBuilder.append("<b>");
case 'm', 'M' -> stringBuilder.append("<st>");
case 'o', 'O' -> stringBuilder.append("<i>");
case 'n', 'N' -> stringBuilder.append("<u>");
case 'k', 'K' -> stringBuilder.append("<obf>");
case 'x', 'X' -> {
if (i + 13 >= chars.length
|| !isLegacyColorCode(chars[i+2])
|| !isLegacyColorCode(chars[i+4])
|| !isLegacyColorCode(chars[i+6])
|| !isLegacyColorCode(chars[i+8])
|| !isLegacyColorCode(chars[i+10])
|| !isLegacyColorCode(chars[i+12])) {
stringBuilder.append(chars[i]);
continue;
}
stringBuilder
.append("<#")
.append(chars[i+3])
.append(chars[i+5])
.append(chars[i+7])
.append(chars[i+9])
.append(chars[i+11])
.append(chars[i+13])
.append(">");
i += 12;
}
case '#' -> {
if (i + 7 >= chars.length
|| !isHexColorCode(chars[i+2])
|| !isHexColorCode(chars[i+3])
|| !isHexColorCode(chars[i+4])
|| !isHexColorCode(chars[i+5])
|| !isHexColorCode(chars[i+6])
|| !isHexColorCode(chars[i+7])) {
stringBuilder.append(chars[i]);
continue;
}
stringBuilder
.append("<#")
.append(chars[i+2])
.append(chars[i+3])
.append(chars[i+4])
.append(chars[i+5])
.append(chars[i+6])
.append(chars[i+7])
.append(">");
i += 6;
}
default -> {
stringBuilder.append(chars[i]);
continue;
}
}
i++;
}
return stringBuilder.toString();
}
private static boolean isHexColorCode(char c) {
return c >= '0' && c <= '9' ||
c >= 'a' && c <= 'f' ||
c >= 'A' && c <= 'F';
}
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.helper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Helper class for managing Gson instances.
*/
public class GsonHelper {
private final Gson gson;
/**
* Create the gson
*/
public GsonHelper() {
this.gson = new GsonBuilder()
.create();
}
/**
* Retrieves the Gson instance.
*
* @return the Gson instance
*/
public Gson getGson() {
return gson;
}
/**
* Retrieves the singleton Gson instance from GsonHelper.
*
* @return the singleton Gson instance
*/
public static Gson get() {
return SingletonHolder.INSTANCE.getGson();
}
/**
* Static inner class for holding the singleton instance of GsonHelper.
*/
private static class SingletonHolder {
private static final GsonHelper INSTANCE = new GsonHelper();
}
}
@@ -0,0 +1,330 @@
/*
* Copyright (C) <2024> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.helper;
import net.momirealms.customnameplates.common.plugin.NameplatesPlugin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* VersionHelper is a utility class that provides methods for managing and checking version-related information,
* including plugin updates and server version details. It implements the VersionManager interface.
*/
public class VersionHelper {
/**
* A function to check for plugin updates asynchronously by comparing the plugin's current version with the latest version available.
*/
public static final Function<NameplatesPlugin, CompletableFuture<Boolean>> UPDATE_CHECKER = (plugin) -> {
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
plugin.getScheduler().async().execute(() -> {
try {
URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2723&key=version");
URLConnection conn = url.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(60000);
InputStream inputStream = conn.getInputStream();
String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine();
String current = plugin.getPluginVersion();
inputStream.close();
if (!compareVer(newest, current)) {
updateFuture.complete(false);
return;
}
updateFuture.complete(true);
} catch (Exception exception) {
plugin.getPluginLogger().warn("Error occurred when checking update.");
updateFuture.completeExceptionally(exception);
}
});
return updateFuture;
};
private static int version;
private static boolean mojmap;
private static boolean folia;
private static boolean mohist;
private static boolean paper;
/**
* Initializes version-specific settings based on the server version.
* This method checks if the server is running Mojmap, Folia, Mohist, or Paper.
*
* @param serverVersion The server version string.
*/
public static void init(String serverVersion) {
version = parseVersionToInteger(serverVersion);
checkMojMap();
checkFolia();
checkMohist();
checkPaper();
boolean isModdedServer = mohist;
paper = paper && !isModdedServer;
}
public static int parseVersionToInteger(String versionString) {
int v1 = 0;
int v2 = 0;
int v3 = 0;
int currentNumber = 0;
int part = 0;
for(int i = 0; i < versionString.length(); ++i) {
char c = versionString.charAt(i);
if (c >= '0' && c <= '9') {
currentNumber = currentNumber * 10 + (c - 48);
} else if (c == '.') {
if (part == 0) {
v1 = currentNumber;
}
if (part == 1) {
v2 = currentNumber;
}
++part;
currentNumber = 0;
if (part > 2) {
break;
}
}
}
if (part == 0) {
v1 = currentNumber;
} else if (part == 1) {
v2 = currentNumber;
} else if (part == 2) {
v3 = currentNumber;
}
return 10000 * v1 + v2 * 100 + v3;
}
/**
* Gets the current server version as a float.
*
* @return The server version as a float.
*/
public static float version() {
return version;
}
/**
* Checks if the server is running Mojmap.
*/
private static void checkMojMap() {
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
mojmap = true;
} catch (ClassNotFoundException ignored) {
}
}
/**
* Checks if the server is running Folia.
*/
private static void checkFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
folia = true;
} catch (ClassNotFoundException ignored) {
}
}
/**
* Checks if the server is running Mohist.
*/
private static void checkMohist() {
try {
Class.forName("com.mohistmc.api.ServerAPI");
mohist = true;
} catch (ClassNotFoundException ignored) {
}
}
/**
* Checks if the server is running Paper or its forks.
*/
private static void checkPaper() {
try {
Class.forName("com.destroystokyo.paper.Metrics");
paper = true;
} catch (ClassNotFoundException ignored) {
}
}
public static boolean isVersionNewerThan26_1() {
return version >= 260100;
}
/**
* Checks if the server version is newer than 1.21.9
*
* @return True if the version is newer than 1.21.9, otherwise false.
*/
public static boolean isVersionNewerThan1_21_9() {
return version >= 12109;
}
/**
* Checks if the server version is newer than 1.21.5
*
* @return True if the version is newer than 1.21.5, otherwise false.
*/
public static boolean isVersionNewerThan1_21_5() {
return version >= 12105;
}
/**
* Checks if the server version is newer than 1.21.4
*
* @return True if the version is newer than 1.21.4, otherwise false.
*/
public static boolean isVersionNewerThan1_21_4() {
return version >= 12104;
}
/**
* Checks if the server version is newer than 1.21.2.
*
* @return True if the version is newer than 1.21.2, otherwise false.
*/
public static boolean isVersionNewerThan1_21_2() {
return version >= 12102;
}
/**
* Checks if the server version is newer than 1.20.5.
*
* @return True if the version is newer than 1.20.5, otherwise false.
*/
public static boolean isVersionNewerThan1_20_5() {
return version >= 12005;
}
/**
* Checks if the server version is newer than 1.20.4.
*
* @return True if the version is newer than 1.20.4, otherwise false.
*/
public static boolean isVersionNewerThan1_20_4() {
return version >= 12004;
}
/**
* Checks if the server version is newer than 1.19.4.
*
* @return True if the version is newer than 1.19.4, otherwise false.
*/
public static boolean isVersionNewerThan1_19_4() {
return version >= 11904;
}
/**
* Checks if the server version is newer than 1.20.2.
*
* @return True if the version is newer than 1.20.2, otherwise false.
*/
public static boolean isVersionNewerThan1_20_2() {
return version >= 12002;
}
/**
* Checks if the server version is newer than 1.20.
*
* @return True if the version is newer than 1.20, otherwise false.
*/
public static boolean isVersionNewerThan1_20() {
return version >= 12000;
}
/**
* Checks if the server is running Folia.
*
* @return True if the server is running Folia, otherwise false.
*/
public static boolean isFolia() {
return folia;
}
/**
* Checks if the server is running Mohist.
*
* @return True if the server is running Mohist, otherwise false.
*/
public static boolean isMohist() {
return mohist;
}
/**
* Checks if the server is running Paper or its forks.
*
* @return True if the server is running Paper or its forks, otherwise false.
*/
public static boolean isPaperOrItsForks() {
return paper;
}
/**
* Checks if the server is using Mojmap.
*
* @return True if the server is using Mojmap, otherwise false.
*/
public static boolean isMojmap() {
return mojmap;
}
/**
* Compares two version strings to determine if the first version is newer than the second.
*
* @param newV The new version string.
* @param currentV The current version string.
* @return True if the new version is newer than the current version, otherwise false.
*/
private static boolean compareVer(String newV, String currentV) {
if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
return false;
}
String[] newVS = newV.split("\\.");
String[] currentVS = currentV.split("\\.");
int maxL = Math.min(newVS.length, currentVS.length);
for (int i = 0; i < maxL; i++) {
try {
String[] newPart = newVS[i].split("-");
String[] currentPart = currentVS[i].split("-");
int newNum = Integer.parseInt(newPart[0]);
int currentNum = Integer.parseInt(currentPart[0]);
if (newNum > currentNum) {
return true;
} else if (newNum < currentNum) {
return false;
}
} catch (NumberFormatException e) {
// handle error
}
}
return false;
}
}
@@ -1,191 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public interface AdventureManager {
/**
* Strip all the tags from text
*
* @param text text
* @return stripped
*/
String stripTags(String text);
/**
* Get component from text
*
* @param text text
* @return component
*/
Component getComponentFromMiniMessage(String text);
/**
* Send a message to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessage(CommandSender sender, String msg);
/**
* Send a message with prefix to a command sender
*
* @param sender sender
* @param msg message
*/
void sendMessageWithPrefix(CommandSender sender, String msg);
/**
* Send a message to console
*
* @param msg message
*/
void sendConsoleMessage(String msg);
/**
* Send a message to a player
*
* @param player player
* @param msg message
*/
void sendPlayerMessage(Player player, String msg);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, String title, String subtitle, int in, int duration, int out);
/**
* Send a title
*
* @param player player
* @param title title
* @param subtitle subtitle
* @param in in (ms)
* @param duration duration (ms)
* @param out out (ms)
*/
void sendTitle(Player player, Component title, Component subtitle, int in, int duration, int out);
/**
* Send an actionbar
*
* @param player player
* @param msg msg
*/
void sendActionbar(Player player, String msg);
/**
* Send an actionbar
*
* @param player player
* @param component component
*/
void sendActionbar(Player player, Component component);
/**
* Play a sound to a player
*
* @param player player
* @param source sound source
* @param key sound key
* @param volume volume
* @param pitch pitch
*/
void sendSound(Player player, Sound.Source source, Key key, float volume, float pitch);
/**
* Play a sound to a player
*
* @param player player
* @param sound sound
*/
void sendSound(Player player, Sound sound);
/**
* Replace legacy color codes to MiniMessage format
*
* @param legacy legacy text
* @return MiniMessage format text
*/
String legacyToMiniMessage(String legacy);
/**
* If a char is legacy color code
*
* @param c char
* @return is legacy color
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isColorCode(char c);
/**
* Convert a color into decimal
*
* @param color color
* @return decimal
*/
int colorToDecimal(ChatColor color);
/**
* Get legacy format text
*
* @param component component
* @return legacy format text
*/
String componentToLegacy(Component component);
/**
* Get json by component
*
* @param component component
* @return json
*/
String componentToJson(Component component);
/**
* Get MiniMessage format text from component
*
* @param component component
* @return text
*/
String getMiniMessageFormat(Component component);
/**
* Get IChatComponent from Json
*
* @param json json
* @return component
*/
Object getIChatComponent(String json);
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface BackGroundManager {
/**
* Get a background's config by key
*
* @param key key
* @return background
*/
@Nullable
BackGround getBackGround(@NotNull String key);
/**
* Get all the backgrounds
*
* @return backgrounds
*/
Collection<BackGround> getBackGrounds();
/**
* Register a background into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param backGround background
* @return success or not
*/
boolean registerBackGround(@NotNull String key, @NotNull BackGround backGround);
/**
* Unregister a background by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterBackGround(@NotNull String key);
}
@@ -1,135 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.bubble.Bubble;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public interface BubbleManager {
/**
* Register a bubble into map
*
* @param key key
* @param bubble bubble
* @return success or not
*/
boolean registerBubble(String key, Bubble bubble);
/**
* Unregister a bubble from map
*
* @param key key
* @return success or not
*/
boolean unregisterBubble(String key);
/**
* Get a bubble from map
*
* @param bubble key
* @return bubble
*/
@Nullable Bubble getBubble(String bubble);
/**
* If a player has a certain bubble
*
* @param player player
* @param bubble key
* @return
*/
boolean hasBubble(Player player, String bubble);
/**
* Get a list of the bubbles that a player has
*
* @param player player
* @return bubbles' keys
*/
List<String> getAvailableBubbles(Player player);
/**
* Get a list of the bubbles' display names that a player has
*
* @param player player
* @return bubbles' display names
*/
List<String> getAvailableBubblesDisplayNames(Player player);
/**
* Get blacklist chat channels
*
* @return channels
*/
String[] getBlacklistChannels();
/**
* Get all the bubbles
*
* @return bubbles
*/
Collection<Bubble> getBubbles();
/**
* Whether a bubble exists
*/
boolean containsBubble(String key);
/**
* Equip a bubble for a player
*
* @param player player
* @param bubble bubble
* @return success or not
*/
boolean equipBubble(Player player, String bubble);
/**
* Unequip a bubble for a player
*
* @param player player
*/
void unEquipBubble(Player player);
/**
* Get the default bubble key
*
* @return bubble key
*/
String getDefaultBubble();
/**
* Get all the bubbles' keys
*
* @return keys
*/
Collection<String> getBubbleKeys();
/**
* Trigger chat
*
* @param player player
* @param text text
*/
void onChat(Player player, String text);
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface ImageManager {
/**
* Get an image by key
*
* @param key key
* @return image
*/
@Nullable
ConfiguredChar getImage(@NotNull String key);
/**
* Get all the images
*
* @return images
*/
Collection<ConfiguredChar> getImages();
/**
* Register am image into the plugin
* This will fail if there already exists one with the same key
*
* @param key key
* @param configuredChar image
* @return success or not
*/
boolean registerImage(@NotNull String key, @NotNull ConfiguredChar configuredChar);
/**
* Unregister an image by key
* This will fail if the key doesn't exist
*
* @param key key
* @return success or not
*/
boolean unregisterImage(@NotNull String key);
}
@@ -1,311 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.nameplate.CachedNameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.Nameplate;
import net.momirealms.customnameplates.api.mechanic.nameplate.TagMode;
import net.momirealms.customnameplates.api.mechanic.tag.NameplatePlayer;
import net.momirealms.customnameplates.common.team.TeamColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
public interface NameplateManager {
/**
* Get the default nameplate
*/
@NotNull
String getDefaultNameplate();
/**
* Put an entity's ID to map
* This map is used for quickly getting the entity instance
* Removal from the map is necessary when the entity is invalid
* Otherwise it would cause memory leak
*
* @param entityID entityID
* @param entity entity
*/
boolean putEntityIDToMap(int entityID, @NotNull Entity entity);
/**
* Remove the entity from map
*
* @param entityID entityID
* @return the removed entity
*/
@Nullable
Entity removeEntityIDFromMap(int entityID);
/**
* Nameplates are cached in memory so they would not be frequently updated
* The update rate is decided by "refresh-frequency" in nameplate.yml
*
* @param uuid player uuid
* @param nameplate cached nameplate
*/
boolean putCachedNameplateToMap(@NotNull UUID uuid, @NotNull CachedNameplate nameplate);
/**
* Remove CachedNameplate from map
*
* @param uuid player uuid
* @return removed CachedNameplate
*/
@Nullable
CachedNameplate removeCachedNameplateFromMap(@NotNull UUID uuid);
/**
* Get player by entityID from the cache
*
* @param id entityID
* @return player
*/
@Nullable
Player getPlayerByEntityID(int id);
/**
* Get entity by entityID from the cache
*
* @param id entityID
* @return entity
*/
@Nullable
Entity getEntityByEntityID(int id);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(@NotNull Player player);
/**
* Update a player's cached nameplate
* The nameplate is affected by "prefix" and "suffix" option
*
* @param player player
* @return if the nameplate is updated
*/
boolean updateCachedNameplate(@NotNull Player player, @Nullable Nameplate nameplate);
/**
* This should not be null when player's data is loaded (async process)
*
* @param player player
* @return cached nameplate
*/
@Nullable
CachedNameplate getCacheNameplate(@NotNull Player player);
/**
* Create a name tag for a player, the tag type is decided by the mode in nameplate.yml
* If mode is DISABLE, this method would return null
* The tag would be put into map automatically and you can get it by getNameplatePlayer(uuid)
*
* @param player player
*/
@Nullable
NameplatePlayer createNameTag(@NotNull Player player);
/**
* Put a nameplater player to map
*
* @param player player
*/
void putNameplatePlayerToMap(@NotNull NameplatePlayer player);
/**
* Get a nameplate player from map
*
* @param uuid uuid
* @return nameplate player
*/
@Nullable
NameplatePlayer getNameplatePlayer(@NotNull UUID uuid);
/**
* Remove nameplate player from map
*
* @param uuid uuid
* @return removed nameplate player
*/
@Nullable
NameplatePlayer removeNameplatePlayerFromMap(@NotNull UUID uuid);
/**
* Get the nameplate's prefix with text tags
*
* @param player player
* @return prefix with text tags
*/
@NotNull
String getNameplatePrefix(@NotNull Player player);
/**
* Get the nameplate's suffix with text tags
*
* @param player player
* @return suffix with text tags
*/
@NotNull
String getNameplateSuffix(@NotNull Player player);
/**
* Get the full nameplate tag
*
* @param player player
* @return nameplate tag
*/
@NotNull
String getFullNameTag(@NotNull Player player);
/**
* Register a custom nameplate into map
*
* @param key key
* @param nameplate nameplate
* @return success or not
*/
boolean registerNameplate(@NotNull String key, @NotNull Nameplate nameplate);
/**
* Unregister a nameplate from map
*
* @param key key
* @return success or not
*/
boolean unregisterNameplate(@NotNull String key);
/**
* Equip a nameplate for a player
*
* @param player player
* @param nameplateKey key
* @param temp whether save to storage
* @return success or not
*/
boolean equipNameplate(@NotNull Player player, @NotNull String nameplateKey, boolean temp);
/**
* Remove a nameplate for a player
*
* @param player player
* @param temp whether save to storage
*/
void unEquipNameplate(Player player, boolean temp);
/**
* Is team managed on proxy side
*/
boolean isProxyMode();
/**
* Get preview duration
*/
int getPreviewDuration();
/**
* Get the tag mode
*/
@NotNull
TagMode getTagMode();
/**
* Get a nameplate by key
*
* @param key key
* @return nameplate
*/
@NotNull
Nameplate getNameplate(@NotNull String key);
/**
* Get all the nameplates
*
* @return nameplates
*/
@NotNull
Collection<Nameplate> getNameplates();
/**
* Get all the nameplates' keys
*
* @return keys
*/
@NotNull
Collection<String> getNameplateKeys();
/**
* Whether a nameplate key exists
*/
boolean containsNameplate(@NotNull String key);
/**
* Get all the nameplates that the player has
*
* @param player player
* @return nameplates' keys
*/
@NotNull
List<String> getAvailableNameplates(@NotNull Player player);
/**
* If player has permission for a certain nameplate
*/
boolean hasNameplate(@NotNull Player player, @NotNull String nameplate);
/**
* Get all the nameplates' display names that the player has
*
* @param player player
* @return nameplates' display names
*/
@NotNull
List<String> getAvailableNameplateDisplayNames(@NotNull Player player);
/**
* Get the nameplate's team color
*
* @param player player
* @return team color
*/
@NotNull
TeamColor getTeamColor(@NotNull Player player);
/**
* Get team tag manager
*/
@NotNull
TeamTagManager getTeamTagManager();
/**
* Get unlimited tag manager
*/
@NotNull
UnlimitedTagManager getUnlimitedTagManager();
}
@@ -1,148 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.placeholder.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public interface PlaceholderManager {
/**
* Detect all the placeholders
*
* @param text text
* @return placeholder
*/
@NotNull
List<String> detectPlaceholders(String text);
/**
* Get a static text instance
*
* @param key key
* @return static text
*/
@Nullable
StaticText getStaticText(String key);
/**
* Get all the static texts
*
* @return static texts
*/
Collection<StaticText> getStaticTexts();
/**
* Get a switch text instance
*
* @param key key
* @return switch text
*/
@Nullable
SwitchText getSwitchText(String key);
/**
* Get all the switch texts
*
* @return switch texts
*/
Collection<SwitchText> getSwitchTexts();
/**
* Get a descent text instance
*
* @param key key
* @return descent text
*/
@Nullable
DescentText getDescentText(String key);
/**
* Get all the descent texts
*
* @return descent texts
*/
Collection<DescentText> getDescentTexts();
/**
* Get a conditional text
*
* @param key key
* @return conditional text
*/
@Nullable
ConditionalText getConditionalText(String key);
/**
* Get all the conditional texts
*
* @return conditional texts
*/
Collection<ConditionalText> getConditionalTexts();
/**
* Get a nameplate text
*
* @param key key
* @return nameplate text
*/
@Nullable
NameplateText getNameplateText(String key);
/**
* Get all the nameplate texts
*
* @return nameplate texts
*/
Collection<NameplateText> getNameplateTexts();
/**
* Get a background text
*
* @param key key
* @return background text
*/
@Nullable
BackGroundText getBackGroundText(String key);
/**
* Get all the background texts
*
* @return background texts
*/
Collection<BackGroundText> getBackGroundTexts();
/**
* Get a vanilla hud
*
* @param key key
* @return vanilla hud
*/
VanillaHud getVanillaHud(String key);
/**
* Get all the vanilla huds
*
* @return vanilla huds
*/
Collection<VanillaHud> getVanillaHuds();
}
@@ -1,104 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.api.requirement.RequirementFactory;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface RequirementManager {
/**
* Registers a custom requirement type with its corresponding factory.
*
* @param type The type identifier of the requirement.
* @param requirementFactory The factory responsible for creating instances of the requirement.
* @return True if registration was successful, false if the type is already registered.
*/
boolean registerRequirement(String type, RequirementFactory requirementFactory);
/**
* Unregisters a custom requirement type.
*
* @param type The type identifier of the requirement to unregister.
* @return True if unregistration was successful, false if the type is not registered.
*/
boolean unregisterRequirement(String type);
/**
* Retrieves an array of requirements based on a configuration section.
*
* @param section The configuration section containing requirement definitions.
* @return An array of Requirement objects based on the configuration section
*/
@Nullable Requirement[] getRequirements(ConfigurationSection section);
/**
* Retrieves a Requirement object based on a configuration section and advanced flag.
* <p>
* requirement_1: <- section
* type: xxx
* value: xxx
*
* @param section The configuration section containing requirement definitions.
* @return A Requirement object based on the configuration section, or an EmptyRequirement if the section is null or invalid.
*/
@NotNull Requirement getRequirement(ConfigurationSection section);
/**
* Gets a requirement based on the provided type and value.
* If a valid RequirementFactory is found for the type, it is used to create the requirement.
* If no factory is found, a warning is logged, and an empty requirement instance is returned.
* <p>
* world: <- type
* - world <- value
*
* @param type The type representing the requirement type.
* @param value The value associated with the requirement.
* @return A Requirement instance based on the type and value, or an EmptyRequirement if the type is invalid.
*/
@NotNull Requirement getRequirement(String type, Object value);
/**
* Retrieves a RequirementFactory based on the specified requirement type.
*
* @param type The requirement type for which to retrieve a factory.
* @return A RequirementFactory for the specified type, or null if no factory is found.
*/
@Nullable RequirementFactory getRequirementFactory(String type);
/**
* Checks if an array of requirements is met for a given condition.
*
* @param condition The Condition object to check against the requirements.
* @param requirements An array of Requirement instances to be evaluated.
* @return True if all requirements are met, false otherwise. Returns true if the requirements array is null.
*/
static boolean isRequirementMet(Condition condition, Requirement... requirements) {
if (requirements == null) return true;
for (Requirement requirement : requirements) {
if (!requirement.isConditionMet(condition)) {
return false;
}
}
return true;
}
}
@@ -1,108 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.data.DataStorageInterface;
import net.momirealms.customnameplates.api.data.OnlineUser;
import net.momirealms.customnameplates.api.data.PlayerData;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface StorageManager {
/**
* Get online users
*
* @return online users
*/
Collection<OnlineUser> getOnlineUsers();
/**
* Get a player's data by uuid
* The player can be an offline one
*
* @param uuid uuid
* @return player data
*/
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid);
/**
* Save online players' data
*
* @param uuid uuid
* @return success or not
*/
CompletableFuture<Boolean> saveOnlinePlayerData(UUID uuid);
/**
* Save specified data
*
* @param uuid uuid
* @param playerData playerData
* @return success or not
*/
CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData);
/**
* Get an online user by uuid
*
* @param uuid uuid
* @return online user
*/
Optional<OnlineUser> getOnlineUser(UUID uuid);
/**
* Get player data from json
*
* @param json json
* @return data
*/
@NotNull
PlayerData fromJson(String json);
/**
* Get player data from bytes
*
* @param data data
* @return data
*/
PlayerData fromBytes(byte[] data);
/**
* Convert player data to bytes
*
* @param playerData playerData
* @return bytes
*/
byte[] toBytes(PlayerData playerData);
/**
* Convert player data to json
*
* @param playerData playerData
* @return json
*/
@NotNull
String toJson(@NotNull PlayerData playerData);
DataStorageInterface getDataSource();
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.common.team.TeamColor;
import net.momirealms.customnameplates.common.team.TeamTagVisibility;
import org.bukkit.entity.Player;
public interface TeamManager {
/**
* Create team for a player
*
* @param player player
*/
void createTeam(Player player);
/**
* Remove a team for a player
*
* @param player player
*/
void removeTeam(Player player);
/**
* Update a player's team for a viewer
*/
void updateTeam(Player owner, Player viewer, String prefix, String suffix, TeamColor color, TeamTagVisibility visibility);
/**
* Get the team player in
*
* @param player player
* @param viewer viewer
* @return team name
*/
String getTeamName(Player player, Player viewer);
}
@@ -1,63 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.tag.unlimited.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public interface UnlimitedTagManager {
/**
* Create a named entity (ArmorStand) for an entity
* To apply the changes, you should add it to the EntityTagEntity
*
* @param entity entity
* @param setting setting
* @return named entity
*/
@NotNull StaticTextEntity createNamedEntity(EntityTagEntity entity, StaticTextTagSetting setting);
/**
* Create a named entity (ArmorStand) for a player
* To apply the changes, you should add it the named player instance
*
* @param player player
* @param setting setting
* @return named entity
*/
@NotNull
DynamicTextEntity createNamedEntity(EntityTagPlayer player, DynamicTextTagSetting setting);
/**
* Create or get a tag instance
*
* @param entity entity
* @return entity tag instance
*/
EntityTagEntity createOrGetTagForEntity(Entity entity);
/**
* Create or get a tag instance
*
* @param player player
* @return entity tag instance
*/
EntityTagPlayer createOrGetTagForPlayer(Player player);
}
@@ -1,76 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletionStage;
public interface VersionManager {
/**
* Is folia scheduler implemented
*/
boolean isFolia();
/**
* Get bukkit version
*
* @return version
*/
String getServerVersion();
/**
* Check update
*
* @return return true if plugin needs update
*/
CompletionStage<Boolean> checkUpdate();
/**
* Get plugin version
*
* @return version
*/
@NotNull
String getPluginVersion();
/**
* Is the plugin the latest version
*
* @return latest or not
*/
boolean isLatest();
/**
* Get pack format
*
* @return pack format
*/
int getPackFormat();
boolean isVersionNewerThan1_19();
boolean isVersionNewerThan1_19_R2();
boolean isVersionNewerThan1_19_R3();
boolean isVersionNewerThan1_20();
boolean isVersionNewerThan1_20_R2();
}
@@ -1,61 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.manager;
import net.momirealms.customnameplates.api.mechanic.font.FontData;
import net.momirealms.customnameplates.common.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface WidthManager {
/**
* Register a font data into the plugin
* If there already exists one, it would fail
*
* @param key key
* @param fontData data
* @return success or not
*/
boolean registerFontData(@NotNull Key key, @NotNull FontData fontData);
/**
* Unregister a font data from map
*
* @param key key
* @return success or not
*/
boolean unregisterFontData(@NotNull Key key);
/**
* Get font data by key
*
* @param key key
* @return font data
*/
@Nullable
FontData getFontData(@NotNull Key key);
/**
* Get text's width (MiniMessage format text)
*
* @param textWithTags text
* @return width
*/
int getTextWidth(@NotNull String textWithTags);
}
@@ -1,230 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.background;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
public class BackGround {
private ConfiguredChar left, offset_1, offset_2, offset_4, offset_8, offset_16, offset_32, offset_64, offset_128, right;
private int leftMargin, rightMargin;
private BackGround() {
}
public BackGround(
ConfiguredChar left,
ConfiguredChar offset_1,
ConfiguredChar offset_2,
ConfiguredChar offset_4,
ConfiguredChar offset_8,
ConfiguredChar offset_16,
ConfiguredChar offset_32,
ConfiguredChar offset_64,
ConfiguredChar offset_128,
ConfiguredChar right,
int leftMargin,
int rightMargin,
boolean removeShadow
) {
this.left = left;
this.offset_1 = offset_1;
this.offset_2 = offset_2;
this.offset_4 = offset_4;
this.offset_8 = offset_8;
this.offset_16 = offset_16;
this.offset_32 = offset_32;
this.offset_64 = offset_64;
this.offset_128 = offset_128;
this.right = right;
this.leftMargin = leftMargin;
this.rightMargin = rightMargin;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getOffset_1() {
return offset_1;
}
public ConfiguredChar getOffset_2() {
return offset_2;
}
public ConfiguredChar getOffset_4() {
return offset_4;
}
public ConfiguredChar getOffset_8() {
return offset_8;
}
public ConfiguredChar getOffset_16() {
return offset_16;
}
public ConfiguredChar getOffset_32() {
return offset_32;
}
public ConfiguredChar getOffset_64() {
return offset_64;
}
public ConfiguredChar getOffset_128() {
return offset_128;
}
public ConfiguredChar getRight() {
return right;
}
public static Builder builder() {
return new Builder();
}
public String getBackGroundImage(int n) {
String offset = OffsetFont.getShortestNegChars(n + rightMargin + 2);
n = n + leftMargin + rightMargin + 2;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(left.getCharacter());
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_8.getCharacter());
n -= 8;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_4.getCharacter());
n -= 4;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(offset_1.getCharacter());
}
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(offset);
return stringBuilder.toString();
}
public static class Builder {
private final BackGround backGround;
public static Builder of() {
return new Builder();
}
public Builder() {
this.backGround = new BackGround();
}
public Builder left(ConfiguredChar configuredChar) {
backGround.left = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
backGround.right = configuredChar;
return this;
}
public Builder offset_1(ConfiguredChar configuredChar) {
backGround.offset_1 = configuredChar;
return this;
}
public Builder offset_2(ConfiguredChar configuredChar) {
backGround.offset_2 = configuredChar;
return this;
}
public Builder offset_4(ConfiguredChar configuredChar) {
backGround.offset_4 = configuredChar;
return this;
}
public Builder offset_8(ConfiguredChar configuredChar) {
backGround.offset_8 = configuredChar;
return this;
}
public Builder offset_16(ConfiguredChar configuredChar) {
backGround.offset_16 = configuredChar;
return this;
}
public Builder offset_32(ConfiguredChar configuredChar) {
backGround.offset_32 = configuredChar;
return this;
}
public Builder offset_64(ConfiguredChar configuredChar) {
backGround.offset_64 = configuredChar;
return this;
}
public Builder offset_128(ConfiguredChar configuredChar) {
backGround.offset_128 = configuredChar;
return this;
}
public Builder leftMargin(int margin) {
backGround.leftMargin = margin;
return this;
}
public Builder rightMargin(int margin) {
backGround.rightMargin = margin;
return this;
}
public BackGround build() {
return backGround;
}
}
}
@@ -1,172 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.bubble;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
public class Bubble {
private String startFormat, endFormat;
private String displayName;
private ConfiguredChar left, middle, right, tail;
private Bubble() {
}
public Bubble(String startFormat, String endFormat, String displayName, ConfiguredChar left, ConfiguredChar middle, ConfiguredChar right, ConfiguredChar tail) {
this.startFormat = startFormat;
this.endFormat = endFormat;
this.displayName = displayName;
this.left = left;
this.middle = middle;
this.right = right;
this.tail = tail;
}
public String getPrefixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getPrefix(textWidth));
}
public String getPrefix(int textWidth) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<#FEFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + left.getWidth() + 1));
stringBuilder.append(left.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
int mid_amount;
if (textWidth - 1 <= tail.getWidth()) {
mid_amount = -1;
} else {
mid_amount = (textWidth - 1 - tail.getWidth()) / (middle.getWidth());
}
if (mid_amount == -1) {
stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
} else if (mid_amount == 0) {
stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth - 1 - tail.getWidth()) % middle.getWidth()));
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
} else {
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
for (int i = 0; i < mid_amount; i++) {
if (i == mid_amount / 2) stringBuilder.append("<#FDFEFE>").append(tail.getCharacter()).append("</#FDFEFE>").append(OffsetFont.NEG_1.getCharacter());
else stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth - 1 - tail.getWidth()) % middle.getWidth()));
stringBuilder.append(middle.getCharacter()).append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append("<#FDFEFE>");
stringBuilder.append(right.getCharacter());
stringBuilder.append("</#FDFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + right.getWidth()));
stringBuilder.append("</#FEFEFE>");
return stringBuilder.toString();
}
public String getSuffixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getSuffix(textWidth));
}
public String getSuffix(int textWidth) {
return OffsetFont.getShortestNegChars(textWidth + textWidth % 2 + 1);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Bubble bubble;
public static Builder of() {
return new Builder();
}
public Builder() {
this.bubble = new Bubble();
}
public Builder startFormat(String startFormat) {
this.bubble.startFormat = startFormat;
return this;
}
public Builder endFormat(String endFormat) {
this.bubble.endFormat = endFormat;
return this;
}
public Builder left(ConfiguredChar left) {
this.bubble.left = left;
return this;
}
public Builder displayName(String displayName) {
this.bubble.displayName = displayName;
return this;
}
public Builder middle(ConfiguredChar middle) {
this.bubble.middle = middle;
return this;
}
public Builder right(ConfiguredChar right) {
this.bubble.right = right;
return this;
}
public Builder tail(ConfiguredChar tail) {
this.bubble.tail = tail;
return this;
}
public Bubble build() {
return bubble;
}
}
public String getStartFormat() {
return startFormat;
}
public String getEndFormat() {
return endFormat;
}
public String getDisplayName() {
return displayName;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getMiddle() {
return middle;
}
public ConfiguredChar getRight() {
return right;
}
public ConfiguredChar getTail() {
return tail;
}
}
@@ -1,124 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.character;
import net.momirealms.customnameplates.api.util.LogUtils;
public class ConfiguredChar {
private char character;
private String pngFile;
private int height;
private int width;
private int ascent;
private ConfiguredChar() {
}
public ConfiguredChar(char character, String pngFile, int height, int width, int ascent) {
this.character = character;
this.pngFile = pngFile;
this.height = height;
this.width = width;
this.ascent = ascent;
}
public char getCharacter() {
return character;
}
public static Builder builder() {
return new Builder();
}
public String getPngFile() {
return pngFile;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getAscent() {
return ascent;
}
public String getFile() {
return pngFile + ".png";
}
public static class Builder {
private final ConfiguredChar configuredChar;
public static Builder of() {
return new Builder();
}
public Builder() {
this.configuredChar = new ConfiguredChar();
}
public Builder character(char character) {
configuredChar.character = character;
return this;
}
public Builder png(String png) {
configuredChar.pngFile = png;
return this;
}
public Builder height(int height) {
configuredChar.height = height;
return this;
}
public Builder ascent(int ascent) {
configuredChar.ascent = ascent;
if (ascent >= configuredChar.height) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Ascent " + ascent + " should be no higher than Height " + configuredChar.height);
}
return this;
}
public Builder descent(int descent) {
if (descent < 0) {
LogUtils.warn("Invalid config for " + configuredChar.pngFile);
LogUtils.warn("Descent " + descent + " should be no lower than 0");
}
configuredChar.ascent = configuredChar.height - descent;
return this;
}
public Builder width(int width) {
configuredChar.width = width;
return this;
}
public ConfiguredChar build() {
return configuredChar;
}
}
}
@@ -1,78 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.font;
import java.util.HashMap;
public class FontData {
private final HashMap<Integer, Integer> widthData;
private final int defaultWidth;
public FontData(int defaultWidth) {
this.widthData = new HashMap<>();
this.defaultWidth = defaultWidth;
}
/**
* Register a char's width
*
* @param codePoint code point
* @param width width
*/
public void registerCharWidth(int codePoint, int width) {
widthData.put(codePoint, width);
}
/**
* Get a character's width
*
* @param codePoint code point
* @return width
*/
public int getWidth(int codePoint) {
return widthData.getOrDefault(codePoint, defaultWidth);
}
/**
* Get the data map
*
* @return map
*/
public HashMap<Integer, Integer> getWidthData() {
return widthData;
}
/**
* Override the data with another one
*
* @param fontData font data
*/
public void overrideWith(FontData fontData) {
if (fontData == null) return;
widthData.putAll(fontData.getWidthData());
}
@Override
public String toString() {
return "FontData{" +
"widthData=" + widthData +
", defaultWidth=" + defaultWidth +
'}';
}
}
@@ -1,198 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.font;
public enum OffsetFont {
NEG_1('\uf801', -1, -3),
NEG_2('\uf802', -2, -4),
NEG_3('\uf803', -3, -5),
NEG_4('\uf804', -4, -6),
NEG_5('\uf805', -5, -7),
NEG_6('\uf806', -6, -8),
NEG_7('\uf807', -7, -9),
NEG_8('\uf808', -8, -10),
NEG_16('\uf809', -16, -18),
NEG_32('\uf80a', -32, -34),
NEG_64('\uf80b', -64, -66),
NEG_128('\uf80c', -128, -130),
POS_1('\uf811', 1, -1),
POS_2('\uf812', 2, 1),
POS_3('\uf813', 3, 2),
POS_4('\uf814', 4, 3),
POS_5('\uf815', 5, 4),
POS_6('\uf816', 6, 5),
POS_7('\uf817', 7, 6),
POS_8('\uf818', 8, 7),
POS_16('\uf819', 16, 15),
POS_32('\uf81a', 32, 31),
POS_64('\uf81b', 64, 63),
POS_128('\uf81c', 128, 127);
private final char character;
private final int space;
private final int height;
OffsetFont(char character, int space, int height) {
this.character = character;
this.space = space;
this.height = height;
}
public char getCharacter() {
return this.character;
}
public int getSpace() {
return this.space;
}
public int getHeight() {
return this.height;
}
/**
* Get offset characters
*
* @param offset offset
* @return chars
*/
public static String getOffsetChars(int offset) {
if (offset >= 0) {
return getShortestPosChars(offset);
} else {
return getShortestNegChars(-offset);
}
}
/**
* get negative characters
*
* @param n n > 0
* @return chars
*/
public static String getShortestNegChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.NEG_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.NEG_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.NEG_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.NEG_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.NEG_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.NEG_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.NEG_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.NEG_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.NEG_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.NEG_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.NEG_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
return stringBuilder.toString();
}
/**
* get positive characters
*
* @param n n > 0
* @return chars
*/
public static String getShortestPosChars(int n) {
StringBuilder stringBuilder = new StringBuilder();
while (n >= 128) {
stringBuilder.append(OffsetFont.POS_128.getCharacter());
n -= 128;
}
if (n - 64 >= 0) {
stringBuilder.append(OffsetFont.POS_64.getCharacter());
n -= 64;
}
if (n - 32 >= 0) {
stringBuilder.append(OffsetFont.POS_32.getCharacter());
n -= 32;
}
if (n - 16 >= 0) {
stringBuilder.append(OffsetFont.POS_16.getCharacter());
n -= 16;
}
if (n - 8 >= 0) {
stringBuilder.append(OffsetFont.POS_8.getCharacter());
n -= 8;
}
if (n - 7 >= 0) {
stringBuilder.append(OffsetFont.POS_7.getCharacter());
n -= 7;
}
if (n - 6 >= 0) {
stringBuilder.append(OffsetFont.POS_6.getCharacter());
n -= 6;
}
if (n - 5 >= 0) {
stringBuilder.append(OffsetFont.POS_5.getCharacter());
n -= 5;
}
if (n - 4 >= 0) {
stringBuilder.append(OffsetFont.POS_4.getCharacter());
n -= 4;
}
if (n - 3 >= 0) {
stringBuilder.append(OffsetFont.POS_3.getCharacter());
n -= 3;
}
if (n - 2 >= 0) {
stringBuilder.append(OffsetFont.POS_2.getCharacter());
n -= 2;
}
if (n - 1 >= 0) {
stringBuilder.append(OffsetFont.POS_1.getCharacter());
}
return stringBuilder.toString();
}
}
@@ -1,132 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.misc;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.CustomNameplatesPlugin;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class ViewerText {
private final Player owner;
private String processedText;
private final ClaimedText[] placeholders;
private final ConcurrentHashMap<UUID, String> valueMap;
public ViewerText(Player owner, String rawText) {
this.processedText = rawText;
this.valueMap = new ConcurrentHashMap<>();
this.owner = owner;
List<String> placeholders = CustomNameplatesPlugin.get().getPlaceholderManager().detectPlaceholders(rawText);
this.placeholders = new ClaimedText[placeholders.size()];
int i = 0;
for (String placeholder : placeholders) {
processedText = processedText.replace(placeholder, "%s");
if (placeholder.startsWith("%viewer_")) {
this.placeholders[i] = new ClaimedText(null, "%" + placeholder.substring("%viewer_".length()));
} else {
this.placeholders[i] = new ClaimedText(owner, placeholder);
}
i++;
}
}
public void updateForOwner() {
for (ClaimedText text : placeholders) {
text.update();
}
}
public boolean updateForViewer(Player viewer) {
String string;
if ("%s".equals(processedText)) {
string = placeholders[0].getValue(viewer);
} else if (placeholders.length != 0) {
Object[] values = new String[placeholders.length];
for (int i = 0; i < placeholders.length; i++) {
values[i] = placeholders[i].getValue(viewer);
}
string = String.format(processedText, values);
} else {
string = processedText;
}
var uuid = viewer.getUniqueId();
if (!valueMap.containsKey(uuid)) {
valueMap.put(uuid, string);
return true;
}
String previousValue = valueMap.get(uuid);
if (!previousValue.equals(string)) {
valueMap.put(uuid, string);
return true;
}
return false;
}
public void removeViewer(Player viewer) {
valueMap.remove(viewer.getUniqueId());
}
public void clear() {
valueMap.clear();
}
public String getProcessedText() {
return processedText;
}
public String getLatestValue(Player viewer) {
return valueMap.get(viewer.getUniqueId());
}
public Entity getOwner() {
return owner;
}
public static class ClaimedText {
private final String placeholder;
private final Player owner;
private String latestValue;
public ClaimedText(Player owner, String placeholder) {
this.placeholder = placeholder;
this.owner = owner;
this.latestValue = null;
this.update();
}
public void update() {
if (owner == null) return;
this.latestValue = PlaceholderAPI.setPlaceholders(owner, placeholder);
}
public String getValue(Player viewer) {
return Objects.requireNonNullElseGet(
latestValue,
() -> PlaceholderAPI.setPlaceholders(owner == null ? viewer : owner, placeholder)
);
}
}
}
@@ -1,87 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.nameplate;
import net.momirealms.customnameplates.common.team.TeamColor;
public class CachedNameplate {
private TeamColor teamColor;
private String tagPrefix;
private String tagSuffix;
private String namePrefix;
private String nameSuffix;
private String playerName;
public CachedNameplate() {
this.tagPrefix = "";
this.tagSuffix = "";
this.namePrefix = "";
this.nameSuffix = "";
this.playerName = "";
this.teamColor = TeamColor.WHITE;
}
public String getTagPrefix() {
return tagPrefix;
}
public void setTagPrefix(String prefix) {
this.tagPrefix = prefix;
}
public String getTagSuffix() {
return tagSuffix;
}
public void setTagSuffix(String suffix) {
this.tagSuffix = suffix;
}
public void setNamePrefix(String namePrefix) {
this.namePrefix = namePrefix;
}
public void setNameSuffix(String nameSuffix) {
this.nameSuffix = nameSuffix;
}
public String getNamePrefix() {
return namePrefix;
}
public String getNameSuffix() {
return nameSuffix;
}
public TeamColor getTeamColor() {
return teamColor;
}
public void setTeamColor(TeamColor teamColor) {
this.teamColor = teamColor;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
}
@@ -1,187 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.nameplate;
import net.momirealms.customnameplates.api.mechanic.character.ConfiguredChar;
import net.momirealms.customnameplates.api.mechanic.font.OffsetFont;
import net.momirealms.customnameplates.api.util.FontUtils;
import net.momirealms.customnameplates.common.team.TeamColor;
public class Nameplate {
private String displayName;
private TeamColor teamColor;
private String namePrefix;
private String nameSuffix;
private ConfiguredChar left;
private ConfiguredChar middle;
private ConfiguredChar right;
private Nameplate() {
}
public Nameplate(
String displayName,
TeamColor teamColor,
String namePrefix,
String nameSuffix,
ConfiguredChar left,
ConfiguredChar middle,
ConfiguredChar right
) {
this.displayName = displayName;
this.teamColor = teamColor;
this.left = left;
this.middle = middle;
this.right = right;
this.namePrefix = namePrefix;
this.nameSuffix = nameSuffix;
}
public String getDisplayName() {
return displayName;
}
public TeamColor getTeamColor() {
return teamColor;
}
public ConfiguredChar getLeft() {
return left;
}
public ConfiguredChar getMiddle() {
return middle;
}
public ConfiguredChar getRight() {
return right;
}
public String getNamePrefix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return namePrefix;
}
return "<" + teamColor.name() + ">";
}
public String getNameSuffix() {
if (teamColor == TeamColor.NONE) {
return "";
}
if (teamColor == TeamColor.CUSTOM) {
return nameSuffix;
}
return "</" + teamColor.name() + ">";
}
public static Builder builder() {
return new Builder();
}
public String getPrefixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getPrefix(textWidth));
}
public String getPrefix(int textWidth) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<#FEFEFE>");
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + left.getWidth() + 1));
stringBuilder.append(left.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
int mid_amount = (textWidth+2) / (middle.getWidth());
if (mid_amount != 0) {
for (int i = 0; i < mid_amount; i++) {
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
}
stringBuilder.append(OffsetFont.getShortestNegChars(middle.getWidth() - (textWidth+2) % middle.getWidth() + 1)); // +1
}
stringBuilder.append("</#FEFEFE>");
stringBuilder.append("<#FDFEFE>");
stringBuilder.append(middle.getCharacter());
stringBuilder.append(OffsetFont.NEG_1.getCharacter());
stringBuilder.append(right.getCharacter());
stringBuilder.append(OffsetFont.getShortestNegChars(textWidth + right.getWidth() + 1)); // -1;
stringBuilder.append("</#FDFEFE>");
return stringBuilder.toString();
}
public String getSuffixWithFont(int textWidth) {
return FontUtils.surroundNameplateFont(getSuffix(textWidth));
}
public String getSuffix(int textWidth) {
return OffsetFont.getShortestNegChars(textWidth + textWidth % 2 + 1);
}
public static class Builder {
private final Nameplate nameplate;
public Builder() {
this.nameplate = new Nameplate();
}
public static Builder of() {
return new Builder();
}
public Builder displayName(String display) {
nameplate.displayName = display;
return this;
}
public Builder teamColor(TeamColor teamColor) {
nameplate.teamColor = teamColor;
return this;
}
public Builder namePrefix(String namePrefix) {
nameplate.namePrefix = namePrefix;
return this;
}
public Builder nameSuffix(String nameSuffix) {
nameplate.nameSuffix = nameSuffix;
return this;
}
public Builder left(ConfiguredChar configuredChar) {
nameplate.left = configuredChar;
return this;
}
public Builder middle(ConfiguredChar configuredChar) {
nameplate.middle = configuredChar;
return this;
}
public Builder right(ConfiguredChar configuredChar) {
nameplate.right = configuredChar;
return this;
}
public Nameplate build() {
return nameplate;
}
}
}
@@ -1,91 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.mechanic.background.BackGround;
import net.momirealms.customnameplates.api.util.FontUtils;
import org.bukkit.OfflinePlayer;
public class BackGroundText {
private String text;
private BackGround backGround;
private boolean removeShadow;
private BackGroundText() {
}
public BackGroundText(String text, BackGround backGround, boolean removeShadow) {
this.text = text;
this.backGround = backGround;
this.removeShadow = removeShadow;
}
public String getText() {
return text;
}
public BackGround getBackGround() {
return backGround;
}
public String getValue(OfflinePlayer player) {
String parsed = PlaceholderAPI.setPlaceholders(player, text);
if (parsed.equals("")) return "";
int parsedWidth = FontUtils.getTextWidth(parsed);
String bg = FontUtils.surroundNameplateFont(backGround.getBackGroundImage(parsedWidth));
return (removeShadow ? "<#FFFEFD>" + bg + "</#FFFEFD>" : bg)+ parsed;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final BackGroundText text;
public Builder() {
this.text = new BackGroundText();
}
public static Builder of() {
return new Builder();
}
public Builder text(String value) {
text.text = value;
return this;
}
public Builder background(BackGround backGround) {
text.backGround = backGround;
return this;
}
public Builder removeShadow(boolean remove) {
text.removeShadow = remove;
return this;
}
public BackGroundText build() {
return text;
}
}
}
@@ -1,71 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.placeholder;
public class CachedText {
private long refreshInterval;
private String text;
private CachedText() {
}
public CachedText(long refreshInterval, String text) {
this.refreshInterval = refreshInterval;
this.text = text;
}
public long getRefreshInterval() {
return refreshInterval;
}
public String getText() {
return text;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final CachedText text;
public Builder() {
this.text = new CachedText();
}
public static Builder of() {
return new Builder();
}
public Builder refreshInterval(long time) {
this.text.refreshInterval = time;
return this;
}
public Builder text(String text) {
this.text.text = text;
return this;
}
public CachedText build() {
return text;
}
}
}
@@ -1,75 +0,0 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customnameplates.api.mechanic.placeholder;
import me.clip.placeholderapi.PlaceholderAPI;
import net.momirealms.customnameplates.api.manager.RequirementManager;
import net.momirealms.customnameplates.api.requirement.Condition;
import net.momirealms.customnameplates.api.requirement.Requirement;
import net.momirealms.customnameplates.common.Pair;
import org.bukkit.OfflinePlayer;
import java.util.List;
public class ConditionalText {
private List<Pair<String, Requirement[]>> textList;
private ConditionalText() {
}
public ConditionalText(List<Pair<String, Requirement[]>> textList) {
this.textList = textList;
}
public static Builder builder() {
return new Builder();
}
public String getValue(OfflinePlayer player) {
Condition condition = new Condition(player);
for (Pair<String, Requirement[]> pair : textList) {
if (RequirementManager.isRequirementMet(condition, pair.right())) {
return PlaceholderAPI.setPlaceholders(player, pair.left());
}
}
return "";
}
public static class Builder {
private final ConditionalText conditionalText;
public static Builder of() {
return new Builder();
}
public Builder() {
this.conditionalText = new ConditionalText();
}
public Builder textList(List<Pair<String, Requirement[]>> textList) {
conditionalText.textList = textList;
return this;
}
public ConditionalText build() {
return conditionalText;
}
}
}
Loaded 100 of 948 files, more files were not shown because too many files have changed in this diff. Show more