mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 10:53:05 +00:00
Compare commits
934 Commits
5.0.0-BETA
...
5.21.1
Author | SHA1 | Date | |
---|---|---|---|
4a702b97fd | |||
d2c3b8dacb | |||
2ff6470792 | |||
231eec911f | |||
8c04d47b1b | |||
b3b8aaddff | |||
2173aab967 | |||
e598364f06 | |||
734ca1cc6b | |||
96b12bddc1 | |||
84464cde4f | |||
72fc138631 | |||
c63d0ef1b6 | |||
82c416624d | |||
9e19391f20 | |||
c0b74b0341 | |||
3c96e72f7d | |||
0376e37966 | |||
94dff74494 | |||
0065fe649f | |||
8ef5e737de | |||
e7d8d99ca6 | |||
414e8acf8c | |||
d372af351a | |||
4814db4fe7 | |||
d01203d7c4 | |||
847f931660 | |||
22718c4971 | |||
acbfb0a3e9 | |||
7f9e79c83e | |||
7e343617b9 | |||
d945cbf517 | |||
c4e72c880e | |||
3ef7001d8e | |||
f1b1a7022d | |||
59d14de1d8 | |||
c8f567b093 | |||
5cc1068cd4 | |||
f6e6f15c63 | |||
4e6b34f573 | |||
a4a07a8e5a | |||
0a7cbdd56d | |||
a5babb2c9f | |||
49c2f13cf0 | |||
60cac18104 | |||
f6e2a1ecce | |||
00e39821f0 | |||
72d941fc1b | |||
8cb2e577a1 | |||
2a7b183ab8 | |||
e9b597af6c | |||
9381fc4172 | |||
281afb6838 | |||
ede363eb0f | |||
bdbcfd10cc | |||
e6f9cdd990 | |||
5241118f0b | |||
93a270d251 | |||
a7638cf914 | |||
c44e6c59fc | |||
92f380bb9c | |||
c32744ebc7 | |||
e3baf3cddb | |||
9176b2494a | |||
0f365886e0 | |||
8c3cf7a687 | |||
994fa5f792 | |||
3ed9615180 | |||
f5ab2979a0 | |||
929cd63135 | |||
585dc835e7 | |||
13f5cc9f87 | |||
1ce774ae73 | |||
d077bda30c | |||
e017780cc3 | |||
25c66e4c8b | |||
ee17ac5246 | |||
33dc995cc7 | |||
26761c2b87 | |||
5a926a79cb | |||
c4a2b6494d | |||
2aa64dc15e | |||
d0d7a995fb | |||
be2437ac6e | |||
bdb5845cec | |||
54e7749c0b | |||
237677c028 | |||
787afb6b00 | |||
df4ada81e5 | |||
a96f1a5083 | |||
1f510caf88 | |||
32be474840 | |||
f750b01d8b | |||
31484ee5c1 | |||
786d84a9e1 | |||
d6c48fd3a2 | |||
85606925a1 | |||
ef9791eaed | |||
accaa0acce | |||
616f96a703 | |||
824e270041 | |||
37bf4bc0b0 | |||
5d60ba36b7 | |||
68d2e2915e | |||
2ffc38c835 | |||
20f5741ed7 | |||
f6c0b228ec | |||
23b2b75acf | |||
25ea9b2218 | |||
77db7a8941 | |||
af4294295b | |||
b342c497d1 | |||
428e38f913 | |||
5ae13209c0 | |||
585aee9386 | |||
433bd6a8aa | |||
22a1549998 | |||
0ec8465fcf | |||
f121654452 | |||
08c6e63aac | |||
4c418b4318 | |||
fb9a74e879 | |||
554775841e | |||
373dd9938c | |||
f772bb7384 | |||
5ef247620a | |||
1b082f99e9 | |||
371eccd007 | |||
9b6a0c9945 | |||
ab3be50b49 | |||
27dc43f131 | |||
d67f5a5c6f | |||
ed158f8a1b | |||
d70a7d34a7 | |||
be6754494f | |||
d273ccf87c | |||
737f5066a0 | |||
10238d7934 | |||
6077748caa | |||
50e2c469a5 | |||
fa87602661 | |||
d3c9c137ad | |||
37322e0d50 | |||
55cf24aa02 | |||
3590d84d03 | |||
68f8fa8caf | |||
1ad190024a | |||
769a149057 | |||
ea339355bb | |||
b9288c238b | |||
16f29c775e | |||
e30e27dd57 | |||
cd6634d34b | |||
f013079ff6 | |||
c4abac4606 | |||
11fbc8db6f | |||
022362a01a | |||
98380e46bf | |||
dad9a7e6cd | |||
de6a91dabc | |||
0615afa766 | |||
d5919dc094 | |||
09904dc519 | |||
f799cfaba6 | |||
11f119551d | |||
2584314202 | |||
337e462c8f | |||
b680a1693c | |||
0e5395c59b | |||
94e0bf954b | |||
556b00d11f | |||
981f49ff56 | |||
f527a4c8fe | |||
7148c7a222 | |||
e31fd122d9 | |||
a835069564 | |||
b77193b987 | |||
11ca208d93 | |||
8d7f1a8557 | |||
7ff0ae19d6 | |||
1de66cb0de | |||
9f3533d870 | |||
2d24fac067 | |||
f193a990b0 | |||
c11c0679e3 | |||
ba48f258f3 | |||
e105c9bd76 | |||
23f4632409 | |||
264ce06cbf | |||
a6202d0442 | |||
8ec304e66e | |||
cbffbd23f9 | |||
9d7aec5891 | |||
ac8dbf8640 | |||
dbc7105e5b | |||
3b97d067a3 | |||
b0390a39fd | |||
5cb69e00d0 | |||
781e3643dd | |||
2ca50ecd36 | |||
5ad63f27bb | |||
f13eaaab05 | |||
72f3c0b4b9 | |||
b9a1ef1357 | |||
4abc36275c | |||
4b5ac53276 | |||
90409b50d1 | |||
bc2abf4b15 | |||
b2c97cf2f1 | |||
a35c3406a8 | |||
54ea404d80 | |||
98042f844f | |||
a0cca53f52 | |||
6872118355 | |||
efd113bdc8 | |||
34a5f91aa9 | |||
aee3656415 | |||
c58e599eb2 | |||
47f0119660 | |||
561ffd3da3 | |||
b744e09352 | |||
7b89dda420 | |||
db665fefdb | |||
6872661fd0 | |||
920341668f | |||
4fab518384 | |||
e06b042cd0 | |||
44ce9ca610 | |||
2616d8c5ad | |||
61d0181bfd | |||
db894e3a4a | |||
53cbc44d70 | |||
be102dc95f | |||
d211392b67 | |||
eaab1a8784 | |||
169d3e0de8 | |||
ce8fecc6ec | |||
4fcb644c51 | |||
826cbea0bc | |||
fe06bfcda0 | |||
f54ed8362d | |||
8c7a4d720a | |||
6492e7f4a2 | |||
6bb84bc46c | |||
20837c9894 | |||
f207d1bbf2 | |||
5709d727a2 | |||
234199d241 | |||
e28d20a68e | |||
81d5b9ba06 | |||
d97c8e2fd2 | |||
c7c20d4d79 | |||
c6a09e5ed8 | |||
e77cd39316 | |||
a459e3c1a9 | |||
288bd4018b | |||
9b03b082ab | |||
db3bb55a2b | |||
8372c9efc2 | |||
4db38ee452 | |||
ee977c8001 | |||
5b5c73f660 | |||
f83280ece6 | |||
19556634e3 | |||
5718a1a20e | |||
5386e86079 | |||
1b0ef468f3 | |||
b69843a8bd | |||
03619ebca9 | |||
fd1bc1b845 | |||
c05116849a | |||
7a55a6e6b6 | |||
bf99917f2a | |||
57f3a04bc5 | |||
c51b1b2812 | |||
80125f9b19 | |||
8dc28b7ea8 | |||
58ce746ae1 | |||
74cb0be868 | |||
4d9b97d2bb | |||
90af8cfd69 | |||
c8da9dea95 | |||
e1f4fd3048 | |||
d3d7f24015 | |||
944dd7d3e4 | |||
a03013d582 | |||
053abfbb6f | |||
00a8ea267c | |||
daeba95101 | |||
a750af72db | |||
61decaa2f8 | |||
06b2e61d3c | |||
b4838f5b4e | |||
46307973e3 | |||
2f1d6115a0 | |||
ba89ae5bf2 | |||
30433bba10 | |||
ed3fe2b727 | |||
927f129c6e | |||
2a136c7804 | |||
25cca1b63f | |||
15574ec99a | |||
2420dee8be | |||
bd65948453 | |||
0984aa670d | |||
239f9ed83a | |||
b2df405cc0 | |||
d596dc571d | |||
bc11894f0a | |||
d51475dc72 | |||
233c8b746d | |||
c1f0f13d5a | |||
06e2d36294 | |||
a1748a92ca | |||
fbcf4649eb | |||
0f620fad94 | |||
67ad2bad17 | |||
bc07778434 | |||
519784460f | |||
a25597ca30 | |||
89fbb3fd0d | |||
e9c5846a06 | |||
886ed60e6a | |||
8f107e785b | |||
69f197dbec | |||
13f34a500c | |||
e5c96faa4b | |||
dd98e4aaed | |||
e525699dd4 | |||
0ad6429fee | |||
923c922960 | |||
77590fb63a | |||
bd43ff6579 | |||
c2189bc2df | |||
58ea94bab8 | |||
22b10e4cb0 | |||
c44758f36c | |||
7a4cf8ef68 | |||
269b3d89a2 | |||
b3766834c6 | |||
93699024da | |||
c3c81b09e8 | |||
08f9873c32 | |||
50592dc269 | |||
e3700cab50 | |||
4103631bc1 | |||
c1ed182112 | |||
5f3a2a5096 | |||
8ccaf907d1 | |||
6b5c405939 | |||
d09af2e30d | |||
bbe66e8e09 | |||
457660235e | |||
9fc9609694 | |||
1055b7580a | |||
3385087c56 | |||
d3b7861d1a | |||
a6b36d6c3c | |||
109673382d | |||
1e4a1565bb | |||
8aaa6dd176 | |||
07dff9c9e8 | |||
75a39491be | |||
a10e4b6481 | |||
68c6b87678 | |||
e20c031aa1 | |||
9832fe899f | |||
55f3477ed9 | |||
2c17f82eb8 | |||
e6e2c54ec9 | |||
abce512860 | |||
0093732d49 | |||
9eb2a46942 | |||
1402571055 | |||
34bb86d2bf | |||
b41960dfec | |||
0b2fc84827 | |||
22b9e70372 | |||
a222636476 | |||
fb586cc562 | |||
f3f22ba48b | |||
a2e6e2e5b9 | |||
1aaaadb909 | |||
53a740433f | |||
8491d3c6c0 | |||
d637370b83 | |||
f655eda3b3 | |||
af432c1a7f | |||
9fcc9f4338 | |||
41c5f63565 | |||
73b1fba53c | |||
8e17aed4f4 | |||
1f461977d4 | |||
e4888d7102 | |||
450ad42202 | |||
eb935ca80f | |||
1c5d3b43be | |||
decc188302 | |||
8fa5c7cdab | |||
7dd3a70d2e | |||
dbb5a32a96 | |||
9474324f75 | |||
ada37899aa | |||
f1440324a7 | |||
73659318f6 | |||
f868c1d8c6 | |||
114f444ec3 | |||
19a1792184 | |||
6a3ec70c72 | |||
ccd2cdd324 | |||
c7a358a56f | |||
b3390458b4 | |||
b4d55e4384 | |||
932116fa52 | |||
7b5c30bc2c | |||
c14eb63f9b | |||
48dcf0e32c | |||
7f3de835e4 | |||
63fcf9879a | |||
224a69b11a | |||
d0d16cdeb7 | |||
18b711aca8 | |||
b0936a50c1 | |||
82d6fc3890 | |||
3c614b505d | |||
15ba642258 | |||
edea793a98 | |||
1da7e3586b | |||
538b698a00 | |||
128eb500eb | |||
7d200247f8 | |||
8b52a5cd9e | |||
c9163a1505 | |||
2d697c5f04 | |||
364f408eb1 | |||
660e2b8173 | |||
9facb98327 | |||
7e42a03db3 | |||
ee26d6d570 | |||
94a17f59d2 | |||
ed4088755f | |||
006f78c0a7 | |||
55cc5a6651 | |||
390cc3060a | |||
ca69f08da0 | |||
eac0564792 | |||
628d77f8d7 | |||
fe543a4789 | |||
31cd096b4b | |||
78cc5ba635 | |||
4b9d170954 | |||
d94391af57 | |||
ff89d4d055 | |||
a6b030f2b3 | |||
56d7039086 | |||
8f804f6f34 | |||
4f13e446a1 | |||
6ec340359b | |||
c3bca9e172 | |||
c028bb9055 | |||
f151047b5e | |||
77566db766 | |||
dd2e6ea33f | |||
ee6d551729 | |||
04b815a87a | |||
d138a15a32 | |||
7a2cfa92b6 | |||
912fd3f5c6 | |||
3906600d44 | |||
3f7abf29a8 | |||
fe3e2cc90a | |||
5eca90d478 | |||
338bb3fe6d | |||
f485f7fb46 | |||
63eba3eb53 | |||
914eb62e94 | |||
a85814d0c9 | |||
eb2e472b01 | |||
6553852d99 | |||
540476365f | |||
e9169cfa67 | |||
537e194161 | |||
f7f5af607c | |||
b293d7bf1f | |||
efafc2c6ca | |||
2a528b4afb | |||
999eab0c84 | |||
33a0fb9061 | |||
904b0acfff | |||
093b1e1b18 | |||
d7f69c5e24 | |||
d60fca0a1c | |||
0e87ee1e0e | |||
03ecc98a24 | |||
a5aeabd836 | |||
d3ab516ba4 | |||
aa916b2c49 | |||
7ce33d9375 | |||
14f2368454 | |||
07194e3884 | |||
58278f22f3 | |||
7dcd2592d4 | |||
6887fcd590 | |||
c168818311 | |||
b50efbc15a | |||
94d98fb5c4 | |||
ae564e445d | |||
fe94379a93 | |||
79acc4fed4 | |||
c8d357f4eb | |||
ec1cd5967d | |||
5a010e8213 | |||
73a44d50ee | |||
6aab07debd | |||
b160b87e24 | |||
690ee4c574 | |||
a0c7587b68 | |||
be4e091d40 | |||
857c2edc2c | |||
b1ab69ac6c | |||
e95a920fb8 | |||
67f399b238 | |||
a7c806d549 | |||
0920c76a35 | |||
a91ca999fe | |||
ce04478395 | |||
28ce7ac5fd | |||
540f088eda | |||
19e3d339f6 | |||
9fdb6ba5aa | |||
4a0a538278 | |||
2912e7ca29 | |||
31d8cc1cb5 | |||
506d8d1064 | |||
d1a7c1d453 | |||
b56f1b679e | |||
1a18e32011 | |||
09c9dfb576 | |||
f2b710c083 | |||
c7a311c17a | |||
ce53a221a5 | |||
c8100480ac | |||
8814d06dfd | |||
923f7561fb | |||
f4e1c31dcf | |||
998fcf20db | |||
1504fdca24 | |||
bf668c0f6c | |||
d942748203 | |||
29fdc8b08d | |||
20a41b00ba | |||
df96e023dc | |||
f4d5605de1 | |||
d03e4d17ec | |||
4cc858829f | |||
e852a43821 | |||
05f40b1315 | |||
7aaef8cb89 | |||
9d4c37fc3a | |||
cd6abbe0bb | |||
22778583cf | |||
d44e0e87d0 | |||
47b448965d | |||
cfa2df82eb | |||
7f78ec0a32 | |||
8572311bf4 | |||
18ca3a37d9 | |||
b2414b4c29 | |||
b3c740081e | |||
4b41fca991 | |||
9f09acc079 | |||
beaca8bb6d | |||
e323c5dd76 | |||
b65b7a7f74 | |||
f516c3c502 | |||
5afbb9d807 | |||
b330cbe8e2 | |||
39867b97c5 | |||
4c25d38b44 | |||
983aa79a0b | |||
af9ae445fc | |||
91d5a3ddfe | |||
e48b5b2ec0 | |||
f03e708f64 | |||
37f2dafae1 | |||
7826e0a11e | |||
97700636c6 | |||
447f061566 | |||
b86b389fc5 | |||
e27121a437 | |||
2d5c9e64ce | |||
78f5fbddf3 | |||
aa3f4f2545 | |||
f7279b6672 | |||
2711ab4f00 | |||
b4c5f5d58d | |||
a5d8ef7a6c | |||
59c88fe7f7 | |||
735d9a5bf4 | |||
f4a06605b1 | |||
77dfbc4e23 | |||
662f2495e9 | |||
b8a4ca45e4 | |||
ebcd6a0bb2 | |||
baefbce863 | |||
b45b4b5edf | |||
9f14901820 | |||
dd79d4c463 | |||
9c1ab943bc | |||
2c74124e2e | |||
514fc1ebb5 | |||
c1638ffaab | |||
710177ceb5 | |||
2559d1719f | |||
2e58387a43 | |||
515f8eae4c | |||
35a28300f6 | |||
1cf508abdb | |||
6ac45526f9 | |||
c91c8c2f9e | |||
81941ae9e5 | |||
1a2c10e844 | |||
d88c3d8ced | |||
82f87cc2da | |||
bb0e648276 | |||
6000bcccdd | |||
0b86fafafb | |||
2608637210 | |||
442d65143d | |||
53de55dcde | |||
01664d2e81 | |||
0a90a5928a | |||
46f24b165a | |||
6f09286fed | |||
774eb3e72b | |||
cd8219d9fd | |||
52ce3444d8 | |||
e9e5923639 | |||
49a9da147b | |||
4c0df5ee4e | |||
4c737b2ee3 | |||
eb53b795d5 | |||
befd3637f6 | |||
9b2a7b43c2 | |||
5ec3f4655f | |||
c972e65741 | |||
a45763328b | |||
82a5ea9ed3 | |||
bbdcab7277 | |||
6086ef667c | |||
486d4099df | |||
a1f34a460b | |||
5ff03c81f8 | |||
1c611a03e6 | |||
948875b025 | |||
fb43f59458 | |||
16dfd27935 | |||
2a4909d328 | |||
b078e01b65 | |||
4eb9dacd3c | |||
43770313ba | |||
3afe3b7f44 | |||
fd23281183 | |||
70dd8732e2 | |||
cdf72563f4 | |||
2779f92828 | |||
5899f2fc1d | |||
9ef835c82d | |||
d65d8c3356 | |||
9b43ddecbd | |||
4bdd6410db | |||
6ea7fd7d6b | |||
5e7f18cbcf | |||
4517948297 | |||
777a901932 | |||
24d979bd08 | |||
86810c5e1c | |||
b33a9690e9 | |||
1b9c282194 | |||
82b75e0ccb | |||
6c59912ed5 | |||
3c34841dfc | |||
914dd90b3d | |||
537721fe7d | |||
fba51e3bf9 | |||
763241b11f | |||
8414c78969 | |||
4637aae621 | |||
6fbc133e5d | |||
f38aee1fc5 | |||
69abd5eb53 | |||
f6ee7ddc9e | |||
cff4a8d2bc | |||
20b7e8d702 | |||
c6110be051 | |||
c053742f5d | |||
0051b34797 | |||
a74ab756bd | |||
90520c8962 | |||
2e9a4f2be2 | |||
e23806d417 | |||
30db658d70 | |||
83d11c7429 | |||
4c6b82f30a | |||
fb6a7d279f | |||
0c1bfb058a | |||
45d1ce9bb8 | |||
8c8794ec71 | |||
b399eda21e | |||
f7c08dedee | |||
250d18e41b | |||
86bd6777a3 | |||
935df62006 | |||
489a7ba365 | |||
2709dd359c | |||
4e646d19a4 | |||
2a11762e61 | |||
dca752c72f | |||
259cc305df | |||
7132ac0ad3 | |||
0d8a06732a | |||
d2f4ba74c6 | |||
d4716ef457 | |||
d630b3af7b | |||
c2bb51cb37 | |||
7e0b5cf73d | |||
e903da8998 | |||
b7210755a7 | |||
f2193d1ba7 | |||
4daacb2ab7 | |||
f7977c9668 | |||
93d3f439bf | |||
200e5f940c | |||
9365ffa7fa | |||
cfd9950b02 | |||
8ebcdb452d | |||
ef85fbffe1 | |||
aacc00a911 | |||
0c250a2ef0 | |||
c01d2dc718 | |||
8f217ca6e0 | |||
f0d5647aa2 | |||
e6de9a70a2 | |||
a34514c6a1 | |||
6a80b210d4 | |||
02ffb04b92 | |||
6cbb03bf9b | |||
3abd592b1f | |||
644b417d2c | |||
588a754f1c | |||
70dd9c7371 | |||
f8e6f036af | |||
5d51ffdfe3 | |||
a2a7006878 | |||
b78c18ad2d | |||
41281db6a5 | |||
2278275505 | |||
53a6d8451b | |||
bbabccfc89 | |||
1698eac6dc | |||
83378d9403 | |||
321972b87b | |||
24b74a96eb | |||
e61796b146 | |||
c86c9b3ead | |||
249ef9c534 | |||
17842703a1 | |||
f4dab17a1b | |||
eed423505e | |||
c165670e0a | |||
882d50b14e | |||
0b0b72f596 | |||
2654fb294b | |||
2b40c1a5be | |||
74d219dcb6 | |||
470a3e1a3a | |||
ad67fb7291 | |||
3eed0a4620 | |||
b8788c55c5 | |||
c06763c59b | |||
881451c40c | |||
36f52f1ade | |||
0240d35c05 | |||
8dedbb7471 | |||
6f82942c64 | |||
9d0d60afd1 | |||
391732f00c | |||
ad3f854701 | |||
64e09525f3 | |||
774f92435a | |||
be8cca1d55 | |||
eb9f804781 | |||
bccda4fe44 | |||
8f48f8a596 | |||
288ebfa08a | |||
a3046eb6fa | |||
ff0199cdf8 | |||
39a6a9ee70 | |||
0939301938 | |||
202be92c06 | |||
df4a8d4788 | |||
1d25e15ec8 | |||
1b35c352cc | |||
ab75838c89 | |||
1533dc4e56 | |||
3800c0480f | |||
0f8e61eda4 | |||
0eb5f9b684 | |||
0f9283fda1 | |||
ab8386ed5a | |||
64c1776910 | |||
e85605af7f | |||
92bd88c77c | |||
7cd317bf39 | |||
35fc9abacf | |||
dfd70615ad | |||
ee903cad1f | |||
9a04481bec | |||
833f9401f9 | |||
a46dfaf677 | |||
4a3b175468 | |||
73ee94b62c | |||
ab83210aa0 | |||
3f2d51c58a | |||
13dee2a615 | |||
5d514a274f | |||
2220dc557e | |||
b5fc31a781 | |||
9a67e3d660 | |||
132330e16f | |||
179eec9754 | |||
441f1f534f | |||
e747478afd | |||
92c45dd7e1 | |||
2538880408 | |||
4af981d726 | |||
ab3ebc1aa8 | |||
57cbc25080 | |||
b9bdfe580b | |||
6d7f44d8fe | |||
f9818efff4 | |||
7fef8f0ab6 | |||
2f43ccea6f | |||
af1f7e098b | |||
1706fb43eb | |||
8d7f8ff3f5 | |||
c715efb18e | |||
40be564689 | |||
4e031e7b3e | |||
4340c26029 | |||
9c6d4093ae | |||
007ef833d4 | |||
6678360c00 | |||
102fd4d63a | |||
2c0715ac6e | |||
f75bb061ce | |||
73e7201acb | |||
b16cc69974 | |||
5de4215169 | |||
e128a4e1e7 | |||
c95c600100 | |||
3db45b6a68 | |||
3e87ad281f | |||
b72da777eb | |||
de49910e84 | |||
d2fe537159 | |||
bb31df051d | |||
1101f35c17 | |||
07225df936 | |||
3948dc4f75 | |||
4f4dca7fc0 | |||
0ed5e94a72 | |||
3a4e958e84 | |||
20942b37eb | |||
d343db8750 | |||
f2df702c67 | |||
481270e6aa | |||
e7bdaa8579 | |||
76749cbaa7 | |||
a897bdfaa0 | |||
09668a37d6 | |||
ea92a23d0d | |||
691e67018d | |||
fe2140a716 | |||
8744032ab6 | |||
5a9cdef40c | |||
a49842278a | |||
d57954dff0 | |||
ce5e663a73 | |||
c10be0f346 | |||
f5a1a0c9cb | |||
7f1550ef04 | |||
9baf59702b | |||
473c062b40 | |||
b8ba2d03ba | |||
06b0fa4d67 | |||
fddab29e87 | |||
bdb0ed0701 | |||
edafe9d21f | |||
cc77f18ff0 | |||
24e897f813 | |||
ffe3556be1 | |||
57330a7186 | |||
2ebf8757c1 | |||
1c69116717 | |||
9d9c628acd | |||
cbda24d77e | |||
ed64eac76f | |||
a7aebed0a0 | |||
c66a3a8b3e | |||
4aba9d9725 | |||
d2c34615f5 | |||
815b4e2bab | |||
69273f3ff7 | |||
9ddac21de0 | |||
fdb724c646 | |||
3109a179db | |||
5afeeb8f89 | |||
1cb7846f7c | |||
097feba4d5 | |||
9509d7e04d | |||
3116fb8187 | |||
e0630fbb25 | |||
8245cfab0e | |||
8454076235 | |||
4a3843a881 | |||
bd6af68f91 | |||
b27d3a5fce | |||
c91aa24daa | |||
b8a1b32461 | |||
9c82507168 | |||
db95bf8b9b | |||
edcf0f8405 | |||
0629d11e13 |
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -34,7 +34,10 @@ Requires translations:
|
||||
|
||||
## Tests
|
||||
<!--
|
||||
Details should be provided of tests done. Simply saying "tested" or equivalent is not acceptable.
|
||||
|
||||
Attach scripts or actions to test this pull request, as well as the result
|
||||
PRs which have not been tested MUST be marked as draft.
|
||||
-->
|
||||
I tested this PR by doing the following (tick all that apply):
|
||||
- [ ] Writing PHPUnit tests (commit these in the `tests/phpunit` folder)
|
||||
- [ ] Playtesting using a Minecraft client (provide screenshots or a video)
|
||||
- [ ] Writing a test plugin (provide the code and sample output)
|
||||
- [ ] Other (provide details)
|
||||
|
20
.github/dependabot.yml
vendored
20
.github/dependabot.yml
vendored
@ -3,7 +3,7 @@ updates:
|
||||
- package-ecosystem: composer
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: weekly
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
@ -12,6 +12,22 @@ updates:
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
groups:
|
||||
production-patch-updates:
|
||||
dependency-type: production
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "patch"
|
||||
development-patch-updates:
|
||||
dependency-type: development
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "patch"
|
||||
phpstan:
|
||||
patterns:
|
||||
- "phpstan/*"
|
||||
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
@ -21,4 +37,4 @@ updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: weekly
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
.github/readme/pocketmine-dark-rgb.gif
vendored
Normal file
BIN
.github/readme/pocketmine-dark-rgb.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 173 KiB |
BIN
.github/readme/pocketmine-rgb.gif
vendored
Normal file
BIN
.github/readme/pocketmine-rgb.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 173 KiB |
16
.github/workflows/build-docker-image.yml
vendored
16
.github/workflows/build-docker-image.yml
vendored
@ -12,23 +12,23 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Clone pmmp/PocketMine-Docker repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: pmmp/PocketMine-Docker
|
||||
fetch-depth: 1
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
22
.github/workflows/discord-release-embed.php
vendored
22
.github/workflows/discord-release-embed.php
vendored
@ -18,7 +18,12 @@ require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
/**
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId) : array{
|
||||
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId, ?string $phpDownloadUrl) : array{
|
||||
if($phpDownloadUrl !== null){
|
||||
$phpEmbedLink = " | [PHP Binaries]($phpDownloadUrl)";
|
||||
}else{
|
||||
$phpEmbedLink = "";
|
||||
}
|
||||
return [
|
||||
"content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)",
|
||||
"embeds" => [
|
||||
@ -27,7 +32,7 @@ function generateDiscordEmbed(string $version, string $channel, string $descript
|
||||
"description" => <<<DESCRIPTION
|
||||
$description
|
||||
|
||||
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
|
||||
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)$phpEmbedLink
|
||||
DESCRIPTION,
|
||||
"url" => $detailsUrl,
|
||||
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
|
||||
@ -84,10 +89,21 @@ $detailsUrl = $buildInfoJson["details_url"];
|
||||
$sourceUrl = $buildInfoJson["source_url"];
|
||||
$pharDownloadUrl = $buildInfoJson["download_url"];
|
||||
$buildLogUrl = $buildInfoJson["build_log_url"];
|
||||
$phpBinaryUrl = $buildInfoJson["php_download_url"] ?? null;
|
||||
|
||||
$description = $releaseInfoJson["body"];
|
||||
|
||||
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl, (int) $newsPingRoleId);
|
||||
$discordPayload = generateDiscordEmbed(
|
||||
$buildInfoJson["base_version"],
|
||||
$buildInfoJson["channel"],
|
||||
$description,
|
||||
$detailsUrl,
|
||||
$sourceUrl,
|
||||
$pharDownloadUrl,
|
||||
$buildLogUrl,
|
||||
(int) $newsPingRoleId,
|
||||
$phpBinaryUrl
|
||||
);
|
||||
|
||||
$response = Internet::postURL(
|
||||
$hookURL,
|
||||
|
8
.github/workflows/discord-release-notify.yml
vendored
8
.github/workflows/discord-release-notify.yml
vendored
@ -10,15 +10,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
|
65
.github/workflows/draft-release-from-pr.yml
vendored
Normal file
65
.github/workflows/draft-release-from-pr.yml
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
name: Draft release from PR
|
||||
|
||||
on:
|
||||
#presume that pull_request_target is safe at this point, since the PR was approved and merged
|
||||
#we need write access to prepare the release & create comments
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- stable
|
||||
- minor-next
|
||||
- major-next
|
||||
- "legacy/*"
|
||||
paths:
|
||||
- "src/VersionInfo.php"
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check release
|
||||
uses: ./.github/workflows/draft-release-pr-check.yml
|
||||
|
||||
draft:
|
||||
name: Create GitHub draft release
|
||||
needs: [check]
|
||||
if: needs.check.outputs.valid == 'true'
|
||||
|
||||
uses: ./.github/workflows/draft-release.yml
|
||||
|
||||
post-draft-url-comment:
|
||||
name: Post draft release URL as comment
|
||||
needs: [draft]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Post draft release URL on PR
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
message: "[Draft release ${{ needs.draft.outputs.version }}](${{ needs.draft.outputs.draft-url }}) has been created for commit ${{ github.sha }}. Please review and publish it."
|
||||
|
||||
trigger-post-release-workflow:
|
||||
name: Trigger post-release RestrictedActions workflow
|
||||
# Not sure if needs is actually needed here
|
||||
needs: [check]
|
||||
if: needs.check.outputs.valid == 'true'
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: RestrictedActions
|
||||
|
||||
- name: Dispatch post-release restricted action
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
repository: ${{ github.repository_owner }}/RestrictedActions
|
||||
event-type: pocketmine_mp_post_release
|
||||
client-payload: '{"branch": "${{ github.ref }}"}'
|
13
.github/workflows/draft-release-from-tag.yml
vendored
Normal file
13
.github/workflows/draft-release-from-tag.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#Allows creating a release by pushing a tag
|
||||
#This might be useful for retroactive releases
|
||||
name: Draft release from git tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: "*"
|
||||
|
||||
jobs:
|
||||
draft:
|
||||
name: Create GitHub draft release
|
||||
if: "startsWith(github.event.head_commit.message, 'Release ')"
|
||||
uses: ./.github/workflows/draft-release.yml
|
111
.github/workflows/draft-release-pr-check.yml
vendored
Normal file
111
.github/workflows/draft-release-pr-check.yml
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
name: Release PR checks
|
||||
|
||||
on:
|
||||
#do checks on every PR update
|
||||
pull_request:
|
||||
branches:
|
||||
- stable
|
||||
- minor-next
|
||||
- major-next
|
||||
- "legacy/*"
|
||||
paths:
|
||||
- "src/VersionInfo.php"
|
||||
|
||||
#allow this workflow to be invoked on PR merge, prior to creating the release
|
||||
workflow_call:
|
||||
outputs:
|
||||
valid:
|
||||
description: Whether this commit is valid for release
|
||||
value: ${{ jobs.check-intent.outputs.valid && jobs.check-validity.result == 'success' }}
|
||||
|
||||
permissions:
|
||||
contents: read #for user access check
|
||||
|
||||
jobs:
|
||||
check-intent:
|
||||
name: Check release trigger
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
outputs:
|
||||
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check IS_DEVELOPMENT_BUILD flag
|
||||
id: validate
|
||||
run: |
|
||||
echo DEV_BUILD=$(sed -n "s/^\s*public const IS_DEVELOPMENT_BUILD = \(true\|false\);$/\1/p" src/VersionInfo.php) >> $GITHUB_OUTPUT
|
||||
|
||||
check-validity:
|
||||
name: Validate release info
|
||||
needs: [check-intent]
|
||||
#don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses
|
||||
if: needs.check-intent.outputs.valid == 'true'
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Check author permissions
|
||||
id: check-permission
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
require: write
|
||||
username: ${{ github.event.pull_request.user.login }}
|
||||
#technically this would be fine for dependabot but generally bots don't count as team members
|
||||
check-bot: true
|
||||
|
||||
- name: Abort if user permissions are insufficient
|
||||
#user doesn't have permission or is a bot
|
||||
if: steps.check-permission.outputs.require-result != 'true' || steps.check-permission.outputs.check-result != 'false'
|
||||
run: |
|
||||
echo "::error::This user is not authorized to trigger releases"
|
||||
exit 1
|
||||
|
||||
- name: Check changelog file is present
|
||||
id: file-presence
|
||||
run: |
|
||||
CHANGELOG_FILE="changelogs/$(php build/dump-version-info.php changelog_file_name)"
|
||||
if [ ! -f "${{ github.workspace }}/$CHANGELOG_FILE" ]; then
|
||||
echo "::error::$CHANGELOG_FILE does not exist"
|
||||
exit 1
|
||||
fi
|
||||
echo FILE="$CHANGELOG_FILE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check header is present in changelog file
|
||||
run: |
|
||||
FILE="${{ steps.file-presence.outputs.FILE }}"
|
||||
VERSION="$(php build/dump-version-info.php base_version)"
|
||||
if ! grep -Fqx "# $VERSION" "${{ github.workspace }}/$FILE"; then
|
||||
echo "::error::Header for $VERSION not found in $FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check version is valid for the selected channel
|
||||
run: |
|
||||
CHANNEL="$(php build/dump-version-info.php channel)"
|
||||
if [ "$(php build/dump-version-info.php suffix_valid)" != "true" ]; then
|
||||
echo "::error::Version $(php build/dump-version-info.php base_version) is not allowed on the $CHANNEL channel"
|
||||
exit 1
|
||||
fi
|
68
.github/workflows/draft-release.yml
vendored
68
.github/workflows/draft-release.yml
vendored
@ -1,29 +1,41 @@
|
||||
name: Draft release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: "*"
|
||||
workflow_call:
|
||||
outputs:
|
||||
draft-url:
|
||||
description: 'The URL of the draft release'
|
||||
value: ${{ jobs.draft.outputs.draft-url }}
|
||||
version:
|
||||
description: 'PocketMine-MP version'
|
||||
value: ${{ jobs.draft.outputs.version }}
|
||||
|
||||
jobs:
|
||||
draft:
|
||||
name: Create GitHub draft release
|
||||
if: "startsWith(github.event.head_commit.message, 'Release ')"
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version: [8.2]
|
||||
|
||||
outputs:
|
||||
draft-url: ${{ steps.create-draft.outputs.html_url }}
|
||||
version: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -51,36 +63,56 @@ jobs:
|
||||
- name: Get PocketMine-MP release version
|
||||
id: get-pm-version
|
||||
run: |
|
||||
echo PM_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') >> $GITHUB_OUTPUT
|
||||
echo MCPE_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION_SHORT=$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);') >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION_MD=$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_SUFFIX=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;') >> $GITHUB_OUTPUT
|
||||
echo PRERELEASE=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";') >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION=$(php build/dump-version-info.php base_version) >> $GITHUB_OUTPUT
|
||||
echo MCPE_VERSION=$(php build/dump-version-info.php mcpe_version) >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_FILE_NAME=$(php build/dump-version-info.php changelog_file_name) >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_MD_HEADER=$(php build/dump-version-info.php changelog_md_header) >> $GITHUB_OUTPUT
|
||||
echo PRERELEASE=$(php build/dump-version-info.php prerelease) >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate PHP binary download URL
|
||||
id: php-binary-url
|
||||
run: |
|
||||
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/php-${{ matrix.php-version }}-latest" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate build info
|
||||
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
|
||||
run: |
|
||||
php build/generate-build-info-json.php \
|
||||
${{ github.sha }} \
|
||||
${{ steps.get-pm-version.outputs.PM_VERSION }} \
|
||||
${{ github.repository }} \
|
||||
${{ steps.build-number.outputs.BUILD_NUMBER }} \
|
||||
${{ github.run_id }} \
|
||||
${{ steps.php-binary-url.outputs.PHP_BINARY_URL }} \
|
||||
> build_info.json
|
||||
|
||||
- name: Generate core permission doc for doc.pmmp.io
|
||||
run: php tools/generate-permission-doc.php rst
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release_artifacts
|
||||
path: |
|
||||
${{ github.workspace }}/PocketMine-MP.phar
|
||||
${{ github.workspace }}/start.*
|
||||
${{ github.workspace }}/build_info.json
|
||||
${{ github.workspace }}/core-permissions.rst
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.12.0
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
id: create-draft
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
|
||||
commit: ${{ github.sha }}
|
||||
draft: true
|
||||
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
|
||||
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
skipIfReleaseExists: true #for release PRs, tags will be created on release publish and trigger the tag release workflow - don't create a second draft
|
||||
body: |
|
||||
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
|
||||
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.CHANGELOG_FILE_NAME }}#${{ steps.get-pm-version.outputs.CHANGELOG_MD_HEADER }}) for details.
|
||||
|
||||
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
|
||||
|
156
.github/workflows/main-php-matrix.yml
vendored
Normal file
156
.github/workflows/main-php-matrix.yml
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
name: CI (all supported PHP versions)
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
php:
|
||||
description: 'PHP version in X.Y format'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
#these are parameterized to ease updating
|
||||
pm-version-major:
|
||||
description: 'PocketMine-MP major version'
|
||||
default: 5
|
||||
type: number
|
||||
image:
|
||||
description: 'Runner image to use'
|
||||
default: 'ubuntu-20.04'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
runs-on: ${{ inputs.image }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||
|
||||
integration:
|
||||
name: Integration tests
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run integration tests
|
||||
run: ./tests/travis.sh -t4
|
||||
|
||||
codegen:
|
||||
name: Generated Code consistency checks
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Update generated code
|
||||
run: composer update-codegen
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
git diff --quiet
|
212
.github/workflows/main.yml
vendored
212
.github/workflows/main.yml
vendored
@ -6,195 +6,17 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-php:
|
||||
name: Prepare PHP
|
||||
runs-on: ${{ matrix.image }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- name: Build and prepare PHP cache
|
||||
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
|
||||
all-php-versions:
|
||||
name: PHP ${{ matrix.php }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.1.19, 8.2.6]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||
|
||||
integration:
|
||||
name: Integration tests
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run integration tests
|
||||
run: ./tests/travis.sh -t4
|
||||
|
||||
codegen:
|
||||
name: Generated Code consistency checks
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Regenerate registry annotations
|
||||
run: php build/generate-registry-annotations.php src
|
||||
|
||||
- name: Regenerate KnownTranslation APIs
|
||||
run: php build/generate-known-translation-apis.php
|
||||
|
||||
- name: Regenerate RuntimeEnum(De)serializer
|
||||
run: php build/generate-runtime-enum-serializers.php
|
||||
|
||||
- name: Regenerate BedrockData available files constants
|
||||
run: php build/generate-bedrockdata-path-consts.php
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
git diff --quiet
|
||||
uses: ./.github/workflows/main-php-matrix.yml
|
||||
with:
|
||||
php: ${{ matrix.php }}
|
||||
secrets: inherit
|
||||
|
||||
codestyle:
|
||||
name: Code Style checks
|
||||
@ -203,15 +25,27 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.1
|
||||
tools: php-cs-fixer:3.16
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.49
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
||||
shellcheck:
|
||||
name: ShellCheck
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@2.0.0
|
||||
|
2
.github/workflows/support.yml
vendored
2
.github/workflows/support.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v3
|
||||
- uses: dessant/support-requests@v4
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
support-label: "Support request"
|
||||
|
42
.github/workflows/team-pr-auto-approve.yml
vendored
Normal file
42
.github/workflows/team-pr-auto-approve.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
#Due to GitHub awkwardness, it's not easy to reduce the review requirement for collaborators.
|
||||
#Our policy is that 2 collaborators should be aware of every change.
|
||||
#For outside PRs, this means 2 collaborator reviews.
|
||||
#For PRs made by collaborators, this means 1 reviewer + the author.
|
||||
#We trust that collaborators don't need as much oversight.
|
||||
name: Auto approve collaborator PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
name: Auto approve
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check if PR author has write access
|
||||
id: check-permission
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
require: write
|
||||
username: ${{ github.event.pull_request.user.login }}
|
||||
#technically this would be fine for dependabot but generally bots don't count as team members
|
||||
check-bot: true
|
||||
|
||||
#TODO: Some way to avoid unnecessary repeated reviews would be nice here
|
||||
|
||||
- name: Approve PR if authorized
|
||||
if: steps.check-permission.outputs.require-result == 'true' && steps.check-permission.outputs.check-result == 'false'
|
||||
uses: juliangruber/approve-pull-request-action@v2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ github.event.pull_request.number }}
|
50
.github/workflows/update-php-versions.php
vendored
50
.github/workflows/update-php-versions.php
vendored
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"8.1",
|
||||
"8.2"
|
||||
];
|
||||
|
||||
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
|
||||
$newWorkflowFile = $workflowFile;
|
||||
foreach(VERSIONS as $v){
|
||||
$releaseInfo = file_get_contents("https://secure.php.net/releases?json&version=$v");
|
||||
if($releaseInfo === false){
|
||||
throw new \RuntimeException("Failed to contact php.net API");
|
||||
}
|
||||
$data = json_decode($releaseInfo, true);
|
||||
if(!is_array($data) || !isset($data["version"]) || !is_string($data["version"]) || preg_match('/^\d+\.\d+\.\d+(-[A-Za-z\d]+)?$/', $data["version"]) === 0){
|
||||
throw new \RuntimeException("Invalid data returned by API");
|
||||
}
|
||||
$updated = preg_replace("/$v\.\d+/", $data["version"], $newWorkflowFile);
|
||||
if($updated !== $newWorkflowFile){
|
||||
echo "Updated $v revision to " . $data["version"] . "\n";
|
||||
}
|
||||
$newWorkflowFile = $updated;
|
||||
}
|
||||
|
||||
if($workflowFile !== $newWorkflowFile){
|
||||
echo "Writing modified workflow file\n";
|
||||
file_put_contents(__DIR__ . '/main.yml', $newWorkflowFile);
|
||||
}
|
3
.github/workflows/update-updater-api.yml
vendored
3
.github/workflows/update-updater-api.yml
vendored
@ -8,12 +8,13 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
concurrency: update-updater-api # only one job can run at a time, to avoid git conflicts when updating the repository
|
||||
|
||||
steps:
|
||||
- name: Install jq
|
||||
run: sudo apt update && sudo apt install jq -y
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -53,3 +53,6 @@ Documentation/*
|
||||
# php-cs-fixer
|
||||
/.php_cs.cache
|
||||
/.php-cs-fixer.cache
|
||||
|
||||
# install-local-protocol.sh
|
||||
/composer-local-protocol.*
|
||||
|
7
.idea/codeStyles/Project.xml
generated
7
.idea/codeStyles/Project.xml
generated
@ -30,6 +30,13 @@
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Markdown">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="CLASS_BRACE_STYLE" value="1" />
|
||||
<option name="METHOD_BRACE_STYLE" value="1" />
|
||||
|
@ -2,7 +2,7 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 8.1 or newer available in your shell
|
||||
- PHP 8.2 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
|
@ -28,10 +28,8 @@ Take a look at the table below if you can't find the class or function you're lo
|
||||
|:----------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [pmmp/BedrockProtocol](https://github.com/pmmp/BedrockProtocol) | `pocketmine\network\mcpe\protocol` |
|
||||
| [pmmp/BinaryUtils](https://github.com/pmmp/BinaryUtils) | `pocketmine\utils\BinaryDataException`</br>`pocketmine\utils\BinaryStream`</br>`pocketmine\utils\Binary` |
|
||||
| [pmmp/ClassLoader](https://github.com/pmmp/`ClassLoader`) | `BaseClassLoader`</br>`ClassLoader`</br>`DynamicClassLoader` |
|
||||
| [pmmp/Color](https://github.com/pmmp/Color) | `pocketmine\color` |
|
||||
| [pmmp/ErrorHandler](https://github.com/pmmp/ErrorHandler) | `pocketmine\errorhandler` |
|
||||
| [pmmp/LogPthreads](https://github.com/pmmp/LogPthreads) | `ThreadedLoggerAttachment`</br>`ThreadedLogger`</br>`AttachableThreadedLogger` |
|
||||
| [pmmp/Log](https://github.com/pmmp/Log) | `AttachableLogger`</br>`BufferedLogger`</br>`GlobalLogger`</br>`LogLevel`</br>`Logger`</br>`PrefixedLogger`</br>`SimpleLogger` |
|
||||
| [pmmp/Math](https://github.com/pmmp/Math) | `pocketmine\math` |
|
||||
| [pmmp/NBT](https://github.com/pmmp/NBT) | `pocketmine\nbt` |
|
||||
@ -90,45 +88,58 @@ Depending on the changes, maintainers might ask you to make changes to the PR to
|
||||
### Requirements
|
||||
The following are required as a minimum for pull requests. PRs that don't meet these requirements will be declined unless updated to meet them.
|
||||
|
||||
#### Licensing
|
||||
PocketMine-MP is licensed under [LGPLv3 license](LICENSE).
|
||||
By proposing a pull request, you agree to your code being distributed within PocketMine-MP under the same license.
|
||||
If you take code from other projects, that code MUST be licensed under an LGPL-compatible license.
|
||||
|
||||
#### PRs should be about exactly ONE thing
|
||||
If you want to make multiple changes, those changes should each be contributed as separate pull requests. **DO NOT** mix unrelated changes.
|
||||
|
||||
#### PRs must not include unnecessary/unrelated changes
|
||||
Do not include changes which aren't strictly necessary. This makes it harder to review a PR, because the code diff becomes larger and harder to review.
|
||||
This means:
|
||||
- don't reformat or rearrange existing code
|
||||
- don't change things that aren't related to the PR's objective
|
||||
- don't rewrite existing code just to make it "look nicer"
|
||||
- don't change PhpDocs to native types in code you didn't write
|
||||
|
||||
#### Tests must be provided
|
||||
Where possible, PHPUnit tests should be written for new or changed code.
|
||||
If that's not possible (e.g. for in-game functionality), the code must be tested manually and details of the tests done must be provided.
|
||||
**Simply saying "Tested" is not acceptable** and will lead to your PR being declined.
|
||||
|
||||
#### Comments and documentation must be written in American English
|
||||
English is the shared languages of all current maintainers.
|
||||
|
||||
#### Code must be in the PocketMine-MP style
|
||||
It's your responsibility to ensure your code matches the formatting and styling of the rest of the code.
|
||||
If you use PhpStorm, a `Project` code style is provided, which you can use to automatically format new code.
|
||||
You can also use [`php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to format your code.
|
||||
- **All code must be licensed under the [LGPLv3 license](LICENSE)** as per PocketMine-MP's own license, or a compatible license.
|
||||
- By proposing a pull request, you agree to your code being distributed within PocketMine-MP under the same license.
|
||||
- If you take code from other projects, that code MUST be licensed under an LGPL-compatible license.
|
||||
- **PRs should be about ONE thing**
|
||||
- If you want to make multiple changes, those changes should each be contributed as separate pull requests. **DO NOT** mix unrelated changes.
|
||||
- **Do not include unnecessary changes.** This makes the code diff larger and more noisy, making it harder to review.
|
||||
- Don't change things that aren't related to the PR's objective
|
||||
- Don't reformat or rearrange existing code without a good reason related to the PR's objective
|
||||
- Don't rewrite existing code just to make it "look nicer"
|
||||
- Don't change PhpDocs to native types in code you didn't write, unless that's the objective of the PR
|
||||
- **Test code changes, and tell us what tests have been done.**
|
||||
- Where possible, PHPUnit tests should be written for new or changed code. If that's not possible (e.g. for in-game functionality), the code must be tested manually and details of the tests done must be provided.
|
||||
- **Simply saying "Tested" is not acceptable** and could lead to your PR being declined.
|
||||
- **Code, comments and documentation must be written in American English.** English is the shared languages of all current maintainers.
|
||||
- **Code must be in the PocketMine-MP style.**
|
||||
- It's your responsibility to ensure your code matches the formatting and styling of the rest of the code.
|
||||
- If you use PhpStorm, a `Project` code style is provided, which you can use to automatically format new code.
|
||||
- You can also use [`php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to format your code.
|
||||
- **Use `final` and `private` wherever possible**.
|
||||
- Changing from `private` to `protected` or `final` to non-`final` doesn't break backwards compatibility, but the opposite does.
|
||||
- `private` and `final` also enable certain performance optimizations which are otherwise not possible.
|
||||
- `private` members can be freely changed, added and removed in the future, so it's ideal for internal functions. Abusing `protected` makes internal improvements inconvenient.
|
||||
- "Let's leave it protected/public in case someone needs it for ... idk what" is **not a valid reason to expose things**. If there isn't a clear reason for something to be accessible from the outside, don't expose it.
|
||||
- **This is a lesson learned through years of experience.** You may not like it, but it's for the best.
|
||||
- **Immutable things are almost always preferred.**
|
||||
- Do not add unnecessary setters or public writable properties to classes. As above, "Let's leave it in case someone needs it" is **not a valid reason to expose things**.
|
||||
- Mutable classes and properties are unpredictable, since code has no way to know if the object it's working with might be randomly modified by another part of the code. This makes it harder to maintain code and debug issues.
|
||||
- Most classes exist only to hold some data. These are called "data transfer objects" (DTOs). These types of classes should pretty much always be immutable.
|
||||
- Make use of `final`, `private` and `readonly` modifiers.
|
||||
|
||||
### Recommendations
|
||||
|
||||
- **Be patient.** Reviewing pull requests takes a lot of time and energy, and maintainers are often unavailable or busy. Your PR might not receive attention for a while.
|
||||
- Remember, PRs with small diffs are much easier to review. Small PRs are generally reviewed and merged much faster than large ones.
|
||||
- **Start small.** Try fixing minor bugs or doing something isolated (e.g. adding a new block or item) before attempting larger changes.
|
||||
- This helps you get familiar with the codebase, the contribution process, and the expectations of maintainers.
|
||||
- Check out the [issues page]() for something that you could tackle without too much effort.
|
||||
- **Do not copy-paste other people's code**. Many PRs involve discussion about the changes, and changes are often requested by reviewers. If you don't understand the code you're copy-pasting, your PR is likely to fail.
|
||||
- **Do not edit code directly on github.com.** We recommend learning how to use [`git`](https://git-scm.com). `git` allows you to "clone" a repository onto your computer, so that you can make changes using an IDE.
|
||||
- **Use an IDE, not a text editor.** We recommend PhpStorm or VSCode.
|
||||
- **Do not make large pull requests without an RFC.**
|
||||
- Large changes should be discussed beforehand using the [RFC / Change Proposal](#rfcs--change-proposals) process.
|
||||
- Large changes are much harder to review, and are more likely to be declined if maintainers don't have a good idea what you're trying to do in advance.
|
||||
- **Create a new branch on your fork for each pull request.** This allows you to use the same fork to make multiple pull requests at the same time.
|
||||
- **Make your PR diff as small as possible.** Smaller PRs are **much more likely** to be accepted, as they are easier to review.
|
||||
- Avoid moving code around in files if possible.
|
||||
- Don't make random CS changes. This makes the diff noisier and harder to review.
|
||||
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
- **Do not include multiple unrelated changes in one commit.** An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set. See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits. See the [documentation on `git add`](https://git-scm.com/docs/git-add) for information on how to isolate local changes for committing.
|
||||
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
|
||||
- **Do not make large pull requests without an RFC.** Large changes should be discussed beforehand using the [RFC / Change Proposal](#rfcs--change-proposals) process. Large changes are much harder to review and are more likely to be declined if maintainers don't have a good idea what you're trying to do in advance.
|
||||
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit.
|
||||
- **Split unrelated changes into multiple commits.**
|
||||
- An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set.
|
||||
- If you need to use "and" or "multiple changes" in your commit message, the commit probably needs to be split up. There are exceptions, but this is a good rule of thumb.
|
||||
- See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits.
|
||||
- See the [documentation on `git add -i` or `git add -p`](https://git-scm.com/docs/git-add) for information on how to split up local changes for committing.
|
||||
|
||||
|
||||
**Thanks for contributing to PocketMine-MP!**
|
||||
|
52
README.md
52
README.md
@ -4,8 +4,8 @@
|
||||
<img src="https://github.com/pmmp/PocketMine-MP/blob/stable/.github/readme/pocketmine.png" alt="The PocketMine-MP logo" title="PocketMine" loading="eager" />
|
||||
<![endif]-->
|
||||
<picture>
|
||||
<source srcset="https://github.com/pmmp/PocketMine-MP/raw/stable/.github/readme/pocketmine-dark.png" media="(prefers-color-scheme: dark)">
|
||||
<img src="https://github.com/pmmp/PocketMine-MP/raw/stable/.github/readme/pocketmine.png" loading="eager" />
|
||||
<source srcset="https://raw.githubusercontent.com/pmmp/PocketMine-MP/stable/.github/readme/pocketmine-dark-rgb.gif" media="(prefers-color-scheme: dark)">
|
||||
<img src="https://raw.githubusercontent.com/pmmp/PocketMine-MP/stable/.github/readme/pocketmine-rgb.gif" loading="eager" />
|
||||
</picture>
|
||||
</a><br>
|
||||
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
|
||||
@ -20,31 +20,61 @@
|
||||
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver"></a>
|
||||
</p>
|
||||
|
||||
## Getting started
|
||||
## What is this?
|
||||
PocketMine-MP is a highly customisable server software for Minecraft: Bedrock Edition, built from scratch in PHP, with over 10 years of history.
|
||||
|
||||
If you're looking to create a Minecraft: Bedrock server with **custom functionality**, look no further.
|
||||
|
||||
- 🧩 **Powerful plugin API** - extend and customise gameplay as you see fit
|
||||
- 🗺️ **Rich ecosystem** and **large developer community** - find plugins easily and learn to develop your own
|
||||
- 🌐 **Multi-world support** - offer a more varied game experience to players without transferring them to other server nodes
|
||||
- 🏎️ **Performance** - get 100+ players onto one server (depending on hardware and plugins)
|
||||
- ⤴️ **Continuously updated** - new Minecraft versions are usually supported within days
|
||||
|
||||
## :x: PocketMine-MP is NOT a vanilla Minecraft server software.
|
||||
**It is poorly suited to hosting vanilla survival servers.**
|
||||
It doesn't have many features from the vanilla game, such as vanilla world generation, redstone, mob AI, and various other things.
|
||||
|
||||
If you just want to play **vanilla survival multiplayer**, consider using the [official Minecraft: Bedrock server software](https://minecraft.net/download/server/bedrock) instead of PocketMine-MP.
|
||||
|
||||
If that's not an option for you, you may be able to add some of PocketMine-MP's missing features using plugins from [Poggit](https://poggit.pmmp.io/plugins), or write plugins to implement them yourself.
|
||||
|
||||
## Getting Started
|
||||
- [Documentation](http://pmmp.readthedocs.org/)
|
||||
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
|
||||
- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp)
|
||||
- [Plugin repository](https://poggit.pmmp.io/plugins)
|
||||
|
||||
## Discussion/Help
|
||||
- [Forums](https://forums.pmmp.io/)
|
||||
- [Discord](https://discord.gg/bmSAZBG)
|
||||
- [StackOverflow](https://stackoverflow.com/tags/pocketmine)
|
||||
## Community & Support
|
||||
Join our [Discord](https://discord.gg/bmSAZBG) server to chat with other users and developers.
|
||||
|
||||
You can also post questions on [StackOverflow](https://stackoverflow.com/tags/pocketmine) under the tag `pocketmine`.
|
||||
|
||||
## Developing Plugins
|
||||
If you want to write your own plugins, the following resources may be useful.
|
||||
Don't forget you can always ask our community if you need help.
|
||||
|
||||
## For developers
|
||||
* [Building and running from source](BUILDING.md)
|
||||
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
|
||||
* [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release
|
||||
* [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `major-next` branch
|
||||
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
|
||||
## Contributing to PocketMine-MP
|
||||
PocketMine-MP accepts community contributions! The following resources will be useful if you want to contribute to PocketMine-MP.
|
||||
* [Building and running PocketMine-MP from source](BUILDING.md)
|
||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||
|
||||
## Donate
|
||||
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
|
||||
PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.
|
||||
|
||||
You can support development using the following methods:
|
||||
|
||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
|
||||
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
|
||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||
|
||||
Thanks for your support!
|
||||
|
||||
## Licensing information
|
||||
This project is licensed under LGPL-3.0. Please see the [LICENSE](/LICENSE) file for details.
|
||||
|
86
build/dump-version-info.php
Normal file
86
build/dump-version-info.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\VersionInfo;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/*
|
||||
* Dumps version info in a machine-readable format for use in GitHub Actions workflows
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string[]|\Closure[] $options
|
||||
* @phpstan-var array<string, string|\Closure() : string> $options
|
||||
*/
|
||||
$options = [
|
||||
"base_version" => VersionInfo::BASE_VERSION,
|
||||
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"changelog_file_name" => function() : string{
|
||||
$version = VersionInfo::VERSION();
|
||||
$result = $version->getMajor() . "." . $version->getMinor();
|
||||
$suffix = $version->getSuffix();
|
||||
if($suffix !== ""){
|
||||
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
|
||||
fwrite(STDERR, "error: invalid current version suffix \"$suffix\"; aborting" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
$baseSuffix = $matches[1];
|
||||
$result .= "-" . strtolower($baseSuffix);
|
||||
}
|
||||
return $result . ".md";
|
||||
},
|
||||
"changelog_md_header" => fn() : string => str_replace(".", "", VersionInfo::BASE_VERSION),
|
||||
"prerelease" => fn() : bool => VersionInfo::VERSION()->getSuffix() !== "",
|
||||
"channel" => VersionInfo::BUILD_CHANNEL,
|
||||
"suffix_valid" => function() : bool{
|
||||
//TODO: maybe this should be put into its own script?
|
||||
$suffix = VersionInfo::VERSION()->getSuffix();
|
||||
if(VersionInfo::BUILD_CHANNEL === "stable"){
|
||||
//stable builds may not have suffixes
|
||||
return $suffix === "";
|
||||
}
|
||||
if(VersionInfo::BUILD_CHANNEL === "alpha" || VersionInfo::BUILD_CHANNEL === "beta"){
|
||||
$upperChannel = strtoupper(VersionInfo::BUILD_CHANNEL);
|
||||
$upperSuffix = strtoupper($suffix);
|
||||
return str_starts_with($upperSuffix, $upperChannel) && is_numeric(substr($upperSuffix, strlen($upperChannel)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
];
|
||||
if(count($argv) !== 2 || !isset($options[$argv[1]])){
|
||||
fwrite(STDERR, "Please provide an option (one of: " . implode(", ", array_keys($options)) . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$result = $options[$argv[1]];
|
||||
if($result instanceof Closure){
|
||||
$result = $result();
|
||||
}
|
||||
if(is_bool($result)){
|
||||
echo $result ? "true" : "false";
|
||||
}else{
|
||||
echo $result;
|
||||
}
|
133
build/generate-biome-ids.php
Normal file
133
build/generate-biome-ids.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\generate_biome_ids;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use function asort;
|
||||
use function dirname;
|
||||
use function fclose;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
const HEADER = <<<'HEADER'
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
HEADER;
|
||||
|
||||
/** @return resource */
|
||||
function safe_fopen(string $file, string $flags){
|
||||
$result = fopen($file, $flags);
|
||||
if($result === false){
|
||||
throw new \RuntimeException("Failed to open file");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function make_const_name(string $name) : string{
|
||||
return strtoupper(str_replace(['.', 'minecraft:'], ['_', ''], $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $map
|
||||
* @phpstan-param array<string, int> $map
|
||||
*/
|
||||
function generate(array $map, string $outputFile) : void{
|
||||
$file = safe_fopen($outputFile, 'wb');
|
||||
fwrite($file, HEADER);
|
||||
fwrite($file, <<<'CLASSHEADER'
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
final class BiomeIds{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
CLASSHEADER
|
||||
);
|
||||
$list = $map;
|
||||
asort($list, SORT_NUMERIC);
|
||||
$lastId = -1;
|
||||
foreach(Utils::stringifyKeys($list) as $name => $id){
|
||||
if($name === ""){
|
||||
continue;
|
||||
}
|
||||
if($id !== $lastId + 1){
|
||||
fwrite($file, "\n");
|
||||
}
|
||||
$lastId = $id;
|
||||
fwrite($file, "\tpublic const " . make_const_name($name) . ' = ' . $id . ';' . "\n");
|
||||
}
|
||||
fwrite($file, "}\n");
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
$ids = json_decode(Filesystem::fileGetContents(BedrockDataFiles::BIOME_ID_MAP_JSON), true);
|
||||
if(!is_array($ids)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected array for root JSON object");
|
||||
}
|
||||
$cleanedIds = [];
|
||||
foreach($ids as $name => $id){
|
||||
if(!is_string($name) || !is_int($id)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected string => int map");
|
||||
}
|
||||
$cleanedIds[$name] = $id;
|
||||
}
|
||||
generate($cleanedIds, dirname(__DIR__) . '/src/data/bedrock/BiomeIds.php');
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
@ -44,6 +44,7 @@ use function fwrite;
|
||||
use function is_string;
|
||||
use function ksort;
|
||||
use function mb_strtoupper;
|
||||
use function preg_replace;
|
||||
use function sort;
|
||||
use function strrpos;
|
||||
use function strtoupper;
|
||||
@ -101,6 +102,25 @@ function generateClassHeader(string $className) : string{
|
||||
return <<<HEADER
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace $namespace;
|
||||
@ -138,7 +158,7 @@ function generateBlockStateNames(BlockPaletteReport $data) : void{
|
||||
|
||||
fwrite($output, generateClassHeader(BlockStateNames::class));
|
||||
foreach(Utils::stringifyKeys($data->seenStateValues) as $state => $values){
|
||||
$constName = mb_strtoupper($state, 'US-ASCII');
|
||||
$constName = mb_strtoupper(preg_replace("/^minecraft:/", "mc_", $state) ?? throw new AssumptionFailedError("This regex is not invalid"), 'US-ASCII');
|
||||
fwrite($output, "\tpublic const $constName = \"$state\";\n");
|
||||
}
|
||||
|
||||
@ -158,7 +178,7 @@ function generateBlockStringValues(BlockPaletteReport $data) : void{
|
||||
continue;
|
||||
}
|
||||
$anyWritten = true;
|
||||
$constName = mb_strtoupper($stateName . "_" . $value, 'US-ASCII');
|
||||
$constName = mb_strtoupper(preg_replace("/^minecraft:/", "mc_", $stateName) . "_" . $value, 'US-ASCII');
|
||||
fwrite($output, "\tpublic const $constName = \"$value\";\n");
|
||||
}
|
||||
if($anyWritten){
|
||||
|
@ -21,24 +21,28 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\VersionInfo;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 6){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
|
||||
if(count($argv) !== 7){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID> <PHP binary download URL>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
|
||||
"base_version" => \pocketmine\VersionInfo::BASE_VERSION,
|
||||
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION), //deprecated
|
||||
"base_version" => VersionInfo::BASE_VERSION,
|
||||
"build" => (int) $argv[4],
|
||||
"is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"channel" => \pocketmine\VersionInfo::BUILD_CHANNEL,
|
||||
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"channel" => VersionInfo::BUILD_CHANNEL,
|
||||
"git_commit" => $argv[1],
|
||||
"mcpe_version" => \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"date" => time(), //TODO: maybe we should embed this in VersionInfo?
|
||||
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
|
||||
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
|
||||
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
|
||||
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
|
||||
"php_download_url" => $argv[6],
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\generate_item_serializer_ids;
|
||||
|
||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\network\mcpe\convert\ItemTypeDictionaryFromDataHelper;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
@ -45,10 +46,10 @@ function constifyMcId(string $id) : string{
|
||||
return strtoupper(explode(":", $id, 2)[1]);
|
||||
}
|
||||
|
||||
function generateItemIds(ItemTypeDictionary $dictionary) : void{
|
||||
function generateItemIds(ItemTypeDictionary $dictionary, BlockItemIdMap $blockItemIdMap) : void{
|
||||
$ids = [];
|
||||
foreach($dictionary->getEntries() as $entry){
|
||||
if($entry->getNumericId() < 256){ //blockitems are serialized via BlockStateSerializer
|
||||
if($entry->getStringId() === "minecraft:air" || $blockItemIdMap->lookupBlockId($entry->getStringId()) !== null){ //blockitems are serialized via BlockStateSerializer
|
||||
continue;
|
||||
}
|
||||
$ids[$entry->getStringId()] = $entry->getStringId();
|
||||
@ -60,6 +61,25 @@ function generateItemIds(ItemTypeDictionary $dictionary) : void{
|
||||
fwrite($file, <<<'HEADER'
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\item;
|
||||
@ -92,6 +112,7 @@ if($raw === false){
|
||||
}
|
||||
|
||||
$dictionary = ItemTypeDictionaryFromDataHelper::loadFromString($raw);
|
||||
generateItemIds($dictionary);
|
||||
$blockItemIdMap = BlockItemIdMap::getInstance();
|
||||
generateItemIds($dictionary, $blockItemIdMap);
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
||||
|
120
build/generate-pocketmine-yml-property-consts.php
Normal file
120
build/generate-pocketmine-yml-property-consts.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$defaultConfig = yaml_parse(Filesystem::fileGetContents(dirname(__DIR__) . '/resources/pocketmine.yml'));
|
||||
|
||||
if(!is_array($defaultConfig)){
|
||||
fwrite(STDERR, "Invalid default pocketmine.yml\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$constants = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $properties
|
||||
* @param string[] $constants
|
||||
* @phpstan-param array<string, string> $constants
|
||||
* @phpstan-param-out array<string, string> $constants
|
||||
*/
|
||||
function collectProperties(string $prefix, array $properties, array &$constants) : void{
|
||||
foreach($properties as $propertyName => $property){
|
||||
$fullPropertyName = ($prefix !== "" ? $prefix . "." : "") . $propertyName;
|
||||
|
||||
$constName = str_replace([".", "-"], "_", strtoupper($fullPropertyName));
|
||||
$constants[$constName] = $fullPropertyName;
|
||||
|
||||
if(is_array($property)){
|
||||
collectProperties($fullPropertyName, $property, $constants);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectProperties("", $defaultConfig, $constants);
|
||||
ksort($constants, SORT_STRING);
|
||||
|
||||
$file = fopen(dirname(__DIR__) . '/src/YmlServerProperties.php', 'wb');
|
||||
if($file === false){
|
||||
fwrite(STDERR, "Failed to open output file\n");
|
||||
exit(1);
|
||||
}
|
||||
fwrite($file, "<?php\n");
|
||||
fwrite($file, <<<'HEADER'
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
HEADER
|
||||
);
|
||||
fwrite($file, "declare(strict_types=1);\n\n");
|
||||
fwrite($file, "namespace pocketmine;\n\n");
|
||||
|
||||
fwrite($file, <<<'DOC'
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in pocketmine.yml.
|
||||
* This is generated by build/generate-pocketmine-yml-property-consts.php.
|
||||
* Do not edit this file manually.
|
||||
*/
|
||||
|
||||
DOC
|
||||
);
|
||||
fwrite($file, "final class YmlServerProperties{\n");
|
||||
fwrite($file, <<<'CONSTRUCTOR'
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
CONSTRUCTOR
|
||||
);
|
||||
foreach(Utils::stringifyKeys($constants) as $constName => $propertyName){
|
||||
fwrite($file, "\tpublic const $constName = '$propertyName';\n");
|
||||
}
|
||||
fwrite($file, "}\n");
|
||||
|
||||
fclose($file);
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
@ -1,263 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\generate_runtime_enum_serializers;
|
||||
|
||||
use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\CopperOxidation;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DirtType;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\FroglightType;
|
||||
use pocketmine\block\utils\LeverFacing;
|
||||
use pocketmine\block\utils\MushroomBlockType;
|
||||
use pocketmine\block\utils\SkullType;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\item\MedicineType;
|
||||
use pocketmine\item\PotionType;
|
||||
use pocketmine\item\SuspiciousStewType;
|
||||
use function array_key_first;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function file_put_contents;
|
||||
use function implode;
|
||||
use function ksort;
|
||||
use function lcfirst;
|
||||
use function log;
|
||||
use function ob_get_clean;
|
||||
use function ob_start;
|
||||
use const SORT_STRING;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @param string[] $memberNames
|
||||
* @phpstan-param list<string> $memberNames
|
||||
*
|
||||
* @return string[]
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
function buildWriterFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string $functionName) : array{
|
||||
$bits = getBitsRequired($memberNames);
|
||||
$lines = [];
|
||||
|
||||
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
|
||||
$lines[] = "\t\$this->writeInt($bits, match(\$value){";
|
||||
|
||||
foreach($memberNames as $key => $memberName){
|
||||
$lines[] = "\t\t$memberName => $key,";
|
||||
}
|
||||
$lines[] = "\t\tdefault => throw new \pocketmine\utils\AssumptionFailedError(\"All $virtualTypeName cases should be covered\")";
|
||||
$lines[] = "\t});";
|
||||
$lines[] = "}";
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $memberNames
|
||||
* @phpstan-param list<string> $memberNames
|
||||
*
|
||||
* @return string[]
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
function buildReaderFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string $functionName) : array{
|
||||
$bits = getBitsRequired($memberNames);
|
||||
$lines = [];
|
||||
|
||||
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
|
||||
$lines[] = "\t\$value = match(\$this->readInt($bits)){";
|
||||
|
||||
foreach($memberNames as $key => $memberName){
|
||||
$lines[] = "\t\t$key => $memberName,";
|
||||
}
|
||||
$lines[] = "\t\tdefault => throw new InvalidSerializedRuntimeDataException(\"Invalid serialized value for $virtualTypeName\")";
|
||||
$lines[] = "\t};";
|
||||
$lines[] = "}";
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
function buildInterfaceFunc(string $nativeTypeName, string $functionName) : string{
|
||||
return "public function $functionName(\\$nativeTypeName &\$value) : void;";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $memberNames
|
||||
* @phpstan-param list<string> $memberNames
|
||||
*
|
||||
* @return string[]
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
function buildSizeCalculationFunc(string $nativeTypeName, string $functionName, array $memberNames) : array{
|
||||
$lines = [];
|
||||
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
|
||||
$lines[] = "\t\$this->addBits(" . getBitsRequired($memberNames) . ");";
|
||||
$lines[] = "}";
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $members
|
||||
*/
|
||||
function getBitsRequired(array $members) : int{
|
||||
return (int) ceil(log(count($members), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $members
|
||||
* @phpstan-param array<string, object> $members
|
||||
*
|
||||
* @return string[]
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
function stringifyEnumMembers(array $members, string $enumClass) : array{
|
||||
ksort($members, SORT_STRING);
|
||||
return array_map(fn(string $enumCaseName) => "\\$enumClass::$enumCaseName()", array_keys($members));
|
||||
}
|
||||
|
||||
$enumsUsed = [
|
||||
BellAttachmentType::getAll(),
|
||||
CopperOxidation::getAll(),
|
||||
CoralType::getAll(),
|
||||
DirtType::getAll(),
|
||||
DyeColor::getAll(),
|
||||
FroglightType::getAll(),
|
||||
LeverFacing::getAll(),
|
||||
MedicineType::getAll(),
|
||||
MushroomBlockType::getAll(),
|
||||
SkullType::getAll(),
|
||||
SlabType::getAll(),
|
||||
SuspiciousStewType::getAll(),
|
||||
PotionType::getAll()
|
||||
];
|
||||
|
||||
$readerFuncs = [
|
||||
"" => [
|
||||
"abstract protected function readInt(int \$bits) : int;"
|
||||
]
|
||||
];
|
||||
$writerFuncs = [
|
||||
"" => [
|
||||
"abstract protected function writeInt(int \$bits, int \$value) : void;"
|
||||
]
|
||||
];
|
||||
$interfaceFuncs = [];
|
||||
$sizeCalculationFuncs = [
|
||||
"" => [
|
||||
"abstract protected function addBits(int \$bits) : void;"
|
||||
]
|
||||
];
|
||||
|
||||
foreach($enumsUsed as $enumMembers){
|
||||
if(count($enumMembers) === 0){
|
||||
throw new \InvalidArgumentException("Enum members cannot be empty");
|
||||
}
|
||||
$reflect = new \ReflectionClass($enumMembers[array_key_first($enumMembers)]);
|
||||
$virtualTypeName = $reflect->getShortName();
|
||||
$nativeTypeName = $reflect->getName();
|
||||
$functionName = lcfirst($virtualTypeName);
|
||||
|
||||
$stringifiedMembers = stringifyEnumMembers($enumMembers, $nativeTypeName);
|
||||
$writerFuncs[$functionName] = buildWriterFunc(
|
||||
$virtualTypeName,
|
||||
$nativeTypeName,
|
||||
$stringifiedMembers,
|
||||
$functionName
|
||||
);
|
||||
$readerFuncs[$functionName] = buildReaderFunc(
|
||||
$virtualTypeName,
|
||||
$nativeTypeName,
|
||||
$stringifiedMembers,
|
||||
$functionName
|
||||
);
|
||||
$interfaceFuncs[$functionName] = [buildInterfaceFunc(
|
||||
$nativeTypeName,
|
||||
$functionName
|
||||
)];
|
||||
$sizeCalculationFuncs[$functionName] = buildSizeCalculationFunc(
|
||||
$nativeTypeName,
|
||||
$functionName,
|
||||
$stringifiedMembers
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[][] $functions
|
||||
* @phpstan-param array<string, list<string>> $functions
|
||||
*/
|
||||
function printFunctions(array $functions, string $className, string $classType) : void{
|
||||
ksort($functions, SORT_STRING);
|
||||
|
||||
ob_start();
|
||||
|
||||
echo <<<'HEADER'
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\runtime;
|
||||
|
||||
/**
|
||||
* This class is auto-generated. Do not edit it manually.
|
||||
* @see build/generate-runtime-enum-serializers.php
|
||||
*/
|
||||
|
||||
HEADER;
|
||||
|
||||
echo "$classType $className{\n\n";
|
||||
echo implode("\n\n", array_map(fn(array $functionLines) => "\t" . implode("\n\t", $functionLines), $functions));
|
||||
echo "\n\n}\n";
|
||||
|
||||
file_put_contents(dirname(__DIR__) . '/src/data/runtime/' . $className . '.php', ob_get_clean());
|
||||
}
|
||||
|
||||
printFunctions($writerFuncs, "RuntimeEnumSerializerTrait", "trait");
|
||||
printFunctions($readerFuncs, "RuntimeEnumDeserializerTrait", "trait");
|
||||
printFunctions($interfaceFuncs, "RuntimeEnumDescriber", "interface");
|
||||
printFunctions($sizeCalculationFuncs, "RuntimeEnumSizeCalculatorTrait", "trait");
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
@ -86,7 +86,8 @@ function systemWrapper(string $command, string $errorMessage) : void{
|
||||
|
||||
function main() : void{
|
||||
$filteredOpts = [];
|
||||
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
|
||||
$postCommitOnly = false;
|
||||
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help", "post"])) as $optName => $optValue){
|
||||
if($optName === "help"){
|
||||
fwrite(STDOUT, "Options:\n");
|
||||
|
||||
@ -96,6 +97,10 @@ function main() : void{
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
if($optName === "post"){
|
||||
$postCommitOnly = true;
|
||||
continue;
|
||||
}
|
||||
if(!is_string($optValue)){
|
||||
fwrite(STDERR, "--$optName expects exactly 1 value\n");
|
||||
exit(1);
|
||||
@ -141,20 +146,25 @@ function main() : void{
|
||||
$channel ??= "stable";
|
||||
}
|
||||
|
||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||
echo "$currentVer will be published on release channel \"$channel\".\n";
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
|
||||
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
|
||||
if($result === 0){
|
||||
echo "error: no changelog changes detected; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
|
||||
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
|
||||
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
|
||||
|
||||
if($postCommitOnly){
|
||||
echo "Skipping release commit & tag. Bumping to next version $nextVer directly.\n";
|
||||
}else{
|
||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||
echo "$currentVer will be published on release channel \"$channel\".\n";
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
|
||||
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
|
||||
if($result === 0){
|
||||
echo "error: no changelog changes detected; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
|
||||
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
|
||||
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
|
||||
}
|
||||
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
|
||||
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
|
||||
|
Submodule build/php updated: f860ade30a...084822aa9e
168
build/server-phar-stub.php
Normal file
168
build/server-phar-stub.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\server_phar_stub;
|
||||
|
||||
use function clearstatcache;
|
||||
use function copy;
|
||||
use function fclose;
|
||||
use function fflush;
|
||||
use function flock;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function getmypid;
|
||||
use function hrtime;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function mkdir;
|
||||
use function number_format;
|
||||
use function str_replace;
|
||||
use function stream_get_contents;
|
||||
use function sys_get_temp_dir;
|
||||
use function tempnam;
|
||||
use function unlink;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const LOCK_EX;
|
||||
use const LOCK_NB;
|
||||
use const LOCK_UN;
|
||||
|
||||
/**
|
||||
* Finds the appropriate tmp directory to store the decompressed phar cache, accounting for potential file name
|
||||
* collisions.
|
||||
*/
|
||||
function preparePharCacheDirectory() : string{
|
||||
clearstatcache();
|
||||
|
||||
$i = 0;
|
||||
do{
|
||||
$tmpPath = sys_get_temp_dir() . '/PocketMine-MP-phar-cache.' . $i;
|
||||
$i++;
|
||||
}while(is_file($tmpPath));
|
||||
if(!@mkdir($tmpPath) && !is_dir($tmpPath)){
|
||||
throw new \RuntimeException("Failed to create temporary directory $tmpPath. Please ensure the disk has enough space and that the current user has permission to write to this location.");
|
||||
}
|
||||
|
||||
return $tmpPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes caches left behind by previous server instances.
|
||||
* This ensures that the tmp directory doesn't get flooded by servers crashing in restart loops.
|
||||
*/
|
||||
function cleanupPharCache(string $tmpPath) : void{
|
||||
clearstatcache();
|
||||
|
||||
/** @var string[] $matches */
|
||||
foreach(new \RegexIterator(
|
||||
new \FilesystemIterator(
|
||||
$tmpPath,
|
||||
\FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS
|
||||
),
|
||||
'/(.+)\.lock$/',
|
||||
\RegexIterator::GET_MATCH
|
||||
) as $matches){
|
||||
$lockFilePath = $matches[0];
|
||||
$baseTmpPath = $matches[1];
|
||||
|
||||
$file = @fopen($lockFilePath, "rb");
|
||||
if($file === false){
|
||||
//another process probably deleted the lock file already
|
||||
continue;
|
||||
}
|
||||
|
||||
if(flock($file, LOCK_EX | LOCK_NB)){
|
||||
//this tmpfile is no longer in use
|
||||
flock($file, LOCK_UN);
|
||||
fclose($file);
|
||||
|
||||
unlink($lockFilePath);
|
||||
unlink($baseTmpPath . ".tar");
|
||||
unlink($baseTmpPath);
|
||||
echo "Deleted stale phar cache at $baseTmpPath\n";
|
||||
}else{
|
||||
$pid = stream_get_contents($file);
|
||||
fclose($file);
|
||||
|
||||
echo "Phar cache at $baseTmpPath is still in use by PID $pid\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertPharToTar(string $tmpName, string $pharPath) : string{
|
||||
$tmpPharPath = $tmpName . ".phar";
|
||||
copy($pharPath, $tmpPharPath);
|
||||
|
||||
$phar = new \Phar($tmpPharPath);
|
||||
//phar requires phar.readonly=0, and zip doesn't support disabling compression - tar is the only viable option
|
||||
//we don't need phar anyway since we don't need to directly execute the file, only require files from inside it
|
||||
$phar->convertToData(\Phar::TAR, \Phar::NONE);
|
||||
unset($phar);
|
||||
\Phar::unlinkArchive($tmpPharPath);
|
||||
|
||||
return $tmpName . ".tar";
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a phar tmp cache to prevent it from being deleted by other server instances.
|
||||
* This code looks similar to Filesystem::createLockFile(), but we can't use that because it's inside the compressed
|
||||
* phar.
|
||||
*/
|
||||
function lockPharCache(string $lockFilePath) : void{
|
||||
//this static variable will keep the file(s) locked until the process ends
|
||||
static $lockFiles = [];
|
||||
|
||||
$lockFile = fopen($lockFilePath, "wb");
|
||||
if($lockFile === false){
|
||||
throw new \RuntimeException("Failed to open temporary file");
|
||||
}
|
||||
flock($lockFile, LOCK_EX); //this tells other server instances not to delete this cache file
|
||||
fwrite($lockFile, (string) getmypid()); //maybe useful for debugging
|
||||
fflush($lockFile);
|
||||
$lockFiles[$lockFilePath] = $lockFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a decompressed .tar of PocketMine-MP.phar in the system temp directory for loading code from.
|
||||
*
|
||||
* @return string path to the temporary decompressed phar (actually a .tar)
|
||||
*/
|
||||
function preparePharCache(string $tmpPath, string $pharPath) : string{
|
||||
clearstatcache();
|
||||
|
||||
$tmpName = tempnam($tmpPath, "PMMP");
|
||||
if($tmpName === false){
|
||||
throw new \RuntimeException("Failed to create temporary file");
|
||||
}
|
||||
|
||||
lockPharCache($tmpName . ".lock");
|
||||
return convertPharToTar($tmpName, $pharPath);
|
||||
}
|
||||
|
||||
$tmpDir = preparePharCacheDirectory();
|
||||
cleanupPharCache($tmpDir);
|
||||
echo "Preparing PocketMine-MP.phar decompressed cache...\n";
|
||||
$start = hrtime(true);
|
||||
$cacheName = preparePharCache($tmpDir, __FILE__);
|
||||
echo "Cache ready at $cacheName in " . number_format((hrtime(true) - $start) / 1e9, 2) . "s\n";
|
||||
|
||||
require 'phar://' . str_replace(DIRECTORY_SEPARATOR, '/', $cacheName) . '/src/PocketMine.php';
|
@ -23,7 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\server_phar;
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Git;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function dirname;
|
||||
@ -32,6 +34,7 @@ use function getcwd;
|
||||
use function getopt;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function is_string;
|
||||
use function microtime;
|
||||
use function preg_quote;
|
||||
use function realpath;
|
||||
@ -147,8 +150,17 @@ function main() : void{
|
||||
}else{
|
||||
$build = 0;
|
||||
}
|
||||
if(isset($opts["out"])){
|
||||
if(!is_string($opts["out"])){
|
||||
echo "--out cannot be specified multiple times" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$pharPath = $opts["out"];
|
||||
}else{
|
||||
$pharPath = getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar";
|
||||
}
|
||||
foreach(buildPhar(
|
||||
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
|
||||
$pharPath,
|
||||
dirname(__DIR__) . DIRECTORY_SEPARATOR,
|
||||
[
|
||||
'resources',
|
||||
@ -159,21 +171,7 @@ function main() : void{
|
||||
'git' => $gitHash,
|
||||
'build' => $build
|
||||
],
|
||||
<<<'STUB'
|
||||
<?php
|
||||
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
if(!is_readable($tmpDir) or !is_writable($tmpDir)){
|
||||
echo "ERROR: tmpdir $tmpDir is not accessible." . PHP_EOL;
|
||||
echo "Check that the directory exists, and that the current user has read/write permissions for it." . PHP_EOL;
|
||||
echo "Alternatively, set 'sys_temp_dir' to a different directory in your php.ini file." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require("phar://" . __FILE__ . "/src/PocketMine.php");
|
||||
__HALT_COMPILER();
|
||||
STUB
|
||||
,
|
||||
Filesystem::fileGetContents(Path::join(__DIR__, 'server-phar-stub.php')) . "\n__HALT_COMPILER();",
|
||||
\Phar::SHA1,
|
||||
\Phar::GZ
|
||||
) as $line){
|
||||
|
@ -71,3 +71,9 @@ Released 6th May 2023.
|
||||
## Fixes
|
||||
- Fixed players being forced into flight mode in every game mode.
|
||||
- Moral of the story: do not assume anything in Mojang internals does what its name suggests...
|
||||
|
||||
# 4.20.5
|
||||
Released 30th May 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).
|
||||
|
@ -69,3 +69,9 @@ Released 17th May 2023.
|
||||
- Registered but ineligible ticking chunks are no longer rechecked every tick.
|
||||
- This was causing wasted cycles during async worker backlog.
|
||||
- The internal system must call `markTickingChunkForRecheck()` whenever a ticking chunk's eligibility for ticking has potentially changed, rather than just when it has changed from a yes to a no.
|
||||
|
||||
# 4.21.1
|
||||
Released 30th May 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).
|
||||
|
58
changelogs/4.22.md
Normal file
58
changelogs/4.22.md
Normal file
@ -0,0 +1,58 @@
|
||||
# 4.22.0
|
||||
Released 7th June 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.0**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.0.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Interim releases
|
||||
If you're upgrading from 4.20.x directly to 4.22.x, please also read the following changelogs, as the interim releases contain important changes:
|
||||
- [4.21.0](https://github.com/pmmp/PocketMine-MP/blob/4.22.0/changelogs/4.21.md#4210) - PHP 8.1 minimum version, minor performance improvements
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.0.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Removed deprecated `ReflectionProperty::setAccessible()` calls.
|
||||
- Fixed jukebox music not stopping when destroyed by an explosion.
|
||||
|
||||
# 4.22.1
|
||||
Released 9th June 2023.
|
||||
|
||||
## Fixes
|
||||
- Replaced workaround for an old teleporting client bug:
|
||||
- This workaround broke due to an additional client bug introduced by 1.20, causing players to become frozen to observers when teleported.
|
||||
- The original client bug has still not been fixed, meaning a new workaround was needed, but no perfect solution could be found.
|
||||
- The new workaround involves broadcasting teleport movements as regular movements, which causes unwanted interpolation between the old and new positions, but otherwise works correctly. This solution is not ideal, but it is the best we can do for now.
|
||||
- See issues [#4394](https://github.com/pmmp/PocketMine-MP/issues/4394) and [#5810](https://github.com/pmmp/PocketMine-MP/issues/5810) for more details.
|
||||
|
||||
# 4.22.2
|
||||
Released 1st July 2023.
|
||||
|
||||
## Changes
|
||||
- Added obsoletion warnings to the server log at the end of the startup sequence.
|
||||
|
||||
## Fixes
|
||||
- Fixed players being disconnected en masse with "Not authenticated" messages.
|
||||
- This occurred due to a check intended to disable the old authentication key after July 1st.
|
||||
- We expected that the new key would have been deployed by Mojang by now, but it seems like that has not yet happened.
|
||||
- Due to the lack of a hard date for the key changeover, we guessed that July 1st would be a safe bet, but this appears to have backfired.
|
||||
- This version will accept both old and new keys indefinitely.
|
||||
- A security release will be published to remove the old key after the transition occurs.
|
||||
|
||||
# 4.22.3
|
||||
Released 11th July 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed mishandling of NBT leading to a server crash when editing signs.
|
||||
- Fixed an edge case crash that could occur in `AsyncTask->__destruct()` when thread-local storage referenced other `AsyncTask` objects.
|
||||
|
||||
## Internals
|
||||
- Added a concurrency lock to prevent the `update-updater-api` GitHub Action from running for multiple releases at the same time (which would have caused one of them to fail due to git conflicts).
|
68
changelogs/4.23.md
Normal file
68
changelogs/4.23.md
Normal file
@ -0,0 +1,68 @@
|
||||
# 4.23.0
|
||||
Released 12th July 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.10.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.10.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed Docker image build failure due to outdated `build/php` submodule.
|
||||
|
||||
# 4.23.1
|
||||
Released 14th July 2023.
|
||||
|
||||
## Fixes
|
||||
- Hardened validation of JWT signing keys in `LoginPacket`.
|
||||
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).
|
||||
|
||||
# 4.23.2
|
||||
Released 18th July 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed login errors due to a new `sandboxId` field appearing in the Xbox Live authentication data in `LoginPacket`. All clients, regardless of version, are affected by this change.
|
||||
|
||||
# 4.23.3
|
||||
Released 24th July 2023.
|
||||
|
||||
## Documentation
|
||||
- Fixed typo in `ChunkSelector::selectChunks()` documentation.
|
||||
|
||||
## Fixes
|
||||
- Fixed the server not stopping properly during crash conditions on *nix platforms.
|
||||
- Fixed `HORSE_EQUIP` and `SMITHING_TABLE_TEMPLATE` container UI types not being handled by `ItemStackContainerIdTranslator`. This bug prevented plugins from implementing missing inventory types.
|
||||
- Player emotes no longer broadcast messages to other players. This was unintended behaviour caused by a client-side behavioural change.
|
||||
- Shulker boxes no longer support the placement of torches or other similar blocks.
|
||||
- Fire can now be placed on upper slabs and the top of upside-down stairs.
|
||||
|
||||
# 4.23.4
|
||||
Released 1st August 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed exponentially increasing lag when many hundreds of non-mergeable dropped items occupied the same space. This disproportionately affected SkyBlock servers due to large cactus farms using water to collect items together.
|
||||
|
||||
# 4.23.5
|
||||
Released 9th August 2023.
|
||||
|
||||
## General
|
||||
- Updated translation data to [pmmp/Language 2.19.6](https://github.com/pmmp/Language/releases/tag/2.19.6).
|
||||
|
||||
## Fixes
|
||||
- Fixed `PluginBase->saveResource()` leaking file resources when the data file already exists in the plugin's data folder. This bug existed since 2014 and was only discovered recently.
|
||||
- Fixed coral blocks becoming dead after calling `getDropsForCompatibleTool()` on them.
|
||||
- Fixed `BlockDeathEvent->getOldState()` returning a block which is already dead.
|
||||
|
||||
# 4.23.6
|
||||
Released 21st August 2023.
|
||||
|
||||
## Fixes
|
||||
- Added a workaround for armor and other inventories not working correctly after inventory sync. This is caused by a client bug.
|
17
changelogs/4.24.md
Normal file
17
changelogs/4.24.md
Normal file
@ -0,0 +1,17 @@
|
||||
# 4.24.0
|
||||
Released 20th September 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.30**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.30.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.30.
|
||||
- Removed support for older versions.
|
||||
- Updated 4.x obsoletion message.
|
16
changelogs/4.25.md
Normal file
16
changelogs/4.25.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 4.25.0
|
||||
Released 26th October 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.40**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.40.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.40.
|
||||
- Removed support for older versions.
|
16
changelogs/4.26.md
Normal file
16
changelogs/4.26.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 4.26.0
|
||||
Released 6th December 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.50**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.50.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.50.
|
||||
- Removed support for older versions.
|
@ -194,3 +194,22 @@ Released 17th May 2023.
|
||||
- `RuntimeBlockMapping` has been renamed to `BlockTranslator`.
|
||||
- Singletons in the `pocketmine\network\mcpe\convert` package have been centralized under `TypeConverter`. In the future, this will be injected where needed, allowing different converters to be used for different sessions (useful for multiversion).
|
||||
- Overriding of serializers and deserializers of items and blocks is now consistently disallowed. Due to the lack of a good reason to allow overriding built-in blocks and items, this is no longer allowed.
|
||||
|
||||
# 5.0.0-BETA4
|
||||
Released 23rd May 2023.
|
||||
|
||||
## General
|
||||
- [`ext-pmmpthread` version 6.0.0](https://github.com/pmmp/ext-pmmpthread/releases/6.0.0) (renamed from `ext-pthreads`) is now required. This version has API changes compared to pthreads v5. Please read the linked changelog for details.
|
||||
- [`pocketmine/snooze` version 0.5.0](https://github.com/pmmp/Snooze/releases/0.5.0) is now required.
|
||||
- `pocketmine/classloader` and `pocketmine/log-pthreads` packages have been removed. The relevant classes from these packages are now included in-house in the `pocketmine/thread` namespace.
|
||||
- `BaseClassLoader` is replaced with `pocketmine\thread\ThreadSafeClassLoader`
|
||||
- `ThreadedLogger` is replaced by `pocketmine\thread\ThreadSafeLogger`
|
||||
- `AttachableThreadedLogger` is replaced by `pocketmine\thread\AttachableThreadSafeLogger`
|
||||
- `ThreadedLoggerAttachment` is replaced by `pocketmine\thread\ThreadSafeLoggerAttachment`
|
||||
|
||||
## Fixes
|
||||
- Fixed crash on unknown blocks due to late initialization of properties in `UnknownBlock`.
|
||||
|
||||
## API changes
|
||||
### `pocketmine\scheduler`
|
||||
- `AsyncTask->setResult()` now works with thread-safe objects. This was previously not possible due to limitations in the `pthreads` extension.
|
||||
|
791
changelogs/5.0.md
Normal file
791
changelogs/5.0.md
Normal file
@ -0,0 +1,791 @@
|
||||
# 5.0.0
|
||||
Released 1st June 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.19.80**
|
||||
|
||||
5.0.0 is a major feature update to PocketMine-MP, including support for Bedrock worlds from 1.13 onwards, a large array of new blocks and items, and various changes to the plugin API.
|
||||
|
||||
It is **not** compatible with plugins written for 4.x.y, and plugins may require code changes to work with it.
|
||||
|
||||
**As this changelog is quite large, its accuracy and completeness cannot be guaranteed.**
|
||||
Make sure you're looking at the [latest revision](https://github.com/pmmp/PocketMine-MP/blob/stable/changelogs/5.0.md), as it may be amended after release.
|
||||
|
||||
## Core
|
||||
- Worlds are now saved according to the Bedrock 1.19.80 format.
|
||||
- Worlds generated by Bedrock from 1.13.0 and up are now supported (previously, only worlds up to 1.12 were supported).
|
||||
- `/particle` now accepts strings for particle data instead of integers.
|
||||
- `/particle` no longer accepts integers for block or item IDs.
|
||||
- The usage of `blockcrack`, `iconcrack` and `blockdust` particle types in `/particle` now follows the same pattern as
|
||||
other particle types, with the data for each being passed in the `data` parameter instead of being baked into the
|
||||
particle name.
|
||||
- Commands are now enabled by default in worlds exported from PocketMine-MP to Bedrock.
|
||||
|
||||
## Build system
|
||||
- `build/generate-block-serializer-consts.php` has been added to generate `BlockTypeNames`, `BlockStateNames` and `BlockStateStringValues` in the `pocketmine\data\bedrock\block` package.
|
||||
- `build/generate-item-type-names.php` has been added to generate `ItemTypeNames` in the `pocketmine\data\bedrock\item` package.
|
||||
- `build/generate-runtime-enum-serializers.php` has been added to generate `RuntimeEnumSerializer`, `RuntimeEnumSerializerTrait`, and `RuntimeEnumSizeCalculatorTrait` in `pocketmine\data\runtime` package.
|
||||
|
||||
## Localization
|
||||
- Localized disconnect messages are now used in the following cases:
|
||||
- Server full
|
||||
- Player not on the server whitelist
|
||||
- Player on the server ban list
|
||||
- Invalid skin
|
||||
- Invalid username
|
||||
- Kicked using `/kick`
|
||||
- Banned using `/ban`
|
||||
- Failure to find a safe spawn position
|
||||
- Session open, session close and session player name discovery messages are now localized.
|
||||
- All permissions now have localized descriptions. These are not currently used by PocketMine-MP, but may be useful for plugins.
|
||||
|
||||
## Performance
|
||||
- Improved performance of dropping block inventory contents when the block is destroyed.
|
||||
- Improved light propagation performance by 10-15%.
|
||||
- [`ext-pmmpthread` version 6.0.0](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.0.0) is now used, featuring significant performance improvements for thread-safe objects and various threading use-cases.
|
||||
|
||||
## Tools
|
||||
- The following tool scripts have been added:
|
||||
- `generate-block-palette-spec.php` - generates a JSON file with a readable overview of blocks, their state
|
||||
properties, and their possible values
|
||||
- `generate-blockstate-upgrade-schema.php` - generates JSON blockstate upgrade schemas like those found
|
||||
in [BedrockBlockUpgradeSchema](https://github.com/pmmp/BedrockBlockUpgradeSchema)
|
||||
- `generate-item-upgrade-schema.php` - generates JSON item ID/meta upgrade schemas like those found
|
||||
in [BedrockItemUpgradeSchema](https://github.com/pmmp/BedrockItemUpgradeSchema)
|
||||
- `generate-bedrock-data-from-packets.php` - generates various files for [BedrockData](https://github.com/pmmp/BedrockData)
|
||||
- This script accepts a txt file containing base64-encoded packet dumps.
|
||||
- This script has been in use for several years, but has only now been open-sourced.
|
||||
- It's used to generate data such as crafting recipes, creative inventory data, and various other blobs of data needed to support the current version of Minecraft: Bedrock Edition.
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Added the following new blocks:
|
||||
- Amethyst Block
|
||||
- Ancient Debris
|
||||
- Azalea Leaves
|
||||
- Basalt
|
||||
- Blackstone blocks, slabs, stairs, and walls
|
||||
- Cakes with Candle & Dyed Candle
|
||||
- Calcite
|
||||
- Candle & Dyed Candle
|
||||
- Cartography Table (not currently usable due to maps not being implemented)
|
||||
- Cauldron
|
||||
- Cave Vines
|
||||
- Chain
|
||||
- Chiseled Deepslate
|
||||
- Chiseled Nether Bricks
|
||||
- Chiseled Polished Blackstone
|
||||
- Chorus Flower
|
||||
- Chorus Plant
|
||||
- Cobbled Deepslate blocks, slabs, stairs, and walls
|
||||
- Copper Ore
|
||||
- Copper block (random oxidation not yet implemented)
|
||||
- Crached Deepslate Tiles
|
||||
- Cracked Deepslate Bricks
|
||||
- Cracked Nether Bricks
|
||||
- Cracked Polished Blackstone Bricks
|
||||
- Crimson buttons, doors, fences, fence gates, hyphae, planks, pressure plates, signs, slabs, stairs, stems, and trapdoors
|
||||
- Crying Obsidian
|
||||
- Cut Copper block, stairs and slabs (random oxidation not yet implemented)
|
||||
- Deepslate
|
||||
- Deepslate Bricks blocks, slabs, stairs, and walls
|
||||
- Deepslate Ores (coal, copper, diamond, emerald, gold, iron, lapis lazuli, redstone)
|
||||
- Deepslate Tiles blocks, slabs, stairs, and walls
|
||||
- Flowering Azalea Leaves
|
||||
- Froglight (pearlescent, verdant, ochre)
|
||||
- Gilded Blackstone
|
||||
- Glow Item Frame
|
||||
- Hanging Roots
|
||||
- Honeycomb Block
|
||||
- Light Block
|
||||
- Lightning Rod
|
||||
- Mangrove Leaves
|
||||
- Mangrove Roots
|
||||
- Mangrove buttons, doors, fences, fence gates, logs, planks, pressure plates, signs, slabs, stairs, trapdoors, and wood
|
||||
- Mud Bricks blocks, slabs, stairs, and walls
|
||||
- Muddy Mangrove Roots
|
||||
- Nether Gold Ore
|
||||
- Netherite Block
|
||||
- Polished Basalt
|
||||
- Polished Blackstone Bricks blocks, slabs, stairs, and walls
|
||||
- Polished Blackstone blocks, buttons, pressure plates, slabs, stairs, and walls
|
||||
- Polished Deepslate blocks, slabs, stairs, and walls
|
||||
- Quartz Bricks
|
||||
- Reinforced Deepslate
|
||||
- Rooted Dirt
|
||||
- Sculk
|
||||
- Shroomlight
|
||||
- Smithing Table
|
||||
- Smooth Basalt
|
||||
- Soul Fire
|
||||
- Soul Lantern
|
||||
- Soul Soil
|
||||
- Soul Torch
|
||||
- Spore Blossom
|
||||
- Tinted Glass
|
||||
- Tuff
|
||||
- Twisting Vines
|
||||
- Warped Wart Block
|
||||
- Warped buttons, doors, fences, fence gates, hyphae, planks, pressure plates, signs, slabs, stairs, stems, and trapdoors
|
||||
- Weeping Vines
|
||||
- Wither Rose
|
||||
- Added support for basalt generators
|
||||
- Added support for dyeing sign text and making it glow.
|
||||
- All-sided logs ("wood", for want of a better name) can now be placed in X, Y, and Z orientations.
|
||||
- Coral and coral fans now behave correctly when placed out of water (they no longer immediately die).
|
||||
- Fixed dead bush being able to be placed on some invalid blocks (e.g. stone).
|
||||
- Fixed lava setting entities on fire for an incorrect duration (Java vs Bedrock inconsistency).
|
||||
- Fixed sugarcane not being able to be placed on some blocks.
|
||||
- Iron Ore and Gold Ore now drop Raw Iron and Raw Gold respectively, instead of the ore blocks.
|
||||
- Item frames can now be placed on the top and bottom of blocks.
|
||||
- Stripping logs by right-clicking them with an axe is now supported.
|
||||
- TNT can now be ignited by fire charges.
|
||||
- Vines can now only be placed on the side of full-cube blocks.
|
||||
- Walls now connect when placed, following the pre-1.16 logic. (1.16 logic is planned to be implemented, but currently low priority.)
|
||||
- Anvils are now damaged when they hit the ground after falling.
|
||||
- Added missing sounds for anvils hitting the ground after falling.
|
||||
- Anvils now damage entities when they fall on top of them.
|
||||
|
||||
### Items
|
||||
- Added the following new items:
|
||||
- Amethyst Shard
|
||||
- Antidote (from Education Edition)
|
||||
- Copper Ingot
|
||||
- Disc Fragment (5)
|
||||
- Echo Shard
|
||||
- Elixir (from Education Edition)
|
||||
- Eye Drops (from Education Edition)
|
||||
- Fire Charge
|
||||
- Glow Berries
|
||||
- Glow Ink Sac
|
||||
- Honey Bottle
|
||||
- Honeycomb
|
||||
- Mangrove Boat (incomplete)
|
||||
- Music Disc (5)
|
||||
- Music Disc (Otherside)
|
||||
- Music Disc (Pigstep)
|
||||
- Netherite Axe
|
||||
- Netherite Boots
|
||||
- Netherite Chestplate
|
||||
- Netherite Helmet
|
||||
- Netherite Ingot
|
||||
- Netherite Leggings
|
||||
- Netherite Pickaxe
|
||||
- Netherite Scrap
|
||||
- Netherite Shovel
|
||||
- Netherite Sword
|
||||
- Phantom Membrane
|
||||
- Raw Copper
|
||||
- Raw Gold
|
||||
- Raw Iron
|
||||
- Spyglass
|
||||
- Suspicious Stew
|
||||
- Tonic (from Education Edition)
|
||||
- Glass bottles can now be filled with water by clicking on a water source block.
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Armour durability is now only reduced when the wearer receives a type of damage that the armour can protect against.
|
||||
- Bells now ring when hit by a projectile.
|
||||
|
||||
### Worlds
|
||||
- World height of -64 to 319 is now supported.
|
||||
- Added support for 3D biomes. This isn't used by PocketMine-MP yet, but is necessary to be able to fully load 1.18 worlds.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Union and mixed native parameter, return and property types are now used where appropriate.
|
||||
- Protected and public properties now use native property types wherever possible.
|
||||
- Parameter and return typehints have been applied in many places where it wasn't previously possible.
|
||||
|
||||
### Dependencies
|
||||
- [`ext-pmmpthread` version 6.0.0](https://github.com/pmmp/ext-pmmpthread/releases/6.0.0) (renamed from `ext-pthreads`) is now required. This version features major API changes and improvements. Please read the [upgrading guide](https://github.com/pmmp/ext-pmmpthread/blob/fork/docs/UPGRADING_4.x_to_6.0.md) for details.
|
||||
- [`pocketmine/snooze` version 0.5.0](https://github.com/pmmp/Snooze/releases/0.5.0) is now required.
|
||||
- [`pocketmine/raklib` version 0.15.0](https://github.com/pmmp/RakLib/releases/0.15.0) is now required.
|
||||
- [`pocketmine/raklib-ipc` version 0.2.0](https://github.com/pmmp/RakLibIpc/releases/0.2.0) is now required.
|
||||
- `pocketmine/classloader` and `pocketmine/log-pthreads` packages have been removed. The relevant classes from these packages are now included in-house in the `pocketmine/thread` namespace.
|
||||
- `BaseClassLoader` is replaced with `pocketmine\thread\ThreadSafeClassLoader`
|
||||
- `ThreadedLogger` is replaced by `pocketmine\thread\ThreadSafeLogger`
|
||||
- `AttachableThreadedLogger` is replaced by `pocketmine\thread\AttachableThreadSafeLogger`
|
||||
- `ThreadedLoggerAttachment` is replaced by `pocketmine\thread\ThreadSafeLoggerAttachment`
|
||||
- `webmozart/path-util` has been removed (replaced by [`symfony/filesystem`](https://github.com/symfony/filesystem)).
|
||||
|
||||
### `pocketmine\block`
|
||||
#### Highlights
|
||||
- Blocks no longer use internal Minecraft IDs and metadata to identify themselves. All APIs associated with legacy IDs
|
||||
and meta have been removed.
|
||||
- A new set of runtime IDs generated from `VanillaBlocks` is used to identify block types. These IDs are defined
|
||||
in `BlockTypeIds`.
|
||||
- These new IDs are used for runtime representation of blocks on chunks, and for type comparison purposes.
|
||||
- Block type IDs are used at **runtime only**. **Do not store them in configs or databases**, as they are subject to
|
||||
change without warning.
|
||||
- Block type IDs are **specific to PocketMine-MP** and have no relation to the IDs used by Minecraft.
|
||||
- Block type IDs cannot be negative
|
||||
- Block type IDs must not be reused, even if overriding an already defined block
|
||||
- Block state properties (e.g. facing, colour, etc.) are now represented by PM-specific state data instead of legacy
|
||||
metadata. The state data consists of:
|
||||
- Block-item state properties - retained by items when the block is broken (colour, wet/dry, coral type, etc.) - handled by `Block->describeBlockItemState()`
|
||||
- Block-only state data - discarded when the block is broken (facing direction, lit/unlit, powered/unpowered, etc.) - handled by `Block->describeBlockOnlyState()`
|
||||
- Chunks now store dynamic state ID derived from the runtime type ID and runtime (PocketMine-MP defined) state data.
|
||||
- Introduced "type tags" concept, which allows marking certain blocks as having certain behaviours.
|
||||
- The idea for this system was borrowed from the Minecraft Java tags system.
|
||||
- It's still in very early concept stage, but is currently used for deciding which types of blocks plants can be placed on without needing to enumerate every single ID in every class, eliminating a bunch of boilerplate code and improving consistency.
|
||||
- All `Block` descendents now accept `BlockTypeInfo` in the constructor, instead of `BlockBreakInfo`. This allows for future additions without needing to change dozens of overridden constructors.
|
||||
- `&$returnedItems` reference parameter is now used in some places such as `Block->onInteract()` to enable actions to return items to players without caring about whether they are in creative or anything else.
|
||||
- This eliminates boilerplate code of deciding whether to set the player's held item or not, as well as automatically dropping any overflow items that don't fit into the inventory.
|
||||
- This is currently used when filling/emptying cauldrons using buckets or glass bottles.
|
||||
- Dependency between `RuntimeBlockStateRegistry` (previously `BlockFactory`) and `VanillaBlocks` has been inverted.
|
||||
- Now, blocks types are defined in `VanillaBlocks`
|
||||
- `RuntimeBlockStateRegistry` automatically registers states for blocks defined in `VanillaBlocks`.
|
||||
- Manual registration in `RuntimeBlockStateRegistry` is still required for custom blocks (see section below about registering new blocks).
|
||||
- `RuntimeBlockStateRegistry` now has only one purpose - to map internal blockstate IDs to `Block` objects when reading blocks from chunks. It should not be used by plugins unless registering new blocks.
|
||||
- To get a block at runtime, e.g. stone, use `VanillaBlocks::STONE()`
|
||||
- To load a block from **old** config or database data:
|
||||
1. Use `GlobalBlockStateHandlers::getUpgrader()->upgradeIntIdMeta()` to convert it to modern data
|
||||
2. Pass the data to `GlobalBlockStateHandlers::getDeserializer()` to get a blockstate ID
|
||||
3. Pass the blockstate ID to `RuntimeBlockStateRegistry::fromStateId()` to get a `Block` instance
|
||||
- Prefer using `StringToItemParser` wherever possible for configs and databases (see `lookupAliases()` and `lookupBlockAliases()`).
|
||||
|
||||
#### Registering new blocks
|
||||
##### In a plugin
|
||||
To add a vanilla block in a plugin which isn't yet supported by PocketMine-MP, do the following:
|
||||
|
||||
1. Get a new type ID using `BlockTypeIds::newId()` - _you'll want to keep this in a property somewhere if you want to
|
||||
compare using `getTypeId()` later_
|
||||
2. Set up the block type somewhere - _this can be anywhere you like, e.g. a plugin main class property, but using
|
||||
a `RegistryTrait` class is recommended - you'll need this later to create new instances of the block_
|
||||
3. Register the block in `RuntimeBlockStateRegistry` - _this informs the server of all the block's possible states so
|
||||
that it can be read from chunks at runtime_
|
||||
4. Register a deserializer for the block's Minecraft ID in `BlockStateToObjectDeserializer` - _needed for the block to
|
||||
be recognized when loaded from disk_
|
||||
5. Register a serializer for the block in `BlockObjectToStateSerializer` - _needed for the block to be saved to disk,
|
||||
and to be sent over the network_
|
||||
6. Optionally, register a string alias for the block in `StringToItemParser` - _so that it can be given via `/give`_
|
||||
|
||||
To see a demo of how to do this in a plugin, see [this example plugin](https://github.com/pmmp/RegisterBlocksDemoPM5).
|
||||
|
||||
Registering custom blocks follows a similar process, but requires additional steps to modify `BlockStateDictionary`
|
||||
which won't be covered here.
|
||||
Since this is not currently officially supported by PocketMine-MP, this won't be covered here.
|
||||
|
||||
This is admittedly rather more of a hassle than in PM4, but this system offers significantly more flexibility than the
|
||||
old system.
|
||||
|
||||
##### As a PocketMine-MP core contribution
|
||||
To register a new vanilla block into the core, the process is slightly different:
|
||||
|
||||
1. Instead of using `BlockTypeIds::newId()`, add a new constant for the block to `BlockTypeIds`
|
||||
2. Register the new block in `VanillaBlocks` - `RuntimeBlockStateRegistry` will automagically take notice of all blocks
|
||||
defined in `VanillaBlocks`
|
||||
3. Follow steps 4 onwards above
|
||||
|
||||
#### Change list
|
||||
- The following classes have been removed:
|
||||
- `BlockIdentifierFlattened`
|
||||
- `BlockLegacyIdHelper`
|
||||
- `BlockLegacyIds`
|
||||
- `BlockLegacyMetadata`
|
||||
- `utils\BlockDataSerializer`
|
||||
- `utils\ColorInMetadataTrait` - `utils\ColoredTrait` now implements colour type data serialization uniformly
|
||||
- `utils\InvalidBlockStateException` - this has been superseded by `pocketmine\data\runtime\InvalidSerializedRuntimeDataException`
|
||||
- `utils\NormalHorizontalFacingInMetadataTrait` - `utils\HorizontalFacingTrait` now implements facing type data serialization uniformly
|
||||
- `utils\PillarRotationInMetadataTrait` - `utils\PillarRotationTrait` now implements rotation type data serialization uniformly
|
||||
- The following classes have been renamed:
|
||||
- `BlockFactory` -> `RuntimeBlockStateRegistry` - this class is now exclusively used for mapping state IDs to block instances for runtime chunk block reading
|
||||
- `Skull` -> `MobHead`
|
||||
- `utils\SkullType` -> `utils\MobHeadType`
|
||||
- `utils\TreeType` -> `pocketmine\world\generator\object\TreeType`
|
||||
- The following classes have been added:
|
||||
- `BaseCake`
|
||||
- `BaseFire`
|
||||
- `BlockTypeIds` - list of type IDs, one for each entry in `VanillaBlocks`
|
||||
- `BlockTypeInfo`
|
||||
- `BlockTypeTags`
|
||||
- `CakeWithCandle`
|
||||
- `CakeWithDyedCandle`
|
||||
- `Candle`
|
||||
- `CartographyTable`
|
||||
- `Chain`
|
||||
- `CopperOre`
|
||||
- `CopperSlab`
|
||||
- `CopperStairs`
|
||||
- `Copper`
|
||||
- `DyedCandle`
|
||||
- `GildedBlackstone`
|
||||
- `GoldOre`
|
||||
- `HangingRoots`
|
||||
- `IronOre`
|
||||
- `Light`
|
||||
- `LightningRod`
|
||||
- `NetherGoldOre`
|
||||
- `Sculk`
|
||||
- `SmithingTable`
|
||||
- `SoulFire`
|
||||
- `WitherRose`
|
||||
- `utils\CandleTrait`
|
||||
- `utils\CopperOxidation`
|
||||
- `utils\CopperTrait`
|
||||
- `utils\SaplingType` - enum of all sapling types
|
||||
- `utils\WallConnectionType` - enum of all possible wall connection types
|
||||
- `utils\WoodTypeTrait`
|
||||
- `utils\WoodType` - enum of all possible wood types, used for wood material blocks like planks and logs
|
||||
- The following API methods have been removed:
|
||||
- `Block->getId()` - for type comparisons, use `Block->getTypeId()` instead
|
||||
- `Block->getMeta()` - for state comparisons, use `Block->getStateId()` instead
|
||||
- `Block->getStateBitmask()`
|
||||
- `Block->readStateFromData()`
|
||||
- `Block->writeStateToItemMeta()`
|
||||
- `Block->writeStateToMeta()`
|
||||
- `BlockFactory->get()` - see notes above about `RuntimeBlockStateRegistry`
|
||||
- `BlockIdentifier->getAllBlockIds()`
|
||||
- `BlockIdentifier->getBlockId()`
|
||||
- `BlockIdentifier->getItemId()`
|
||||
- `BlockIdentifier->getVariant()`
|
||||
- `Door->isPowered()`
|
||||
- `Door->setPowered()`
|
||||
- `MobHead->isNoDrops()` (previously `Skull->isNoDrops()`)
|
||||
- `MobHead->setNoDrops()` (previously `Skull->setNoDrops()`)
|
||||
- `VanillaBlocks::*_GLAZED_TERRACOTTA()` - use `VanillaBlocks::GLAZED_TERRACOTTA()->setColor(DyeColor::WHATEVER())` instead
|
||||
- `utils\FallableTrait->getId()` is no longer required
|
||||
- `utils\FallableTrait->getMeta()` is no longer required
|
||||
- `utils\MobHeadType->getMagicNumber()` (previously `utils\SkullType->getMagicNumber()`)
|
||||
- `utils\MobHeadType::fromMagicNumber()` (previously `utils\SkullType::fromMagicNumber()`)
|
||||
- The following constants have been removed:
|
||||
- `Block::INTERNAL_METADATA_BITS`
|
||||
- `Block::INTERNAL_METADATA_MASK`
|
||||
- The following API methods have been renamed:
|
||||
- `Block->getFullId()` -> `Block->getStateId()`
|
||||
- `Block->isSameType()` -> `Block->hasSameTypeId()`
|
||||
- `MobHead->getSkullType()` -> `MobHead->getMobHeadType()` (previously `Skull->getSkullType()`)
|
||||
- `MobHead->setSkullType()` -> `MobHead->setMobHeadType()` (previously `Skull->setSkullType()`)
|
||||
- The following API methods have signature changes:
|
||||
- `Block->onBreak()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Block->onInteract()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Block->readStateFromWorld()` now returns `Block` - this allows blocks to replace themselves with a different block entirely based on world conditions.
|
||||
- `BlockIdentifier->__construct()` now accepts `int $blockTypeId`, and no longer accepts `int $blockId, int $variant, ?int $itemId`
|
||||
- `ItemFrame->getFacing()` may now return `Facing::UP` and `Facing::DOWN`
|
||||
- `ItemFrame->setFacing()` now accepts `Facing::UP` and `Facing::DOWN`
|
||||
- `Leaves->__construct()` now accepts `LeavesType $leavesType` instead of `TreeType $treeType`
|
||||
- `RuntimeBlockStateRegistry->register()` no longer accepts an `$override` parameter.
|
||||
- `Sapling::__construct()` now accepts `SaplingType $saplingType` instead of `TreeType $treeType`
|
||||
- `utils\SignText::__construct()` now accepts two new optional parameters: `?Color $baseColor` and `bool $glowing`
|
||||
- `utils\SignText::fromBlob()` now accepts two new optional parameters: `?Color $baseColor` and `bool $glowing`
|
||||
- The following API methods have been added:
|
||||
- `protected Block->describeBlockOnlyState(RuntimeDataDescriber $w) : void` - describes state properties which are discarded when the block is broken or block-picked, such as facing, powered, etc.
|
||||
- `public Block->describeBlockItemState(RuntimeDataDescriber $w) : void` - describes state properties which are kept by the item when the block is broken or block-picked, such as dye color
|
||||
- `public Block->generateStatePermutations() : \Generator<int, Block, void, void>` - yields all possible states this block type can be in (used for `RuntimeBlockStateRegistry`)
|
||||
- `public Block->getTypeTags() : array<string>`
|
||||
- `public Block->hasTypeTag(string $tag) : bool`
|
||||
- `public Block->isFireProofAsItem() : bool`
|
||||
- `public Block->onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void`
|
||||
- `public BlockIdentifier->getBlockTypeId() : int` - returns the block's type ID according to `BlockTypeIds`
|
||||
- `public Furnace->getFurnaceType() : utils\FurnaceType`
|
||||
- `public GlazedTerracotta->getColor() : utils\DyeColor` (from `ColoredTrait`) - this was previously unsupported due to legacy limitations
|
||||
- `public GlazedTerracotta->setColor(utils\DyeColor $color) : $this` (from `ColoredTrait`) - this was previously unsupported due to legacy limitations
|
||||
- `public Leaves->getLeavesType() : utils\LeavesType` - returns the type of leaves
|
||||
- `public Wall->getConnection(int $face) : utils\WallConnectionType`
|
||||
- `public Wall->getConnections() : array<int, utils\WallConnectionType>` - returns the wall's connections and their types (see `utils\WallConnectionType`)
|
||||
- `public Wall->isPost() : bool`
|
||||
- `public Wall->setConnection(int $face, ?utils\WallConnectionType $type) : $this`
|
||||
- `public Wall->setConnections()` - sets the wall's connections and their types (see `utils\WallConnectionType`)
|
||||
- `public Wall->setPost(bool $post) : $this`
|
||||
- `public Wood->isStripped() : bool`
|
||||
- `public Wood->setStripped(bool $stripped) : $this`
|
||||
- `public static BlockBreakInfo::axe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo`
|
||||
- `public static BlockBreakInfo::pickaxe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo`
|
||||
- `public static BlockBreakInfo::shovel(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo`
|
||||
- `public static BlockBreakInfo::tier(float $hardness, int $toolType, ToolTier $toolTier, ?float $blastResistance = null) : BlockBreakInfo`
|
||||
- `public tile\Spawnable->getRenderUpdateBugWorkaroundStateProperties(Block $block) : array<string, Tag>` - allows spawnable tiles to spoof block state properties to work around client-side rendering bugs without actually changing the block server-side
|
||||
- `public utils\SignText->getBaseColor() : \pocketmine\color\Color`
|
||||
- `public utils\SignText->isGlowing() : bool`
|
||||
- The following classes now use new traits, adding API methods and/or properties:
|
||||
- `FenceGate` uses `utils\WoodTypeTrait`
|
||||
- `GlazedTerracotta` uses `utils\ColoredTrait`
|
||||
- `Planks` uses `utils\WoodTypeTrait`
|
||||
- `Wood` uses `utils\WoodTypeTrait`
|
||||
- `WoodenButton` uses `utils\WoodTypeTrait`
|
||||
- `WoodenDoor` uses `utils\WoodTypeTrait`
|
||||
- `WoodenFence` uses `utils\WoodTypeTrait`
|
||||
- `WoodenPressurePlate` uses `utils\WoodTypeTrait`
|
||||
- `WoodenSlab` uses `utils\WoodTypeTrait`
|
||||
- `WoodenStairs` uses `utils\WoodTypeTrait`
|
||||
- `WoodenTrapdoor` uses `utils\WoodTypeTrait`
|
||||
- The following API interface requirements have been added (BC breaking):
|
||||
- `public utils\Fallable->getFallDamagePerBlock() : float` (default implementation provided by `utils\FallableTrait`)
|
||||
- `public utils\Fallable->getLandSound() : ?Sound` (default implementation provided by `utils\FallableTrait`)
|
||||
- `public utils\Fallable->getMaxFallDamage() : float` (default implementation provided by `utils\FallableTrait`)
|
||||
- `public utils\Fallable->onHitGround(FallingBlock $blockEntity) : bool` (default implementation provided by `utils\FallableTrait`)
|
||||
|
||||
### `pocketmine\command`
|
||||
- Command permissions are now always checked by the server when running a command.
|
||||
- This only affects commands implemented by extending `Command`. Plugins using `PluginBase->onCommand()` are not affected by this change, since they already had permissions checked by the server anyway.
|
||||
- Previously, direct inheritors of `Command` were responsible for checking permissions, which required developers to duplicate the same code in every command, and opened lots of potential for security vulnerabilities.
|
||||
- If you want to do something on permission denied (e.g. sending a special message, or audit logging), you can do so by overriding `Command->testPermission()`, instead of baking the code directly into `Command->execute()`.
|
||||
- If you don't want to use permissions at all, just create a permission with a default of `true` (or belonging to `pocketmine.group.user`) and assign that.
|
||||
- `SimpleCommandMap` now requires all commands to have a permission set when registered.
|
||||
- If you actually want to allow everyone to use your command (not advised), you can add a new permission to the `pocketmine.group.user` group, or use `default: true` for `plugin.yml` permissions.
|
||||
- The following API methods have changed behaviour:
|
||||
- `Command->testPermissionSilent()` now returns `false` if there are no permissions associated with the command. This is to prevent commands with no permissions being usable by everyone, which has previously been a source of security issues.
|
||||
- The following API methods have been added:
|
||||
- `public Command->getPermissions() : list<string>` - returns a list of permissions which grant usage access to this command. A user with one or more of these permissions will be able to invoke the command's `execute()` method
|
||||
- `public Command->setPermissions(list<string> $permissions) : void` - sets the permissions which grant usage access to this command. This should be used instead of `setPermission()` with `;` separators (which is now deprecated)
|
||||
|
||||
### `pocketmine\crafting`
|
||||
- JSON models have been updated to reflect updated crafting data format.
|
||||
- The following enum classes have new members:
|
||||
- `ShapelessRecipeType` has new members `CARTOGRAPHY` and `SMITHING`
|
||||
- The following classes have been added:
|
||||
- `ExactRecipeIngredient` - matches an exact item
|
||||
- `MetaWildcardRecipeIngredient` - matches an item with the given legacy Minecraft ID, but any metadata value
|
||||
- `RecipeIngredient` interface
|
||||
- `TagWildcardRecipeIngredient` - matches an item based on its Minecraft tags, e.g. `minecraft:wooden_tier`
|
||||
- The following API methods have signature changes:
|
||||
- `FurnaceRecipe->__construct()` now accepts `RecipeIngredient` instead of `Item`
|
||||
- `FurnaceRecipe->getInput()` now returns `RecipeIngredient` instead of `Item`
|
||||
- `PotionContainerChangeRecipe->__construct()` now accepts `string, RecipeIngredient, string` (using Minecraft string IDs instead of legacy integers).
|
||||
- `PotionContainerChangeRecipe->getIngredient()` now returns `RecipeIngredient` instead of `Item`.
|
||||
- `PotionContainerChangeRecipe->getInputItemId()` now returns `string` (using Minecraft string IDs instead of legacy integers).
|
||||
- `PotionContainerChangeRecipe->getOutputItemId()` now returns `string` (using Minecraft string IDs instead of legacy integers).
|
||||
- `PotionTypeRecipe->__construct()` now accepts `RecipeIngredient` instead of `Item`
|
||||
- `PotionTypeRecipe->getIngredient()` now returns `RecipeIngredient` instead of `Item`
|
||||
- `PotionTypeRecipe->getInput()` now returns `RecipeIngredient` instead of `Item`
|
||||
- `ShapedRecipe->__construct()` now accepts `RecipeIngredient` instead of `Item`
|
||||
- `ShapedRecipe->getIngredient()` now returns `?RecipeIngredient` instead of `?Item`
|
||||
- `ShapedRecipe->getIngredientList()` now returns `RecipeIngredient[]` instead of `Item[]`
|
||||
- `ShapedRecipe->getIngredientMap()` now returns `RecipeIngredient[][]` instead of `Item[][]`
|
||||
- `ShapelessRecipe->__construct()` `$type` parameter is now mandatory.
|
||||
- `ShapelessRecipe->__construct()` now accepts `RecipeIngredient` instead of `Item`
|
||||
- `ShapelessRecipe->getIngredientList()` now returns `RecipeIngredient[]` instead of `Item[]`
|
||||
|
||||
### `pocketmine\data`
|
||||
- New packages `bedrock\block` and `bedrock\item` have been added. These packages contain all the necessary code for loading and saving Bedrock blocks and items from disk.
|
||||
- New package `runtime` has been added. This package contains code for serializing runtime data for blocks and items.
|
||||
- `LegacyToStringBidirectionalIdMap` has been reduced to `LegacyToStringIdMap`.
|
||||
- Since we never map from string ID to legacy ID, bidirectional mapping is no longer necessary.
|
||||
- This affects the following subclasses:
|
||||
- `LegacyBiomeIdToStringIdMap`
|
||||
- `LegacyBlockIdToStringIdMap`
|
||||
- `LegacyEntityIdToStringIdMap`
|
||||
- `LegacyItemIdToStringIdMap`
|
||||
- The following internal API methods have been added:
|
||||
- `public LegacyToStringIdMap->add(string $string, int $legacy) : void` - adds a mapping from a custom legacy ID to custom string ID, needed for upgrading old saved data
|
||||
|
||||
### `pocketmine\entity`
|
||||
- `Entity` now declares new abstract methods which must be implemented by subclasses:
|
||||
- `public Entity->getInitialDragMultiplier() : float`
|
||||
- `public Entity->getInitialGravity() : float`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string`
|
||||
- The following API methods have changed signatures:
|
||||
- `EntityFactory->register()` no longer accepts a `$legacyMcpeSaveId` parameter (now handled by internal conversions instead).
|
||||
- The following API methods have been renamed:
|
||||
- `Entity->isImmobile()` -> `Entity->hasNoClientPredictions()`
|
||||
- `Entity->setImmobile()` -> `Entity->setNoClientPredictions()`
|
||||
- The following internal fields have been renamed:
|
||||
- `Entity->immobile` -> `Entity->noClientPredictions`
|
||||
- The following classes have been removed:
|
||||
- `EntityLegacyIds`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following classes have inheritance changes:
|
||||
- `block\BlockPlaceEvent` no longer extends `BlockEvent`, and therefore no longer has `getBlock()`. Use `getTransaction()` instead (may contain multiple blocks).
|
||||
- `BlockFormEvent` now includes information about the block which caused the event.
|
||||
|
||||
- The following new classes have been added:
|
||||
- `world\WorldDisplayNameChangeEvent` - called when a world's display name is changed
|
||||
- The following classes have been renamed:
|
||||
- `entity\ExplosionPrimeEvent` -> `entity\EntityPreExplodeEvent`
|
||||
- The following API methods have been added:
|
||||
- `public block\BlockFormEvent->getCausingBlock() : Block`
|
||||
- `public block\BlockGrowEvent->getPlayer() : ?Player` - returns the player that triggered the block growth, or `null` if it was not triggered by a player
|
||||
- `public block\BlockPlaceEvent->getTransaction() : BlockTransaction` - returns the transaction containing a list of changed block positions and the blockstates they will be changed to
|
||||
- `public server\DataPacketSendEvent->setPackets(list<ClientboundPacket> $packets) : void`
|
||||
- The following API methods have changed signatures:
|
||||
- `block\BlockPlaceEvent->__construct()` now accepts `BlockTransaction $transaction` instead of `Block $blockPlace, Block $blockReplace`
|
||||
- `entity\EntityPreExplodeEvent->__construct()` has the `$force` parameter renamed to `$radius`
|
||||
- `entity\EntityPreExplodeEvent->getForce() : float` -> `entity\EntityPreExplodeEvent->getRadius() : float`
|
||||
- `entity\EntityPreExplodeEvent->setForce(float $force) : void` -> `entity\EntityPreExplodeEvent->setRadius(float $radius) : void`
|
||||
- The following API methods have been removed:
|
||||
- `block\BlockPlaceEvent->getBlockReplaced()` - this information is now provided in the `BlockTransaction` object returned by `BlockPlaceEvent->getTransaction()`
|
||||
- The following new API constants have been added:
|
||||
- `entity\EntityDamageEvent::CAUSE_FALLING_BLOCK`
|
||||
- `entity\EntityDamageEvent::MODIFIER_ARMOR_HELMET`
|
||||
|
||||
### `pocketmine\event\player`
|
||||
- `PlayerPreLoginEvent`, `PlayerDuplicateLoginEvent` and `PlayerKickEvent` now supports setting separate log reasons (disconnect reason) and disconnect screen messages.
|
||||
- The following classes have been removed:
|
||||
- `PlayerCommandPreprocessEvent`
|
||||
- The following API methods have changed signatures:
|
||||
- `PlayerDuplicateLoginEvent->getDisconnectMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerDuplicateLoginEvent->setDisconnectMessage()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerKickEvent->getReason()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerKickEvent->setReason()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerLoginEvent->getKickMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerLoginEvent->setKickMessage()` now accepts `Translatable|string` instead of `string`
|
||||
- `PlayerPreLoginEvent->getFinalKickMessage()` now returns `Translatable|string` instead of `string`
|
||||
- `PlayerPreLoginEvent->getKickMessage()` now returns `Translatable|string|null` instead of `string|null`
|
||||
- `PlayerPreLoginEvent->setKickFlag()` (previously `setKickReason()`) now accepts `Translatable|string $disconnectReason, Translatable|string|null $disconnectScreenMessage = null` instead of `Translatable|string $message`
|
||||
- `PlayerPreLoginEvent->setKickReason()` now accepts `Translatable|string` for the `$message` parameter instead of `string`
|
||||
- `PlayerQuitEvent->getQuitReason()` now returns `Translatable|string` instead of `string`
|
||||
- The following API methods have been removed:
|
||||
- `PlayerChatEvent->getFormat()` (use `PlayerChatEvent->getChatFormatter()` instead)
|
||||
- `PlayerChatEvent->setFormat()` (use `PlayerChatEvent->setChatFormatter()` instead)
|
||||
- `PlayerDuplicateLoginEvent->getDisconnectMessage()` - replaced by `getDisconnectReason()` and `getDisconnectScreenMessage()`
|
||||
- `PlayerDuplicateLoginEvent->setDisconnectMessage()` - replaced by `setDisconnectReason()` and `setDisconnectScreenMessage()`
|
||||
- `PlayerKickEvent->getReason()` - replaced by `getDisconnectReason()` and `getDisconnectScreenMessage()`
|
||||
- `PlayerKickEvent->setReason()` - replaced by `setDisconnectReason()` and `setDisconnectScreenMessage()`
|
||||
- The following new API methods have been added:
|
||||
- `public PlayerChatEvent->getChatFormatter() : \pocketmine\player\chat\ChatFormatter` - returns the chat formatter to be used for this event
|
||||
- `public PlayerChatEvent->setChatFormatter(\pocketmine\player\chat\ChatFormatter $formatter) : void` - sets the chat formatter to be used for this event
|
||||
- `public PlayerDeathEvent->getDeathScreenMessage() : Translatable|string` - returns the message to be displayed on the death screen
|
||||
- `public PlayerDeathEvent->setDeathScreenMessage(Translatable|string $deathScreenMessage) : void` - sets the message to be displayed on the death screen
|
||||
- `public PlayerDuplicateLoginEvent->getDisconnectReason() : Translatable|string` - returns the reason for the disconnection displayed in the console and server log
|
||||
- `public PlayerDuplicateLoginEvent->getDisconnectScreenMessage() : Translatable|string|null` - returns the message to be displayed on the disconnect screen (the message in `getDisconnectReason()` is used if null is returned)
|
||||
- `public PlayerDuplicateLoginEvent->setDisconnectReason(Translatable|string $disconnectReason) : void` - sets the reason for the disconnection displayed in the console and server log
|
||||
- `public PlayerDuplicateLoginEvent->setDisconnectScreenMessage(Translatable|string|null $disconnectScreenMessage) : void` - sets the message to be displayed on the disconnect screen (the message in `setDisconnectReason()` is used if null is passed)
|
||||
- `public PlayerKickEvent->getDisconnectReason() : Translatable|string` - returns the reason for the disconnection displayed in the console and server log
|
||||
- `public PlayerKickEvent->getDisconnectScreenMessage() : Translatable|string|null` - returns the message to be displayed on the disconnect screen (the message in `getDisconnectReason()` is used if null is returned)
|
||||
- `public PlayerKickEvent->setDisconnectReason(Translatable|string $disconnectReason) : void` - sets the reason for the disconnection displayed in the console and server log
|
||||
- `public PlayerKickEvent->setDisconnectScreenMessage(Translatable|string|null $disconnectScreenMessage) : void` - sets the message to be displayed on the disconnect screen (the message in `setDisconnectReason()` is used if null is passed)
|
||||
- `public PlayerPreLoginEvent->getDisconnectScreenMessage(int $flag) : Translatable|string|null` - returns the message to be displayed on the disconnect screen for the specified kick flag, if set
|
||||
- `public PlayerPreLoginEvent->getFinalDisconnectScreenMessage() : Translatable|string|null` - returns the message to be displayed on the disconnect screen, taking into account the kick flags set
|
||||
- The following classes have inheritance changes:
|
||||
- `PlayerPreLoginEvent` no longer implements `Cancellable`. This caused unexpected behaviour for most plugin devs due to default-ignoring cancelled events, forcing people to usually have to use `@handleCancelled` to handle the event when they wanted to use it.
|
||||
- The following API constants have been renamed:
|
||||
- `PlayerPreLoginEvent::KICK_REASON_BANNED` -> `PlayerPreLoginEvent::KICK_FLAG_BANNED`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_PLUGIN` -> `PlayerPreLoginEvent::KICK_FLAG_PLUGIN`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_PRIORITY` -> `PlayerPreLoginEvent::KICK_FLAG_PRIORITY`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_SERVER_FULL` -> `PlayerPreLoginEvent::KICK_FLAG_SERVER_FULL`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED` -> `PlayerPreLoginEvent::KICK_FLAG_SERVER_WHITELISTED`
|
||||
- The following API methods have been renamed:
|
||||
- `PlayerPreLoginEvent->clearAllKickReasons()` -> `PlayerPreLoginEvent->clearAllKickFlags()`
|
||||
- `PlayerPreLoginEvent->clearKickReason()` -> `PlayerPreLoginEvent->clearKickFlag()`
|
||||
- `PlayerPreLoginEvent->getFinalKickMessage()` -> `PlayerPreLoginEvent->getFinalDisconnectReason()` (now used for logs only, if a disconnect screen message is set for the highest priority flag)
|
||||
- `PlayerPreLoginEvent->getKickMessage()` -> `PlayerPreLoginEvent->getDisconnectReason()` (now used for logs only, if a disconnect screen message is set for the flag)
|
||||
- `PlayerPreLoginEvent->getKickReasons()` -> `PlayerPreLoginEvent->getKickFlags()`
|
||||
- `PlayerPreLoginEvent->isKickReasonSet()` -> `PlayerPreLoginEvent->isKickFlagSet()`
|
||||
- `PlayerPreLoginEvent->setKickReason()` -> `PlayerPreLoginEvent->setKickFlag()`
|
||||
|
||||
### `pocketmine\item`
|
||||
#### Highlights
|
||||
- `ItemFactory` has been removed. Vanilla item registration is now done via `VanillaItems`.
|
||||
- To get an item at runtime, e.g. iron ingot, use `VanillaItems::IRON_INGOT()`
|
||||
- To get a block as an item, e.g. stone, use `VanillaBlocks::STONE()->asItem()`
|
||||
- To load an item from legacy ID and meta:
|
||||
1. Use `GlobalItemDataHandlers::getUpgrader()->upgradeItemTypeDataInt()` to convert the legacy ID and meta to `SavedItemStackData`
|
||||
2. Pass the itemstack data to `GlobalItemDataHandlers::getDeserializer()` to get an `Item` instance
|
||||
- Items no longer use internal Minecraft string IDs and metadata to identify themselves. All APIs associated with legacy
|
||||
IDs and/or meta have been removed.
|
||||
- A new set of runtime item IDs generated from `VanillaItems` is now used to identify item types. These IDs are defined
|
||||
in `ItemTypeIds`.
|
||||
- These new IDs are primarily intended for type comparison purposes.
|
||||
- Item type IDs are used at **runtime only**. They should **NOT** be stored in configs or databases, as they are not
|
||||
guaranteed to remain the same between versions.
|
||||
- In some cases, items may have additional "type data" which provides extra type information about an item. This
|
||||
replaces item metadata in some cases.
|
||||
- Type data may be used to store dynamic type information such as dye colour, potion type, etc.
|
||||
- Items must have the same type ID **and** type data in order to be stackable.
|
||||
- Blocks, when represented as items:
|
||||
- retain their block type data, but not state data (for example, different colours of concrete don't stack, but things
|
||||
like facing don't affect stackability)
|
||||
- use the negative of their block type ID (e.g. a block with type ID `1` will have an item type ID of `-1`).
|
||||
- Durable items (e.g. tools, armour) now use NBT `Damage` tag to store durability (like Minecraft 1.13+), instead of
|
||||
legacy meta values.
|
||||
- `&$returnedItems` reference parameter is now used in some places (e.g. `onInteractBlock()`) to enable actions to return items to players without caring about whether they are in creative or anything else.
|
||||
- This eliminates boilerplate code of deciding whether to set the player's held item or not, as well as automatically dropping any overflow items that don't fit into the inventory.
|
||||
- This is used for things like filling/emptying buckets and bottles, and equipping armor.
|
||||
- Blocks which previously had separate items, such as mob heads and beds, no longer do. Their item form can be acquired using `Block->asItem()` in the same way as every other block. This is facilitated by the new serializer system.
|
||||
|
||||
#### Implementing new items
|
||||
##### In a plugin
|
||||
This follows a similar process to registering blocks.
|
||||
|
||||
1. Get a new type ID using `ItemTypeIds::newId()` - _you'll want to keep this in a property somewhere if you want to
|
||||
compare using `getTypeId()` later_
|
||||
2. Set up the item type somewhere - _this can be anywhere you like, e.g. a plugin main class property, but using
|
||||
a `RegistryTrait` class is recommended - you'll need this later to create new instances of the item_
|
||||
3. Register a deserializer in `ItemDeserializer` - _needed for the item to be recognized when loaded from disk_
|
||||
4. Register a serializer in `ItemSerializer` - _needed for the item to be saved to disk, and to be sent over the
|
||||
network_
|
||||
5. Optionally, register a string alias for the item in `StringToItemParser` - _so that it can be given via `/give`_
|
||||
|
||||
To see a demo of how to do this in a plugin, see [this example plugin](https://github.com/pmmp/RegisterBlocksDemoPM5).
|
||||
|
||||
Again, it's acknowledged this is rather more cumbersome than it should be, but this is an ongoing process.
|
||||
|
||||
##### As a PocketMine-MP core contribution
|
||||
|
||||
To register a new vanilla item into the core, the process is slightly different:
|
||||
|
||||
1. Instead of using `ItemTypeIds::newId()`, add a new constant for the block to `ItemTypeIds`
|
||||
2. Register the new item in `VanillaItems`
|
||||
3. Follow steps 3 onwards from the plugin instructions above
|
||||
|
||||
#### Change list
|
||||
- `Item` is no longer `json_encode()`-able.
|
||||
- The original purpose of this was to allow items to be serialized to JSON for crafting data generated from `CraftingDataPacket`. Due to changes in the generation methodology, bypassing `Item`s entirely, this is no longer necessary.
|
||||
- In addition, `jsonSerialize()` required the item to know about the method by which it will be serialized (since there is no way to inject context), creating a cyclic dependency between the `Item` implementation and its serialization method.
|
||||
- It's relatively easy to write a replacement method to encode items to JSON as you desire.
|
||||
- `Item::legacyJsonDeserialize()` (previously `Item::jsonDeserialize()`) is retained to allow loading legacy data, although it may be removed in the future.
|
||||
- The following classes have been removed:
|
||||
- `Bed`
|
||||
- `ItemFactory`
|
||||
- `ItemIds`
|
||||
- `Skull`
|
||||
- The following classes have been added:
|
||||
- `BoatType` - enum of all boat types
|
||||
- `CoralFan`
|
||||
- `HoneyBottle`
|
||||
- `MedicineType`
|
||||
- `Medicine`
|
||||
- `Spyglass`
|
||||
- `SuspiciousStewType`
|
||||
- `SuspiciousStew`
|
||||
- The following API methods have been added:
|
||||
- `protected Item->describeState(RuntimeDataDescriber $w) : void`
|
||||
- `public Armor->clearCustomColor() : $this` - clears the custom color of an armor item
|
||||
- `public ArmorTypeInfo->getToughness() : int`
|
||||
- `public ArmorTypeInfo->isFireProof() : bool`
|
||||
- `public Boat->getType() : BoatType`
|
||||
- `public Dye->setColor(\pocketmine\block\utils\DyeColor $color) : $this`
|
||||
- `public Item->getStateId() : int` - returns a runtime numeric state ID for comparisons including information such as coral type, dye color, etc. - DO NOT save this to disk or databases
|
||||
- `public Item->getTypeId() : int` - returns a runtime numeric type ID for comparisons - DO NOT save this to disk or databases
|
||||
- `public Item->isFireProof() : bool`
|
||||
- `public ItemIdentifer->getTypeId() : int`
|
||||
- `public Potion->setType(PotionType $type) : $this`
|
||||
- `public SplashPotion->setType(PotionType $type) : $this`
|
||||
- `public StringToItemParser->lookupAliases(Item $item) : list<string>` - returns a list of all registered aliases for the given item
|
||||
- `public StringToItemParser->lookupBlockAliases(Block $block) : list<string>` - returns a list of all registered aliases for the given block
|
||||
- `public static ItemIdentifier::fromBlock(Block $block) : self`
|
||||
- The following API methods have been removed:
|
||||
- `Boat->getWoodType()`
|
||||
- `Item->getId()` - for type comparisons, use `Item->getTypeId()` instead
|
||||
- `Item->getMeta()` - use the item's specific API methods to compare information such as colour, potion type etc.
|
||||
- `Item->hasAnyDamageValue()` - for meta wildcard recipe ingredients, use `pocketmine\crafting\MetaWildcardRecipeIngredient` instead
|
||||
- `ItemIdentifier->getId()`
|
||||
- `ItemIdentifier->getMeta()`
|
||||
- The following API methods have been renamed:
|
||||
- `Item::jsonDeserialize()` -> `Item::legacyJsonDeserialize()`
|
||||
- The following API methods have signature changes:
|
||||
- `ArmorTypeInfo->__construct()` now accepts optional parameters `int $toughness` and `bool $fireProof`
|
||||
- `BoatType::__construct()` now accepts `BoatType $boatType` instead of `TreeType $woodType`.
|
||||
- `Item->onAttackEntity()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Item->onClickAir()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Item->onDestroyBlock()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Item->onInteractBlock()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `Item->onReleaseUsing()` now accepts `array<Item> &$returnedItems` reference parameter.
|
||||
- `ItemIdentifier->__construct()` no longer accepts a `$variant` parameter, and now expects an item type ID for the ID parameter
|
||||
- `LegacyStringToItemParser->addMapping()` now accepts a string for ID, instead of an integer
|
||||
- The following API methods have behaviour changes:
|
||||
- `Item->equals()`'s `$checkDamage` parameter is now ignored, as tool damage is now stored as an NBT tag. This parameter wasn't removed due to being followed by a second `bool` parameter, which would potentially end up in the wrong place and silently cause bugs in updated plugins.
|
||||
- `Item->equals()`'s `$checkTags` parameter will now cause tool and armor damage to be checked if true.
|
||||
- The following enums have new members:
|
||||
- `ToolTier` has new member `NETHERITE`
|
||||
|
||||
### `pocketmine\network`
|
||||
- The following API methods have changed signatures:
|
||||
- `NetworkSessionManager->close()` now accepts an additional `Translatable|string|null $disconnectScreenMessage` parameter.
|
||||
- The following API methods have changed signatures:
|
||||
- `query\QueryInfo->getPlayerList()` now returns `list<string>` instead of `list<Player>`
|
||||
- `query\QueryInfo->setPlayerList()` now accepts `list<string>` instead of `list<Player>`
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following API methods have changed signatures:
|
||||
- `Player->disconnect()` now accepts `Translatable|string` for `$reason` instead of `string` (to allow localized disconnect messages)
|
||||
- `Player->disconnect()` now accepts an additional `Translatable|string|null $disconnectScreenMessage` parameter, which is the message to be displayed on the disconnect screen (the message in `$reason` is used if null is passed)
|
||||
- `Player->kick()` now accepts `Translatable|string` for `$reason` instead of `string` (to allow localized kick messages)
|
||||
- `Player->kick()` now accepts an additional `Translatable|string|null $disconnectScreenMessage` parameter, which is the message to be displayed on the disconnect screen (the message in `$reason` is used if null is passed)
|
||||
- `Player->sendJukeboxPopup()` now accepts `Translatable|string` instead of `string, string[]`
|
||||
- The following classes have been removed:
|
||||
- `PlayerChunkLoader` - deprecated in 4.19.0 (this was technically internal, but never marked as such)
|
||||
|
||||
### `pocketmine\player\chat`
|
||||
- The following new classes have been added:
|
||||
- `ChatFormatter` - interface implemented by chat formatters - this is far more powerful than the old API
|
||||
- `LegacyRawChatFormatter` - implements the same behaviour previously used by `PlayerChatEvent->setFormat()`
|
||||
- `StandardChatFormatter` - formats chat messages in the vanilla Minecraft style
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- `AsyncTask->setResult()` now works with thread-safe objects. This was previously not possible due to limitations in the `pthreads` extension.
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following API methods have been added:
|
||||
- `public World->setDisplayName(string $name) : void`
|
||||
- The following API methods have changed signatures:
|
||||
- `Explosion->__construct()` has the `$size` parameter renamed to `$radius`
|
||||
- The following public properties have been renamed:
|
||||
- `Explosion->size` -> `Explosion->radius`
|
||||
|
||||
### `pocketmine\world\format`
|
||||
- Chunks are now considered dirty (modified) by default, unless loaded from a `WorldProvider` by `World`. Previously, chunks were considered unmodified by default, which allowed several pathways to bugs.
|
||||
- The following classes have been added:
|
||||
- `io\GlobalBlockStateHandlers` - gives access to block data serializer, deserializer, and upgraders
|
||||
- `io\GlobalItemDataHandlers` - gives access to item data serializer, deserializer, and upgraders
|
||||
- `io\LoadedChunkData` - represents a chunk loaded from disk, along with information such as whether the chunk was upgraded and what fixes it requires
|
||||
- The following new API methods have been added:
|
||||
- `public SubChunk->getBiomeArray() : PalettedBlockArray`
|
||||
- The following classes have been removed:
|
||||
- `BiomeArray` - `PalettedBlockArray` is now used for 3D biome data
|
||||
- The following API methods have changed signatures:
|
||||
- `Chunk->getBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `Chunk->setBiomeId()` now accepts `int $x, int $y, int $z` instead of `int $x, int $z`
|
||||
- `Chunk->__construct()` no longer accepts `BiomeArray` as a parameter (contained in each subchunk instead)
|
||||
- `SubChunk->__construct()` now accepts `int $emptyBlockId, list<PalettedBlockArray> $blockLayers, PalettedBlockArray $biomes, ?LightArray $blockLight, ?LightArray $skyLight` instead of `int, list<PalettedBlockArray>, ?LightArray, ?LightArray`
|
||||
- `io\WorldProvider->loadChunk()` now returns `LoadedChunkData` instead of `ChunkData`
|
||||
- `io\WorldProvider->getAllChunks()` now yields `LoadedChunkData` instead of `ChunkData`
|
||||
- `io\ChunkData->__construct()` now accepts `array<int, SubChunk>, bool $populated` instead of `Chunk $chunk`
|
||||
- The following API methods have been renamed:
|
||||
- `Chunk->getFullBlock()` -> `Chunk->getBlockStateId()`
|
||||
- `Chunk->setFullBlock()` -> `Chunk->setBlockStateId()`
|
||||
- `SubChunk->getFullBlock()` -> `SubChunk->getBlockStateId()`
|
||||
- `SubChunk->setFullBlock()` -> `SubChunk->setBlockStateId()`
|
||||
- The following API interface requirements have been added:
|
||||
- `public io\data\WorldData->setDisplayName(string $value) : void`
|
||||
|
||||
### `pocketmine\world\generator\object`
|
||||
- The following API methods have been removed:
|
||||
- `TreeType::fromMagicNumber()`
|
||||
- `TreeType->getMagicNumber()`
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following classes have been added:
|
||||
- `CopperWaxApplySound`
|
||||
- `CopperWaxRemoveSound`
|
||||
- `DyeUseSound`
|
||||
- `InkSacUseSound`
|
||||
- The following enums have new members:
|
||||
- `NoteInstrument` has new members `BELL`, `FLUTE`, `CHIME`, `XYLOPHONE`, `IRON_XYLOPHONE`, `COW_BELL`, `DIDGERIDOO`, `BIT`, `BANJO`, `PLING`
|
||||
- The following API methods have been removed:
|
||||
- `NoteInstrument::fromMagicNumber()`
|
||||
- `NoteInstrument->getMagicNumber()`
|
||||
|
||||
## Internals
|
||||
- All external usages of `KnownTranslationKeys` are now removed. All localized messages are now sent using `Translatable` objects (usually from `KnownTranslationFactory`).
|
||||
- All usages of NBT keys now use class constants instead of hardcoded strings (except for an occasional overlooked one).
|
||||
- Built-in commands now declare their names inside the class constructor, rather than accepting them as parameters. This improves code consistency.
|
||||
- Commands now use an array for permissions internally, instead of a string separated by `;`.
|
||||
- Make use of `Item->canStackWith()` instead of `Item->equals()` wherever possible, to make the code more readable.
|
||||
- Moved command timings to `Timings`.
|
||||
- Overriding of serializers and deserializers of items and blocks is now consistently disallowed. Since overriding stuff is non-cooperative, it doesn't make any sense in plugins, which must coexist with other plugins. If you want to modify the functionality of built-in stuff, you have several alternative options:
|
||||
- Use existing API (e.g. events, API methods) - most uses of overrides in PM4 and earlier were abuses that could have been done with events
|
||||
- Submit feature proposals or pull requests for new API to be added (e.g. new events)
|
||||
- Register completely custom items, and reuse behaviour from the item you want to mimic
|
||||
- Fork PocketMine-MP and alter the code directly - this way your plugins aren't pretending to be cooperative with other plugins
|
||||
- `level.dat`, block, item, entity, tile and chunk data are now tagged with a version ID as per `VersionInfo::WORLD_DATA_VERSION`. This allows the server to apply fixes to older worlds if necessary.
|
||||
- Protocol creative inventory entries are now cached in `CreativeInventoryCache` to improve performance of initial join and game mode changes.
|
||||
- Singletons in the `pocketmine\network\mcpe\convert` package have been centralized under `TypeConverter`. In the future, this will be injected where needed, allowing different converters to be used for different sessions (useful for multiversion).
|
||||
- `BlockStateDictionary` memory usage is now reduced from 9 MB to 3.5 MB using various techniques, including string reuse and binary-encoded states.
|
||||
- `NetworkSession` disconnect APIs now accept `Translatable|string` instead of `string` to allow localized disconnect messages.
|
||||
- `NetworkSession` disconnect methods have been altered to allow specifying a different disconnect reason and disconnection screen message.
|
||||
- `RuntimeBlockMapping` has been renamed to `BlockTranslator`.
|
||||
|
||||
# 5.0.1
|
||||
Released 3rd June 2023.
|
||||
|
||||
## Changes
|
||||
- [`ext-pmmpthread` version 6.0.1](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.0.1) is now required (for bug fixes).
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when breaking blocks placed in the same session (mishandled default block states).
|
||||
- Fixed spore blossoms not dropping when broken.
|
||||
- Fixed jukebox music not stopping when destroyed by an explosion.
|
||||
|
||||
## Documentation
|
||||
- Added documentation for `BlockSpreadEvent->__construct()` parameters.
|
52
changelogs/5.1.md
Normal file
52
changelogs/5.1.md
Normal file
@ -0,0 +1,52 @@
|
||||
# 5.1.0
|
||||
Released 7th June 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.0**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.0.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.0.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 5.1.1
|
||||
Released 7th June 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed blockstates being saved with the wrong version ID for 1.20.0.
|
||||
|
||||
# 5.1.2
|
||||
Released 9th June 2023.
|
||||
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.22.1](https://github.com/pmmp/PocketMine-MP/blob/4.22.1/changelogs/4.22.md#4221) - Teleportation client bug workarounds
|
||||
|
||||
This release contains no other changes.
|
||||
|
||||
# 5.1.3
|
||||
Released 1st July 2023.
|
||||
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.22.2](https://github.com/pmmp/PocketMine-MP/blob/4.22.2/changelogs/4.22.md#4222) - Authentication time bomb fix
|
||||
|
||||
## General
|
||||
- Updated logos to new RGB-style logo. Thanks to @MrCakeSlayer and @HBIDamian for their efforts.
|
||||
- Improved error messages generated by the world system when some version tags are missing from `level.dat` in Bedrock worlds.
|
||||
- Outsourced Composer dependencies now only receive patch updates automatically (pinned using the `~` constraint).
|
||||
- Minor and major updates now require manually updating `composer.json`, to ensure that the plugin API is not broken by libraries getting randomly updated from one patch release to the next.
|
||||
|
||||
## Documentation
|
||||
- Updated doc comment for `Player->setGamemode()` to remove outdated information.
|
||||
- Added documentation for the `$clickVector` parameter of `Block->onInteract()` to specify that it is relative to the block's position.
|
||||
- Added missing `@required` tag for `BlockStateUpgradeSchemaModelBlockRemap->newState`.
|
||||
|
||||
## Fixes
|
||||
- Fixed blue candles not appearing in the creative inventory.
|
||||
- Fixed server crash when block-picking candle cakes.
|
||||
- `World->useItemOn()` now ensures that the `$clickVector` components are always in the range of 0-1. Previously, any invalid values were accepted, potentially leading to a crash.
|
46
changelogs/5.10.md
Normal file
46
changelogs/5.10.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 5.10.0
|
||||
Released 14th December 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.50**
|
||||
|
||||
This is a minor feature release, including new gameplay features and minor performance improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- PHP 8.2 is now used by default. PHP 8.1 is still supported, but will be removed in a future 5.x release.
|
||||
- Improved timings reports by removing `Breakdown` timings group. This group serves no purpose with tree timings and made for confusing reading.
|
||||
|
||||
## Performance
|
||||
- Improved performance of `Block::encodeFullState()` in most conditions. This in turn improves performance of `World::setBlock()` and `World::setBlockAt()`.
|
||||
- Improved network compression performance by avoiding unnecessary object allocations.
|
||||
- Timings now report time spent in individual `Snooze` handlers, making it easier to debug performance issues.
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Implemented crop growth speed modifiers.
|
||||
- The following things now positively affect crop growth speed:
|
||||
- Being planted on or being adjacent to farmland (hydrated farmland offers a larger benefit than dry farmland)
|
||||
- Potential light level of at least 9
|
||||
- Being planted in rows with space between them (or a different type of crop)
|
||||
- The following things now negatively affect crop growth speed:
|
||||
- Improper arrangement (e.g. the same crop on all sides)
|
||||
- Insufficient light level (below 9)
|
||||
- Poorly arranged crops will grow slower in this version. Past versions behaved as if crops were always planted in ideal conditions.
|
||||
- Crops planted in ideal conditions will grow at the same speed as before.
|
||||
|
||||
### Items
|
||||
- Added the following new items:
|
||||
- All types of Smithing Template
|
||||
- Pitcher Pod is now correctly registered. In previous versions, it was mapped to the Pitcher Crop block, causing incorrect name display in commands.
|
||||
|
||||
## Internals
|
||||
- Cleaned up various getter usages where direct property access is possible.
|
||||
- Avoided unnecessary repeated getter calls in some loops.
|
||||
- `NetworkSession` may now track `string` instead of `CompressBatchPromise` when a batch was synchronously compressed. This significantly reduces object allocations and improves performance.
|
||||
- `NetworkSession` now sends less information to clients on login validation failure. This avoids leaking potentially sensitive error information to clients.
|
||||
- Clients can correlate their disconnects with server-side logs using the `Error ID` shown on the disconnect screen.
|
45
changelogs/5.11.md
Normal file
45
changelogs/5.11.md
Normal file
@ -0,0 +1,45 @@
|
||||
# 5.11.0
|
||||
Released 7th February 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.60**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.60.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.60.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed `tools/generate-item-upgrade-schema.php` not correctly handling items whose IDs were changed multiple times.
|
||||
- Fixed `ServerKiller` not working correctly in some cases (incorrectly handled wake-up conditions).
|
||||
- `ItemBlock`s of `Air` blocks are now always considered as "null" items regardless of count, and don't occupy inventory slots.
|
||||
|
||||
## Internals
|
||||
- Restructured GitHub Actions CI workflows to make them easier to maintain (no need to update PHP versions in multiple places anymore).
|
||||
- GitHub Actions CodeStyle workflow now uses php-cs-fixer 3.49.x.
|
||||
- Dependabot updates are now processed weekly instead of daily.
|
||||
|
||||
# 5.11.1
|
||||
Released 23rd February 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed subchunk count calculation in `ChunkSerializer` for non-overworld dimension (useful for dimension plugins).
|
||||
- Harden options used for processing JSON data, particularly on the network, to close security issues.
|
||||
|
||||
## Documentation
|
||||
- Fixed PHPStan signature for `Utils::cloneObjectArray()`.
|
||||
|
||||
## Internals
|
||||
- Updated GitHub Actions versions to get rid of deprecation warnings.
|
||||
|
||||
# 5.11.2
|
||||
Released 26th February 2024.
|
||||
|
||||
## Fixes
|
||||
- Added extra checks for `BookEditPacket` handling.
|
63
changelogs/5.12.md
Normal file
63
changelogs/5.12.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 5.12.0
|
||||
Released 28th February 2024
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.60**
|
||||
|
||||
This is a minor feature release, with a few new features and improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added a `--version` command-line option to display the server version and exit.
|
||||
|
||||
## Tools
|
||||
- Added `tools/generate-biome-ids.php` to generate `pocketmine\data\bedrock\BiomeIds`.
|
||||
- Fixed ordering of property values generated by `tools/generate-block-palette-spec.php`.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new classes have been added:
|
||||
- `utils\LightableTrait` - used by blocks with `getLit()` and `setLit()` methods
|
||||
- The following methods have been deprecated:
|
||||
- `Block->isSolid()` - this method returns confusing results which don't match expectations and no one really knows what it actually means
|
||||
- `CocoaBlock` now extends `Flowable` to match vanilla Minecraft behaviour.
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- `PluginManager->registerEvent()` now throws an exception when given a generator function for the event handler.
|
||||
- `PluginManager->registerEvents()` now throws an exception if any of the detected event handlers are generator functions. Use `@notHandler` to have the function ignored if intended.
|
||||
|
||||
### `pocketmine\promise`
|
||||
- The following methods have been added:
|
||||
- `public static Promise::all(list<Promise> $promises) : Promise` - returns a promise that is resolved once all given promises are resolved, or is rejected if any of the promises are rejected.
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- The following methods have been deprecated:
|
||||
- `AsyncWorker->getFromThreadStore()` - use class static properties for thread-local storage
|
||||
- `AsyncWorker->removeFromThreadStore()`
|
||||
- `AsyncWorker->saveToThreadStore()`
|
||||
|
||||
## Documentation
|
||||
- Improved documentation of various methods in `Block`.
|
||||
|
||||
## Gameplay
|
||||
- The following new items have been added:
|
||||
- Name Tag
|
||||
|
||||
## Internals
|
||||
- Removed specialization of shutdown logic for `Thread` vs `Worker` (no specialization is required).
|
||||
- Authentication system no longer accepts logins signed with the old Mojang root public key.
|
||||
- ID to enum mappings in `pocketmine\data` now use a new `match` convention to allow static analysis to ensure that all enum cases are handled.
|
||||
- Updated version of `pocketmine/bedrock-protocol` allows avoiding decoding of some itemstack data from the client in most cases, improving performance.
|
||||
|
||||
# 5.12.1
|
||||
Released 13th March 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed `Player Network Receive - Decompression` timings not being stopped correctly when receiving an uncompressed packet.
|
||||
|
||||
## Internals
|
||||
- Removed hardcoded batch packet size limit. This was already covered by other limits anyway.
|
16
changelogs/5.13.md
Normal file
16
changelogs/5.13.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.13.0
|
||||
Released 13th March 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.70**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.70.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.70.
|
||||
- Removed support for earlier versions.
|
94
changelogs/5.14.md
Normal file
94
changelogs/5.14.md
Normal file
@ -0,0 +1,94 @@
|
||||
# 5.14.0
|
||||
Released 5th April 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.70**
|
||||
|
||||
This is a minor feature release, including performance improvements, minor gameplay features, new API features, and various internal improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for a `--no-log-file` command-line option, which disables the creation of a `server.log` file.
|
||||
- **Use this with caution.** If you don't have another mechanism for collecting logs (e.g. Docker), this may make debugging harder.
|
||||
- Added support for automatic `server.log` rotation. When the `server.log` exceeds 32 MB, it will be renamed and moved to the `log_archive` folder in the server's data directory.
|
||||
- Files in the `log_archive` folder can be safely modified or deleted without stopping the server.
|
||||
- We suggest a cron job or similar to manage old log files (e.g. deleting or compressing them).
|
||||
- Added a new cache mechanism for `PocketMine-MP.phar`. This has several advantages:
|
||||
- Caches are now reused by all threads - this significantly reduces `/tmp` usage (previously every thread generated its own cache, wasting lots of space)
|
||||
- Dead cache files are automatically cleaned up by new servers - this means that a server crash loop won't flood `/tmp` anymore
|
||||
- `/status` now reports a more accurate number of threads on Windows.
|
||||
- Large resource packs are now able to be properly downloaded from the server.
|
||||
- Larger player skin sizes are now accepted by the server.
|
||||
- Improved logging from world providers to reduce spam when chunks contain invalid data.
|
||||
- Added more error logging for Anvil, PMAnvil and MCRegion worlds.
|
||||
- PHP deprecation warnings no longer cause the server to crash. This should make it easier for server owners to update to newer PHP versions.
|
||||
|
||||
## Performance
|
||||
- Improved world loading performance. This was achieved through a combination of changes:
|
||||
- Improvements to `BlockStateUpgrader` to avoid unnecessary work
|
||||
- Improvements to `BlockStateUpgradeSchema` to clean up stupid code
|
||||
- Improvements to `BlockStateReader` unused state handling
|
||||
- Optimizations to `RegistryTrait` (see below)
|
||||
- Improved performance of `RegistryTrait::__callStatic()` accessor by introducing a fast-path optimization. Ensure that you access registries with the correct function name case to benefit from this.
|
||||
- This improves the performance of `VanillaBlocks::WHATEVER()`, `VanillaItems`, etc.
|
||||
|
||||
## Tools
|
||||
- `tools/generate-blockstate-upgrade-schema.php` now supports generating schemas using `flattenedValueRemaps` (described in [BlockStateUpgradeSchema](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/4.0.0)).
|
||||
|
||||
## Gameplay
|
||||
- Added sounds for armour equipping and unequipping.
|
||||
- Added sound for picking berries from a sweet berry bush.
|
||||
|
||||
## API
|
||||
### `pocketmine\block\utils`
|
||||
- The following enum cases have been added:
|
||||
- `BannerPatternType::GLOBE`
|
||||
- `BannerPatternType::PIGLIN`
|
||||
|
||||
### `pocketmine\event\player`
|
||||
- The following classes have been added:
|
||||
- `PlayerResourcePackOfferEvent` - called before the server tells a connecting client which resource packs are available to download - allows customizing the pack list and other options
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following API methods have been added:
|
||||
- `public ArmorMaterial->getEquipSound() : ?\pocketmine\world\Sound` - returns the sound to play when this armour is equipped or unequipped
|
||||
- The following API methods have signature changes:
|
||||
- `ArmorMaterial->__construct()` now accepts an optional `?Sound $equipSound` parameter
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following API methods have signature changes:
|
||||
- `MainLogger->__construct()` now accepts `null` for the `$logFile` parameter - this disables the creation of a logger thread and log file
|
||||
- `MainLogger->__construct()` now accepts an optional `?string $logArchiveDir` parameter. If set, this enables log archiving in the specified directory when the current log file exceeds 32 MB.
|
||||
|
||||
## Dependencies
|
||||
- Now uses [`pocketmine/bedrock-block-upgrade-schema` version 4.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/4.0.0).
|
||||
- Now uses [`pmmp/ext-pmmpthread` version 6.1.0](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.1.0).
|
||||
- Now uses [`pocketmine/errorhandler` version 0.7.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.7.0).
|
||||
- Now uses [`pocketmine/raklib` version 1.1.0](https://github.com/pmmp/RakLib/releases/tag/1.1.0).
|
||||
- Now uses [`pocketmine/raklib-ipc` version 1.0.0](https://github.com/pmmp/RakLibIpc/releases/tag/1.0.0).
|
||||
|
||||
## Internals
|
||||
- (Re)Added support for RakLib packet ACK receipts. This was used to throttle resource pack sending and prevent network overloading.
|
||||
- Added `NetworkSession->sendDataPacketWithReceipt()` to make use of this feature.
|
||||
- `PacketSender` now requires an additional `?int $receiptId` parameter.
|
||||
- `ResourcePackPacketHandler` now uses `sendDataPacketWithReceipt()` to send resource packs, and delays sending the next chunk until the current one is acknowledged.
|
||||
- `ResourcePackPacketHandler` now accepts resource pack info directly in the constructor, instead of `ResourcePackManager`. This eases the implementation of `PlayerResourcePackOfferEvent`.
|
||||
- Increased `ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE` to 8 MB (previously 2 MB). While this weakens server security, it appears to be necessary to deal with extremely bloated Persona skins.
|
||||
- Increased max split packet parts accepted by `RakLib` to 512 (previously 128). Again, this is necessary to deal with extremely bloated Persona skins.
|
||||
- Added a new cache mechanism for `PocketMine-MP.phar`.
|
||||
- `ext-phar`'s default mechanism is extremely wasteful (generating a separate cache file per thread), and doesn't clean up after itself.
|
||||
- The new cache mechanism is shared between all threads, and automatically cleans up stale caches.
|
||||
- The phar stub (`build/server-phar-stub.php`) now converts the phar contents into a `.tar`, and decompresses all the files into `$TMPDIR/PocketMine-MP-phar-cache.<random>/`.
|
||||
- `phar://` URIs still work with this system, but `new Phar(__FILE__)` must be replaced by `new PharData(__FILE__)` within PocketMine-MP core code.
|
||||
- Backtraces from a `phar`'d server will now point to a location in the extracted phar cache, rather than the phar itself.
|
||||
- `block_factory_consistency_check` test (actually for `RuntimeBlockStateRegistry`) now stores less data, and is no longer affected by changes to internal state ID construction.
|
||||
|
||||
# 5.14.1
|
||||
Released 5th April 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed incorrect `pmmpthread` version check in server bootstrap.
|
16
changelogs/5.15.md
Normal file
16
changelogs/5.15.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.15.0
|
||||
Released 25th April 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.80**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.80.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.80.
|
||||
- Removed support for earlier versions.
|
26
changelogs/5.16.md
Normal file
26
changelogs/5.16.md
Normal file
@ -0,0 +1,26 @@
|
||||
# 5.16.0
|
||||
Released 13th June 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.0**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.0.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.0.
|
||||
- Removed support for earlier versions.
|
||||
- Generated permission docs are now included with every release.
|
||||
- Crash throttle message (which appears when the server crashed after being up for less than 120 seconds) now shows the server uptime as well as the wait time. This should make it clearer how the wait time is decided.
|
||||
|
||||
## Tools
|
||||
- Added `install-local-protocol.sh` script. This allows installing local copies of protocol dependencies without needing to create releases. Useful for integration testing when doing protocol updates.
|
||||
|
||||
## Fixes
|
||||
- Attacking an entity with a higher damage weapon while it's on attack cooldown from a lower damage weapon (switching) no longer causes additional knockback to the victim.
|
||||
- Wooden stairs can now be used as fuel in furnaces.
|
||||
- Fixed incorrect description of the permission `pocketmine.command.save.perform`.
|
38
changelogs/5.17.md
Normal file
38
changelogs/5.17.md
Normal file
@ -0,0 +1,38 @@
|
||||
# 5.17.0
|
||||
Released 10th July 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.2**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.2.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.2.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## API
|
||||
### `pocketmine\player`
|
||||
- The following methods have been added:
|
||||
- `public function closeAllForms() : void` - closes the current viewing form and forms in queue.
|
||||
|
||||
## Fixes
|
||||
- Bowl can now be used as fuel.
|
||||
- Bells always drops themselves even when using an incompatible tool.
|
||||
|
||||
# 5.17.1
|
||||
Released 13th August 2024.
|
||||
|
||||
## Documentation
|
||||
- Added a note about `BlockStateData::CURRENT_VERSION`.
|
||||
|
||||
## Fixes
|
||||
- Fixed anvil placement rotation to match vanilla.
|
||||
- Fixed outdated `BedrockWorldData` version, this was preventing use newer worlds.
|
||||
|
||||
## Internals
|
||||
- Dependabot: PHPStan and patch updates are now grouped into a single PR.
|
30
changelogs/5.18.md
Normal file
30
changelogs/5.18.md
Normal file
@ -0,0 +1,30 @@
|
||||
# 5.18.0
|
||||
Released 16th August 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.20**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.20.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.20.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Use `VISIBLE_MOB_EFFECTS` actor metadata property to send effect bubbles, this fixes effect bubbles not showing
|
||||
|
||||
# 5.18.1
|
||||
Released 3rd September 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed shift-crafting.
|
||||
- Blue Ice block no longer emits light & it's now dropped when mined with a tool with silk touch enchantment.
|
||||
|
||||
## Internals
|
||||
- Pull Requests from team members now get an approval automatically. This means that if a team member makes a PR, only one other approval should be needed.
|
||||
- Added [ShellCheck](https://github.com/koalaman/shellcheck) to the CI tests.
|
16
changelogs/5.19.md
Normal file
16
changelogs/5.19.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.19.0
|
||||
Released 21st September 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.30**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.30.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.30.
|
||||
- Removed support for earlier versions.
|
79
changelogs/5.2.md
Normal file
79
changelogs/5.2.md
Normal file
@ -0,0 +1,79 @@
|
||||
# 5.2.0
|
||||
Released 4th July 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.0**
|
||||
|
||||
This is a minor technical update, including changes to AsyncTask error handling and support for BedrockBlockUpgradeSchema version 3.0.0.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Core
|
||||
- [BedrockBlockUpgradeSchema version 3.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/3.0.0) is now supported.
|
||||
- [`ext-pmmpthread` version 6.0.4](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.0.4) is now required (bug fixes required to support technical changes in this release).
|
||||
|
||||
## Performance
|
||||
- Improved performance of `AsyncPool->submitTask()` and `AsyncPool->submitTaskToWorker()`.
|
||||
- Added new timings for `AsyncTask->onProgressUpdate()` and `AsyncTask->onCompletion()`.
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Added the following new blocks:
|
||||
- Cherry Button
|
||||
- Cherry Door
|
||||
- Cherry Fence
|
||||
- Cherry Fence Gate
|
||||
- Cherry Leaves
|
||||
- Cherry Log
|
||||
- Cherry Planks
|
||||
- Cherry Pressure Plate
|
||||
- Cherry Sign
|
||||
- Cherry Slab
|
||||
- Cherry Stairs
|
||||
- Cherry Trapdoor
|
||||
- Cherry Wood
|
||||
- Glow Lichen
|
||||
- Piglin Head
|
||||
|
||||
## Tools
|
||||
- `generate-block-upgrade-schema.php` now supports generating schemas a la BedrockBlockUpgradeSchema version 3.0.0, using `newFlattenedName` to reduce schema size.
|
||||
- Improved property remapping detection in `generate-block-upgrade-schema.php`. It now detects related properties with more confidence (even when multiple properties were change), and no longer considers unrelated properties as mapped (e.g. `mapped_type` and `deprecated` in 1.9->1.10).
|
||||
|
||||
## API
|
||||
### `pocketmine\data\bedrock\block`
|
||||
- The following new API methods have been added:
|
||||
- `public BlockStateData->toVanillaNbt() : CompoundTag` - returns the NBT for the blockstate without any PMMP extra metadata (`toNbt()` will normally include a `PMMPDataVersion` tag).
|
||||
|
||||
### `pocketmine\data\runtime`
|
||||
- The following new API methods have been added:
|
||||
- `public RuntimeDataDescriber->facingFlags(list<int> $faces) : void`
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- `AsyncTask->onRun()` no longer tolerates uncaught exceptions.
|
||||
- This means that any uncaught exceptions thrown from `AsyncTask->onRun()` will now crash the worker thread, and by extension, the server.
|
||||
- This change makes it easier to debug errors by detecting them earlier.
|
||||
- The following API methods have been deprecated:
|
||||
- `AsyncTask->onError()`
|
||||
|
||||
## Internals
|
||||
- `AsyncTask->progressUpdates` is now lazily initialized when a task publishes a progress update.
|
||||
- This was previously not possible due to technical limitations of the `ext-pmmpthread` extension.
|
||||
- This change improves performance of `AsyncPool->submitTask()` and `AsyncPool->submitTaskToWorker()`, as well as reducing the amount of work needed to check for progress updates on tick.
|
||||
- Errors in `AsyncWorker` now cascade and crash the whole server.
|
||||
- This makes it easier to debug errors by detecting them earlier.
|
||||
- This includes all types of unexpected errors, such as OOM, uncaught exceptions, etc.
|
||||
- This change is not expected to affect normal server operation, as worker threads are not expected to crash under normal circumstances.
|
||||
- `AsyncTask::$threadLocalStorage` now uses a plain `array` instead of `ArrayObject`. The `ArrayObject` was a workaround for `ext-pthreads` to prevent thread-locals getting copied to the worker thread, and is no longer necessary.
|
||||
- Regenerated `pocketmine\data\bedrock\item\ItemTypeNames` for Bedrock 1.20 (BC breaking, some item names have changed).
|
||||
- Fixed `build/generate-item-type-names.php` not including some newer blockitems, such as doors and hanging signs.
|
||||
|
||||
# 5.2.1
|
||||
Released 11th July 2023.
|
||||
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.22.3](https://github.com/pmmp/PocketMine-MP/blob/4.22.3/changelogs/4.22.md#4223) - Fixes for some crash issues
|
||||
|
||||
This release contains no other changes.
|
25
changelogs/5.20.md
Normal file
25
changelogs/5.20.md
Normal file
@ -0,0 +1,25 @@
|
||||
# 5.20.0
|
||||
Released 26th October 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.40**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.40.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.40.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed a bug in `tools/generate-blockstate-upgrade-schema.php` that caused it to fail on 1.21.40 with the new mushroom block changes.
|
||||
|
||||
# 5.20.1
|
||||
Released 31st October 2024.
|
||||
|
||||
## Fixes
|
||||
- Workaround old mob heads in world saves not being upgraded correctly and causing crashes.
|
112
changelogs/5.21.md
Normal file
112
changelogs/5.21.md
Normal file
@ -0,0 +1,112 @@
|
||||
# 5.21.0
|
||||
Released 3rd November 2024.
|
||||
|
||||
This is a minor feature release, including gameplay features and minor internals improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Gameplay
|
||||
- Added the following new blocks:
|
||||
- Campfire
|
||||
- Chiseled Copper
|
||||
- Chiseled Tuff
|
||||
- Chiseled Tuff Bricks
|
||||
- Copper Bulb
|
||||
- Copper Door
|
||||
- Copper Grate
|
||||
- Copper Trapdoor
|
||||
- Polished Tuff, Slabs, Stairs and Walls
|
||||
- Soul Campfire
|
||||
- Tuff Bricks, Slabs, Stairs and Walls
|
||||
- Tuff Slab, Stairs and Walls
|
||||
- Added the following new types of painting:
|
||||
- backyard
|
||||
- baroque
|
||||
- bouquet
|
||||
- cavebird
|
||||
- changing
|
||||
- cotan
|
||||
- endboss
|
||||
- fern
|
||||
- finding
|
||||
- humble
|
||||
- lowmist
|
||||
- meditative
|
||||
- orb
|
||||
- owlemons
|
||||
- passage
|
||||
- pond
|
||||
- prairie_ride
|
||||
- sunflowers
|
||||
- tides
|
||||
- unpacked
|
||||
- Armor slots are now properly restricted (on the server side) to only contain the appropriate type of armor or headwear.
|
||||
- Implemented Aqua Affinity enchantment. Since the server doesn't currently enforce any movement restrictions in water, this enchantment works based on client-side behaviour only.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public ChiseledBookshelf->getLastInteractedSlot() : ?ChiseledBookshelfSlot`
|
||||
- `public ChiseledBookshelf->setLastInteractedSlot(?ChiseledBookshelfSlot $lastInteractedSlot) : $this`
|
||||
- The following new classes have been added:
|
||||
- `utils\CopperMaterial` - interface implemented by all copper-like blocks with oxidation and waxed properties
|
||||
- `CopperBulb`
|
||||
- `CopperDoor`
|
||||
- `CopperGrate`
|
||||
- `CopperTrapdoor`
|
||||
- `SoulCampfire`
|
||||
- `Campfire`
|
||||
- The following enums have new cases:
|
||||
- `utils\BannerPatternType` has new cases `FLOW` and `GUSTER`
|
||||
|
||||
### `pocketmine\crafting`
|
||||
- The following enums have new cases:
|
||||
- `FurnaceType` has new cases `CAMPFIRE` and `SOUL_CAMPFIRE`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\CampfireCookEvent` - called when a campfire finishes cooking an item
|
||||
|
||||
### `pocketmine\inventory`
|
||||
- Added support for slot validators, which permit restricting the types of items a player can put into an inventory slot.
|
||||
- The following new classes have been added:
|
||||
- `transaction\action\SlotValidator` - interface
|
||||
- `transaction\action\CallbackSlotValidator` - class allowing a closure to be used for slot content validation
|
||||
- `SlotValidatedInventory` - implemented by inventories which support the use of slot validators
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->getCooldownTag() : ?string` - returns the cooldown group this item belongs to, used for ensuring that, for example, different types of goat horns all respect a general horn cooldown
|
||||
- The following new classes have been added:
|
||||
- `ItemCooldownTags` - list of cooldown group tags used by PocketMine-MP
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added
|
||||
- `CampfireSound` - sound made by campfires while lit
|
||||
|
||||
## Tools
|
||||
- `tools/blockstate-upgrade-schema-utils.php` (formerly `generate-blockstate-upgrade-schema.php`) has several improvements:
|
||||
- Support for generating `flattenedProperties` rules as per [BedrockBlockUpgradeSchema 5.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/5.0.0)
|
||||
- Improved criteria for flattened property selection to minimize the amount of rules required
|
||||
- Several subcommands are now available:
|
||||
- `generate` - generates a schema from provided data
|
||||
- `update` - regenerates an existing schema in a newer format
|
||||
- `update-all` - regenerates a folder of existing schemas in a newer format (useful for updating `BedrockBlockUpgradeSchema` en masse)
|
||||
- `test` - verifies that a schema produces the results expected by provided data
|
||||
|
||||
## Internals
|
||||
- Fixed incorrect visibility of `createEntity` in spawn eggs.
|
||||
- Added support for newer `BedrockBlockUpgradeSchema` in `BlockStateUpgrader`.
|
||||
|
||||
# 5.21.1
|
||||
Released 12th November 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when applying a cooldown to an item with 1 count.
|
||||
- Fixed garbage collector cycle count increase on player disconnect.
|
||||
- Fixed weakness effect being applied to all attack types, causing damage splash potions to become weaker.
|
||||
- Fixed Enchanted Golden Apple regeneration effect amplifier to match vanilla.
|
81
changelogs/5.3.md
Normal file
81
changelogs/5.3.md
Normal file
@ -0,0 +1,81 @@
|
||||
# 5.3.0
|
||||
Released 12th July 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.10.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Interim releases
|
||||
If you're upgrading directly from 5.1.x to 5.3.x, please also read the following changelogs, as the interim releases contain important changes:
|
||||
- [5.2.0](https://github.com/pmmp/PocketMine-MP/blob/5.2.0/changelogs/5.2.md#520)
|
||||
|
||||
## Included releases
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.23.0](https://github.com/pmmp/PocketMine-MP/blob/4.23.0/changelogs/4.23.md#4230) - Support for Minecraft: Bedrock Edition 1.20.10
|
||||
|
||||
## Internals
|
||||
- `BlockTypeNames`, `BlockStateNames`, `BlockStateStringValues` and `ItemTypeNames` in the `pocketmine\data\bedrock` package have BC-breaking changes to accommodate Bedrock 1.20.10.
|
||||
|
||||
# 5.3.1
|
||||
Released 14th July 2023.
|
||||
|
||||
## Included releases
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.23.1](https://github.com/pmmp/PocketMine-MP/blob/4.23.1/changelogs/4.23.md#4231) - Security fixes
|
||||
|
||||
## General
|
||||
- Updated `build/php` submodule to pmmp/PHP-Binaries@e0c918d1379465964acefd562d9e48f87cfc2c9e.
|
||||
|
||||
# 5.3.2
|
||||
Released 18th July 2023.
|
||||
|
||||
## Included releases
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.23.2](https://github.com/pmmp/PocketMine-MP/blob/4.23.2/changelogs/4.23.md#4232) - Fix for `sandboxId`-related login errors
|
||||
|
||||
## Documentation
|
||||
- Fixed documentation error in `StringToTParser`.
|
||||
|
||||
## Fixes
|
||||
- Fixed turtle helmet not being able to be unequipped.
|
||||
|
||||
## Internals
|
||||
- Armor pieces are no longer set back into the armor inventory if no change was made. This reduces the number of slot updates sent to clients, as well as avoiding unnecessary updates for armor pieces which have Unbreaking enchantments.
|
||||
|
||||
# 5.3.3
|
||||
Released 24th July 2023.
|
||||
|
||||
## Included releases
|
||||
**This release includes changes from the following releases:**
|
||||
- [4.23.3](https://github.com/pmmp/PocketMine-MP/blob/4.23.3/changelogs/4.23.md#4233) - Various bug fixes
|
||||
|
||||
## Fixes
|
||||
- Added a workaround for PM4 worlds with chunks corrupted by [Refaltor77/CustomItemAPI](https://github.com/Refaltor77/CustomItemAPI).
|
||||
- While this was not the fault of PocketMine-MP itself, a significant number of users were affected by this problem.
|
||||
- This error was not detected by PM4 due to missing validation of certain data which should not have existed in 1.12.
|
||||
- An error will now be logged when this corruption is detected, but the affected chunks should otherwise load normally.
|
||||
- Relaxed validation of expected 3D biome array counts per chunk in LevelDB worlds.
|
||||
- Vanilla Bedrock currently saves 24 palettes (and only 24 are required), but it saved 25, 32, or 64 biome palettes per chunk in older versions.
|
||||
- Core validation for these padding biomes was very strict, enforcing exact compliance with vanilla.
|
||||
- Since only 24 palettes are actually required, the remaining palettes may now be omitted irrespective of the chunk version.
|
||||
- An error will still be logged when this mistake is detected, but the affected chunks will otherwise load normally.
|
||||
- Fixed `/kill` not working on players who had (re)spawned in the 3 seconds immediately after (re)spawning (due to `noDamageTicks`).
|
||||
- Fixed `/kill` not working correctly for players with high levels of Health Boost or other health-altering effects.
|
||||
- Fixed netherite items being destroyed by lava.
|
||||
- Fireproof entities no longer display the burning animation when in fire or lava. This does not apply to creative players, who are immortal rather than being fireproof.
|
||||
- Fixed frosted ice melting in certain conditions which didn't match vanilla Bedrock.
|
||||
|
||||
# 5.3.4
|
||||
Released 1st August 2023.
|
||||
|
||||
## Included releases
|
||||
This release includes changes from the following releases:
|
||||
- [4.23.4](https://github.com/pmmp/PocketMine-MP/blob/4.23.4/changelogs/4.23.md#4234) - Item entity lag fix
|
||||
|
||||
This release contains no other significant changes.
|
133
changelogs/5.4.md
Normal file
133
changelogs/5.4.md
Normal file
@ -0,0 +1,133 @@
|
||||
# 5.4.0
|
||||
Released 1st August 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a minor feature update, including a handful of new gameplay features, new plugin APIs and improvements to error reporting.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Improved error reporting for async task and thread crashes.
|
||||
- Players may now have different creative inventories.
|
||||
|
||||
## Gameplay
|
||||
### General
|
||||
- Added support for 1.5-block height sneaking.
|
||||
- Fixed missing player arm swing and sounds when punching the air.
|
||||
|
||||
### Blocks
|
||||
- Implemented the following new blocks:
|
||||
- Big Dripleaf Head
|
||||
- Big Dripleaf Stem
|
||||
- Small Dripleaf
|
||||
- Acacia saplings now grow into acacia trees.
|
||||
- Fixed melon and pumpkin stems not attaching to the correct block when growing.
|
||||
- Various blocks now drop more items when mined with a compatible tool enchanted with Fortune.
|
||||
|
||||
### Items
|
||||
- Implemented Strong Slowness potion.
|
||||
- Implemented Fortune enchantment.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new classes have been added:
|
||||
- `utils\FortuneDropHelper` - utility methods for calculating the drop counts for Fortune-affected blocks
|
||||
- The following new API methods have been added:
|
||||
- `protected Block->getAdjacentSupportType(int $facing) : utils\SupportType` - returns the type of support provided by the block in the given direction on the adjacent face
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API constants have been added:
|
||||
- `Living::DEFAULT_KNOCKBACK_FORCE`
|
||||
- `Living::DEFAULT_KNOCKBACK_VERTICAL_LIMIT`
|
||||
|
||||
### `pocketmine\entity\animation`
|
||||
- `ConsumingItemAnimation` now accepts `Living` instances instead of just `Human`.
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `PlayerMissSwingEvent` - called when the player attempts the attack action (left click on desktop) without any target
|
||||
- This is possible thanks to the introduction of new flags in `PlayerAuthInputPacket` in Bedrock 1.20.10
|
||||
- The following new API methods have been added:
|
||||
- `public EntityDamageByEntityEvent->getVerticalKnockBackLimit() : float`
|
||||
- `public EntityDamageByEntityEvent->setVerticalKnockBackLimit(float $verticalKnockBackLimit) : void` - sets the max vertical velocity that can result from the victim being knocked back
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new API methods have been added:
|
||||
- `public Player->getCreativeInventory() : pocketmine\inventory\CreativeInventory`
|
||||
- `public Player->setCreativeInventory(pocketmine\inventory\CreativeInventory $inventory) : void`
|
||||
- `public Player->missSwing() : void` - performs actions associated with the attack action when there is no target (see `PlayerMissSwingEvent`)
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- Cancellation functionality has been removed from `AsyncTask`, as it didn't make any sense and wasn't used by anything for what it was intended for.
|
||||
- It broke sequential task execution - later tasks might depend on state from earlier tasks
|
||||
- It didn't actually cancel the task anyway - at best, it prevented it from running, but couldn't interrupt it (though interrupting a task does not make sense either)
|
||||
- The following API methods have been deprecated, and their functionality has been removed:
|
||||
- `AsyncTask->hasCancelledRun()`
|
||||
- `AsyncTask->cancelRun()`
|
||||
|
||||
## Internals
|
||||
- Uncaught exceptions and fatal errors in `AsyncTask`, threads extending `pocketmine\thread\Thread`, and `pocketmine\thread\Worker` are now recorded in crashdumps, making it significantly easier to debug errors in these areas.
|
||||
- JWT signature DER <-> raw conversions are now handled in-house using code in `JwtUtils`
|
||||
- Due to the simplicity of the conversion and only requiring a tiny subset of the ASN.1 spec, it didn't make much sense to introduce another dependency.
|
||||
- `fgrosse/phpasn1` is no longer required. This package was abandoned by its author and only used by PocketMine-MP for this one purpose.
|
||||
- Various usages of `Closure::fromCallable()` have been replaced by PHP 8.1 first-class callable syntax.
|
||||
- Blocks requiring support shifted to a "can be supported at" model, rather than "can be supported by".
|
||||
- This model reduces repeated logic when placing and performing nearby block updates (no need to hardcode facing everywhere).
|
||||
- In addition, this change facilitates the use of the newly introduced `Block->getAdjacentSupportType()` API method, reducing boilerplate support-type checking code.
|
||||
- Bell block code has been simplified and cleaned up.
|
||||
- `TallGrass` and `DoubleTallGrass` now use a shared `TallGrassTrait` to reduce code duplication.
|
||||
|
||||
# 5.4.1
|
||||
Released 8th August 2023.
|
||||
|
||||
## General
|
||||
- Updated translation data to [pmmp/Language 2.19.6](https://github.com/pmmp/Language/releases/tag/2.19.6).
|
||||
- [`ext-pmmpthread` 6.0.7](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.0.7) is now required (needed for bug fixes).
|
||||
|
||||
## Fixes
|
||||
- Fixed Podzol not dropping itself when mined with Silk Touch.
|
||||
- Fixed `World->getSafeSpawn()` not accepting positions below `y=0` (world height limit change).
|
||||
- Fixed `pocketmine\thread\Thread` and `pocketmine\thread\Worker` instances not logging any information when they crash.
|
||||
- Fixed `CraftItemEvent` not cloning returned items.
|
||||
|
||||
## Internals
|
||||
- Foreach by-reference is now disallowed via a custom PHPStan rule.
|
||||
|
||||
# 5.4.2
|
||||
Released 9th August 2023.
|
||||
|
||||
## Included releases
|
||||
- [4.23.5](https://github.com/pmmp/PocketMine-MP/blob/4.23.5/changelogs/4.23.md#4235) - Minor bug fixes
|
||||
|
||||
## Fixes
|
||||
- Fixed cake accepting candle placement when slices have already been eaten.
|
||||
- Fixed fire charges not lighting candles.
|
||||
|
||||
# 5.4.3
|
||||
Released 21st August 2023.
|
||||
|
||||
## Included releases
|
||||
- [4.23.6](https://github.com/pmmp/PocketMine-MP/blob/4.23.6/changelogs/4.23.md#4236) - Armor inventory client bug workaround
|
||||
|
||||
## Fixes
|
||||
- Fixed crashdumps not generating correctly on fatal errors.
|
||||
- Fixed `PotionCauldron::setPotionItem()` not validating the item type.
|
||||
- Fixed chorus fruit not considering teleport destinations below y=0.
|
||||
- Fixed cake dropping itself when mined.
|
||||
|
||||
# 5.4.4
|
||||
Released 6th September 2023.
|
||||
|
||||
## General
|
||||
- Crashdumps caused by non-phar plugins are now submitted to the Crash Archive, the same as other plugins. Previously, non-phar plugin crashes would not be submitted, causing maintainers to potentially miss important issues.
|
||||
|
||||
## Fixes
|
||||
- Fixed player Y coordinates sometimes being slightly below the top of the block they were standing on (floating point error due to subtracting eye height).
|
||||
- Fixed template slot of smithing tables not accepting any items.
|
||||
- `tools/generate-bedrock-data-from-packets.php` is now significantly less spammy when warning about duplicated recipes.
|
||||
- Fixed empty stack traces in `lastError` data of crashdumps.
|
156
changelogs/5.5-beta.md
Normal file
156
changelogs/5.5-beta.md
Normal file
@ -0,0 +1,156 @@
|
||||
# 5.5.0-BETA1
|
||||
Released 23rd August 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Dependencies
|
||||
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
|
||||
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
|
||||
|
||||
## Performance
|
||||
- Some events are now no longer fired if no handlers are registered.
|
||||
- This improves performance by avoiding unnecessary object allocations and function calls.
|
||||
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
|
||||
- Significantly improved performance of small moving entities, such as dropped items.
|
||||
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
|
||||
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
|
||||
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
|
||||
- This improves performance of collision detection for small entities, such as dropped items.
|
||||
|
||||
## Gameplay
|
||||
### General
|
||||
- Implemented enchanting using an enchanting table (yes, finally!)
|
||||
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
|
||||
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
|
||||
|
||||
### Blocks
|
||||
- The following new blocks have been implemented:
|
||||
- Pink Petals
|
||||
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
|
||||
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
|
||||
- Signs can now be edited by right-clicking them.
|
||||
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
|
||||
|
||||
### Items
|
||||
- The following new items have been implemented:
|
||||
- Enchanted Book
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
|
||||
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
|
||||
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
|
||||
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
|
||||
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
|
||||
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
|
||||
- `public BaseSign->isWaxed() : bool`
|
||||
- `public BaseSign->setWaxed(bool $waxed) : $this`
|
||||
- `public inventory\EnchantInventory->getInput() : Item`
|
||||
- `public inventory\EnchantInventory->getLapis() : Item`
|
||||
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
|
||||
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
|
||||
- The following API methods have signature changes:
|
||||
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
|
||||
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- The following new classes have been added:
|
||||
- `PinkPetals`
|
||||
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
|
||||
- The following classes have been deprecated:
|
||||
- `WeightedPressurePlateLight`
|
||||
- `WeightedPressurePlateHeavy`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
|
||||
- `public Human->setEnchantmentSeed(int $seed) : void`
|
||||
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
|
||||
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
|
||||
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
|
||||
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
|
||||
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
|
||||
- The following new API methods have been added:
|
||||
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
|
||||
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- The following new classes have been added:
|
||||
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
|
||||
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
|
||||
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
|
||||
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
|
||||
- `public ToolTier->getEnchantability() : int`
|
||||
- The following API methods have signature changes:
|
||||
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
|
||||
- The following new classes have been added:
|
||||
- `ArmorMaterial` - container for shared armor properties
|
||||
- `VanillaArmorMaterials` - all vanilla armor materials
|
||||
- `EnchantedBook` - represents an enchanted book item
|
||||
|
||||
### `pocketmine\item\enchantment`
|
||||
- The following new classes have been added:
|
||||
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
|
||||
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
|
||||
- `EnchantingOption` - represents an option on the enchanting table menu
|
||||
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
|
||||
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
|
||||
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
|
||||
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
|
||||
- The following classes have been deprecated
|
||||
- `ItemFlags`
|
||||
- The following API methods have been added:
|
||||
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
|
||||
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
|
||||
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
|
||||
- The following API methods have signature changes:
|
||||
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
|
||||
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
|
||||
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
|
||||
- The following API methods have been deprecated:
|
||||
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->hasPrimaryItemType()`
|
||||
- `Enchantment->hasSecondaryItemType()`
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- The following new API methods have been added:
|
||||
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
|
||||
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
|
||||
- The following API methods have been deprecated:
|
||||
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
|
||||
|
||||
### `pocketmine\world\generator`
|
||||
- The following new API methods have been added:
|
||||
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `PressurePlateActivateSound`
|
||||
- `PressurePlateDeactivateSound`
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters
|
162
changelogs/5.5.md
Normal file
162
changelogs/5.5.md
Normal file
@ -0,0 +1,162 @@
|
||||
# 5.5.0
|
||||
Released 6th September 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.10**
|
||||
|
||||
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Dependencies
|
||||
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
|
||||
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
|
||||
|
||||
## Performance
|
||||
- Some events are now no longer fired if no handlers are registered.
|
||||
- This improves performance by avoiding unnecessary object allocations and function calls.
|
||||
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
|
||||
- Significantly improved performance of small moving entities, such as dropped items.
|
||||
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
|
||||
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
|
||||
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
|
||||
- This improves performance of collision detection for small entities, such as dropped items.
|
||||
|
||||
## Gameplay
|
||||
### General
|
||||
- Implemented enchanting using an enchanting table (yes, finally!)
|
||||
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
|
||||
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
|
||||
|
||||
### Blocks
|
||||
- The following new blocks have been implemented:
|
||||
- Pink Petals
|
||||
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
|
||||
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
|
||||
- Signs can now be edited by right-clicking them.
|
||||
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
|
||||
|
||||
### Items
|
||||
- The following new items have been implemented:
|
||||
- Enchanted Book
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
|
||||
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
|
||||
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
|
||||
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
|
||||
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
|
||||
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
|
||||
- `public BaseSign->isWaxed() : bool`
|
||||
- `public BaseSign->setWaxed(bool $waxed) : $this`
|
||||
- `public inventory\EnchantInventory->getInput() : Item`
|
||||
- `public inventory\EnchantInventory->getLapis() : Item`
|
||||
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
|
||||
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
|
||||
- The following API methods have signature changes:
|
||||
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
|
||||
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
|
||||
- The following new classes have been added:
|
||||
- `PinkPetals`
|
||||
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
|
||||
- The following classes have been deprecated:
|
||||
- `WeightedPressurePlateLight`
|
||||
- `WeightedPressurePlateHeavy`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
|
||||
- `public Human->setEnchantmentSeed(int $seed) : void`
|
||||
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
|
||||
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
|
||||
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
|
||||
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
|
||||
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
|
||||
- The following new API methods have been added:
|
||||
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
|
||||
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- The following new classes have been added:
|
||||
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
|
||||
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
|
||||
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
|
||||
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
|
||||
- `public ToolTier->getEnchantability() : int`
|
||||
- The following API methods have signature changes:
|
||||
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
|
||||
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
|
||||
- The following new classes have been added:
|
||||
- `ArmorMaterial` - container for shared armor properties
|
||||
- `VanillaArmorMaterials` - all vanilla armor materials
|
||||
- `EnchantedBook` - represents an enchanted book item
|
||||
|
||||
### `pocketmine\item\enchantment`
|
||||
- The following new classes have been added:
|
||||
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
|
||||
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
|
||||
- `EnchantingOption` - represents an option on the enchanting table menu
|
||||
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
|
||||
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
|
||||
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
|
||||
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
|
||||
- The following classes have been deprecated
|
||||
- `ItemFlags`
|
||||
- The following API methods have been added:
|
||||
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
|
||||
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
|
||||
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
|
||||
- The following API methods have signature changes:
|
||||
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
|
||||
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
|
||||
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
|
||||
- The following API methods have been deprecated:
|
||||
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
|
||||
- `Enchantment->hasPrimaryItemType()`
|
||||
- `Enchantment->hasSecondaryItemType()`
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- The following new API methods have been added:
|
||||
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
|
||||
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
|
||||
- The following API methods have been deprecated:
|
||||
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
|
||||
|
||||
### `pocketmine\world\generator`
|
||||
- The following new API methods have been added:
|
||||
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `PressurePlateActivateSound`
|
||||
- `PressurePlateDeactivateSound`
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters
|
||||
|
||||
## Internals
|
||||
- Various `TypeIdMap` classes in the `pocketmine\data\bedrock` package now use the new `IntSaveIdMapTrait` to reduce code duplication.
|
||||
- Added a new `ServerProperties` class containing constants for all known `server.properties` keys.
|
||||
- Added a new `YmlServerProperties` class containing generated constants for all known `pocketmine.yml` keys. These keys can be used with `Config->getNested()`.
|
||||
|
34
changelogs/5.6.md
Normal file
34
changelogs/5.6.md
Normal file
@ -0,0 +1,34 @@
|
||||
# 5.6.0
|
||||
Released 20th September 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.30**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.30.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.30.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed support conditions for hanging roots, cave vines and dead bushes.
|
||||
- Fixed connection conditions for fences, glass panes, iron bars, and walls.
|
||||
|
||||
# 5.6.1
|
||||
Released 20th October 2023.
|
||||
|
||||
## Performance
|
||||
- Improved performance of cactus growth by disabling neighbour updates when only the age property was updated. While this isn't a perfect solution, it provides significant performance gains for servers with large cactus farms.
|
||||
|
||||
## Fixes
|
||||
- Fixed `tools/generate-bedrock-data-from-packets.php` incorrectly interpreting network meta as blockstates in some cases (broken crafting recipes).
|
||||
- Fixed crafting recipes involving beds, skulls and some other items not working correctly (incorrectly interpreted data).
|
||||
- Fixed crashes when flower pot or cauldron blockentities exist in places where they shouldn't (leftovers from upgraded PM3 worlds).
|
||||
- Fixed `Entity->broadcastSound()` not firing `WorldSoundEvent` (bypassing internal sound system).
|
||||
- Fixed wooden signs, buttons and doors not being able to be used as furnace fuel.
|
||||
- Fixed bone meal and tools only working when used on the top side of dirt and grass. Bone meal now works from any side, and tools work on any side except the bottom.
|
27
changelogs/5.7.md
Normal file
27
changelogs/5.7.md
Normal file
@ -0,0 +1,27 @@
|
||||
# 5.7.0
|
||||
Released 26th October 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.40**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.40.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.40.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed `cartography_table`, `smithing_table`, `stripped_cherry_log` and `stripped_cherry_wood` not working in `StringToItemParser`.
|
||||
- Fixed `Promise<null>::onCompletion()` always calling the reject handler if the promise was already completed.
|
||||
|
||||
# 5.7.1
|
||||
Released 1st November 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed non-reentrant-safe code in `PermissionManager` and various other subscriber subsystems.
|
||||
- These issues caused server crashes when deleting a subscriber indirectly triggered the deletion of other subscribers (e.g. due to the GC activating in `unset()`).
|
138
changelogs/5.8.md
Normal file
138
changelogs/5.8.md
Normal file
@ -0,0 +1,138 @@
|
||||
# 5.8.0
|
||||
Released 1st November 2023.
|
||||
|
||||
**Borked release, forgot to merge branches.**
|
||||
|
||||
# 5.8.1
|
||||
Released 1st November 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.40**
|
||||
|
||||
This is a minor feature release, including new gameplay features, various performance improvements to internal `World` and `Block` systems, and changes to the API.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Neighbour block updates now have a separate timer for timings. Previously, these were counted under `Scheduled Block Updates`, which was misleading.
|
||||
|
||||
## Performance
|
||||
- `LightUpdate` now avoids attempting to propagate back in the same direction the light came from. This produces a small performance improvement of around 6% in light propagation.
|
||||
- Improved worst-case (non-cached) performance of `World::getCollisionBlocks()` (and its successor `World::getBlockCollisionBlocks()`).
|
||||
- While 5.5.0 introduced caching at the `World` level for AABBs, the cache was rarely useful due to entity and player movement being too unpredictable. This meant that most users saw a performance degradation with lots of moving entities, except in specific situations.
|
||||
- Performance for fetching non-cached AABBs for a cell is now improved by 2x. Overall performance benefit to a server depends on the number of entities and players.
|
||||
- Added cache for hydrated farmland blocks to remember the last known location of nearby water.
|
||||
- If nearby water sources are not changed, this cache allows hydrated farmland to completely avoid checking up to 161 nearby blocks for water after the first check.
|
||||
- Tests with large wheat farms showed a 25% performance improvement in overall server performance compared to previous 5.x versions.
|
||||
- Migrated various internal enums to native PHP 8.1 enums. Bypassing magic `__callStatic()` accessors improved performance in many areas, although it's hard to quantify the exact benefit.
|
||||
- Made use of `Facing::OFFSET` constant in various places to avoid unnecessary `Vector3` and `Position` object allocations. Many pathways benefit from this, including neighbour block updates (due to faster `Block::getSide()` and less useless objects).
|
||||
- Avoided clearing block AABB caches except when strictly necessary. Previously, the cache was wiped every time blocks were read from the world, making them mostly useless.
|
||||
- Avoided random updates on blocks which have reached their final state, such as fully-grown crops. This produces a minimal performance improvement.
|
||||
- Removed useless checks in some `World` hot paths.
|
||||
|
||||
## API
|
||||
### General
|
||||
- All enums have been migrated to native PHP 8.1 enums.
|
||||
- For now, the old APIs and accessors are still usable (via `LegacyEnumShimTrait`), but these will be removed in the next major release.
|
||||
- `EnumTrait` has been deprecated, and will be removed in the next major release.
|
||||
- Migration for most plugin developers will simply involve deleting `()` from the end of enum case usages, which is a trivial change and also improves performance.
|
||||
- Plugin usages of `EnumTrait` are encouraged to move to native enums, optionally using `LegacyEnumShimTrait` to provide backwards compatibility.
|
||||
- See [this code](https://github.com/pmmp/PocketMine-MP/blob/9832fe899f13a8ea47cc9d73de7088f7775a12f5/src/block/utils/DyeColor.php#L85-L107) for an example of how to associate properties with enum cases (since native enums don't support this directly).
|
||||
- Thanks to improvements in `RuntimeDataDescriber`, any native enum can now be used as a custom block's state property.
|
||||
|
||||
### `pocketmine\block`
|
||||
- The following classes have been added:
|
||||
- `utils\AgeableTrait` - used by blocks which have an age property, such as crops
|
||||
- `utils\StaticSupportTrait` - used by blocks which have the same support requirements regardless of their state, such as crops
|
||||
|
||||
### `pocketmine\data\runtime`
|
||||
- The following API methods have been added:
|
||||
- `public RuntimeDataDescriber->boundedIntAuto(int $min, int $max, int &$value) : void` - similar to `boundedInt()`, but automatically calculates the needed number of bits based on the given min/max
|
||||
- `public RuntimeDataDescriber->enum(T extends \UnitEnum &$case) : void` - describes any native PHP 8.1 enum case
|
||||
- `public RuntimeDataDescriber->enumSet(array<int, T extends \UnitEnum> &$set, array<int, T extends \UnitEnum> $allCases) : void` - describes a set of enum cases (similar to bitflags)
|
||||
- The following API methods have been deprecated:
|
||||
- `RuntimeDataDescriber->bellAttachmentType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->boundedInt()` - use `boundedIntAuto()` instead
|
||||
- `RuntimeDataDescriber->brewingStandSlots()` - use `enumSet()` instead
|
||||
- `RuntimeDataDescriber->copperOxidation()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->coralType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->dirtType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->dripleafState()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->dyeColor()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->froglightType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->leverFacing()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->medicineType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->mobHeadType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->mushroomBlockType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->potionType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->slabType()` - use `enum()` instead
|
||||
- `RuntimeDataDescriber->suspiciousStewType()` - use `enum()` instead
|
||||
|
||||
### `pocketmine\player`
|
||||
- `TitleID` is now included in `PlayerInfo` metadata for plugin consumption.
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following API methods have been added:
|
||||
- `public World->getBlockCollisionBoxes(AxisAlignedBB $bb) : list<AxisAlignedBB>` - similar to `getCollisionBoxes` but exclusively for blocks, avoiding the need for conditionally useless parameters
|
||||
- The following API methods have been deprecated:
|
||||
- `World->getCollisionBoxes()` - use `getBlockCollisionBoxes()` instead (alongside `getCollidingEntities()` if entity collision boxes are also required)
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following classes have been deprecated:
|
||||
- `EnumTrait` - use native PHP 8.1 enums instead
|
||||
- The following classes have been added:
|
||||
- `LegacyEnumShimTrait` - can be `use`d by native PHP 8.1 enums to provide the same API as `EnumTrait`
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Implemented the following blocks:
|
||||
- Amethyst
|
||||
- Amethyst Cluster
|
||||
- Chiseled Bookshelf
|
||||
- Crimson Roots
|
||||
- Pitcher Crop
|
||||
- Pitcher Plant
|
||||
- Torchflower
|
||||
- Torchflower Crop
|
||||
- Warped Roots
|
||||
|
||||
### Items
|
||||
- Implemented the following items:
|
||||
- Pitcher Pod
|
||||
- Torchflower Seeds
|
||||
|
||||
## Internals
|
||||
- `Farmland` block now has an extra property (`waterPositionIndex`) stored in its blockstate ID to track the position of nearby water. This property is not saved to disk, and is only used for caching.
|
||||
- The format of internal blockstate ID has been updated.
|
||||
- The lower `11` bits are now reserved for state data (previously `8` bits). This increase facilitates the new cache for `Farmland` blocks.
|
||||
- The state data bits are now XOR'd with the `xxh3` of the block's type ID, instead of being directly XOR'd with the type ID.
|
||||
- This XOR improves the distribution of the lower bits of the blockstate ID, which is important for hashtable indexing to minimize collisions.
|
||||
- Previously, the lower bits were XOR'd with the type ID directly, but the effectiveness of this reduced as more state data bits were added.
|
||||
- `xxh3` produces consistently good results for this purpose regardless of the number of state data bits allocated.
|
||||
- Hash collisions with blockstate IDs are reduced by 50% with this change, which is a happy side effect.
|
||||
- This is backwards-incompatible, so anyone saving internal blockstate IDs on disk or in a DB will be burned by this change (though they shouldn't have been doing that anyway).
|
||||
- Removed code generation step for `RuntimeDataDescriber` enum serialization. All described enums now use PHP 8.1 native enums, which can be described without codegen using `RuntimeDataDescriber->enum()`.
|
||||
- Added `DeprecatedLegacyEnumAccessRule` custom PHPStan rule to flag legacy `EnumTrait` case accessors.
|
||||
- Cleaned up remaining hardcoded `Config` keys in `SetupWizard`. These usages now use auto-generated constants like the rest of the codebase.
|
||||
|
||||
# 5.8.2
|
||||
Released 9th November 2023.
|
||||
|
||||
## Performance
|
||||
- Improved performance of small packet zero-compression (unintended use of slow zlib compressor instead of fast libdeflate one).
|
||||
- This affected the majority of outbound packets, as most packets are below the 256-byte threshold for compression.
|
||||
- This faster method is over 20x faster than the old method, producing noticeable performance gains for large servers.
|
||||
|
||||
## Fixes
|
||||
- Fixed melons and pumpkins not growing.
|
||||
- Fixed melon and pumpkin stems not attaching to the grown melon/pumpkin.
|
||||
- Fixed iron and gold ores not being affected by the Fortune enchantment.
|
||||
- Fixed ancient debris burning in lava.
|
||||
- Fixed sign (front) text loading from vanilla world saves (back text is not yet supported).
|
||||
|
||||
## Internals
|
||||
- Removed bogus optimization from `tools/generate-blockstate-upgrade-schema.php` that could cause incorrect `remappedStates` generation when some of the states stayed under the old ID.
|
||||
- Fixed possible crash in `BlockStateUpgrader` name flattening rule handling with invalid blockstate NBT data.
|
30
changelogs/5.9.md
Normal file
30
changelogs/5.9.md
Normal file
@ -0,0 +1,30 @@
|
||||
# 5.9.0
|
||||
Released 6th December 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.50**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.50.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.50.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed `pitcher_plant` and `pitcher_pod` not being accepted by `StringToItemParser` (and therefore not being usable in commands).
|
||||
- Rotation of items in item frames in worlds from newer versions of Bedrock is now correctly loaded.
|
||||
- Fixed possible crash in block update sending if a chunk was unloaded during a previous chunk's block update syncing.
|
||||
- Fixed `AsyncTask::fetchLocal()` throwing an exception if `null` was stored in the local storage.
|
||||
|
||||
## Documentation
|
||||
- `Server::prepareBatch()` is now correctly marked as `@internal`.
|
||||
- Updated documentation for `Server::prepareBatch()` to accurately reflect its behaviour.
|
||||
- Fixed incorrect path in doc comments of `EnumTrait` and `RegistryTrait`.
|
||||
|
||||
## Internals
|
||||
- Added PHP 8.3 to the test matrix. This has not been thoroughly tested yet, so it should only be used for testing purposes.
|
@ -22,7 +22,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pthreads": "^5.1",
|
||||
"ext-pmmpthread": "^6.1.0",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
@ -31,34 +31,31 @@
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"fgrosse/phpasn1": "^2.3",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~2.1.0+bedrock-1.19.80",
|
||||
"pocketmine/bedrock-data": "~2.2.0+bedrock-1.19.80",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.2.0+bedrock-1.19.80",
|
||||
"pocketmine/bedrock-protocol": "~21.0.0+bedrock-1.19.80",
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~5.0.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-data": "~2.14.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.13.0+bedrock-1.21.40",
|
||||
"pocketmine/bedrock-protocol": "~35.0.0+bedrock-1.21.40",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.3.0",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/errorhandler": "^0.7.0",
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.5.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
"pocketmine/nbt": "^0.3.2",
|
||||
"pocketmine/raklib": "^0.15.0",
|
||||
"pocketmine/raklib-ipc": "^0.2.0",
|
||||
"pocketmine/snooze": "^0.4.0",
|
||||
"ramsey/uuid": "^4.1",
|
||||
"symfony/filesystem": "^5.4"
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
"pocketmine/raklib": "~1.1.0",
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.7.0",
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.15",
|
||||
"phpstan/phpstan": "1.11.11",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
"phpunit/phpunit": "^10.5.24"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@ -86,11 +83,14 @@
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
],
|
||||
"update-registry-annotations": [
|
||||
"update-codegen": [
|
||||
"@php build/generate-bedrockdata-path-consts.php",
|
||||
"@php build/generate-biome-ids.php",
|
||||
"@php build/generate-block-serializer-consts.php vendor/pocketmine/bedrock-data/canonical_block_states.nbt",
|
||||
"@php build/generate-item-type-names.php vendor/pocketmine/bedrock-data/required_item_list.json",
|
||||
"@php build/generate-known-translation-apis.php",
|
||||
"@php build/generate-pocketmine-yml-property-consts.php",
|
||||
"@php build/generate-registry-annotations.php src"
|
||||
],
|
||||
"update-translation-apis": [
|
||||
"@php build/generate-known-translation-apis.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
1338
composer.lock
generated
1338
composer.lock
generated
File diff suppressed because it is too large
Load Diff
21
install-local-protocol.sh
Normal file
21
install-local-protocol.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "--- Installing BedrockProtocol, BedrockData, BedrockBlockUpgradeSchema, BedrockItemUpgradeSchema dependencies from local repositories."
|
||||
echo "--- This allows you to perform integration tests using PocketMine-MP, without immediately publishing new versions of these libraries."
|
||||
|
||||
cp composer.json composer-local-protocol.json
|
||||
cp composer.lock composer-local-protocol.lock
|
||||
|
||||
export COMPOSER=composer-local-protocol.json
|
||||
composer config repositories.bedrock-protocol path ../deps/BedrockProtocol
|
||||
composer config repositories.bedrock-data path ../deps/BedrockData
|
||||
composer config repositories.bedrock-block-upgrade-schema path ../deps/BedrockBlockUpgradeSchema
|
||||
composer config repositories.bedrock-item-upgrade-schema path ../deps/BedrockItemUpgradeSchema
|
||||
|
||||
composer require pocketmine/bedrock-protocol:*@dev pocketmine/bedrock-data:*@dev pocketmine/bedrock-block-upgrade-schema:*@dev pocketmine/bedrock-item-upgrade-schema:*@dev
|
||||
|
||||
composer install
|
||||
|
||||
echo "--- Local dependencies have been successfully installed."
|
||||
echo "--- This script does not modify composer.json. To go back to the original dependency versions, simply run 'composer install'."
|
||||
|
@ -10,7 +10,9 @@ includes:
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||
|
||||
@ -38,13 +40,13 @@ parameters:
|
||||
- build/php
|
||||
dynamicConstantNames:
|
||||
- pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD
|
||||
- pocketmine\VersionInfo::BUILD_CHANNEL
|
||||
- pocketmine\DEBUG
|
||||
- pocketmine\IS_DEVELOPMENT_BUILD
|
||||
stubFiles:
|
||||
- tests/phpstan/stubs/JsonMapper.stub
|
||||
- tests/phpstan/stubs/leveldb.stub
|
||||
- tests/phpstan/stubs/phpasn1.stub
|
||||
- tests/phpstan/stubs/pthreads.stub
|
||||
- tests/phpstan/stubs/pmmpthread.stub
|
||||
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
|
||||
staticReflectionClassNamePatterns:
|
||||
- "#^COM$#"
|
||||
|
52
src/BootstrapOptions.php
Normal file
52
src/BootstrapOptions.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
/**
|
||||
* Constants for all the command-line options that PocketMine-MP supports.
|
||||
* Other options not listed here can be used to override server.properties and pocketmine.yml values temporarily.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class BootstrapOptions{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/** Disables the setup wizard on first startup */
|
||||
public const NO_WIZARD = "no-wizard";
|
||||
/** Force-disables console text colour and formatting */
|
||||
public const DISABLE_ANSI = "disable-ansi";
|
||||
/** Force-enables console text colour and formatting */
|
||||
public const ENABLE_ANSI = "enable-ansi";
|
||||
/** Path to look in for plugins */
|
||||
public const PLUGINS = "plugins";
|
||||
/** Path to store and load server data */
|
||||
public const DATA = "data";
|
||||
/** Shows basic server version information and exits */
|
||||
public const VERSION = "version";
|
||||
/** Disables writing logs to server.log */
|
||||
public const NO_LOG_FILE = "no-log-file";
|
||||
}
|
@ -30,6 +30,7 @@ use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties as Yml;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function arsort;
|
||||
use function count;
|
||||
@ -109,7 +110,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
private function init(ServerConfigGroup $config) : void{
|
||||
$this->memoryLimit = $config->getPropertyInt("memory.main-limit", 0) * 1024 * 1024;
|
||||
$this->memoryLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_LIMIT, 0) * 1024 * 1024;
|
||||
|
||||
$defaultMemory = 1024;
|
||||
|
||||
@ -127,7 +128,7 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
$hardLimit = $config->getPropertyInt("memory.main-hard-limit", $defaultMemory);
|
||||
$hardLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_HARD_LIMIT, $defaultMemory);
|
||||
|
||||
if($hardLimit <= 0){
|
||||
ini_set("memory_limit", '-1');
|
||||
@ -135,22 +136,22 @@ class MemoryManager{
|
||||
ini_set("memory_limit", $hardLimit . "M");
|
||||
}
|
||||
|
||||
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
|
||||
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
$this->globalMemoryLimit = $config->getPropertyInt(Yml::MEMORY_GLOBAL_LIMIT, 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt(Yml::MEMORY_CHECK_RATE, self::DEFAULT_CHECK_RATE);
|
||||
$this->continuousTrigger = $config->getPropertyBool(Yml::MEMORY_CONTINUOUS_TRIGGER, true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt(Yml::MEMORY_CONTINUOUS_TRIGGER_RATE, self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt(Yml::MEMORY_GARBAGE_COLLECTION_PERIOD, self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER, true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER, true);
|
||||
|
||||
$this->lowMemChunkRadiusOverride = $config->getPropertyInt("memory.max-chunks.chunk-radius", 4);
|
||||
$this->lowMemChunkGC = $config->getPropertyBool("memory.max-chunks.trigger-chunk-collect", true);
|
||||
$this->lowMemChunkRadiusOverride = $config->getPropertyInt(Yml::MEMORY_MAX_CHUNKS_CHUNK_RADIUS, 4);
|
||||
$this->lowMemChunkGC = $config->getPropertyBool(Yml::MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT, true);
|
||||
|
||||
$this->lowMemDisableChunkCache = $config->getPropertyBool("memory.world-caches.disable-chunk-cache", true);
|
||||
$this->lowMemClearWorldCache = $config->getPropertyBool("memory.world-caches.low-memory-trigger", true);
|
||||
$this->lowMemDisableChunkCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE, true);
|
||||
$this->lowMemClearWorldCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER, true);
|
||||
|
||||
$this->dumpWorkers = $config->getPropertyBool("memory.memory-dump.dump-async-worker", true);
|
||||
$this->dumpWorkers = $config->getPropertyBool(Yml::MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER, true);
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
@ -314,9 +315,6 @@ class MemoryManager{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!$property->isPublic()){
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
if(!$property->isInitialized()){
|
||||
continue;
|
||||
}
|
||||
@ -362,7 +360,7 @@ class MemoryManager{
|
||||
'_SESSION' => true
|
||||
];
|
||||
|
||||
foreach(Utils::stringifyKeys($GLOBALS) as $varName => $value){
|
||||
foreach($GLOBALS as $varName => $value){
|
||||
if(isset($ignoredGlobals[$varName])){
|
||||
continue;
|
||||
}
|
||||
@ -440,9 +438,6 @@ class MemoryManager{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!$property->isPublic()){
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
if(!$property->isInitialized($object)){
|
||||
continue;
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ namespace pocketmine {
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\thread\ThreadManager;
|
||||
use pocketmine\thread\ThreadSafeClassLoader;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Process;
|
||||
@ -39,14 +41,17 @@ namespace pocketmine {
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function getcwd;
|
||||
use function getopt;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function phpversion;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function printf;
|
||||
use function realpath;
|
||||
use function version_compare;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
@ -103,7 +108,7 @@ namespace pocketmine {
|
||||
"openssl" => "OpenSSL",
|
||||
"pcre" => "PCRE",
|
||||
"phar" => "Phar",
|
||||
"pthreads" => "pthreads",
|
||||
"pmmpthread" => "pmmpthread",
|
||||
"reflection" => "Reflection",
|
||||
"sockets" => "Sockets",
|
||||
"spl" => "SPL",
|
||||
@ -118,12 +123,9 @@ namespace pocketmine {
|
||||
}
|
||||
}
|
||||
|
||||
if(($pthreads_version = phpversion("pthreads")) !== false){
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "5.1.0") < 0 || version_compare($pthreads_version, "6.0.0") >= 0){
|
||||
$messages[] = "pthreads ^5.0.0 is required, while you have $pthreads_version.";
|
||||
if(($pmmpthread_version = phpversion("pmmpthread")) !== false){
|
||||
if(version_compare($pmmpthread_version, "6.1.0") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.1.0 is required, while you have $pmmpthread_version.";
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +148,13 @@ namespace pocketmine {
|
||||
$messages[] = "chunkutils2 ^$wantedVersionMin is required, while you have $chunkutils2_version.";
|
||||
}
|
||||
|
||||
if(($libdeflate_version = phpversion("libdeflate")) !== false){
|
||||
//make sure level 0 compression is available
|
||||
if(version_compare($libdeflate_version, "0.2.0") < 0 || version_compare($libdeflate_version, "0.3.0") >= 0){
|
||||
$messages[] = "php-libdeflate ^0.2.0 is required, while you have $libdeflate_version.";
|
||||
}
|
||||
}
|
||||
|
||||
if(extension_loaded("pocketmine")){
|
||||
$messages[] = "The native PocketMine extension is no longer supported.";
|
||||
}
|
||||
@ -161,7 +170,7 @@ namespace pocketmine {
|
||||
* @return void
|
||||
*/
|
||||
function emit_performance_warnings(\Logger $logger){
|
||||
if(PHP_DEBUG !== 0){
|
||||
if(ZEND_DEBUG_BUILD){
|
||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||
}
|
||||
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
||||
@ -268,9 +277,14 @@ JIT_WARNING
|
||||
|
||||
ErrorToExceptionHandler::set();
|
||||
|
||||
if(count(getopt("", [BootstrapOptions::VERSION])) > 0){
|
||||
printf("%s %s (git hash %s) for Minecraft: Bedrock Edition %s\n", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true), VersionInfo::GIT_HASH(), ProtocolInfo::MINECRAFT_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||
$dataPath = getopt_string("data") ?? $cwd;
|
||||
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
||||
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
||||
|
||||
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
||||
@ -303,23 +317,28 @@ JIT_WARNING
|
||||
//Logger has a dependency on timezone
|
||||
Timezone::init();
|
||||
|
||||
$opts = getopt("", ["no-wizard", "enable-ansi", "disable-ansi"]);
|
||||
if(isset($opts["enable-ansi"])){
|
||||
$opts = getopt("", [BootstrapOptions::NO_WIZARD, BootstrapOptions::ENABLE_ANSI, BootstrapOptions::DISABLE_ANSI, BootstrapOptions::NO_LOG_FILE]);
|
||||
if(isset($opts[BootstrapOptions::ENABLE_ANSI])){
|
||||
Terminal::init(true);
|
||||
}elseif(isset($opts["disable-ansi"])){
|
||||
}elseif(isset($opts[BootstrapOptions::DISABLE_ANSI])){
|
||||
Terminal::init(false);
|
||||
}else{
|
||||
Terminal::init();
|
||||
}
|
||||
$logFile = isset($opts[BootstrapOptions::NO_LOG_FILE]) ? null : Path::join($dataPath, "server.log");
|
||||
|
||||
$logger = new MainLogger($logFile, Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get()), false, Path::join($dataPath, "log_archive"));
|
||||
if($logFile === null){
|
||||
$logger->notice("Logging to file disabled. Ensure logs are collected by other means (e.g. Docker logs).");
|
||||
}
|
||||
|
||||
$logger = new MainLogger(Path::join($dataPath, "server.log"), Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get()));
|
||||
\GlobalLogger::set($logger);
|
||||
|
||||
emit_performance_warnings($logger);
|
||||
|
||||
$exitCode = 0;
|
||||
do{
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts["no-wizard"])){
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts[BootstrapOptions::NO_WIZARD])){
|
||||
$installer = new SetupWizard($dataPath);
|
||||
if(!$installer->run()){
|
||||
$exitCode = -1;
|
||||
@ -330,7 +349,7 @@ JIT_WARNING
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
||||
*/
|
||||
$autoloader = new \BaseClassLoader();
|
||||
$autoloader = new ThreadSafeClassLoader();
|
||||
$autoloader->register(false);
|
||||
|
||||
new Server($autoloader, $logger, $dataPath, $pluginPath);
|
||||
@ -338,12 +357,12 @@ JIT_WARNING
|
||||
$logger->info("Stopping other threads");
|
||||
|
||||
$killer = new ServerKiller(8);
|
||||
$killer->start(PTHREADS_INHERIT_NONE);
|
||||
$killer->start();
|
||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||
|
||||
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||
$logger->debug("Some threads could not be stopped, performing a force-kill");
|
||||
Process::kill(Process::pid(), true);
|
||||
Process::kill(Process::pid());
|
||||
}
|
||||
}while(false);
|
||||
|
||||
|
360
src/Server.php
360
src/Server.php
@ -59,7 +59,7 @@ use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
||||
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
||||
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
||||
use pocketmine\network\mcpe\StandardPacketBroadcaster;
|
||||
@ -80,7 +80,6 @@ use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\plugin\PluginEnableOrder;
|
||||
use pocketmine\plugin\PluginGraylist;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
@ -92,6 +91,9 @@ use pocketmine\resourcepacks\ResourcePackManager;
|
||||
use pocketmine\scheduler\AsyncPool;
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\stats\SendUsageTask;
|
||||
use pocketmine\thread\log\AttachableThreadSafeLogger;
|
||||
use pocketmine\thread\ThreadCrashException;
|
||||
use pocketmine\thread\ThreadSafeClassLoader;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\updater\UpdateChecker;
|
||||
@ -117,11 +119,13 @@ use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\world\WorldCreationOptions;
|
||||
use pocketmine\world\WorldManager;
|
||||
use pocketmine\YmlServerProperties as Yml;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_fill;
|
||||
use function array_sum;
|
||||
use function base64_encode;
|
||||
use function chr;
|
||||
use function cli_set_process_title;
|
||||
use function copy;
|
||||
use function count;
|
||||
@ -354,15 +358,15 @@ class Server{
|
||||
}
|
||||
|
||||
public function getPort() : int{
|
||||
return $this->configGroup->getConfigInt("server-port", self::DEFAULT_PORT_IPV4);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV4, self::DEFAULT_PORT_IPV4);
|
||||
}
|
||||
|
||||
public function getPortV6() : int{
|
||||
return $this->configGroup->getConfigInt("server-portv6", self::DEFAULT_PORT_IPV6);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV6, self::DEFAULT_PORT_IPV6);
|
||||
}
|
||||
|
||||
public function getViewDistance() : int{
|
||||
return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_MAX_VIEW_DISTANCE));
|
||||
return max(2, $this->configGroup->getConfigInt(ServerProperties::VIEW_DISTANCE, self::DEFAULT_MAX_VIEW_DISTANCE));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,12 +377,12 @@ class Server{
|
||||
}
|
||||
|
||||
public function getIp() : string{
|
||||
$str = $this->configGroup->getConfigString("server-ip");
|
||||
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV4);
|
||||
return $str !== "" ? $str : "0.0.0.0";
|
||||
}
|
||||
|
||||
public function getIpV6() : string{
|
||||
$str = $this->configGroup->getConfigString("server-ipv6");
|
||||
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV6);
|
||||
return $str !== "" ? $str : "::";
|
||||
}
|
||||
|
||||
@ -387,37 +391,37 @@ class Server{
|
||||
}
|
||||
|
||||
public function getGamemode() : GameMode{
|
||||
return GameMode::fromString($this->configGroup->getConfigString("gamemode", GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
|
||||
return GameMode::fromString($this->configGroup->getConfigString(ServerProperties::GAME_MODE)) ?? GameMode::SURVIVAL;
|
||||
}
|
||||
|
||||
public function getForceGamemode() : bool{
|
||||
return $this->configGroup->getConfigBool("force-gamemode", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::FORCE_GAME_MODE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Server global difficulty. Note that this may be overridden in individual worlds.
|
||||
*/
|
||||
public function getDifficulty() : int{
|
||||
return $this->configGroup->getConfigInt("difficulty", World::DIFFICULTY_NORMAL);
|
||||
return $this->configGroup->getConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_NORMAL);
|
||||
}
|
||||
|
||||
public function hasWhitelist() : bool{
|
||||
return $this->configGroup->getConfigBool("white-list", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::WHITELIST, false);
|
||||
}
|
||||
|
||||
public function isHardcore() : bool{
|
||||
return $this->configGroup->getConfigBool("hardcore", false);
|
||||
return $this->configGroup->getConfigBool(ServerProperties::HARDCORE, false);
|
||||
}
|
||||
|
||||
public function getMotd() : string{
|
||||
return $this->configGroup->getConfigString("motd", self::DEFAULT_SERVER_NAME);
|
||||
return $this->configGroup->getConfigString(ServerProperties::MOTD, self::DEFAULT_SERVER_NAME);
|
||||
}
|
||||
|
||||
public function getLoader() : \DynamicClassLoader{
|
||||
public function getLoader() : ThreadSafeClassLoader{
|
||||
return $this->autoloader;
|
||||
}
|
||||
|
||||
public function getLogger() : \AttachableThreadedLogger{
|
||||
public function getLogger() : AttachableThreadSafeLogger{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
@ -493,7 +497,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function shouldSavePlayerData() : bool{
|
||||
return $this->configGroup->getPropertyBool("player.save-player-data", true);
|
||||
return $this->configGroup->getPropertyBool(Yml::PLAYER_SAVE_PLAYER_DATA, true);
|
||||
}
|
||||
|
||||
public function getOfflinePlayer(string $name) : Player|OfflinePlayer|null{
|
||||
@ -520,7 +524,7 @@ class Server{
|
||||
return $this->playerDataProvider->loadData($name);
|
||||
}catch(PlayerDataLoadException $e){
|
||||
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@ -539,7 +543,7 @@ class Server{
|
||||
try{
|
||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||
}catch(PlayerDataSaveException $e){
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
});
|
||||
@ -567,6 +571,7 @@ class Server{
|
||||
$playerPromiseResolver = new PromiseResolver();
|
||||
|
||||
$createPlayer = function(Location $location) use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $offlinePlayerData) : void{
|
||||
/** @see Player::__construct() */
|
||||
$player = new $class($this, $session, $playerInfo, $authenticated, $location, $offlinePlayerData);
|
||||
if(!$player->hasPlayedBefore()){
|
||||
$player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
|
||||
@ -733,7 +738,7 @@ class Server{
|
||||
* @return string[][]
|
||||
*/
|
||||
public function getCommandAliases() : array{
|
||||
$section = $this->configGroup->getProperty("aliases");
|
||||
$section = $this->configGroup->getProperty(Yml::ALIASES);
|
||||
$result = [];
|
||||
if(is_array($section)){
|
||||
foreach($section as $key => $value){
|
||||
@ -759,8 +764,8 @@ class Server{
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
private \DynamicClassLoader $autoloader,
|
||||
private \AttachableThreadedLogger $logger,
|
||||
private ThreadSafeClassLoader $autoloader,
|
||||
private AttachableThreadSafeLogger $logger,
|
||||
string $dataPath,
|
||||
string $pluginPath
|
||||
){
|
||||
@ -808,36 +813,36 @@ class Server{
|
||||
$this->configGroup = new ServerConfigGroup(
|
||||
new Config($pocketmineYmlPath, Config::YAML, []),
|
||||
new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [
|
||||
"motd" => self::DEFAULT_SERVER_NAME,
|
||||
"server-port" => self::DEFAULT_PORT_IPV4,
|
||||
"server-portv6" => self::DEFAULT_PORT_IPV6,
|
||||
"enable-ipv6" => true,
|
||||
"white-list" => false,
|
||||
"max-players" => self::DEFAULT_MAX_PLAYERS,
|
||||
"gamemode" => GameMode::SURVIVAL()->name(),
|
||||
"force-gamemode" => false,
|
||||
"hardcore" => false,
|
||||
"pvp" => true,
|
||||
"difficulty" => World::DIFFICULTY_NORMAL,
|
||||
"generator-settings" => "",
|
||||
"level-name" => "world",
|
||||
"level-seed" => "",
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"auto-save" => true,
|
||||
"view-distance" => self::DEFAULT_MAX_VIEW_DISTANCE,
|
||||
"xbox-auth" => true,
|
||||
"language" => "eng"
|
||||
ServerProperties::MOTD => self::DEFAULT_SERVER_NAME,
|
||||
ServerProperties::SERVER_PORT_IPV4 => self::DEFAULT_PORT_IPV4,
|
||||
ServerProperties::SERVER_PORT_IPV6 => self::DEFAULT_PORT_IPV6,
|
||||
ServerProperties::ENABLE_IPV6 => true,
|
||||
ServerProperties::WHITELIST => false,
|
||||
ServerProperties::MAX_PLAYERS => self::DEFAULT_MAX_PLAYERS,
|
||||
ServerProperties::GAME_MODE => GameMode::SURVIVAL->name, //TODO: this probably shouldn't use the enum name directly
|
||||
ServerProperties::FORCE_GAME_MODE => false,
|
||||
ServerProperties::HARDCORE => false,
|
||||
ServerProperties::PVP => true,
|
||||
ServerProperties::DIFFICULTY => World::DIFFICULTY_NORMAL,
|
||||
ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS => "",
|
||||
ServerProperties::DEFAULT_WORLD_NAME => "world",
|
||||
ServerProperties::DEFAULT_WORLD_SEED => "",
|
||||
ServerProperties::DEFAULT_WORLD_GENERATOR => "DEFAULT",
|
||||
ServerProperties::ENABLE_QUERY => true,
|
||||
ServerProperties::AUTO_SAVE => true,
|
||||
ServerProperties::VIEW_DISTANCE => self::DEFAULT_MAX_VIEW_DISTANCE,
|
||||
ServerProperties::XBOX_AUTH => true,
|
||||
ServerProperties::LANGUAGE => "eng"
|
||||
])
|
||||
);
|
||||
|
||||
$debugLogLevel = $this->configGroup->getPropertyInt("debug.level", 1);
|
||||
$debugLogLevel = $this->configGroup->getPropertyInt(Yml::DEBUG_LEVEL, 1);
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->setLogDebug($debugLogLevel > 1);
|
||||
}
|
||||
|
||||
$this->forceLanguage = $this->configGroup->getPropertyBool("settings.force-language", false);
|
||||
$selectedLang = $this->configGroup->getConfigString("language", $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
|
||||
$this->forceLanguage = $this->configGroup->getPropertyBool(Yml::SETTINGS_FORCE_LANGUAGE, false);
|
||||
$selectedLang = $this->configGroup->getConfigString(ServerProperties::LANGUAGE, $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
|
||||
try{
|
||||
$this->language = new Language($selectedLang);
|
||||
}catch(LanguageNotFoundException $e){
|
||||
@ -850,14 +855,14 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::language_selected($this->language->getName(), $this->language->getLang())));
|
||||
|
||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||
if(!$this->configGroup->getPropertyBool("settings.enable-dev-builds", false)){
|
||||
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error1(VersionInfo::NAME)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error2()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4("settings.enable-dev-builds")));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(Yml::SETTINGS_ENABLE_DEV_BUILDS)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases")));
|
||||
$this->forceShutdownExit();
|
||||
|
||||
@ -873,9 +878,9 @@ class Server{
|
||||
|
||||
$this->memoryManager = new MemoryManager($this);
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
|
||||
if(($poolSize = $this->configGroup->getPropertyString("settings.async-workers", "auto")) === "auto"){
|
||||
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
||||
$poolSize = 2;
|
||||
$processors = Utils::getCoreCount() - 2;
|
||||
|
||||
@ -886,32 +891,32 @@ class Server{
|
||||
$poolSize = max(1, (int) $poolSize);
|
||||
}
|
||||
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger, $this->tickSleeper);
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt(Yml::MEMORY_ASYNC_WORKER_HARD_LIMIT, 256)), $this->autoloader, $this->logger, $this->tickSleeper);
|
||||
|
||||
$netCompressionThreshold = -1;
|
||||
if($this->configGroup->getPropertyInt("network.batch-threshold", 256) >= 0){
|
||||
$netCompressionThreshold = $this->configGroup->getPropertyInt("network.batch-threshold", 256);
|
||||
if($this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256) >= 0){
|
||||
$netCompressionThreshold = $this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256);
|
||||
}
|
||||
if($netCompressionThreshold < 0){
|
||||
$netCompressionThreshold = null;
|
||||
}
|
||||
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6);
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt(Yml::NETWORK_COMPRESSION_LEVEL, 6);
|
||||
if($netCompressionLevel < 1 || $netCompressionLevel > 9){
|
||||
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 6");
|
||||
$netCompressionLevel = 6;
|
||||
}
|
||||
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
|
||||
|
||||
$this->networkCompressionAsync = $this->configGroup->getPropertyBool("network.async-compression", true);
|
||||
$this->networkCompressionAsync = $this->configGroup->getPropertyBool(Yml::NETWORK_ASYNC_COMPRESSION, true);
|
||||
$this->networkCompressionAsyncThreshold = max(
|
||||
$this->configGroup->getPropertyInt("network.async-compression-threshold", self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
|
||||
$this->configGroup->getPropertyInt(Yml::NETWORK_ASYNC_COMPRESSION_THRESHOLD, self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
|
||||
$netCompressionThreshold ?? self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD
|
||||
);
|
||||
|
||||
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool("network.enable-encryption", true);
|
||||
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool(Yml::NETWORK_ENABLE_ENCRYPTION, true);
|
||||
|
||||
$this->doTitleTick = $this->configGroup->getPropertyBool("console.title-tick", true) && Terminal::hasFormattingCodes();
|
||||
$this->doTitleTick = $this->configGroup->getPropertyBool(Yml::CONSOLE_TITLE_TICK, true) && Terminal::hasFormattingCodes();
|
||||
|
||||
$this->operators = new Config(Path::join($this->dataPath, "ops.txt"), Config::ENUM);
|
||||
$this->whitelist = new Config(Path::join($this->dataPath, "white-list.txt"), Config::ENUM);
|
||||
@ -929,39 +934,39 @@ class Server{
|
||||
$this->banByIP = new BanList($bannedIpsTxt);
|
||||
$this->banByIP->load();
|
||||
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", self::DEFAULT_MAX_PLAYERS);
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt(ServerProperties::MAX_PLAYERS, self::DEFAULT_MAX_PLAYERS);
|
||||
|
||||
$this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true);
|
||||
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
||||
if($this->onlineMode){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
}else{
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
if($this->configGroup->getConfigBool("hardcore", false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD);
|
||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
||||
|
||||
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
|
||||
|
||||
$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
$this->logger->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->logger->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
|
||||
$this->network = new Network($this->logger);
|
||||
$this->network->setName($this->getMotd());
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->getName(),
|
||||
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
DefaultPermissions::registerCorePermissions();
|
||||
|
||||
@ -969,7 +974,7 @@ class Server{
|
||||
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
||||
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
|
||||
|
||||
$pluginGraylist = null;
|
||||
$graylistFile = Path::join($this->dataPath, "plugin_list.yml");
|
||||
@ -983,13 +988,13 @@ class Server{
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null &&
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString(Yml::LEVEL_SETTINGS_DEFAULT_FORMAT, ""))) !== null &&
|
||||
$format instanceof WritableWorldProviderManagerEntry
|
||||
){
|
||||
$providerManager->setDefault($format);
|
||||
@ -998,16 +1003,16 @@ class Server{
|
||||
}
|
||||
|
||||
$this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager);
|
||||
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
|
||||
$this->worldManager->setAutoSave($this->configGroup->getConfigBool(ServerProperties::AUTO_SAVE, $this->worldManager->getAutoSave()));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt(Yml::TICKS_PER_AUTOSAVE, $this->worldManager->getAutoSaveInterval()));
|
||||
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io"));
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString(Yml::AUTO_UPDATER_HOST, "update.pmmp.io"));
|
||||
|
||||
$this->queryInfo = new QueryInfo($this);
|
||||
|
||||
$this->playerDataProvider = new DatFilePlayerDataProvider(Path::join($this->dataPath, "players"));
|
||||
|
||||
register_shutdown_function([$this, "crashDump"]);
|
||||
register_shutdown_function($this->crashDump(...));
|
||||
|
||||
$loadErrorCount = 0;
|
||||
$this->pluginManager->loadPlugins($this->pluginPath, $loadErrorCount);
|
||||
@ -1016,7 +1021,7 @@ class Server{
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
if(!$this->enablePlugins(PluginEnableOrder::STARTUP())){
|
||||
if(!$this->enablePlugins(PluginEnableOrder::STARTUP)){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
@ -1027,7 +1032,7 @@ class Server{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->enablePlugins(PluginEnableOrder::POSTWORLD())){
|
||||
if(!$this->enablePlugins(PluginEnableOrder::POSTWORLD)){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
@ -1038,23 +1043,23 @@ class Server{
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_OPEN);
|
||||
}
|
||||
|
||||
$this->configGroup->save();
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
|
||||
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);
|
||||
|
||||
//TODO: move console parts to a separate component
|
||||
if($this->configGroup->getPropertyBool("console.enable-input", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::CONSOLE_ENABLE_INPUT, true)){
|
||||
$this->console = new ConsoleReaderChildProcessDaemon($this->logger);
|
||||
}
|
||||
|
||||
@ -1089,7 +1094,7 @@ class Server{
|
||||
|
||||
$anyWorldFailedToLoad = false;
|
||||
|
||||
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
|
||||
foreach((array) $this->configGroup->getProperty(Yml::WORLDS, []) as $name => $options){
|
||||
if($options === null){
|
||||
$options = [];
|
||||
}elseif(!is_array($options)){
|
||||
@ -1133,30 +1138,30 @@ class Server{
|
||||
}
|
||||
|
||||
if($this->worldManager->getDefaultWorld() === null){
|
||||
$default = $this->configGroup->getConfigString("level-name", "world");
|
||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
if(trim($default) == ""){
|
||||
$this->getLogger()->warning("level-name cannot be null, using default");
|
||||
$this->logger->warning("level-name cannot be null, using default");
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString("level-name", "world");
|
||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($default, true)){
|
||||
if($this->worldManager->isWorldGenerated($default)){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
|
||||
return false;
|
||||
}
|
||||
$generatorName = $this->configGroup->getConfigString("level-type");
|
||||
$generatorOptions = $this->configGroup->getConfigString("generator-settings");
|
||||
$generatorName = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR);
|
||||
$generatorOptions = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS);
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||
|
||||
if($generatorClass === null){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
return false;
|
||||
}
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
->setGeneratorClass($generatorClass)
|
||||
->setGeneratorOptions($generatorOptions);
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_SEED));
|
||||
if($convertedSeed !== null){
|
||||
$creationOptions->setSeed($convertedSeed);
|
||||
}
|
||||
@ -1181,12 +1186,11 @@ class Server{
|
||||
bool $useQuery,
|
||||
PacketBroadcaster $packetBroadcaster,
|
||||
EntityEventBroadcaster $entityEventBroadcaster,
|
||||
PacketSerializerContext $packetSerializerContext,
|
||||
TypeConverter $typeConverter
|
||||
) : bool{
|
||||
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
||||
try{
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter));
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $typeConverter));
|
||||
}catch(NetworkInterfaceStartException $e){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
||||
$ip,
|
||||
@ -1196,7 +1200,7 @@ class Server{
|
||||
return false;
|
||||
}
|
||||
if($rakLibRegistered){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
}
|
||||
if($useQuery){
|
||||
if(!$rakLibRegistered){
|
||||
@ -1204,24 +1208,23 @@ class Server{
|
||||
//if it's not registered we need to make sure Query still works
|
||||
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
|
||||
}
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function startupPrepareNetworkInterfaces() : bool{
|
||||
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
|
||||
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
||||
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this);
|
||||
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster, $typeConverter);
|
||||
|
||||
if(
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter) ||
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter) ||
|
||||
(
|
||||
$this->configGroup->getConfigBool("enable-ipv6", true) &&
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter)
|
||||
$this->configGroup->getConfigBool(ServerProperties::ENABLE_IPV6, true) &&
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
@ -1235,7 +1238,7 @@ class Server{
|
||||
$this->network->blockAddress($entry->getName(), -1);
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){
|
||||
if($this->configGroup->getPropertyBool(Yml::NETWORK_UPNP_FORWARDING, false)){
|
||||
$this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort()));
|
||||
}
|
||||
|
||||
@ -1255,9 +1258,10 @@ class Server{
|
||||
*/
|
||||
public function unsubscribeFromBroadcastChannel(string $channelId, CommandSender $subscriber) : void{
|
||||
if(isset($this->broadcastSubscribers[$channelId][spl_object_id($subscriber)])){
|
||||
unset($this->broadcastSubscribers[$channelId][spl_object_id($subscriber)]);
|
||||
if(count($this->broadcastSubscribers[$channelId]) === 0){
|
||||
if(count($this->broadcastSubscribers[$channelId]) === 1){
|
||||
unset($this->broadcastSubscribers[$channelId]);
|
||||
}else{
|
||||
unset($this->broadcastSubscribers[$channelId][spl_object_id($subscriber)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1351,29 +1355,43 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a list of packets in a batch to a list of players
|
||||
* @internal
|
||||
* Promises to compress the given batch buffer using the selected compressor, optionally on a separate thread.
|
||||
*
|
||||
* If the buffer is smaller than the batch-threshold (usually 256), the buffer will be compressed at level 0 if supported
|
||||
* by the compressor. This means that the payload will be wrapped with the appropriate header and footer, but not
|
||||
* actually compressed.
|
||||
*
|
||||
* If the buffer is larger than the async-compression-threshold (usually 10,000), the buffer may be compressed in
|
||||
* a separate thread (if available).
|
||||
*
|
||||
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
||||
*/
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise|string{
|
||||
$timings ??= Timings::$playerNetworkSendCompress;
|
||||
try{
|
||||
$timings->startTiming();
|
||||
|
||||
if($sync === null){
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
|
||||
}
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
if($threshold === null || strlen($buffer) < $compressor->getCompressionThreshold()){
|
||||
$compressionType = CompressionAlgorithm::NONE;
|
||||
$compressed = $buffer;
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
}else{
|
||||
$promise->resolve($compressor->compress($buffer));
|
||||
$sync ??= !$this->networkCompressionAsync;
|
||||
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$promise = new CompressBatchPromise();
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
return $promise;
|
||||
}
|
||||
|
||||
$compressionType = $compressor->getNetworkId();
|
||||
$compressed = $compressor->compress($buffer);
|
||||
}
|
||||
|
||||
return $promise;
|
||||
return chr($compressionType) . $compressed;
|
||||
}finally{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
@ -1382,14 +1400,14 @@ class Server{
|
||||
public function enablePlugins(PluginEnableOrder $type) : bool{
|
||||
$allSuccess = true;
|
||||
foreach($this->pluginManager->getPlugins() as $plugin){
|
||||
if(!$plugin->isEnabled() && $plugin->getDescription()->getOrder()->equals($type)){
|
||||
if(!$plugin->isEnabled() && $plugin->getDescription()->getOrder() === $type){
|
||||
if(!$this->pluginManager->enablePlugin($plugin)){
|
||||
$allSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($type->equals(PluginEnableOrder::POSTWORLD())){
|
||||
if($type === PluginEnableOrder::POSTWORLD){
|
||||
$this->commandMap->registerServerAliases();
|
||||
}
|
||||
|
||||
@ -1425,7 +1443,7 @@ class Server{
|
||||
|
||||
private function forceShutdownExit() : void{
|
||||
$this->forceShutdown();
|
||||
Process::kill(Process::pid(), true);
|
||||
Process::kill(Process::pid());
|
||||
}
|
||||
|
||||
public function forceShutdown() : void{
|
||||
@ -1450,50 +1468,50 @@ class Server{
|
||||
$this->shutdown();
|
||||
|
||||
if(isset($this->pluginManager)){
|
||||
$this->getLogger()->debug("Disabling all plugins");
|
||||
$this->logger->debug("Disabling all plugins");
|
||||
$this->pluginManager->disablePlugins();
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString("settings.shutdown-message", "Server closed"));
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString(Yml::SETTINGS_SHUTDOWN_MESSAGE, "Server closed"));
|
||||
}
|
||||
|
||||
if(isset($this->worldManager)){
|
||||
$this->getLogger()->debug("Unloading all worlds");
|
||||
$this->logger->debug("Unloading all worlds");
|
||||
foreach($this->worldManager->getWorlds() as $world){
|
||||
$this->worldManager->unloadWorld($world, true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Removing event handlers");
|
||||
$this->logger->debug("Removing event handlers");
|
||||
HandlerListManager::global()->unregisterAll();
|
||||
|
||||
if(isset($this->asyncPool)){
|
||||
$this->getLogger()->debug("Shutting down async task worker pool");
|
||||
$this->logger->debug("Shutting down async task worker pool");
|
||||
$this->asyncPool->shutdown();
|
||||
}
|
||||
|
||||
if(isset($this->configGroup)){
|
||||
$this->getLogger()->debug("Saving properties");
|
||||
$this->logger->debug("Saving properties");
|
||||
$this->configGroup->save();
|
||||
}
|
||||
|
||||
if($this->console !== null){
|
||||
$this->getLogger()->debug("Closing console");
|
||||
$this->logger->debug("Closing console");
|
||||
$this->console->quit();
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->getLogger()->debug("Stopping network interfaces");
|
||||
$this->logger->debug("Stopping network interfaces");
|
||||
foreach($this->network->getInterfaces() as $interface){
|
||||
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
|
||||
$this->logger->debug("Stopping network interface " . get_class($interface));
|
||||
$this->network->unregisterInterface($interface);
|
||||
}
|
||||
}
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
$this->logger->emergency("Crashed while crashing, killing process");
|
||||
@Process::kill(Process::pid(), true);
|
||||
@Process::kill(Process::pid());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1514,23 +1532,38 @@ class Server{
|
||||
$trace = $e->getTrace();
|
||||
}
|
||||
|
||||
$errstr = $e->getMessage();
|
||||
$errfile = $e->getFile();
|
||||
$errline = $e->getLine();
|
||||
//If this is a thread crash, this logs where the exception came from on the main thread, as opposed to the
|
||||
//crashed thread. This is intentional, and might be useful for debugging
|
||||
//Assume that the thread already logged the original exception with the correct stack trace
|
||||
$this->logger->logException($e, $trace);
|
||||
|
||||
if($e instanceof ThreadCrashException){
|
||||
$info = $e->getCrashInfo();
|
||||
$type = $info->getType();
|
||||
$errstr = $info->getMessage();
|
||||
$errfile = $info->getFile();
|
||||
$errline = $info->getLine();
|
||||
$printableTrace = $info->getTrace();
|
||||
$thread = $info->getThreadName();
|
||||
}else{
|
||||
$type = get_class($e);
|
||||
$errstr = $e->getMessage();
|
||||
$errfile = $e->getFile();
|
||||
$errline = $e->getLine();
|
||||
$printableTrace = Utils::printableTraceWithMetadata($trace);
|
||||
$thread = "Main";
|
||||
}
|
||||
|
||||
$errstr = preg_replace('/\s+/', ' ', trim($errstr));
|
||||
|
||||
$errfile = Filesystem::cleanPath($errfile);
|
||||
|
||||
$this->logger->logException($e, $trace);
|
||||
|
||||
$lastError = [
|
||||
"type" => get_class($e),
|
||||
"type" => $type,
|
||||
"message" => $errstr,
|
||||
"fullFile" => $e->getFile(),
|
||||
"file" => $errfile,
|
||||
"fullFile" => $errfile,
|
||||
"file" => Filesystem::cleanPath($errfile),
|
||||
"line" => $errline,
|
||||
"trace" => $trace
|
||||
"trace" => $printableTrace,
|
||||
"thread" => $thread
|
||||
];
|
||||
|
||||
global $lastExceptionError, $lastError;
|
||||
@ -1539,7 +1572,7 @@ class Server{
|
||||
}
|
||||
|
||||
private function writeCrashDumpFile(CrashDump $dump) : string{
|
||||
$crashFolder = Path::join($this->getDataPath(), "crashdumps");
|
||||
$crashFolder = Path::join($this->dataPath, "crashdumps");
|
||||
if(!is_dir($crashFolder)){
|
||||
mkdir($crashFolder);
|
||||
}
|
||||
@ -1570,17 +1603,17 @@ class Server{
|
||||
ini_set("error_reporting", '0');
|
||||
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
|
||||
try{
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$dump = new CrashDump($this, $this->pluginManager ?? null);
|
||||
|
||||
$crashDumpPath = $this->writeCrashDumpFile($dump);
|
||||
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
|
||||
if($this->configGroup->getPropertyBool("auto-report.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
||||
$report = true;
|
||||
|
||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
||||
$stamp = Path::join($this->dataPath, "crashdumps", ".last_crash");
|
||||
$crashInterval = 120; //2 minutes
|
||||
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
||||
$report = false;
|
||||
@ -1588,15 +1621,6 @@ class Server{
|
||||
}
|
||||
@touch($stamp); //update file timestamp
|
||||
|
||||
$plugin = $dump->getData()->plugin;
|
||||
if($plugin !== ""){
|
||||
$p = $this->pluginManager->getPlugin($plugin);
|
||||
if($p instanceof Plugin && !($p->getPluginLoader() instanceof PharPluginLoader)){
|
||||
$this->logger->debug("Not sending crashdump due to caused by non-phar plugin");
|
||||
$report = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($dump->getData()->error["type"] === \ParseError::class){
|
||||
$report = false;
|
||||
}
|
||||
@ -1607,7 +1631,7 @@ class Server{
|
||||
}
|
||||
|
||||
if($report){
|
||||
$url = ($this->configGroup->getPropertyBool("auto-report.use-https", true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString("auto-report.host", "crash.pmmp.io") . "/submit/api";
|
||||
$url = ($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_USE_HTTPS, true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString(Yml::AUTO_REPORT_HOST, "crash.pmmp.io") . "/submit/api";
|
||||
$postUrlError = "Unknown error";
|
||||
$reply = Internet::postURL($url, [
|
||||
"report" => "yes",
|
||||
@ -1620,7 +1644,7 @@ class Server{
|
||||
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
}elseif(isset($data->error) && is_string($data->error)){
|
||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||
}else{
|
||||
@ -1634,7 +1658,7 @@ class Server{
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
try{
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
}catch(\Throwable $e){}
|
||||
}
|
||||
|
||||
@ -1642,12 +1666,14 @@ class Server{
|
||||
$this->isRunning = false;
|
||||
|
||||
//Force minimum uptime to be >= 120 seconds, to reduce the impact of spammy crash loops
|
||||
$spacing = ((int) $this->startTime) - time() + 120;
|
||||
$uptime = time() - ((int) $this->startTime);
|
||||
$minUptime = 120;
|
||||
$spacing = $minUptime - $uptime;
|
||||
if($spacing > 0){
|
||||
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
|
||||
echo "--- Uptime {$uptime}s - waiting {$spacing}s to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
|
||||
sleep($spacing);
|
||||
}
|
||||
@Process::kill(Process::pid(), true);
|
||||
@Process::kill(Process::pid());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -1718,7 +1744,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function sendUsage(int $type = SendUsageTask::TYPE_STATUS) : void{
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
|
||||
$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
||||
}
|
||||
$this->uniquePlayers = [];
|
||||
@ -1752,7 +1778,7 @@ class Server{
|
||||
|
||||
echo "\x1b]0;" . $this->getName() . " " .
|
||||
$this->getPocketMineVersion() .
|
||||
" | Online $online/" . $this->getMaxPlayers() .
|
||||
" | Online $online/" . $this->maxPlayers .
|
||||
($connecting > 0 ? " (+$connecting connecting)" : "") .
|
||||
" | Memory " . $usage .
|
||||
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
|
||||
@ -1817,10 +1843,10 @@ class Server{
|
||||
}
|
||||
|
||||
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
|
||||
$this->getMemoryManager()->check();
|
||||
$this->memoryManager->check();
|
||||
|
||||
if($this->console !== null){
|
||||
Timings::$serverCommand->startTiming();
|
||||
|
58
src/ServerProperties.php
Normal file
58
src/ServerProperties.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in server.properties.
|
||||
*/
|
||||
final class ServerProperties{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const AUTO_SAVE = "auto-save";
|
||||
public const DEFAULT_WORLD_GENERATOR = "level-type";
|
||||
public const DEFAULT_WORLD_GENERATOR_SETTINGS = "generator-settings";
|
||||
public const DEFAULT_WORLD_NAME = "level-name";
|
||||
public const DEFAULT_WORLD_SEED = "level-seed";
|
||||
public const DIFFICULTY = "difficulty";
|
||||
public const ENABLE_IPV6 = "enable-ipv6";
|
||||
public const ENABLE_QUERY = "enable-query";
|
||||
public const FORCE_GAME_MODE = "force-gamemode";
|
||||
public const GAME_MODE = "gamemode";
|
||||
public const HARDCORE = "hardcore";
|
||||
public const LANGUAGE = "language";
|
||||
public const MAX_PLAYERS = "max-players";
|
||||
public const MOTD = "motd";
|
||||
public const PVP = "pvp";
|
||||
public const SERVER_IPV4 = "server-ip";
|
||||
public const SERVER_IPV6 = "server-ipv6";
|
||||
public const SERVER_PORT_IPV4 = "server-port";
|
||||
public const SERVER_PORT_IPV6 = "server-portv6";
|
||||
public const VIEW_DISTANCE = "view-distance";
|
||||
public const WHITELIST = "white-list";
|
||||
public const XBOX_AUTH = "xbox-auth";
|
||||
}
|
@ -24,7 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\snooze\SleeperHandlerEntry;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Utils;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
@ -35,12 +37,29 @@ final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
/**
|
||||
* @var TimingsHandler[]
|
||||
* @phpstan-var array<string, TimingsHandler>
|
||||
*/
|
||||
private static array $handlerTimings = [];
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
|
||||
$name = Utils::getNiceClosureName($handler);
|
||||
$timings = self::$handlerTimings[$name] ??= new TimingsHandler("Snooze Handler: " . $name, $this->timings);
|
||||
|
||||
return parent::addNotifier(function() use ($timings, $handler) : void{
|
||||
$timings->startTiming();
|
||||
$handler();
|
||||
$timings->stopTiming();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
|
@ -31,9 +31,24 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.0.0-BETA3";
|
||||
public const BASE_VERSION = "5.21.1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "beta";
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
/**
|
||||
* PocketMine-MP-specific version ID for world data. Used to determine what fixes need to be applied to old world
|
||||
* data (e.g. stuff saved wrongly by past versions).
|
||||
* This version supplements the Minecraft vanilla world version.
|
||||
*
|
||||
* This should be bumped if any **non-Mojang** BC-breaking change or bug fix is made to world save data of any kind
|
||||
* (entities, tiles, blocks, biomes etc.). For example, if PM accidentally saved a block with its facing value
|
||||
* swapped, we would bump this, but not if Mojang did the same change.
|
||||
*/
|
||||
public const WORLD_DATA_VERSION = 1;
|
||||
/**
|
||||
* Name of the NBT tag used to store the world data version.
|
||||
*/
|
||||
public const TAG_WORLD_DATA_VERSION = "PMMPDataVersion"; //TAG_Long
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
@ -48,7 +63,8 @@ final class VersionInfo{
|
||||
if(\Phar::running(true) === ""){
|
||||
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
|
||||
}else{
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$pharPath = \Phar::running(false);
|
||||
$phar = \Phar::isValidPharFilename($pharPath) ? new \Phar($pharPath) : new \PharData($pharPath);
|
||||
$meta = $phar->getMetadata();
|
||||
if(isset($meta["git"])){
|
||||
$gitHash = $meta["git"];
|
||||
@ -67,7 +83,8 @@ final class VersionInfo{
|
||||
if(self::$buildNumber === null){
|
||||
self::$buildNumber = 0;
|
||||
if(\Phar::running(true) !== ""){
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$pharPath = \Phar::running(false);
|
||||
$phar = \Phar::isValidPharFilename($pharPath) ? new \Phar($pharPath) : new \PharData($pharPath);
|
||||
$meta = $phar->getMetadata();
|
||||
if(is_array($meta) && isset($meta["build"]) && is_int($meta["build"])){
|
||||
self::$buildNumber = $meta["build"];
|
||||
|
118
src/YmlServerProperties.php
Normal file
118
src/YmlServerProperties.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Constants for all properties available in pocketmine.yml.
|
||||
* This is generated by build/generate-pocketmine-yml-property-consts.php.
|
||||
* Do not edit this file manually.
|
||||
*/
|
||||
final class YmlServerProperties{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const ALIASES = 'aliases';
|
||||
public const ANONYMOUS_STATISTICS = 'anonymous-statistics';
|
||||
public const ANONYMOUS_STATISTICS_ENABLED = 'anonymous-statistics.enabled';
|
||||
public const ANONYMOUS_STATISTICS_HOST = 'anonymous-statistics.host';
|
||||
public const AUTO_REPORT = 'auto-report';
|
||||
public const AUTO_REPORT_ENABLED = 'auto-report.enabled';
|
||||
public const AUTO_REPORT_HOST = 'auto-report.host';
|
||||
public const AUTO_REPORT_SEND_CODE = 'auto-report.send-code';
|
||||
public const AUTO_REPORT_SEND_PHPINFO = 'auto-report.send-phpinfo';
|
||||
public const AUTO_REPORT_SEND_SETTINGS = 'auto-report.send-settings';
|
||||
public const AUTO_REPORT_USE_HTTPS = 'auto-report.use-https';
|
||||
public const AUTO_UPDATER = 'auto-updater';
|
||||
public const AUTO_UPDATER_ENABLED = 'auto-updater.enabled';
|
||||
public const AUTO_UPDATER_HOST = 'auto-updater.host';
|
||||
public const AUTO_UPDATER_ON_UPDATE = 'auto-updater.on-update';
|
||||
public const AUTO_UPDATER_ON_UPDATE_WARN_CONSOLE = 'auto-updater.on-update.warn-console';
|
||||
public const AUTO_UPDATER_PREFERRED_CHANNEL = 'auto-updater.preferred-channel';
|
||||
public const AUTO_UPDATER_SUGGEST_CHANNELS = 'auto-updater.suggest-channels';
|
||||
public const CHUNK_GENERATION = 'chunk-generation';
|
||||
public const CHUNK_GENERATION_POPULATION_QUEUE_SIZE = 'chunk-generation.population-queue-size';
|
||||
public const CHUNK_SENDING = 'chunk-sending';
|
||||
public const CHUNK_SENDING_PER_TICK = 'chunk-sending.per-tick';
|
||||
public const CHUNK_SENDING_SPAWN_RADIUS = 'chunk-sending.spawn-radius';
|
||||
public const CHUNK_TICKING = 'chunk-ticking';
|
||||
public const CHUNK_TICKING_BLOCKS_PER_SUBCHUNK_PER_TICK = 'chunk-ticking.blocks-per-subchunk-per-tick';
|
||||
public const CHUNK_TICKING_DISABLE_BLOCK_TICKING = 'chunk-ticking.disable-block-ticking';
|
||||
public const CHUNK_TICKING_TICK_RADIUS = 'chunk-ticking.tick-radius';
|
||||
public const CONSOLE = 'console';
|
||||
public const CONSOLE_ENABLE_INPUT = 'console.enable-input';
|
||||
public const CONSOLE_TITLE_TICK = 'console.title-tick';
|
||||
public const DEBUG = 'debug';
|
||||
public const DEBUG_LEVEL = 'debug.level';
|
||||
public const LEVEL_SETTINGS = 'level-settings';
|
||||
public const LEVEL_SETTINGS_DEFAULT_FORMAT = 'level-settings.default-format';
|
||||
public const MEMORY = 'memory';
|
||||
public const MEMORY_ASYNC_WORKER_HARD_LIMIT = 'memory.async-worker-hard-limit';
|
||||
public const MEMORY_CHECK_RATE = 'memory.check-rate';
|
||||
public const MEMORY_CONTINUOUS_TRIGGER = 'memory.continuous-trigger';
|
||||
public const MEMORY_CONTINUOUS_TRIGGER_RATE = 'memory.continuous-trigger-rate';
|
||||
public const MEMORY_GARBAGE_COLLECTION = 'memory.garbage-collection';
|
||||
public const MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER = 'memory.garbage-collection.collect-async-worker';
|
||||
public const MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER = 'memory.garbage-collection.low-memory-trigger';
|
||||
public const MEMORY_GARBAGE_COLLECTION_PERIOD = 'memory.garbage-collection.period';
|
||||
public const MEMORY_GLOBAL_LIMIT = 'memory.global-limit';
|
||||
public const MEMORY_MAIN_HARD_LIMIT = 'memory.main-hard-limit';
|
||||
public const MEMORY_MAIN_LIMIT = 'memory.main-limit';
|
||||
public const MEMORY_MAX_CHUNKS = 'memory.max-chunks';
|
||||
public const MEMORY_MAX_CHUNKS_CHUNK_RADIUS = 'memory.max-chunks.chunk-radius';
|
||||
public const MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT = 'memory.max-chunks.trigger-chunk-collect';
|
||||
public const MEMORY_MEMORY_DUMP = 'memory.memory-dump';
|
||||
public const MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER = 'memory.memory-dump.dump-async-worker';
|
||||
public const MEMORY_WORLD_CACHES = 'memory.world-caches';
|
||||
public const MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE = 'memory.world-caches.disable-chunk-cache';
|
||||
public const MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER = 'memory.world-caches.low-memory-trigger';
|
||||
public const NETWORK = 'network';
|
||||
public const NETWORK_ASYNC_COMPRESSION = 'network.async-compression';
|
||||
public const NETWORK_ASYNC_COMPRESSION_THRESHOLD = 'network.async-compression-threshold';
|
||||
public const NETWORK_BATCH_THRESHOLD = 'network.batch-threshold';
|
||||
public const NETWORK_COMPRESSION_LEVEL = 'network.compression-level';
|
||||
public const NETWORK_ENABLE_ENCRYPTION = 'network.enable-encryption';
|
||||
public const NETWORK_MAX_MTU_SIZE = 'network.max-mtu-size';
|
||||
public const NETWORK_UPNP_FORWARDING = 'network.upnp-forwarding';
|
||||
public const PLAYER = 'player';
|
||||
public const PLAYER_SAVE_PLAYER_DATA = 'player.save-player-data';
|
||||
public const PLAYER_VERIFY_XUID = 'player.verify-xuid';
|
||||
public const PLUGINS = 'plugins';
|
||||
public const PLUGINS_LEGACY_DATA_DIR = 'plugins.legacy-data-dir';
|
||||
public const SETTINGS = 'settings';
|
||||
public const SETTINGS_ASYNC_WORKERS = 'settings.async-workers';
|
||||
public const SETTINGS_ENABLE_DEV_BUILDS = 'settings.enable-dev-builds';
|
||||
public const SETTINGS_ENABLE_PROFILING = 'settings.enable-profiling';
|
||||
public const SETTINGS_FORCE_LANGUAGE = 'settings.force-language';
|
||||
public const SETTINGS_PROFILE_REPORT_TRIGGER = 'settings.profile-report-trigger';
|
||||
public const SETTINGS_QUERY_PLUGINS = 'settings.query-plugins';
|
||||
public const SETTINGS_SHUTDOWN_MESSAGE = 'settings.shutdown-message';
|
||||
public const TICKS_PER = 'ticks-per';
|
||||
public const TICKS_PER_AUTOSAVE = 'ticks-per.autosave';
|
||||
public const TIMINGS = 'timings';
|
||||
public const TIMINGS_HOST = 'timings.host';
|
||||
public const WORLDS = 'worlds';
|
||||
}
|
133
src/block/AmethystCluster.php
Normal file
133
src/block/AmethystCluster.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
use pocketmine\block\utils\AnyFacingTrait;
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
final class AmethystCluster extends Transparent{
|
||||
use AmethystTrait;
|
||||
use AnyFacingTrait;
|
||||
|
||||
public const STAGE_SMALL_BUD = 0;
|
||||
public const STAGE_MEDIUM_BUD = 1;
|
||||
public const STAGE_LARGE_BUD = 2;
|
||||
public const STAGE_CLUSTER = 3;
|
||||
|
||||
private int $stage = self::STAGE_CLUSTER;
|
||||
|
||||
public function describeBlockItemState(RuntimeDataDescriber $w) : void{
|
||||
$w->boundedIntAuto(self::STAGE_SMALL_BUD, self::STAGE_CLUSTER, $this->stage);
|
||||
}
|
||||
|
||||
public function getStage() : int{ return $this->stage; }
|
||||
|
||||
public function setStage(int $stage) : self{
|
||||
if($stage < self::STAGE_SMALL_BUD || $stage > self::STAGE_CLUSTER){
|
||||
throw new \InvalidArgumentException("Size must be in range " . self::STAGE_SMALL_BUD . " ... " . self::STAGE_CLUSTER);
|
||||
}
|
||||
$this->stage = $stage;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return match($this->stage){
|
||||
self::STAGE_SMALL_BUD => 1,
|
||||
self::STAGE_MEDIUM_BUD => 2,
|
||||
self::STAGE_LARGE_BUD => 4,
|
||||
self::STAGE_CLUSTER => 5,
|
||||
default => throw new AssumptionFailedError("Invalid stage $this->stage"),
|
||||
};
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$myAxis = Facing::axis($this->facing);
|
||||
|
||||
$box = AxisAlignedBB::one();
|
||||
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
|
||||
if($axis === $myAxis){
|
||||
continue;
|
||||
}
|
||||
$box->squash($axis, $this->stage === self::STAGE_SMALL_BUD ? 4 / 16 : 3 / 16);
|
||||
}
|
||||
$box->trim($this->facing, 1 - ($this->stage === self::STAGE_CLUSTER ? 7 / 16 : ($this->stage + 3) / 16));
|
||||
|
||||
return [$box];
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $facing) : bool{
|
||||
return $block->getAdjacentSupportType($facing) === SupportType::FULL;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if($this->stage === self::STAGE_CLUSTER){
|
||||
return [VanillaItems::AMETHYST_SHARD()->setCount(FortuneDropHelper::weighted($item, min: 4, maxBase: 4))];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getDropsForIncompatibleTool(Item $item) : array{
|
||||
if($this->stage === self::STAGE_CLUSTER){
|
||||
return [VanillaItems::AMETHYST_SHARD()->setCount(FortuneDropHelper::weighted($item, min: 2, maxBase: 2))];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ class Anvil extends Transparent implements Fallable{
|
||||
private int $damage = self::UNDAMAGED;
|
||||
|
||||
public function describeBlockItemState(RuntimeDataDescriber $w) : void{
|
||||
$w->boundedInt(2, self::UNDAMAGED, self::VERY_DAMAGED, $this->damage);
|
||||
$w->boundedIntAuto(self::UNDAMAGED, self::VERY_DAMAGED, $this->damage);
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
@ -78,7 +78,7 @@ class Anvil extends Transparent implements Fallable{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
@ -91,7 +91,7 @@ class Anvil extends Transparent implements Fallable{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->facing = Facing::rotateY($player->getHorizontalFacing(), true);
|
||||
$this->facing = Facing::rotateY($player->getHorizontalFacing(), false);
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
@ -46,6 +47,7 @@ use function mt_rand;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
class Bamboo extends Transparent{
|
||||
use StaticSupportTrait;
|
||||
|
||||
public const NO_LEAVES = 0;
|
||||
public const SMALL_LEAVES = 1;
|
||||
@ -56,7 +58,7 @@ class Bamboo extends Transparent{
|
||||
protected int $leafSize = self::NO_LEAVES;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->boundedInt(2, self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize);
|
||||
$w->boundedIntAuto(self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize);
|
||||
$w->bool($this->thick);
|
||||
$w->bool($this->ready);
|
||||
}
|
||||
@ -95,7 +97,7 @@ class Bamboo extends Transparent{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
private static function getOffsetSeed(int $x, int $y, int $z) : int{
|
||||
@ -120,12 +122,14 @@ class Bamboo extends Transparent{
|
||||
return new Vector3($retX, 0, $retZ);
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$supportBlock = $block->getSide(Facing::DOWN);
|
||||
return
|
||||
$block->getTypeId() === BlockTypeIds::GRAVEL ||
|
||||
$block->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$block->hasTypeTag(BlockTypeTags::MUD) ||
|
||||
$block->hasTypeTag(BlockTypeTags::SAND);
|
||||
$supportBlock->hasSameTypeId($this) ||
|
||||
$supportBlock->getTypeId() === BlockTypeIds::GRAVEL ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::MUD) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::SAND);
|
||||
}
|
||||
|
||||
private function seekToTop() : Bamboo{
|
||||
@ -153,14 +157,6 @@ class Bamboo extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$world = $this->position->getWorld();
|
||||
$below = $world->getBlock($this->position->down());
|
||||
if(!$this->canBeSupportedBy($below) && !$below->hasSameTypeId($this)){
|
||||
$world->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$world->getBlock($this->position->up())->canBeReplaced()){
|
||||
@ -177,7 +173,7 @@ class Bamboo extends Transparent{
|
||||
$newHeight = $height + $growAmount;
|
||||
|
||||
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
|
||||
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped
|
||||
if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
|
||||
$stemBlock = $stemBlock->setThick(true);
|
||||
}
|
||||
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
|
||||
|
@ -23,17 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Bamboo as ItemBamboo;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
final class BambooSapling extends Flowable{
|
||||
use StaticSupportTrait;
|
||||
|
||||
private bool $ready = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
@ -48,19 +52,13 @@ final class BambooSapling extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$supportBlock = $block->getSide(Facing::DOWN);
|
||||
return
|
||||
$block->getTypeId() === BlockTypeIds::GRAVEL ||
|
||||
$block->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$block->hasTypeTag(BlockTypeTags::MUD) ||
|
||||
$block->hasTypeTag(BlockTypeTags::SAND);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->position->getWorld()->getBlock($blockReplace->position->down()))){
|
||||
return false;
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
$supportBlock->getTypeId() === BlockTypeIds::GRAVEL ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::MUD) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::SAND);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
@ -73,13 +71,6 @@ final class BambooSapling extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){
|
||||
$world->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$world->getBlock($this->position->up())->canBeReplaced()){
|
||||
|
@ -55,12 +55,12 @@ class Barrel extends Opaque{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){
|
||||
$y = $player->getEyePos()->getY();
|
||||
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
|
||||
$y = $player->getEyePos()->y;
|
||||
|
||||
if($y - $this->position->getY() > 2){
|
||||
if($y - $this->position->y > 2){
|
||||
$this->facing = Facing::UP;
|
||||
}elseif($this->position->getY() - $y > 0){
|
||||
}elseif($this->position->y - $y > 0){
|
||||
$this->facing = Facing::DOWN;
|
||||
}else{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Banner as TileBanner;
|
||||
use pocketmine\block\utils\BannerPatternLayer;
|
||||
use pocketmine\block\utils\ColoredTrait;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Banner as ItemBanner;
|
||||
use pocketmine\item\Item;
|
||||
@ -35,7 +34,6 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function array_filter;
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
@ -48,11 +46,6 @@ abstract class BaseBanner extends Transparent{
|
||||
*/
|
||||
protected array $patterns = [];
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->color = DyeColor::BLACK();
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
parent::readStateFromWorld();
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
@ -95,11 +88,12 @@ abstract class BaseBanner extends Transparent{
|
||||
* @return $this
|
||||
*/
|
||||
public function setPatterns(array $patterns) : self{
|
||||
$checked = array_filter($patterns, fn($v) => $v instanceof BannerPatternLayer);
|
||||
if(count($checked) !== count($patterns)){
|
||||
throw new \TypeError("Deque must only contain " . BannerPatternLayer::class . " objects");
|
||||
foreach($patterns as $pattern){
|
||||
if(!$pattern instanceof BannerPatternLayer){
|
||||
throw new \TypeError("Array must only contain " . BannerPatternLayer::class . " objects");
|
||||
}
|
||||
}
|
||||
$this->patterns = $checked;
|
||||
$this->patterns = $patterns;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -111,7 +105,7 @@ abstract class BaseBanner extends Transparent{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
|
136
src/block/BaseBigDripleaf.php
Normal file
136
src/block/BaseBigDripleaf.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
abstract class BaseBigDripleaf extends Transparent{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
abstract protected function isHead() : bool;
|
||||
|
||||
private function canBeSupportedBy(Block $block, bool $head) : bool{
|
||||
//TODO: Moss block
|
||||
return
|
||||
($block instanceof BaseBigDripleaf && $block->isHead() === $head) ||
|
||||
$block->getTypeId() === BlockTypeIds::CLAY ||
|
||||
$block->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$block->hasTypeTag(BlockTypeTags::MUD);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(
|
||||
(!$this->isHead() && !$this->getSide(Facing::UP) instanceof BaseBigDripleaf) ||
|
||||
!$this->canBeSupportedBy($this->getSide(Facing::DOWN), false)
|
||||
){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$block = $blockReplace->getSide(Facing::DOWN);
|
||||
if(!$this->canBeSupportedBy($block, true)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
if($block instanceof BaseBigDripleaf){
|
||||
$this->facing = $block->facing;
|
||||
$tx->addBlock($block->position, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && $this->grow($player)){
|
||||
$item->pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function seekToHead() : ?BaseBigDripleaf{
|
||||
if($this->isHead()){
|
||||
return $this;
|
||||
}
|
||||
$step = 1;
|
||||
while(($next = $this->getSide(Facing::UP, $step)) instanceof BaseBigDripleaf){
|
||||
if($next->isHead()){
|
||||
return $next;
|
||||
}
|
||||
$step++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function grow(?Player $player) : bool{
|
||||
$head = $this->seekToHead();
|
||||
if($head === null){
|
||||
return false;
|
||||
}
|
||||
$pos = $head->position;
|
||||
$up = $pos->up();
|
||||
$world = $pos->getWorld();
|
||||
if(
|
||||
!$world->isInWorld($up->getFloorX(), $up->getFloorY(), $up->getFloorZ()) ||
|
||||
$world->getBlock($up)->getTypeId() !== BlockTypeIds::AIR
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
|
||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->facing));
|
||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->facing));
|
||||
|
||||
$ev = new StructureGrowEvent($head, $tx, $player);
|
||||
$ev->call();
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
return $tx->apply();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFlameEncouragement() : int{
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getFlammability() : int{
|
||||
return 100;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\effect\EffectInstance;
|
||||
use pocketmine\entity\FoodSource;
|
||||
@ -31,27 +32,16 @@ use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
abstract class BaseCake extends Transparent implements FoodSource{
|
||||
use StaticSupportTrait;
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if($down->getTypeId() !== BlockTypeIds::AIR){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::AIR){ //Replace with common break method
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getSide(Facing::DOWN)->getTypeId() !== BlockTypeIds::AIR;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
|
@ -23,21 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
use function mt_rand;
|
||||
|
||||
abstract class BaseCoral extends Transparent{
|
||||
use CoralTypeTrait;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->coralType = CoralType::TUBE();
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->dead){
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(40, 200));
|
||||
@ -46,11 +40,7 @@ abstract class BaseCoral extends Transparent{
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if(!$this->dead && !$this->isCoveredWithWater()){
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
BlockEventHelper::die($this, (clone $this)->setDead(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +72,6 @@ abstract class BaseCoral extends Transparent{
|
||||
protected function recalculateCollisionBoxes() : array{ return []; }
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ use function in_array;
|
||||
abstract class BaseRail extends Flowable{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockReplace->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
if($blockReplace->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ abstract class BaseRail extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$world = $this->position->getWorld();
|
||||
if(!$this->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
if(!$this->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
|
@ -49,6 +49,8 @@ abstract class BaseSign extends Transparent{
|
||||
use WoodTypeTrait;
|
||||
|
||||
protected SignText $text;
|
||||
private bool $waxed = false;
|
||||
|
||||
protected ?int $editorEntityRuntimeId = null;
|
||||
|
||||
/** @var \Closure() : Item */
|
||||
@ -69,6 +71,7 @@ abstract class BaseSign extends Transparent{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileSign){
|
||||
$this->text = $tile->getText();
|
||||
$this->waxed = $tile->isWaxed();
|
||||
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
|
||||
}
|
||||
|
||||
@ -80,6 +83,7 @@ abstract class BaseSign extends Transparent{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
assert($tile instanceof TileSign);
|
||||
$tile->setText($this->text);
|
||||
$tile->setWaxed($this->waxed);
|
||||
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
|
||||
}
|
||||
|
||||
@ -99,7 +103,7 @@ abstract class BaseSign extends Transparent{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
abstract protected function getSupportingFace() : int;
|
||||
@ -147,32 +151,53 @@ abstract class BaseSign extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function wax(Player $player, Item $item) : bool{
|
||||
if($this->waxed){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->waxed = true;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$item->pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player === null){
|
||||
return false;
|
||||
}
|
||||
if($this->waxed){
|
||||
return true;
|
||||
}
|
||||
|
||||
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
|
||||
ItemTypeIds::BONE_MEAL => DyeColor::WHITE(),
|
||||
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE(),
|
||||
ItemTypeIds::COCOA_BEANS => DyeColor::BROWN(),
|
||||
ItemTypeIds::BONE_MEAL => DyeColor::WHITE,
|
||||
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE,
|
||||
ItemTypeIds::COCOA_BEANS => DyeColor::BROWN,
|
||||
default => null
|
||||
};
|
||||
if($dyeColor !== null){
|
||||
$color = $dyeColor->equals(DyeColor::BLACK()) ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
|
||||
if($color->toARGB() === $this->text->getBaseColor()->toARGB()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)){
|
||||
$color = $dyeColor === DyeColor::BLACK ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
|
||||
if(
|
||||
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
|
||||
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
|
||||
){
|
||||
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
|
||||
return true;
|
||||
}
|
||||
}elseif($item->getTypeId() === ItemTypeIds::INK_SAC){
|
||||
return $this->changeSignGlowingState(false, $player, $item);
|
||||
}elseif($item->getTypeId() === ItemTypeIds::GLOW_INK_SAC){
|
||||
return $this->changeSignGlowingState(true, $player, $item);
|
||||
}elseif(match($item->getTypeId()){
|
||||
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item),
|
||||
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item),
|
||||
ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
|
||||
default => false
|
||||
}){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
$player->openSignEditor($this->position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +213,17 @@ abstract class BaseSign extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sign has been waxed using a honeycomb. If true, the sign cannot be edited by a player.
|
||||
*/
|
||||
public function isWaxed() : bool{ return $this->waxed; }
|
||||
|
||||
/** @return $this */
|
||||
public function setWaxed(bool $waxed) : self{
|
||||
$this->waxed = $waxed;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the runtime entity ID of the player editing this sign. Only this player will be able to edit the sign.
|
||||
* This is used to prevent multiple players from editing the same sign at the same time, and to prevent players
|
||||
@ -217,8 +253,8 @@ abstract class BaseSign extends Transparent{
|
||||
}
|
||||
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
|
||||
return TextFormat::clean($line, false);
|
||||
}, $text->getLines())));
|
||||
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $author->getId()){
|
||||
}, $text->getLines()), $this->text->getBaseColor(), $this->text->isGlowing()));
|
||||
if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
@ -235,4 +271,8 @@ abstract class BaseSign extends Transparent{
|
||||
public function asItem() : Item{
|
||||
return ($this->asItemCallback)();
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
return $this->woodType->isFlammable() ? 200 : 0;
|
||||
}
|
||||
}
|
||||
|
@ -48,11 +48,6 @@ class Bed extends Transparent{
|
||||
protected bool $occupied = false;
|
||||
protected bool $head = false;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->color = DyeColor::RED();
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->bool($this->occupied);
|
||||
@ -65,6 +60,8 @@ class Bed extends Transparent{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileBed){
|
||||
$this->color = $tile->getColor();
|
||||
}else{
|
||||
$this->color = DyeColor::RED; //legacy pre-1.1 beds don't have tiles
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -87,7 +84,7 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function isHeadPart() : bool{
|
||||
@ -148,7 +145,7 @@ class Bed extends Transparent{
|
||||
|
||||
$b = ($this->isHeadPart() ? $this : $other);
|
||||
|
||||
if($b->isOccupied()){
|
||||
if($b->occupied){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
|
||||
|
||||
return true;
|
||||
@ -177,11 +174,11 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
if($this->canBeSupportedAt($blockReplace)){
|
||||
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
|
||||
|
||||
$next = $this->getSide($this->getOtherHalfSide());
|
||||
if($next->canBeReplaced() && $this->canBeSupportedBy($next->getSide(Facing::DOWN))){
|
||||
if($next->canBeReplaced() && $this->canBeSupportedAt($next)){
|
||||
$nextState = clone $this;
|
||||
$nextState->head = true;
|
||||
$tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState);
|
||||
@ -208,8 +205,8 @@ class Bed extends Transparent{
|
||||
return parent::getAffectedBlocks();
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
return $block->getAdjacentSupportType(Facing::DOWN) !== SupportType::NONE;
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{ return 1; }
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Beetroot extends Crops{
|
||||
|
||||
@ -33,7 +33,7 @@ class Beetroot extends Crops{
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return [
|
||||
VanillaItems::BEETROOT(),
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(mt_rand(0, 3))
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(FortuneDropHelper::binomial($item, 0))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -41,25 +41,20 @@ use pocketmine\world\sound\BellRingSound;
|
||||
final class Bell extends Transparent{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
private BellAttachmentType $attachmentType;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->attachmentType = BellAttachmentType::FLOOR();
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
private BellAttachmentType $attachmentType = BellAttachmentType::FLOOR;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->bellAttachmentType($this->attachmentType);
|
||||
$w->enum($this->attachmentType);
|
||||
$w->horizontalFacing($this->facing);
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR())){
|
||||
if($this->attachmentType === BellAttachmentType::FLOOR){
|
||||
return [
|
||||
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
|
||||
];
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
if($this->attachmentType === BellAttachmentType::CEILING){
|
||||
return [
|
||||
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
|
||||
];
|
||||
@ -71,12 +66,12 @@ final class Bell extends Transparent{
|
||||
->trim(Facing::DOWN, 1 / 4);
|
||||
|
||||
return [
|
||||
$this->attachmentType->equals(BellAttachmentType::ONE_WALL()) ? $box->trim($this->facing, 3 / 16) : $box
|
||||
$this->attachmentType === BellAttachmentType::ONE_WALL ? $box->trim($this->facing, 3 / 16) : $box
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function getAttachmentType() : BellAttachmentType{ return $this->attachmentType; }
|
||||
@ -87,46 +82,43 @@ final class Bell extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block, int $face) : bool{
|
||||
return !$block->getSupportType($face)->equals(SupportType::NONE());
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
return $block->getAdjacentSupportType($face) !== SupportType::NONE;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
|
||||
return false;
|
||||
}
|
||||
if($face === Facing::UP){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->setFacing(Facing::opposite($player->getHorizontalFacing()));
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR());
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR);
|
||||
}elseif($face === Facing::DOWN){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
|
||||
return false;
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING());
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING);
|
||||
}else{
|
||||
$this->setFacing($face);
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))), $face)){
|
||||
$this->setAttachmentType(BellAttachmentType::ONE_WALL());
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
|
||||
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
|
||||
}
|
||||
$this->setAttachmentType(
|
||||
$this->canBeSupportedAt($blockReplace, $face) ?
|
||||
BellAttachmentType::TWO_WALLS :
|
||||
BellAttachmentType::ONE_WALL
|
||||
);
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP), Facing::DOWN)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN), Facing::UP)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing), Facing::opposite($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)))
|
||||
){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
foreach(match($this->attachmentType){
|
||||
BellAttachmentType::CEILING => [Facing::UP],
|
||||
BellAttachmentType::FLOOR => [Facing::DOWN],
|
||||
BellAttachmentType::ONE_WALL => [Facing::opposite($this->facing)],
|
||||
BellAttachmentType::TWO_WALLS => [$this->facing, Facing::opposite($this->facing)]
|
||||
} as $supportBlockDirection){
|
||||
if(!$this->canBeSupportedAt($this, $supportBlockDirection)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,14 +150,15 @@ final class Bell extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
public function getDropsForIncompatibleTool(Item $item) : array{
|
||||
return [$this->asItem()];
|
||||
}
|
||||
|
||||
private function isValidFaceToRing(int $faceHit) : bool{
|
||||
return (
|
||||
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
|
||||
(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
)
|
||||
);
|
||||
return match($this->attachmentType){
|
||||
BellAttachmentType::CEILING => true,
|
||||
BellAttachmentType::FLOOR => Facing::axis($faceHit) === Facing::axis($this->facing),
|
||||
BellAttachmentType::ONE_WALL, BellAttachmentType::TWO_WALLS => $faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
125
src/block/BigDripleafHead.php
Normal file
125
src/block/BigDripleafHead.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\DripleafState;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\world\sound\DripleafTiltDownSound;
|
||||
use pocketmine\world\sound\DripleafTiltUpSound;
|
||||
|
||||
class BigDripleafHead extends BaseBigDripleaf{
|
||||
|
||||
protected DripleafState $leafState = DripleafState::STABLE;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
parent::describeBlockOnlyState($w);
|
||||
$w->enum($this->leafState);
|
||||
}
|
||||
|
||||
protected function isHead() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLeafState() : DripleafState{
|
||||
return $this->leafState;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setLeafState(DripleafState $leafState) : self{
|
||||
$this->leafState = $leafState;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function setTiltAndScheduleTick(DripleafState $tilt) : void{
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setLeafState($tilt));
|
||||
$delay = $tilt->getScheduledUpdateDelayTicks();
|
||||
if($delay !== null){
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, $delay);
|
||||
}
|
||||
}
|
||||
|
||||
private function getLeafTopOffset() : float{
|
||||
return match($this->leafState){
|
||||
DripleafState::STABLE, DripleafState::UNSTABLE => 1 / 16,
|
||||
DripleafState::PARTIAL_TILT => 3 / 16,
|
||||
default => 0
|
||||
};
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
if(!$entity instanceof Projectile && $this->leafState === DripleafState::STABLE){
|
||||
//the entity must be standing on top of the leaf - do not collapse if the entity is standing underneath
|
||||
$intersection = AxisAlignedBB::one()
|
||||
->offset($this->position->x, $this->position->y, $this->position->z)
|
||||
->trim(Facing::DOWN, 1 - $this->getLeafTopOffset());
|
||||
if($entity->getBoundingBox()->intersectsWith($intersection)){
|
||||
$this->setTiltAndScheduleTick(DripleafState::UNSTABLE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
if($this->leafState !== DripleafState::FULL_TILT){
|
||||
$this->setTiltAndScheduleTick(DripleafState::FULL_TILT);
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltDownSound());
|
||||
}
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if($this->leafState !== DripleafState::STABLE){
|
||||
if($this->leafState === DripleafState::FULL_TILT){
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setLeafState(DripleafState::STABLE));
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltUpSound());
|
||||
}else{
|
||||
$this->setTiltAndScheduleTick(match($this->leafState){
|
||||
DripleafState::UNSTABLE => DripleafState::PARTIAL_TILT,
|
||||
DripleafState::PARTIAL_TILT => DripleafState::FULL_TILT,
|
||||
});
|
||||
$this->position->getWorld()->addSound($this->position, new DripleafTiltDownSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->leafState !== DripleafState::FULL_TILT){
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
->trim(Facing::DOWN, 11 / 16)
|
||||
->trim(Facing::UP, $this->getLeafTopOffset())
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
41
src/block/BigDripleafStem.php
Normal file
41
src/block/BigDripleafStem.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class BigDripleafStem extends BaseBigDripleaf{
|
||||
|
||||
protected function isHead() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaBlocks::BIG_DRIPLEAF_HEAD()->asItem();
|
||||
}
|
||||
}
|
@ -36,28 +36,40 @@ use pocketmine\data\runtime\RuntimeDataSizeCalculator;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\enchantment\AvailableEnchantmentRegistry;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTagRegistry;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemBlock;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function hash;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
class Block{
|
||||
public const INTERNAL_STATE_DATA_BITS = 8;
|
||||
public const INTERNAL_STATE_DATA_BITS = 11;
|
||||
public const INTERNAL_STATE_DATA_MASK = ~(~0 << self::INTERNAL_STATE_DATA_BITS);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Hardcoded int is `Binary::readLong(hash('xxh3', Binary::writeLLong(BlockTypeIds::AIR), binary: true))`
|
||||
* TODO: it would be much easier if we could just make this 0 or some other easy value
|
||||
*/
|
||||
public const EMPTY_STATE_ID = (BlockTypeIds::AIR << self::INTERNAL_STATE_DATA_BITS) | (-7482769108513497636 & self::INTERNAL_STATE_DATA_MASK);
|
||||
|
||||
protected BlockIdentifier $idInfo;
|
||||
protected string $fallbackName;
|
||||
protected BlockTypeInfo $typeInfo;
|
||||
@ -68,7 +80,25 @@ class Block{
|
||||
|
||||
private int $requiredBlockItemStateDataBits;
|
||||
private int $requiredBlockOnlyStateDataBits;
|
||||
private int $defaultBlockOnlyStateData;
|
||||
|
||||
private Block $defaultState;
|
||||
|
||||
private int $stateIdXorMask;
|
||||
|
||||
/**
|
||||
* Computes the mask to be XOR'd with the state data.
|
||||
* This is to improve distribution of the state data bits, which occupy the least significant bits of the state ID.
|
||||
* Improved distribution improves PHP array performance when using the state ID as a key, as PHP arrays use some of
|
||||
* the lower bits of integer keys directly without hashing.
|
||||
*
|
||||
* The type ID is included in the XOR mask. This is not necessary to improve distribution, but it reduces the number
|
||||
* of operations required to compute the state ID (micro optimization).
|
||||
*/
|
||||
private static function computeStateIdXorMask(int $typeId) : int{
|
||||
return
|
||||
$typeId << self::INTERNAL_STATE_DATA_BITS |
|
||||
(Binary::readLong(hash('xxh3', Binary::writeLLong($typeId), binary: true)) & self::INTERNAL_STATE_DATA_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
@ -87,7 +117,12 @@ class Block{
|
||||
$this->describeBlockOnlyState($calculator);
|
||||
$this->requiredBlockOnlyStateDataBits = $calculator->getBitsUsed();
|
||||
|
||||
$this->defaultBlockOnlyStateData = $this->encodeBlockOnlyState();
|
||||
$this->stateIdXorMask = self::computeStateIdXorMask($idInfo->getBlockTypeId());
|
||||
|
||||
//this must be done last, otherwise the defaultState could have uninitialized fields
|
||||
$defaultState = clone $this;
|
||||
$this->defaultState = $defaultState;
|
||||
$defaultState->defaultState = $defaultState;
|
||||
}
|
||||
|
||||
public function __clone(){
|
||||
@ -140,7 +175,7 @@ class Block{
|
||||
* {@link RuntimeBlockStateRegistry::fromStateId()}.
|
||||
*/
|
||||
public function getStateId() : int{
|
||||
return ($this->getTypeId() << self::INTERNAL_STATE_DATA_BITS) | $this->encodeFullState();
|
||||
return $this->encodeFullState() ^ $this->stateIdXorMask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,10 +217,11 @@ class Block{
|
||||
* Returns the block as an item.
|
||||
* Block-only state such as facing, powered/unpowered, open/closed, etc., is discarded.
|
||||
* Block-item state such as colour, wood type, etc. is preserved.
|
||||
* Complex state properties stored in the tile data (e.g. inventory) are discarded.
|
||||
*/
|
||||
public function asItem() : Item{
|
||||
$normalized = clone $this;
|
||||
$normalized->decodeBlockOnlyState($this->defaultBlockOnlyStateData);
|
||||
$normalized = clone $this->defaultState;
|
||||
$normalized->decodeBlockItemState($this->encodeBlockItemState());
|
||||
return new ItemBlock($normalized);
|
||||
}
|
||||
|
||||
@ -209,12 +245,6 @@ class Block{
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeFullState(int $data) : void{
|
||||
$reader = new RuntimeDataReader($this->requiredBlockItemStateDataBits + $this->requiredBlockOnlyStateDataBits, $data);
|
||||
$this->decodeBlockItemState($reader->readInt($this->requiredBlockItemStateDataBits));
|
||||
$this->decodeBlockOnlyState($reader->readInt($this->requiredBlockOnlyStateDataBits));
|
||||
}
|
||||
|
||||
private function encodeBlockItemState() : int{
|
||||
$writer = new RuntimeDataWriter($this->requiredBlockItemStateDataBits);
|
||||
|
||||
@ -240,11 +270,22 @@ class Block{
|
||||
}
|
||||
|
||||
private function encodeFullState() : int{
|
||||
$writer = new RuntimeDataWriter($this->requiredBlockItemStateDataBits + $this->requiredBlockOnlyStateDataBits);
|
||||
$writer->writeInt($this->requiredBlockItemStateDataBits, $this->encodeBlockItemState());
|
||||
$writer->writeInt($this->requiredBlockOnlyStateDataBits, $this->encodeBlockOnlyState());
|
||||
$blockItemBits = $this->requiredBlockItemStateDataBits;
|
||||
$blockOnlyBits = $this->requiredBlockOnlyStateDataBits;
|
||||
|
||||
return $writer->getValue();
|
||||
if($blockOnlyBits === 0 && $blockItemBits === 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
if($blockItemBits > 0){
|
||||
$result |= $this->encodeBlockItemState();
|
||||
}
|
||||
if($blockOnlyBits > 0){
|
||||
$result |= $this->encodeBlockOnlyState() << $blockItemBits;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,34 +326,44 @@ class Block{
|
||||
if($bits > Block::INTERNAL_STATE_DATA_BITS){
|
||||
throw new \LogicException("Block state data cannot use more than " . Block::INTERNAL_STATE_DATA_BITS . " bits");
|
||||
}
|
||||
for($stateData = 0; $stateData < (1 << $bits); ++$stateData){
|
||||
$v = clone $this;
|
||||
for($blockItemStateData = 0; $blockItemStateData < (1 << $this->requiredBlockItemStateDataBits); ++$blockItemStateData){
|
||||
$withType = clone $this;
|
||||
try{
|
||||
$v->decodeFullState($stateData);
|
||||
if($v->encodeFullState() !== $stateData){
|
||||
throw new \LogicException(static::class . "::decodeStateData() accepts invalid state data (returned " . $v->encodeFullState() . " for input $stateData)");
|
||||
$withType->decodeBlockItemState($blockItemStateData);
|
||||
$encoded = $withType->encodeBlockItemState();
|
||||
if($encoded !== $blockItemStateData){
|
||||
throw new \LogicException(static::class . "::decodeBlockItemState() accepts invalid inputs (returned $encoded for input $blockItemStateData)");
|
||||
}
|
||||
}catch(InvalidSerializedRuntimeDataException){ //invalid property combination, leave it
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $v;
|
||||
for($blockOnlyStateData = 0; $blockOnlyStateData < (1 << $this->requiredBlockOnlyStateDataBits); ++$blockOnlyStateData){
|
||||
$withState = clone $withType;
|
||||
try{
|
||||
$withState->decodeBlockOnlyState($blockOnlyStateData);
|
||||
$encoded = $withState->encodeBlockOnlyState();
|
||||
if($encoded !== $blockOnlyStateData){
|
||||
throw new \LogicException(static::class . "::decodeBlockOnlyState() accepts invalid inputs (returned $encoded for input $blockOnlyStateData)");
|
||||
}
|
||||
}catch(InvalidSerializedRuntimeDataException){ //invalid property combination, leave it
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $withState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is created, set, or has a neighbouring block update, to re-detect dynamic properties which
|
||||
* are not saved on the world.
|
||||
*
|
||||
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
|
||||
* AABBs and force recalculation.
|
||||
* are not saved in the blockstate ID.
|
||||
* If any such properties are updated, don't forget to clear things like AABB caches if necessary.
|
||||
*
|
||||
* A replacement block may be returned. This is useful if the block type changed due to reading of world data (e.g.
|
||||
* data from a block entity).
|
||||
*/
|
||||
public function readStateFromWorld() : Block{
|
||||
$this->collisionBoxes = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -351,7 +402,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
* Returns whether this block can be placed when obtained as an item.
|
||||
*/
|
||||
public function canBePlaced() : bool{
|
||||
return true;
|
||||
@ -406,6 +457,19 @@ class Block{
|
||||
return $this->typeInfo->getBreakInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tags that represent the type of item being enchanted and are used to determine
|
||||
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
* @see ItemEnchantmentTags
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEnchantmentTags() : array{
|
||||
return $this->typeInfo->getEnchantmentTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
@ -452,7 +516,8 @@ class Block{
|
||||
/**
|
||||
* Do actions when interacted by Item. Returns if it has done anything
|
||||
*
|
||||
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if the inventory is full)
|
||||
* @param Vector3 $clickVector Exact position where the click occurred, relative to the block's integer position
|
||||
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if the inventory is full)
|
||||
*/
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
return false;
|
||||
@ -507,16 +572,28 @@ class Block{
|
||||
return $this->getLightFilter() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block allows any light to pass through it.
|
||||
*/
|
||||
public function isTransparent() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated TL;DR: Don't use this function. Its results are confusing and inconsistent.
|
||||
*
|
||||
* No one is sure what the meaning of this property actually is. It's borrowed from Minecraft Java Edition, and is
|
||||
* used by various blocks for support checks.
|
||||
*
|
||||
* Things like signs and banners are considered "solid" despite having no collision box, and things like skulls and
|
||||
* flower pots are considered non-solid despite obviously being "solid" in the conventional, real-world sense.
|
||||
*/
|
||||
public function isSolid() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isFlowable
|
||||
* Returns whether this block can be destroyed by liquid flowing into its cell.
|
||||
*/
|
||||
public function canBeFlowedInto() : bool{
|
||||
return false;
|
||||
@ -538,6 +615,7 @@ class Block{
|
||||
*/
|
||||
final public function position(World $world, int $x, int $y, int $z) : void{
|
||||
$this->position = new Position($x, $y, $z, $world);
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -688,8 +766,14 @@ class Block{
|
||||
* @return Block
|
||||
*/
|
||||
public function getSide(int $side, int $step = 1){
|
||||
if($this->position->isValid()){
|
||||
return $this->position->getWorld()->getBlock($this->position->getSide($side, $step));
|
||||
$position = $this->position;
|
||||
if($position->isValid()){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$side] ?? [0, 0, 0];
|
||||
return $position->getWorld()->getBlockAt(
|
||||
$position->x + ($dx * $step),
|
||||
$position->y + ($dy * $step),
|
||||
$position->z + ($dz * $step)
|
||||
);
|
||||
}
|
||||
|
||||
throw new \LogicException("Block does not have a valid world");
|
||||
@ -703,8 +787,14 @@ class Block{
|
||||
*/
|
||||
public function getHorizontalSides() : \Generator{
|
||||
$world = $this->position->getWorld();
|
||||
foreach($this->position->sidesAroundAxis(Axis::Y) as $vector3){
|
||||
yield $world->getBlock($vector3);
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
[$dx, $dy, $dz] = Facing::OFFSET[$facing];
|
||||
//TODO: yield Facing as the key?
|
||||
yield $world->getBlockAt(
|
||||
$this->position->x + $dx,
|
||||
$this->position->y + $dy,
|
||||
$this->position->z + $dz
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,8 +806,13 @@ class Block{
|
||||
*/
|
||||
public function getAllSides() : \Generator{
|
||||
$world = $this->position->getWorld();
|
||||
foreach($this->position->sides() as $vector3){
|
||||
yield $world->getBlock($vector3);
|
||||
foreach(Facing::OFFSET as [$dx, $dy, $dz]){
|
||||
//TODO: yield Facing as the key?
|
||||
yield $world->getBlockAt(
|
||||
$this->position->x + $dx,
|
||||
$this->position->y + $dy,
|
||||
$this->position->z + $dz
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,7 +939,11 @@ class Block{
|
||||
* blocks placed on the given face can be supported by this block.
|
||||
*/
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::FULL();
|
||||
return SupportType::FULL;
|
||||
}
|
||||
|
||||
protected function getAdjacentSupportType(int $facing) : SupportType{
|
||||
return $this->getSide($facing)->getSupportType(Facing::opposite($facing));
|
||||
}
|
||||
|
||||
public function isFullCube() : bool{
|
||||
|
@ -24,11 +24,14 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Enum of all the block runtime IDs used by PocketMine-MP. These IDs are specific to PocketMine-MP and have no
|
||||
* relevance to any Minecraft vanilla things.
|
||||
* Every block in {@link VanillaBlocks} has a corresponding constant in this class. These constants can be used to
|
||||
* identify and compare block types efficiently using {@link Block::getTypeId()}.
|
||||
*
|
||||
* WARNING: DO NOT STORE THESE IDS. They can and will change without warning.
|
||||
* They should ONLY be used to IDENTIFY blocks at runtime.
|
||||
* Type ID is also used internally as part of block state ID, which is used to store blocks and their simple properties
|
||||
* in a memory-efficient way in chunks at runtime.
|
||||
*
|
||||
* WARNING: These are NOT a replacement for Minecraft legacy IDs. Do **NOT** hardcode their values, or store them in
|
||||
* configs or databases. They will change without warning.
|
||||
*/
|
||||
final class BlockTypeIds{
|
||||
|
||||
@ -559,10 +562,10 @@ final class BlockTypeIds{
|
||||
public const WEIGHTED_PRESSURE_PLATE_HEAVY = 10532;
|
||||
public const WEIGHTED_PRESSURE_PLATE_LIGHT = 10533;
|
||||
public const WHEAT = 10534;
|
||||
|
||||
public const BUDDING_AMETHYST = 10535;
|
||||
public const WHITE_TULIP = 10536;
|
||||
public const WOOL = 10537;
|
||||
|
||||
public const AMETHYST_CLUSTER = 10538;
|
||||
public const GLAZED_TERRACOTTA = 10539;
|
||||
public const AMETHYST = 10540;
|
||||
public const ANCIENT_DEBRIS = 10541;
|
||||
@ -714,8 +717,56 @@ final class BlockTypeIds{
|
||||
public const FLOWERING_AZALEA_LEAVES = 10687;
|
||||
public const REINFORCED_DEEPSLATE = 10688;
|
||||
public const CAVE_VINES = 10689;
|
||||
public const GLOW_LICHEN = 10690;
|
||||
public const CHERRY_BUTTON = 10691;
|
||||
public const CHERRY_DOOR = 10692;
|
||||
public const CHERRY_FENCE = 10693;
|
||||
public const CHERRY_FENCE_GATE = 10694;
|
||||
public const CHERRY_LEAVES = 10695;
|
||||
public const CHERRY_LOG = 10696;
|
||||
public const CHERRY_PLANKS = 10697;
|
||||
public const CHERRY_PRESSURE_PLATE = 10698;
|
||||
public const CHERRY_SAPLING = 10699;
|
||||
public const CHERRY_SIGN = 10700;
|
||||
public const CHERRY_SLAB = 10701;
|
||||
public const CHERRY_STAIRS = 10702;
|
||||
public const CHERRY_TRAPDOOR = 10703;
|
||||
public const CHERRY_WALL_SIGN = 10704;
|
||||
public const CHERRY_WOOD = 10705;
|
||||
public const SMALL_DRIPLEAF = 10706;
|
||||
public const BIG_DRIPLEAF_HEAD = 10707;
|
||||
public const BIG_DRIPLEAF_STEM = 10708;
|
||||
public const PINK_PETALS = 10709;
|
||||
public const CRIMSON_ROOTS = 10710;
|
||||
public const WARPED_ROOTS = 10711;
|
||||
public const CHISELED_BOOKSHELF = 10712;
|
||||
public const TORCHFLOWER = 10713;
|
||||
public const TORCHFLOWER_CROP = 10714;
|
||||
public const PITCHER_PLANT = 10715;
|
||||
public const PITCHER_CROP = 10716;
|
||||
public const DOUBLE_PITCHER_CROP = 10717;
|
||||
public const CAMPFIRE = 10718;
|
||||
public const SOUL_CAMPFIRE = 10719;
|
||||
public const TUFF_SLAB = 10720;
|
||||
public const TUFF_STAIRS = 10721;
|
||||
public const TUFF_WALL = 10722;
|
||||
public const CHISELED_TUFF = 10723;
|
||||
public const TUFF_BRICKS = 10724;
|
||||
public const TUFF_BRICK_SLAB = 10725;
|
||||
public const TUFF_BRICK_STAIRS = 10726;
|
||||
public const TUFF_BRICK_WALL = 10727;
|
||||
public const CHISELED_TUFF_BRICKS = 10728;
|
||||
public const POLISHED_TUFF = 10729;
|
||||
public const POLISHED_TUFF_SLAB = 10730;
|
||||
public const POLISHED_TUFF_STAIRS = 10731;
|
||||
public const POLISHED_TUFF_WALL = 10732;
|
||||
public const COPPER_BULB = 10733;
|
||||
public const COPPER_DOOR = 10734;
|
||||
public const COPPER_TRAPDOOR = 10735;
|
||||
public const CHISELED_COPPER = 10736;
|
||||
public const COPPER_GRATE = 10737;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10690;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10738;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
@ -35,10 +35,12 @@ final class BlockTypeInfo{
|
||||
|
||||
/**
|
||||
* @param string[] $typeTags
|
||||
* @param string[] $enchantmentTags
|
||||
*/
|
||||
public function __construct(
|
||||
private BlockBreakInfo $breakInfo,
|
||||
array $typeTags = []
|
||||
array $typeTags = [],
|
||||
private array $enchantmentTags = []
|
||||
){
|
||||
$this->typeTags = array_fill_keys($typeTags, true);
|
||||
}
|
||||
@ -49,4 +51,17 @@ final class BlockTypeInfo{
|
||||
public function getTypeTags() : array{ return array_keys($this->typeTags); }
|
||||
|
||||
public function hasTypeTag(string $tag) : bool{ return isset($this->typeTags[$tag]); }
|
||||
|
||||
/**
|
||||
* Returns tags that represent the type of item being enchanted and are used to determine
|
||||
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
* @see ItemEnchantmentTags
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEnchantmentTags() : array{
|
||||
return $this->enchantmentTags;
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,6 @@ use pocketmine\item\Item;
|
||||
|
||||
class BlueIce extends Opaque{
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getFrictionFactor() : float{
|
||||
return 0.99;
|
||||
}
|
||||
@ -38,4 +34,8 @@ class BlueIce extends Opaque{
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function array_key_exists;
|
||||
use function spl_object_id;
|
||||
|
||||
class BrewingStand extends Transparent{
|
||||
|
||||
@ -44,7 +45,7 @@ class BrewingStand extends Transparent{
|
||||
protected array $slots = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->brewingStandSlots($this->slots);
|
||||
$w->enumSet($this->slots, BrewingStandSlot::cases());
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
@ -61,18 +62,18 @@ class BrewingStand extends Transparent{
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function hasSlot(BrewingStandSlot $slot) : bool{
|
||||
return array_key_exists($slot->id(), $this->slots);
|
||||
return array_key_exists(spl_object_id($slot), $this->slots);
|
||||
}
|
||||
|
||||
public function setSlot(BrewingStandSlot $slot, bool $occupied) : self{
|
||||
if($occupied){
|
||||
$this->slots[$slot->id()] = $slot;
|
||||
$this->slots[spl_object_id($slot)] = $slot;
|
||||
}else{
|
||||
unset($this->slots[$slot->id()]);
|
||||
unset($this->slots[spl_object_id($slot)]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@ -89,7 +90,7 @@ class BrewingStand extends Transparent{
|
||||
public function setSlots(array $slots) : self{
|
||||
$this->slots = [];
|
||||
foreach($slots as $slot){
|
||||
$this->slots[$slot->id()] = $slot;
|
||||
$this->slots[spl_object_id($slot)] = $slot;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@ -114,7 +115,7 @@ class BrewingStand extends Transparent{
|
||||
}
|
||||
|
||||
$changed = false;
|
||||
foreach(BrewingStandSlot::getAll() as $slot){
|
||||
foreach(BrewingStandSlot::cases() as $slot){
|
||||
$occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber());
|
||||
if($occupied !== $this->hasSlot($slot)){
|
||||
$this->setSlot($slot, $occupied);
|
||||
|
68
src/block/BuddingAmethyst.php
Normal file
68
src/block/BuddingAmethyst.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AmethystTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use function array_rand;
|
||||
use function mt_rand;
|
||||
|
||||
final class BuddingAmethyst extends Opaque{
|
||||
use AmethystTrait;
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(1, 5) === 1){
|
||||
$face = Facing::ALL[array_rand(Facing::ALL)];
|
||||
|
||||
$adjacent = $this->getSide($face);
|
||||
//TODO: amethyst buds can spawn in water - we need waterlogging support for this
|
||||
|
||||
$newStage = null;
|
||||
|
||||
if($adjacent->getTypeId() === BlockTypeIds::AIR){
|
||||
$newStage = AmethystCluster::STAGE_SMALL_BUD;
|
||||
}elseif(
|
||||
$adjacent->getTypeId() === BlockTypeIds::AMETHYST_CLUSTER &&
|
||||
$adjacent instanceof AmethystCluster &&
|
||||
$adjacent->getStage() < AmethystCluster::STAGE_CLUSTER &&
|
||||
$adjacent->getFacing() === $face
|
||||
){
|
||||
$newStage = $adjacent->getStage() + 1;
|
||||
}
|
||||
if($newStage !== null){
|
||||
BlockEventHelper::grow($adjacent, VanillaBlocks::AMETHYST_CLUSTER()->setStage($newStage)->setFacing($face), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user