forked from SteamWar/SteamWar
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b42f0d13c | ||
|
|
4306fe7bc9 | ||
|
|
58df6087f0 | ||
|
|
b9b7869124 | ||
|
|
1e85b14667 | ||
|
|
35c27923aa | ||
|
|
c3b3e3e60f | ||
|
|
3aa1bf7ffd | ||
|
|
5a02a58437 | ||
|
|
6209b86149 | ||
|
|
6f1403df9c | ||
|
|
0113788da2 | ||
|
|
8a7f65e000 | ||
|
|
8401f67b24 | ||
|
|
362468e756 | ||
|
|
ece12df0bc | ||
|
|
f35c07ab5b | ||
|
|
549f7e555c | ||
|
|
859238d7fa | ||
|
|
a79b00f78f | ||
|
|
105eda32e6 | ||
|
|
b4487b8079 | ||
|
|
ea3aad3bd2 | ||
|
|
d307f890e2 | ||
|
|
97c1da1b2a | ||
|
|
8a53aecfac | ||
|
|
5236afba17 | ||
|
|
d3c8b6e1c6 | ||
|
|
00ea792eee | ||
|
|
38e845b0e4 | ||
|
|
c60a8caed8 | ||
|
|
2e390286b2 | ||
|
|
6476125a3f | ||
|
|
311437d451 | ||
|
|
5a52771ec1 | ||
|
|
72b70a62e1 | ||
|
|
8575dcac33 | ||
|
|
cb744f6aa0 | ||
|
|
227f63c9ff | ||
|
|
397b10c319 | ||
|
|
32569f19d9 | ||
|
|
f19e4158e7 | ||
|
|
6c46b5b2a2 | ||
|
|
58516448d9 | ||
|
|
683236bb59 | ||
|
|
8dc101639d | ||
|
|
792620804a | ||
|
|
4aa7c99a6e | ||
|
|
cce18124f2 | ||
|
|
18ad0ad90c | ||
|
|
a58de898bb | ||
|
|
507b7c2569 | ||
|
|
a18098b8f4 | ||
|
|
97773f292d | ||
|
|
5fdfc03587 | ||
|
|
493e66cc98 | ||
|
|
2be3a136ae | ||
|
|
c62a566447 | ||
|
|
0684765a76 | ||
|
|
c40f29c3c1 | ||
|
|
72dc4eee9e | ||
|
|
c7a949322e | ||
|
|
9d5b7893f1 | ||
|
|
ae898e14c2 | ||
|
|
726f73cc45 | ||
|
|
badff1c70f | ||
|
|
1d2ac4f705 | ||
|
|
b48c75ef74 | ||
|
|
8b6ea12a08 | ||
|
|
801678ddd3 | ||
|
|
e5cc874834 | ||
|
|
95119fc93f | ||
|
|
d84ca3547a | ||
|
|
25ab79abc0 | ||
|
|
582d6a62e3 | ||
|
|
5eec792aff
|
||
|
|
e0f26c3e8d
|
||
|
|
a59e9b4343 | ||
|
|
64e627514d | ||
|
|
a8c68864d8 | ||
|
|
c0668723d7 | ||
|
|
5bc2daf37a | ||
|
|
e6d39da36b | ||
|
|
390d388692 | ||
|
|
9a60ac228c | ||
|
|
dab443b989 | ||
|
|
bf3c65c630 | ||
|
|
b488c4ed7c | ||
|
|
2e795aaf8e | ||
|
|
7a601235f5 | ||
|
|
3a247de43d
|
||
|
|
62e855ec1b
|
||
|
|
9e7311934f | ||
|
|
6fd3e6f690
|
||
|
|
7acd51fd61
|
||
|
|
b278ca15f3
|
||
|
|
029249c2b0
|
||
|
|
1ceb10439b
|
||
|
|
a5dfe6ab7e
|
||
|
|
c8a5f567eb | ||
|
|
47fb4da85b
|
||
|
|
0eef22aab0 | ||
|
|
013d18614f | ||
|
|
c7c1ab64e0 | ||
|
|
b68a27fbb6 | ||
|
|
7038dc2aa5
|
||
|
|
7af586ec16
|
||
|
|
b04e99ce54 | ||
|
|
524702fbb9 | ||
|
|
e07298e748 | ||
|
|
e1df793e9f | ||
|
|
806a1affea | ||
|
|
c538cdbbd2 | ||
|
|
d7ba19049a | ||
|
|
47909b6f07 | ||
|
|
48846a698f | ||
|
|
b771c95b99 | ||
|
|
d0aada2b00 | ||
|
|
6522fc77f2 | ||
|
|
27e01a56ae | ||
|
|
ed89770c0f | ||
|
|
3ec3c90f04 | ||
|
|
73d4ed26c8 | ||
|
|
256bcfb1bf | ||
|
|
28ce288815 | ||
|
|
6599dd026a | ||
|
|
03052b677f | ||
|
|
f76a6fa79d | ||
|
|
7fb7f46ca7 | ||
|
|
1269b7f00a | ||
|
|
91a0685724 | ||
|
|
72dd2ef59a | ||
|
|
54a1549973 | ||
|
|
fd5f5b92b4 | ||
|
|
60dc5e4442 | ||
|
|
4cdaf759af | ||
|
|
6e919d9148 | ||
|
|
a20ec8c93d | ||
|
|
18b65a2984 | ||
|
|
669235709e | ||
|
|
796e154c1c | ||
|
|
9efe35fe0d | ||
|
|
e0aaacd66a | ||
|
|
7adb1e8b4a | ||
|
|
b88e592e79 | ||
|
|
914134600e | ||
|
|
27877938bc
|
||
|
|
701964c2f2 | ||
|
|
70c8678c60
|
||
|
|
6cbfc94e6d | ||
|
|
c0ff123279 | ||
|
|
5511a1f08e | ||
|
|
8c8da355bb | ||
|
|
7326ed4aa0 | ||
|
|
2d59eb81c7 | ||
|
|
711920464a | ||
|
|
117dbd08ae | ||
|
|
b36464e69e | ||
|
|
f5ac006c0c | ||
|
|
414bfbfe3c | ||
|
|
c362a3e1f0 | ||
|
|
2b43af8851 | ||
|
|
1590f8f0ee | ||
|
|
932732737d | ||
|
|
2bc164c1b0 | ||
|
|
aa66b3dc83 | ||
|
|
f5d9c6e175 | ||
|
|
36b31fac77 | ||
|
|
641cefad01 | ||
|
|
eb866125ea | ||
|
|
961331f029 | ||
|
|
786257ad0e | ||
|
|
997292d58e | ||
|
|
8050f51424
|
||
|
|
e176b3bca8 | ||
|
|
a6681ffaf6
|
||
|
|
a23530074c
|
||
|
|
e88a4c624b
|
||
|
|
105beaf7a6 | ||
|
|
5f7ab3cd7b
|
||
|
|
f81f05c3d0 | ||
|
|
0afb6ce06a | ||
|
|
5ce69e6b7a
|
||
|
|
a938abde3f | ||
|
|
ec9b0387c5 | ||
|
|
03c3d49659 | ||
|
|
8d9a77ab67 | ||
|
|
fc2997e011 | ||
|
|
8eb5f5ddf2 | ||
|
|
aa807060f4 | ||
|
|
9bbbab9d4b | ||
|
|
7cca4ada10 | ||
|
|
725e6df047 | ||
|
|
f3ce124a23 | ||
|
|
e83f72a53e | ||
|
|
def0c19e43 | ||
|
|
3810ccd63d | ||
|
|
9e43d5cd1b | ||
|
|
2ad9ae3c7f | ||
|
|
847eb3fe5d | ||
|
|
8fa9f7b0d3 | ||
|
|
559cae2b6d | ||
|
|
5dbf3638d0 | ||
|
|
a018af1c8a | ||
|
|
fd8f942014 | ||
|
|
eab8826583 | ||
|
|
bc0177df43 | ||
|
|
1dc78b8eb8 | ||
|
|
a9fb982143 | ||
|
|
5b8d881e01 | ||
|
|
eb55f4b395 | ||
|
|
273db91d06 | ||
|
|
983ad544c1 | ||
|
|
a6a34b2221 | ||
|
|
6c6bd19038 | ||
|
|
89e05cd109 | ||
|
|
ea9d7ac584 | ||
|
|
17e1cf53b0 | ||
|
|
f64f337f17 | ||
|
|
c5f5be7d58 | ||
|
|
9f18644763 | ||
|
|
1de17d27f4 | ||
|
|
3cd0db9bdf | ||
|
|
9711b48f2f | ||
|
|
9934b8bbb2
|
||
|
|
6447265b90 | ||
|
|
71258318db | ||
|
|
52e95e2649 | ||
|
|
de6ac2cf20 | ||
|
|
628001e693 | ||
|
|
47c148d64a | ||
|
|
78617d5a98 | ||
|
|
69b924ded6 | ||
|
|
002f7e5542 | ||
|
|
5d70f75ac9 | ||
|
|
7f21a31ec9 | ||
|
|
23b5ab3e82 | ||
|
|
4f9fe07951 | ||
|
|
3bcff4c5ce | ||
|
|
1810cb7546 | ||
|
|
e55ca911c4 | ||
|
|
793f2de6c3 | ||
|
|
54fa47bd99 | ||
|
|
14a770b207 | ||
|
|
7b3a04f4eb | ||
|
|
f2a06057a8 | ||
|
|
e11f3f7cbc | ||
|
|
ebc10c1ce4 | ||
|
|
d682e35159 | ||
|
|
7d74eb0c09 | ||
|
|
7e18207b87 | ||
|
|
72b23ad116 | ||
|
|
c508627d92 | ||
|
|
93ff982649 | ||
|
|
21f6394359 | ||
|
|
29d0c8978c | ||
|
|
7366f83b15 | ||
|
|
9240bcfd5f | ||
|
|
bede8caa82 | ||
|
|
108aa2af9a | ||
|
|
d07a86c13f | ||
|
|
29106d5bb5 | ||
|
|
32fd4b4630 | ||
|
|
c241aef932 | ||
|
|
2db24ef2eb | ||
|
|
a2caa79f99 | ||
|
|
e49cfa9495 | ||
|
|
1f44b3169e | ||
|
|
49fafa5955 | ||
|
|
c81e6b15e5 | ||
|
|
dc0365834a | ||
|
|
13334e03a4 | ||
|
|
b35b2c0138 | ||
|
|
6ef311ce68 | ||
|
|
68d9c55525 | ||
|
|
dcd70c5ced | ||
|
|
a1d22b7d77 | ||
|
|
3b6fdbeec3 | ||
|
|
714f86a55b | ||
|
|
a177cc4faf | ||
|
|
09aa2ee22c | ||
|
|
b8499a7a8a | ||
|
|
e50bff3d38 | ||
|
|
8424f842c3 | ||
|
|
8f23f57415 | ||
|
|
3b65b93e73 | ||
|
|
4a458f0e92 | ||
|
|
5f5a98bcd6 | ||
|
|
72df919312 | ||
|
|
7ed36fe56e | ||
|
|
a7a8c4d051 | ||
|
|
5da3767378 | ||
|
|
53f98d4cd7 | ||
|
|
48fb6b5ed7 | ||
|
|
24d8ec7301 | ||
|
|
ba29e5cf23 | ||
|
|
a5992a9e4e | ||
|
|
e94eac9b9d
|
||
|
|
a000beee20 | ||
|
|
2fd6c40b15 | ||
|
|
32a2cbb4dd | ||
|
|
cf7a1ee086 | ||
|
|
8da7956523 | ||
|
|
9b821ff08f | ||
|
|
ae6f279dcf | ||
|
|
deb56c0c02 | ||
|
|
aead25650e | ||
|
|
53ada2de83 | ||
|
|
496cc3121c | ||
|
|
e9c766dbbb | ||
|
|
706f6ed743 | ||
|
|
270d82eb71 | ||
|
|
6da180136e | ||
|
|
463d8336a7 | ||
|
|
c241b9c264 | ||
|
|
b98273a7b2
|
||
|
|
bd28b133a2
|
||
|
|
5c618d03e8 | ||
|
|
89b8a3ea42 | ||
|
|
4198a08cda | ||
|
|
9f319128cc | ||
|
|
088d548d61 | ||
|
|
e435154c12 | ||
|
|
eceb58b28c | ||
|
|
5125453406 | ||
|
|
d110df924e | ||
|
|
81dd8045f2 | ||
|
|
245072f02c | ||
|
|
00147f2a74 | ||
|
|
fcc370c353 | ||
|
|
3bd1cf7167 | ||
|
|
cfa650bcf4 | ||
|
|
ba4ee08489 | ||
|
|
723a7dc0ca | ||
|
|
88de28ed68 | ||
|
|
6f1a3fe70c | ||
|
|
4a43e09a8b | ||
|
|
6fb018b86b | ||
|
|
ec310dfee9 | ||
|
|
9de5a93997 | ||
|
|
ce88e88859 | ||
|
|
5589c6cd20
|
||
|
|
35dead9c74 | ||
|
|
f1fbe14e60 | ||
|
|
b146c9928f | ||
|
|
136b0f5b97
|
||
|
|
2d679028c0
|
||
|
|
ce1f947f4b | ||
|
|
5fb51b63c3
|
||
|
|
c04dc8fd86
|
||
|
|
ab3970981d | ||
|
|
9e4c9ce04a | ||
|
|
44e37467d6
|
||
|
|
7c74ca014d
|
||
|
|
e7454f6ce8 | ||
|
|
a100d2d798 | ||
|
|
3c48e7c02d | ||
|
|
2b3c79fcab | ||
|
|
7ff778b60a | ||
|
|
b83476b451 | ||
|
|
58652cac5c | ||
|
|
b216438a47 | ||
|
|
604657a084 | ||
|
|
5a57b5f799 | ||
|
|
be233c65fe | ||
|
|
9f201f8191 | ||
|
|
55c1962294
|
||
|
|
441932b30a
|
||
|
|
bdecec304a | ||
|
|
75e3e77478 | ||
|
|
5c93ca6143
|
||
|
|
0452a9faa5 | ||
|
|
9a75f38226 | ||
|
|
6d24aa160f
|
||
|
|
105630bbd8
|
||
|
|
228ab5b2f2 | ||
|
|
b97fe7e5b1 | ||
|
|
01db4fa951 | ||
|
|
cb153b50f1
|
||
|
|
8b33bf40c3
|
||
|
|
9a6221b723 | ||
|
|
a20b1cb263
|
||
|
|
cfe6055083
|
||
|
|
eea9abdc56
|
||
|
|
138b94e562 | ||
|
|
d11467bd1b
|
||
|
|
7be40d9bf9 | ||
|
|
dae8073992
|
||
|
|
143e7dc17c
|
||
|
|
f4ace64173 | ||
|
|
236b486845
|
||
|
|
c666f0228d
|
||
|
|
81049856b5 | ||
|
|
4813e24848 | ||
|
|
d61d001ddf | ||
|
|
060364abb5 | ||
|
|
13185f0e05 | ||
|
|
fd266969f5 | ||
|
|
bd471330e1 | ||
|
|
92602efa9e
|
||
|
|
55a39ac85a
|
||
|
|
39898825ef
|
||
|
|
59a2d1454e | ||
|
|
16c324cf32
|
||
|
|
b923b98b2c
|
||
|
|
afca7d5135 | ||
|
|
a05bebcd81
|
||
|
|
02cc8330ca
|
||
|
|
f8397b8bab
|
||
|
|
38603fbe45 | ||
|
|
78700e868d
|
||
|
|
259e8bdb7b
|
||
|
|
0ea3c25b7b | ||
|
|
2fa1b7d329
|
||
|
|
af805f6ba4 | ||
|
|
34c361d3f8
|
||
|
|
83eb621b0f | ||
|
|
65aaf4857d
|
||
|
|
7d52447b00 | ||
|
|
046ab8d1a8 | ||
|
|
33c032092d
|
||
|
|
b8eeb93a8f | ||
|
|
e95f68406f
|
||
|
|
c6f432a5c4
|
||
|
|
9ca7446dba | ||
|
|
773a1adf64 | ||
|
|
6afe5d4c0d
|
||
|
|
755a05fe34
|
||
|
|
202da658ee
|
||
|
|
a5856cf240 | ||
|
|
38099e6167
|
||
|
|
d307038e5e
|
||
|
|
d5aeeaf5e3
|
||
|
|
134a05ea23
|
||
|
|
db63f2a67c
|
||
|
|
97a3c3ef35 | ||
|
|
a40e904ab3 | ||
|
|
a8a89b0809 | ||
|
|
480efd1f8b
|
||
|
|
26baccf3c4 | ||
|
|
42808f40c0 | ||
|
|
57c21122e6 | ||
|
|
42faba70d9 | ||
|
|
99e1f01869 | ||
|
|
13bddbe359 | ||
|
|
51ff0e1a9f | ||
|
|
6766862a00 | ||
|
|
916f9b2557 | ||
|
|
c30aad179b | ||
|
|
d3aad6a198 | ||
|
|
744dc67ca9 | ||
|
|
164a7f5826 | ||
|
|
210cfcf3a6 | ||
|
|
34992344b2 | ||
|
|
1ea8dea381 | ||
|
|
15aa0572f3 | ||
|
|
6a843f4a71
|
||
|
|
a63c1a94ca
|
||
|
|
43263035d9 | ||
|
|
42ab55d0f8
|
||
|
|
44846cce57
|
||
|
|
1451750bcb
|
||
|
|
8ade5180cb | ||
|
|
d0535d0c47 | ||
|
|
79fa09e39b | ||
|
|
4010c2125c
|
||
|
|
32de0077de | ||
|
|
bd53e016c5 | ||
|
|
5b1ed644d1 | ||
|
|
a41787d89d | ||
|
|
8e392b56c3 | ||
|
|
42feadcd2d | ||
|
|
15f0344416 | ||
|
|
c90a977ab2 | ||
|
|
b186228f4e | ||
|
|
5f38474809 | ||
|
|
4f27320548 | ||
|
|
ba7bd1f1dd | ||
|
|
fbe70e7ead | ||
|
|
30a499be1d | ||
|
|
86e212fe42
|
||
|
|
4a646e6be0 | ||
|
|
bc0dc1925e | ||
|
|
c3af4dbc68 | ||
|
|
703639537d | ||
|
|
9ac3bf6a6c | ||
|
|
41ea6c9407 | ||
|
|
67e9a3544e | ||
|
|
f69ae3e77b | ||
|
|
73f903fc23 | ||
|
|
25116c3865
|
||
|
|
22ed7e23da
|
||
|
|
c0163d813e
|
@@ -0,0 +1,60 @@
|
|||||||
|
name: Bug Report
|
||||||
|
about: Du hast einen Fehler gefunden? Melde ihn hier!
|
||||||
|
labels: [ "typ/bug" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
ACHTUNG: Sollte es bei dem Bug ein Sicherheitsrisiko geben, melde es bitte auf unserem Discord Server
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Beschreibe deinen Bug in kurzer Form.
|
||||||
|
- type: input
|
||||||
|
id: mc-ver
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version
|
||||||
|
description: Minecraft Version des Clients
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: mc-ver-ser
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version Server
|
||||||
|
description: Minecraft Version des Servers, nur bei Bau oder Arenen Servern
|
||||||
|
- type: dropdown
|
||||||
|
id: can-reproduce
|
||||||
|
attributes:
|
||||||
|
label: Kannst du den Fehler wiederholen?
|
||||||
|
description: |
|
||||||
|
Wenn du den Fehler wiederholen kannst, können wir dieses Problem schneller beheben.
|
||||||
|
Solltest du den Fehler nicht wiederholen können, melde dich bitte auf unserem Discord Server.
|
||||||
|
options:
|
||||||
|
- "Yes"
|
||||||
|
- "No"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce-steps
|
||||||
|
attributes:
|
||||||
|
label: Wie kannst du den Fehler wiederholen?
|
||||||
|
description: Welche Schritte musst du ausführen, um den Fehler wiederholen zu können?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected-result
|
||||||
|
attributes:
|
||||||
|
label: Was sollte passieren?
|
||||||
|
description: Was sollte hier deiner Erwartung nach passieren?
|
||||||
|
- type: input
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Auf welchem Server ist der Fehler aufgetreten?
|
||||||
|
description: Gebe bitte den Namen des Servers an, auf dem der Fehler aufgetreten ist. z.B. "Lobby", "Lixfels Bauserver" etc.
|
||||||
|
- type: textarea
|
||||||
|
id: screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: Sollte es ein Visuelles Problem geben, kannst du hier Screenshots hinzufügen.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: true
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
name: Feature Idee
|
||||||
|
about: Du hast eine Idee für ein neues Feature, welches SteamWar nicht hat? Stelle sie hier vor.
|
||||||
|
labels: [ "typ/idee" ]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Feature Beschreibung
|
||||||
|
placeholder: |
|
||||||
|
Ich glaube, dass ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: Wenn es sich um etwas grafisches handelt, kannst du hier Screenshots hinzufügen.
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
name: Backport CommonCore
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
BACKPORT_PATH: CommonCore
|
||||||
|
BACKPORT_BRANCH_PREFIX: backport/commoncore
|
||||||
|
DISABLE_BACKPORT_LABEL: no-backport
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backport:
|
||||||
|
name: Create CommonCore backport PRs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check backport eligibility
|
||||||
|
id: eligibility
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
||||||
|
|
||||||
|
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
|
||||||
|
echo "Backport debug: server=${GITHUB_SERVER_URL}"
|
||||||
|
echo "Backport debug: api=${api_url}"
|
||||||
|
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
|
||||||
|
echo "Backport debug: action=$(jq -r '.action // ""' "$GITHUB_EVENT_PATH")"
|
||||||
|
|
||||||
|
merged="$(jq -r '.pull_request.merged // (.pull_request.merged_at != null)' "$GITHUB_EVENT_PATH")"
|
||||||
|
base_branch="$(jq -r '.pull_request.base.ref' "$GITHUB_EVENT_PATH")"
|
||||||
|
has_disable_label="$(jq -r --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.pull_request.labels[]?; .name == $disable_backport_label)' "$GITHUB_EVENT_PATH")"
|
||||||
|
echo "Backport debug: pr=$(jq -r '.pull_request.number // ""' "$GITHUB_EVENT_PATH") base=${base_branch} merged=${merged}"
|
||||||
|
echo "Backport debug: disable label present=${has_disable_label}"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "should_backport=$([[ "$merged" == "true" && "$base_branch" == "main" && "$has_disable_label" != "true" ]] && echo true || echo false)"
|
||||||
|
echo "pr_number=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
|
||||||
|
echo "pr_title<<EOF"
|
||||||
|
jq -r '.pull_request.title' "$GITHUB_EVENT_PATH"
|
||||||
|
echo "EOF"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
labels="$(curl -fsS \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
|
"${api_url}/repos/${GITHUB_REPOSITORY}/labels")"
|
||||||
|
|
||||||
|
if ! jq -e --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.[]; .name == $disable_backport_label)' <<< "$labels" >/dev/null; then
|
||||||
|
curl -fsS -X POST \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$(jq -n --arg name "$DISABLE_BACKPORT_LABEL" --arg color "ededed" --arg description "Disable automatic CommonCore backporting for this pull request." '{name: $name, color: $color, description: $description}')" \
|
||||||
|
"${api_url}/repos/${GITHUB_REPOSITORY}/labels"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create backport pull requests
|
||||||
|
if: steps.eligibility.outputs.should_backport == 'true'
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ steps.eligibility.outputs.pr_number }}
|
||||||
|
PR_TITLE: ${{ steps.eligibility.outputs.pr_title }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
||||||
|
repo_api_path="/repos/${GITHUB_REPOSITORY}"
|
||||||
|
|
||||||
|
api_request() {
|
||||||
|
local method="$1"
|
||||||
|
local path="$2"
|
||||||
|
local output="$3"
|
||||||
|
local data_file="${4:-}"
|
||||||
|
local status
|
||||||
|
local args=(-sS -X "$method" -H "Accept: application/json" -H "Authorization: token ${GITHUB_TOKEN}" -w "%{http_code}" -o "$output")
|
||||||
|
|
||||||
|
if [[ -n "$data_file" ]]; then
|
||||||
|
args+=(-H "Content-Type: application/json" --data-binary "@${data_file}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Backport debug: ${method} ${path}"
|
||||||
|
if ! status="$(curl "${args[@]}" "${api_url}${path}")"; then
|
||||||
|
echo "Backport debug: ${method} ${path} failed before HTTP status was captured."
|
||||||
|
if [[ -s "$output" ]]; then
|
||||||
|
echo "Backport debug: response body:"
|
||||||
|
cat "$output"
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Backport debug: ${method} ${path} -> HTTP ${status}"
|
||||||
|
if [[ ! "$status" =~ ^2 ]]; then
|
||||||
|
echo "Backport debug: response body:"
|
||||||
|
cat "$output"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
|
||||||
|
echo "Backport debug: server=${GITHUB_SERVER_URL}"
|
||||||
|
echo "Backport debug: api=${api_url}"
|
||||||
|
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
|
||||||
|
echo "Backport debug: pr=${PR_NUMBER}"
|
||||||
|
echo "Backport debug: actor=${GITHUB_ACTOR:-unknown}"
|
||||||
|
|
||||||
|
git config user.name "SteamWar Backport Bot"
|
||||||
|
git config user.email "actions@steamwar.de"
|
||||||
|
|
||||||
|
if [[ "${GITHUB_SERVER_URL}" == https://* ]]; then
|
||||||
|
auth_host="${GITHUB_SERVER_URL#https://}"
|
||||||
|
git remote set-url origin "https://oauth2:${GITHUB_TOKEN}@${auth_host}/${GITHUB_REPOSITORY}.git"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git fetch --prune origin '+refs/heads/version/*:refs/remotes/origin/version/*'
|
||||||
|
|
||||||
|
api_request GET "${repo_api_path}" repo-debug.json
|
||||||
|
jq -r '"Backport debug: repo permissions admin=\(.permissions.admin // "unknown") push=\(.permissions.push // "unknown") pull=\(.permissions.pull // "unknown")"' repo-debug.json || true
|
||||||
|
|
||||||
|
echo "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff"
|
||||||
|
curl -fsSL -w "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff -> HTTP %{http_code}\n" \
|
||||||
|
-H "Accept: text/plain" \
|
||||||
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
|
"${api_url}${repo_api_path}/pulls/${PR_NUMBER}.diff" \
|
||||||
|
-o pull-request.diff
|
||||||
|
|
||||||
|
if ! grep -Eq "^diff --git a/${BACKPORT_PATH}/" pull-request.diff; then
|
||||||
|
echo "Pull request #${PR_NUMBER} has no ${BACKPORT_PATH} changes to backport."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -t target_branches < <(git for-each-ref --format='%(refname:strip=3)' refs/remotes/origin/version)
|
||||||
|
if [[ "${#target_branches[@]}" -eq 0 ]]; then
|
||||||
|
echo "No version/* branches found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for target_branch in "${target_branches[@]}"; do
|
||||||
|
safe_target="${target_branch//\//-}"
|
||||||
|
backport_branch="${BACKPORT_BRANCH_PREFIX}/pr-${PR_NUMBER}-to-${safe_target}"
|
||||||
|
|
||||||
|
git checkout -B "${backport_branch}" "origin/${target_branch}"
|
||||||
|
git reset --hard "origin/${target_branch}"
|
||||||
|
|
||||||
|
if ! git apply --3way --index --include="${BACKPORT_PATH}/**" pull-request.diff; then
|
||||||
|
echo "Failed to apply CommonCore backport for ${target_branch}."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "CommonCore changes from #${PR_NUMBER} are already present in ${target_branch}."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
git commit -m "Backport CommonCore changes from #${PR_NUMBER}" -m "${PR_TITLE}"
|
||||||
|
git push --force-with-lease origin "${backport_branch}"
|
||||||
|
|
||||||
|
api_request GET "${repo_api_path}/pulls?state=open" open-pulls.json
|
||||||
|
open_pr_number="$(jq -r --arg base "$target_branch" --arg head "$backport_branch" '[.[] | select(.base.ref == $base and .head.ref == $head) | (.number // .index)][0] // empty' open-pulls.json)"
|
||||||
|
|
||||||
|
if [[ -n "$open_pr_number" ]]; then
|
||||||
|
echo "Backport PR #${open_pr_number} already exists for ${target_branch}."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
pr_body="$(printf 'Automatic CommonCore backport of #%s.\n\nOriginal PR title: %s\n\nOnly files below `CommonCore/` are included.' "$PR_NUMBER" "$PR_TITLE")"
|
||||||
|
|
||||||
|
jq -n \
|
||||||
|
--arg base "$target_branch" \
|
||||||
|
--arg head "$backport_branch" \
|
||||||
|
--arg title "Backport CommonCore changes from #${PR_NUMBER} to ${target_branch}" \
|
||||||
|
--arg body "$pr_body" \
|
||||||
|
'{base: $base, head: $head, title: $title, body: $body}' > create-pull.json
|
||||||
|
|
||||||
|
echo "Backport debug: create PR base=${target_branch} head=${backport_branch}"
|
||||||
|
api_request POST "${repo_api_path}/pulls" create-pull-response.json create-pull.json
|
||||||
|
done
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
name: Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- version/*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Setup Java 8
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 8
|
||||||
|
- name: Setup Java 11
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 11
|
||||||
|
- name: Setup Java 17
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 21
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v6
|
||||||
|
- name: Setup Maven Repository
|
||||||
|
env:
|
||||||
|
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
|
||||||
|
run: |
|
||||||
|
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew clean build --no-daemon --no-build-cache --refresh-dependencies
|
||||||
|
|
||||||
|
- name: Stage deploy artifacts
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
rm -rf deploy
|
||||||
|
mkdir -p deploy
|
||||||
|
|
||||||
|
cp "AccessWidener/build/libs/AccessWidener-all.jar" "deploy/AccessWidener.jar"
|
||||||
|
cp "BauSystem/build/libs/BauSystem-all.jar" "deploy/BauSystem.jar"
|
||||||
|
cp "FightSystem/build/libs/FightSystem-all.jar" "deploy/FightSystem.jar"
|
||||||
|
cp "KotlinCore/build/libs/KotlinCore-all.jar" "deploy/KotlinCore.jar"
|
||||||
|
cp "TNTLeague/build/libs/TNTLeague.jar" "deploy/TNTLeague.jar"
|
||||||
|
cp "LobbySystem/build/libs/LobbySystem.jar" "deploy/LobbySystem.jar"
|
||||||
|
cp "MissileWars/build/libs/MissileWars.jar" "deploy/MissileWars.jar"
|
||||||
|
cp "Realtime/build/libs/Realtime.jar" "deploy/RealTime.jar"
|
||||||
|
cp "SchematicSystem/build/libs/SchematicSystem-all.jar" "deploy/SchematicSystem.jar"
|
||||||
|
cp "SpigotCore/build/libs/SpigotCore-all.jar" "deploy/SpigotCore.jar"
|
||||||
|
cp "Teamserver/build/libs/Teamserver.jar" "deploy/Builder.jar"
|
||||||
|
cp "TowerRun/build/libs/TowerRun.jar" "deploy/TowerRun.jar"
|
||||||
|
cp "VelocityCore/Persistent/build/libs/Persistent.jar" "deploy/PersistentVelocityCore.jar"
|
||||||
|
cp "VelocityCore/Dependencies/build/libs/Dependencies-all.jar" "deploy/DependenciesVelocityCore.jar"
|
||||||
|
cp "VelocityCore/build/libs/VelocityCore-all.jar" "deploy/VelocityCore.jar"
|
||||||
|
cp "WebsiteBackend/build/libs/WebsiteBackend-all.jar" "deploy/website-api.jar"
|
||||||
|
cp "CLI/build/distributions/sw.zip" "deploy/sw.zip"
|
||||||
|
|
||||||
|
- name: Upload deploy artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: steamwar-jars
|
||||||
|
path: deploy/
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: Deploy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Download deploy artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: steamwar-jars
|
||||||
|
path: deploy
|
||||||
|
|
||||||
|
- name: Resolve deploy target
|
||||||
|
id: target
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ "${GITHUB_REF_NAME}" == "main" ]]; then
|
||||||
|
echo "path=/jars/current" >> "$GITHUB_OUTPUT"
|
||||||
|
elif [[ "${GITHUB_REF_NAME}" == version/* ]]; then
|
||||||
|
version="${GITHUB_REF_NAME#version/}"
|
||||||
|
if [[ ! "$version" =~ ^[A-Za-z0-9._-]+$ ]]; then
|
||||||
|
echo "Unsupported version branch name: ${GITHUB_REF_NAME}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "path=/jars/${version}" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "Unsupported deployment branch: ${GITHUB_REF_NAME}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload jars with scp
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
|
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
||||||
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
DEPLOY_PATH: ${{ steps.target.outputs.path }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${DEPLOY_HOST:?Missing DEPLOY_HOST secret}"
|
||||||
|
: "${DEPLOY_USER:?Missing DEPLOY_USER secret}"
|
||||||
|
: "${DEPLOY_SSH_KEY:?Missing DEPLOY_SSH_KEY secret}"
|
||||||
|
|
||||||
|
port="${DEPLOY_PORT:-22}"
|
||||||
|
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key
|
||||||
|
chmod 600 ~/.ssh/deploy_key
|
||||||
|
ssh-keyscan -p "$port" "$DEPLOY_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH'"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH/upload'"
|
||||||
|
scp -i ~/.ssh/deploy_key -P "$port" deploy/* "${DEPLOY_USER}@${DEPLOY_HOST}:$DEPLOY_PATH/upload"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -f '$DEPLOY_PATH'/*.jar '$DEPLOY_PATH'/*.zip"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mv '$DEPLOY_PATH'/upload/* '$DEPLOY_PATH'"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -r '$DEPLOY_PATH/upload'"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "chmod o-w '$DEPLOY_PATH'/*"
|
||||||
|
- name: Restart Services
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
|
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
||||||
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "sudo systemctl restart api.service"
|
||||||
|
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "unzip -o /jars/current/sw.zip -d /jars"
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
name: Pull Request Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Setup Java 8
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 8
|
||||||
|
- name: Setup Java 11
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 11
|
||||||
|
- name: Setup Java 17
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 17
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: 21
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v6
|
||||||
|
- name: Setup Maven Repository
|
||||||
|
env:
|
||||||
|
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
|
||||||
|
run: |
|
||||||
|
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew build --no-daemon
|
||||||
|
|
||||||
|
- name: Merge successful backport PR
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
BACKPORT_BRANCH_PREFIX: backport/commoncore
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
head_branch="$(jq -r '.pull_request.head.ref // ""' "$GITHUB_EVENT_PATH")"
|
||||||
|
base_branch="$(jq -r '.pull_request.base.ref // ""' "$GITHUB_EVENT_PATH")"
|
||||||
|
pr_number="$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
|
||||||
|
|
||||||
|
if [[ "${head_branch}" != "${BACKPORT_BRANCH_PREFIX}/"* ]]; then
|
||||||
|
echo "Not a CommonCore backport PR."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${base_branch}" != version/* ]]; then
|
||||||
|
echo "Backport PR target is not a version/* branch."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
|
||||||
|
|
||||||
|
curl -fsS -X POST \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"Do":"merge","delete_branch_after_merge":true}' \
|
||||||
|
"${api_url}/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/merge"
|
||||||
+6
-1
@@ -15,10 +15,15 @@ bin/
|
|||||||
.vscode
|
.vscode
|
||||||
.settings
|
.settings
|
||||||
|
|
||||||
|
# Language Server
|
||||||
|
**/.project
|
||||||
|
**/.factorypath
|
||||||
|
**/.classpath
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
lib
|
lib
|
||||||
/WebsiteBackend/data
|
/WebsiteBackend/data
|
||||||
/WebsiteBackend/logs
|
/WebsiteBackend/logs
|
||||||
/WebsiteBackend/skins
|
/WebsiteBackend/skins
|
||||||
/WebsiteBackend/config.json
|
/WebsiteBackend/config.json
|
||||||
/WebsiteBackend/sessions
|
/WebsiteBackend/sessions
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Remote JVM Debugger" type="Remote">
|
||||||
|
<option name="USE_SOCKET_TRANSPORT" value="true" />
|
||||||
|
<option name="SERVER_MODE" value="false" />
|
||||||
|
<option name="SHMEM_ADDRESS" />
|
||||||
|
<option name="HOST" value="localhost" />
|
||||||
|
<option name="PORT" value="5005" />
|
||||||
|
<option name="AUTO_RESTART" value="false" />
|
||||||
|
<RunnerSettings RunnerId="Debug">
|
||||||
|
<option name="DEBUG_PORT" value="5005" />
|
||||||
|
<option name="LOCAL" value="false" />
|
||||||
|
</RunnerSettings>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -18,18 +18,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
steamwar.java
|
`java-library`
|
||||||
}
|
alias(libs.plugins.shadow)
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
implementation("org.ow2.asm:asm:9.7")
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
implementation("org.ow2.asm:asm-commons:9.7")
|
||||||
|
}
|
||||||
compileOnly(libs.spigotapi)
|
|
||||||
compileOnly(libs.nms18)
|
tasks.shadowJar {
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
"Manifest-Version" to "1.0",
|
||||||
|
"Build-Jdk-Spec" to "21",
|
||||||
|
"Main-Class" to "de.steamwar.Main",
|
||||||
|
"Premain-Class" to "de.steamwar.Agent",
|
||||||
|
"Can-Retransform-Classes" to "true",
|
||||||
|
"Can-Redefine-Classes" to "true",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
dependsOn(tasks.shadowJar)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single parsed line from a .accesswidener file.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* accessible class net/minecraft/server/level/ServerPlayer
|
||||||
|
* accessible method net/minecraft/server/level/ServerPlayer getStats ()V
|
||||||
|
* mutable field net/minecraft/world/entity/Entity id I
|
||||||
|
* extendable class net/minecraft/world/level/chunk/LevelChunk
|
||||||
|
*/
|
||||||
|
public record AccessWidenerEntry(
|
||||||
|
/** accessible | mutable | extendable (may have "transitive-" prefix) */
|
||||||
|
String directive,
|
||||||
|
/** class | method | field */
|
||||||
|
String memberType,
|
||||||
|
/** Internal class name, e.g. net/minecraft/server/level/ServerPlayer */
|
||||||
|
String target,
|
||||||
|
/** Method/field name, null for class entries */
|
||||||
|
String name,
|
||||||
|
/** Descriptor, null for class entries */
|
||||||
|
String descriptor) {
|
||||||
|
/**
|
||||||
|
* Returns true if this entry targets the class with the given internal name.
|
||||||
|
*/
|
||||||
|
public boolean targets(String internalName) {
|
||||||
|
return target.equals(internalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses Fabric-compatible .accesswidener files.
|
||||||
|
* <p>
|
||||||
|
* Supported format:
|
||||||
|
* <pre>
|
||||||
|
* accessWidener v2 named
|
||||||
|
*
|
||||||
|
* # comments are supported
|
||||||
|
* accessible class net/minecraft/Foo
|
||||||
|
* accessible method net/minecraft/Foo someMethod ()V
|
||||||
|
* accessible field net/minecraft/Foo someField I
|
||||||
|
* mutable field net/minecraft/Foo someField I
|
||||||
|
* extendable class net/minecraft/Foo
|
||||||
|
* extendable method net/minecraft/Foo someMethod ()V
|
||||||
|
*
|
||||||
|
* # transitive variants (expose widening to dependents)
|
||||||
|
* transitive-accessible class net/minecraft/Foo
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final class AccessWidenerParser {
|
||||||
|
|
||||||
|
private AccessWidenerParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AccessWidenerEntry> parse(InputStream in) throws IOException {
|
||||||
|
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
|
||||||
|
|
||||||
|
String line;
|
||||||
|
boolean headerSeen = false;
|
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
// Strip inline comments
|
||||||
|
int commentIdx = line.indexOf('#');
|
||||||
|
if (commentIdx >= 0) line = line.substring(0, commentIdx);
|
||||||
|
line = line.strip();
|
||||||
|
|
||||||
|
if (line.isEmpty()) continue;
|
||||||
|
|
||||||
|
if (!headerSeen) {
|
||||||
|
// First non-blank, non-comment line must be the header
|
||||||
|
if (!line.startsWith("accessWidener")) {
|
||||||
|
throw new IOException("Missing accessWidener header, got: " + line);
|
||||||
|
}
|
||||||
|
headerSeen = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessWidenerEntry entry = parseLine(line);
|
||||||
|
if (entry != null) entries.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccessWidenerEntry parseLine(String line) {
|
||||||
|
String[] parts = line.split("\\s+");
|
||||||
|
if (parts.length < 3) return null;
|
||||||
|
|
||||||
|
String directive = parts[0]; // accessible / mutable / extendable / transitive-*
|
||||||
|
String memberType = parts[1]; // class / method / field
|
||||||
|
String target = parts[2]; // internal class name
|
||||||
|
|
||||||
|
return switch (memberType) {
|
||||||
|
case "class" -> new AccessWidenerEntry(directive, "class", target, null, null);
|
||||||
|
case "method", "field" -> {
|
||||||
|
if (parts.length < 5) yield null;
|
||||||
|
yield new AccessWidenerEntry(directive, memberType, target, parts[3], parts[4]);
|
||||||
|
}
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java agent entry point.
|
||||||
|
* <p>
|
||||||
|
* At JVM startup: java -javaagent:paper-access-widener-agent.jar -jar server.jar
|
||||||
|
* <p>
|
||||||
|
* On attach the agent:
|
||||||
|
* <ol>
|
||||||
|
* <li>Find all .jar files inside the plugins folder</li>
|
||||||
|
* <li>Scan all found jars for *.accesswidener resources</li>
|
||||||
|
* <li>Transform any class during loading</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
public class Agent {
|
||||||
|
private Agent() {
|
||||||
|
throw new IllegalStateException("Utility class");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
||||||
|
|
||||||
|
// -javaagent: startup
|
||||||
|
public static void premain(String args, Instrumentation inst) {
|
||||||
|
init(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void init(Instrumentation inst) {
|
||||||
|
LOG.info("[AccessWidener] Agent initialising.");
|
||||||
|
|
||||||
|
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||||
|
File file = new File(new File(".").getAbsoluteFile(), "plugins/");
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files == null) files = new File[0];
|
||||||
|
for (File jarFile : files) {
|
||||||
|
if (!jarFile.isFile()) continue;
|
||||||
|
if (!jarFile.getName().endsWith(".jar")) continue;
|
||||||
|
try {
|
||||||
|
entries.addAll(Utils.findAndParseAccessWideners(jarFile.toPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warning("Failed to parse access wideners from " + jarFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info("[AccessWidener] Loaded " + entries.size() + " access wideners.");
|
||||||
|
|
||||||
|
inst.addTransformer(new WideningTransformer(entries), false);
|
||||||
|
LOG.info("[AccessWidener] Agent ready.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses ASM to patch class bytecode according to a list of access widener entries.
|
||||||
|
*
|
||||||
|
* Returns {@code null} if the class is not targeted by any entry (no-op signal
|
||||||
|
* to the caller so it can skip the write).
|
||||||
|
*/
|
||||||
|
public class ClassPatcher {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger("ClassPatcher");
|
||||||
|
|
||||||
|
private final List<AccessWidenerEntry> entries;
|
||||||
|
|
||||||
|
/** Pre-computed set of targeted internal names for fast filtering. */
|
||||||
|
private final Set<String> targets;
|
||||||
|
|
||||||
|
private final Set<String> targetsPublicConstructor;
|
||||||
|
|
||||||
|
public ClassPatcher(List<AccessWidenerEntry> entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
this.targets = entries.stream()
|
||||||
|
.map(AccessWidenerEntry::target)
|
||||||
|
.flatMap(s -> {
|
||||||
|
if (!s.contains("$")) return Stream.of(s);
|
||||||
|
int index = s.lastIndexOf('$');
|
||||||
|
return Stream.of(s, s.substring(0, index));
|
||||||
|
})
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
this.targetsPublicConstructor = entries.stream()
|
||||||
|
.filter(entry -> entry.directive().equals("transitive-extendable"))
|
||||||
|
.map(AccessWidenerEntry::target)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patches {@code classBytes} if {@code className} is targeted.
|
||||||
|
*
|
||||||
|
* @return patched bytes, or {@code null} if no changes were needed
|
||||||
|
*/
|
||||||
|
public byte[] patch(String className, byte[] classBytes) {
|
||||||
|
if (!targets.contains(className)) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ClassReader cr = new ClassReader(classBytes);
|
||||||
|
ClassWriter cw = new ClassWriter(cr, 0);
|
||||||
|
cr.accept(new ClassTransformer(cw, className, entries, targetsPublicConstructor.contains(className)), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
|
return cw.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warning("[AccessWidener] Failed to transform " + className + ": " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.FieldVisitor;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ClassTransformer extends ClassVisitor {
|
||||||
|
|
||||||
|
private final String internalName;
|
||||||
|
private final List<AccessWidenerEntry> entries;
|
||||||
|
private final boolean appendPublicConstructor;
|
||||||
|
|
||||||
|
public ClassTransformer(ClassVisitor cv, String internalName, List<AccessWidenerEntry> entries, boolean appendPublicConstructor) {
|
||||||
|
super(Opcodes.ASM9, cv);
|
||||||
|
this.internalName = internalName;
|
||||||
|
this.entries = entries;
|
||||||
|
this.appendPublicConstructor = appendPublicConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||||
|
int newAccess = access;
|
||||||
|
for (AccessWidenerEntry e : entries) {
|
||||||
|
if (!e.targets(internalName) || !"class".equals(e.memberType())) continue;
|
||||||
|
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||||
|
}
|
||||||
|
if (appendPublicConstructor) {
|
||||||
|
MethodVisitor methodVisitor = visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
|
||||||
|
methodVisitor.visitCode();
|
||||||
|
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
methodVisitor.visitMethodInsn(
|
||||||
|
Opcodes.INVOKESPECIAL,
|
||||||
|
"java/lang/Object",
|
||||||
|
"<init>",
|
||||||
|
"()V",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||||
|
methodVisitor.visitMaxs(1, 1);
|
||||||
|
methodVisitor.visitEnd();
|
||||||
|
}
|
||||||
|
super.visit(version, newAccess, name, signature, superName, interfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||||
|
int newAccess = access;
|
||||||
|
for (AccessWidenerEntry e : entries) {
|
||||||
|
if (!e.target().equals(name) || !"class".equals(e.memberType())) continue;
|
||||||
|
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||||
|
}
|
||||||
|
super.visitInnerClass(name, outerName, innerName, newAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
|
int newAccess = access;
|
||||||
|
for (AccessWidenerEntry e : entries) {
|
||||||
|
if (!e.targets(internalName) || !"method".equals(e.memberType())) continue;
|
||||||
|
if (!name.equals(e.name()) || !descriptor.equals(e.descriptor())) continue;
|
||||||
|
newAccess = applyDirective(e.directive(), newAccess, false);
|
||||||
|
}
|
||||||
|
return super.visitMethod(newAccess, name, descriptor, signature, exceptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||||
|
int newAccess = access;
|
||||||
|
for (AccessWidenerEntry e : entries) {
|
||||||
|
if (!e.targets(internalName) || !"field".equals(e.memberType())) continue;
|
||||||
|
if (!name.equals(e.name())) continue;
|
||||||
|
newAccess = applyDirective(e.directive(), newAccess, true);
|
||||||
|
}
|
||||||
|
return super.visitField(newAccess, name, descriptor, signature, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a directive to an access bitmask.
|
||||||
|
*
|
||||||
|
* @param directive accessible / mutable / extendable (with optional "transitive-" prefix)
|
||||||
|
* @param access current access flags
|
||||||
|
* @param isField true when processing a field (mutable removes final)
|
||||||
|
*/
|
||||||
|
private static int applyDirective(String directive, int access, boolean isField) {
|
||||||
|
// Strip transitive- prefix — the widening itself is the same
|
||||||
|
String effective = directive.startsWith("transitive-") ? directive.substring("transitive-".length()) : directive;
|
||||||
|
|
||||||
|
return switch (effective) {
|
||||||
|
case "accessible" -> makePublic(access);
|
||||||
|
case "extendable" -> makePublic(removeFinal(access));
|
||||||
|
case "mutable" -> isField ? removeFinal(access) : access;
|
||||||
|
default -> access;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int makePublic(int access) {
|
||||||
|
return (access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int removeFinal(int access) {
|
||||||
|
return access & ~Opcodes.ACC_FINAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command-line tool that produces a widened copy of a JAR for use as a
|
||||||
|
* compile-time stub in IntelliJ / Gradle.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* java -jar jar-widener.jar <input.jar> <output.jar> [file.accesswidener ...]
|
||||||
|
*
|
||||||
|
* The output JAR is identical to the input JAR except that every class
|
||||||
|
* targeted by the access widener entries has its access flags patched:
|
||||||
|
* accessible → public
|
||||||
|
* extendable → public + non-final
|
||||||
|
* mutable → non-final field
|
||||||
|
*
|
||||||
|
* Intended for use as a Gradle task so IntelliJ sees the already-widened
|
||||||
|
* class when you Ctrl+click NMS code, and javac compiles without complaints.
|
||||||
|
*/
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if (args.length < 2) {
|
||||||
|
System.err.println("Usage: jar-widener <input.jar> <output.jar> [*.accesswidener ...]");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path inputJar = Path.of(args[0]);
|
||||||
|
Path outputJar = Path.of(args[1]);
|
||||||
|
|
||||||
|
if (!Files.exists(inputJar)) {
|
||||||
|
System.err.println("Input JAR not found: " + inputJar);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Collect all access widener entries ---
|
||||||
|
List<AccessWidenerEntry> entries = new ArrayList<>();
|
||||||
|
|
||||||
|
if (args.length > 2) {
|
||||||
|
for (int i = 2; i < args.length; i++) {
|
||||||
|
Path awFile = Path.of(args[i]);
|
||||||
|
if (!Files.exists(awFile)) {
|
||||||
|
System.err.println("Warning: access widener file not found, skipping: " + awFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStream in = Files.newInputStream(awFile)) {
|
||||||
|
List<AccessWidenerEntry> parsed = AccessWidenerParser.parse(in);
|
||||||
|
System.out.println("Loaded " + parsed.size() + " entries from " + awFile.getFileName());
|
||||||
|
entries.addAll(parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.isEmpty()) {
|
||||||
|
System.out.println("No access widener entries found — copying JAR unchanged.");
|
||||||
|
Files.createDirectories(outputJar.getParent());
|
||||||
|
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Widening " + inputJar.getFileName()
|
||||||
|
+ " with " + entries.size() + " total entr"
|
||||||
|
+ (entries.size() == 1 ? "y" : "ies") + "...");
|
||||||
|
|
||||||
|
// --- Copy input → output, transforming .class files in place ---
|
||||||
|
Files.createDirectories(outputJar.getParent());
|
||||||
|
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
|
ClassPatcher patcher = new ClassPatcher(entries);
|
||||||
|
|
||||||
|
try (FileSystem fs = FileSystems.newFileSystem(outputJar)) {
|
||||||
|
// Walk every .class entry in the JAR
|
||||||
|
try (var stream = Files.walk(fs.getPath("/"))) {
|
||||||
|
stream.filter(p -> p.toString().endsWith(".class"))
|
||||||
|
.forEach(classPath -> patchClass(fs, classPath, patcher));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Done. Widened JAR written to " + outputJar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void patchClass(FileSystem fs, Path classPath, ClassPatcher patcher) {
|
||||||
|
// Derive internal class name from path e.g. /net/minecraft/Foo.class → net/minecraft/Foo
|
||||||
|
String internalName = classPath.toString()
|
||||||
|
.replaceFirst("^/", "")
|
||||||
|
.replace(".class", "");
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] original = Files.readAllBytes(classPath);
|
||||||
|
byte[] patched = patcher.patch(internalName, original);
|
||||||
|
|
||||||
|
if (patched != null) {
|
||||||
|
Files.write(classPath, patched);
|
||||||
|
System.out.println(" Widened: " + internalName);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println(" Warning: failed to patch " + internalName + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
|
||||||
|
|
||||||
|
private Utils() {
|
||||||
|
throw new IllegalStateException("Utility class");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AccessWidenerEntry> findAndParseAccessWideners(Path jarPath) throws IOException {
|
||||||
|
List<AccessWidenerEntry> results = new ArrayList<>();
|
||||||
|
|
||||||
|
try (ZipFile zip = new ZipFile(jarPath.toFile())) {
|
||||||
|
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
if (entry.isDirectory() || !entry.getName().endsWith(".accesswidener")) continue;
|
||||||
|
|
||||||
|
try (InputStream in = zip.getInputStream(entry)) {
|
||||||
|
results.addAll(AccessWidenerParser.parse(in));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warning("[AccessWidener] Failed to parse " + entry.getName()
|
||||||
|
+ " in " + jarPath.getFileName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar;
|
||||||
|
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms class bytecode to apply access widening rules.
|
||||||
|
* <p>
|
||||||
|
* Also monitors for new plugin ClassLoaders appearing (when plugins load after
|
||||||
|
* the agent attaches) and automatically picks up their .accesswidener files.
|
||||||
|
*/
|
||||||
|
public class WideningTransformer implements ClassFileTransformer {
|
||||||
|
|
||||||
|
private final ClassPatcher patcher;
|
||||||
|
|
||||||
|
public WideningTransformer(List<AccessWidenerEntry> entries) {
|
||||||
|
patcher = new ClassPatcher(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
|
||||||
|
return patcher.patch(className, classfileBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
steamwar.java
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
|
||||||
|
|
||||||
compileOnly(libs.nms15)
|
|
||||||
compileOnly(libs.worldedit15)
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import com.sk89q.worldedit.EditSession;
|
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
|
||||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
|
||||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
|
||||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
|
||||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
|
||||||
import com.sk89q.worldedit.world.World;
|
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
|
||||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
|
||||||
import de.steamwar.bausystem.region.Point;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.data.BlockData;
|
|
||||||
import org.bukkit.block.data.Waterlogged;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class FlatteningWrapper15 implements FlatteningWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNoBook(ItemStack item) {
|
|
||||||
return item.getType() != Material.WRITABLE_BOOK && item.getType() != Material.WRITTEN_BOOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Set<Material> unpushable = new HashSet<>(Arrays.asList(Material.BARRIER, Material.BEACON, Material.COMMAND_BLOCK, Material.CHAIN_COMMAND_BLOCK, Material.REPEATING_COMMAND_BLOCK, Material.ENCHANTING_TABLE, Material.END_GATEWAY, Material.END_PORTAL, Material.ENDER_CHEST, Material.GRINDSTONE, Material.JIGSAW, Material.JUKEBOX, Material.NETHER_PORTAL, Material.OBSIDIAN, Material.STRUCTURE_VOID, Material.BARREL, Material.BEEHIVE, Material.BEE_NEST, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CHEST, Material.DAYLIGHT_DETECTOR, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.LECTERN, Material.SMOKER, Material.TRAPPED_CHEST));
|
|
||||||
|
|
||||||
// TODO: FLOWER
|
|
||||||
private static final Set<Material> breaking = new HashSet<>(Arrays.asList(Material.BAMBOO, Material.CACTUS, Material.CAKE, Material.CARVED_PUMPKIN, Material.CHORUS_FLOWER, Material.CHORUS_PLANT, Material.COBWEB, Material.COCOA, Material.DRAGON_EGG, Material.FIRE, Material.FLOWER_POT, Material.JACK_O_LANTERN, Material.LADDER, Material.LAVA, Material.LAVA, Material.LEVER, Material.LILY_PAD, Material.MELON, Material.NETHER_WART, Material.PUMPKIN, Material.COMPARATOR, Material.REDSTONE_WIRE, Material.REPEATER, Material.TORCH, Material.STRUCTURE_VOID, Material.SCAFFOLDING, Material.SEA_PICKLE, Material.SNOW, Material.SUGAR_CANE, Material.TORCH, Material.TRIPWIRE, Material.TRIPWIRE_HOOK, Material.TURTLE_EGG, Material.VINE, Material.WATER, Material.WHEAT));
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUnpusheable(Material material) {
|
|
||||||
if (unpushable.contains(material)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
String name = material.name();
|
|
||||||
return name.contains("BANNER") || name.contains("SIGN");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isBreakingOnPush(Material material) {
|
|
||||||
if (breaking.contains(material)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
String name = material.name();
|
|
||||||
return name.contains("BED") || name.contains("BUTTON") || name.contains("CARPET") || (name.contains("DOOR") && !name.contains("TRAPDOOR")) || name.contains("HEAD") || name.contains("LEAVES") || name.contains("MUSHROOM") || name.contains("PRESSURE_PLATE") || name.contains("SHULKER_BOX");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWorldEditCommand(String command) {
|
|
||||||
if (command.startsWith("/")) {
|
|
||||||
command = command.replaceFirst("/", "");
|
|
||||||
}
|
|
||||||
command = command.toLowerCase();
|
|
||||||
return WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().containsCommand(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final WorldEditPlugin WORLDEDIT_PLUGIN = Objects.requireNonNull((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"));
|
|
||||||
private static final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0));
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSelection(Player p, Point minPoint, Point maxPoint) {
|
|
||||||
WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, minPoint.toBlockVector3(), maxPoint.toBlockVector3()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Clipboard loadSchematic(File file) {
|
|
||||||
Clipboard clipboard;
|
|
||||||
try (ClipboardReader reader = Objects.requireNonNull(ClipboardFormats.findByFile(file)).getReader(new FileInputStream(file))) {
|
|
||||||
clipboard = reader.read();
|
|
||||||
} catch (NullPointerException | IOException e) {
|
|
||||||
throw new SecurityException("Bausystem schematic not found", e);
|
|
||||||
}
|
|
||||||
return clipboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EditSession paste(PasteBuilder pasteBuilder) {
|
|
||||||
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
|
|
||||||
Clipboard clipboard = pasteBuilder.getClipboard();
|
|
||||||
|
|
||||||
if (!pasteBuilder.getMappers().isEmpty()) {
|
|
||||||
BlockVector3 minimum = clipboard.getRegion().getMinimumPoint();
|
|
||||||
for (int x = 0; x < clipboard.getDimensions().getX(); x++) {
|
|
||||||
for (int y = 0; y < clipboard.getDimensions().getY(); y++) {
|
|
||||||
for (int z = 0; z < clipboard.getDimensions().getZ(); z++) {
|
|
||||||
BlockVector3 pos = minimum.add(x, y, z);
|
|
||||||
pasteBuilder.getMappers().forEach(mapper -> mapper.accept(clipboard, pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicReference<BlockVector3> pastePoint = new AtomicReference<>();
|
|
||||||
if (!pasteBuilder.getPredicates().isEmpty()) {
|
|
||||||
e.setMask(new Mask() {
|
|
||||||
@Override
|
|
||||||
public boolean test(BlockVector3 blockVector3) {
|
|
||||||
BaseBlock block = clipboard.getFullBlock(blockVector3.subtract(pastePoint.get()).add(clipboard.getRegion().getMinimumPoint()));
|
|
||||||
String blockName = block.getBlockType().toString().toLowerCase();
|
|
||||||
for (BiPredicate<BaseBlock, String> predicate : pasteBuilder.getPredicates()) {
|
|
||||||
if (!predicate.test(block, blockName)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mask copy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Mask2D toMask2D() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ClipboardHolder ch = new ClipboardHolder(clipboard);
|
|
||||||
BlockVector3 dimensions = clipboard.getDimensions();
|
|
||||||
BlockVector3 v = BlockVector3.at(pasteBuilder.getPastPoint().getX(), pasteBuilder.getPastPoint().getY(), pasteBuilder.getPastPoint().getZ());
|
|
||||||
BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
|
|
||||||
if (pasteBuilder.isRotate()) {
|
|
||||||
ch.setTransform(new AffineTransform().rotateY(180));
|
|
||||||
v = v.add(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset.multiply(-1, 1, -1)).subtract(0, 0, 1);
|
|
||||||
} else {
|
|
||||||
v = v.subtract(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset);
|
|
||||||
}
|
|
||||||
pastePoint.set(v);
|
|
||||||
|
|
||||||
if (pasteBuilder.isReset()) {
|
|
||||||
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
|
|
||||||
if (pasteBuilder.getWaterLevel() != 0) {
|
|
||||||
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3().withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(pasteBuilder.isIgnoreAir()).build());
|
|
||||||
return e;
|
|
||||||
} catch (WorldEditException e) {
|
|
||||||
throw new SecurityException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint) {
|
|
||||||
BukkitWorld bukkitWorld = new BukkitWorld(Bukkit.getWorlds().get(0));
|
|
||||||
CuboidRegion region = new CuboidRegion(bukkitWorld, minPoint.toBlockVector3(), maxPoint.toBlockVector3());
|
|
||||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
|
||||||
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(bukkitWorld, -1)) {
|
|
||||||
ForwardExtentCopy copy = new ForwardExtentCopy(
|
|
||||||
e, region, clipboard, region.getMinimumPoint()
|
|
||||||
);
|
|
||||||
|
|
||||||
copy.setCopyingEntities(false);
|
|
||||||
copy.setCopyingBiomes(false);
|
|
||||||
|
|
||||||
Operations.complete(copy);
|
|
||||||
clipboard.setOrigin(copyPoint.toBlockVector3());
|
|
||||||
return clipboard;
|
|
||||||
} catch (WorldEditException e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean backup(Point minPoint, Point maxPoint, File file) {
|
|
||||||
Clipboard clipboard = copy(minPoint, maxPoint, minPoint);
|
|
||||||
try (ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) {
|
|
||||||
writer.write(clipboard);
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inWater(org.bukkit.World world, Vector tntPosition) {
|
|
||||||
Block block = world.getBlockAt(tntPosition.getBlockX(), tntPosition.getBlockY(), tntPosition.getBlockZ());
|
|
||||||
if (block.getType() == Material.WATER)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
BlockData data = block.getBlockData();
|
|
||||||
if (!(data instanceof Waterlogged))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return ((Waterlogged) data).isWaterlogged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.features.util.NoClipCommand;
|
|
||||||
import net.minecraft.server.v1_15_R1.*;
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NMSWrapper15 implements NMSWrapper {
|
|
||||||
|
|
||||||
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
|
||||||
playerGameMode.set(((CraftPlayer) player).getHandle().playerInteractManager, EnumGamemode.getById(gameMode.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSlotToItemStack(Player player, Object o) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
|
||||||
int index = packetPlayInSetCreativeSlot.b();
|
|
||||||
if (index >= 36 && index <= 44) {
|
|
||||||
index -= 36;
|
|
||||||
} else if (index > 44) {
|
|
||||||
index -= 5;
|
|
||||||
} else if (index <= 8) {
|
|
||||||
index = index - 8 + 36;
|
|
||||||
}
|
|
||||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItemStack()));
|
|
||||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
|
||||||
player.updateInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Reflection.Field<Integer> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, int.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameStateChangeReason(Object packet) {
|
|
||||||
gameStateChangeReason.set(packet, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlayerBuildAbilities(Player player) {
|
|
||||||
((CraftPlayer) player).getHandle().abilities.mayBuild = true;
|
|
||||||
((CraftPlayer) player).getHandle().abilities.canInstantlyBuild = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material pathMaterial() {
|
|
||||||
return Material.GRASS_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int threshold = 2048;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkItemStack(ItemStack item) {
|
|
||||||
net.minecraft.server.v1_15_R1.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
|
||||||
NBTTagCompound tag = nmsItem.getTag();
|
|
||||||
if (tag != null && tag.hasKey("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = tag.getCompound("BlockEntityTag");
|
|
||||||
if (blockTag.hasKey("Items")) {
|
|
||||||
return drillDown(blockTag.getList("Items", 10), 0, 0) > threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int drillDown(NBTTagList items, int layer, int start) {
|
|
||||||
if (layer > 2) return start + threshold;
|
|
||||||
int invalid = start;
|
|
||||||
for (NBTBase nbtBase : items) {
|
|
||||||
if (!(nbtBase instanceof NBTTagCompound))
|
|
||||||
continue;
|
|
||||||
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
|
||||||
if (slot.hasKey("tag")) {
|
|
||||||
invalid += slot.getByte("Count");
|
|
||||||
NBTTagCompound iTag = slot.getCompound("tag");
|
|
||||||
if (iTag.hasKey("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = iTag.getCompound("BlockEntityTag");
|
|
||||||
if (blockTag.hasKey("Items")) {
|
|
||||||
invalid = drillDown(blockTag.getList("Items", 10), layer + 1, invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (invalid > threshold)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
|
||||||
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
|
||||||
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
|
||||||
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
|
||||||
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
|
||||||
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resetExplosionKnockback(Object packet) {
|
|
||||||
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
|
||||||
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), Vec3D.a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
|
|
||||||
public class PlaceItemWrapper15 implements PlaceItemWrapper {
|
|
||||||
|
|
||||||
public PlaceItemWrapper15() {
|
|
||||||
for (Material material : Material.values()) {
|
|
||||||
if (!material.isBlock()) continue;
|
|
||||||
if (material.isLegacy()) continue;
|
|
||||||
|
|
||||||
String nonWall = material.name().replace("_WALL_", "").replace("WALL_", "").replace("_WALL", "");
|
|
||||||
try {
|
|
||||||
Material nonWallMaterial = Material.valueOf(nonWall);
|
|
||||||
if (nonWallMaterial != material && nonWallMaterial.isItem() && !nonWallMaterial.isBlock()) {
|
|
||||||
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(nonWallMaterial, material);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(Material.REDSTONE, Material.REDSTONE_WIRE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import net.minecraft.server.v1_15_R1.EntityPlayer;
|
|
||||||
import net.minecraft.server.v1_15_R1.PacketPlayInFlying;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class PlayerMovementWrapper15 implements PlayerMovementWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPosition(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
|
||||||
if (Float.isNaN(packetPlayInFlying.a(Float.NaN))) {
|
|
||||||
entityPlayer.e(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0));
|
|
||||||
} else {
|
|
||||||
entityPlayer.setLocation(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0), packetPlayInFlying.a(0F), packetPlayInFlying.b(0F));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object convertToOut(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
Object packet = Reflection.newInstance(teleportPacket);
|
|
||||||
teleportEntity.set(packet, player.getEntityId());
|
|
||||||
teleportPosition.set(packet, packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0),
|
|
||||||
Float.isNaN(packetPlayInFlying.a(Float.NaN)) ? player.getLocation().getYaw() : packetPlayInFlying.a(0.0F),
|
|
||||||
Float.isNaN(packetPlayInFlying.b(Float.NaN)) ? player.getLocation().getPitch() : packetPlayInFlying.b(0.0F));
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
|
||||||
import de.steamwar.bausystem.utils.tps.TPSFreezeUtils;
|
|
||||||
import de.steamwar.bausystem.utils.tps.TPSLimitUtils;
|
|
||||||
import de.steamwar.core.TPSWarpUtils;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
|
|
||||||
public class TickManager15 implements TickManager, Listener {
|
|
||||||
|
|
||||||
private static float currentTPSLimit = 20;
|
|
||||||
private boolean currentlyStepping = false;
|
|
||||||
private float currentLimit;
|
|
||||||
private int stepsTotal;
|
|
||||||
private int stepsLeft;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canFreeze() {
|
|
||||||
return TPSFreezeUtils.isCanFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTickRate(float tickRate) {
|
|
||||||
if (currentlyStepping) {
|
|
||||||
currentlyStepping = false;
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
|
||||||
BossBarService.instance.remove(player, Region.getGlobalRegion(), "TickStep");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
TPSWarpUtils.warp(tickRate);
|
|
||||||
if (currentTPSLimit == 0 && tickRate != 0) {
|
|
||||||
TPSFreezeUtils.unfreeze();
|
|
||||||
}
|
|
||||||
currentTPSLimit = tickRate;
|
|
||||||
if (tickRate == 0) {
|
|
||||||
TPSLimitUtils.unlimit();
|
|
||||||
TPSFreezeUtils.freeze();
|
|
||||||
} else if (tickRate < 20.0) {
|
|
||||||
TPSLimitUtils.limit(tickRate);
|
|
||||||
} else if (tickRate >= 20) {
|
|
||||||
TPSLimitUtils.unlimit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFrozen() {
|
|
||||||
return TPSFreezeUtils.frozen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFreeze(boolean freeze) {
|
|
||||||
if (freeze) {
|
|
||||||
setTickRate(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stepTicks(int ticks) {
|
|
||||||
currentLimit = 0;
|
|
||||||
setTickRate(20);
|
|
||||||
stepsLeft = ticks;
|
|
||||||
stepsTotal = ticks;
|
|
||||||
currentlyStepping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sprintTicks(int ticks) {
|
|
||||||
currentLimit = currentTPSLimit;
|
|
||||||
setTickRate(4000);
|
|
||||||
stepsLeft = ticks;
|
|
||||||
stepsTotal = ticks;
|
|
||||||
currentlyStepping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSprinting() {
|
|
||||||
return currentlyStepping && currentTPSLimit > 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStepping() {
|
|
||||||
return currentlyStepping && currentTPSLimit <= 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getTickRate() {
|
|
||||||
return currentTPSLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBlockTpsPacket(boolean block) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTotalTicks() {
|
|
||||||
return stepsTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDoneTicks() {
|
|
||||||
return stepsTotal - stepsLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getRemainingTicks() {
|
|
||||||
return stepsLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onTickEnd(TickEndEvent event) {
|
|
||||||
if (!currentlyStepping) return;
|
|
||||||
stepsLeft--;
|
|
||||||
if (stepsLeft <= 0) {
|
|
||||||
setTickRate(currentLimit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils.tps;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
|
||||||
import de.steamwar.core.BountifulWrapper;
|
|
||||||
import de.steamwar.core.ChatWrapper;
|
|
||||||
import de.steamwar.core.Core;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
class PacketCache {
|
|
||||||
|
|
||||||
private static List<Object> packets = new ArrayList<>();
|
|
||||||
private static Set<Entity> entities = new HashSet<>();
|
|
||||||
private static BukkitTask task = null;
|
|
||||||
|
|
||||||
private static Class<?> vec3dClass = Reflection.getClass("net.minecraft.world.phys.Vec3");
|
|
||||||
private static Reflection.Field<Object> zeroVec3d = (Reflection.Field<Object>) Reflection.getField(vec3dClass, vec3dClass, 0);
|
|
||||||
private static Object ZERO_VEC3D = zeroVec3d.get(null);
|
|
||||||
private static Class<?> velocityPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket");
|
|
||||||
private static Reflection.Constructor velocityPacketConstructor = Reflection.getConstructor(velocityPacketClass, int.class, vec3dClass);
|
|
||||||
|
|
||||||
private static Class<?> teleportPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
|
|
||||||
private static Class<?> entityClass = Reflection.getClass("net.minecraft.world.entity.Entity");
|
|
||||||
private static Reflection.Constructor teleportPacketConstructor = Reflection.getConstructor(teleportPacketClass, entityClass);
|
|
||||||
|
|
||||||
private static Class<?> craftEntityClass = Reflection.getClass("org.bukkit.craftbukkit.entity.CraftEntity");
|
|
||||||
private static Reflection.Method getHandle = Reflection.getMethod(craftEntityClass, "getHandle");
|
|
||||||
|
|
||||||
private static Object noGravityDataWatcher = BountifulWrapper.impl.getDataWatcherObject(5, Boolean.class);
|
|
||||||
private static Object fuseDataWatcher = BountifulWrapper.impl.getDataWatcherObject(8, Integer.class);
|
|
||||||
|
|
||||||
public void continuousSendCache() {
|
|
||||||
if (task != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
createPackets();
|
|
||||||
task = new BukkitRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
_sendCache();
|
|
||||||
}
|
|
||||||
}.runTaskTimer(Core.getInstance(), 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendCache() {
|
|
||||||
if (task != null) {
|
|
||||||
task.cancel();
|
|
||||||
task = null;
|
|
||||||
}
|
|
||||||
_sendCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _sendCache() {
|
|
||||||
createPackets();
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
||||||
for (Object packet : packets) {
|
|
||||||
TinyProtocol.instance.sendPacket(player, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCache() {
|
|
||||||
packets.clear();
|
|
||||||
entities.clear();
|
|
||||||
|
|
||||||
if (task != null) {
|
|
||||||
task.cancel();
|
|
||||||
task = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createPackets() {
|
|
||||||
if (entities.stream().anyMatch(Entity::isDead)) {
|
|
||||||
entities.clear();
|
|
||||||
packets.clear();
|
|
||||||
}
|
|
||||||
List<Entity> entities = Bukkit.getWorlds().get(0).getEntities().stream()
|
|
||||||
.filter(e -> !(e instanceof Player))
|
|
||||||
.filter(e -> PacketCache.entities.add(e))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
packets.add(teleportPacketConstructor.invoke(getHandle.invoke(entity)));
|
|
||||||
}
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
packets.add(velocityPacketConstructor.invoke(entity.getEntityId(), ZERO_VEC3D));
|
|
||||||
}
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
packets.add(ChatWrapper.impl.getDataWatcherPacket(entity.getEntityId(), noGravityDataWatcher, true));
|
|
||||||
}
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
if (!(entity instanceof TNTPrimed)) continue;
|
|
||||||
TNTPrimed tnt = (TNTPrimed) entity;
|
|
||||||
int fuse = tnt.getFuseTicks();
|
|
||||||
packets.add(ChatWrapper.impl.getDataWatcherPacket(entity.getEntityId(), fuseDataWatcher, fuse - (fuse % 5) + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils.tps;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class TPSFreezeUtils {
|
|
||||||
|
|
||||||
private static Reflection.Field<Boolean> fieldAccessor;
|
|
||||||
@Getter
|
|
||||||
private static final boolean canFreeze;
|
|
||||||
|
|
||||||
private static final Reflection.Method getWorldHandle = Reflection.getTypedMethod(Reflection.getClass("org.bukkit.craftbukkit.CraftWorld"), "getHandle", null);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private static boolean frozen = false;
|
|
||||||
|
|
||||||
private static final World world = Bukkit.getWorlds().get(0);
|
|
||||||
|
|
||||||
static {
|
|
||||||
Reflection.Field<Boolean> fieldAccessor;
|
|
||||||
try {
|
|
||||||
fieldAccessor = Reflection.getField(Reflection.getClass("net.minecraft.server.level.ServerLevel"), "freezed", boolean.class);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
fieldAccessor = null;
|
|
||||||
}
|
|
||||||
canFreeze = fieldAccessor != null;
|
|
||||||
TPSFreezeUtils.fieldAccessor = fieldAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void freeze() {
|
|
||||||
setFreeze(world, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unfreeze() {
|
|
||||||
setFreeze(world, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean frozen() {
|
|
||||||
return canFreeze && frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setFreeze(World world, boolean state) {
|
|
||||||
if (canFreeze) {
|
|
||||||
fieldAccessor.set(getWorldHandle.invoke(world), state);
|
|
||||||
if (state) {
|
|
||||||
PacketCache.continuousSendCache();
|
|
||||||
} else {
|
|
||||||
PacketCache.clearCache();
|
|
||||||
}
|
|
||||||
frozen = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils.tps;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
|
||||||
import de.steamwar.bausystem.utils.PlayerMovementWrapper;
|
|
||||||
import de.steamwar.core.Core;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class TPSLimitUtils {
|
|
||||||
|
|
||||||
private static long currentTime = System.nanoTime();
|
|
||||||
private static BukkitTask tpsLimiter = null;
|
|
||||||
private static Queue<Runnable> packetQueue = new ConcurrentLinkedQueue<>();
|
|
||||||
|
|
||||||
public void unlimit() {
|
|
||||||
if (tpsLimiter != null) tpsLimiter.cancel();
|
|
||||||
tpsLimiter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void limit(double tps) {
|
|
||||||
if (tpsLimiter != null) tpsLimiter.cancel();
|
|
||||||
|
|
||||||
double delay = 20 / tps;
|
|
||||||
int loops = (int) Math.ceil(delay);
|
|
||||||
long sleepDelay = (long) (50 * delay) / loops;
|
|
||||||
|
|
||||||
tpsLimiter = Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
|
|
||||||
PacketCache.sendCache();
|
|
||||||
for (int i = 0; i < loops; i++) {
|
|
||||||
sleepUntilNextTick(sleepDelay);
|
|
||||||
PacketCache.sendCache();
|
|
||||||
while (true) {
|
|
||||||
Runnable runnable = packetQueue.poll();
|
|
||||||
if (runnable == null) break;
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PacketCache.clearCache();
|
|
||||||
}, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sleepUntilNextTick(long neededDelta) {
|
|
||||||
long lastTime = currentTime;
|
|
||||||
currentTime = System.nanoTime();
|
|
||||||
|
|
||||||
long timeDelta = (currentTime - lastTime) / 1000000;
|
|
||||||
if (neededDelta - timeDelta < 0) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(neededDelta - timeDelta);
|
|
||||||
currentTime = System.nanoTime();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
static {
|
|
||||||
long timeInterval = 50;
|
|
||||||
final long[] lastTime = {System.currentTimeMillis()};
|
|
||||||
final double[] tps = {20.0};
|
|
||||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
if (currentTime > lastTime[0]) {
|
|
||||||
tps[0] = (double)timeInterval / (double)(currentTime - lastTime[0]) * 20.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTime[0] = currentTime;
|
|
||||||
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
|
||||||
SWUtils.sendToActionbar(player, String.valueOf((int) (tps[0] * 10.0) / 10.0));
|
|
||||||
});
|
|
||||||
}, timeInterval / 50L, timeInterval / 50L);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static final Class<?> position = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos");
|
|
||||||
private static final Class<?> positionLook = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot");
|
|
||||||
static {
|
|
||||||
BiFunction<Player, Object, Object> positionSetter = (player, o) -> {
|
|
||||||
if (tpsLimiter != null) {
|
|
||||||
Object object = PlayerMovementWrapper.impl.convertToOut(player, o);
|
|
||||||
packetQueue.add(() -> {
|
|
||||||
PlayerMovementWrapper.impl.setPosition(player, o);
|
|
||||||
Bukkit.getOnlinePlayers().forEach(p -> {
|
|
||||||
if (p == player) return;
|
|
||||||
TinyProtocol.instance.sendPacket(p, object);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
};
|
|
||||||
TinyProtocol.instance.addFilter(position, positionSetter);
|
|
||||||
TinyProtocol.instance.addFilter(positionLook, positionSetter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.features.util.NoClipCommand;
|
|
||||||
import net.minecraft.nbt.NBTBase;
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
|
||||||
import net.minecraft.nbt.NBTTagList;
|
|
||||||
import net.minecraft.network.protocol.game.*;
|
|
||||||
import net.minecraft.server.level.PlayerInteractManager;
|
|
||||||
import net.minecraft.world.level.EnumGamemode;
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NMSWrapper18 implements NMSWrapper {
|
|
||||||
|
|
||||||
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
|
||||||
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSlotToItemStack(Player player, Object o) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
|
||||||
int index = packetPlayInSetCreativeSlot.b();
|
|
||||||
if (index >= 36 && index <= 44) {
|
|
||||||
index -= 36;
|
|
||||||
} else if (index > 44) {
|
|
||||||
index -= 5;
|
|
||||||
} else if (index <= 8) {
|
|
||||||
index = index - 8 + 36;
|
|
||||||
}
|
|
||||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
|
||||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
|
||||||
player.updateInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameStateChangeReason(Object packet) {
|
|
||||||
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlayerBuildAbilities(Player player) {
|
|
||||||
((CraftPlayer) player).getHandle().fs().d = true;
|
|
||||||
((CraftPlayer) player).getHandle().fs().e = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material pathMaterial() {
|
|
||||||
return Material.DIRT_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int threshold = 2048;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkItemStack(ItemStack item) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
|
||||||
NBTTagCompound tag = nmsItem.t();
|
|
||||||
if (tag != null && tag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int drillDown(NBTTagList items, int layer, int start) {
|
|
||||||
if (layer > 2) return start + threshold;
|
|
||||||
int invalid = start;
|
|
||||||
for (NBTBase nbtBase : items) {
|
|
||||||
if (!(nbtBase instanceof NBTTagCompound))
|
|
||||||
continue;
|
|
||||||
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
|
||||||
if (slot.e("tag")) {
|
|
||||||
invalid += slot.f("Count");
|
|
||||||
NBTTagCompound iTag = slot.p("tag");
|
|
||||||
if (iTag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (invalid > threshold)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
|
||||||
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
|
||||||
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
|
||||||
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
|
||||||
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
|
||||||
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resetExplosionKnockback(Object packet) {
|
|
||||||
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
|
||||||
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
|
||||||
import net.minecraft.server.level.EntityPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class PlayerMovementWrapper18 implements PlayerMovementWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPosition(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
|
||||||
if (packetPlayInFlying.h) {
|
|
||||||
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
|
||||||
} else {
|
|
||||||
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object convertToOut(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
Object packet = Reflection.newInstance(teleportPacket);
|
|
||||||
teleportEntity.set(packet, player.getEntityId());
|
|
||||||
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
steamwar.java
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
|
||||||
|
|
||||||
compileOnly(libs.spigotapi)
|
|
||||||
compileOnly(libs.paperapi)
|
|
||||||
|
|
||||||
compileOnly(libs.nms19)
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.features.util.NoClipCommand;
|
|
||||||
import net.minecraft.nbt.NBTBase;
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
|
||||||
import net.minecraft.nbt.NBTTagList;
|
|
||||||
import net.minecraft.network.protocol.game.*;
|
|
||||||
import net.minecraft.server.level.PlayerInteractManager;
|
|
||||||
import net.minecraft.world.level.EnumGamemode;
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NMSWrapper19 implements NMSWrapper {
|
|
||||||
|
|
||||||
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
|
||||||
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSlotToItemStack(Player player, Object o) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
|
||||||
int index = packetPlayInSetCreativeSlot.b();
|
|
||||||
if (index >= 36 && index <= 44) {
|
|
||||||
index -= 36;
|
|
||||||
} else if (index > 44) {
|
|
||||||
index -= 5;
|
|
||||||
} else if (index <= 8) {
|
|
||||||
index = index - 8 + 36;
|
|
||||||
}
|
|
||||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
|
||||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
|
||||||
player.updateInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameStateChangeReason(Object packet) {
|
|
||||||
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlayerBuildAbilities(Player player) {
|
|
||||||
((CraftPlayer) player).getHandle().fF().d = true;
|
|
||||||
((CraftPlayer) player).getHandle().fF().e = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material pathMaterial() {
|
|
||||||
return Material.DIRT_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int threshold = 2048;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkItemStack(ItemStack item) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
|
||||||
NBTTagCompound tag = nmsItem.v();
|
|
||||||
if (tag != null && tag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int drillDown(NBTTagList items, int layer, int start) {
|
|
||||||
if (layer > 2) return start + threshold;
|
|
||||||
int invalid = start;
|
|
||||||
for (NBTBase nbtBase : items) {
|
|
||||||
if (!(nbtBase instanceof NBTTagCompound))
|
|
||||||
continue;
|
|
||||||
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
|
||||||
if (slot.e("tag")) {
|
|
||||||
invalid += slot.f("Count");
|
|
||||||
NBTTagCompound iTag = slot.p("tag");
|
|
||||||
if (iTag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (invalid > threshold)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
|
||||||
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
|
||||||
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
|
||||||
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
|
||||||
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
|
||||||
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resetExplosionKnockback(Object packet) {
|
|
||||||
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
|
||||||
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
|
||||||
import net.minecraft.server.level.EntityPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class PlayerMovementWrapper19 implements PlayerMovementWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPosition(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
|
||||||
if (packetPlayInFlying.h) {
|
|
||||||
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
|
||||||
} else {
|
|
||||||
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object convertToOut(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
Object packet = Reflection.newInstance(teleportPacket);
|
|
||||||
teleportEntity.set(packet, player.getEntityId());
|
|
||||||
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
|
|
||||||
import com.destroystokyo.paper.event.server.ServerTickStartEvent;
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
|
|
||||||
public class TickListener19 implements TickListener, Listener {
|
|
||||||
|
|
||||||
private boolean tickStartRan = false;
|
|
||||||
|
|
||||||
public TickListener19() {
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onServerTickStart(ServerTickStartEvent event) {
|
|
||||||
if (TickManager.impl.isFrozen()) return;
|
|
||||||
Bukkit.getPluginManager().callEvent(new TickStartEvent());
|
|
||||||
tickStartRan = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onServerTickEnd(ServerTickEndEvent event) {
|
|
||||||
if (!tickStartRan) return;
|
|
||||||
Bukkit.getPluginManager().callEvent(new TickEndEvent());
|
|
||||||
tickStartRan = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
steamwar.java
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
|
||||||
|
|
||||||
compileOnly(libs.spigotapi)
|
|
||||||
|
|
||||||
compileOnly(libs.nms20)
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.features.util.NoClipCommand;
|
|
||||||
import net.minecraft.nbt.NBTBase;
|
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
|
||||||
import net.minecraft.nbt.NBTTagList;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutExplosion;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
|
|
||||||
import net.minecraft.server.level.PlayerInteractManager;
|
|
||||||
import net.minecraft.world.level.EnumGamemode;
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NMSWrapper20 implements NMSWrapper {
|
|
||||||
|
|
||||||
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
|
||||||
playerGameMode.set(((CraftPlayer) player).getHandle().e, EnumGamemode.a(gameMode.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSlotToItemStack(Player player, Object o) {
|
|
||||||
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
|
|
||||||
int index = packetPlayInSetCreativeSlot.a();
|
|
||||||
if (index >= 36 && index <= 44) {
|
|
||||||
index -= 36;
|
|
||||||
} else if (index > 44) {
|
|
||||||
index -= 5;
|
|
||||||
} else if (index <= 8) {
|
|
||||||
index = index - 8 + 36;
|
|
||||||
}
|
|
||||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
|
|
||||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
|
||||||
player.updateInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameStateChangeReason(Object packet) {
|
|
||||||
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlayerBuildAbilities(Player player) {
|
|
||||||
((CraftPlayer) player).getHandle().fO().d = true;
|
|
||||||
((CraftPlayer) player).getHandle().fO().e = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material pathMaterial() {
|
|
||||||
return Material.DIRT_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int threshold = 2048;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkItemStack(ItemStack item) {
|
|
||||||
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
|
|
||||||
NBTTagCompound tag = nmsItem.v();
|
|
||||||
if (tag != null && tag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = tag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int drillDown(NBTTagList items, int layer, int start) {
|
|
||||||
if (layer > 2) return start + threshold;
|
|
||||||
int invalid = start;
|
|
||||||
for (NBTBase nbtBase : items) {
|
|
||||||
if (!(nbtBase instanceof NBTTagCompound))
|
|
||||||
continue;
|
|
||||||
NBTTagCompound slot = (NBTTagCompound) nbtBase;
|
|
||||||
if (slot.e("tag")) {
|
|
||||||
invalid += slot.f("Count");
|
|
||||||
NBTTagCompound iTag = slot.p("tag");
|
|
||||||
if (iTag.e("BlockEntityTag")) {
|
|
||||||
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
|
|
||||||
if (blockTag.e("Items")) {
|
|
||||||
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (invalid > threshold)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
|
|
||||||
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
|
|
||||||
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
|
|
||||||
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
|
|
||||||
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
|
|
||||||
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resetExplosionKnockback(Object packet) {
|
|
||||||
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
|
|
||||||
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.data.BlockData;
|
|
||||||
|
|
||||||
public class PlaceItemWrapper20 implements PlaceItemWrapper {
|
|
||||||
|
|
||||||
public PlaceItemWrapper20() {
|
|
||||||
for (Material material : Material.values()) {
|
|
||||||
if (!material.isBlock()) continue;
|
|
||||||
if (material.isLegacy()) continue;
|
|
||||||
BlockData blockData = material.createBlockData();
|
|
||||||
Material placementMaterial = blockData.getPlacementMaterial();
|
|
||||||
if (material == placementMaterial) continue;
|
|
||||||
if (placementMaterial == Material.AIR) continue;
|
|
||||||
if (placementMaterial.isItem() && !placementMaterial.isBlock()) {
|
|
||||||
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(placementMaterial, material);
|
|
||||||
}
|
|
||||||
if (material.name().contains("WALL")) {
|
|
||||||
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(placementMaterial, material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import net.minecraft.network.protocol.game.PacketPlayInFlying;
|
|
||||||
import net.minecraft.server.level.EntityPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class PlayerMovementWrapper20 implements PlayerMovementWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPosition(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
|
|
||||||
if (packetPlayInFlying.h) {
|
|
||||||
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
|
|
||||||
} else {
|
|
||||||
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object convertToOut(Player player, Object object) {
|
|
||||||
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
|
|
||||||
Object packet = Reflection.newInstance(teleportPacket);
|
|
||||||
teleportEntity.set(packet, player.getEntityId());
|
|
||||||
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
|
|
||||||
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
steamwar.java
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
|
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
|
||||||
|
|
||||||
compileOnly(libs.paperapi21)
|
|
||||||
|
|
||||||
compileOnly(libs.nms21)
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.features.util.NoClipCommand;
|
|
||||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
|
||||||
import io.papermc.paper.datacomponent.item.ItemContainerContents;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
|
||||||
import net.minecraft.world.entity.player.Abilities;
|
|
||||||
import net.minecraft.world.level.GameType;
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class NMSWrapper21 implements NMSWrapper {
|
|
||||||
|
|
||||||
private static final Reflection.Field<ServerPlayerGameMode> playerInteractManager = Reflection.getField(ServerPlayer.class, null, ServerPlayerGameMode.class);
|
|
||||||
private static final Reflection.Field<GameType> playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setInternalGameMode(Player player, GameMode gameMode) {
|
|
||||||
playerGameMode.set(playerInteractManager.get(((CraftPlayer) player).getHandle()), GameType.byId(gameMode.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSlotToItemStack(Player player, Object o) {
|
|
||||||
ClientboundContainerSetSlotPacket packetPlayInSetCreativeSlot = (ClientboundContainerSetSlotPacket) o;
|
|
||||||
int index = packetPlayInSetCreativeSlot.getSlot();
|
|
||||||
if (index >= 36 && index <= 44) {
|
|
||||||
index -= 36;
|
|
||||||
} else if (index > 44) {
|
|
||||||
index -= 5;
|
|
||||||
} else if (index <= 8) {
|
|
||||||
index = index - 8 + 36;
|
|
||||||
}
|
|
||||||
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItem()));
|
|
||||||
if (index < 9) player.getInventory().setHeldItemSlot(index);
|
|
||||||
player.updateInventory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Reflection.Field<ClientboundGameEventPacket.Type> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, ClientboundGameEventPacket.Type.class, 14);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setGameStateChangeReason(Object packet) {
|
|
||||||
gameStateChangeReason.set(packet, ClientboundGameEventPacket.CHANGE_GAME_MODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlayerBuildAbilities(Player player) {
|
|
||||||
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
|
|
||||||
abilities.mayBuild = true;
|
|
||||||
abilities.mayfly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Material pathMaterial() {
|
|
||||||
return Material.DIRT_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int threshold = 2048;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkItemStack(ItemStack item) {
|
|
||||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
|
||||||
if (data == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return drillDown(data.contents(), 0, 0) > threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int drillDown(List<ItemStack> items, int layer, int start) {
|
|
||||||
if (layer > 2) return start + threshold;
|
|
||||||
int invalid = start;
|
|
||||||
for (int i = start; i < items.size(); i++) {
|
|
||||||
ItemStack item = items.get(i);
|
|
||||||
if (item.isEmpty()) continue;
|
|
||||||
|
|
||||||
invalid += item.getAmount();
|
|
||||||
|
|
||||||
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
|
|
||||||
if (data == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ItemStack> subItems = data.contents();
|
|
||||||
if (subItems.size() > 1) {
|
|
||||||
invalid = drillDown(subItems, layer + 1, invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resetExplosionKnockback(Object packet) {
|
|
||||||
ClientboundExplodePacket explosion = (ClientboundExplodePacket) packet;
|
|
||||||
|
|
||||||
return new ClientboundExplodePacket(
|
|
||||||
explosion.center(),
|
|
||||||
Optional.empty(),
|
|
||||||
explosion.explosionParticle(),
|
|
||||||
explosion.explosionSound()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class PlayerMovementWrapper21 implements PlayerMovementWrapper {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPosition(Player player, Object object) {
|
|
||||||
ServerboundMovePlayerPacket packetPlayInFlying = ((ServerboundMovePlayerPacket) object);
|
|
||||||
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
|
||||||
if (packetPlayInFlying.hasPos) {
|
|
||||||
serverPlayer.setPosRaw(packetPlayInFlying.x, packetPlayInFlying.y, packetPlayInFlying.z);
|
|
||||||
}
|
|
||||||
if (packetPlayInFlying.hasRot) {
|
|
||||||
serverPlayer.setXRot(packetPlayInFlying.xRot);
|
|
||||||
serverPlayer.setYRot(packetPlayInFlying.yRot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object convertToOut(Player player, Object object) {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
|
||||||
|
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.ServerTickRateManager;
|
|
||||||
import net.minecraft.world.TickRateManager;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
public class TickManager21 implements TickManager {
|
|
||||||
private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
|
|
||||||
private static final Reflection.Field<Integer> frozenTicksToRun = Reflection.getField(TickRateManager.class, int.class, 0);
|
|
||||||
private static final Reflection.Field<Long> remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0);
|
|
||||||
|
|
||||||
private boolean blockTpsPacket = true;
|
|
||||||
private int totalSteps;
|
|
||||||
|
|
||||||
public TickManager21() {
|
|
||||||
TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object blockPacket(Player player, Object packet) {
|
|
||||||
if (blockTpsPacket) {
|
|
||||||
return new ClientboundTickingStatePacket(20, manager.isFrozen());
|
|
||||||
} else {
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canFreeze() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBlockTpsPacket(boolean block) {
|
|
||||||
blockTpsPacket = block;
|
|
||||||
if (blockTpsPacket) {
|
|
||||||
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(20, manager.isFrozen());
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
|
|
||||||
} else {
|
|
||||||
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(manager.tickrate(), manager.isFrozen());
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTickRate(float tickRate) {
|
|
||||||
if (isFrozen()) {
|
|
||||||
setFreeze(false);
|
|
||||||
}
|
|
||||||
manager.setTickRate(tickRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFrozen() {
|
|
||||||
return manager.isFrozen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFreeze(boolean freeze) {
|
|
||||||
manager.setFrozen(freeze);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stepTicks(int ticks) {
|
|
||||||
if (manager.isSprinting()) {
|
|
||||||
manager.stopSprinting();
|
|
||||||
} else if (manager.isSteppingForward()) {
|
|
||||||
manager.stopStepping();
|
|
||||||
}
|
|
||||||
this.totalSteps = ticks;
|
|
||||||
manager.setFrozen(true);
|
|
||||||
manager.stepGameIfPaused(ticks);
|
|
||||||
manager.setFrozen(false);
|
|
||||||
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), (bukkitTask) -> {
|
|
||||||
if (manager.isSteppingForward()) return;
|
|
||||||
manager.setFrozen(true);
|
|
||||||
bukkitTask.cancel();
|
|
||||||
}, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sprintTicks(int ticks) {
|
|
||||||
if (manager.isSteppingForward()) {
|
|
||||||
manager.stopStepping();
|
|
||||||
} else if (manager.isSprinting()) {
|
|
||||||
manager.stopSprinting();
|
|
||||||
}
|
|
||||||
this.totalSteps = ticks;
|
|
||||||
manager.requestGameToSprint(ticks, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSprinting() {
|
|
||||||
return manager.isSprinting();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStepping() {
|
|
||||||
return manager.isSteppingForward();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getTickRate() {
|
|
||||||
return manager.tickrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getRemainingTicks() {
|
|
||||||
if (isSprinting()) {
|
|
||||||
return remainingSprintTicks.get(manager);
|
|
||||||
} else {
|
|
||||||
return frozenTicksToRun.get(manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDoneTicks() {
|
|
||||||
return totalSteps - getRemainingTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTotalTicks() {
|
|
||||||
return totalSteps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
steamwar.java
|
steamwar.java
|
||||||
|
widener
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava {
|
tasks.compileJava {
|
||||||
@@ -26,21 +27,29 @@ tasks.compileJava {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(libs.classindex)
|
compileOnly(libs.classindex)
|
||||||
annotationProcessor(libs.classindex)
|
annotationProcessor(libs.classindex)
|
||||||
compileOnly(project(":SpigotCore", "default"))
|
compileOnly(project(":SpigotCore", "default"))
|
||||||
|
compileOnly(project(":KotlinCore", "default"))
|
||||||
|
|
||||||
compileOnly(libs.spigotapi)
|
|
||||||
compileOnly(libs.axiom)
|
compileOnly(libs.axiom)
|
||||||
compileOnly(libs.authlib)
|
compileOnly(libs.authlib)
|
||||||
|
|
||||||
compileOnly(libs.fawe18)
|
compileOnly(libs.paperapi)
|
||||||
|
compileOnly(libs.nms)
|
||||||
|
|
||||||
|
compileOnly(libs.fawe)
|
||||||
|
compileOnly(libs.netty)
|
||||||
|
|
||||||
implementation(libs.luaj)
|
implementation(libs.luaj)
|
||||||
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
// implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
|
||||||
|
}
|
||||||
|
|
||||||
|
widener {
|
||||||
|
fromCatalog(libs.nms)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
|||||||
|
accessWidener v2 named
|
||||||
|
|
||||||
|
# For NoClipCommand
|
||||||
|
accessible field net/minecraft/server/level/ServerPlayerGameMode gameModeForPlayer Lnet/minecraft/world/level/GameType;
|
||||||
|
|
||||||
|
# For PlaceItemUtils
|
||||||
|
accessible field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
||||||
|
mutable field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
|
||||||
|
accessible field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
||||||
|
mutable field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
|
||||||
|
|
||||||
|
# For TickManager
|
||||||
|
accessible field net/minecraft/server/ServerTickRateManager remainingSprintTicks J
|
||||||
@@ -20,8 +20,7 @@
|
|||||||
package de.steamwar.bausystem;
|
package de.steamwar.bausystem;
|
||||||
|
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
import de.steamwar.bausystem.configplayer.Config;
|
import de.steamwar.bausystem.config.ConfigStore;
|
||||||
import de.steamwar.bausystem.configplayer.ConfigConverter;
|
|
||||||
import de.steamwar.bausystem.features.gui.BauGUI;
|
import de.steamwar.bausystem.features.gui.BauGUI;
|
||||||
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
|
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
|
||||||
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
|
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
|
||||||
@@ -32,17 +31,17 @@ import de.steamwar.bausystem.features.tracer.TraceManager;
|
|||||||
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||||
import de.steamwar.bausystem.features.world.BauScoreboard;
|
import de.steamwar.bausystem.features.world.BauScoreboard;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.BauGuiItem;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.RegionSystem;
|
import de.steamwar.bausystem.region.RegionSystem;
|
||||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||||
import de.steamwar.bausystem.utils.TickListener;
|
|
||||||
import de.steamwar.bausystem.utils.TickManager;
|
import de.steamwar.bausystem.utils.TickManager;
|
||||||
import de.steamwar.bausystem.worlddata.WorldData;
|
|
||||||
import de.steamwar.command.AbstractValidator;
|
import de.steamwar.command.AbstractValidator;
|
||||||
import de.steamwar.command.SWCommandUtils;
|
import de.steamwar.command.SWCommandUtils;
|
||||||
import de.steamwar.core.CRIUSleepEvent;
|
import de.steamwar.core.CRIUSleepEvent;
|
||||||
import de.steamwar.core.Core;
|
import de.steamwar.core.Core;
|
||||||
import de.steamwar.core.WorldEditRendererCUIEditor;
|
|
||||||
import de.steamwar.core.WorldIdentifier;
|
import de.steamwar.core.WorldIdentifier;
|
||||||
|
import de.steamwar.core.worldedit.SteamEdit;
|
||||||
|
import de.steamwar.core.worldedit.WorldEditRendererCUIEditor;
|
||||||
import de.steamwar.linkage.AbstractLinker;
|
import de.steamwar.linkage.AbstractLinker;
|
||||||
import de.steamwar.linkage.SpigotLinker;
|
import de.steamwar.linkage.SpigotLinker;
|
||||||
import de.steamwar.message.Message;
|
import de.steamwar.message.Message;
|
||||||
@@ -50,6 +49,7 @@ import de.steamwar.providers.BauServerInfo;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameRule;
|
import org.bukkit.GameRule;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@@ -110,9 +110,6 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
if (any instanceof PanzernAlgorithm) {
|
if (any instanceof PanzernAlgorithm) {
|
||||||
Panzern.add((PanzernAlgorithm) any);
|
Panzern.add((PanzernAlgorithm) any);
|
||||||
}
|
}
|
||||||
if (any instanceof ConfigConverter) {
|
|
||||||
Config.addConfigConverter((ConfigConverter) any);
|
|
||||||
}
|
|
||||||
if (any instanceof BoundingBoxLoader) {
|
if (any instanceof BoundingBoxLoader) {
|
||||||
((BoundingBoxLoader) any).load();
|
((BoundingBoxLoader) any).load();
|
||||||
}
|
}
|
||||||
@@ -127,12 +124,22 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TickListener.impl.init();
|
|
||||||
|
|
||||||
TraceManager.instance.init();
|
TraceManager.instance.init();
|
||||||
TraceRecorder.instance.init();
|
TraceRecorder.instance.init();
|
||||||
|
|
||||||
new WorldEditRendererCUIEditor();
|
SteamEdit.init();
|
||||||
|
SteamEdit.ADJACENT_FILTERS = location -> {
|
||||||
|
Region region = Region.getRegion(location);
|
||||||
|
Region.Area area;
|
||||||
|
if (region.getBuildArea().inRegion(location, true)) {
|
||||||
|
area = region.getBuildArea();
|
||||||
|
} else if (region.getTestblockArea().inRegion(location, true)) {
|
||||||
|
area = region.getTestblockArea();
|
||||||
|
} else {
|
||||||
|
return SteamEdit.AdjacentFilter.ALWAYS;
|
||||||
|
}
|
||||||
|
return (x, y, z) -> area.inRegion(new Location(null, x, y, z), true);
|
||||||
|
};
|
||||||
|
|
||||||
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
|
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
|
||||||
|
|
||||||
@@ -148,9 +155,8 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
linker.unlink();
|
linker.unlink();
|
||||||
WorldData.write();
|
|
||||||
RegionSystem.INSTANCE.save();
|
RegionSystem.INSTANCE.save();
|
||||||
Config.getInstance().saveAll();
|
ConfigStore.saveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends CommandSender> AbstractValidator<T, ?> validator(Permission permission) {
|
private <T extends CommandSender> AbstractValidator<T, ?> validator(Permission permission) {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a config of one version into the next version, e.g. ConfigV1 to
|
||||||
|
* ConfigV2. The converter for the second newest version converts into the
|
||||||
|
* current version. Converters are registered in the {@link ConfigStore}
|
||||||
|
* of the config.
|
||||||
|
*
|
||||||
|
* @param <F> the config version to convert from
|
||||||
|
* @param <T> the config version to convert to
|
||||||
|
*/
|
||||||
|
public interface ConfigConverter<F extends VersionedConfig, T extends VersionedConfig> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the version this converter converts from
|
||||||
|
*/
|
||||||
|
int version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the config to the next version. If anything goes wrong do not
|
||||||
|
* silently exit this method, throw an Exception. The {@link ConfigStore}
|
||||||
|
* will deal with it.
|
||||||
|
*
|
||||||
|
* @param config the config to convert
|
||||||
|
* @return the converted config
|
||||||
|
*/
|
||||||
|
T convert(F config);
|
||||||
|
}
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.config;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import de.steamwar.sql.UserConfig;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads, converts and saves a versioned config stored as JSON. Older versions
|
||||||
|
* are converted with the registered {@link ConfigConverter}s, legacy formats
|
||||||
|
* that are not JSON can be read with {@link #legacy(Predicate, Function)}.
|
||||||
|
* <p>
|
||||||
|
* A store can be bound to where the config is stored:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #userConfig(String)}: one config per player in the {@link UserConfig}, use {@link #get(Player)}</li>
|
||||||
|
* <li>{@link #file(File)}: one config in a file, use {@link #get()}</li>
|
||||||
|
* <li>unbound: use {@link #load(File)} and {@link #save(File, VersionedConfig)}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param <T> the current config version
|
||||||
|
*/
|
||||||
|
public class ConfigStore<T extends VersionedConfig> {
|
||||||
|
|
||||||
|
private static final List<ConfigStore<?>> STORES = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Class<T> type;
|
||||||
|
private final int version;
|
||||||
|
private final Supplier<T> defaultConfig;
|
||||||
|
|
||||||
|
private final Map<Integer, Class<? extends VersionedConfig>> jsonVersions = new HashMap<>();
|
||||||
|
private final Map<Integer, ConfigConverter<?, ?>> converters = new HashMap<>();
|
||||||
|
private final List<LegacyFormat> legacyFormats = new ArrayList<>();
|
||||||
|
private Gson gson = new Gson();
|
||||||
|
private Integer unversionedVersion = null;
|
||||||
|
|
||||||
|
private String userConfigKey = null;
|
||||||
|
private Predicate<T> removeIf = config -> false;
|
||||||
|
private final Map<UUID, T> playerConfigs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private File file = null;
|
||||||
|
private File legacyFile = null;
|
||||||
|
private Function<String, ? extends VersionedConfig> legacyFileReader = null;
|
||||||
|
private T fileConfig = null;
|
||||||
|
|
||||||
|
private record LegacyFormat(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigStore(Class<T> type, int version, Supplier<T> defaultConfig) {
|
||||||
|
this.type = type;
|
||||||
|
this.version = version;
|
||||||
|
this.defaultConfig = defaultConfig;
|
||||||
|
jsonVersions.put(version, type);
|
||||||
|
STORES.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigStore<T> gson(Gson gson) {
|
||||||
|
this.gson = gson;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an older config version that is stored as JSON.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> jsonVersion(int version, Class<? extends VersionedConfig> type) {
|
||||||
|
jsonVersions.put(version, type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigStore<T> converter(ConfigConverter<?, ?> converter) {
|
||||||
|
if (converters.putIfAbsent(converter.version(), converter) != null) {
|
||||||
|
throw new IllegalStateException("Duplicate converter for version " + converter.version() + " of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a legacy format that is not JSON, stored strings matching the predicate are read by the reader.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> legacy(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
|
||||||
|
legacyFormats.add(new LegacyFormat(matches, reader));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of stored JSON without a version field.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> unversioned(int version) {
|
||||||
|
this.unversionedVersion = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds this store to the {@link UserConfig} with the given key, one config per player.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> userConfig(String key) {
|
||||||
|
this.userConfigKey = key;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the config from the {@link UserConfig} instead of saving it, if the predicate matches.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> removeIf(Predicate<T> removeIf) {
|
||||||
|
this.removeIf = removeIf;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds this store to a single file.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> file(File file) {
|
||||||
|
this.file = file;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy file to read, if the file of this store does not exist yet.
|
||||||
|
*/
|
||||||
|
public ConfigStore<T> legacyFile(File legacyFile, Function<String, ? extends VersionedConfig> reader) {
|
||||||
|
this.legacyFile = legacyFile;
|
||||||
|
this.legacyFileReader = reader;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a stored config and converts it to the current version.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if the config could not be read or converted
|
||||||
|
*/
|
||||||
|
public T read(String stored) {
|
||||||
|
for (LegacyFormat legacyFormat : legacyFormats) {
|
||||||
|
if (legacyFormat.matches().test(stored)) {
|
||||||
|
return update(legacyFormat.reader().apply(stored));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject json = JsonParser.parseString(stored).getAsJsonObject();
|
||||||
|
int storedVersion;
|
||||||
|
if (json.has("version")) {
|
||||||
|
storedVersion = json.get("version").getAsInt();
|
||||||
|
} else if (unversionedVersion != null) {
|
||||||
|
storedVersion = unversionedVersion;
|
||||||
|
json.addProperty("version", storedVersion);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Missing version of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
Class<? extends VersionedConfig> storedType = jsonVersions.get(storedVersion);
|
||||||
|
if (storedType == null) {
|
||||||
|
throw new IllegalStateException("Unknown version " + storedVersion + " of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
return update(gson.fromJson(json, storedType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String write(T config) {
|
||||||
|
return gson.toJson(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a config to the current version.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public T update(VersionedConfig config) {
|
||||||
|
while (config.getVersion() < version) {
|
||||||
|
ConfigConverter converter = converters.get(config.getVersion());
|
||||||
|
if (converter == null) {
|
||||||
|
throw new IllegalStateException("No converter found for version " + config.getVersion() + " of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
VersionedConfig converted = converter.convert(config);
|
||||||
|
if (converted.getVersion() <= config.getVersion()) {
|
||||||
|
throw new IllegalStateException("Version did not increase after conversion of version " + config.getVersion() + " of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
config = converted;
|
||||||
|
}
|
||||||
|
if (!type.isInstance(config)) {
|
||||||
|
throw new IllegalStateException("Version " + config.getVersion() + " is not the current version of " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
return type.cast(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the config stored in the file, or the default config if the file is missing or empty
|
||||||
|
* @throws RuntimeException if the config could not be read or converted
|
||||||
|
*/
|
||||||
|
public T load(File file) throws IOException {
|
||||||
|
if (file.length() == 0) {
|
||||||
|
return defaultConfig.get();
|
||||||
|
}
|
||||||
|
return read(Files.readString(file.toPath(), StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(File file, T config) throws IOException {
|
||||||
|
Files.writeString(file.toPath(), write(config), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the config of a player, loads it from the {@link UserConfig} and converts it if necessary.
|
||||||
|
*/
|
||||||
|
public T get(Player player) {
|
||||||
|
requireUserConfig();
|
||||||
|
return playerConfigs.computeIfAbsent(player.getUniqueId(), this::loadPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the config of a player, this does not unload the config.
|
||||||
|
*/
|
||||||
|
public void save(Player player) {
|
||||||
|
requireUserConfig();
|
||||||
|
T config = playerConfigs.get(player.getUniqueId());
|
||||||
|
if (config != null) {
|
||||||
|
savePlayer(player.getUniqueId(), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save and unload the config of a player.
|
||||||
|
*/
|
||||||
|
public void unload(Player player) {
|
||||||
|
if (userConfigKey == null) return;
|
||||||
|
T config = playerConfigs.remove(player.getUniqueId());
|
||||||
|
if (config != null) {
|
||||||
|
savePlayer(player.getUniqueId(), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private T loadPlayer(UUID uuid) {
|
||||||
|
String stored = UserConfig.getConfig(uuid, userConfigKey);
|
||||||
|
if (stored == null) {
|
||||||
|
return defaultConfig.get();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return read(stored);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + type.getSimpleName() + " of " + uuid, e);
|
||||||
|
return defaultConfig.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePlayer(UUID uuid, T config) {
|
||||||
|
if (removeIf.test(config)) {
|
||||||
|
UserConfig.removePlayerConfig(uuid, userConfigKey);
|
||||||
|
} else {
|
||||||
|
UserConfig.updatePlayerConfig(uuid, userConfigKey, write(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireUserConfig() {
|
||||||
|
if (userConfigKey == null) {
|
||||||
|
throw new IllegalStateException(type.getSimpleName() + " is not stored in the UserConfig");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the config of the file of this store, loads it and converts it if necessary.
|
||||||
|
*/
|
||||||
|
public T get() {
|
||||||
|
requireFile();
|
||||||
|
if (fileConfig == null) {
|
||||||
|
fileConfig = loadFile();
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
return fileConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the config to the file of this store, if it was loaded.
|
||||||
|
*/
|
||||||
|
public void save() {
|
||||||
|
requireFile();
|
||||||
|
if (fileConfig == null) return;
|
||||||
|
try {
|
||||||
|
save(file, fileConfig);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Could not write " + file, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private T loadFile() {
|
||||||
|
try {
|
||||||
|
if (file.length() != 0) {
|
||||||
|
return load(file);
|
||||||
|
}
|
||||||
|
if (legacyFile != null && legacyFile.length() != 0) {
|
||||||
|
return update(legacyFileReader.apply(Files.readString(legacyFile.toPath(), StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
return defaultConfig.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + file + ", using default " + type.getSimpleName(), e);
|
||||||
|
backupBrokenFile();
|
||||||
|
return defaultConfig.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backupBrokenFile() {
|
||||||
|
if (file.length() == 0) return;
|
||||||
|
try {
|
||||||
|
Files.copy(file.toPath(), new File(file.getParentFile(), file.getName() + ".broken").toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Could not backup broken " + file, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireFile() {
|
||||||
|
if (file == null) {
|
||||||
|
throw new IllegalStateException(type.getSimpleName() + " is not bound to a file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unloadAll(Player player) {
|
||||||
|
STORES.forEach(store -> store.unload(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves every loaded config and unloads the configs of the players.
|
||||||
|
*/
|
||||||
|
public static void saveAll() {
|
||||||
|
for (ConfigStore<?> store : STORES) {
|
||||||
|
if (store.userConfigKey != null) {
|
||||||
|
store.playerConfigs.forEach((uuid, config) -> saveUnchecked(store, uuid, config));
|
||||||
|
store.playerConfigs.clear();
|
||||||
|
}
|
||||||
|
if (store.file != null) {
|
||||||
|
store.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T extends VersionedConfig> void saveUnchecked(ConfigStore<T> store, UUID uuid, Object config) {
|
||||||
|
store.savePlayer(uuid, (T) config);
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-8
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -17,18 +17,29 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.core;
|
package de.steamwar.bausystem.config;
|
||||||
|
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.core.CRIUSleepEvent;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.player.PlayerLocaleChangeEvent;
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import java.util.Locale;
|
/**
|
||||||
|
* Saves and unloads the configs of the {@link ConfigStore}s bound to the UserConfig
|
||||||
|
* when a player quits, configs are loaded on first use.
|
||||||
|
*/
|
||||||
|
@Linked
|
||||||
|
public class ConfigStoreListener implements Listener {
|
||||||
|
|
||||||
public class LocaleChangeWrapper12 implements LocaleChangeWrapper {
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
ConfigStore.unloadAll(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
private void onLocale(PlayerLocaleChangeEvent event) {
|
public void onCRIUSleep(CRIUSleepEvent event) {
|
||||||
SteamwarUser.get(event.getPlayer().getUniqueId()).setLocale(Locale.forLanguageTag(event.getLocale()), false);
|
ConfigStore.saveAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-12
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -17,15 +17,13 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
package de.steamwar.bausystem.config;
|
||||||
steamwar.java
|
|
||||||
}
|
/**
|
||||||
|
* Common interface of every version of a config stored by a {@link ConfigStore},
|
||||||
dependencies {
|
* the current version (e.g. Config) and every older version (ConfigV1, ConfigV2, ...).
|
||||||
compileOnly(project(":FightSystem:FightSystem_Core", "default"))
|
*/
|
||||||
compileOnly(project(":FightSystem:FightSystem_18", "default"))
|
public interface VersionedConfig {
|
||||||
|
|
||||||
compileOnly(libs.spigotapi)
|
int getVersion();
|
||||||
|
|
||||||
compileOnly(libs.nms19)
|
|
||||||
}
|
}
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.config.legacy;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes {@link ItemStack}s that were serialized by YAPION, read with {@link YapionReader}.
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
@Deprecated
|
||||||
|
public class YapionItemDeserializer {
|
||||||
|
|
||||||
|
private static final String TYPE_IDENTIFIER = "@type";
|
||||||
|
|
||||||
|
public ItemStack deserializeItem(Object yapion) {
|
||||||
|
if (yapion == null) return null;
|
||||||
|
Object result = deserialize(yapion);
|
||||||
|
if (result instanceof ItemStack itemStack) return itemStack;
|
||||||
|
throw new IllegalArgumentException("Not an ItemStack: " + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object deserialize(Object yapion) {
|
||||||
|
if (yapion instanceof List<?> list) {
|
||||||
|
List<Object> result = new ArrayList<>();
|
||||||
|
list.forEach(o -> result.add(deserialize(o)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (yapion instanceof YapionReader.YapionMap map) {
|
||||||
|
Map<Object, Object> result = new LinkedHashMap<>();
|
||||||
|
map.entries().forEach((key, value) -> result.put(deserialize(key), deserialize(value)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (yapion instanceof Map<?, ?> object) {
|
||||||
|
return deserializeObject(object);
|
||||||
|
}
|
||||||
|
return yapion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object deserializeObject(Map<?, ?> object) {
|
||||||
|
Map<String, Object> data = new LinkedHashMap<>();
|
||||||
|
object.forEach((key, value) -> {
|
||||||
|
if (!TYPE_IDENTIFIER.equals(key)) data.put((String) key, deserialize(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!(object.get(TYPE_IDENTIFIER) instanceof String type)) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> javaType = javaUtilClass(type);
|
||||||
|
if (javaType != null && Collection.class.isAssignableFrom(javaType)) {
|
||||||
|
return data.getOrDefault("values", new ArrayList<>());
|
||||||
|
}
|
||||||
|
if (javaType != null && Map.class.isAssignableFrom(javaType)) {
|
||||||
|
return data.containsKey("values") ? data.get("values") : data;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, type.equals("org.bukkit.inventory.meta.ItemMeta") ? "ItemMeta" : type);
|
||||||
|
return ConfigurationSerialization.deserializeObject(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> javaUtilClass(String type) {
|
||||||
|
if (!type.startsWith("java.util.")) return null;
|
||||||
|
try {
|
||||||
|
return Class.forName(type);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.config.legacy;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal reader for the legacy YAPION format, only used to migrate old data.
|
||||||
|
* <p>
|
||||||
|
* The result is built from plain java objects:
|
||||||
|
* <ul>
|
||||||
|
* <li>YAPION objects {@code {key(value)}} become a {@link LinkedHashMap} of String to value</li>
|
||||||
|
* <li>YAPION arrays {@code [a,b]} become a {@link List}</li>
|
||||||
|
* <li>YAPION maps {@code <(a):(b)>} become a {@link YapionMap}</li>
|
||||||
|
* <li>YAPION values {@code (value)} become null, Boolean, Number or String</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public class YapionReader {
|
||||||
|
|
||||||
|
private static final Pattern INTEGER = Pattern.compile("[-+]?\\d+");
|
||||||
|
private static final Pattern DECIMAL = Pattern.compile("[-+]?(\\d+\\.\\d*|\\.\\d+|\\d+)([eE][-+]?\\d+)?");
|
||||||
|
|
||||||
|
public record YapionMap(Map<Object, Object> entries) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> parse(String yapion) {
|
||||||
|
YapionReader reader = new YapionReader(yapion);
|
||||||
|
reader.skipWhitespace();
|
||||||
|
Map<String, Object> result = reader.readObject();
|
||||||
|
reader.skipWhitespace();
|
||||||
|
if (reader.index != yapion.length()) {
|
||||||
|
throw reader.error("Unexpected trailing content");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getDouble(Map<?, ?> object, String key, double defaultValue) {
|
||||||
|
return object.get(key) instanceof Number value ? value.doubleValue() : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getInt(Map<?, ?> object, String key, int defaultValue) {
|
||||||
|
return object.get(key) instanceof Number value ? value.intValue() : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getBoolean(Map<?, ?> object, String key, boolean defaultValue) {
|
||||||
|
return object.get(key) instanceof Boolean value ? value : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(Map<?, ?> object, String key, String defaultValue) {
|
||||||
|
return object.get(key) instanceof String value ? value : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the entries of the array that are YAPION objects
|
||||||
|
*/
|
||||||
|
public static List<Map<?, ?>> getObjects(Map<?, ?> object, String key) {
|
||||||
|
List<Map<?, ?>> objects = new ArrayList<>();
|
||||||
|
if (object.get(key) instanceof List<?> array) {
|
||||||
|
array.forEach(o -> {
|
||||||
|
if (o instanceof Map<?, ?> map) objects.add(map);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String input;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
private YapionReader(String input) {
|
||||||
|
this.input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readAny() {
|
||||||
|
return switch (peek()) {
|
||||||
|
case '{' -> readObject();
|
||||||
|
case '[' -> readArray();
|
||||||
|
case '<' -> readMap();
|
||||||
|
case '(' -> readValue();
|
||||||
|
default -> throw error("Expected '{', '[', '<' or '('");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> readObject() {
|
||||||
|
expect('{');
|
||||||
|
Map<String, Object> object = new LinkedHashMap<>();
|
||||||
|
while (true) {
|
||||||
|
skipWhitespace();
|
||||||
|
if (peek() == '}') {
|
||||||
|
index++;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
StringBuilder key = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
char c = peek();
|
||||||
|
if (c == '(' || c == '{' || c == '[' || c == '<') break;
|
||||||
|
if (c == '}') throw error("Key without value");
|
||||||
|
key.append(readChar());
|
||||||
|
}
|
||||||
|
object.put(key.toString(), readAny());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> readArray() {
|
||||||
|
expect('[');
|
||||||
|
List<Object> array = new ArrayList<>();
|
||||||
|
skipWhitespace();
|
||||||
|
if (peek() == ']') {
|
||||||
|
index++;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
int start = index;
|
||||||
|
skipWhitespace();
|
||||||
|
char c = peek();
|
||||||
|
if (c == '{' || c == '[' || c == '<' || c == '(') {
|
||||||
|
array.add(readAny());
|
||||||
|
skipWhitespace();
|
||||||
|
} else {
|
||||||
|
// Whitespace is part of plain values
|
||||||
|
index = start;
|
||||||
|
StringBuilder value = new StringBuilder();
|
||||||
|
while (peek() != ',' && peek() != ']') {
|
||||||
|
value.append(readChar());
|
||||||
|
}
|
||||||
|
array.add(typed(value.toString()));
|
||||||
|
}
|
||||||
|
char separator = input.charAt(index++);
|
||||||
|
if (separator == ']') return array;
|
||||||
|
if (separator != ',') throw error("Expected ',' or ']'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private YapionMap readMap() {
|
||||||
|
expect('<');
|
||||||
|
Map<Object, Object> map = new LinkedHashMap<>();
|
||||||
|
while (true) {
|
||||||
|
skipWhitespace();
|
||||||
|
if (peek() == '>') {
|
||||||
|
index++;
|
||||||
|
return new YapionMap(map);
|
||||||
|
}
|
||||||
|
Object key = readAny();
|
||||||
|
skipWhitespace();
|
||||||
|
expect(':');
|
||||||
|
skipWhitespace();
|
||||||
|
map.put(key, readAny());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YAPION does not escape parentheses in values, balanced parentheses are part of the value.
|
||||||
|
* A backslash only escapes a backslash, a unicode sequence or a control character, otherwise it is kept.
|
||||||
|
*/
|
||||||
|
private Object readValue() {
|
||||||
|
expect('(');
|
||||||
|
StringBuilder value = new StringBuilder();
|
||||||
|
int depth = 0;
|
||||||
|
while (true) {
|
||||||
|
char c = peek();
|
||||||
|
if (c == '\\') {
|
||||||
|
value.append(readValueEscape());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
if (c == '(') {
|
||||||
|
depth++;
|
||||||
|
} else if (c == ')') {
|
||||||
|
if (depth == 0) break;
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
value.append(c);
|
||||||
|
}
|
||||||
|
return typed(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readValueEscape() {
|
||||||
|
index++;
|
||||||
|
if (index >= input.length()) return "\\";
|
||||||
|
char escaped = input.charAt(index);
|
||||||
|
switch (escaped) {
|
||||||
|
case '\\', '(', ')':
|
||||||
|
index++;
|
||||||
|
return String.valueOf(escaped);
|
||||||
|
case 'n':
|
||||||
|
index++;
|
||||||
|
return "\n";
|
||||||
|
case 't':
|
||||||
|
index++;
|
||||||
|
return "\t";
|
||||||
|
case 'r':
|
||||||
|
index++;
|
||||||
|
return "\r";
|
||||||
|
case 'u':
|
||||||
|
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
|
||||||
|
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
|
||||||
|
index += 5;
|
||||||
|
return String.valueOf(unicode);
|
||||||
|
}
|
||||||
|
return "\\";
|
||||||
|
default:
|
||||||
|
return "\\";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads one character of a key or plain array value, resolving backslash escapes.
|
||||||
|
* A backslash that does not escape anything is kept, as the old player config
|
||||||
|
* collapsed escaped backslashes into a single one.
|
||||||
|
*/
|
||||||
|
private char readChar() {
|
||||||
|
char c = input.charAt(index++);
|
||||||
|
if (c != '\\') return c;
|
||||||
|
if (index >= input.length()) throw error("Unterminated escape");
|
||||||
|
char escaped = input.charAt(index);
|
||||||
|
switch (escaped) {
|
||||||
|
case 'n':
|
||||||
|
index++;
|
||||||
|
return '\n';
|
||||||
|
case 't':
|
||||||
|
index++;
|
||||||
|
return '\t';
|
||||||
|
case 'r':
|
||||||
|
index++;
|
||||||
|
return '\r';
|
||||||
|
case 'u':
|
||||||
|
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
|
||||||
|
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
|
||||||
|
index += 5;
|
||||||
|
return unicode;
|
||||||
|
}
|
||||||
|
return '\\';
|
||||||
|
case '\\', ',', ' ', '(', ')', '{', '}', '[', ']', '<', '>', '"', ':', '@':
|
||||||
|
index++;
|
||||||
|
return escaped;
|
||||||
|
default:
|
||||||
|
return '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object typed(String value) {
|
||||||
|
if (value.equals("null")) return null;
|
||||||
|
if (value.equals("true")) return true;
|
||||||
|
if (value.equals("false")) return false;
|
||||||
|
if (value.length() >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
|
||||||
|
return value.substring(1, value.length() - 1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (INTEGER.matcher(value).matches()) {
|
||||||
|
long l = Long.parseLong(value);
|
||||||
|
if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) return (int) l;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
if (value.length() > 1) {
|
||||||
|
String number = value.substring(0, value.length() - 1);
|
||||||
|
switch (value.charAt(value.length() - 1)) {
|
||||||
|
case 'L':
|
||||||
|
if (INTEGER.matcher(number).matches()) return Long.parseLong(number);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (INTEGER.matcher(number).matches()) return Short.parseShort(number);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
if (INTEGER.matcher(number).matches()) return Byte.parseByte(number);
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
if (DECIMAL.matcher(number).matches()) return Float.parseFloat(number);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
if (DECIMAL.matcher(number).matches()) return Double.parseDouble(number);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DECIMAL.matcher(value).matches()) return Double.parseDouble(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// Not a number, fall through to String
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skipWhitespace() {
|
||||||
|
while (index < input.length() && Character.isWhitespace(input.charAt(index))) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private char peek() {
|
||||||
|
if (index >= input.length()) throw error("Unexpected end of input");
|
||||||
|
return input.charAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expect(char c) {
|
||||||
|
if (peek() != c) throw error("Expected '" + c + "'");
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IllegalArgumentException error(String message) {
|
||||||
|
return new IllegalArgumentException(message + " at index " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.config.serializer;
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores an {@link ItemStack} as Base64 of {@link ItemStack#serializeAsBytes()}, which
|
||||||
|
* contains the data version and gets upgraded on newer Minecraft versions.
|
||||||
|
* Empty items are stored as null, items that can't be read are deserialized as null.
|
||||||
|
*/
|
||||||
|
public class ItemStackTypeAdapter extends TypeAdapter<ItemStack> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, ItemStack itemStack) throws IOException {
|
||||||
|
if (itemStack == null || itemStack.isEmpty()) {
|
||||||
|
out.nullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.value(Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack read(JsonReader in) throws IOException {
|
||||||
|
if (in.peek() == JsonToken.NULL) {
|
||||||
|
in.nextNull();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String value = in.nextString();
|
||||||
|
try {
|
||||||
|
return ItemStack.deserializeBytes(Base64.getDecoder().decode(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "Could not deserialize ItemStack", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -19,129 +19,77 @@
|
|||||||
|
|
||||||
package de.steamwar.bausystem.configplayer;
|
package de.steamwar.bausystem.configplayer;
|
||||||
|
|
||||||
import de.steamwar.bausystem.configplayer.serializer.ConfigurationSerializableSerializer;
|
import com.google.gson.GsonBuilder;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.bausystem.config.ConfigConverter;
|
||||||
import de.steamwar.sql.UserConfig;
|
import de.steamwar.bausystem.config.ConfigStore;
|
||||||
|
import de.steamwar.bausystem.config.VersionedConfig;
|
||||||
|
import de.steamwar.bausystem.config.serializer.ItemStackTypeAdapter;
|
||||||
|
import de.steamwar.bausystem.configplayer.converter.ConfigV1ToV2Converter;
|
||||||
|
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import lombok.Setter;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import yapion.hierarchy.output.StringOutput;
|
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
import yapion.parser.YAPIONParser;
|
|
||||||
import yapion.serializing.SerializeManager;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
@Linked
|
/**
|
||||||
public class Config implements Listener {
|
* The current player config. It is stored as JSON, fields missing in the
|
||||||
|
* stored JSON keep the default value of their initializer, so adding a new
|
||||||
|
* field does not need a new version.
|
||||||
|
* <p>
|
||||||
|
* When a field gets removed, renamed or its meaning changes, copy this class
|
||||||
|
* to ConfigV{@link #VERSION} (without the {@link #STORE}), increase {@link #VERSION},
|
||||||
|
* write a {@link ConfigConverter} from the copy to this class and register it in the {@link #STORE}.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Config implements VersionedConfig {
|
||||||
|
|
||||||
static {
|
public static final int VERSION = 2;
|
||||||
SerializeManager.add(new ConfigurationSerializableSerializer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
public static final ConfigStore<Config> STORE = new ConfigStore<>(Config.class, VERSION, Config::new)
|
||||||
private static Config instance;
|
.gson(new GsonBuilder().registerTypeHierarchyAdapter(ItemStack.class, new ItemStackTypeAdapter()).create())
|
||||||
|
.legacy(s -> s.startsWith("{@version(1)"), ConfigV1::parse)
|
||||||
|
.converter(new ConfigV1ToV2Converter())
|
||||||
|
.userConfig("bausystem");
|
||||||
|
|
||||||
{
|
@Setter(AccessLevel.NONE)
|
||||||
instance = this;
|
protected int version = VERSION;
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<UUID, YAPIONObject> playerConfigurations = new HashMap<>();
|
|
||||||
|
|
||||||
private static final Map<Integer, ConfigConverter> CONFIG_CONVERTER_MAP = new HashMap<>();
|
|
||||||
|
|
||||||
public static void addConfigConverter(ConfigConverter configConverter) {
|
|
||||||
CONFIG_CONVERTER_MAP.putIfAbsent(configConverter.version(), configConverter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
get(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
|
||||||
save(event.getPlayer());
|
|
||||||
playerConfigurations.remove(event.getPlayer().getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a PlayerConfig, optionally loads it from the DataBase and migrates it if necessary.
|
* BauGui item id to inventory slot
|
||||||
*
|
|
||||||
* @param player the player from whom to get the config.
|
|
||||||
* @return the config object
|
|
||||||
*/
|
*/
|
||||||
public YAPIONObject get(Player player) {
|
protected Map<Integer, Integer> bauGui = defaultBauGui();
|
||||||
UUID uuid = player.getUniqueId();
|
protected int bauGuiSize = 45;
|
||||||
if (!playerConfigurations.containsKey(uuid)) {
|
|
||||||
String s = UserConfig.getConfig(uuid, "bausystem");
|
|
||||||
YAPIONObject yapionObject;
|
|
||||||
if (s == null) {
|
|
||||||
yapionObject = ConfigCreator.createDefaultConfig();
|
|
||||||
} else {
|
|
||||||
yapionObject = YAPIONParser.parse(s);
|
|
||||||
}
|
|
||||||
yapionObject = update(yapionObject);
|
|
||||||
playerConfigurations.put(uuid, yapionObject);
|
|
||||||
return yapionObject;
|
|
||||||
}
|
|
||||||
return playerConfigurations.get(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveAll() {
|
|
||||||
playerConfigurations.forEach((uuid, yapionObject) -> {
|
|
||||||
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\+", "\\");
|
|
||||||
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
|
|
||||||
});
|
|
||||||
playerConfigurations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a PlayerConfig, this does not remove the key value mapping from the map.
|
* Slots 0-8 are the hotbar, slots 9-12 the armor contents
|
||||||
*
|
|
||||||
* @param player the player to save the config.
|
|
||||||
*/
|
*/
|
||||||
public void save(Player player) {
|
protected ItemStack[] hotbar = DefaultHotbar.defaultHotbar();
|
||||||
UUID uuid = player.getUniqueId();
|
|
||||||
if (playerConfigurations.containsKey(uuid)) {
|
|
||||||
YAPIONObject yapionObject = playerConfigurations.get(uuid);
|
|
||||||
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\\\+", "\\\\");
|
|
||||||
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private YAPIONObject update(YAPIONObject yapionObject) {
|
protected boolean nightVision = false;
|
||||||
int version = yapionObject.getPlainValue("@version");
|
protected boolean tntClickDetails = true;
|
||||||
while (version < ConfigCreator.currentVersion) {
|
protected boolean detonatorAutostart = false;
|
||||||
ConfigConverter configConverter = CONFIG_CONVERTER_MAP.getOrDefault(version, null);
|
protected boolean inventoryFill = false;
|
||||||
if (configConverter == null) {
|
protected boolean rayVisualizer = false;
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "No updater found for version " + version);
|
protected boolean smartPlace = false;
|
||||||
return ConfigCreator.createDefaultConfig();
|
protected boolean blockCounter = false;
|
||||||
}
|
protected boolean depthMessage = true;
|
||||||
try {
|
|
||||||
configConverter.update(yapionObject);
|
public static Map<Integer, Integer> defaultBauGui() {
|
||||||
} catch (Exception e) {
|
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
|
||||||
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
|
||||||
return ConfigCreator.createDefaultConfig();
|
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
|
||||||
}
|
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
|
||||||
int newVersion = yapionObject.getPlainValue("@version");
|
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
|
||||||
if (version == newVersion) {
|
Map<Integer, Integer> bauGui = new HashMap<>();
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was the same after conversion");
|
bauGui.put(10, 2); bauGui.put(3, 3); bauGui.put(7, 4); bauGui.put(17, 5); bauGui.put(15, 6);
|
||||||
return ConfigCreator.createDefaultConfig();
|
bauGui.put(5, 9); bauGui.put(4, 18); bauGui.put(6, 27);
|
||||||
}
|
bauGui.put(16, 17); bauGui.put(11, 26); bauGui.put(18, 35);
|
||||||
if (newVersion < version) {
|
bauGui.put(19, 20); bauGui.put(21, 21); bauGui.put(9, 22); bauGui.put(0, 23); bauGui.put(1, 24);
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was earlier after conversion");
|
bauGui.put(23, 37); bauGui.put(20, 38); bauGui.put(8, 39); bauGui.put(22, 40); bauGui.put(26, 41); bauGui.put(12, 42); bauGui.put(14, 43);
|
||||||
return ConfigCreator.createDefaultConfig();
|
return bauGui;
|
||||||
}
|
|
||||||
version = newVersion;
|
|
||||||
}
|
|
||||||
return yapionObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.configplayer;
|
|
||||||
|
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A new {@link ConfigConverter} should be written when you remove anything
|
|
||||||
* from the Config or modify any mayor part. When you move anything from
|
|
||||||
* any key to any other key you should write a new {@link ConfigConverter}.
|
|
||||||
* For adding any new key you should be able to get the default without
|
|
||||||
* having it in the Config. Anything you need to change you should also
|
|
||||||
* change the {@link ConfigCreator} accordingly, to produce the new Config.
|
|
||||||
*/
|
|
||||||
public interface ConfigConverter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This describes the version this Converter can convert from. The version
|
|
||||||
* it should convert to is the version 1 above this number. But this is not
|
|
||||||
* a necessity. In the config Object as parameter given in {@link #update(YAPIONObject)}
|
|
||||||
* you should update the <b>@version</b> variable in the root object to the
|
|
||||||
* new version this converter produced.
|
|
||||||
*
|
|
||||||
* @return the version number
|
|
||||||
*/
|
|
||||||
int version();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method should update everything needed to go from a lower config
|
|
||||||
* version to a higher. It should update the <b>@version</b> variable
|
|
||||||
* accordingly. Anything else is up the implementation. If anything goes wrong
|
|
||||||
* do not silently exit this method, throw an Exception. The updater Code will
|
|
||||||
* deal with it. Never leave the inputted object in a corrupted state.
|
|
||||||
*
|
|
||||||
* @param config the config object to update
|
|
||||||
*/
|
|
||||||
void update(YAPIONObject config);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.configplayer;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class ConfigCreator {
|
|
||||||
|
|
||||||
public static final int currentVersion = 1;
|
|
||||||
|
|
||||||
public YAPIONObject createDefaultConfig() {
|
|
||||||
YAPIONObject yapionObject = new YAPIONObject();
|
|
||||||
// This call should never be touched
|
|
||||||
yapionObject.add("@version", currentVersion);
|
|
||||||
|
|
||||||
// Any initialising goes into here
|
|
||||||
yapionObject.add("baugui", defaultBauGui());
|
|
||||||
|
|
||||||
// Default Hotbar Gui
|
|
||||||
yapionObject.add("hotbar", DefaultHotbar.defaultHotbar());
|
|
||||||
return yapionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private YAPIONObject defaultBauGui() {
|
|
||||||
YAPIONObject yapionObject = new YAPIONObject();
|
|
||||||
|
|
||||||
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
|
|
||||||
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
|
|
||||||
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
|
|
||||||
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
|
|
||||||
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
|
|
||||||
|
|
||||||
yapionObject.add("10", 2).add("3", 3).add("7", 4).add("17", 5).add("15", 6);
|
|
||||||
yapionObject.add("5", 9).add("4", 18).add("6", 27);
|
|
||||||
yapionObject.add("16", 17).add("11", 26).add("18", 35);
|
|
||||||
yapionObject.add("19", 20).add("21", 21).add("9", 22).add("0", 23).add("1", 24);
|
|
||||||
yapionObject.add("23", 37).add("20", 38).add("8", 39).add("22", 40).add("26", 41).add("12", 42).add("14", 43);
|
|
||||||
yapionObject.add("size", 45);
|
|
||||||
return yapionObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.configplayer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.config.VersionedConfig;
|
||||||
|
import de.steamwar.bausystem.config.legacy.YapionReader;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The legacy config that was stored in the YAPION format.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ConfigV1 implements VersionedConfig {
|
||||||
|
|
||||||
|
public static final int VERSION = 1;
|
||||||
|
|
||||||
|
@Setter(AccessLevel.NONE)
|
||||||
|
protected int version = VERSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BauGui item id to inventory slot
|
||||||
|
*/
|
||||||
|
protected Map<Integer, Integer> bauGui = new HashMap<>();
|
||||||
|
protected int bauGuiSize = 45;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft version to the hotbar serialized by YAPION, read with {@link YapionReader}.
|
||||||
|
* Use {@link de.steamwar.bausystem.config.legacy.YapionItemDeserializer} to get the items.
|
||||||
|
*/
|
||||||
|
protected Map<Integer, List<?>> hotbars = new HashMap<>();
|
||||||
|
|
||||||
|
protected boolean nightVision = false;
|
||||||
|
protected boolean tntClickDetails = true;
|
||||||
|
protected boolean detonatorAutostart = false;
|
||||||
|
protected boolean inventoryFill = false;
|
||||||
|
protected boolean rayVisualizer = false;
|
||||||
|
protected boolean smartPlace = false;
|
||||||
|
protected boolean blockCounter = false;
|
||||||
|
protected boolean depthMessage = true;
|
||||||
|
|
||||||
|
public static ConfigV1 parse(String yapion) {
|
||||||
|
Map<String, Object> object = YapionReader.parse(yapion);
|
||||||
|
ConfigV1 config = new ConfigV1();
|
||||||
|
config.version = (Integer) object.get("@version");
|
||||||
|
|
||||||
|
if (object.get("baugui") instanceof Map<?, ?> bauGui) {
|
||||||
|
bauGui.forEach((key, value) -> {
|
||||||
|
if (key.equals("size")) {
|
||||||
|
config.bauGuiSize = (Integer) value;
|
||||||
|
} else {
|
||||||
|
config.bauGui.put(Integer.parseInt((String) key), (Integer) value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
object.forEach((key, value) -> {
|
||||||
|
if (!(value instanceof List<?> hotbar)) return;
|
||||||
|
if (key.equals("hotbar")) {
|
||||||
|
// Hotbars were stored without version prior to 1.19
|
||||||
|
config.hotbars.putIfAbsent(19, hotbar);
|
||||||
|
} else if (key.startsWith("hotbar-")) {
|
||||||
|
config.hotbars.put(Integer.parseInt(key.substring("hotbar-".length())), hotbar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
config.nightVision = getBoolean(object, "nightvision", config.nightVision);
|
||||||
|
config.tntClickDetails = getBoolean(object, "tnt_click_details", config.tntClickDetails);
|
||||||
|
config.detonatorAutostart = getBoolean(object, "detonator-autostart", config.detonatorAutostart);
|
||||||
|
config.inventoryFill = getBoolean(object, "inventoryfill", config.inventoryFill);
|
||||||
|
config.rayVisualizer = getBoolean(object, "rayvisualizer", config.rayVisualizer);
|
||||||
|
config.smartPlace = getBoolean(object, "smartPlace", config.smartPlace);
|
||||||
|
config.blockCounter = getBoolean(object, "blockCounter", config.blockCounter);
|
||||||
|
config.depthMessage = getBoolean(object, "depth_message", config.depthMessage);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean getBoolean(Map<String, Object> object, String key, boolean defaultValue) {
|
||||||
|
return object.get(key) instanceof Boolean value ? value : defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.configplayer.converter;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.config.ConfigConverter;
|
||||||
|
import de.steamwar.bausystem.config.legacy.YapionItemDeserializer;
|
||||||
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
|
import de.steamwar.bausystem.configplayer.ConfigV1;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public class ConfigV1ToV2Converter implements ConfigConverter<ConfigV1, Config> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int version() {
|
||||||
|
return ConfigV1.VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Config convert(ConfigV1 old) {
|
||||||
|
Config config = new Config();
|
||||||
|
config.setBauGui(new HashMap<>(old.getBauGui()));
|
||||||
|
config.setBauGuiSize(old.getBauGuiSize());
|
||||||
|
|
||||||
|
List<?> hotbar = old.getHotbars().get(Core.getVersion());
|
||||||
|
if (hotbar != null) {
|
||||||
|
config.setHotbar(convertHotbar(hotbar));
|
||||||
|
}
|
||||||
|
|
||||||
|
config.setNightVision(old.isNightVision());
|
||||||
|
config.setTntClickDetails(old.isTntClickDetails());
|
||||||
|
config.setDetonatorAutostart(old.isDetonatorAutostart());
|
||||||
|
config.setInventoryFill(old.isInventoryFill());
|
||||||
|
config.setRayVisualizer(old.isRayVisualizer());
|
||||||
|
config.setSmartPlace(old.isSmartPlace());
|
||||||
|
config.setBlockCounter(old.isBlockCounter());
|
||||||
|
config.setDepthMessage(old.isDepthMessage());
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack[] convertHotbar(List<?> hotbar) {
|
||||||
|
ItemStack[] items = new ItemStack[13];
|
||||||
|
for (int i = 0; i < Math.min(hotbar.size(), items.length); i++) {
|
||||||
|
try {
|
||||||
|
items[i] = YapionItemDeserializer.deserializeItem(hotbar.get(i));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "Could not convert hotbar item " + i, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
-90
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bausystem.configplayer.serializer;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import yapion.hierarchy.api.groups.YAPIONAnyType;
|
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
import yapion.serializing.api.SerializerObject;
|
|
||||||
import yapion.serializing.data.DeserializeData;
|
|
||||||
import yapion.serializing.data.SerializeData;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static yapion.utils.IdentifierUtils.TYPE_IDENTIFIER;
|
|
||||||
|
|
||||||
public class ConfigurationSerializableSerializer extends SerializerObject<ConfigurationSerializable> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<ConfigurationSerializable> type() {
|
|
||||||
return ConfigurationSerializable.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInterface() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public YAPIONObject serialize(SerializeData<ConfigurationSerializable> serializeData) {
|
|
||||||
YAPIONObject yapionObject = new YAPIONObject();
|
|
||||||
yapionObject.add(TYPE_IDENTIFIER, serializeData.object.getClass().getTypeName());
|
|
||||||
if (serializeData.object instanceof ItemStack) {
|
|
||||||
yapionObject.add(TYPE_IDENTIFIER, ItemStack.class.getTypeName());
|
|
||||||
}
|
|
||||||
if (serializeData.object instanceof ItemMeta) {
|
|
||||||
yapionObject.add(TYPE_IDENTIFIER, ItemMeta.class.getTypeName());
|
|
||||||
}
|
|
||||||
Map<String, Object> serializeDataMap = serializeData.object.serialize();
|
|
||||||
serializeDataMap.forEach((s, o) -> {
|
|
||||||
YAPIONAnyType yapionAnyType = serializeData.serialize(o);
|
|
||||||
if (yapionAnyType instanceof YAPIONObject) {
|
|
||||||
YAPIONObject object = (YAPIONObject) yapionAnyType;
|
|
||||||
if (object.containsKey(TYPE_IDENTIFIER) && object.getPlainValue(TYPE_IDENTIFIER).equals("com.google.common.collect.RegularImmutableList")) {
|
|
||||||
object.put(TYPE_IDENTIFIER, ArrayList.class.getTypeName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yapionObject.add(s, yapionAnyType);
|
|
||||||
});
|
|
||||||
return yapionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConfigurationSerializable deserialize(DeserializeData<YAPIONObject> deserializeData) {
|
|
||||||
Map<String, Object> deserializeDataMap = new HashMap<>();
|
|
||||||
deserializeData.object.forEach((s, yapionAnyType) -> {
|
|
||||||
if (s.equals(TYPE_IDENTIFIER)) {
|
|
||||||
if (yapionAnyType.toString().equals("(org.bukkit.inventory.meta.ItemMeta)")) {
|
|
||||||
deserializeDataMap.put("==", "ItemMeta");
|
|
||||||
} else {
|
|
||||||
deserializeDataMap.put("==", deserializeData.deserialize(yapionAnyType));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deserializeDataMap.put(s, deserializeData.deserialize(yapionAnyType));
|
|
||||||
});
|
|
||||||
return ConfigurationSerialization.deserializeObject(deserializeDataMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+12
-4
@@ -76,13 +76,21 @@ public class AttributesCopyCommand extends SWCommand {
|
|||||||
if (itemStack.getType() == Material.ZOMBIE_HEAD && block.getType() == Material.ZOMBIE_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.ZOMBIE_HEAD && block.getType() == Material.ZOMBIE_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.CREEPER_HEAD && block.getType() == Material.CREEPER_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.CREEPER_HEAD && block.getType() == Material.CREEPER_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.DRAGON_HEAD && block.getType() == Material.DRAGON_WALL_HEAD) return true;
|
if (itemStack.getType() == Material.DRAGON_HEAD && block.getType() == Material.DRAGON_WALL_HEAD) return true;
|
||||||
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) return true;
|
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) {
|
||||||
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) return true;
|
return true;
|
||||||
|
}
|
||||||
|
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (itemStack.getType() == Material.TORCH && block.getType() == Material.WALL_TORCH) return true;
|
if (itemStack.getType() == Material.TORCH && block.getType() == Material.WALL_TORCH) return true;
|
||||||
if (itemStack.getType() == Material.SOUL_TORCH && block.getType() == Material.SOUL_WALL_TORCH) return true;
|
if (itemStack.getType() == Material.SOUL_TORCH && block.getType() == Material.SOUL_WALL_TORCH) return true;
|
||||||
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) return true;
|
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (itemStack.getType() == Material.WHEAT_SEEDS && block.getType() == Material.WHEAT) return true;
|
if (itemStack.getType() == Material.WHEAT_SEEDS && block.getType() == Material.WHEAT) return true;
|
||||||
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) return true;
|
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ public class AttributesPlaceListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockPlace(BlockPlaceEvent event) {
|
public void onBlockPlace(BlockPlaceEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
ItemStack itemStack = event.getItemInHand();
|
ItemStack itemStack = event.getItemInHand();
|
||||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
if (itemMeta == null) return;
|
if (itemMeta == null) return;
|
||||||
|
|||||||
+2
-2
@@ -65,7 +65,7 @@ public class AutostartListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!ItemUtils.isItem(event.getItem(), "autostart")) {
|
if (!ItemUtils.isItem(event.getItem(), "autostart")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ public class AutostartListener implements Listener {
|
|||||||
if (!(event.getPlayer() instanceof Player)) {
|
if (!(event.getPlayer() instanceof Player)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
|
||||||
if (!ItemUtils.isItem(event.getPlayer().getInventory().getItemInMainHand(), "autostart")) {
|
if (!ItemUtils.isItem(event.getPlayer().getInventory().getItemInMainHand(), "autostart")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -104,7 +104,8 @@ public class BackupCommand extends SWCommand {
|
|||||||
List<String> lore = Arrays.asList(BauSystem.MESSAGE.parse("BACKUP_LORE", p));
|
List<String> lore = Arrays.asList(BauSystem.MESSAGE.parse("BACKUP_LORE", p));
|
||||||
for (int i = 0; i < backups.size(); i++) {
|
for (int i = 0; i < backups.size(); i++) {
|
||||||
RegionBackups.Backup backup = backups.get(i);
|
RegionBackups.Backup backup = backups.get(i);
|
||||||
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, backup.getName()), lore, false, clickType -> {});
|
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, backup.getName()), lore, false, clickType -> {
|
||||||
|
});
|
||||||
swItem.getItemStack().setAmount(i + 1);
|
swItem.getItemStack().setAmount(i + 1);
|
||||||
swListEntries.add(new SWListInv.SWListEntry<>(swItem, backup));
|
swListEntries.add(new SWListInv.SWListEntry<>(swItem, backup));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class Depth {
|
|||||||
dimensions.setZ(Math.abs(dimensions.getZ()));
|
dimensions.setZ(Math.abs(dimensions.getZ()));
|
||||||
|
|
||||||
RegionUtils.message(region, player -> {
|
RegionUtils.message(region, player -> {
|
||||||
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
|
if (Config.STORE.get(player).isDepthMessage()) {
|
||||||
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
|
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-3
@@ -34,11 +34,11 @@ public class DepthCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register
|
@Register
|
||||||
public void toggle(Player player) {
|
public void toggle(Player player) {
|
||||||
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
|
if (Config.STORE.get(player).isDepthMessage()) {
|
||||||
Config.getInstance().get(player).put("depth_message", false);
|
Config.STORE.get(player).setDepthMessage(false);
|
||||||
BauSystem.MESSAGE.send("DEPTH_COUNTER_DISABLE", player);
|
BauSystem.MESSAGE.send("DEPTH_COUNTER_DISABLE", player);
|
||||||
} else {
|
} else {
|
||||||
Config.getInstance().get(player).put("depth_message", true);
|
Config.STORE.get(player).setDepthMessage(true);
|
||||||
BauSystem.MESSAGE.send("DEPTH_COUNTER_ENABLE", player);
|
BauSystem.MESSAGE.send("DEPTH_COUNTER_ENABLE", player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -58,14 +58,14 @@ public class Countingwand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemStack getWandItem(Player player) {
|
public static ItemStack getWandItem(Player player) {
|
||||||
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
ItemStack itemStack = new SWItem(Material.STICK, BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE1", player), BauSystem.MESSAGE.parse("COUNTINGWAND_ITEM_LORE2", player)), false, null).getItemStack();
|
||||||
ItemUtils.setItem(itemStack, "countingwand");
|
ItemUtils.setItem(itemStack, "countingwand");
|
||||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
itemMeta.setCustomModelData(1);
|
itemMeta.setCustomModelData(1);
|
||||||
itemStack.setItemMeta(itemMeta);
|
itemStack.setItemMeta(itemMeta);
|
||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCountingwand(ItemStack itemStack) {
|
public boolean isCountingwand(ItemStack itemStack) {
|
||||||
return ItemUtils.isItem(itemStack, "countingwand");
|
return ItemUtils.isItem(itemStack, "countingwand");
|
||||||
|
|||||||
+7
-7
@@ -28,12 +28,12 @@ import org.bukkit.entity.Player;
|
|||||||
@Linked
|
@Linked
|
||||||
public class CountingwandCommand extends SWCommand {
|
public class CountingwandCommand extends SWCommand {
|
||||||
|
|
||||||
public CountingwandCommand() {
|
public CountingwandCommand() {
|
||||||
super("countingwand", "/countingwand", "cwand", "/cwand", "zollstock", "/zollstock");
|
super("countingwand", "/countingwand", "cwand", "/cwand", "zollstock", "/zollstock");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(description = "COUNTINGWAND_COMMAND_HELP")
|
@Register(description = "COUNTINGWAND_COMMAND_HELP")
|
||||||
public void genericCommand(final Player p) {
|
public void genericCommand(final Player p) {
|
||||||
SWUtils.giveItemToPlayer(p, Countingwand.getWandItem(p));
|
SWUtils.giveItemToPlayer(p, Countingwand.getWandItem(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-17
@@ -30,24 +30,24 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
@Linked
|
@Linked
|
||||||
public class CountingwandGuiItem extends BauGuiItem {
|
public class CountingwandGuiItem extends BauGuiItem {
|
||||||
|
|
||||||
public CountingwandGuiItem() {
|
public CountingwandGuiItem() {
|
||||||
super(22);
|
super(22);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getItem(Player player) {
|
public ItemStack getItem(Player player) {
|
||||||
return Countingwand.getWandItem(player);
|
return Countingwand.getWandItem(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean click(ClickType click, Player p) {
|
public boolean click(ClickType click, Player p) {
|
||||||
p.closeInventory();
|
p.closeInventory();
|
||||||
p.performCommand("countingwand");
|
p.performCommand("countingwand");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Permission permission() {
|
public Permission permission() {
|
||||||
return Permission.MEMBER;
|
return Permission.MEMBER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+27
-27
@@ -35,35 +35,35 @@ import java.util.Objects;
|
|||||||
@Linked
|
@Linked
|
||||||
public class CountingwandListener implements Listener {
|
public class CountingwandListener implements Listener {
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(final BlockBreakEvent event) {
|
public void onBlockBreak(final BlockBreakEvent event) {
|
||||||
if (!Countingwand.isCountingwand(event.getPlayer().getInventory().getItemInMainHand())) {
|
if (!Countingwand.isCountingwand(event.getPlayer().getInventory().getItemInMainHand())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
Countingwand.checkSelection(Point.fromLocation(event.getBlock().getLocation()), true, event.getPlayer());
|
Countingwand.checkSelection(Point.fromLocation(event.getBlock().getLocation()), true, event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(final PlayerInteractEvent event) {
|
public void onPlayerInteract(final PlayerInteractEvent event) {
|
||||||
if (!Countingwand.isCountingwand(event.getItem())) {
|
if (!Countingwand.isCountingwand(event.getItem())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_AIR) {
|
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_AIR) {
|
||||||
RayTraceResult rayTraceResult = event.getPlayer().rayTraceBlocks(200, FluidCollisionMode.NEVER);
|
RayTraceResult rayTraceResult = event.getPlayer().rayTraceBlocks(200, FluidCollisionMode.NEVER);
|
||||||
if (rayTraceResult == null) {
|
if (rayTraceResult == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(rayTraceResult.getHitBlock()).getLocation()), event.getAction() == Action.LEFT_CLICK_AIR, event.getPlayer());
|
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(rayTraceResult.getHitBlock()).getLocation()), event.getAction() == Action.LEFT_CLICK_AIR, event.getPlayer());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
Countingwand.checkSelection(Point.fromLocation(Objects.requireNonNull(event.getClickedBlock()).getLocation()), false, event.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-14
@@ -21,9 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.entity.REntity;
|
import de.steamwar.entity.*;
|
||||||
import de.steamwar.entity.REntityServer;
|
|
||||||
import de.steamwar.entity.RFallingBlockEntity;
|
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -59,15 +57,15 @@ public class DesignEndStone {
|
|||||||
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
|
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
|
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
|
||||||
|
}
|
||||||
|
|
||||||
entityServer.setCallback((player, rEntity, entityAction) -> {
|
private void interact(Player player, RInteraction entity, REntityAction action) {
|
||||||
if (entityAction != REntityServer.EntityAction.ATTACK) return;
|
if (action != REntityAction.ATTACK) return;
|
||||||
Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ());
|
Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
|
||||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||||
location.getBlock().breakNaturally();
|
location.getBlock().breakNaturally();
|
||||||
calc();
|
calc();
|
||||||
}, 1);
|
}, 1);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calc() {
|
public void calc() {
|
||||||
@@ -110,12 +108,15 @@ public class DesignEndStone {
|
|||||||
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
|
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
|
||||||
|
|
||||||
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
|
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
|
||||||
Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5);
|
Location location = new Location(WORLD, cx, cy, cz);
|
||||||
if (!locations.add(location)) break;
|
if (!locations.add(location)) break;
|
||||||
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS);
|
RBlockDisplay entity = new RBlockDisplay(entityServer, location);
|
||||||
entity.setNoGravity(true);
|
entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
||||||
entity.setGlowing(true);
|
entity.setGlowing(true);
|
||||||
entities.add(entity);
|
entities.add(entity);
|
||||||
|
RInteraction interaction = new RInteraction(entityServer, location);
|
||||||
|
interaction.setCallback(this::interact);
|
||||||
|
entities.add(interaction);
|
||||||
break;
|
break;
|
||||||
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
|
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
+11
-10
@@ -26,8 +26,9 @@ import de.steamwar.bausystem.features.autostart.AutostartListener;
|
|||||||
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
|
||||||
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
|
||||||
import de.steamwar.core.SWPlayer;
|
import de.steamwar.core.SWPlayer;
|
||||||
|
import de.steamwar.entity.RBlockDisplay;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.entity.RFallingBlockEntity;
|
import de.steamwar.entity.RInteraction;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
@@ -58,10 +59,6 @@ public class Detonator {
|
|||||||
@Override
|
@Override
|
||||||
public void onMount(SWPlayer player) {
|
public void onMount(SWPlayer player) {
|
||||||
entities.addPlayer(player.getPlayer());
|
entities.addPlayer(player.getPlayer());
|
||||||
entities.setCallback((player1, entity, action) -> {
|
|
||||||
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
|
|
||||||
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,8 +67,6 @@ public class Detonator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Vector HALF = new Vector(0.5, 0, 0.5);
|
|
||||||
|
|
||||||
public static boolean isDetonator(ItemStack itemStack) {
|
public static boolean isDetonator(ItemStack itemStack) {
|
||||||
return ItemStorage.isDetonator(itemStack);
|
return ItemStorage.isDetonator(itemStack);
|
||||||
}
|
}
|
||||||
@@ -79,8 +74,14 @@ public class Detonator {
|
|||||||
public static void showDetonator(Player p, List<Location> locs) {
|
public static void showDetonator(Player p, List<Location> locs) {
|
||||||
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
|
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
|
||||||
locs.forEach(location -> {
|
locs.forEach(location -> {
|
||||||
RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
|
RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
|
||||||
entity.setNoGravity(true);
|
blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
|
||||||
|
|
||||||
|
RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
|
||||||
|
interaction.setCallback((player, entity, action) -> {
|
||||||
|
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
|
||||||
|
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ public class Detonator {
|
|||||||
|
|
||||||
public static void activateDetonator(DetonatorStorage detonator) {
|
public static void activateDetonator(DetonatorStorage detonator) {
|
||||||
Player p = detonator.getPlayer();
|
Player p = detonator.getPlayer();
|
||||||
if (Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false)) {
|
if (Config.STORE.get(p).isDetonatorAutostart()) {
|
||||||
AutostartListener.instance.activate(p);
|
AutostartListener.instance.activate(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -76,8 +76,8 @@ public class DetonatorCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register(value = "autostart", description = "DETONATOR_HELP_AUTOSTART")
|
@Register(value = "autostart", description = "DETONATOR_HELP_AUTOSTART")
|
||||||
public void toggleAutostartTimer(Player p) {
|
public void toggleAutostartTimer(Player p) {
|
||||||
boolean current = Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false);
|
boolean current = Config.STORE.get(p).isDetonatorAutostart();
|
||||||
Config.getInstance().get(p).put("detonator-autostart", !current);
|
Config.STORE.get(p).setDetonatorAutostart(!current);
|
||||||
if (!current) {
|
if (!current) {
|
||||||
BauSystem.MESSAGE.send("DETONATOR_AUTOSTART_ENABLE", p);
|
BauSystem.MESSAGE.send("DETONATOR_AUTOSTART_ENABLE", p);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.features.dev;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.command.SWCommand;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class CreateKitCommand extends SWCommand {
|
||||||
|
|
||||||
|
public CreateKitCommand() {
|
||||||
|
super("createkit");
|
||||||
|
if (!BauSystem.DEV_SERVER) unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register
|
||||||
|
public void onCommand(Player player, String name) {
|
||||||
|
YamlConfiguration yaml = new YamlConfiguration();
|
||||||
|
|
||||||
|
yaml.set("Items", player.getInventory().getContents());
|
||||||
|
yaml.set("Armor", player.getInventory().getArmorContents());
|
||||||
|
yaml.set("Effects", player.getActivePotionEffects());
|
||||||
|
yaml.set("LeaderAllowed", true);
|
||||||
|
yaml.set("MemberAllowed", true);
|
||||||
|
yaml.set("EnterStage", 0);
|
||||||
|
yaml.set("TNT", true);
|
||||||
|
|
||||||
|
YamlConfiguration kits = new YamlConfiguration();
|
||||||
|
|
||||||
|
kits.set("Kits." + name, yaml);
|
||||||
|
|
||||||
|
try {
|
||||||
|
kits.save(new File("new.kits.yaml"));
|
||||||
|
|
||||||
|
player.sendMessage("Kit created!");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-8
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2025 SteamWar.de-Serverteam
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -17,15 +17,15 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
package de.steamwar.bausystem.features.experimental;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.core.VersionDependent;
|
import de.steamwar.linkage.Linked;
|
||||||
|
|
||||||
public interface TickListener {
|
@Linked
|
||||||
|
public class ExperimentalCommand extends SWCommand {
|
||||||
|
|
||||||
TickListener impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
public ExperimentalCommand() {
|
||||||
|
super("experimental", "experiment");
|
||||||
default void init() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bausystem.features.experimental.redstone_engine;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.experimental.ExperimentalCommand;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||||
|
import de.steamwar.command.AbstractSWCommand;
|
||||||
|
import de.steamwar.command.SWCommand;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import io.papermc.paper.configuration.WorldConfiguration;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.title.TitlePart;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AbstractSWCommand.PartOf(ExperimentalCommand.class)
|
||||||
|
@Linked
|
||||||
|
public class RedstoneEngine extends SWCommand implements Listener, ScoreboardElement {
|
||||||
|
|
||||||
|
public RedstoneEngine() {
|
||||||
|
super("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private WorldConfiguration.Misc getConfig() {
|
||||||
|
return ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().paperConfig().misc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register("redstone")
|
||||||
|
@Register("redstoneengine")
|
||||||
|
public void setRedstoneEngine(Player player, @StaticValue("alternate_current") String __, WorldConfiguration.Misc.AlternateCurrentUpdateOrder updateOrder) {
|
||||||
|
WorldConfiguration.Misc misc = getConfig();
|
||||||
|
misc.redstoneImplementation = WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT;
|
||||||
|
misc.alternateCurrentUpdateOrder = updateOrder;
|
||||||
|
broadcastTitle(Bukkit.getOnlinePlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register("redstone")
|
||||||
|
@Register("redstoneengine")
|
||||||
|
public void setRedstoneEngine(Player player, WorldConfiguration.Misc.RedstoneImplementation implementation) {
|
||||||
|
getConfig().redstoneImplementation = implementation;
|
||||||
|
broadcastTitle(Bukkit.getOnlinePlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
WorldConfiguration.Misc misc = getConfig();
|
||||||
|
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
|
||||||
|
broadcastTitle(List.of(event.getPlayer()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastTitle(Collection<? extends Player> players) {
|
||||||
|
WorldConfiguration.Misc misc = getConfig();
|
||||||
|
Component title = switch (misc.redstoneImplementation) {
|
||||||
|
case VANILLA -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: Vanilla ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
||||||
|
case EIGENCRAFT -> Component.text("Redstone: Eigencraft");
|
||||||
|
case ALTERNATE_CURRENT -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: AC ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
|
||||||
|
};
|
||||||
|
Component subtitle;
|
||||||
|
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||||
|
subtitle = Component.text().build();
|
||||||
|
} else {
|
||||||
|
subtitle = switch (misc.alternateCurrentUpdateOrder) {
|
||||||
|
case VERTICAL_FIRST_INWARD -> Component.text("Y first inwards"); // Y before XZ
|
||||||
|
case VERTICAL_FIRST_OUTWARD -> Component.text("Y first outwards"); // XZ before Y
|
||||||
|
case HORIZONTAL_FIRST_INWARD -> Component.text("XZ first inwards"); // Y before XZ
|
||||||
|
case HORIZONTAL_FIRST_OUTWARD -> Component.text("XZ first outwards"); // XZ before Y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
players.forEach(player -> {
|
||||||
|
player.sendTitlePart(TitlePart.TITLE, title);
|
||||||
|
player.sendTitlePart(TitlePart.SUBTITLE, subtitle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScoreboardGroup getGroup() {
|
||||||
|
return ScoreboardGroup.FOOTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int order() {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(Region region, Player p) {
|
||||||
|
WorldConfiguration.Misc misc = getConfig();
|
||||||
|
switch (misc.redstoneImplementation) {
|
||||||
|
case ALTERNATE_CURRENT:
|
||||||
|
switch (misc.alternateCurrentUpdateOrder) {
|
||||||
|
case VERTICAL_FIRST_INWARD:
|
||||||
|
return "§eRedstone§8: §cAC §8(§7Y in§8)";
|
||||||
|
case VERTICAL_FIRST_OUTWARD:
|
||||||
|
return "§eRedstone§8: §cAC §8(§7Y out§8)";
|
||||||
|
case HORIZONTAL_FIRST_INWARD:
|
||||||
|
return "§eRedstone§8: §cAC §8(§7XZ in§8)";
|
||||||
|
case HORIZONTAL_FIRST_OUTWARD:
|
||||||
|
return "§eRedstone§8: §cAC §8(§7XZ out§8)";
|
||||||
|
}
|
||||||
|
return "§eRedstone§8: §cAC";
|
||||||
|
case EIGENCRAFT:
|
||||||
|
return null;
|
||||||
|
case VANILLA:
|
||||||
|
default:
|
||||||
|
return "§eRedstone§8: §cVanilla";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.gui.editor;
|
|||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.features.gui.BauGUI;
|
import de.steamwar.bausystem.features.gui.BauGUI;
|
||||||
import de.steamwar.bausystem.linkage.BauGuiItem;
|
import de.steamwar.bausystem.linkage.BauGuiItem;
|
||||||
import de.steamwar.core.TrickyTrialsWrapper;
|
|
||||||
import de.steamwar.data.CMDs;
|
import de.steamwar.data.CMDs;
|
||||||
import de.steamwar.inventory.SWItem;
|
import de.steamwar.inventory.SWItem;
|
||||||
import de.steamwar.inventory.SWListInv;
|
import de.steamwar.inventory.SWListInv;
|
||||||
@@ -74,7 +73,7 @@ public class BauGuiEditor implements Listener {
|
|||||||
|
|
||||||
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
|
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
|
||||||
}).getItemStack());
|
}).getItemStack());
|
||||||
inv.setItem(mapping.getSize() + 6, new SWItem(TrickyTrialsWrapper.impl.getTurtleScute(), BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
|
inv.setItem(mapping.getSize() + 6, new SWItem(Material.TURTLE_SCUTE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
|
||||||
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack());
|
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack());
|
||||||
|
|
||||||
p.openInventory(inv);
|
p.openInventory(inv);
|
||||||
|
|||||||
+15
-16
@@ -28,7 +28,6 @@ import lombok.Setter;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -52,15 +51,15 @@ public class BauGuiMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final YAPIONObject object;
|
private final Config config;
|
||||||
@Getter
|
@Getter
|
||||||
private final Player owner;
|
private final Player owner;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private boolean saved;
|
private boolean saved;
|
||||||
|
|
||||||
protected BauGuiMapping(YAPIONObject object, Player p) {
|
protected BauGuiMapping(Config config, Player p) {
|
||||||
this.object = object;
|
this.config = config;
|
||||||
this.owner = p;
|
this.owner = p;
|
||||||
fromUUID.put(p.getUniqueId(), this);
|
fromUUID.put(p.getUniqueId(), this);
|
||||||
mappings.add(this);
|
mappings.add(this);
|
||||||
@@ -70,19 +69,18 @@ public class BauGuiMapping {
|
|||||||
BauGuiMapping mapping = fromUUID.get(p.getUniqueId());
|
BauGuiMapping mapping = fromUUID.get(p.getUniqueId());
|
||||||
|
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
YAPIONObject yapionObject = Config.getInstance().get(p);
|
mapping = new BauGuiMapping(Config.STORE.get(p), p);
|
||||||
mapping = new BauGuiMapping(yapionObject.getObject("baugui"), p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShown(int id) {
|
public boolean isShown(int id) {
|
||||||
return object.getPlainValueOrDefault(Integer.toString(id), -1) >= 0;
|
return config.getBauGui().getOrDefault(id, -1) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSlot(int id) {
|
public int getSlot(int id) {
|
||||||
return object.getPlainValue(Integer.toString(id));
|
return config.getBauGui().get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, Integer> getMapping() {
|
public Map<Integer, Integer> getMapping() {
|
||||||
@@ -94,7 +92,7 @@ public class BauGuiMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return object.getPlainValueOrDefault("size", 45);
|
return config.getBauGuiSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSize(int size) {
|
public void setSize(int size) {
|
||||||
@@ -102,7 +100,7 @@ public class BauGuiMapping {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object.add("size", size);
|
config.setBauGuiSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tick() {
|
private void tick() {
|
||||||
@@ -111,16 +109,17 @@ public class BauGuiMapping {
|
|||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
if (saved) return;
|
if (saved) return;
|
||||||
YAPIONObject config = Config.getInstance().get(owner);
|
Config current = Config.STORE.get(owner);
|
||||||
config.add("baugui", object);
|
current.setBauGui(config.getBauGui());
|
||||||
Config.getInstance().save(owner);
|
current.setBauGuiSize(config.getBauGuiSize());
|
||||||
|
Config.STORE.save(owner);
|
||||||
saved = true;
|
saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Integer, Integer> internalReadMap() {
|
private Map<Integer, Integer> internalReadMap() {
|
||||||
Map<Integer, Integer> map = new HashMap<>();
|
Map<Integer, Integer> map = new HashMap<>();
|
||||||
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
||||||
Integer value = object.getPlainValueOrDefault(e.getKey().toString(), -1);
|
Integer value = config.getBauGui().getOrDefault(e.getKey(), -1);
|
||||||
if (value == -1) continue;
|
if (value == -1) continue;
|
||||||
map.put(e.getKey(), value);
|
map.put(e.getKey(), value);
|
||||||
}
|
}
|
||||||
@@ -129,10 +128,10 @@ public class BauGuiMapping {
|
|||||||
|
|
||||||
private void internalWriteMap(Map<Integer, Integer> map) {
|
private void internalWriteMap(Map<Integer, Integer> map) {
|
||||||
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
|
||||||
object.remove(e.getKey().toString());
|
config.getBauGui().remove(e.getKey());
|
||||||
Integer value = map.getOrDefault(e.getKey(), -1);
|
Integer value = map.getOrDefault(e.getKey(), -1);
|
||||||
if (value == -1) continue;
|
if (value == -1) continue;
|
||||||
object.add(e.getKey().toString(), value);
|
config.getBauGui().put(e.getKey(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-40
@@ -20,39 +20,23 @@
|
|||||||
package de.steamwar.bausystem.features.hotbar;
|
package de.steamwar.bausystem.features.hotbar;
|
||||||
|
|
||||||
import de.steamwar.bausystem.configplayer.Config;
|
import de.steamwar.bausystem.configplayer.Config;
|
||||||
import de.steamwar.core.Core;
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import yapion.hierarchy.types.YAPIONArray;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import yapion.hierarchy.types.YAPIONObject;
|
|
||||||
import yapion.hierarchy.types.YAPIONValue;
|
|
||||||
import yapion.parser.YAPIONParser;
|
|
||||||
import yapion.serializing.YAPIONDeserializer;
|
|
||||||
import yapion.serializing.YAPIONSerializer;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class DefaultHotbar {
|
public class DefaultHotbar {
|
||||||
|
|
||||||
private final YAPIONArray DEFAULT_HOTBAR = YAPIONParser.parse("{[{@type(org.bukkit.inventory.ItemStack)v(2230)type(WOODEN_AXE)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(WorldEdit Wand)lore{@type(java.util.ArrayList)values[Left click: select pos #1,Right click: select pos #2]}}},{@type(org.bukkit.inventory.ItemStack)v(2230)type(COMPASS)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(Navigation Wand)lore{@type(java.util.ArrayList)values[Left click: jump to location,Right click: pass through walls]}}},null,null,null,null,null,null,{@type(org.bukkit.inventory.ItemStack)v(2230)type(NETHER_STAR)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(§eBau GUI)}},null,null,{@type(org.bukkit.inventory.ItemStack)v(3117)type(ELYTRA)},null]}").getArray("");
|
|
||||||
|
|
||||||
public void updateHotbar(Player p) {
|
public void updateHotbar(Player p) {
|
||||||
ItemStack[] hotbar = new ItemStack[13];
|
ItemStack[] hotbar = new ItemStack[13];
|
||||||
System.arraycopy(p.getInventory().getContents(), 0, hotbar, 0, 9);
|
System.arraycopy(p.getInventory().getContents(), 0, hotbar, 0, 9);
|
||||||
System.arraycopy(p.getInventory().getArmorContents(), 0, hotbar, 9, 4);
|
System.arraycopy(p.getInventory().getArmorContents(), 0, hotbar, 9, 4);
|
||||||
YAPIONArray yapionArray = new YAPIONArray();
|
Config.STORE.get(p).setHotbar(copy(hotbar));
|
||||||
for (ItemStack itemStack : hotbar) {
|
Config.STORE.save(p);
|
||||||
if (itemStack != null) {
|
|
||||||
yapionArray.add(YAPIONSerializer.serialize(itemStack));
|
|
||||||
} else {
|
|
||||||
yapionArray.add(new YAPIONValue<>(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Config.getInstance().get(p).add("hotbar-" + Core.getVersion(), yapionArray);
|
|
||||||
Config.getInstance().save(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHotbar(Player p) {
|
public void setHotbar(Player p) {
|
||||||
@@ -66,28 +50,34 @@ public class DefaultHotbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack[] getItems(Player p) {
|
public ItemStack[] getItems(Player p) {
|
||||||
Config.getInstance().get(p).remap("hotbar", "hotbar-19");
|
return copy(Config.STORE.get(p).getHotbar());
|
||||||
YAPIONArray yapionArray = Config.getInstance().get(p).getYAPIONArrayOrSetDefault("hotbar-" + Core.getVersion(), defaultHotbar());
|
}
|
||||||
|
|
||||||
|
public ItemStack[] defaultHotbar() {
|
||||||
ItemStack[] hotbar = new ItemStack[13];
|
ItemStack[] hotbar = new ItemStack[13];
|
||||||
Set<Integer> invalid = new HashSet<>();
|
hotbar[0] = item(Material.WOODEN_AXE, "WorldEdit Wand", "Left click: select pos #1", "Right click: select pos #2");
|
||||||
yapionArray.forEach((integer, yapionAnyType) -> {
|
hotbar[1] = item(Material.COMPASS, "Navigation Wand", "Left click: jump to location", "Right click: pass through walls");
|
||||||
if (yapionAnyType instanceof YAPIONValue) {
|
hotbar[8] = item(Material.NETHER_STAR, "§eBau GUI");
|
||||||
hotbar[integer] = null;
|
hotbar[11] = new ItemStack(Material.ELYTRA);
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
hotbar[integer] = YAPIONDeserializer.deserialize((YAPIONObject) yapionAnyType);
|
|
||||||
} catch (Exception e) {
|
|
||||||
invalid.add(integer);
|
|
||||||
hotbar[integer] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
invalid.forEach(i -> yapionArray.set(i, new YAPIONValue<>(null)));
|
|
||||||
if (!invalid.isEmpty()) Config.getInstance().save(p);
|
|
||||||
return hotbar;
|
return hotbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public YAPIONArray defaultHotbar() {
|
private ItemStack item(Material material, String name, String... lore) {
|
||||||
return DEFAULT_HOTBAR;
|
ItemStack itemStack = new ItemStack(material);
|
||||||
|
ItemMeta meta = itemStack.getItemMeta();
|
||||||
|
meta.setDisplayName(name);
|
||||||
|
if (lore.length > 0) {
|
||||||
|
meta.setLore(List.of(lore));
|
||||||
|
}
|
||||||
|
itemStack.setItemMeta(meta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack[] copy(ItemStack[] hotbar) {
|
||||||
|
ItemStack[] copy = new ItemStack[13];
|
||||||
|
for (int i = 0; i < Math.min(hotbar.length, copy.length); i++) {
|
||||||
|
copy[i] = hotbar[i] == null ? null : hotbar[i].clone();
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ public class HotbarListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (allNull(event.getPlayer().getInventory().getContents()) && allNull(event.getPlayer().getInventory().getArmorContents())) {
|
if (allNull(event.getPlayer().getInventory().getContents()) && allNull(event.getPlayer().getInventory().getArmorContents())) {
|
||||||
DefaultHotbar.setHotbar(event.getPlayer());
|
DefaultHotbar.setHotbar(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -49,8 +49,9 @@ public class InventoryFillBauGuiItem extends BauGuiItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getItem(Player player) {
|
public ItemStack getItem(Player player) {
|
||||||
String loreKey = Config.getInstance().get(player).getPlainValueOrDefault("inventoryfill", false) ? "OTHER_ITEMS_INVENTORY_FILL_LORE_ACTIVE" : "OTHER_ITEMS_INVENTORY_FILL_LORE_INACTIVE";
|
String loreKey = Config.STORE.get(player).isInventoryFill() ? "OTHER_ITEMS_INVENTORY_FILL_LORE_ACTIVE" : "OTHER_ITEMS_INVENTORY_FILL_LORE_INACTIVE";
|
||||||
return new SWItem(Material.HOPPER, BauSystem.MESSAGE.parse("OTHER_ITEMS_INVENTORY_FILL_NAME", player), Collections.singletonList(BauSystem.MESSAGE.parse(loreKey, player)), false, clickType -> {}).getItemStack();
|
return new SWItem(Material.HOPPER, BauSystem.MESSAGE.parse("OTHER_ITEMS_INVENTORY_FILL_NAME", player), Collections.singletonList(BauSystem.MESSAGE.parse(loreKey, player)), false, clickType -> {
|
||||||
|
}).getItemStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+4
-4
@@ -39,8 +39,8 @@ public class InventoryFiller implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("inventoryfill", false)) return;
|
if (!Config.STORE.get(event.getPlayer()).isInventoryFill()) return;
|
||||||
if (!event.getPlayer().isSneaking()) return;
|
if (!event.getPlayer().isSneaking()) return;
|
||||||
Block block = event.getPlayer().getTargetBlockExact(5);
|
Block block = event.getPlayer().getTargetBlockExact(5);
|
||||||
if (block == null) return;
|
if (block == null) return;
|
||||||
@@ -61,8 +61,8 @@ public class InventoryFiller implements Listener {
|
|||||||
*/
|
*/
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("inventoryfill", false)) return;
|
if (!Config.STORE.get(event.getPlayer()).isInventoryFill()) return;
|
||||||
if (!event.getPlayer().isSneaking()) return;
|
if (!event.getPlayer().isSneaking()) return;
|
||||||
ItemStack itemStack = event.getPlayer().getInventory().getItemInMainHand();
|
ItemStack itemStack = event.getPlayer().getInventory().getItemInMainHand();
|
||||||
if (itemStack.getType() == Material.AIR) return;
|
if (itemStack.getType() == Material.AIR) return;
|
||||||
|
|||||||
+2
-2
@@ -68,8 +68,8 @@ public class InventoryFillerCommand extends SWCommand {
|
|||||||
|
|
||||||
@Register(description = {"INVENTORY_FILL_HELP", "INVENTORY_FILL_INFO"})
|
@Register(description = {"INVENTORY_FILL_HELP", "INVENTORY_FILL_INFO"})
|
||||||
public void toggle(Player player) {
|
public void toggle(Player player) {
|
||||||
boolean inventoryFill = Config.getInstance().get(player).getPlainValueOrDefault("inventoryfill", false);
|
boolean inventoryFill = Config.STORE.get(player).isInventoryFill();
|
||||||
Config.getInstance().get(player).put("inventoryfill", !inventoryFill);
|
Config.STORE.get(player).setInventoryFill(!inventoryFill);
|
||||||
if (!inventoryFill) {
|
if (!inventoryFill) {
|
||||||
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("INVENTORY_FILL_ENABLE", player));
|
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("INVENTORY_FILL_ENABLE", player));
|
||||||
BauSystem.MESSAGE.send("INVENTORY_FILL_INFO", player);
|
BauSystem.MESSAGE.send("INVENTORY_FILL_INFO", player);
|
||||||
|
|||||||
+12
-8
@@ -24,9 +24,9 @@ import de.steamwar.bausystem.region.Point;
|
|||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
|
||||||
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
import de.steamwar.bausystem.utils.bossbar.BossBarService;
|
||||||
|
import de.steamwar.entity.RBlockDisplay;
|
||||||
import de.steamwar.entity.REntity;
|
import de.steamwar.entity.REntity;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.entity.RFallingBlockEntity;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@@ -58,9 +58,9 @@ public class KillcheckerVisualizer {
|
|||||||
Material.BLACK_CONCRETE,
|
Material.BLACK_CONCRETE,
|
||||||
};
|
};
|
||||||
private static final World WORLD = Bukkit.getWorlds().get(0);
|
private static final World WORLD = Bukkit.getWorlds().get(0);
|
||||||
|
|
||||||
private static final double SURROUND = 4.5;
|
private static final double SURROUND = 4.5;
|
||||||
|
|
||||||
private final Point minPoint;
|
private final Point minPoint;
|
||||||
private final Point maxPoint;
|
private final Point maxPoint;
|
||||||
|
|
||||||
@@ -104,7 +104,9 @@ public class KillcheckerVisualizer {
|
|||||||
Block block = WORLD.getBlockAt(x, y, z);
|
Block block = WORLD.getBlockAt(x, y, z);
|
||||||
if (block.getType().isAir()) continue;
|
if (block.getType().isAir()) continue;
|
||||||
String name = block.getType().name();
|
String name = block.getType().name();
|
||||||
if (!name.endsWith("_WOOL") && !name.endsWith("_STAINED_GLASS") && !name.endsWith("_CONCRETE") && !name.endsWith("_TERRACOTTA")) continue;
|
if (!name.endsWith("_WOOL") && !name.endsWith("_STAINED_GLASS") && !name.endsWith("_CONCRETE") && !name.endsWith("_TERRACOTTA")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (name.equals("_GLAZED_TERRACOTTA")) continue;
|
if (name.equals("_GLAZED_TERRACOTTA")) continue;
|
||||||
Cuboid cuboid = create(block.getType(), x, y, z);
|
Cuboid cuboid = create(block.getType(), x, y, z);
|
||||||
cuboids.add(cuboid);
|
cuboids.add(cuboid);
|
||||||
@@ -283,11 +285,13 @@ public class KillcheckerVisualizer {
|
|||||||
}
|
}
|
||||||
kill.forEach((point, count) -> {
|
kill.forEach((point, count) -> {
|
||||||
if (rEntities.containsKey(point)) {
|
if (rEntities.containsKey(point)) {
|
||||||
if (killCount.get(point) == count && outlinePoints.contains(point) == outlinePointsCacheLast.contains(point)) return;
|
if (killCount.get(point) == count && outlinePoints.contains(point) == outlinePointsCacheLast.contains(point)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
rEntities.get(point).die();
|
rEntities.get(point).die();
|
||||||
}
|
}
|
||||||
RFallingBlockEntity entity = new RFallingBlockEntity(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5), MATERIALS[Math.min(count - 1, MATERIALS.length) - 1]);
|
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0, 0, 0));
|
||||||
entity.setNoGravity(true);
|
entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
|
||||||
rEntities.put(point, entity);
|
rEntities.put(point, entity);
|
||||||
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
|
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
|
||||||
killCount.put(point, count);
|
killCount.put(point, count);
|
||||||
@@ -325,7 +329,7 @@ public class KillcheckerVisualizer {
|
|||||||
if (point.getX() < minPoint.getX() || point.getX() > maxPoint.getX()) continue;
|
if (point.getX() < minPoint.getX() || point.getX() > maxPoint.getX()) continue;
|
||||||
if (point.getY() < minPoint.getY() || point.getY() > maxPoint.getY()) continue;
|
if (point.getY() < minPoint.getY() || point.getY() > maxPoint.getY()) continue;
|
||||||
if (point.getZ() < minPoint.getZ() || point.getZ() > maxPoint.getZ()) continue;
|
if (point.getZ() < minPoint.getZ() || point.getZ() > maxPoint.getZ()) continue;
|
||||||
|
|
||||||
if (WORLD.getBlockAt(point.getX() + 1, point.getY(), point.getZ()).getType() == type) {
|
if (WORLD.getBlockAt(point.getX() + 1, point.getY(), point.getZ()).getType() == type) {
|
||||||
points.add(new Point(point.getX() + 1, point.getY(), point.getZ()));
|
points.add(new Point(point.getX() + 1, point.getY(), point.getZ()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class Loader implements Listener, SWPlayer.Component {
|
|||||||
|
|
||||||
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
||||||
if (stage != Stage.RUNNING && stage != Stage.SINGLE) return;
|
if (stage != Stage.RUNNING && stage != Stage.SINGLE) return;
|
||||||
if(!Permission.BUILD.hasPermission(p)) return;
|
if (!Permission.BUILD.hasPermission(p)) return;
|
||||||
if (waitTime > 0) {
|
if (waitTime > 0) {
|
||||||
waitTime--;
|
waitTime--;
|
||||||
return;
|
return;
|
||||||
@@ -213,7 +213,8 @@ public class Loader implements Listener, SWPlayer.Component {
|
|||||||
};
|
};
|
||||||
updateRunnable.run();
|
updateRunnable.run();
|
||||||
|
|
||||||
SWListInv<LoaderElement> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("LOADER_GUI_TITLE", p), false, list, (clickType, loaderElement) -> {});
|
SWListInv<LoaderElement> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("LOADER_GUI_TITLE", p), false, list, (clickType, loaderElement) -> {
|
||||||
|
});
|
||||||
swListInv.setCallback((clickType, entry) -> entry.click(p, () -> {
|
swListInv.setCallback((clickType, entry) -> entry.click(p, () -> {
|
||||||
updateRunnable.run();
|
updateRunnable.run();
|
||||||
swListInv.open();
|
swListInv.open();
|
||||||
@@ -363,7 +364,9 @@ public class Loader implements Listener, SWPlayer.Component {
|
|||||||
public static int LENGTH = SettingsSorting.values().length;
|
public static int LENGTH = SettingsSorting.values().length;
|
||||||
|
|
||||||
public abstract Material getMaterial();
|
public abstract Material getMaterial();
|
||||||
|
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
|
|
||||||
public abstract boolean shouldShow(LoaderElement previous, LoaderElement current, LoaderElement next);
|
public abstract boolean shouldShow(LoaderElement previous, LoaderElement current, LoaderElement next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ public class LoaderScoreboardElement implements ScoreboardElement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(Region region, Player p) {
|
public String get(Region region, Player p) {
|
||||||
if(!Permission.BUILD.hasPermission(p)) return null;
|
if (!Permission.BUILD.hasPermission(p)) return null;
|
||||||
Loader loader = Loader.getLoader(p);
|
Loader loader = Loader.getLoader(p);
|
||||||
if (loader == null) return null;
|
if (loader == null) return null;
|
||||||
if (loader.getStage() == Loader.Stage.RUNNING) {
|
if (loader.getStage() == Loader.Stage.RUNNING) {
|
||||||
|
|||||||
+2
@@ -26,6 +26,8 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
public interface LoaderElement {
|
public interface LoaderElement {
|
||||||
SWItem menu(Player player);
|
SWItem menu(Player player);
|
||||||
|
|
||||||
void execute(Consumer<Long> delay);
|
void execute(Consumer<Long> delay);
|
||||||
|
|
||||||
void click(Player player, Runnable backAction);
|
void click(Player player, Runnable backAction);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-6
@@ -95,7 +95,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
};
|
};
|
||||||
updateRunnable.run();
|
updateRunnable.run();
|
||||||
|
|
||||||
SWListInv<Integer> listInv = new SWListInv<>(player, "Interaction Settings", false, entries, (clickType, entry) -> {});
|
SWListInv<Integer> listInv = new SWListInv<>(player, "Interaction Settings", false, entries, (clickType, entry) -> {
|
||||||
|
});
|
||||||
listInv.setCallback((clickType, entry) -> {
|
listInv.setCallback((clickType, entry) -> {
|
||||||
openIndividualSettingsMenu(player, entry, () -> {
|
openIndividualSettingsMenu(player, entry, () -> {
|
||||||
updateRunnable.run();
|
updateRunnable.run();
|
||||||
@@ -150,7 +151,10 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
}
|
}
|
||||||
|
|
||||||
SWInventory swInventory = new SWInventory(player, guiSize, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_TITLE", player));
|
SWInventory swInventory = new SWInventory(player, guiSize, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_TITLE", player));
|
||||||
for (int i = guiSize - 9; i < guiSize; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7", clickType -> {}));
|
for (int i = guiSize - 9; i < guiSize; i++) {
|
||||||
|
swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7", clickType -> {
|
||||||
|
}));
|
||||||
|
}
|
||||||
swInventory.setItem(guiSize - 9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> back.run());
|
swInventory.setItem(guiSize - 9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> back.run());
|
||||||
swInventory.setItem(guiSize - 5, new SWItem(Material.WOODEN_AXE, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_COPY", player)).getItemStack(), clickType -> {
|
swInventory.setItem(guiSize - 5, new SWItem(Material.WOODEN_AXE, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_COPY", player)).getItemStack(), clickType -> {
|
||||||
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_GUI_COPY_TITLE", player), "1");
|
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_GUI_COPY_TITLE", player), "1");
|
||||||
@@ -197,7 +201,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
for (int power = 0; power < 16; power++) {
|
for (int power = 0; power < 16; power++) {
|
||||||
int finalPowerPosition = power;
|
int finalPowerPosition = power;
|
||||||
if (power >= 9) finalPowerPosition++;
|
if (power >= 9) finalPowerPosition++;
|
||||||
SWItem powerItem = new SWItem(Material.REDSTONE, BauSystem.MESSAGE.parse("LOADER_SETTING_POWER", player, power), Arrays.asList(), false, clickType -> {});
|
SWItem powerItem = new SWItem(Material.REDSTONE, BauSystem.MESSAGE.parse("LOADER_SETTING_POWER", player, power), Arrays.asList(), false, clickType -> {
|
||||||
|
});
|
||||||
powerItem.getItemStack().setAmount(Math.max(power, 1));
|
powerItem.getItemStack().setAmount(Math.max(power, 1));
|
||||||
if (extraPower.get(index) == power) powerItem.setEnchanted(true);
|
if (extraPower.get(index) == power) powerItem.setEnchanted(true);
|
||||||
|
|
||||||
@@ -210,7 +215,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentElement.hasTicks(this)) {
|
if (currentElement.hasTicks(this)) {
|
||||||
swInventory.setItem(ticksStart + 3, new SWItem(SWItem.getDye(1), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
|
swInventory.setItem(ticksStart + 3, new SWItem(Material.RED_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {
|
||||||
|
}).getItemStack(), clickType -> {
|
||||||
long ticks = extraTicks.get(index);
|
long ticks = extraTicks.get(index);
|
||||||
ticks -= clickType.isShiftClick() ? 5 : 1;
|
ticks -= clickType.isShiftClick() ? 5 : 1;
|
||||||
if (ticks < 1) ticks = 1;
|
if (ticks < 1) ticks = 1;
|
||||||
@@ -218,7 +224,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
openIndividualSettingsMenu(player, index, back, delete);
|
openIndividualSettingsMenu(player, index, back, delete);
|
||||||
});
|
});
|
||||||
|
|
||||||
SWItem ticksItem = new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS", player, extraTicks.get(index)), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_GUI_CLICK_TO_EDIT", player)), false, clickType -> {});
|
SWItem ticksItem = new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS", player, extraTicks.get(index)), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_GUI_CLICK_TO_EDIT", player)), false, clickType -> {
|
||||||
|
});
|
||||||
ticksItem.getItemStack().setAmount((int) Math.min(extraTicks.get(index), 64));
|
ticksItem.getItemStack().setAmount((int) Math.min(extraTicks.get(index), 64));
|
||||||
swInventory.setItem(ticksStart + 4, ticksItem.getItemStack(), clickType -> {
|
swInventory.setItem(ticksStart + 4, ticksItem.getItemStack(), clickType -> {
|
||||||
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_NAME", player), extraTicks.get(index) + "");
|
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_NAME", player), extraTicks.get(index) + "");
|
||||||
@@ -234,7 +241,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
|
|||||||
swAnvilInv.open();
|
swAnvilInv.open();
|
||||||
});
|
});
|
||||||
|
|
||||||
swInventory.setItem(ticksStart + 5, new SWItem(SWItem.getDye(10), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
|
swInventory.setItem(ticksStart + 5, new SWItem(Material.LIME_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {
|
||||||
|
}).getItemStack(), clickType -> {
|
||||||
long ticks = extraTicks.get(index);
|
long ticks = extraTicks.get(index);
|
||||||
ticks += clickType.isShiftClick() ? 5 : 1;
|
ticks += clickType.isShiftClick() ? 5 : 1;
|
||||||
extraTicks.set(index, ticks);
|
extraTicks.set(index, ticks);
|
||||||
|
|||||||
+3
@@ -28,10 +28,13 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
public interface LoaderSettingsEnum<T, P extends LoaderInteractionElement<E>, E extends Enum<E> & LoaderSettingsEnum<T, P, E>> {
|
public interface LoaderSettingsEnum<T, P extends LoaderInteractionElement<E>, E extends Enum<E> & LoaderSettingsEnum<T, P, E>> {
|
||||||
int getPos();
|
int getPos();
|
||||||
|
|
||||||
SWItem menu(Player player, P parent, int power, long ticks);
|
SWItem menu(Player player, P parent, int power, long ticks);
|
||||||
|
|
||||||
default boolean hasPower(P parent) {
|
default boolean hasPower(P parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean hasTicks(P parent) {
|
default boolean hasTicks(P parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -63,7 +63,8 @@ public class LoaderWait implements LoaderElement {
|
|||||||
for (int i = 9; i < 18; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7"));
|
for (int i = 9; i < 18; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7"));
|
||||||
swInventory.setItem(9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> backAction.run());
|
swInventory.setItem(9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> backAction.run());
|
||||||
|
|
||||||
swInventory.setItem(3, new SWItem(SWItem.getDye(1), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
|
swInventory.setItem(3, new SWItem(Material.RED_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {
|
||||||
|
}).getItemStack(), clickType -> {
|
||||||
delay -= clickType.isShiftClick() ? 5 : 1;
|
delay -= clickType.isShiftClick() ? 5 : 1;
|
||||||
if (delay < 0) delay = 0;
|
if (delay < 0) delay = 0;
|
||||||
swInventory.setItem(4, menu(player));
|
swInventory.setItem(4, menu(player));
|
||||||
@@ -80,7 +81,8 @@ public class LoaderWait implements LoaderElement {
|
|||||||
});
|
});
|
||||||
swAnvilInv.open();
|
swAnvilInv.open();
|
||||||
});
|
});
|
||||||
swInventory.setItem(5, new SWItem(SWItem.getDye(10), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
|
swInventory.setItem(5, new SWItem(Material.LIME_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {
|
||||||
|
}).getItemStack(), clickType -> {
|
||||||
delay += clickType.isShiftClick() ? 5 : 1;
|
delay += clickType.isShiftClick() ? 5 : 1;
|
||||||
swInventory.setItem(4, menu(player));
|
swInventory.setItem(4, menu(player));
|
||||||
});
|
});
|
||||||
|
|||||||
+2
-4
@@ -146,8 +146,7 @@ public class Loadtimer implements Listener {
|
|||||||
if ((stage == Stage.COUNTING || stage == Stage.ACTIVATED)) {
|
if ((stage == Stage.COUNTING || stage == Stage.ACTIVATED)) {
|
||||||
stage = Stage.IGNITION;
|
stage = Stage.IGNITION;
|
||||||
ignite = TPSUtils.currentRealTick.get();
|
ignite = TPSUtils.currentRealTick.get();
|
||||||
if (activate == -1)
|
if (activate == -1) activate = TPSUtils.currentRealTick.get();
|
||||||
activate = TPSUtils.currentRealTick.get();
|
|
||||||
if (finishOnActive) {
|
if (finishOnActive) {
|
||||||
stage = Stage.END;
|
stage = Stage.END;
|
||||||
print();
|
print();
|
||||||
@@ -184,8 +183,7 @@ public class Loadtimer implements Listener {
|
|||||||
|
|
||||||
long ignTime = ignite - activate;
|
long ignTime = ignite - activate;
|
||||||
long explTime = explode - ignTime - activate;
|
long explTime = explode - ignTime - activate;
|
||||||
if (explTime < 0)
|
if (explTime < 0) explTime = loadTime;
|
||||||
explTime = loadTime;
|
|
||||||
|
|
||||||
int finalAllTnt = allTnt;
|
int finalAllTnt = allTnt;
|
||||||
long finalExplTime = explTime;
|
long finalExplTime = explTime;
|
||||||
|
|||||||
+4
-2
@@ -40,16 +40,18 @@ public class LoadtimerCommand extends SWCommand {
|
|||||||
public void start(@Validator Player p, TimerMode mode) {
|
public void start(@Validator Player p, TimerMode mode) {
|
||||||
Region r = Region.getRegion(p.getLocation());
|
Region r = Region.getRegion(p.getLocation());
|
||||||
if (r.getType().isGlobal()) return;
|
if (r.getType().isGlobal()) return;
|
||||||
if (!Loadtimer.hasTimer(r))
|
if (!Loadtimer.hasTimer(r)) {
|
||||||
Loadtimer.createLoadtimer(r, mode == TimerMode.HALF);
|
Loadtimer.createLoadtimer(r, mode == TimerMode.HALF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = "stop", description = "LOADTIMER_HELP_STOP")
|
@Register(value = "stop", description = "LOADTIMER_HELP_STOP")
|
||||||
public void stop(@Validator Player p) {
|
public void stop(@Validator Player p) {
|
||||||
Region r = Region.getRegion(p.getLocation());
|
Region r = Region.getRegion(p.getLocation());
|
||||||
if (r.getType().isGlobal()) return;
|
if (r.getType().isGlobal()) return;
|
||||||
if (Loadtimer.hasTimer(r))
|
if (Loadtimer.hasTimer(r)) {
|
||||||
Loadtimer.getTimer(r).delete();
|
Loadtimer.getTimer(r).delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TimerMode {
|
public enum TimerMode {
|
||||||
|
|||||||
+2
-1
@@ -46,8 +46,9 @@ public class LoadtimerGuiItem extends BauGuiItem {
|
|||||||
@Override
|
@Override
|
||||||
public ItemStack getItem(Player player) {
|
public ItemStack getItem(Player player) {
|
||||||
Region r = Region.getRegion(player.getLocation());
|
Region r = Region.getRegion(player.getLocation());
|
||||||
if (r.getType().isGlobal())
|
if (r.getType().isGlobal()) {
|
||||||
return new SWItem(Material.BOWL, BauSystem.MESSAGE.parse("LOADTIMER_GUI_GLOBAL", player)).getItemStack();
|
return new SWItem(Material.BOWL, BauSystem.MESSAGE.parse("LOADTIMER_GUI_GLOBAL", player)).getItemStack();
|
||||||
|
}
|
||||||
if (Loadtimer.hasTimer(r)) {
|
if (Loadtimer.hasTimer(r)) {
|
||||||
return new SWItem(Material.BOW, BauSystem.MESSAGE.parse("LOADTIMER_GUI_STOP", player)).getItemStack();
|
return new SWItem(Material.BOW, BauSystem.MESSAGE.parse("LOADTIMER_GUI_STOP", player)).getItemStack();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+3
-3
@@ -20,9 +20,9 @@
|
|||||||
package de.steamwar.bausystem.features.loadtimer;
|
package de.steamwar.bausystem.features.loadtimer;
|
||||||
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.core.TrickyTrialsWrapper;
|
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
@@ -57,7 +57,7 @@ public class LoadtimerListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onEntitySpawn(EntitySpawnEvent event) {
|
public void onEntitySpawn(EntitySpawnEvent event) {
|
||||||
if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
|
if (!getTimers().isEmpty() && event.getEntityType() == EntityType.TNT) {
|
||||||
Region r = Region.getRegion(event.getLocation());
|
Region r = Region.getRegion(event.getLocation());
|
||||||
if (hasTimer(r)) {
|
if (hasTimer(r)) {
|
||||||
getTimer(r).onTntSpawn();
|
getTimer(r).onTntSpawn();
|
||||||
@@ -67,7 +67,7 @@ public class LoadtimerListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onEntityExplode(EntityExplodeEvent event) {
|
public void onEntityExplode(EntityExplodeEvent event) {
|
||||||
if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
|
if (!getTimers().isEmpty() && event.getEntityType() == EntityType.TNT) {
|
||||||
Region r = Region.getRegion(event.getLocation());
|
Region r = Region.getRegion(event.getLocation());
|
||||||
if (hasTimer(r)) {
|
if (hasTimer(r)) {
|
||||||
getTimer(r).onTntExplode(event);
|
getTimer(r).onTntExplode(event);
|
||||||
|
|||||||
+3
-4
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package de.steamwar.bausystem.features.observer;
|
package de.steamwar.bausystem.features.observer;
|
||||||
|
|
||||||
import de.steamwar.Reflection;
|
|
||||||
import de.steamwar.bausystem.region.Point;
|
import de.steamwar.bausystem.region.Point;
|
||||||
import de.steamwar.core.SWPlayer;
|
import de.steamwar.core.SWPlayer;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -29,8 +28,9 @@ import org.bukkit.block.Block;
|
|||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.block.data.Bisected;
|
import org.bukkit.block.data.Bisected;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.block.data.type.Observer;
|
|
||||||
import org.bukkit.block.data.type.*;
|
import org.bukkit.block.data.type.*;
|
||||||
|
import org.bukkit.block.data.type.Observer;
|
||||||
|
import org.bukkit.craftbukkit.block.impl.CraftPoweredRail;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -171,7 +171,6 @@ public class ObserverTracer implements SWPlayer.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Class<?> craftPoweredRail = Reflection.getClass("org.bukkit.craftbukkit.block.impl.CraftPoweredRail");
|
|
||||||
private boolean checkAllowed(Block block, BlockData blockData) {
|
private boolean checkAllowed(Block block, BlockData blockData) {
|
||||||
if (checkMaterial(block)) return true;
|
if (checkMaterial(block)) return true;
|
||||||
if (block.getType() == Material.BELL) {
|
if (block.getType() == Material.BELL) {
|
||||||
@@ -180,7 +179,7 @@ public class ObserverTracer implements SWPlayer.Component {
|
|||||||
|
|
||||||
return blockData instanceof Door
|
return blockData instanceof Door
|
||||||
|| blockData instanceof Gate
|
|| blockData instanceof Gate
|
||||||
|| craftPoweredRail.isInstance(blockData)
|
|| blockData instanceof CraftPoweredRail
|
||||||
|| blockData instanceof TrapDoor
|
|| blockData instanceof TrapDoor
|
||||||
|| blockData instanceof GlassPane;
|
|| blockData instanceof GlassPane;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -46,7 +46,7 @@ public class ObserverTracerListener implements Listener {
|
|||||||
public ObserverTracerListener() {
|
public ObserverTracerListener() {
|
||||||
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
|
||||||
SWPlayer.allWithSingleComponent(ObserverTracer.class).forEach(pair -> {
|
SWPlayer.allWithSingleComponent(ObserverTracer.class).forEach(pair -> {
|
||||||
if (pair.getPlayer().getGameMode() != GameMode.SPECTATOR) return;
|
if (pair.getSwPlayer().getPlayer().getGameMode() != GameMode.SPECTATOR) return;
|
||||||
pair.getComponent().show();
|
pair.getComponent().show();
|
||||||
});
|
});
|
||||||
}, 15L, 15L);
|
}, 15L, 15L);
|
||||||
@@ -54,7 +54,7 @@ public class ObserverTracerListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
if (!enabled.contains(event.getPlayer())) return;
|
if (!enabled.contains(event.getPlayer())) return;
|
||||||
if (event.getClickedBlock() == null) return;
|
if (event.getClickedBlock() == null) return;
|
||||||
ObserverTracer observerTracer = SWPlayer.of(event.getPlayer()).getComponent(ObserverTracer.class).orElse(null);
|
ObserverTracer observerTracer = SWPlayer.of(event.getPlayer()).getComponent(ObserverTracer.class).orElse(null);
|
||||||
|
|||||||
+7
-9
@@ -28,7 +28,6 @@ import de.steamwar.command.SWCommand;
|
|||||||
import de.steamwar.entity.CRay;
|
import de.steamwar.entity.CRay;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.linkage.MinVersion;
|
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -42,7 +41,6 @@ import org.bukkit.util.RayTraceResult;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
@MinVersion(20)
|
|
||||||
public class RayVisualizerCommand extends SWCommand implements Listener {
|
public class RayVisualizerCommand extends SWCommand implements Listener {
|
||||||
|
|
||||||
private BlockData VISIBLE = Material.LIME_CONCRETE.createBlockData();
|
private BlockData VISIBLE = Material.LIME_CONCRETE.createBlockData();
|
||||||
@@ -63,9 +61,9 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean locEquals(Location loc1, Location loc2) {
|
private boolean locEquals(Location loc1, Location loc2) {
|
||||||
if ((long)(loc1.getX() * 1000) != (long)(loc2.getX() * 1000)) return false;
|
if ((long) (loc1.getX() * 1000) != (long) (loc2.getX() * 1000)) return false;
|
||||||
if ((long)(loc1.getY() * 1000) != (long)(loc2.getY() * 1000)) return false;
|
if ((long) (loc1.getY() * 1000) != (long) (loc2.getY() * 1000)) return false;
|
||||||
if ((long)(loc1.getZ() * 1000) != (long)(loc2.getZ() * 1000)) return false;
|
if ((long) (loc1.getZ() * 1000) != (long) (loc2.getZ() * 1000)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +167,7 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
|
||||||
boolean rayvisualizer = Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("rayvisualizer", false);
|
boolean rayvisualizer = Config.STORE.get(event.getPlayer()).isRayVisualizer();
|
||||||
if (rayvisualizer) server.addPlayer(event.getPlayer());
|
if (rayvisualizer) server.addPlayer(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +181,7 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
|
|||||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (Permission.BUILD.hasPermission(player)) {
|
if (Permission.BUILD.hasPermission(player)) {
|
||||||
boolean rayvisualizer = Config.getInstance().get(player).getPlainValueOrDefault("rayvisualizer", false);
|
boolean rayvisualizer = Config.STORE.get(player).isRayVisualizer();
|
||||||
if (rayvisualizer) server.addPlayer(player);
|
if (rayvisualizer) server.addPlayer(player);
|
||||||
} else {
|
} else {
|
||||||
server.removePlayer(player);
|
server.removePlayer(player);
|
||||||
@@ -194,8 +192,8 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
|
|||||||
|
|
||||||
@Register
|
@Register
|
||||||
public void toggle(@Validator Player player) {
|
public void toggle(@Validator Player player) {
|
||||||
boolean rayvisualizer = Config.getInstance().get(player).getPlainValueOrDefault("rayvisualizer", false);
|
boolean rayvisualizer = Config.STORE.get(player).isRayVisualizer();
|
||||||
Config.getInstance().get(player).put("rayvisualizer", !rayvisualizer);
|
Config.STORE.get(player).setRayVisualizer(!rayvisualizer);
|
||||||
if (!rayvisualizer) {
|
if (!rayvisualizer) {
|
||||||
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("RAY_VISUALIZER_ENABLE", player));
|
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("RAY_VISUALIZER_ENABLE", player));
|
||||||
server.addPlayer(player);
|
server.addPlayer(player);
|
||||||
|
|||||||
+6
-2
@@ -36,12 +36,16 @@ public class FireListener implements Listener, ScoreboardElement {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onFireDamage(BlockBurnEvent e) {
|
public void onFireDamage(BlockBurnEvent e) {
|
||||||
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) e.setCancelled(true);
|
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onFireSpread(BlockSpreadEvent e) {
|
public void onFireSpread(BlockSpreadEvent e) {
|
||||||
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) e.setCancelled(true);
|
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) {
|
||||||
|
e.setCancelled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+2
-2
@@ -44,11 +44,11 @@ public class FreezeCommand extends SWCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getEnableMessage(){
|
private String getEnableMessage() {
|
||||||
return "REGION_FREEZE_ENABLED";
|
return "REGION_FREEZE_ENABLED";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDisableMessage(){
|
private String getDisableMessage() {
|
||||||
return "REGION_FREEZE_DISABLED";
|
return "REGION_FREEZE_DISABLED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -24,8 +24,6 @@ import de.steamwar.bausystem.region.Region;
|
|||||||
import de.steamwar.bausystem.region.flags.Flag;
|
import de.steamwar.bausystem.region.flags.Flag;
|
||||||
import de.steamwar.bausystem.region.flags.FreezeMode;
|
import de.steamwar.bausystem.region.flags.FreezeMode;
|
||||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||||
import de.steamwar.core.Core;
|
|
||||||
import de.steamwar.core.TrickyTrialsWrapper;
|
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -33,6 +31,7 @@ import org.bukkit.block.Block;
|
|||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
import org.bukkit.block.data.type.NoteBlock;
|
import org.bukkit.block.data.type.NoteBlock;
|
||||||
import org.bukkit.block.data.type.Switch;
|
import org.bukkit.block.data.type.Switch;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@@ -48,7 +47,9 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockExplode(BlockExplodeEvent e) {
|
public void onBlockExplode(BlockExplodeEvent e) {
|
||||||
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
|
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
BlockState state = e.getBlock().getState();
|
BlockState state = e.getBlock().getState();
|
||||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||||
@@ -58,9 +59,11 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onEntitySpawn(EntitySpawnEvent e) {
|
public void onEntitySpawn(EntitySpawnEvent e) {
|
||||||
if (Region.getRegion(e.getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
|
if (Region.getRegion(e.getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
if (e.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
|
if (e.getEntityType() == EntityType.TNT) {
|
||||||
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
|
||||||
e.getLocation().getBlock().setType(Material.TNT, false);
|
e.getLocation().getBlock().setType(Material.TNT, false);
|
||||||
}, 1L);
|
}, 1L);
|
||||||
@@ -70,7 +73,9 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockCanBuild(BlockCanBuildEvent e) {
|
public void onBlockCanBuild(BlockCanBuildEvent e) {
|
||||||
if (!e.isBuildable()) return;
|
if (!e.isBuildable()) return;
|
||||||
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
|
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (e.getMaterial() == Material.TNT) {
|
if (e.getMaterial() == Material.TNT) {
|
||||||
e.setBuildable(false);
|
e.setBuildable(false);
|
||||||
e.getBlock().setType(Material.TNT, false);
|
e.getBlock().setType(Material.TNT, false);
|
||||||
@@ -155,7 +160,6 @@ public class FreezeListener implements Listener, ScoreboardElement {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockBreak(BlockBreakEvent e) {
|
public void onBlockBreak(BlockBreakEvent e) {
|
||||||
if (Core.getVersion() < 19) return;
|
|
||||||
if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return;
|
if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return;
|
||||||
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.ACTIVE)) {
|
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.ACTIVE)) {
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
|
|||||||
+2
-4
@@ -25,11 +25,9 @@ import de.steamwar.bausystem.region.flags.Flag;
|
|||||||
import de.steamwar.bausystem.region.flags.ItemMode;
|
import de.steamwar.bausystem.region.flags.ItemMode;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.linkage.MinVersion;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
@MinVersion(19)
|
|
||||||
public class ItemsCommand extends SWCommand {
|
public class ItemsCommand extends SWCommand {
|
||||||
|
|
||||||
public ItemsCommand() {
|
public ItemsCommand() {
|
||||||
@@ -46,11 +44,11 @@ public class ItemsCommand extends SWCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getEnableMessage(){
|
private String getEnableMessage() {
|
||||||
return "REGION_ITEMS_ENABLED";
|
return "REGION_ITEMS_ENABLED";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDisableMessage(){
|
private String getDisableMessage() {
|
||||||
return "REGION_ITEMS_DISABLED";
|
return "REGION_ITEMS_DISABLED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user