Compare commits

...
Sign in to create a new pull request.

297 commits

Author SHA1 Message Date
37e42fb169
feat: updated favorite item 2025-06-27 09:53:54 +02:00
03d66b1c69
feat: update i18n 2025-06-22 15:20:33 +02:00
c35a70712a
chore(build): update luckperms 2025-06-21 19:01:59 +02:00
e91d618dd6
feat: add notice concerning the api 2025-06-12 19:18:56 +02:00
1a169f7709
feat: add user-agent 2025-06-12 19:13:31 +02:00
7fe5985391
feat: display error on 403 2025-06-12 12:49:20 +02:00
bf1d360bd5
feat: add apparence to gui 2025-06-12 12:47:52 +02:00
02fd88d9c9
chore/fix: update adventure/i18n 2025-06-11 18:28:50 +02:00
7fac9d0279
feat(i18n/favorite): update lore 2025-06-08 22:39:46 +02:00
d8f183146b
feat(i18n/favorite): translate item 2025-06-08 22:32:06 +02:00
c6f37579a0
fix(gui/admin): player info item name 2025-06-08 13:31:04 +02:00
e8ac7619de
feat(gui/admin): remove unused item 2025-06-08 13:25:15 +02:00
520840da1f
feat(gui/admin): layout 2025-06-08 13:24:59 +02:00
66495db59b
refactor(gui): rename click 2025-06-08 13:19:58 +02:00
b85325fde5
feat(gui/favorites): remove/add items 2025-06-08 13:13:47 +02:00
8d394df1d6
refactor: move prompt package 2025-06-08 09:39:26 +02:00
666c45735d
fix(favorites): wrong values when item create 2025-06-08 09:16:39 +02:00
7cacb36fec
feat(storage): favorites 2025-06-08 09:11:45 +02:00
8c04009c66
fix: prevent NPE from invalid state of favorites field 2025-06-07 12:46:01 +02:00
0f4b239148
refactor: weird... 2025-06-07 12:33:15 +02:00
66c9313d0e
feat(wip): load favorites 2025-06-06 20:48:34 +02:00
814d7adea7
feat: add favorites item and gui 2025-06-06 19:48:43 +02:00
7eca066cf1
fix: add undisguise sound 2025-06-06 15:40:09 +02:00
1dbb199258
feat: update translation files 2025-06-06 15:10:51 +02:00
bcea10c9db
fix: data save bug 2025-05-18 22:15:34 +02:00
8e32264087
feat(cmd): added about sub-command 2025-05-17 15:38:31 +02:00
e18ecfde1a
refactor: suppress warnings concerning unstable api 2025-05-17 13:35:24 +02:00
278e44ad0d
fix: only support latest minecraft version 2025-05-17 13:33:27 +02:00
1216cfbdf5
refactor: simplify tag 2025-05-17 11:22:21 +02:00
2c7ee30ad2
feat: implemented conversations for name/skin change 2025-05-17 11:12:21 +02:00
b908e0562f
feat: specify if prompt is about name or skin change 2025-05-16 21:19:57 +02:00
1646488316
feat(wip/prompt): bro discovered conversations 2025-05-16 20:35:36 +02:00
63f2e7f699
feat: trying to circumvent AnvilGUI 2025-05-12 18:41:50 +02:00
d30f433527
feat: add chat prompt because nothing reliably works 2025-04-04 10:32:39 +02:00
1a792112cc
refactor: remove unused code 2025-04-04 09:27:57 +02:00
197f4f3259
feat(prompt): sign not working properly due to synchronization issues 2025-04-03 21:17:59 +02:00
dc36a0148e
refactor: fixed changelog 2025-04-03 09:49:12 +02:00
a709a9195f
feat: update changelog 2025-04-03 09:47:48 +02:00
76c8f734e7
refactor(appearance): remove old code 2025-04-03 09:34:04 +02:00
1ce7fbe3f0
feat: update function signature across codebase 2025-04-03 09:33:17 +02:00
875a04a850
feat: update paper plugin sender, fix protocollib classpath access 2025-04-02 18:23:19 +02:00
9adf5f34f5
refactor: update displayed latest minecraft version 2025-03-28 10:09:47 +01:00
c74532ce66
feat: add sign prompt 2025-03-28 09:46:26 +01:00
1edfbb9123
refactor: remove file dependencies 2025-03-26 19:34:25 +01:00
1a81c7c657
feat: split prompt from AnvilGUI dependency 2025-03-26 19:29:12 +01:00
11730d5234
fix: remove test language file 2025-03-20 20:37:34 +01:00
3cc2b4415d
refactor: cleanup leftovers from before the paperweight switch 2025-03-20 20:37:06 +01:00
4f9e334544
feat: make nicko work again partially 2025-03-20 20:35:24 +01:00
a996858ba9
feat: switch to paperweight and create plugin loader 2025-03-20 18:50:06 +01:00
ff892a7451
feat: papi expension 2024-11-26 09:03:46 +01:00
7ba8a26af6
fix: chat session no longer broken and item translated correctly 2024-11-25 20:49:24 +01:00
3d5ef0f020
fix: play sound at location 2024-11-21 12:43:06 +01:00
ea3fa9b52e
feat: removed deadlock from reset/update, updated items/translations 2024-11-20 20:22:47 +01:00
a1919caa2a
feat: removed Metrics, updated loc files, enabled skulls again in GUI 2024-11-16 18:10:57 +01:00
3440f1fad1
feat: internal packet sender is now functional 2024-11-14 20:11:13 +01:00
9b64ec18ba
fix: jackson relocating 2024-10-31 20:35:58 +01:00
f72d5c0948
feat: implemented NMS packet sender 2024-10-31 20:05:22 +01:00
fe33a003ea
feat: disabled the respawn packet 2024-10-31 17:52:30 +01:00
d804fb1207
feat: updated readme 2024-09-29 20:35:15 +02:00
77e8844eee
feat(changelog): updated the changelog to reflect upcoming changes 2024-09-29 20:33:52 +02:00
95a5e99038
refactor: doing a little cleaning of the test code 2024-09-29 20:32:11 +02:00
230acf439e
feat: we're not making progress chat :( 2024-09-29 20:31:07 +02:00
18afb84caa
feat: WE MAKING PROGRESS CHAT 2024-09-29 17:35:09 +02:00
144245fc5a
feat: remove test code 2024-08-29 16:41:27 +02:00
20af9e7328
feat(wrapper): trying to debug the issue 2024-08-29 16:02:57 +02:00
c99c31ba37
fix: messages not read with MiniMessage 2024-08-29 16:02:36 +02:00
0ef5766004
feat(language): reworked messages and formatting 2024-08-27 22:48:39 +02:00
5197fefdaf
feat(error): simplify error management regarding data-related operations 2024-08-27 18:56:55 +02:00
df988dbf87
fix(wrapper): 1.20 2024-08-26 22:39:39 +02:00
23f9424fa9
feat(wrapper): clean code for 1.20-1.20.4, untested 1.21 2024-08-26 22:39:04 +02:00
a98d5a75bd
feat(wrapper): only support 1.20/1.21 (not working for >1.20.2?) 2024-08-20 22:44:15 +02:00
d45ce65c3b
chore(deps): update deps 2024-08-13 18:24:53 +02:00
1133ac4052
style: update docs 2024-06-16 02:50:08 +02:00
40401a1652
feat: why is protocollib api so complicated 2024-06-16 02:49:46 +02:00
db8ddbd507
feat: trying to figure out 1.20.5/1.21 2024-06-16 02:07:46 +02:00
278c801de1
feat: tring to figure out 1.20.5-6/1.21 2024-06-14 23:38:21 +02:00
653c229b85
fix(build): typo 2024-06-14 23:01:13 +02:00
57ed194122
feat(deps): base on latest master ProtocolLib commit 2024-06-14 22:47:11 +02:00
34d1c5c7a0
chore(deps): update server deps 2024-06-08 13:12:48 +02:00
a86acd0d9d
chore(deps): updating dependencies 2024-06-07 22:38:57 +02:00
a64577ac97
feat(gui): translate left item 2024-05-16 21:23:10 +02:00
81b1c8275f
feat: update some code with Java 21 newest methods 2024-05-16 21:15:26 +02:00
eb23580bc4
feat: bump required version to Java 21 2024-05-16 21:09:56 +02:00
81b66b6110
fix: pushed hotfix for file storage 2024-05-04 16:08:51 +02:00
7097e56a6d
feat: update changelog 2024-05-04 14:31:24 +02:00
5de0037d2c
feat: updated dependencies 2024-05-04 14:26:32 +02:00
ineanto
eb44504d6f fix: wrong date 2024-02-25 17:46:47 +01:00
ineanto
c8183ffe44 fix: bumped version again, forgot the previous one 2024-02-25 17:46:26 +01:00
ineanto
89d2499fed fix: change standardcopyoption 2024-02-25 16:39:01 +01:00
ineanto
c1c2d883c4 feat: bump version (1.1.4-RC1) 2024-02-25 16:28:41 +01:00
ineanto
59addc6ee3 feat: fetch skin in separate thread 2024-02-25 16:27:46 +01:00
ineanto
d784ed448f fix(random names): log error message upon failure 2024-02-25 16:16:14 +01:00
ineanto
68ad4ac9b5 feat(changelog): hotfix (1.1.3-RC1) 2023-12-28 22:04:00 +01:00
ineanto
f81ff8bd52 fix: update locale version constant 2023-12-28 22:00:13 +01:00
ineanto
4d45c4660a fix: locale wrong version (whoops) 2023-12-28 21:59:11 +01:00
ineanto
dde8ea48b9 feat(changelog): update (1.1.2-RC1) 2023-12-28 21:54:33 +01:00
ineanto
af4625793c fix(i18n): bump locale version 2023-12-28 21:40:35 +01:00
ineanto
ba753deafd feat(i18n): Updated the localization files (#tf2) 2023-12-28 21:39:04 +01:00
ineanto
f14457fd8b fix(appearance): show error reason 2023-12-28 21:31:07 +01:00
ineanto
365ac9b2d9 refactor(appearance): update to jre17 2023-12-28 21:21:44 +01:00
ineanto
4f13d3fc2d feat: actually reset 2023-12-28 21:20:18 +01:00
ineanto
61132a2c88 style(wrapper): update versions 2023-12-28 21:18:25 +01:00
ineanto
1a0d2ffdf7 fix(placeholder): wrong param 2023-12-28 21:17:16 +01:00
ineanto
52edd9fa65 feat(event): add warning on load failure 2023-12-28 21:09:58 +01:00
ineanto
ff22f5addf fix(i18n): update calls 2023-12-28 21:07:12 +01:00
ineanto
aa9b71bc18 refactor(i18n): optimizations 2023-12-28 21:02:09 +01:00
ineanto
ba9f39659b feat: update changelog 2023-12-27 18:22:08 +01:00
ineanto
ccac492dcd feat: update to 1.20.4 2023-12-27 18:19:12 +01:00
ineanto
2aab497d0a fix(test): assert sql following fallback implementation 2023-12-23 00:15:29 +01:00
ineanto
3f038c6b3d style: this is not an api 2023-12-23 00:08:52 +01:00
ineanto
95b4f4cdef refactor: remove unused constructor 2023-12-23 00:06:30 +01:00
ineanto
b394c7ef0c refactor(build): expand to all yml (1.1.0-RC1) 2023-12-23 00:02:49 +01:00
ineanto
ce8f21c268 feat(i18n): custom locale migration 2023-12-23 00:00:24 +01:00
ineanto
548d210a95 feat: migrate custom locale 2023-12-22 21:23:04 +01:00
ineanto
c78ba0c84a feat(i18n): final touches from the move to adventure 2023-12-22 17:44:29 +01:00
ineanto
84e792880f feat(i18n): move to adventure 2023-12-22 17:23:36 +01:00
ineanto
3377dcf2bf feat: error handling on invalid skin/name 2023-12-22 15:01:30 +01:00
ineanto
30803363ba feat: random skin on join 2023-12-22 14:57:24 +01:00
ineanto
153d666b78 refactor: final var 2023-12-22 14:17:21 +01:00
ineanto
83bc00aebe feat: translate random skin setting 2023-12-22 01:56:38 +01:00
ineanto
fdada8f44f feat: start working on random skin 2023-12-21 17:40:57 +01:00
ineanto
8a544d1ba5 fix: don't minimize bstats 2023-12-21 00:16:19 +01:00
ineanto
95cb064e29 feat(changelog): update (1.0.8-RC1) 2023-12-19 20:07:03 +01:00
ineanto
d44a92372b refactor(i18n): late init 2023-12-19 20:00:55 +01:00
ineanto
5d92cc6d32 feat: update changelog 2023-12-19 19:59:11 +01:00
ineanto
04690bf72c feat: bump api-version 2023-12-19 19:57:31 +01:00
ineanto
a064352492 feat: config version and improvements 2023-12-19 19:57:08 +01:00
ineanto
29e50966fd refactor: delete version 2023-12-19 14:45:18 +01:00
ineanto
e9d6f33930 feat(i18n): version checking 2023-12-19 14:31:15 +01:00
ineanto
2b71bd18eb refactor(i18n): simplify 2023-12-18 21:11:16 +01:00
ineanto
a08744dee3 refactor(test): folders 2023-12-18 20:39:15 +01:00
ineanto
60fa1d46f9 feat(changelog): update 2023-12-14 01:36:00 +01:00
ineanto
48ca85028b feat(storage): fallback on local storage 2023-12-14 01:35:18 +01:00
ineanto
cb98fd2671 feat: up-to-date changelog (1.0.7-RC1) 2023-12-14 00:57:06 +01:00
ineanto
c305f03df5 fix(storage): redundant cache call 2023-12-14 00:52:38 +01:00
ineanto
4238e7b091 fix(readme): update compatibility chart 2023-12-14 00:45:48 +01:00
ineanto
424f0df002 style(changelog): update changelog 2023-12-13 16:48:16 +01:00
ineanto
b2b67b3763 fix(changelog): date 2023-12-13 16:12:36 +01:00
ineanto
2fc3194c8c feat(global): support only latest major versions, bump to jre17 2023-12-13 16:09:00 +01:00
ineanto
3949113dee fix(project): various optimizations 2023-12-11 13:21:30 +01:00
ineanto
dd5aff034d fix(i18n): remove deprecated entry 2023-12-11 13:09:36 +01:00
ineanto
2447c08636 refactor(i18n): remove array type declaration 2023-12-11 13:09:17 +01:00
ineanto
e360d5c8a7 feat: bump version (1.0.6-RC1) 2023-12-11 13:02:48 +01:00
ineanto
9fc902aa75 feat(telemetry): add metrics 2023-12-11 13:02:32 +01:00
ineanto
a3227dfb94 feat(build): minimize jar 2023-12-11 12:31:44 +01:00
ineanto
e5ce8bde1a fix(build): includes/excludes fix (1.0.5-RC1) 2023-12-11 12:31:16 +01:00
ineanto
f306c3abaa fix(readme): bug fixed 2023-12-11 12:01:29 +01:00
ineanto
264d0745ba feat(build): move to gradle for performances reasons 2023-12-11 12:00:33 +01:00
ineanto
8a53b2f188 feat(check gui): dynamic gui 2023-12-09 14:49:17 +01:00
ineanto
d0488bae84 fix(i18n): colors 2023-12-07 19:08:13 +01:00
ineanto
4eecbf416e feat: reset skin via admin panel 2023-12-07 16:03:43 +01:00
ineanto
8611ef2604 feat(version): bump 2023-12-07 13:28:36 +01:00
ineanto
98c0a446c6 fix: visually update health and food levels 2023-12-07 12:34:27 +01:00
ineanto
b7fff273cf fix: rephrase 2023-12-06 22:54:33 +01:00
ineanto
a8483b4a15 fix: typo 2023-12-06 22:54:07 +01:00
ineanto
fc2be7c7a4 refactor: relocate packages 2023-12-06 22:53:51 +01:00
ineanto
8d1c80a5fb feat: bump version and version filtering 2023-12-06 22:41:49 +01:00
ineanto
99e7dd439a fix: make players disguise on join 2023-12-06 22:35:31 +01:00
ineanto
4f8c3c9eec feat: Nicko is out! 🎉 2023-12-06 22:10:57 +01:00
ineanto
14b118eadf fix(build): include mysql drivers 2023-12-06 22:09:35 +01:00
ineanto
37e6f031a6 refactor: cleanup for rc1 2023-12-06 19:35:34 +01:00
ineanto
17345a6b5f feat(ver): bump api version 2023-12-06 19:27:41 +01:00
ineanto
ddb4b6d39c feat: add warning using offline mode 2023-12-06 19:26:19 +01:00
ineanto
fcc4590396 fix: players appearing as allays 2023-12-03 23:25:42 +01:00
ineanto
d75aad6596 feat(disguise): update others when joining 2023-12-03 22:46:59 +01:00
ineanto
d673d34a51 style(comment): date format 2023-11-24 23:42:51 +01:00
ineanto
9bcbb510a0 refactor: remove todo 2023-11-24 23:42:06 +01:00
ineanto
25e3893771 refactor(note): i'm dumb 2023-11-24 23:22:14 +01:00
ineanto
b673a6409f refactor(readme): unnecessary explanation 2023-11-24 23:10:45 +01:00
ineanto
46ce1036ea feat(docs): known bugs 2023-11-24 23:09:49 +01:00
ineanto
3ee51ef6a7 style(wrapper): update note 2023-11-24 22:48:08 +01:00
ineanto
00e820735d refactor(i18n): optimize code 2023-11-24 22:10:52 +01:00
ineanto
f74b6d2f81 feat(readme): update to new logo 2023-11-23 23:43:01 +01:00
ineanto
2cf7f4c8d4 fix(gui): check empty name/skin 2023-11-23 23:38:18 +01:00
ineanto
95cb60a6b3 fix(chat validation): it works!
Chat Sessions are not invalidated anymore after disguised.
2023-11-23 23:21:15 +01:00
ineanto
b1632c049e fix(i18n): scroll down 2023-11-23 23:12:44 +01:00
ineanto
2aa37a10a6 deps(chore): bump deps and update accordingly 2023-11-23 23:12:08 +01:00
ineanto
2a326232ca feat: preliminary 1.20.2 support 2023-10-24 07:37:34 +02:00
ineanto
36589747af feat(command): remove debug command 2023-10-10 14:28:06 +02:00
ineanto
074c07f628 chore: update deps to mc 1.20.2 2023-10-10 14:27:50 +02:00
ineanto
4977e59d24 fix(test): gson constructor missing 2023-10-10 13:15:06 +02:00
ineanto
52c7c00dd1 feat(storage): add support for mysql 2023-10-05 13:56:49 +02:00
ineanto
83b7f90976 feat-gui-i18n: wrong branch rebase (#5)
Reviewed-on: https://ineanto.xyz/git/ineanto/nicko/pulls/5
Co-authored-by: ineanto <pantoine.rochas@gmail.com>
Co-committed-by: ineanto <pantoine.rochas@gmail.com>
2023-10-05 13:43:50 +02:00
ineanto
929423dfbe Merge branch 'master' into feat-gui-i18n 2023-09-17 17:37:48 +02:00
ineanto
649e23409a Dynamically translate GUI (#3)
Reviewed-on: https://ineanto.xyz/git/ineanto/nicko/pulls/3
2023-09-17 17:36:17 +02:00
ineanto
854039d657 feat(i18n): gui translation complete 2023-09-17 17:33:21 +02:00
ineanto
8838961f37 feat(i18n): admin gui 2023-09-15 22:15:00 +02:00
ineanto
f436c7db3a refactor(wrapper): update accordingly 2023-09-11 12:56:56 +02:00
ineanto
597ed23dbc feat(i18n): cache admin 2023-09-11 12:18:43 +02:00
ineanto
b24202e8ab feat: updated the localization files, translated coice gui 2023-09-07 22:12:02 +02:00
ineanto
292e9a4a6b feat(i18n): translate unavailable item 2023-09-02 22:27:25 +02:00
ineanto
6633ac94a8 fix: revert cache close 2023-09-01 22:24:44 +02:00
ineanto
94bb9ffc18 feat: close cache 2023-09-01 16:49:05 +02:00
ineanto
1d366855a2 refactor(packet): note 2023-09-01 16:40:40 +02:00
ineanto
c57400707e feat: home gui translated, fly cancel after disguise 2023-09-01 16:37:01 +02:00
ineanto
dd35f38dc2 fix: inventory closing 2023-08-31 10:44:57 +02:00
ineanto
8bddd56124 feat(i18n): updated localization files 2023-08-31 09:02:00 +02:00
ineanto
027d585210 feat: update to paperapi 2023-08-29 20:24:14 +02:00
ineanto
ccae0084ea feat: delete from cache when leaving, reopen gui on changing language 2023-08-29 20:20:56 +02:00
ineanto
6a4826f441 feat: lore 2023-08-22 17:51:48 +02:00
ineanto
8d87cddbea fix: persistence, i18n 2023-08-21 17:52:15 +02:00
ineanto
618af08024 feat: streamline profile class 2023-08-21 17:01:03 +02:00
ineanto
b81eac497a chore(deps): upgrade 2023-08-20 16:21:12 +02:00
ineanto
ec587b56c3 fix: consistency 2023-08-19 15:30:28 +02:00
ineanto
240d75b1a1 chore(deps): upgraded to paper 2023-08-19 15:13:10 +02:00
ineanto
e471d86801 feat: compartmentalization 2023-08-19 14:59:11 +02:00
ineanto
b64f56a0bb feat: item translation 2023-07-27 23:29:57 +02:00
ineanto
c929e73b0d feat: wip translations 2023-07-27 02:26:11 +02:00
ineanto
5d3a99f72d feat: item translator 2023-07-26 21:42:21 +02:00
ineanto
26daa3a038 feat(deps): upgrade 2023-07-26 21:10:53 +02:00
ineanto
f157831641 feat wip: item lore translation 2023-07-16 16:36:50 +02:00
ineanto
77a2623013 fix(folia): they will be. 2023-07-16 00:16:55 +02:00
ineanto
2ef21a796e feat wip(i18n): gui translation 2023-07-16 00:15:59 +02:00
ineanto
fe78fd0e2b feat: folia warning 2023-07-15 23:08:58 +02:00
ineanto
6fae824fe2 feat: player management/check 2023-07-15 23:06:47 +02:00
ineanto
119392320b refactor(gui): item placement 2023-07-15 12:39:13 +02:00
ineanto
378813c829 refactor: don't set variable 2023-07-15 10:32:22 +02:00
ineanto
7d07834bf7 fix(sql): mockbukkit is the issue 2023-07-15 10:30:20 +02:00
ineanto
3a7da4b3d6 sql: delete is not deleting wtf 2023-07-14 22:54:01 +02:00
ineanto
8464909b6d refactor(sql): delete 2023-07-14 16:53:24 +02:00
ineanto
87a256c9c5 fix: make tests run in order 2023-07-14 13:50:59 +02:00
ineanto
86e65043e1 feat(persistence): delete 2023-07-14 13:39:20 +02:00
ineanto
69bae936d6 feat: update cache 2023-07-14 11:01:35 +02:00
ineanto
f795d42564 refactor(redis): removed debug message 2023-07-14 10:11:48 +02:00
ineanto
7c70ebf9b6 fix(i18n): key mismatch 2023-07-10 17:54:13 +02:00
ineanto
cbc4c748ca fix: item names 2023-07-10 17:51:12 +02:00
ineanto
00168c03a7 feat: permission message and items 2023-07-10 17:38:03 +02:00
ineanto
92f88a1b92 feat: translations 2023-07-10 17:36:59 +02:00
ineanto
57d09f65c2 fix(i18n): translation 2023-07-08 16:15:12 +02:00
ineanto
571ed1d31d fix: store uuid 2023-07-08 16:12:20 +02:00
ineanto
37b1d5bd0c feat: cache uuids 2023-07-08 16:09:37 +02:00
ineanto
da8c7e91ce fix: remove debug statement 2023-07-04 19:36:40 +02:00
ineanto
29a557c42d refactor: titles among other things 2023-07-04 19:36:08 +02:00
ineanto
31c8c8f695 feat(storage): check for cache status 2023-07-03 18:35:51 +02:00
ineanto
b8a52da87e perf: merge instance 2023-07-03 18:30:55 +02:00
ineanto
4abcf7647f feat(global): rename, restructure
in prepartion for the I18N of the GUI.
2023-07-03 18:20:42 +02:00
ineanto
48257e2028 fix: flying after respawn 2023-07-03 17:51:37 +02:00
ineanto
a254d3ed9b fix(lang): missing " char 2023-07-03 17:51:13 +02:00
ineanto
856f550462 style(wrapper): missing space 2023-07-03 15:34:56 +02:00
ineanto
4aa9b23952 feat wip(skin): skin entry name 2023-07-03 15:25:02 +02:00
ineanto
228e3c4374 feat: confirm cache entry delete 2023-07-01 22:39:31 +02:00
ineanto
c8c55611a0 fix: mojangapi returns 2023-07-01 18:30:24 +02:00
ineanto
4fa7082bf5 build: ignore build logs 2023-07-01 18:04:25 +02:00
ineanto
f419f62f6c refactor: missed some more actionresults 2023-07-01 18:03:43 +02:00
ineanto
a91d039dd2 refactor: remove generic from actionresult 2023-07-01 18:01:58 +02:00
ineanto
18d7322406 feat: don't cache reset skin 2023-07-01 17:55:53 +02:00
ineanto
c6f037a24d style: gui adjustements 2023-07-01 17:35:46 +02:00
ineanto
de9904df52 refactor(placeholder): update author 2023-06-29 12:23:40 +02:00
ineanto
5cf35e5b98 refactor(placeholder): streamline 2023-06-29 12:20:19 +02:00
ineanto
82c210459e style: space 2023-06-29 11:55:02 +02:00
ineanto
51ab123eaf feat: throw error skin not found 2023-06-29 11:42:37 +02:00
ineanto
15b02ff390 refactor(disguise): update player after disguise 2023-06-29 11:14:46 +02:00
ineanto
3ec2e7a584 fix(wrapper): packets are final 2023-06-29 11:13:40 +02:00
ineanto
02e03794e4 refactor(i18n): shorter keys 2023-06-29 11:13:16 +02:00
ineanto
cb11f5e47a refactor(i18n): unnecessary static field 2023-06-29 11:06:54 +02:00
ineanto
7eacc92a22 remove logs 2023-06-28 23:23:34 +02:00
ineanto
2fbf3318f9 feat(disguise): update others players + fixes/tweaks 2023-06-28 23:22:50 +02:00
ineanto
f3ebbd6a8d fix(anvilgui): update to 1.20/1.20.1 2023-06-28 13:48:20 +02:00
ineanto
50dd4c3adf feat: 1.20/1.20.1 update 2023-06-28 13:22:48 +02:00
ineanto
c66979133d fix(gui): title 2023-06-20 10:38:06 +02:00
ineanto
c3e10ae81d feat(i18n): title update when going back 2023-06-19 21:52:46 +02:00
ineanto
7cab66a70e fix(docker): open mariadb port 2023-06-19 21:52:21 +02:00
ineanto
bb6764af00 feat: outdated comment 2023-06-19 15:54:31 +02:00
ineanto
f99d20ade3 refactor(wrappers): unused getters 2023-06-19 15:51:37 +02:00
ineanto
041700d070 style: wrap comment 2023-06-19 15:38:47 +02:00
ineanto
f9513aa751 style: chat session data comment move 2023-06-19 15:38:17 +02:00
ineanto
f447abe963 style: description and readme adjustements 2023-06-19 15:32:09 +02:00
ineanto
dee3f9b91c maintenance and player info packet cast fix 2023-06-19 15:08:23 +02:00
ineanto
584b34fd51 feat(wrapper): handle previous versions 2023-05-29 14:01:30 +02:00
ineanto
04fbcd99ba refractor(appearance manager): clarify issue 2023-05-22 20:42:18 +02:00
ineanto
ec3ca218a5 style: line wrapping 2023-05-22 20:39:22 +02:00
ineanto
318c0ffefd feat(redis): add test for redis cache 2023-05-22 14:13:40 +02:00
ineanto
17fa5e81e7 feat(cache): reworked implementation 2023-05-20 14:03:01 +02:00
ineanto
f0b9c62a1b feat(cache): get address and port from configuration 2023-05-20 00:54:49 +02:00
ineanto
87e998d578 feat(cache): initial redis support 2023-05-20 00:52:16 +02:00
ineanto
fecfb7300b feat: player reset
for the time being, message signature is set to null, causing players beyond 1.19.2
to be kicked while being disguised, even after removing said one.
look at the comment for further information.
2023-05-18 18:49:22 +02:00
ineanto
4157c71526 style(i18n): adjust some sentences 2023-05-17 13:39:49 +02:00
ineanto
f3088fca8c refactor: move package 2023-05-17 13:27:15 +02:00
ineanto
3ad3da9179 feat: player respawn support for 1.19 2023-05-17 13:23:21 +02:00
ineanto
ac9af73fb6 style: remove debugging statements 2023-04-29 11:11:27 +02:00
ineanto
af7081a87a feat: still researching packets support 2023-04-29 10:46:08 +02:00
ineanto
3037945729 fix: logs again 2023-04-28 23:53:10 +02:00
ineanto
1eb2af6443 why mojang? why? 2023-04-28 23:52:50 +02:00
ineanto
562f9ea3e4 fix: remove logs??? 2023-04-28 23:32:00 +02:00
ineanto
567184b07d still trying to figure out why protocollib doesn't work. 2023-04-28 23:31:34 +02:00
ineanto
a01b564912 feat: update wrapper 2023-04-28 22:47:57 +02:00
ineanto
7392b8aad2 style: documentation 2023-04-25 23:26:56 +02:00
ineanto
0ad2c408a6 style: clarify code 2023-04-25 23:25:43 +02:00
ineanto
cee168e225 feat: wrappers 2023-04-25 23:25:14 +02:00
ineanto
94634f7bba fix: remove nms folder 2023-04-25 18:37:22 +02:00
ineanto
ebe539c614 fix: remove dependency reduced pom 2023-04-25 18:36:14 +02:00
ineanto
7f3ecddc51 feat: protocollib, java 8 2023-04-25 18:34:49 +02:00
ineanto
fd732fc886 feat: use packetevents 2023-04-03 12:15:47 +02:00
ineanto
d17aadc09a feat(build): rework structure 2023-04-03 11:03:05 +02:00
ineanto
6e0ef4a243 feat(build): remove dist 2023-04-03 11:00:34 +02:00
ineanto
35e2db02e9 feat: remove NMS dependency 2023-04-03 10:56:43 +02:00
ineanto
d37a0bd3ba other: rework config later 2023-04-02 23:39:44 +02:00
196 changed files with 6615 additions and 4925 deletions

71
.gitignore vendored
View file

@ -1,50 +1,29 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
# Compiled class file ### IntelliJ IDEA ###
*.class .idea/
*.iws
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# Idea files
*.iml *.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
# Nicko first pass build files ### Eclipse ###
core/target .apt_generated
v1_14_R1/target .classpath
v1_15_R1/target .factorypath
v1_16_R1/target .project
v1_16_R2/target .settings
v1_16_R3/target .springBeans
v1_17_R1/target .sts4-cache
v1_18_R1/target bin/
v1_18_R2/target !**/src/main/**/bin/
v1_19_R1/target !**/src/test/**/bin/
# Idea Folder ### Server ###
.idea run/
# Build folder
target
# Maven Dependency Reduced Pom
dist/dependency-reduced-pom.xml
core/dependency-reduced-pom.xml

8
.idea/.gitignore generated vendored Normal file
View file

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

18
.idea/gradle.xml generated Normal file
View file

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

View file

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UnusedReceiverParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

10
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="PWA">
<option name="wasEnabledAtLeastOnce" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" project-jdk-name="graal-22" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml generated Normal file
View file

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

129
CHANGELOG.log Normal file
View file

@ -0,0 +1,129 @@
1.3.0-RC1: Update n°13 (XX/XX/25)
[FEATURES]
- Players are now able to mark disguises as favorites.
[FIXES]
- Fixed a bug where a player was improperly named when inspecting it in the admin panel.
- Added a missing sound when players undisguised.
1.2.0-RC1: Update n°12 (XX/XX/25)
[FEATURES]
- Updated to support Minecraft 1.21.5.
- Added a sub-command (/nicko about) to get information about Nicko.
- Modernized the messages and added various sound effects upon interacting with the plugin.
- Cleaned up GUI titles.
[FIXES]
- Fixed an oversight preventing the configuration from properly being migrated.
- Fixed a rare bug that could prevent data from being saved.
- Fixed the placeholder item in the skin cache invalidation not being translated.
- Fixed a oversight about a column name using SQL storage.
[LANGUAGE]
- Moved the prefix to the language file.
[OTHER]
- Cleaned up the codebase to prepare for future updates.
1.1.7-RC1: Hotfix n°5 (04/05/24)
[OTHER]
- Restored download link again on spigotmc.org
1.1.6-RC1: Update n°11 (04/05/24)
[FEATURES]
- Update dependencies in preparation to the 1.20.5 update
[OTHER]
- Restored download link on spigotmc.org
1.1.5-RC1: Update n°10 (25/12/23)
[FEATURES]
- Various improvements to performance.
[FIXES]
- Fixed a bug related to configuration migration.
1.1.4-RC1: Update n°9 (07/02/23)
[OTHER]
- The repository hosting the previous version of Nicko had expired, this is now fixed.
1.1.3-RC1: Hotfix n°4 (28/12/23)
[FIXES]
- Fixed the English Locale version being late.
1.1.2-RC1: Update n°8 (28/12/23)
[FEATURES]
- Players now default back to their original appearance upon failure.
[FIXES]
- Fixed an invalid placeholder parameter (%nicko_random_skin% now gets if the player has random skin on login set or not).
- Fixed the error reason not appearing upon failure.
- Fixed player profiles (name and skin associated) not being reset gracefully upon failure.
- Fixed error messages not being precise enough.
- Various optimizations and improvements.
1.1.1-RC1: Update n°7 (27/12/23)
[FEATURES]
- Made Nicko compatible with 1.20.3 and 1.20.4.
1.1.0-RC1: Update n°6 (23/12/23)
[BREAKING]
- The language system has been updated to use the Adventure library (https://docs.advntr.dev/index.html). This results in the custom locale breaking
Nicko upon usage of legacy color codes (e.g., "§6Nicko"). Your custom locale will be backed up upon starting this version and you will be able to
use the new default English locale to help you make your locale compatible with the new formatting.
[FEATURES]
- Players can now choose to get a random appearance via a list of more than 400 usernames and skins associated.
- Players can now toggle a setting to automatically get a random appearance upon joining.
- Introduced a version string inside Nicko's language files to plan future updates to the file. (see [BREAKING])
(Note: the random skin functionality is still work-in-progress and might break or not work at all because of
the lack of time that I have to test all the usernames and skins associated.)
[FIXES]
- Various optimizations and improvements.
- Internal refactoring
- bStats metrics are not minified anymore.
1.0.8-RC1: Update n°5 (19/12/23)
[FEATURES]
- Introduced a version string inside Nicko's configuration to plan future updates to the file. Your previous configuration file will automatically be migrated to this current version (with the backup of your old one included!)
- Persistence and cache will now fallback to local alternatives when unreachable.
- Player check GUI has been updated to better reflect the current state of player's disguises.
- Developers can now listen to the PlayerDisguiseEvent and cancel the disguise process.
[OTHER]
- Various optimizations and improvements.
- Internal refactoring
1.0.7-RC1: Update n°4 (13/12/23)
[OTHER]
- In line with my thinking that Minecraft servers should always be in one of the latest versions to give developers more freedom and less maintenance hassle, Nicko will now only be supporting the current major version and the one before it. This results in this version of Nicko now needing at minimum Java version 17 and a server running 1.19. If you can't upgrade, consider myself sorry.
- Various optimizations and improvements following the upgrade to Java 17.
1.0.6-RC1: Update n°3 (11/12/23)
[OTHER]
- Added telemetry via bStats to gather useful informations about Nicko. This feature is optional and can be disabled inside the "bStats" folder found in plugins folder. Informations gathered are public record and can be found at: https://bstats.org/plugin/bukkit/Nicko/20483.
1.0.5-RC1: Update n°2 (11/12/23)
[OTHER]
- Moved plugin to the Gradle build chain, resulting in faster builds and smaller Jar. This has no consequences for players.
1.0.4-RC1:
[FEATURES]
- The players check GUI is now updated upon player's joining and leaving
- Administrators are now able to remove a player's disguise through the player check GUI
1.0.3-RC1: Hotfix n°3 (07/12/23)
[FIXES]
- Fixed a visual bug where players in survival mode were seeing themselves as having full health and hunger after disguising.
1.0.2-RC1: Hotfix n°2 (06/12/23)
[OTHER]
- Internal refactoring
1.0.1-RC1: Hotfix n°1 (06/12/23)
[FIXES]
- Fixed an issue when joining and players being disguised were not for the player joining.

View file

@ -1,14 +1,29 @@
# _Nicko_ <img style="vertical-align:middle" src="./img/LOGO.png" alt="" width="50"/> # *Nicko* <img style="vertical-align:middle" src="./img/LOGO.png" alt="" width="65"/>
## The next-generation, most feature-packed disguise plugin for Minecraft. ## The feature packed, next generation disguise plugin for Minecraft.
### Download: ---
Coming soon! ⏳ ## Download:
https://www.spigotmc.org/resources/nicko.113868/
---
## Known bugs:
- Players who have operator (OP) status lose access to the Operator Items tab in creative mode
after disguising **(1.20 and up)**.
- When disguising and only changing their display name, players will have the new default
skins **(1.20 and up)**.
---
#### Version compatibility table #### Version compatibility table
| Version | Supported | | Version | Plugin |
|-----------|----------------------------------------------------------------------------| |---------------|----------------------------------------------------------------------------|
| < 1.12.2 | Use [NickReloaded](https://www.spigotmc.org/resources/nickreloaded.46335/) | | 1.7 and lower | Unsupported |
| \> 1.12.2 | Supported | | 1.8 - 1.12.2 | Use [NickReloaded](https://www.spigotmc.org/resources/nickreloaded.46335/) |
| 1.13 to 1.19 | Unsupported |
| 1.20 - 1.21 | Use Nicko |

106
build.gradle.kts Normal file
View file

@ -0,0 +1,106 @@
plugins {
id("java")
id("com.gradleup.shadow") version "8.3.2"
id("xyz.jpenilla.run-paper") version "2.3.0"
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
}
group = "xyz.ineanto"
version = "1.2.0"
val invuiVersion: String = "1.44"
java {
sourceCompatibility = JavaVersion.VERSION_22
targetCompatibility = JavaVersion.VERSION_22
toolchain {
languageVersion = JavaLanguageVersion.of(22)
}
}
repositories {
mavenCentral()
mavenLocal()
maven("https://repo.xenondevs.xyz/releases")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.codemc.io/repository/maven-snapshots/")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}
dependencies {
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.kyori:adventure-api:4.21.0")
compileOnly("xyz.xenondevs.invui:invui-core:$invuiVersion")
compileOnly("net.wesjd:anvilgui:1.10.4-SNAPSHOT")
compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT")
implementation("de.rapha149.signgui:signgui:2.5.0")
implementation("com.github.jsixface:yamlconfig:1.2")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.1")
implementation("com.fasterxml.jackson.core:jackson-core:2.18.1")
implementation("com.mysql:mysql-connector-j:9.2.0")
implementation("org.mariadb.jdbc:mariadb-java-client:3.5.2")
implementation("redis.clients:jedis:5.2.0")
implementation("com.google.code.gson:gson:2.13.1")
}
tasks {
processResources {
from("src/main/resources")
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
filesMatching("*.yml") {
expand("version" to version)
}
}
shadowJar {
// RELOCATIONS
relocate("net.wesjd", "xyz.ineanto.nicko.libs.anvilgui")
relocate("com.github.jsixface", "xyz.ineanto.nicko.libs.yaml")
relocate("me.clip", "xyz.ineanto.nicko.libs.placeholderapi")
relocate("com.fasterxml.jackson", "xyz.ineanto.nicko.libs.jackson")
relocate("com.mysql", "xyz.ineanto.nicko.libs.mysql")
relocate("org.mariadb.jdbc", "xyz.ineanto.nicko.libs.mariadb")
relocate("redis.clients", "xyz.ineanto.nicko.libs.redis")
relocate("com.google.gson", "xyz.ineanto.nicko.libs.gson")
relocate("org.apache.commons.pool2", "xyz.ineanto.nicko.libs.pool2")
// EXCLUSIONS
exclude("colors.bin")
exclude("waffle/**")
exclude("com/sun/**")
exclude("com/google/protobuf/**")
exclude("com/google/errorprone/**")
exclude("org/apache/commons/logging/**")
exclude("org/jetbrains/**")
exclude("org/intellij/**")
exclude("org/checkerframework/**")
exclude("org/json/**")
exclude("org/slf4j/**")
exclude("org/yaml/**")
exclude("google/protobuf/**")
exclude("net/kyori/**")
// MINIFY
minimize {
exclude(dependency("xyz.xenondevs.invui:.*"))
exclude(dependency("de.rapha149.signgui:.*"))
}
}
runServer {
downloadPlugins {
url("https://download.luckperms.net/1593/bukkit/loader/LuckPerms-Bukkit-5.5.8.jar")
// 1.20.5 - latest testing
url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar")
}
minecraftVersion("1.21.5")
}
}

View file

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>net.artelnatif</groupId>
<artifactId>nicko-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
</repository>
<repository>
<id>placeholderapi</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories>
<dependencies>
<!-- PlaceHolder API -->
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
<!-- Spigot API -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.19.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- Inventory Lib -->
<dependency>
<groupId>xyz.xenondevs.invui</groupId>
<artifactId>invui</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- AnvilGUI -->
<dependency>
<groupId>net.wesjd</groupId>
<artifactId>anvilgui</artifactId>
<version>1.6.3-SNAPSHOT</version>
</dependency>
<!-- Google Guava (GSON) -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<scope>provided</scope>
</dependency>
<!-- MockBukkit 1.19 (Bukkit Unit Tests) -->
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.19</artifactId>
<version>2.29.0</version>
<scope>test</scope>
</dependency>
<!-- MariaDB JDBC Driver -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.1.2</version>
</dependency>
<!-- YAML Reader -->
<dependency>
<groupId>com.github.jsixface</groupId>
<artifactId>yamlconfig</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.14.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.14.2</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.1-SNAPSHOT</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>net.wesjd:anvilgui</include>
<include>xyz.xenondevs.invui:*</include>
<include>com.github.jsixface:*</include>
<include>com.fasterxml.jackson.dataformat</include>
<include>com.fasterxml.jackson.core</include>
<include>org.mariadb.jdbc</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>net.wesjd.anvilgui</pattern>
<shadedPattern>net.artelnatif.libs.anvilgui</shadedPattern>
</relocation>
<relocation>
<pattern>xyz.xenondevs.invui</pattern>
<shadedPattern>net.artelnatif.libs.invui</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.jsixface</pattern>
<shadedPattern>net.artelnatif.libs.yaml</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson.dataformat</pattern>
<shadedPattern>net.artelnatif.libs.jackson.yaml</shadedPattern>
</relocation>
<relocation>
<pattern>com.fasterxml.jackson.core</pattern>
<shadedPattern>net.artelnatif.libs.jackson.core</shadedPattern>
</relocation>
<relocation>
<pattern>org.mariadb.jdbc</pattern>
<shadedPattern>net.artelnatif.libs.mariadb</shadedPattern>
</relocation>
</relocations>
<!-- Prevents breaking AnvilGUI's VersionWrapper. -->
<minimizeJar>false</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources/</directory>
</resource>
</resources>
</build>
</project>

View file

@ -1,167 +0,0 @@
package net.artelnatif.nicko;
import net.artelnatif.nicko.gui.items.common.OptionUnavailable;
import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SimpleItem;
import net.artelnatif.nicko.command.NickoCommand;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.config.ConfigurationManager;
import net.artelnatif.nicko.event.PlayerJoinListener;
import net.artelnatif.nicko.event.PlayerQuitListener;
import net.artelnatif.nicko.gui.items.main.ExitGUI;
import net.artelnatif.nicko.i18n.Locale;
import net.artelnatif.nicko.i18n.LocaleFileManager;
import net.artelnatif.nicko.impl.Internals;
import net.artelnatif.nicko.impl.InternalsProvider;
import net.artelnatif.nicko.mojang.MojangAPI;
import net.artelnatif.nicko.placeholder.PlaceHolderHook;
import net.artelnatif.nicko.storage.PlayerDataStore;
import net.artelnatif.nicko.storage.name.PlayerNameStore;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import java.io.File;
import java.io.IOException;
public class NickoBukkit extends JavaPlugin {
private static NickoBukkit plugin;
private final boolean unitTesting;
private MojangAPI mojangAPI;
private PlayerDataStore dataStore;
private ConfigurationManager configurationManager;
private Configuration configuration;
private LocaleFileManager localeFileManager;
private PlayerNameStore nameStore;
public NickoBukkit() { this.unitTesting = false; }
/**
* Used by MockBukkit
*/
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
this(loader, description, dataFolder, file, null);
}
/**
* Used by MockBukkit
*/
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file, Configuration configuration) {
super(loader, description, dataFolder, file);
unitTesting = true;
this.configuration = configuration;
getLogger().info("Unit Testing Mode enabled.");
}
@Override
public void onEnable() {
plugin = this;
configurationManager = new ConfigurationManager(getDataFolder());
configurationManager.saveDefaultConfig();
mojangAPI = new MojangAPI();
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
nameStore = new PlayerNameStore();
if (!dataStore.getStorage().isError()) {
getLogger().info("Loading persistence...");
if (!dataStore.getStorage().getProvider().init()) {
dataStore.getStorage().setError(true);
getLogger().severe("Failed to open persistence, data will NOT be saved!");
}
}
if (!unitTesting) {
getLogger().info("Loading internals...");
if (getInternals() == null) {
getLogger().severe("Nicko could not find a valid implementation for this server version. Is your server supported?");
dataStore.getStorage().setError(true);
getServer().getPluginManager().disablePlugin(this);
}
localeFileManager = new LocaleFileManager();
if (configuration.isCustomLocale()) {
if (localeFileManager.dumpFromLocale(Locale.ENGLISH)) {
getLogger().info("Successfully loaded custom language file.");
} else {
getLogger().severe("Failed to load custom language file!");
}
}
final PluginCommand command = getCommand("nicko");
if (command != null) {
command.setExecutor(new NickoCommand());
}
Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE).setDisplayName(" ")));
Structure.addGlobalIngredient('U', new OptionUnavailable());
Structure.addGlobalIngredient('E', new ExitGUI());
new PlaceHolderHook(this).hook();
getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this);
getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this);
getLogger().info("Nicko (Bukkit) has been enabled.");
}
}
@Override
public void onDisable() {
if (!getDataStore().getStorage().isError()) {
getLogger().info("Closing persistence...");
nameStore.clearStoredNames();
Bukkit.getOnlinePlayers().forEach(player -> dataStore.saveData(player));
if (!dataStore.getStorage().getProvider().close()) {
getLogger().severe("Failed to close persistence!");
}
}
getLogger().info("Nicko (Bukkit) has been disabled.");
}
public static NickoBukkit getInstance() {
return plugin;
}
public Configuration getNickoConfig() {
try {
if (configuration == null) { return configuration = configurationManager.load(); }
return configuration;
} catch (IOException e) {
getLogger().severe("Failed to load the configuration file!");
getLogger().severe("It may be have been generated with an older version of Nicko.");
getLogger().severe("Delete the configuration and restart the server please :)");
getLogger().severe("(" + e.getMessage() + ")");
return null;
}
}
public PlayerDataStore getDataStore() {
return dataStore;
}
public PlayerNameStore getNameStore() {
return nameStore;
}
public MojangAPI getMojangAPI() {
return mojangAPI;
}
public LocaleFileManager getLocaleFileManager() {
return localeFileManager;
}
public Internals getInternals() {
return InternalsProvider.getInternals();
}
}

View file

@ -1,106 +0,0 @@
package net.artelnatif.nicko.anvil;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.appearance.AppearanceManager;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.i18n.I18N;
import net.artelnatif.nicko.i18n.I18NDict;
import net.artelnatif.nicko.mojang.MojangUtils;
import net.wesjd.anvilgui.AnvilGUI;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Collections;
import java.util.List;
public class AnvilManager {
private final Player player;
private final AppearanceManager appearanceManager;
public AnvilManager(Player player) {
this.player = player;
this.appearanceManager = AppearanceManager.get(player);
}
public void openNameThenSkinAnvil() {
getNameThenSkinAnvil().open(player);
}
public void openSkinAnvil() {
getSkinAnvil().open(player);
}
public void openNameAnvil() {
getNameAnvil().open(player);
}
public AnvilGUI.Builder getNameThenSkinAnvil() {
return new AnvilGUI.Builder()
.plugin(NickoBukkit.getInstance())
.itemLeft(getLeftItem(false))
.interactableSlots(AnvilGUI.Slot.OUTPUT)
.onComplete((completion) -> {
if (MojangUtils.isUsernameInvalid(completion.getText())) {
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
} else {
appearanceManager.setName(completion.getText());
openSkinAnvil();
return Collections.singletonList(AnvilGUI.ResponseAction.close());
}
})
.text("New name...");
}
public AnvilGUI.Builder getNameAnvil() {
return new AnvilGUI.Builder()
.plugin(NickoBukkit.getInstance())
.itemLeft(getLeftItem(false))
.interactableSlots(AnvilGUI.Slot.OUTPUT)
.onComplete((completion) -> {
if (MojangUtils.isUsernameInvalid(completion.getText())) {
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
} else {
appearanceManager.setName(completion.getText());
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(false);
return sendResultAndClose(actionResult);
}
})
.text("New name...");
}
private AnvilGUI.Builder getSkinAnvil() {
return new AnvilGUI.Builder()
.plugin(NickoBukkit.getInstance())
.itemLeft(getLeftItem(true))
.interactableSlots(AnvilGUI.Slot.OUTPUT)
.onComplete((completion) -> {
if (MojangUtils.isUsernameInvalid(completion.getText())) {
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
} else {
appearanceManager.setSkin(completion.getText());
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(true);
return sendResultAndClose(actionResult);
}
})
.text("New skin...");
}
private List<AnvilGUI.ResponseAction> sendResultAndClose(ActionResult<Void> actionResult) {
if (!actionResult.isError()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.SUCCESS));
} else {
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
}
return Collections.singletonList(AnvilGUI.ResponseAction.close());
}
private ItemStack getLeftItem(boolean skin) {
final ItemStack item = new ItemStack(Material.PAPER);
final ItemMeta meta = item.getItemMeta();
meta.setDisplayName("§0New " + (skin ? "skin" : "name") + "...");
item.setItemMeta(meta);
return item;
}
}

View file

@ -1,89 +0,0 @@
package net.artelnatif.nicko.appearance;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.storage.PlayerDataStore;
import net.artelnatif.nicko.storage.name.PlayerNameStore;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.UUID;
public class AppearanceManager {
private final NickoProfile profile;
private final Player player;
private final NickoBukkit instance = NickoBukkit.getInstance();
private final PlayerDataStore dataStore = instance.getDataStore();
private final PlayerNameStore nameStore = instance.getNameStore();
private AppearanceManager(UUID uuid) {
this.player = Bukkit.getPlayer(uuid);
this.profile = dataStore.getData(uuid).orElse(NickoProfile.EMPTY_PROFILE.clone());
}
private AppearanceManager(String name) {
this.player = null;
this.profile = dataStore.getOfflineData(name).orElse(NickoProfile.EMPTY_PROFILE.clone());
}
public static AppearanceManager get(Player player) {
return new AppearanceManager(player.getUniqueId());
}
public static AppearanceManager get(String name) {
return new AppearanceManager(name);
}
public boolean hasData() {
return !profile.isEmpty();
}
public void setSkin(String skin) {
profile.setSkin(skin);
}
public String getSkin() {
return profile.getSkin();
}
public boolean needsASkinChange() {
return profile.getSkin() != null && !profile.getSkin().equals(player.getName());
}
public void setName(String name) {
profile.setName(name);
}
public String getName() {
return profile.getName();
}
public NickoProfile getProfile() {
return profile;
}
public void setNameAndSkin(String name, String skin) {
this.profile.setName(name);
this.profile.setSkin(skin);
updatePlayer(true);
}
public ActionResult<Void> reset() {
final String defaultName = nameStore.getStoredName(player);
this.profile.setName(defaultName);
this.profile.setSkin(defaultName);
final ActionResult<Void> actionResult = resetPlayer();
this.profile.setSkin(null);
this.profile.setName(null);
return actionResult;
}
public ActionResult<Void> resetPlayer() {
return NickoBukkit.getInstance().getInternals().updateProfile(player, profile, true, true);
}
public ActionResult<Void> updatePlayer(boolean skinChange) {
return NickoBukkit.getInstance().getInternals().updateProfile(player, profile, skinChange, false);
}
}

View file

@ -1,48 +0,0 @@
package net.artelnatif.nicko.command;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.command.sub.NickoCheckSubCmd;
import net.artelnatif.nicko.command.sub.NickoDebugSubCmd;
import net.artelnatif.nicko.gui.MainGUI;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NickoCommand implements CommandExecutor {
private String helpMessage = "§cNicko §8§o[{version}] §f- §2Help:\n" +
"§6/nicko §f- §7Open the GUI.\n" +
"§6/nicko help §f- §7Print this help message.\n";
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
if (args.length >= 1) {
switch (args[0]) {
case "debug":
new NickoDebugSubCmd().execute(player, args);
break;
case "check":
new NickoCheckSubCmd().execute(player, args);
break;
default:
sendHelpMessage(sender);
break;
}
return false;
}
new MainGUI(player).open();
return false;
}
sender.sendMessage("This plugin can only be used in-game. Sorry!");
return false;
}
public void sendHelpMessage(CommandSender sender) {
helpMessage = helpMessage.replace("{version}", NickoBukkit.getInstance().getDescription().getVersion());
sender.sendMessage(helpMessage);
}
}

View file

@ -1,42 +0,0 @@
package net.artelnatif.nicko.command.sub;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.appearance.AppearanceManager;
import net.artelnatif.nicko.i18n.I18N;
import net.artelnatif.nicko.i18n.I18NDict;
import net.artelnatif.nicko.mojang.MojangUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.StringJoiner;
public class NickoCheckSubCmd {
public void execute(Player player, String[] args) {
final String targetName = args[1];
final Player target = Bukkit.getPlayerExact(targetName);
AppearanceManager appearanceManager;
if (MojangUtils.isUsernameInvalid(targetName)) {
player.sendMessage(I18N.translate(player, I18NDict.Error.INVALID_USERNAME));
return;
}
if (target == null) {
appearanceManager = AppearanceManager.get(targetName);
} else {
appearanceManager = AppearanceManager.get(target);
}
final StringJoiner builder = new StringJoiner("\n");
builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§6Check for: §f§o" + targetName);
if (!appearanceManager.hasData()) {
builder.add("§cThis player has not data.");
} else {
builder.add("§7- §fNicked: §a✔");
builder.add("§7- §fName: §6" + appearanceManager.getName());
builder.add("§7- §fSkin: §6" + appearanceManager.getSkin());
}
player.sendMessage(builder.toString());
}
}

View file

@ -1,48 +0,0 @@
package net.artelnatif.nicko.command.sub;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.appearance.AppearanceManager;
import net.artelnatif.nicko.mojang.MojangUtils;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NickoDebugSubCmd {
public void execute(CommandSender sender, String[] args) {
final String prefix = NickoBukkit.getInstance().getNickoConfig().getPrefix();
Player target;
String name, skin;
if (args.length == 3) {
target = (Player) sender;
name = args[1];
skin = args[2];
} else {
if (args.length < 3) {
sender.sendMessage(prefix + "§cMissing argument.");
return;
}
final String playerName = args[1];
name = args[2];
skin = args[3];
target = Bukkit.getPlayer(playerName);
if (target == null) {
sender.sendMessage(prefix + "§cSpecified player is offline.");
return;
}
}
final AppearanceManager appearanceManager = AppearanceManager.get(target.getPlayer());
if (MojangUtils.isUsernameInvalid(name) || MojangUtils.isUsernameInvalid(skin)) {
sender.sendMessage(prefix + "§cSpecified username is invalid.");
}
appearanceManager.setNameAndSkin(name, skin);
target.sendMessage(prefix + "§aWhoosh!");
target.playSound(target.getLocation(), Sound.ENTITY_ITEM_FRAME_PLACE, 1, 1);
}
}

View file

@ -1,51 +0,0 @@
package net.artelnatif.nicko.config;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Configuration {
@JsonProperty("sql")
private final DataSourceConfiguration sqlConfiguration;
@JsonProperty("redis")
private final DataSourceConfiguration redisConfiguration;
private final String prefix;
private final Boolean local;
private final Boolean customLocale;
public Configuration(DataSourceConfiguration sqlConfiguration, DataSourceConfiguration redisConfiguration, String prefix, Boolean local, Boolean customLocale) {
this.sqlConfiguration = sqlConfiguration;
this.redisConfiguration = redisConfiguration;
this.prefix = prefix;
this.local = local;
this.customLocale = customLocale;
}
public Configuration() {
this(
new DataSourceConfiguration("", 3306, "", ""),
new DataSourceConfiguration("", 6379, "", ""),
"",
false,
false
);
}
public DataSourceConfiguration getSqlConfiguration() {
return sqlConfiguration;
}
public DataSourceConfiguration getRedisConfiguration() {
return redisConfiguration;
}
public String getPrefix() {
return prefix;
}
public Boolean isLocal() {
return local;
}
public Boolean isCustomLocale() {
return customLocale;
}
}

View file

@ -1,36 +0,0 @@
package net.artelnatif.nicko.config;
public class DataSourceConfiguration {
public static final DataSourceConfiguration SQL_EMPTY = new DataSourceConfiguration("127.0.0.1", 3306, "root", "");
public static final DataSourceConfiguration REDIS_EMPTY = new DataSourceConfiguration("127.0.0.1", 6379, "", "");
private final String address;
private final Integer port;
private final String username;
private final String password;
public DataSourceConfiguration(String address, Integer port, String username, String password) {
this.address = address;
this.port = port;
this.username = username;
this.password = password;
}
public DataSourceConfiguration() { this("", 0, "", ""); }
public String getAddress() {
return address;
}
public Integer getPort() {
return port;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}

View file

@ -1,36 +0,0 @@
package net.artelnatif.nicko.disguise;
import net.artelnatif.nicko.i18n.I18NDict;
public class ActionResult<R> {
private final I18NDict errorMessage;
private boolean error = false;
private R result;
public ActionResult() {
this.errorMessage = null;
}
public ActionResult(I18NDict errorMessage) {
this.errorMessage = errorMessage;
this.error = true;
this.result = null;
}
public ActionResult(R result) {
this.errorMessage = null;
this.result = result;
}
public R getResult() {
return result;
}
public boolean isError() {
return error;
}
public I18NDict getErrorMessage() {
return errorMessage;
}
}

View file

@ -1,72 +0,0 @@
package net.artelnatif.nicko.disguise;
import net.artelnatif.nicko.i18n.Locale;
public class NickoProfile implements Cloneable {
public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null, Locale.ENGLISH, true);
private String name;
private String skin;
private Locale locale;
private boolean bungeecordTransfer;
public NickoProfile(String name, String skin, Locale locale, boolean bungeecordTransfer) {
this.name = name;
this.skin = skin;
this.locale = locale;
this.bungeecordTransfer = bungeecordTransfer;
}
public boolean isEmpty() {
return name == null && skin == null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSkin() {
return skin;
}
public void setSkin(String skin) {
this.skin = skin;
}
public Locale getLocale() { return locale; }
public void setLocale(Locale locale) { this.locale = locale; }
public boolean isBungeecordTransfer() {
return bungeecordTransfer;
}
public void setBungeecordTransfer(boolean bungeecordTransfer) {
this.bungeecordTransfer = bungeecordTransfer;
}
@Override
public String toString() {
return "NickoProfile{" +
"name='" + name + '\'' +
", skin='" + skin + '\'' +
", locale=" + locale +
", bungeecordTransfer=" + bungeecordTransfer +
'}';
}
@Override
public NickoProfile clone() {
Object o;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
return (NickoProfile) o;
}
}

View file

@ -1,42 +0,0 @@
package net.artelnatif.nicko.event;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.appearance.AppearanceManager;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.i18n.I18N;
import net.artelnatif.nicko.i18n.I18NDict;
import net.artelnatif.nicko.storage.PlayerDataStore;
import net.artelnatif.nicko.storage.name.PlayerNameStore;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class PlayerJoinListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
final NickoBukkit instance = NickoBukkit.getInstance();
final PlayerDataStore dataStore = instance.getDataStore();
final PlayerNameStore nameStore = instance.getNameStore();
nameStore.storeName(player);
// TODO: 2/20/23 BungeeCord transfer
dataStore.performProfileUpdate(player.getUniqueId(), NickoProfile.EMPTY_PROFILE);
Bukkit.getScheduler().runTaskLater(instance, () -> {
final AppearanceManager appearanceManager = AppearanceManager.get(player);
if (appearanceManager.hasData()) {
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(appearanceManager.needsASkinChange());
if (!actionResult.isError()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.SUCCESS));
} else {
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.FAIL, I18N.translate(player, actionResult.getErrorMessage())));
}
}
}, 20L);
}
}

View file

@ -1,19 +0,0 @@
package net.artelnatif.nicko.event;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.ActionResult;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerQuitListener implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
final Player player = event.getPlayer();
final ActionResult<Void> result = NickoBukkit.getInstance().getDataStore().saveData(player);
if (result.isError()) {
NickoBukkit.getInstance().getLogger().warning("Failed to save data for " + player.getName());
}
}
}

View file

@ -1,35 +0,0 @@
package net.artelnatif.nicko.gui;
import net.artelnatif.nicko.gui.items.admin.ManageCache;
import net.artelnatif.nicko.gui.items.common.GoBack;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class AdminGUI {
public static final String TITLE = "Nicko > Administration";
private final Player player;
private final Gui gui;
public AdminGUI(Player player) {
this.gui = Gui.normal()
.setStructure(
"# # # # # # # # #",
"# # # S U U # # #",
"B # # # # # # # #"
)
.addIngredient('S', new ManageCache())
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public void open() {
Window.single().setGui(gui).setTitle(TITLE).open(player);
}
}

View file

@ -1,46 +0,0 @@
package net.artelnatif.nicko.gui;
import net.artelnatif.nicko.gui.items.main.AdminSubGUI;
import net.artelnatif.nicko.gui.items.main.ResetAppearance;
import net.artelnatif.nicko.gui.items.main.SettingsSubGUI;
import net.artelnatif.nicko.gui.items.skin.ChangeName;
import net.artelnatif.nicko.gui.items.skin.ChangeNameAndSkin;
import net.artelnatif.nicko.gui.items.skin.ChangeSkin;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class MainGUI {
private final Player player;
private final Gui gui;
public MainGUI(Player player) {
final String[] dynamicStructure = new String[]{
"# # # # # # # # #",
"# # # N B S # # #",
"E P A # # # # # R"};
if (!player.hasPermission("nicko.admin") || !player.isOp()) {
dynamicStructure[2] = dynamicStructure[2].replace("A", "#");
}
this.gui = Gui.normal()
.setStructure(dynamicStructure)
.addIngredient('R', new ResetAppearance())
.addIngredient('N', new ChangeName())
.addIngredient('B', new ChangeNameAndSkin())
.addIngredient('S', new ChangeSkin(player))
.addIngredient('P', new SettingsSubGUI())
.addIngredient('A', new AdminSubGUI())
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public void open() {
Window.single().setGui(gui).setTitle("Nicko - Home").open(player);
}
}

View file

@ -1,38 +0,0 @@
package net.artelnatif.nicko.gui;
import net.artelnatif.nicko.gui.items.common.GoBack;
import net.artelnatif.nicko.gui.items.settings.BungeeCordCycling;
import net.artelnatif.nicko.gui.items.settings.LanguageCycling;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class SettingsGUI {
public static final String TITLE = "Nicko > Settings";
private final Player player;
private final Gui gui;
public SettingsGUI(Player player) {
final String[] dynamicStructure = new String[]{
"# # # # # # # # #",
"# # # L T U # # #",
"B # # # # # # # #"
};
// TODO: 3/6/23 Replace when Redis is not enabled
dynamicStructure[1] = dynamicStructure[1].replace("T", "U");
this.gui = Gui.normal()
.setStructure(dynamicStructure)
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
.addIngredient('L', new LanguageCycling().get(player))
.addIngredient('T', new BungeeCordCycling().get(player))
.build();
this.player = player;
}
public void open() {
Window.single().setGui(gui).setTitle(TITLE).open(player);
}
}

View file

@ -1,36 +0,0 @@
package net.artelnatif.nicko.gui.admin;
import net.artelnatif.nicko.gui.AdminGUI;
import net.artelnatif.nicko.gui.items.admin.cache.CacheDetailed;
import net.artelnatif.nicko.gui.items.admin.cache.CacheInvalidate;
import net.artelnatif.nicko.gui.items.admin.cache.CacheOverview;
import net.artelnatif.nicko.gui.items.common.GoBack;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class CacheManagementGUI {
public static final String TITLE = "Nicko > Admin... > Cache";
private final Player player;
private final Gui gui;
public CacheManagementGUI(Player player) {
this.gui = Gui.normal()
.setStructure("B # S A D")
.addIngredient('B', new GoBack(new AdminGUI(player).getGUI()))
.addIngredient('S', new CacheOverview())
.addIngredient('A', new CacheInvalidate())
.addIngredient('D', new CacheDetailed())
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public void open() {
Window.single().setGui(gui).setTitle(TITLE).open(player);
}
}

View file

@ -1,61 +0,0 @@
package net.artelnatif.nicko.gui.admin.cache;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.gui.items.admin.cache.SkinPlaceholder;
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
import net.artelnatif.nicko.gui.items.common.GoBack;
import net.artelnatif.nicko.gui.items.common.ScrollDown;
import net.artelnatif.nicko.gui.items.common.ScrollUp;
import net.artelnatif.nicko.mojang.MojangSkin;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.window.Window;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
public class CacheDetailedGUI {
public static final String TITLE = "... > Cache > Invalidate";
private final Player player;
private final Gui gui;
public CacheDetailedGUI(Player player) {
final ConcurrentMap<String, Optional<MojangSkin>> skins = NickoBukkit.getInstance().getMojangAPI().getCache().asMap();
final List<String> loadedSkins = skins.entrySet().stream()
.filter(entry -> entry.getValue().isPresent())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
final List<Item> items = loadedSkins.stream()
.map(SkinPlaceholder::new)
.collect(Collectors.toList());
gui = ScrollGui.items(guiItemBuilder -> {
guiItemBuilder.setStructure(
"# # # # # # # # #",
"# x x x x x x U #",
"# x x x x x x # #",
"# x x x x x x # #",
"# x x x x x x D #",
"B # # # # # # # #");
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
guiItemBuilder.addIngredient('U', new ScrollUp());
guiItemBuilder.addIngredient('D', new ScrollDown());
guiItemBuilder.addIngredient('B', new GoBack(new CacheManagementGUI(player).getGUI()));
guiItemBuilder.setContent(items);
});
this.player = player;
}
public void open() {
Window.single().setGui(gui).setTitle(TITLE).open(player);
}
}

View file

@ -1,33 +0,0 @@
package net.artelnatif.nicko.gui.items.admin;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.AsyncItem;
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
public class ManageCache extends AsyncItem {
public ManageCache() {
super(new ItemBuilder(Material.PAINTING)
.setDisplayName("§fManage §6skin §fcache...")
.addLoreLines("§7Access the skin cache management panel."),
() -> {
final SkullBuilder builder = new SkullBuilder("Notch");
builder.setDisplayName("§fManage §6skin §fcache...");
builder.addLoreLines("§7Access the skin cache management panel.");
return builder;
});
}
@Override
public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
if (clickType.isLeftClick() || clickType.isRightClick()) {
event.getView().close();
new CacheManagementGUI(player).open();
}
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.gui.items.admin.cache;
import net.artelnatif.nicko.gui.admin.cache.CacheDetailedGUI;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class CacheDetailed extends SuppliedItem {
public CacheDetailed() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.PAPER);
builder.setDisplayName("§6Invalidate specific skin...");
builder.addLoreLines("§7Select a specific skin to invalidate.");
return builder;
}, (click) -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
new CacheDetailedGUI(click.getPlayer()).open();
return true;
}
return false;
});
}
}

View file

@ -1,36 +0,0 @@
package net.artelnatif.nicko.gui.items.admin.cache;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.i18n.I18N;
import net.artelnatif.nicko.i18n.I18NDict;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class CacheInvalidate extends SuppliedItem {
public CacheInvalidate() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.TNT);
builder.setDisplayName("§fInvalidate §6skin cache");
builder.addLoreLines(
"§c§oNOT RECOMMENDED",
"§7Invalidates every skin entry present in the cache.",
"§7Does not reset player disguises.",
"§7Could be useful if a skin has been updated",
"§7recently and the cache is now outdated.");
return builder;
}, (click) -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
final Player player = click.getPlayer();
click.getEvent().getView().close();
player.sendMessage(I18N.translate(player, I18NDict.Event.Admin.CACHE_CLEAN));
NickoBukkit.getInstance().getMojangAPI().getCache().invalidateAll();
return true;
}
return false;
});
}
}

View file

@ -1,28 +0,0 @@
package net.artelnatif.nicko.gui.items.admin.cache;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.mojang.MojangSkin;
import org.bukkit.Material;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import java.util.Optional;
public class CacheOverview extends SuppliedItem {
public CacheOverview() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
final LoadingCache<String, Optional<MojangSkin>> cache = NickoBukkit.getInstance().getMojangAPI().getCache();
final CacheStats stats = cache.stats();
builder.setDisplayName("§6Skin cache §foverview:");
builder.addLoreLines(
"Request Count: §2" + stats.requestCount(),
"Skin Cached: §2" + Math.round(cache.size()),
"§7§oCache is cleared every 24 hours.",
"§7§o(Click to refresh)");
return builder;
}, (event) -> true);
}
}

View file

@ -1,21 +0,0 @@
package net.artelnatif.nicko.gui.items.admin.cache;
import org.bukkit.Material;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.AsyncItem;
import java.util.UUID;
public class SkinPlaceholder extends AsyncItem {
public SkinPlaceholder(String name) {
super(new ItemBuilder(Material.PAINTING).setDisplayName("§7§oLoading..."), () -> {
final String stringUUID = name.replaceAll("(.{8})(.{4})(.{4})(.{4})(.+)", "$1-$2-$3-$4-$5");
final UUID uuid = UUID.fromString(stringUUID);
final SkullBuilder skull = new SkullBuilder(uuid);
skull.setDisplayName("§6Skin Entry");
skull.addLoreLines("§7Click to invalidate skin");
return skull;
});
}
}

View file

@ -1,23 +0,0 @@
package net.artelnatif.nicko.gui.items.common;
import org.bukkit.Material;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import xyz.xenondevs.invui.window.Window;
public class GoBack extends SuppliedItem {
public GoBack(Gui gui) {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.ARROW);
builder.setDisplayName("Go back");
builder.addLoreLines("§7Return to the previous window.");
return builder;
}, click -> {
click.getEvent().getView().close();
// TODO: 4/1/23 Get title of parent GUI
Window.single().setGui(gui).setTitle("Nicko").open(click.getPlayer());
return true;
});
}
}

View file

@ -1,16 +0,0 @@
package net.artelnatif.nicko.gui.items.common;
import org.bukkit.Material;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class OptionUnavailable extends SuppliedItem {
public OptionUnavailable() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.RED_TERRACOTTA);
builder.setDisplayName("§cFeature unavailable :(");
builder.addLoreLines("§7This button is disabled.");
return builder;
}, click -> true);
}
}

View file

@ -1,25 +0,0 @@
package net.artelnatif.nicko.gui.items.common;
import org.bukkit.Material;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
public class ScrollDown extends ScrollItem {
public ScrollDown() {
super(1);
}
@Override
public ItemProvider getItemProvider(ScrollGui gui) {
ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE);
builder.setDisplayName("§7Scroll down");
if (!gui.canScroll(1))
builder.addLoreLines("§cYou can't scroll further down");
return builder;
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.gui.items.common;
import org.bukkit.Material;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
public class ScrollUp extends ScrollItem {
public ScrollUp() {
super(-1);
}
@Override
public ItemProvider getItemProvider(ScrollGui gui) {
ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE);
builder.setDisplayName("§7Scroll up");
if (!gui.canScroll(-1))
builder.addLoreLines("§cYou've reached the top");
return builder;
}
}

View file

@ -1,17 +0,0 @@
package net.artelnatif.nicko.gui.items.main;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SimpleItem;
public class ExitGUI extends SimpleItem {
public ExitGUI() {
super(new ItemBuilder(Material.OAK_DOOR).setDisplayName("§fExit"), click -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
}
});
}
}

View file

@ -1,42 +0,0 @@
package net.artelnatif.nicko.gui.items.main;
import net.artelnatif.nicko.appearance.AppearanceManager;
import net.artelnatif.nicko.i18n.I18N;
import net.artelnatif.nicko.i18n.I18NDict;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class ResetAppearance extends SuppliedItem {
public ResetAppearance() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.TNT);
builder.setDisplayName("§fReset");
builder.addLoreLines("§7Get rid of your disguise.");
return builder;
}, (event) -> {
final Player player = event.getPlayer();
final ClickType clickType = event.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
final AppearanceManager appearanceManager = AppearanceManager.get(player);
if (!appearanceManager.hasData()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.NONE));
event.getEvent().getView().close();
return true;
}
if (!appearanceManager.reset().isError()) {
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.SUCCESS));
return true;
} else {
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.FAIL));
return false;
}
}
return false;
});
}
}

View file

@ -1,49 +0,0 @@
package net.artelnatif.nicko.gui.items.settings;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.AbstractItem;
import xyz.xenondevs.invui.item.impl.CycleItem;
import xyz.xenondevs.invui.item.impl.SimpleItem;
import java.util.Optional;
public class BungeeCordCycling {
private final ItemProvider[] providers = new ItemProvider[]{
getItemProviderForValue(true),
getItemProviderForValue(false)
};
public AbstractItem get(Player player) {
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
if (profile.isPresent()) {
final NickoProfile nickoProfile = profile.get();
int startingState = nickoProfile.isBungeecordTransfer() ? 0 : 1;
return CycleItem.withStateChangeHandler((observer, integer) -> {
nickoProfile.setBungeecordTransfer(integer != 1);
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
}, startingState, providers);
}
return new SimpleItem(ItemProvider.EMPTY);
}
private ItemProvider getItemProviderForValue(boolean enabled) {
final ItemBuilder builder = new ItemBuilder(Material.COMPASS);
builder.setDisplayName("§6BungeeCord transfer:");
if (enabled) {
builder.addLoreLines("§7> §cDisabled");
builder.addLoreLines("§6§l> §a§lEnabled");
} else {
builder.addLoreLines("§6§l> §c§lDisabled");
builder.addLoreLines("§7> §aEnabled");
}
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
return builder;
}
}

View file

@ -1,63 +0,0 @@
package net.artelnatif.nicko.gui.items.settings;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.i18n.Locale;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.AbstractItem;
import xyz.xenondevs.invui.item.impl.CycleItem;
import xyz.xenondevs.invui.item.impl.SimpleItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class LanguageCycling {
private final ItemProvider[] providers = getItems();
public AbstractItem get(Player player) {
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
if (profile.isPresent()) {
final NickoProfile nickoProfile = profile.get();
int localeOrdinal = nickoProfile.getLocale().ordinal();
return CycleItem.withStateChangeHandler((observer, integer) -> {
nickoProfile.setLocale(Locale.values()[integer]);
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
}, localeOrdinal, providers);
}
return new SimpleItem(ItemProvider.EMPTY);
}
private ItemProvider generateItem(Locale locale, List<Locale> locales) {
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
builder.setDisplayName("§6Select your language:");
for (Locale value : locales) {
if (locale != value) {
builder.addLoreLines("§7> " + value.getName());
} else {
builder.addLoreLines("§6§l> §f" + value.getName());
}
}
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
return builder;
}
private ItemProvider[] getItems() {
final NickoBukkit instance = NickoBukkit.getInstance();
final ArrayList<ItemProvider> items = new ArrayList<>();
final ArrayList<Locale> localesToGenerate = new ArrayList<>();
Collections.addAll(localesToGenerate, Locale.values());
if (!instance.getNickoConfig().isCustomLocale()) {
localesToGenerate.remove(Locale.CUSTOM);
}
localesToGenerate.forEach(locale -> items.add(generateItem(locale, localesToGenerate)));
return items.toArray(new ItemProvider[]{});
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.gui.items.skin;
import net.artelnatif.nicko.anvil.AnvilManager;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class ChangeName extends SuppliedItem {
public ChangeName() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.NAME_TAG);
builder.setDisplayName("§fChange §6name");
builder.addLoreLines("§7Only change your name.");
return builder;
}, click -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
final AnvilManager manager = new AnvilManager(click.getPlayer());
manager.openNameAnvil();
}
return true;
});
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.gui.items.skin;
import net.artelnatif.nicko.anvil.AnvilManager;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class ChangeNameAndSkin extends SuppliedItem {
public ChangeNameAndSkin() {
super(() -> {
final ItemBuilder builder = new ItemBuilder(Material.END_PORTAL_FRAME);
builder.setDisplayName("§6Skin §fand §6name §fchange");
builder.addLoreLines("§7Change both your skin and name.");
return builder;
}, click -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
final AnvilManager manager = new AnvilManager(click.getPlayer());
manager.openNameThenSkinAnvil();
}
return true;
});
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.gui.items.skin;
import net.artelnatif.nicko.anvil.AnvilManager;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class ChangeSkin extends SuppliedItem {
public ChangeSkin(Player player) {
super(() -> {
final SkullBuilder builder = new SkullBuilder(player.getName());
builder.setDisplayName("§fChange §6skin");
builder.addLoreLines("§7Only change your skin.");
return builder;
}, click -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
final AnvilManager manager = new AnvilManager(click.getPlayer());
manager.openSkinAnvil();
}
return true;
});
}
}

View file

@ -1,62 +0,0 @@
package net.artelnatif.nicko.i18n;
import com.github.jsixface.YamlConfig;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.bukkit.entity.Player;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Optional;
public class I18N {
private final static MessageFormat formatter = new MessageFormat("");
private static Locale getLocale(Player player) {
final NickoBukkit instance = NickoBukkit.getInstance();
try {
final Optional<NickoProfile> profile = instance.getDataStore().getData(player.getUniqueId());
return !profile.isPresent() ? Locale.FALLBACK_LOCALE : profile.get().getLocale();
} catch (IllegalArgumentException exception) {
instance.getLogger().severe("Invalid locale provided by " + player.getName() + ", defaulting to " + Locale.FALLBACK_LOCALE.getCode() + ".");
return Locale.FALLBACK_LOCALE;
}
}
public static String translate(Player player, I18NDict key, Object... arguments) {
final NickoBukkit instance = NickoBukkit.getInstance();
final String translation = findTranslation(player, key);
try {
formatter.applyPattern(translation);
return instance.getNickoConfig().getPrefix() + formatter.format(arguments);
} catch (Exception e) {
return instance.getNickoConfig().getPrefix() + key.key();
}
}
public static String translateWithoutPrefix(Player player, I18NDict key, Object... arguments) {
final String translation = findTranslation(player, key);
try {
formatter.applyPattern(translation);
return formatter.format(arguments);
} catch (Exception e) {
return key.key();
}
}
private static String findTranslation(Player player, I18NDict key) {
final NickoBukkit instance = NickoBukkit.getInstance();
final Locale locale = getLocale(player);
String translation;
if (locale == Locale.CUSTOM) {
translation = instance.getLocaleFileManager().get(key.key());
} else {
final InputStream resource = instance.getResource(locale.getCode() + ".yml");
final YamlConfig yamlConfig = YamlConfig.load(resource);
translation = yamlConfig.getString(key.key());
}
return translation;
}
}

View file

@ -1,44 +0,0 @@
package net.artelnatif.nicko.i18n;
public class I18NDict {
private final String key;
public I18NDict(String key) { this.key = key; }
public static class Event {
public static class Admin {
public static final I18NDict CACHE_CLEAN = new I18NDict("event.admin.cache_clear");
}
public static class Disguise {
public static final I18NDict SUCCESS = new I18NDict("event.disguise.success");
public static final I18NDict FAIL = new I18NDict("event.disguise.fail");
}
public static class Undisguise {
public static final I18NDict SUCCESS = new I18NDict("event.undisguise.success");
public static final I18NDict FAIL = new I18NDict("event.undisguise.fail");
public static final I18NDict NONE = new I18NDict("event.undisguise.none");
}
public static class PreviousSkin {
public static final I18NDict SUCCESS = new I18NDict("event.previous_skin_applied.success");
public static final I18NDict FAIL = new I18NDict("event.previous_skin_applied.fail");
}
}
public static class Error {
public static final I18NDict PLAYER_OFFLINE = new I18NDict("error.player_offline");
public static final I18NDict SKIN_FAIL_MOJANG = new I18NDict("error.couldnt_get_skin_from_mojang");
public static final I18NDict SKIN_FAIL_CACHE = new I18NDict("error.couldnt_get_skin_from_cache");
public static final I18NDict NAME_FAIL_MOJANG = new I18NDict("error.couldnt_get_name_from_mojang");
public static final I18NDict INVALID_USERNAME = new I18NDict("error.invalid_username");
public static final I18NDict UNEXPECTED_ERROR = new I18NDict("error.generic");
public static final I18NDict SQL_ERROR = new I18NDict("error.sql");
public static final I18NDict JSON_ERROR = new I18NDict("error.json");
}
public String key() {
return key;
}
}

View file

@ -1,42 +0,0 @@
package net.artelnatif.nicko.i18n;
import com.github.jsixface.YamlConfig;
import net.artelnatif.nicko.NickoBukkit;
import xyz.xenondevs.invui.util.IOUtils;
import java.io.*;
import java.nio.file.Files;
public class LocaleFileManager {
private final File folder = new File(NickoBukkit.getInstance().getDataFolder() + "/lang/");
private final File file = new File(folder, "lang.yml");
public String get(String key) {
if (!file.exists()) return key;
try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
final YamlConfig yamlConfig = YamlConfig.load(inputStream);
return yamlConfig.getString(key);
} catch (IOException e) {
return key;
}
}
public boolean dumpFromLocale(Locale locale) {
if (locale == Locale.CUSTOM) return true;
if (file.exists()) return true;
final InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(locale.getCode() + ".yml");
try {
if (folder.mkdirs()) {
if (file.createNewFile()) {
try (FileOutputStream outputStream = new FileOutputStream(file)) {
IOUtils.copy(inputStream, outputStream, 8192);
}
}
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}

View file

@ -1,38 +0,0 @@
package net.artelnatif.nicko.impl;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.i18n.I18NDict;
import net.artelnatif.nicko.mojang.MojangAPI;
import net.artelnatif.nicko.mojang.MojangSkin;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
public interface Internals {
void updateSelf(Player player);
void updateOthers(Player player);
ActionResult<Void> updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset);
default ActionResult<MojangSkin> fetchSkinTextures(NickoProfile profile, boolean reset) {
Optional<MojangSkin> skin;
try {
final MojangAPI mojang = NickoBukkit.getInstance().getMojangAPI();
final Optional<String> uuid = mojang.getUUID(profile.getSkin());
if (uuid.isPresent()) {
skin = (reset ? mojang.getSkinWithoutCaching(uuid.get()) : mojang.getSkin(uuid.get()));
return skin.map(ActionResult::new).orElseGet(() -> new ActionResult<>(I18NDict.Error.SKIN_FAIL_MOJANG));
}
return new ActionResult<>(I18NDict.Error.NAME_FAIL_MOJANG);
} catch (ExecutionException e) {
return new ActionResult<>(I18NDict.Error.SKIN_FAIL_CACHE);
} catch (IOException e) {
return new ActionResult<>(I18NDict.Error.NAME_FAIL_MOJANG);
}
}
}

View file

@ -1,29 +0,0 @@
package net.artelnatif.nicko.impl;
import org.bukkit.Bukkit;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
public class InternalsProvider {
private static final Logger logger = Logger.getLogger("Internals");
private static Internals internals;
static {
try {
final String packageName = Internals.class.getPackage().getName();
final String bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
final String fullClassName = packageName + "." + bukkitVersion;
final Class<?> clazz = Class.forName(fullClassName);
internals = (Internals) clazz.getConstructors()[0].newInstance();
logger.info("Loaded support for " + bukkitVersion);
} catch (InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException |
ClassCastException exception) {
internals = null;
}
}
public static Internals getInternals() {
return internals;
}
}

View file

@ -1,116 +0,0 @@
package net.artelnatif.nicko.mojang;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import javax.annotation.Nonnull;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class MojangAPI {
public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}";
public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false";
private final Logger logger = Logger.getLogger("MojangAPI");
private final CacheLoader<String, Optional<MojangSkin>> loader = new CacheLoader<String, Optional<MojangSkin>>() {
@Nonnull
public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception {
return getSkinFromMojang(uuid);
}
};
private final LoadingCache<String, Optional<MojangSkin>> cache = CacheBuilder
.newBuilder()
.recordStats()
.expireAfterWrite(24, TimeUnit.HOURS)
.build(loader);
public Optional<MojangSkin> getSkin(String uuid) throws IOException, ExecutionException {
return cache.get(uuid);
}
public Optional<MojangSkin> getSkinWithoutCaching(String uuid) throws IOException {
return getSkinFromMojang(uuid);
}
public Optional<String> getUUID(String name) throws IOException {
final String parametrizedUrl = URL_NAME.replace("{name}", name);
final JsonObject object = getRequestToUrl(parametrizedUrl);
if (hasNoError(object)) {
return Optional.of(object.get("id").getAsString());
}
return Optional.empty();
}
private Optional<MojangSkin> getSkinFromMojang(String uuid) throws IOException {
final String parametrizedUrl = URL_SKIN.replace("{uuid}", uuid);
final JsonObject object = getRequestToUrl(parametrizedUrl);
if (hasNoError(object)) {
final MojangSkin skin = MojangSkin.buildFromJson(object);
return Optional.of(skin);
}
return Optional.empty();
}
private JsonObject getRequestToUrl(String parametrizedUrl) throws IOException {
final URL url = new URL(parametrizedUrl);
final HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoInput(true);
con.setRequestMethod("GET");
switch (con.getResponseCode()) {
case 400:
logger.warning("Failed to parse request: Invalid Name");
return getErrorObject();
case 429:
logger.warning("Failed to parse request: The connection is throttled.");
return getErrorObject();
case 200:
final BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
final StringBuilder builder = new StringBuilder();
String line;
while ((line = input.readLine()) != null) {
builder.append(line);
}
try {
final JsonElement jsonElt = JsonParser.parseString(builder.toString());
return jsonElt.getAsJsonObject();
} catch (JsonParseException | IllegalStateException exception) {
logger.warning("Failed to parse request (" + parametrizedUrl + ")!");
return getErrorObject();
}
default:
logger.warning("Unhandled response code from Mojang: " + con.getResponseCode());
return getErrorObject();
}
}
private JsonObject getErrorObject() {
final JsonObject errorObject = new JsonObject();
errorObject.addProperty("error", "An error occurred.");
return errorObject;
}
private boolean hasNoError(JsonObject object) {
return object.get("error") == null;
}
public LoadingCache<String, Optional<MojangSkin>> getCache() {
return cache;
}
}

View file

@ -1,19 +0,0 @@
package net.artelnatif.nicko.placeholder;
import net.artelnatif.nicko.NickoBukkit;
import org.bukkit.Bukkit;
public class PlaceHolderHook {
private final NickoBukkit instance;
public PlaceHolderHook(NickoBukkit instance) {
this.instance = instance;
}
public void hook() {
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
instance.getLogger().info("Enabling PlaceHolderAPI support...");
new NickoExpansion(instance).register();
}
}
}

View file

@ -1,92 +0,0 @@
package net.artelnatif.nicko.storage;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.i18n.I18NDict;
import net.artelnatif.nicko.mojang.MojangAPI;
import net.artelnatif.nicko.mojang.MojangUtils;
import net.artelnatif.nicko.storage.cache.Cache;
import net.artelnatif.nicko.storage.cache.redis.RedisCache;
import net.artelnatif.nicko.storage.json.JSONStorage;
import net.artelnatif.nicko.storage.sql.SQLStorage;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.util.HashMap;
import java.util.Optional;
import java.util.UUID;
public class PlayerDataStore {
private final Storage storage;
private final Cache cache;
private final MojangAPI mojangAPI;
private final HashMap<UUID, NickoProfile> profiles = new HashMap<>();
public PlayerDataStore(MojangAPI mojangAPI, Configuration configuration) {
this.mojangAPI = mojangAPI;
this.storage = configuration.isLocal() ? new JSONStorage() : new SQLStorage(configuration);
this.cache = new RedisCache(); // The only option for now!
}
public void performProfileUpdate(UUID uuid, NickoProfile profile) {
if (!profiles.containsKey(uuid)) {
profiles.put(uuid, profile);
return;
}
profiles.replace(uuid, profile);
}
public Optional<NickoProfile> getData(UUID uuid) {
if (storage.isError()) {
return Optional.empty();
}
if (profiles.containsKey(uuid)) {
return Optional.of(profiles.get(uuid));
} else if (storage.isStored(uuid)) {
final Optional<NickoProfile> retrievedProfile = storage.retrieve(uuid);
retrievedProfile.ifPresent(profile -> profiles.put(uuid, profile));
return retrievedProfile;
} else {
final NickoProfile newProfile = NickoProfile.EMPTY_PROFILE.clone();
profiles.put(uuid, newProfile);
return Optional.of(newProfile);
}
}
public Optional<NickoProfile> getOfflineData(String name) {
if (storage.isError()) {
return Optional.empty();
}
try {
final Optional<String> uuidTrimmed = mojangAPI.getUUID(name);
if (uuidTrimmed.isPresent()) {
final UUID uuid = MojangUtils.fromTrimmed(uuidTrimmed.get());
return getData(uuid);
}
return Optional.empty();
} catch (IOException e) {
return Optional.empty();
}
}
public ActionResult<Void> saveData(Player player) {
if (storage.isError()) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
if (!profiles.containsKey(player.getUniqueId())) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
final ActionResult<Void> store = storage.store(player.getUniqueId(), profiles.get(player.getUniqueId()));
profiles.remove(player.getUniqueId());
return store;
}
public Storage getStorage() {
return storage;
}
public Cache getCache() {
return cache;
}
}

View file

@ -1,31 +0,0 @@
package net.artelnatif.nicko.storage.cache.redis;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import net.artelnatif.nicko.storage.cache.Cache;
import net.artelnatif.nicko.storage.cache.CacheProvider;
import java.util.Optional;
import java.util.UUID;
public class RedisCache extends Cache {
@Override
public CacheProvider getProvider() {
return null;
}
@Override
public ActionResult<Void> cache(UUID uuid, NickoProfile profile) {
return null;
}
@Override
public boolean isCached(UUID uuid) {
return false;
}
@Override
public Optional<NickoProfile> retrieve(UUID uuid) {
return Optional.empty();
}
}

View file

@ -1,26 +0,0 @@
package net.artelnatif.nicko.storage.cache.redis;
import net.artelnatif.nicko.storage.cache.CacheProvider;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisCacheProvider implements CacheProvider {
private JedisPool pool;
@Override
public boolean init() {
// TODO: 3/12/23 Get port from configuration
pool = new JedisPool("localhost", 6379);
return !pool.isClosed() && pool.getResource() != null;
}
@Override
public boolean close() {
pool.close();
return pool.isClosed();
}
public Jedis getJedis() {
return pool.getResource();
}
}

View file

@ -1,22 +0,0 @@
error:
couldnt_get_name_from_mojang: "Failed to get username from Mojang"
couldnt_get_skin_from_cache: "Failed to get skin from cache"
couldnt_get_skin_from_mojang: "Failed to get skin from Mojang"
generic: "Unknown error"
invalid_username: "§cThe specified username is not a valid Minecraft username."
player_offline: "§c{0} §fis offline, please try again."
sql: "SQL Error"
json: "JSON Error"
event:
admin:
cache_clear: "§aSkin cache cleaned."
disguise:
fail: "§cUnable to apply your disguise. §7§o({0})"
success: "§aDisguise applied!"
previous_skin_applied:
fail: "§cFailed to apply your previous disguise back. §7§o({0})"
success: "§aYour previous active disguise has been applied back."
undisguise:
fail: "§cUnable to remove your disguise. It will be set back to default on your next login. Sorry!"
none: "§cYou do not have an active disguise."
success: "§aDisguise removed."

View file

@ -1,22 +0,0 @@
error:
couldnt_get_name_from_mojang: "Impossible de récupérer le nom d''utilisateur depuis Mojang"
couldnt_get_skin_from_cache: "Impossible de récupérer le skin depuis le cache"
couldnt_get_skin_from_mojang: "Impossible de récupérer le skin depuis Mojang"
generic: "Erreur inconnue"
invalid_username: "§cLe pseudo spécifié n''est pas un pseudo Minecraft valide."
player_offline: "§c{0} §fest hors-ligne, veuillez réessayer."
sql: "Erreur SQL"
json: "Erreur JSON"
event:
admin:
cache_clear: "§aCache des skins nettoyé."
disguise:
fail: "§cImpossible d''appliquer votre déguisement. §7§o({0})"
success: "§aDéguisement appliqué !"
previous_skin_applied:
fail: "§cImpossible d''appliquer votre déguisement précédent. §7§o({0})"
success: "§aVotre précédent déguisement a été réappliqué."
undisguise:
fail: "§cImpossible de retier votre déguisement. Il sera remis par défaut à votre prochaine reconnexion. Désolé !"
none: "§cVous n''avez pas de déguisement."
success: "§aDéguisement retiré."

View file

@ -1,17 +0,0 @@
name: Nicko
main: net.artelnatif.nicko.NickoBukkit
version: 1.0-SNAPSHOT
author: Aro
api-version: 1.13
softdepend: [ PlaceholderAPI ]
commands:
nicko:
description: "Opens Nicko's GUI."
permission: nicko.admin
permissions:
nicko.*:
default: op
children:
- nicko.use
nicko.use:
default: op

View file

@ -1,36 +0,0 @@
package net.artelnatif.nicko.test;
import be.seeseemelk.mockbukkit.MockBukkit;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.config.DataSourceConfiguration;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class NickoPluginTest {
private static NickoBukkit plugin;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
DataSourceConfiguration.SQL_EMPTY,
DataSourceConfiguration.REDIS_EMPTY,
"",
true,
false);
MockBukkit.mock();
plugin = MockBukkit.load(NickoBukkit.class, config);
}
@Test
@DisplayName("Plugin Initialization")
public void initializePlugin() {
assertNotNull(plugin);
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,33 +0,0 @@
package net.artelnatif.nicko.test.config;
import be.seeseemelk.mockbukkit.MockBukkit;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.config.Configuration;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ConfigurationTest {
private static NickoBukkit plugin;
@BeforeAll
public static void setup() {
MockBukkit.mock();
plugin = MockBukkit.load(NickoBukkit.class);
}
@Test
@DisplayName("Read configuration")
public void readConfiguration() {
final Configuration configuration = plugin.getNickoConfig();
assertTrue(configuration.isLocal());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,62 +0,0 @@
package net.artelnatif.nicko.test.storage;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.config.DataSourceConfiguration;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.junit.jupiter.api.*;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BrokenSQLTest {
private static ServerMock server;
private static NickoBukkit plugin;
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
DataSourceConfiguration.SQL_EMPTY,
DataSourceConfiguration.REDIS_EMPTY,
"",
false,
false);
server = MockBukkit.mock();
plugin = MockBukkit.load(NickoBukkit.class, config);
player = server.addPlayer();
}
@Test
@DisplayName("Fail to create Tables")
public void createSQLTables() {
assertTrue(plugin.getDataStore().getStorage().isError());
}
@Test
@DisplayName("Fail to Store Player Via SQL")
public void storePlayer() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertFalse(optionalProfile.isPresent());
ActionResult<Void> result = plugin.getDataStore().saveData(player);
assertTrue(result.isError());
}
@Test
@DisplayName("Fail to Retrieve Player Via SQL")
public void retrievePlayer() {
final Optional<NickoProfile> storeAction = plugin.getDataStore().getData(player.getUniqueId());
assertFalse(storeAction.isPresent());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,117 +0,0 @@
package net.artelnatif.nicko.test.storage;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.config.DataSourceConfiguration;
import net.artelnatif.nicko.i18n.Locale;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.disguise.ActionResult;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.junit.jupiter.api.*;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SQLStorageTest {
private static ServerMock server;
private static NickoBukkit plugin;
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
new DataSourceConfiguration("127.0.0.1", 3306, "root", "12345"),
DataSourceConfiguration.REDIS_EMPTY,
"",
false,
false);
server = MockBukkit.mock();
plugin = MockBukkit.load(NickoBukkit.class, config);
player = server.addPlayer();
}
@Test
@DisplayName("Create SQL Tables")
@Order(1)
public void createSQLTables() {
assertFalse(plugin.getDataStore().getStorage().isError());
}
@Test
@DisplayName("Store Player Via SQL")
@Order(2)
public void storePlayer() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
}
@Test
@DisplayName("Retrieve Player Via SQL")
@Order(3)
public void retrievePlayer() {
final Optional<NickoProfile> storeAction = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(storeAction.isPresent());
}
@Test
@DisplayName("Update Player Via SQL")
@Order(4)
public void updatePlayer() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
final NickoProfile profile = optionalProfile.get();
Assertions.assertNull(profile.getName());
Assertions.assertNull(profile.getSkin());
Assertions.assertEquals(profile.getLocale(), Locale.ENGLISH);
assertTrue(profile.isBungeecordTransfer());
profile.setName("Notch");
profile.setSkin("Notch");
profile.setLocale(Locale.FRENCH);
profile.setBungeecordTransfer(false);
final ActionResult<Void> result = plugin.getDataStore().saveData(player);
assertFalse(result.isError());
final Optional<NickoProfile> optionalUpdatedProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalUpdatedProfile.isPresent());
final NickoProfile updatedProfile = optionalProfile.get();
Assertions.assertEquals(updatedProfile.getName(), "Notch");
Assertions.assertEquals(updatedProfile.getSkin(), "Notch");
Assertions.assertEquals(updatedProfile.getLocale(), Locale.FRENCH);
assertFalse(updatedProfile.isBungeecordTransfer());
}
@Test
@DisplayName("Remove Player Disguise Via SQL")
@Order(5)
public void removePlayerDisguise() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
final NickoProfile profile = optionalProfile.get();
profile.setName(null);
profile.setSkin(null);
final ActionResult<Void> result = plugin.getDataStore().saveData(player);
assertFalse(result.isError());
final Optional<NickoProfile> optionalUpdatedProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalUpdatedProfile.isPresent());
final NickoProfile updatedProfile = optionalProfile.get();
Assertions.assertNull(updatedProfile.getName());
Assertions.assertNull(updatedProfile.getSkin());
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

View file

@ -1,49 +0,0 @@
package net.artelnatif.nicko.test.storage.cache;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import net.artelnatif.nicko.NickoBukkit;
import net.artelnatif.nicko.config.Configuration;
import net.artelnatif.nicko.config.DataSourceConfiguration;
import net.artelnatif.nicko.disguise.NickoProfile;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class CacheStorageTest {
private static ServerMock server;
private static NickoBukkit plugin;
private static PlayerMock player;
@BeforeAll
public static void setup() {
final Configuration config = new Configuration(
new DataSourceConfiguration("127.0.0.1", 3306, "root", "12345"),
DataSourceConfiguration.REDIS_EMPTY,
"",
false,
false);
server = MockBukkit.mock();
plugin = MockBukkit.load(NickoBukkit.class, config);
player = server.addPlayer();
}
@Test
@DisplayName("Cache Player Data")
public void cachePlayerData() {
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
assertTrue(optionalProfile.isPresent());
//assertTrue(plugin.getDataStore().isCached(player.getUniqueId()));
}
@AfterAll
public static void shutdown() {
MockBukkit.unmock();
}
}

115
dist/pom.xml vendored
View file

@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.artelnatif</groupId>
<artifactId>nicko-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>dist</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<directory>../target</directory>
<finalName>nicko-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.1-SNAPSHOT</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>net.artelnatif:*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>core</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_13_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_13_R2</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_14_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_15_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_16_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_16_R2</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_16_R3</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_17_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_18_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_18_R2</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_19_R1</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_19_R2</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>net.artelnatif</groupId>
<artifactId>v1_19_R3</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

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

Binary file not shown.

View file

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

251
gradlew vendored Executable file
View file

@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

94
gradlew.bat vendored Normal file
View file

@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

35
pom.xml
View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.artelnatif</groupId>
<artifactId>nicko-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Nicko</name>
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>dist</module>
<module>v1_13_R1</module>
<module>v1_13_R2</module>
<module>v1_14_R1</module>
<module>v1_15_R1</module>
<module>v1_16_R1</module>
<module>v1_16_R2</module>
<module>v1_16_R3</module>
<module>v1_17_R1</module>
<module>v1_18_R1</module>
<module>v1_18_R2</module>
<module>v1_19_R1</module>
<module>v1_19_R2</module>
<module>v1_19_R3</module>
</modules>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>

2
settings.gradle.kts Normal file
View file

@ -0,0 +1,2 @@
rootProject.name = "nicko"

View file

@ -0,0 +1,176 @@
package xyz.ineanto.nicko;
import com.comphenix.protocol.utility.MinecraftVersion;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.plugin.java.JavaPlugin;
import xyz.ineanto.nicko.appearance.random.RandomNameFetcher;
import xyz.ineanto.nicko.command.NickoCommand;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.config.ConfigurationManager;
import xyz.ineanto.nicko.event.PlayerJoinListener;
import xyz.ineanto.nicko.event.PlayerQuitListener;
import xyz.ineanto.nicko.language.CustomLanguage;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.migration.ConfigurationMigrator;
import xyz.ineanto.nicko.migration.CustomLocaleMigrator;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.ineanto.nicko.placeholder.NickoExpansion;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.json.JSONStorage;
import xyz.ineanto.nicko.storage.map.MapCache;
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
import xyz.xenondevs.invui.InvUI;
import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SimpleItem;
import java.io.IOException;
public class Nicko extends JavaPlugin {
private static Nicko plugin;
private MojangAPI mojangAPI;
private PlayerDataStore dataStore;
private ConfigurationManager configurationManager;
private Configuration configuration;
private CustomLanguage customLanguage;
private PlayerNameStore nameStore;
private RandomNameFetcher nameFetcher;
@Override
public void onEnable() {
plugin = this;
configurationManager = new ConfigurationManager(getDataFolder());
configurationManager.saveDefaultConfig();
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
getLogger().severe("As of version 1.2.0, Nicko only supports the latest Minecraft version. (Currently 1.21.5)");
dataStore.getStorage().setError(true);
Bukkit.getPluginManager().disablePlugin(this);
}
if (!Bukkit.getOnlineMode()) {
getLogger().warning("Nicko has not been tested using offline mode!");
getLogger().warning("Issues regarding Nicko being used in offline mode will be ignored for now.");
}
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServerInitEvent");
getLogger().warning("Nicko has not been tested against Folia and might not work at all!");
getLogger().warning("Issues regarding Nicko on Folia will be ignored for now.");
} catch (ClassNotFoundException ignored) { }
getLogger().info("Loading persistence...");
if (!dataStore.getStorage().getProvider().init()) {
getLogger().severe("Couldn't connect to distant persistence, falling back on local persistence.");
final JSONStorage storage = new JSONStorage();
storage.getProvider().init();
dataStore.setStorage(storage);
}
getLogger().info("Loading cache...");
if (!dataStore.getCache().getProvider().init()) {
getLogger().severe("Couldn't connect to distant cache, falling back on local cache.");
final MapCache cache = new MapCache();
cache.getProvider().init();
dataStore.setCache(cache);
}
nameStore = new PlayerNameStore();
mojangAPI = new MojangAPI();
nameFetcher = new RandomNameFetcher(this);
new ConfigurationMigrator(this).migrate();
InvUI.getInstance().setPlugin(this);
if (configuration.isCustomLocale()) {
try {
CustomLanguage.dumpIntoFile(Language.ENGLISH);
customLanguage = new CustomLanguage();
new CustomLocaleMigrator(this, customLanguage).migrate();
getLogger().info("Successfully loaded the custom locale.");
} catch (IOException e) {
getLogger().severe("Failed to load the custom locale!");
}
}
registerCommand("nicko", new NickoCommand());
Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.AIR)));
Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
getLogger().info("Enabling PlaceHolderAPI support...");
new NickoExpansion(this).register();
}
getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this);
getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this);
getLogger().info("Nicko has been enabled.");
}
@Override
public void onDisable() {
if (!getDataStore().getStorage().isError()) {
Bukkit.getOnlinePlayers().forEach(player -> dataStore.saveData(player));
if (!dataStore.getStorage().getProvider().close()) {
getLogger().severe("Failed to close persistence!");
} else {
getLogger().info("Persistence closed.");
}
}
nameStore.clearStoredNames();
getLogger().info("Nicko (Bukkit) has been disabled.");
}
public static Nicko getInstance() {
return plugin;
}
public Configuration getNickoConfig() {
try {
if (configuration == null) {
configuration = configurationManager.load();
getLogger().info("Configuration file loaded.");
}
return configuration;
} catch (IOException e) {
getLogger().severe("Failed to load the configuration file!");
getLogger().severe("It may be have been generated with an older version of Nicko.");
getLogger().severe("Delete the configuration and restart the server please :)");
getLogger().severe("(" + e.getMessage() + ")");
return null;
}
}
public RandomNameFetcher getNameFetcher() {
return nameFetcher;
}
public PlayerDataStore getDataStore() {
return dataStore;
}
public ConfigurationManager getConfigurationManager() {
return configurationManager;
}
public PlayerNameStore getNameStore() {
return nameStore;
}
public MojangAPI getMojangAPI() {
return mojangAPI;
}
public CustomLanguage getCustomLocale() {
return customLanguage;
}
}

View file

@ -0,0 +1,35 @@
package xyz.ineanto.nicko.appearance;
public class ActionResult {
private final String errorKey;
private boolean error = false;
public static ActionResult ok() {
return new ActionResult();
}
public static ActionResult error() {
return new ActionResult(null);
}
public static ActionResult error(String errorMessage) {
return new ActionResult(errorMessage);
}
private ActionResult() {
this.errorKey = null;
}
private ActionResult(String errorMessage) {
this.errorKey = errorMessage;
this.error = true;
}
public boolean isError() {
return error;
}
public String getErrorKey() {
return errorKey;
}
}

View file

@ -0,0 +1,8 @@
package xyz.ineanto.nicko.appearance;
import javax.annotation.Nullable;
public record Appearance(
@Nullable String name,
@Nullable String skin
) {}

View file

@ -0,0 +1,70 @@
package xyz.ineanto.nicko.appearance;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent;
import xyz.ineanto.nicko.event.custom.PlayerResetDisguiseEvent;
import xyz.ineanto.nicko.packet.PacketSender;
import xyz.ineanto.nicko.packet.PaperPacketSender;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
import java.util.Optional;
public class AppearanceManager {
private final Nicko instance = Nicko.getInstance();
private final PlayerDataStore dataStore = instance.getDataStore();
private final PlayerNameStore nameStore = instance.getNameStore();
private final PacketSender packetSender;
private final Player player;
public AppearanceManager(Player player) {
this.player = player;
this.packetSender = new PaperPacketSender(player, getNickoProfile());
}
public ActionResult reset() {
final NickoProfile profile = getNickoProfile();
// Call the event.
final PlayerResetDisguiseEvent event = new PlayerResetDisguiseEvent(player);
Bukkit.getPluginManager().callEvent(event);
profile.setName(null);
profile.setSkin(null);
dataStore.getCache().cache(player.getUniqueId(), profile);
return ActionResult.error();
}
public ActionResult update(boolean skinChange) {
final NickoProfile profile = getNickoProfile();
final String displayName = profile.getName() == null ? player.getName() : profile.getName();
final ActionResult result = packetSender.updatePlayerProfile(displayName);
if (skinChange) {
final ActionResult propertiesUpdateResult = packetSender.updatePlayerProfileProperties();
if (propertiesUpdateResult.isError()) {
return reset();
}
}
// Call the event.
final PlayerDisguiseEvent event = new PlayerDisguiseEvent(player, profile.getSkin(), profile.getName());
Bukkit.getPluginManager().callEvent(event);
packetSender.sendEntityMetadataUpdate();
packetSender.sendTabListUpdate(displayName);
return result;
}
private NickoProfile getNickoProfile() {
final Optional<NickoProfile> optionalProfile = dataStore.getData(player.getUniqueId());
return optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone());
}
}

View file

@ -0,0 +1,36 @@
package xyz.ineanto.nicko.appearance.random;
import xyz.ineanto.nicko.Nicko;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class RandomNameFetcher {
private final Nicko instance;
public RandomNameFetcher(Nicko instance) {
this.instance = instance;
}
public String getRandomUsername() {
final InputStream resource = instance.getResource("names.txt");
final List<List<String>> records = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource))) {
String line;
while ((line = reader.readLine()) != null) {
final String[] values = line.split("\n");
records.add(Arrays.asList(values));
}
return records.get(new Random().nextInt(records.size() - 1)).getFirst();
} catch (IOException e) {
instance.getLogger().severe("Unable to fetch random names.");
return "Ineanto";
}
}
}

View file

@ -0,0 +1,69 @@
package xyz.ineanto.nicko.command;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jspecify.annotations.Nullable;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.config.Configuration;
import xyz.ineanto.nicko.gui.HomeGUI;
import xyz.ineanto.nicko.language.Language;
import xyz.ineanto.nicko.language.PlayerLanguage;
import java.util.Collection;
import java.util.List;
@SuppressWarnings("UnstableApiUsage")
public class NickoCommand implements BasicCommand {
@Override
public void execute(CommandSourceStack stack, String[] args) {
final Entity executor = stack.getExecutor();
final Player player = (Player) executor;
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
if (player == null) { return; }
if (args.length >= 1 && args[0].equalsIgnoreCase("about")) {
final Component firstAboutMessage = MiniMessage.miniMessage().deserialize(
"<prefix> <dark_gray>(© Ineanto 2023-2025) </dark_gray><gray>v<version></gray> ",
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
Placeholder.unparsed("version", Nicko.getInstance().getPluginMeta().getVersion())
);
final Component secondAboutMessage = MiniMessage.miniMessage().deserialize(
"<gradient:#01a97c:#8ffd54>Configuration</gradient> <gray>v<configversion></gray>, <gradient:#01a97c:#8ffd54>I18N</gradient> <gray><i18nversion></gray>",
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
Placeholder.unparsed("configversion", Configuration.VERSION.toString()),
Placeholder.unparsed("i18nversion", Language.VERSION.toString())
);
player.sendMessage(firstAboutMessage);
player.sendMessage(secondAboutMessage);
return;
}
new HomeGUI(player).open();
}
@Override
public boolean canUse(CommandSender sender) {
return sender instanceof Player && sender.isOp() || sender.hasPermission(permission());
}
@Override
public Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args) {
return List.of("about");
}
@Override
public @Nullable String permission() {
return "nicko.use";
}
}

View file

@ -0,0 +1,54 @@
package xyz.ineanto.nicko.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import xyz.ineanto.nicko.version.Version;
public class Configuration {
public static final Version VERSION = new Version(1, 2, 0);
public static final Configuration DEFAULT = new Configuration(VERSION.toString(),
DefaultDataSources.SQL_EMPTY,
DefaultDataSources.REDIS_EMPTY,
false);
private final transient Version versionObject;
@JsonProperty("version")
private final String version;
@JsonProperty("sql")
private final SQLDataSourceConfiguration sqlConfiguration;
@JsonProperty("redis")
private final DataSourceConfiguration redisConfiguration;
@JsonProperty("customLocale")
private final Boolean customLocale;
public Configuration(@JsonProperty("version") String version,
@JsonProperty("sql") SQLDataSourceConfiguration sqlConfiguration,
@JsonProperty("redis") DataSourceConfiguration redisConfiguration,
@JsonProperty("customLocale") Boolean customLocale) {
this.version = version;
this.versionObject = Version.fromString(version);
this.sqlConfiguration = sqlConfiguration;
this.redisConfiguration = redisConfiguration;
this.customLocale = customLocale;
}
public String getVersion() {
return version;
}
public Version getVersionObject() {
return versionObject;
}
public SQLDataSourceConfiguration getSqlConfiguration() {
return sqlConfiguration;
}
public DataSourceConfiguration getRedisConfiguration() {
return redisConfiguration;
}
public Boolean isCustomLocale() {
return customLocale;
}
}

View file

@ -1,4 +1,4 @@
package net.artelnatif.nicko.config; package xyz.ineanto.nicko.config;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -7,16 +7,23 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.*; import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.logging.Logger; import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class ConfigurationManager { public class ConfigurationManager {
private final Logger logger = Logger.getLogger("ConfigurationManager");
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
private final File file; private final File file;
private final File backupFile;
public ConfigurationManager(File directory) { public ConfigurationManager(File directory) {
final String date = Instant.now()
.atZone(ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
this.file = new File(directory, "config.yml"); this.file = new File(directory, "config.yml");
this.backupFile = new File(directory, "config.old-" + date + ".yml");
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
} }
public void save(Configuration configuration) throws IOException { public void save(Configuration configuration) throws IOException {
@ -31,7 +38,6 @@ public class ConfigurationManager {
try { try {
final InputStream input = getClass().getResourceAsStream("/config.yml"); final InputStream input = getClass().getResourceAsStream("/config.yml");
if (input != null) { if (input != null) {
logger.info("Saved default configuration as config.yml");
Files.createDirectories(file.getParentFile().toPath()); Files.createDirectories(file.getParentFile().toPath());
Files.createFile(file.toPath()); Files.createFile(file.toPath());
Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
@ -47,4 +53,12 @@ public class ConfigurationManager {
return mapper.readValue(reader, Configuration.class); return mapper.readValue(reader, Configuration.class);
} }
} }
public File getFile() {
return file;
}
public File getBackupFile() {
return backupFile;
}
} }

View file

@ -0,0 +1,50 @@
package xyz.ineanto.nicko.config;
public class DataSourceConfiguration {
private final boolean enabled;
private final String address;
private final Integer port;
private final String username;
private final String password;
public DataSourceConfiguration(boolean enabled, String address, Integer port, String username, String password) {
this.enabled = enabled;
this.address = address;
this.port = port;
this.username = username;
this.password = password;
}
public DataSourceConfiguration() { this(false, "", 0, "", ""); }
public boolean isEnabled() {
return enabled;
}
public String getAddress() {
return address;
}
public Integer getPort() {
return port;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
@Override
public String toString() {
return "DataSourceConfiguration{" +
"enabled=" + enabled +
", address='" + address + '\'' +
", port=" + port +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}

View file

@ -0,0 +1,8 @@
package xyz.ineanto.nicko.config;
public class DefaultDataSources {
public static final DataSourceConfiguration REDIS_EMPTY = new DataSourceConfiguration(false, "127.0.0.1", 6379, "", "");
public static final SQLDataSourceConfiguration MARIADB_EMPTY = new SQLDataSourceConfiguration(false, "127.0.0.1", 3306, "root", "", true);
public static final SQLDataSourceConfiguration SQL_EMPTY = new SQLDataSourceConfiguration(false, "127.0.0.1", 3306, "root", "", false);
}

View file

@ -0,0 +1,16 @@
package xyz.ineanto.nicko.config;
public class SQLDataSourceConfiguration extends DataSourceConfiguration {
private final boolean mariadb;
public SQLDataSourceConfiguration() { this(false, "", 0, "", "", true); }
public SQLDataSourceConfiguration(boolean enabled, String address, Integer port, String username, String password, boolean mariadb) {
super(enabled, address, port, username, password);
this.mariadb = mariadb;
}
public boolean isMariadb() {
return mariadb;
}
}

View file

@ -0,0 +1,73 @@
package xyz.ineanto.nicko.event;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.appearance.AppearanceManager;
import xyz.ineanto.nicko.gui.PlayerCheckGUI;
import xyz.ineanto.nicko.gui.PlayerCheckGUIData;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.ineanto.nicko.storage.PlayerDataStore;
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
import xyz.xenondevs.invui.window.Window;
import xyz.xenondevs.invui.window.WindowManager;
import java.util.ArrayList;
import java.util.Optional;
import java.util.UUID;
public class PlayerJoinListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
final Nicko instance = Nicko.getInstance();
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
final PlayerNameStore nameStore = instance.getNameStore();
final PlayerDataStore dataStore = instance.getDataStore();
nameStore.storeName(player);
final Optional<NickoProfile> optionalProfile = dataStore.getData(player.getUniqueId());
optionalProfile.ifPresentOrElse(profile -> {
// Random Skin on connection feature
if (profile.isRandomSkin()) {
final String name = instance.getNameFetcher().getRandomUsername();
final String skin = instance.getNameFetcher().getRandomUsername();
profile.setName(name);
profile.setSkin(skin);
dataStore.updateCache(player.getUniqueId(), profile);
}
if (profile.hasData()) {
final AppearanceManager appearanceManager = new AppearanceManager(player);
final boolean needsASkinChange = profile.getSkin() != null && !profile.getSkin().equals(player.getName());
final ActionResult actionResult = appearanceManager.update(needsASkinChange);
if (!actionResult.isError()) {
player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Restore.OK));
} else {
player.sendMessage(
playerLanguage.translateWithOops(LanguageKey.Event.Appearance.Restore.ERROR,
playerLanguage.translate(actionResult.getErrorKey(), false)
));
}
}
}, () -> instance.getLogger().warning("Failed to load data for " + player.getName()));
@SuppressWarnings("unchecked") final ArrayList<UUID> viewers = (ArrayList<UUID>) PlayerCheckGUIData.VIEWERS.clone();
viewers.forEach(uuid -> {
final Player windowWatcher = Bukkit.getPlayer(uuid);
final Window openWindow = WindowManager.getInstance().getOpenWindow(windowWatcher);
if (openWindow != null) {
final PlayerCheckGUI gui = new PlayerCheckGUI(windowWatcher, Bukkit.getOnlinePlayers());
openWindow.close();
gui.open();
}
});
}
}

View file

@ -0,0 +1,45 @@
package xyz.ineanto.nicko.event;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.ActionResult;
import xyz.ineanto.nicko.gui.PlayerCheckGUI;
import xyz.ineanto.nicko.gui.PlayerCheckGUIData;
import xyz.xenondevs.invui.window.Window;
import xyz.xenondevs.invui.window.WindowManager;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class PlayerQuitListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerQuit(PlayerQuitEvent event) {
final Player player = event.getPlayer();
final ActionResult result = Nicko.getInstance().getDataStore().saveData(player);
if (result.isError()) {
Nicko.getInstance().getLogger().warning("Failed to save data for " + player.getName());
}
// This is a dirty way to do it but could be worse tbh
@SuppressWarnings("unchecked") final ArrayList<UUID> viewers = (ArrayList<UUID>) PlayerCheckGUIData.VIEWERS.clone();
viewers.forEach(uuid -> {
final Player windowWatcher = Bukkit.getPlayer(uuid);
final Window openWindow = WindowManager.getInstance().getOpenWindow(windowWatcher);
if (openWindow != null) {
final List<? extends Player> playersWithoutOffline = Bukkit.getOnlinePlayers()
.stream()
.filter(online -> online.getUniqueId() != player.getUniqueId()).collect(Collectors.toList());
final PlayerCheckGUI gui = new PlayerCheckGUI(windowWatcher, playersWithoutOffline);
openWindow.close();
gui.open();
}
});
}
}

View file

@ -0,0 +1,47 @@
package xyz.ineanto.nicko.event.custom;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class PlayerDisguiseEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS_LIST = new HandlerList();
private boolean isCancelled;
private final Player player;
private final String skin, name;
public PlayerDisguiseEvent(Player player, String skin, String name) {
this.player = player;
this.skin = skin;
this.name = name;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLERS_LIST;
}
public Player getPlayer() {
return player;
}
public String getSkin() {
return skin;
}
public String getName() {
return name;
}
}

View file

@ -0,0 +1,36 @@
package xyz.ineanto.nicko.event.custom;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class PlayerResetDisguiseEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS_LIST = new HandlerList();
private boolean isCancelled;
private final Player player;
public PlayerResetDisguiseEvent(Player player) {
this.player = player;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLERS_LIST;
}
public Player getPlayer() {
return player;
}
}

View file

@ -0,0 +1,49 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.admin.ManageCacheItem;
import xyz.ineanto.nicko.gui.items.admin.ManagePlayerItem;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class AdminGUI {
private final Player player;
private final Gui gui;
private final String title;
public AdminGUI(Player player) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.ADMIN, false);
final HomeGUI parent = new HomeGUI(player);
final GoBackItem backItem = new GoBackItem(player);
final ManagePlayerItem managePlayerItem = new ManagePlayerItem(playerLanguage, player);
this.gui = Gui.normal()
.setStructure(
"# # # # # # # # #",
"# # # S # C # # #",
"B # # # # # # # #"
)
.addIngredient('S', new ManageCacheItem(playerLanguage))
.addIngredient('C', managePlayerItem.get())
.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()))
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public String getTitle() {
return title;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,54 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.admin.cache.CacheStatisticsItem;
import xyz.ineanto.nicko.gui.items.admin.cache.InvalidateCacheItem;
import xyz.ineanto.nicko.gui.items.admin.cache.InvalidateSkinItem;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class CacheManagementGUI {
private final Player player;
private final Gui gui;
private final String title;
public CacheManagementGUI(Player player) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.CACHE, false);
final AdminGUI parent = new AdminGUI(player);
final GoBackItem backItem = new GoBackItem(player);
final CacheStatisticsItem cacheStatisticsItem = new CacheStatisticsItem(player);
final InvalidateCacheItem invalidateCacheItem = new InvalidateCacheItem(player);
final InvalidateSkinItem invalidateSkinItem = new InvalidateSkinItem(player);
this.gui = Gui.normal()
.setStructure(
"# # # # # # # # #",
"# # # S C E # # #",
"B # # # # # # # #"
)
.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()))
.addIngredient('S', cacheStatisticsItem.get())
.addIngredient('C', invalidateCacheItem.get())
.addIngredient('E', invalidateSkinItem.get())
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public String getTitle() {
return title;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,42 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.common.choice.CancelItem;
import xyz.ineanto.nicko.gui.items.common.choice.ChoiceCallback;
import xyz.ineanto.nicko.gui.items.common.choice.ConfirmItem;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SimpleItem;
import xyz.xenondevs.invui.window.Window;
public class ChoiceGUI {
private final Player player;
private final Gui gui;
private final String title;
public ChoiceGUI(Player player, ChoiceCallback callback) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
final ConfirmItem confirmItem = new ConfirmItem(player, callback);
final CancelItem cancelItem = new CancelItem(player, callback);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.CONFIRM, false);
this.gui = Gui.normal()
.setStructure(
"@ @ @ @ % & & & &",
"@ @ @ @ I & & & &",
"@ @ @ @ % & & & &"
)
.addIngredient('@', confirmItem.get())
.addIngredient('&', cancelItem.get())
.addIngredient('I', new SimpleItem(playerLanguage.translateItem(new ItemBuilder(Material.PAPER), LanguageKey.GUI.Choice.CHOOSE)))
.build();
this.player = player;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,84 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.appearance.Appearance;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.gui.items.common.ScrollDownItem;
import xyz.ineanto.nicko.gui.items.common.ScrollUpItem;
import xyz.ineanto.nicko.gui.items.favorites.FavoriteAddItem;
import xyz.ineanto.nicko.gui.items.favorites.FavoriteAppearanceEntryItem;
import xyz.ineanto.nicko.gui.items.favorites.FavoriteRemoveItem;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.profile.NickoProfile;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.window.Window;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class FavoritesGUI {
private final Player player;
private final Gui gui;
private final String title;
public FavoritesGUI(Player player) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.FAVORITES, false);
final HomeGUI parent = new HomeGUI(player);
final GoBackItem backItem = new GoBackItem(player);
final ScrollUpItem scrollUpItem = new ScrollUpItem(playerLanguage);
final ScrollDownItem scrollDownItem = new ScrollDownItem(playerLanguage);
final FavoriteAddItem favoriteAddItem = new FavoriteAddItem(player);
final FavoriteRemoveItem favoriteRemoveItem = new FavoriteRemoveItem(playerLanguage);
final NickoProfile profile = Nicko.getInstance().getDataStore().getData(player.getUniqueId()).orElse(NickoProfile.EMPTY_PROFILE);
final List<Appearance> favorites = profile.getFavorites();
List<Item> items;
if (favorites == null || favorites.isEmpty()) {
items = Collections.emptyList();
} else {
items = favorites.stream()
.map((appearance) -> new FavoriteAppearanceEntryItem(player, appearance).get())
.collect(Collectors.toList());
}
gui = ScrollGui.items(guiItemBuilder -> {
guiItemBuilder.setStructure(
"x x x x x x x x U",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x D",
"% % % A B R % % %");
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
guiItemBuilder.addIngredient('U', scrollUpItem);
guiItemBuilder.addIngredient('D', scrollDownItem);
guiItemBuilder.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()));
guiItemBuilder.addIngredient('A', favoriteAddItem.get());
guiItemBuilder.addIngredient('R', favoriteRemoveItem.get());
guiItemBuilder.setContent(items);
});
this.player = player;
}
public Gui getGUI() {
return gui;
}
public String getTitle() {
return title;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,67 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.appearance.ChangeBothItem;
import xyz.ineanto.nicko.gui.items.appearance.ChangeNameItem;
import xyz.ineanto.nicko.gui.items.appearance.ChangeSkinItem;
import xyz.ineanto.nicko.gui.items.home.*;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class HomeGUI {
private final Player player;
private final Gui gui;
private final String title;
public HomeGUI(Player player) {
final String[] dynamicStructure = new String[]{
"# # # # D # # # #",
"A # # N B S # # #",
"E P # # F # # # R"};
if (!player.isOp() || !player.hasPermission("nicko.admin")) {
dynamicStructure[2] = dynamicStructure[2].replace("A", "#");
}
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.HOME, false);
final ExitItem exitItem = new ExitItem(player);
final ResetItem resetItem = new ResetItem(player);
final ChangeNameItem changeNameItem = new ChangeNameItem(player);
final ChangeBothItem changeBothItem = new ChangeBothItem(player);
final ChangeSkinItem changeSkinItem = new ChangeSkinItem(player);
final SettingsAccessItem settingsAccessItem = new SettingsAccessItem(player);
final AdminAccessItem adminAccessItem = new AdminAccessItem(player);
final RandomSkinItem randomSkinItem = new RandomSkinItem(player);
final FavoritesItem favoritesItem = new FavoritesItem(player);
this.gui = Gui.normal()
.setStructure(dynamicStructure)
.addIngredient('E', exitItem.get())
.addIngredient('R', resetItem.get())
.addIngredient('N', changeNameItem.get())
.addIngredient('B', changeBothItem.get())
.addIngredient('S', changeSkinItem.get())
.addIngredient('P', settingsAccessItem.get())
.addIngredient('A', adminAccessItem.get())
.addIngredient('D', randomSkinItem.get())
.addIngredient('F', favoritesItem.get())
.build();
this.player = player;
}
public Gui getGUI() {
return gui;
}
public String getTitle() {
return title;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,69 @@
package xyz.ineanto.nicko.gui;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.gui.items.common.ScrollUpItem;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.gui.items.admin.cache.CacheEntryItem;
import xyz.ineanto.nicko.gui.items.common.ScrollDownItem;
import org.bukkit.entity.Player;
import xyz.xenondevs.invui.window.Window;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
public class InvalidateSkinGUI {
private final Player player;
private final Gui gui;
private final String title;
public InvalidateSkinGUI(Player player) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.INVALIDATE_SKIN, false);
final ConcurrentMap<String, Optional<MojangSkin>> skins = Nicko.getInstance().getMojangAPI().getSkinCache().asMap();
final List<String> loadedSkins = skins.entrySet().stream()
.filter(entry -> entry.getValue().isPresent())
.map(Map.Entry::getKey)
.toList();
final List<Item> items = loadedSkins.stream()
.map(uuid -> new CacheEntryItem(playerLanguage, uuid))
.collect(Collectors.toList());
final CacheManagementGUI parent = new CacheManagementGUI(player);
final ScrollUpItem scrollUpItem = new ScrollUpItem(playerLanguage);
final ScrollDownItem scrollDownItem = new ScrollDownItem(playerLanguage);
final GoBackItem backItem = new GoBackItem(player);
gui = ScrollGui.items(guiItemBuilder -> {
guiItemBuilder.setStructure(
"x x x x x x x x U",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x D",
"B % % % % % % % %");
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
guiItemBuilder.addIngredient('U', scrollUpItem);
guiItemBuilder.addIngredient('D', scrollDownItem);
guiItemBuilder.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()));
guiItemBuilder.setContent(items);
});
this.player = player;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,68 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.admin.check.PlayerInformationItem;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.gui.items.common.ScrollDownItem;
import xyz.ineanto.nicko.gui.items.common.ScrollUpItem;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.window.Window;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class PlayerCheckGUI {
private final Player player;
private final Gui gui;
private final String title;
public PlayerCheckGUI(Player player, Collection<? extends Player> players) {
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.CHECK, false);
final List<Item> items = players.stream()
.map(Entity::getUniqueId)
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.map(mappedPlayer -> new PlayerInformationItem(playerLanguage, mappedPlayer))
.collect(Collectors.toList());
final AdminGUI parent = new AdminGUI(player);
final GoBackItem backItem = new GoBackItem(player);
final ScrollUpItem scrollUpItem = new ScrollUpItem(playerLanguage);
final ScrollDownItem scrollDownItem = new ScrollDownItem(playerLanguage);
gui = ScrollGui.items(guiItemBuilder -> {
guiItemBuilder.setStructure(
"x x x x x x x x U",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x #",
"x x x x x x x x D",
"B % % % % % % % %");
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
guiItemBuilder.addIngredient('U', scrollUpItem);
guiItemBuilder.addIngredient('D', scrollDownItem);
guiItemBuilder.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()));
guiItemBuilder.setContent(items);
});
this.player = player;
}
public void open() {
final Window.Builder.Normal.Single window = Window.single().setGui(gui).setTitle(title);
window.addOpenHandler(() -> PlayerCheckGUIData.VIEWERS.add(player.getUniqueId()));
window.addCloseHandler(() -> PlayerCheckGUIData.VIEWERS.remove(player.getUniqueId()));
window.open(player);
}
}

View file

@ -0,0 +1,8 @@
package xyz.ineanto.nicko.gui;
import java.util.ArrayList;
import java.util.UUID;
public class PlayerCheckGUIData {
public static final ArrayList<UUID> VIEWERS = new ArrayList<>();
}

View file

@ -0,0 +1,44 @@
package xyz.ineanto.nicko.gui;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.items.common.GoBackItem;
import xyz.ineanto.nicko.gui.items.settings.LanguageCyclingItem;
import xyz.ineanto.nicko.gui.items.settings.RandomSkinCyclingItem;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.Window;
public class SettingsGUI {
private final Player player;
private final Gui gui;
private final String title;
public SettingsGUI(Player player) {
final String[] dynamicStructure = new String[]{
"# # # # # # # # #",
"# # # L # R # # #",
"B # # # # # # # #"
};
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
this.title = playerLanguage.translate(LanguageKey.GUI.Titles.SETTINGS, false);
final HomeGUI parent = new HomeGUI(player);
final LanguageCyclingItem languageItem = new LanguageCyclingItem(player);
final RandomSkinCyclingItem skinItem = new RandomSkinCyclingItem(player);
final GoBackItem backItem = new GoBackItem(player);
this.gui = Gui.normal()
.setStructure(dynamicStructure)
.addIngredient('B', backItem.get(parent.getGUI(), parent.getTitle()))
.addIngredient('L', languageItem.get())
.addIngredient('R', skinItem.get())
.build();
this.player = player;
}
public void open() {
Window.single().setGui(gui).setTitle(title).open(player);
}
}

View file

@ -0,0 +1,22 @@
package xyz.ineanto.nicko.gui.items;
import org.bukkit.Material;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.item.builder.AbstractItemBuilder;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
public class ItemDefaults {
public static AbstractItemBuilder<?> getErrorSkullItem(PlayerLanguage playerLanguage, String key, Object... args) {
// "Missing Value" (Valve's signature missing texture) Texture Value
final SkullBuilder.HeadTexture headTexture = new SkullBuilder.HeadTexture("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjNmZTU5YjJhMWQyYmYzMjcwNDA2OGVmYzg2MGM3NWY5MjEyYzIzMTBiNDNkMDdjNGJiYTRiNGViMjM0ZTY4NCJ9fX0=");
final SkullBuilder builder = new SkullBuilder(headTexture);
return playerLanguage.translateItem(builder, key, args);
}
public static AbstractItemBuilder<?> getUnavailableItem(PlayerLanguage playerLanguage) {
final ItemBuilder builder = new ItemBuilder(Material.RED_TERRACOTTA);
return playerLanguage.translateItem(builder, LanguageKey.GUI.UNAVAILABLE);
}
}

View file

@ -0,0 +1,46 @@
package xyz.ineanto.nicko.gui.items.admin;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import xyz.ineanto.nicko.gui.CacheManagementGUI;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.xenondevs.invui.item.builder.AbstractItemBuilder;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.AsyncItem;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import xyz.xenondevs.invui.util.MojangApiUtils;
import java.io.IOException;
public class ManageCacheItem extends AsyncItem {
public ManageCacheItem(PlayerLanguage playerLanguage) {
super(new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.PAINTING);
return playerLanguage.translateItem(builder, LanguageKey.GUI.LOADING);
}, (_ -> true)).getItemProvider(),
() -> {
AbstractItemBuilder<?> builder;
try {
builder = new SkullBuilder("Notch");
} catch (MojangApiUtils.MojangApiException | IOException e) {
builder = new ItemBuilder(Material.PLAYER_HEAD);
}
return playerLanguage.translateItem(builder, LanguageKey.GUI.Admin.MANAGE_CACHE);
});
}
@Override
public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
if (clickType.isLeftClick() || clickType.isRightClick()) {
event.getView().close();
new CacheManagementGUI(player).open();
}
}
}

View file

@ -0,0 +1,30 @@
package xyz.ineanto.nicko.gui.items.admin;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.gui.PlayerCheckGUI;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class ManagePlayerItem {
private final Player player;
private final PlayerLanguage playerLanguage;
public ManagePlayerItem(PlayerLanguage playerLanguage, Player player) {
this.playerLanguage = playerLanguage;
this.player = player;
}
public SuppliedItem get() {
return new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.WRITABLE_BOOK);
return playerLanguage.translateItem(builder, LanguageKey.GUI.Admin.MANAGE_PLAYER);
}, _ -> {
new PlayerCheckGUI(player, Bukkit.getOnlinePlayers()).open();
return true;
});
}
}

View file

@ -0,0 +1,72 @@
package xyz.ineanto.nicko.gui.items.admin.cache;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.gui.ChoiceGUI;
import xyz.ineanto.nicko.gui.InvalidateSkinGUI;
import xyz.ineanto.nicko.gui.items.ItemDefaults;
import xyz.ineanto.nicko.gui.items.common.choice.ChoiceCallback;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.mojang.MojangAPI;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.builder.SkullBuilder;
import xyz.xenondevs.invui.item.impl.AsyncItem;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import xyz.xenondevs.invui.util.MojangApiUtils;
import java.io.IOException;
import java.util.UUID;
public class CacheEntryItem extends AsyncItem {
private final String name;
private final String uuid;
private final MojangAPI mojangAPI = Nicko.getInstance().getMojangAPI();
private final PlayerLanguage playerLanguage;
public CacheEntryItem(PlayerLanguage playerLanguage, String uuid) {
super(new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.PAINTING);
return playerLanguage.translateItem(builder, LanguageKey.GUI.LOADING);
}, (_ -> true)).getItemProvider(),
() -> {
final String dashedUuid = uuid.replaceAll("(.{8})(.{4})(.{4})(.{4})(.+)", "$1-$2-$3-$4-$5");
final UUID uuidObject = UUID.fromString(dashedUuid);
try {
final SkullBuilder skull = new SkullBuilder(uuidObject);
return playerLanguage.translateItem(skull, LanguageKey.GUI.Admin.Cache.ENTRY, Nicko.getInstance().getMojangAPI().getUUIDName(uuid));
} catch (MojangApiUtils.MojangApiException | IOException e) {
Nicko.getInstance().getLogger().warning("Unable to get Head texture for specified UUID (" + uuid + ")! (GUI/Cache/Entry)");
return ItemDefaults.getErrorSkullItem(playerLanguage, LanguageKey.GUI.Admin.Cache.ENTRY, Nicko.getInstance().getMojangAPI().getUUIDName(uuid));
}
});
this.playerLanguage = playerLanguage;
this.uuid = uuid;
this.name = mojangAPI.getUUIDName(uuid);
}
@Override
public void handleClick(@NotNull ClickType click, @NotNull Player player, @NotNull InventoryClickEvent event) {
if (click.isLeftClick() || click.isRightClick()) {
event.getView().close();
new ChoiceGUI(player, new ChoiceCallback() {
@Override
public void onConfirm() {
player.sendMessage(playerLanguage.translate(LanguageKey.Event.Admin.Cache.INVALIDATE_ENTRY, true, name));
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1, 1f);
mojangAPI.eraseFromCache(uuid);
}
@Override
public void onCancel() {
new InvalidateSkinGUI(player).open();
}
}).open();
}
}
}

View file

@ -0,0 +1,35 @@
package xyz.ineanto.nicko.gui.items.admin.cache;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.ineanto.nicko.mojang.MojangSkin;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
import java.util.Optional;
public class CacheStatisticsItem {
private final PlayerLanguage playerLanguage;
public CacheStatisticsItem(Player player) {
this.playerLanguage = new PlayerLanguage(player);
}
public SuppliedItem get() {
return new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.BOOK);
final LoadingCache<String, Optional<MojangSkin>> cache = Nicko.getInstance().getMojangAPI().getSkinCache();
final CacheStats stats = cache.stats();
return playerLanguage.translateItem(builder, LanguageKey.GUI.Admin.Cache.STATISTICS,
stats.requestCount(),
Math.round(cache.size())
);
}, (event) -> true);
}
}

View file

@ -0,0 +1,39 @@
package xyz.ineanto.nicko.gui.items.admin.cache;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.ineanto.nicko.Nicko;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class InvalidateCacheItem {
private final PlayerLanguage playerLanguage;
public InvalidateCacheItem(Player player) {
this.playerLanguage = new PlayerLanguage(player);
}
public SuppliedItem get() {
return new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.TNT);
return playerLanguage.translateItem(builder, LanguageKey.GUI.Admin.Cache.INVALIDATE_CACHE);
}, (click) -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
final Player player = click.getPlayer();
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Admin.Cache.INVALIDATE_CACHE));
player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1, 1f);
Nicko.getInstance().getMojangAPI().getSkinCache().invalidateAll();
return true;
}
return false;
});
}
}

View file

@ -0,0 +1,33 @@
package xyz.ineanto.nicko.gui.items.admin.cache;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import xyz.ineanto.nicko.gui.InvalidateSkinGUI;
import xyz.ineanto.nicko.language.PlayerLanguage;
import xyz.ineanto.nicko.language.LanguageKey;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.SuppliedItem;
public class InvalidateSkinItem {
private final PlayerLanguage playerLanguage;
public InvalidateSkinItem(Player player) {
this.playerLanguage = new PlayerLanguage(player);
}
public SuppliedItem get() {
return new SuppliedItem(() -> {
final ItemBuilder builder = new ItemBuilder(Material.PAPER);
return playerLanguage.translateItem(builder, LanguageKey.GUI.Admin.Cache.INVALIDATE_SKIN);
}, (click) -> {
final ClickType clickType = click.getClickType();
if (clickType.isLeftClick() || clickType.isRightClick()) {
click.getEvent().getView().close();
new InvalidateSkinGUI(click.getPlayer()).open();
return true;
}
return false;
});
}
}

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