mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 19:02:59 +00:00
Compare commits
1066 Commits
Author | SHA1 | Date | |
---|---|---|---|
9a6d7b505c | |||
1e3b025916 | |||
396d64c60b | |||
d7a0f5362e | |||
c5dcd268ad | |||
910c4c4b24 | |||
2fd6e769e6 | |||
69155015c9 | |||
6854830b6e | |||
fbaf8e3fc8 | |||
c62845e92a | |||
c7930ce9ec | |||
475888b031 | |||
40b90bb722 | |||
5a4550a4fc | |||
7bbc04e6de | |||
3ba662f64f | |||
5d7b99daf4 | |||
e47627f565 | |||
39207c7992 | |||
8912a97be7 | |||
8d2a9ce67c | |||
811352e2ef | |||
4562cfb85b | |||
cb1aac3cd4 | |||
3dd1a14fb7 | |||
63c3127248 | |||
96c32d24ba | |||
d64a9d8b52 | |||
92c29b8172 | |||
0ac9584bbb | |||
fe12e8d944 | |||
7529953f0a | |||
00dbb6855a | |||
7eca3e8081 | |||
b58d7fc82a | |||
ceea8220a9 | |||
18013e9551 | |||
bd3e9e1cad | |||
6173471cca | |||
644881372d | |||
a12aac71fd | |||
608fcd6cd7 | |||
ce9b25e97a | |||
f948cb0086 | |||
6c52723d97 | |||
d5b7bf77b0 | |||
b1a5b02d3a | |||
74e052de51 | |||
a5397d55fe | |||
65ef929d22 | |||
441919c5e3 | |||
448aeec780 | |||
78aea5c34c | |||
d7f40f75d2 | |||
b47035fbab | |||
f0925ff9dc | |||
d9324b9951 | |||
1d9336ed67 | |||
d37142af4b | |||
7c068101b7 | |||
217f9aea02 | |||
2f5e08067d | |||
a8556dff02 | |||
664089861a | |||
edb8f19a0c | |||
6c0254c1eb | |||
0bb9fb09cc | |||
ab21fcdd67 | |||
ad6a423d12 | |||
b03df4f1e6 | |||
0a2a6e2b3a | |||
0eb751c1c9 | |||
b59b1e491e | |||
95e8c68fde | |||
7e16f9be8f | |||
768650cee0 | |||
c2c529e2da | |||
289e86e899 | |||
7d59bafd83 | |||
1bbe053848 | |||
2ed48c8469 | |||
d786ed5ebf | |||
a9f06fc5f4 | |||
dff3f45d22 | |||
1e17d86421 | |||
ba18a81e88 | |||
329c2a6c0f | |||
39218017ca | |||
fc487b17be | |||
91ac47ecba | |||
f4a1d69075 | |||
cbeae906e1 | |||
b25e8e26f0 | |||
a79be994de | |||
e26c8b9e9f | |||
4e9c3e101d | |||
d295e1be54 | |||
2f3fcef97c | |||
4df1f7f502 | |||
d74719704e | |||
c5056e0a43 | |||
a47aa50477 | |||
5021096bdd | |||
f7930a3a0b | |||
bb7df60a4d | |||
992cb06da6 | |||
bb3f87f862 | |||
d2eddf9d33 | |||
81ca0c8fbf | |||
fc77b14760 | |||
52b6f1a492 | |||
0233e74f4f | |||
dd355c58d8 | |||
267032cff9 | |||
d4b8c47a65 | |||
4a3d9f8f83 | |||
1c96e7936c | |||
6cecd690b2 | |||
91e38d1f97 | |||
653178c1fd | |||
eb06535ed1 | |||
f9bcc8e862 | |||
ece49f011c | |||
f43ca405d4 | |||
d146175d27 | |||
3baa5ab712 | |||
e647e8c933 | |||
c02bead12b | |||
e9ca25c1cb | |||
a513cca582 | |||
9a47c1d401 | |||
433f5451d7 | |||
64e505defb | |||
33d1755eae | |||
fc63c54116 | |||
db07976aab | |||
0e4b79ea77 | |||
588c9b114b | |||
b095f606c1 | |||
b312e93176 | |||
172ce659b8 | |||
61933624d2 | |||
0d31b25fba | |||
90beaeaeb4 | |||
466f7e98ed | |||
59be901efe | |||
0d169b4e80 | |||
b1c0eae1f6 | |||
80832ff763 | |||
f7d0d16eb3 | |||
6375139d0b | |||
567bd8abb5 | |||
3d038b28ff | |||
0c9b6a6797 | |||
639f089c55 | |||
9010b2743c | |||
4c91c4aaf1 | |||
17125ce0e3 | |||
3987ee6cb2 | |||
51a684c0ea | |||
43e69041fc | |||
5d2b0acfc8 | |||
7d1d62042c | |||
2a33c9ed3b | |||
b03733442b | |||
9c9929ff39 | |||
566a8a261f | |||
a9e5f92958 | |||
17dde140a5 | |||
ee7d4728d8 | |||
923dcec4e7 | |||
1e5597f0d5 | |||
aebcfc516f | |||
97ef209c5f | |||
99faeb8d05 | |||
1305fd5fb2 | |||
7a137f932f | |||
63e8b1cf3a | |||
65bce762ff | |||
529700bb8b | |||
b2017c8462 | |||
bf44edd179 | |||
aa374083d8 | |||
8c0d3943d8 | |||
d02c6668b2 | |||
880d01daea | |||
50b70708fb | |||
437fa615b8 | |||
0ee6cdb058 | |||
97d6a79b25 | |||
8b5e4c1c16 | |||
c5d716dc9d | |||
95d0a3bf41 | |||
cf707e15c2 | |||
1308cda5c2 | |||
214a5ddc15 | |||
9f7dfe3355 | |||
9b55d18393 | |||
31465525e3 | |||
74613b9b09 | |||
1cefe24414 | |||
4357c110c8 | |||
8bf85d4a18 | |||
b5e6dec0c6 | |||
a3306914cc | |||
3b32ea1b0b | |||
7ec32f981e | |||
b0c87e9d06 | |||
99996b62d6 | |||
fed2a6d917 | |||
1d4b6dc66e | |||
1cb6d9f5af | |||
174c9a48f5 | |||
0a9b52618d | |||
7ae6425d05 | |||
b5cfab497d | |||
774e23137e | |||
3984d220bb | |||
43bc3c7b25 | |||
eb62dc3294 | |||
0b497654f2 | |||
279056fe2f | |||
cd233b123b | |||
64dd5e3bf6 | |||
4e5cc57560 | |||
d476a4c1aa | |||
95263795a8 | |||
2db86d151f | |||
f0358b09b7 | |||
80a432d9ff | |||
ec9f9a469f | |||
d450264e1c | |||
5e92f55d35 | |||
58c1bfe5d2 | |||
641d35a30f | |||
642630a4d2 | |||
d79e6354a0 | |||
ff63983de4 | |||
588215044e | |||
5c1e9a35a9 | |||
aad9f5fb45 | |||
a8dca190c6 | |||
e5f5fe80f9 | |||
36ab34df29 | |||
dda8ff18b1 | |||
6562335120 | |||
0c463a8721 | |||
a66f966b08 | |||
cca22046ab | |||
d19f0bf7be | |||
ff2391e74a | |||
39e10da88d | |||
beed6efd4e | |||
e5bc4deb12 | |||
2fcff13578 | |||
b4b8ef1c6b | |||
9650b7f03a | |||
a3502a711d | |||
83ddcce987 | |||
732dac6fc1 | |||
d5e3636908 | |||
ef100b248b | |||
d03bbb0426 | |||
93e661aa4e | |||
50efcf7424 | |||
a7ac6070dc | |||
069062f122 | |||
bf7014e0ec | |||
824ed0a56a | |||
b3ccf41307 | |||
a39938e6b6 | |||
d5bf88acc0 | |||
2d0602d19f | |||
3a2a23b236 | |||
1a8c8af523 | |||
1e9d83f014 | |||
6153a2ac70 | |||
ed452b9ccd | |||
c19880e045 | |||
cdbdcb5d67 | |||
29301614e8 | |||
2fdc46c165 | |||
bfd1b2c635 | |||
1671405cd0 | |||
fe982c697b | |||
1572b31b8d | |||
b6f6671a81 | |||
6da467b142 | |||
44af519cd6 | |||
fb31e6085e | |||
e4548da173 | |||
0d5287bf0b | |||
a9361b3f8b | |||
6e4c62744e | |||
9a0ead6deb | |||
d74824c8d5 | |||
d4eb73abe9 | |||
7864294336 | |||
2a910c1cc2 | |||
cd04a3db2e | |||
572def9245 | |||
20f5bed926 | |||
14d17a9546 | |||
b74c092d9b | |||
7bcc663b60 | |||
b3bda788d9 | |||
2cc8a56e68 | |||
57deb60355 | |||
92e47b98f8 | |||
b84c110819 | |||
4fadb63f67 | |||
c83f0896ac | |||
0d29a138fb | |||
421379fc77 | |||
293cea7714 | |||
15645759e9 | |||
6ae7cb288e | |||
7df2719fce | |||
10b8dcfdd1 | |||
c1fbac412e | |||
3feaa18f6c | |||
41970feb57 | |||
cd4bb91676 | |||
2be527060f | |||
6f68c6d8a0 | |||
ac16378410 | |||
1f9dfa77bf | |||
0c7f8470b9 | |||
fc56c041f3 | |||
d6bbf8217d | |||
22486dd75e | |||
37ec1193ea | |||
bda0ca23b4 | |||
b21cd82e94 | |||
1c7b1e9e5d | |||
b87e4d8bd3 | |||
86a2f8e360 | |||
def2f8c145 | |||
ed7c95549d | |||
cfb0cad7e0 | |||
83e5b0adb6 | |||
4650a3bb22 | |||
5e5661de75 | |||
e2f1b10165 | |||
455f9fa92e | |||
dec188d4ad | |||
2db3498891 | |||
a7dfa0907c | |||
f448b2e685 | |||
6a0c54f850 | |||
77a18d0aea | |||
140a809c40 | |||
cb7c136035 | |||
83a136a176 | |||
3f7d8a3777 | |||
3c55db531d | |||
93d4475111 | |||
e4fc523251 | |||
7804172846 | |||
7d29ac8293 | |||
481bda8cd5 | |||
d1c75da14b | |||
89e29448ee | |||
66e70e5b0e | |||
785dc71256 | |||
d459afaa54 | |||
db586233da | |||
23e98a30f5 | |||
5bc7ca6569 | |||
f39d2a9be3 | |||
47d98af6ac | |||
9f97654f6f | |||
82ba7903c8 | |||
441b06f6c7 | |||
112974758e | |||
313850eec4 | |||
a82923acb4 | |||
67887afd6b | |||
3d03bb1301 | |||
c063198b89 | |||
f3ca6de1eb | |||
88eafdd614 | |||
6dd5fec4ea | |||
6866c86d39 | |||
a735a69870 | |||
a0ea74c08f | |||
ca4b8a5827 | |||
f88c4d9a8c | |||
66cd156d80 | |||
222049927a | |||
d72e947d15 | |||
770cca2efa | |||
033dac3d16 | |||
1ee02d7e02 | |||
85678aa356 | |||
1d253bc8c2 | |||
973a56ab28 | |||
9e0b4621be | |||
ffb3af3e0d | |||
b3f03d7ae6 | |||
2585160ca2 | |||
14d3e6c7d5 | |||
65ec318c30 | |||
a25cb3741a | |||
b7a15b6e01 | |||
456439566b | |||
5b89833d5c | |||
fb25e05416 | |||
78b5be8dd0 | |||
0a92e91a30 | |||
b3a13a2f21 | |||
08b9495bce | |||
5779622235 | |||
c16893cbac | |||
7f175b47e6 | |||
0e73ffe555 | |||
1ffd38b37b | |||
bd13f39156 | |||
0c446c276c | |||
0284e65f60 | |||
b0d787b3d3 | |||
65e3ed43d5 | |||
75eba9c9ed | |||
b5a049d1fe | |||
bd9fcffe62 | |||
feffbc2c5b | |||
53b51c99b4 | |||
5cb77c8365 | |||
bf8befc40b | |||
f75ca312cc | |||
d144832928 | |||
709a869045 | |||
ac056044ce | |||
fc8434308b | |||
5426b41447 | |||
af2babec23 | |||
5d5366a7c8 | |||
717ab1989a | |||
83db186b6a | |||
6a4e5aba8b | |||
c13170a00b | |||
98778052bb | |||
e86e8254a8 | |||
1b852ac290 | |||
10b799fadb | |||
bc5008334a | |||
d6af2b12f4 | |||
ad2d59923c | |||
792c1b62b7 | |||
e90abecf38 | |||
575dd47db7 | |||
e4a5defabb | |||
c9626c610b | |||
8fb7fff6b9 | |||
5c8d8ff61f | |||
99b55f7427 | |||
dce8bd6d21 | |||
8fa81242d6 | |||
2f4a9469b6 | |||
4d34885b15 | |||
c5b2488fc1 | |||
d62df585f2 | |||
19d7c2b552 | |||
f7ab0a3b92 | |||
036e06e889 | |||
9343a0b800 | |||
14b4644b03 | |||
464b65b25c | |||
15586ed80e | |||
0f8ad8ecf7 | |||
82b9afef77 | |||
2fc84f6c67 | |||
566f5935a3 | |||
44e4dabf6e | |||
8acc535218 | |||
e9a1cb7ce5 | |||
a21419d120 | |||
c2b599166c | |||
df7a1fcba6 | |||
d77a95e4af | |||
5c72807b16 | |||
5c6927e16c | |||
9abbb85a93 | |||
554182b2cb | |||
d669a6f0c7 | |||
16ed16722a | |||
42f9336f7a | |||
5d9f783037 | |||
01ca14c314 | |||
608c6ed6db | |||
c26631d06d | |||
b75bc61a64 | |||
3724479be3 | |||
eb916fe43d | |||
5e3b3a0700 | |||
e10a624444 | |||
b20e04539d | |||
4852f8029a | |||
2940547026 | |||
24e72ec109 | |||
c4f85e526b | |||
6cee428287 | |||
bcba064d69 | |||
dbc0b9634b | |||
86647683bc | |||
040516054f | |||
64f0e58e60 | |||
62f21516d1 | |||
c553f7cf06 | |||
fec89b7803 | |||
4e3964ffce | |||
93254523e6 | |||
2b61c025c2 | |||
e00f8e3a32 | |||
e2855aadff | |||
c7133bc2e6 | |||
4d6ec66270 | |||
baf75089f5 | |||
705df7d508 | |||
f1a63098bd | |||
75d7adfb2d | |||
4b1052022c | |||
9d535e2917 | |||
3ccd288afd | |||
06655bee78 | |||
0ad2985247 | |||
5a8983dd81 | |||
269b6ed16a | |||
f031c3c602 | |||
f3e09dd7d5 | |||
68e704bf97 | |||
9898577135 | |||
38651fde74 | |||
784d602600 | |||
15c99cfe77 | |||
d5fa0a2fc5 | |||
0da9260994 | |||
63ee03a7be | |||
df2d1fd4f9 | |||
088a2e478c | |||
9f65fb5f90 | |||
caa4b78a3f | |||
14352a05bc | |||
bb5b52d998 | |||
5e22b70b6d | |||
02513818a9 | |||
d641812c52 | |||
a851496293 | |||
35fd71eddf | |||
be168beba0 | |||
01a8bce2dd | |||
becbd562d6 | |||
82edb20e0c | |||
64a8c462f9 | |||
4ec97d0f7a | |||
016a80bb70 | |||
ce66a400a7 | |||
50776875bb | |||
bcb0e2ff1f | |||
1584768c80 | |||
5fd685e07d | |||
6ecfbd1bde | |||
b661097c51 | |||
0771295899 | |||
702816458c | |||
e040c2b281 | |||
e12e4e8fb8 | |||
d15a90899e | |||
237c2866e0 | |||
38d6284671 | |||
7355798e77 | |||
4b662d65b3 | |||
c87a3b054c | |||
4b73bedd57 | |||
8b86e43d51 | |||
eade2d2af0 | |||
f2299a562f | |||
3fcf6372e0 | |||
533cb77c50 | |||
681a9bb0e1 | |||
6c080dae55 | |||
670fb4de74 | |||
6d7318af43 | |||
97c0d72e28 | |||
4ccae2d1de | |||
b36c6ea13b | |||
39b8daeeec | |||
c492352d50 | |||
8f1452acd1 | |||
8a2ba584ab | |||
227f28a6d2 | |||
812d5c3f58 | |||
9a5a03ef83 | |||
38d75f3aab | |||
179cac45f5 | |||
1591881bf2 | |||
7bbb2617c8 | |||
2ec65ba799 | |||
3dd7c09351 | |||
afc6e8878d | |||
7eaf1246a0 | |||
645c44ae9c | |||
331b05c681 | |||
3abe80184a | |||
7618b13c6e | |||
351cd4bfd7 | |||
1154c7c1ab | |||
4a3e42f82e | |||
8ecf9717d6 | |||
3ca80b353b | |||
7d172e2211 | |||
e934e2bd26 | |||
3177d19730 | |||
82104a8251 | |||
e9a17374d1 | |||
a31bd19b5a | |||
c82dfef9b0 | |||
1181b13b5d | |||
688be0a404 | |||
33e6b63fe5 | |||
5d92eddc82 | |||
0324392cd8 | |||
01b0742bd4 | |||
02cf6ae46c | |||
fcb2ccab99 | |||
a38a5c67f1 | |||
a45a96b3ee | |||
86efa0aae6 | |||
2b84cb7be4 | |||
26df37e6ef | |||
554f96bc24 | |||
6482aa7c64 | |||
6d941640a9 | |||
0ea3861d43 | |||
a323a5e56d | |||
79caba22a7 | |||
30815bc8a2 | |||
df3a69dcb7 | |||
d4b7f66e15 | |||
8e767da29e | |||
c0b15de504 | |||
1d5430937f | |||
9de88aa734 | |||
9e59819f06 | |||
c60311617d | |||
7bc3dcdefd | |||
22edca610c | |||
6eac2ea7a5 | |||
cd016bedce | |||
95ad3f16e1 | |||
fb4d332d1a | |||
a06b9294df | |||
221c6b8570 | |||
eb95e2a97e | |||
ec6769a6fc | |||
343a12626e | |||
d11d77d328 | |||
20eb80fc9a | |||
071067effb | |||
89cc449808 | |||
1e59679ec2 | |||
8b8560a701 | |||
161ab5af16 | |||
ab41594da2 | |||
80d4c11061 | |||
e767796986 | |||
dea7031b86 | |||
7e3d099d5b | |||
8b1bd5b7ff | |||
4dbac79e86 | |||
5abc7f866a | |||
9dc2a01c2e | |||
6f0aa360d1 | |||
7c3b78b0a0 | |||
12e4724b19 | |||
52e74296de | |||
3b7e274c34 | |||
db6abfb227 | |||
2adaca2521 | |||
b6f39035f8 | |||
cfd550451f | |||
9ff1bf6deb | |||
212c94ce98 | |||
77530b0c24 | |||
3e1246acff | |||
4c29f98292 | |||
5cc0d92eff | |||
b875b68fc7 | |||
a5ebbf8adb | |||
217385efb9 | |||
f70c36baf9 | |||
eda4ae9181 | |||
d2e421c424 | |||
6da53536ca | |||
1da6aa40f8 | |||
a913736235 | |||
124edeacaf | |||
a216f4d089 | |||
17b0e0be84 | |||
81d8aed2e2 | |||
69418084bc | |||
593a4b65ea | |||
869d340f10 | |||
5d64d4a1e3 | |||
cc3c5bdb8d | |||
e1c4150dff | |||
755ca1af9b | |||
7d78b9cb2c | |||
91f802ac7a | |||
72cfea3a63 | |||
a353872327 | |||
f4d71d0b48 | |||
a6299b0927 | |||
6e372d9e36 | |||
ad8132ae11 | |||
5d39d7a1c8 | |||
937bb4c6ce | |||
cf15a0913d | |||
33cf085692 | |||
3752225ed5 | |||
5cf572892f | |||
20ff5d5a3d | |||
b88a47929f | |||
159392e738 | |||
2f03af51dd | |||
cb76c149e1 | |||
6d7bf1c5d8 | |||
ed2a239334 | |||
46c504e529 | |||
0e7e776862 | |||
de12b701ac | |||
b402df8b91 | |||
dca457b1e0 | |||
72cff0ee11 | |||
09778e3f1b | |||
9f5d4180c9 | |||
c8a7a53d70 | |||
223893fd5c | |||
a58551af5b | |||
f7dce4af88 | |||
dff5c30172 | |||
e8994dbc17 | |||
aaba8a2a9a | |||
27056b6c37 | |||
9930de01b9 | |||
cd021f49cd | |||
e4ce467c0b | |||
6b4687a36b | |||
c085bf0db4 | |||
e0d4bd985e | |||
3339225fe8 | |||
df33e179e5 | |||
624a7dff16 | |||
1d314ad4ce | |||
5a98b08ee8 | |||
ded7e24f67 | |||
e73bb07da0 | |||
d9d02d526a | |||
f272986903 | |||
988da8eaab | |||
ea7f706aed | |||
52e3f1e269 | |||
4c9d2a989e | |||
022db5cbe3 | |||
3bbf558883 | |||
1d68d9f71a | |||
f2e8824242 | |||
a0e47b5a64 | |||
f7465f55e7 | |||
453bf6d73b | |||
3353a00641 | |||
e388cb1643 | |||
741182c55f | |||
2efce35331 | |||
d1dfbd95e2 | |||
4fc712119f | |||
1aee5b1ed8 | |||
fefd3e6b29 | |||
9b43be9d9c | |||
ea677154cb | |||
7f2802e75f | |||
f924208881 | |||
6bea2961d9 | |||
ac3a6033b9 | |||
d7e6b01216 | |||
26aee7ff73 | |||
319c8fe32c | |||
ce121ccea9 | |||
7f1a4185b5 | |||
7d1464f0a1 | |||
8cc7fb9dd9 | |||
194cb1fb84 | |||
8ea106c091 | |||
a6cb3313b0 | |||
c6374b79b0 | |||
f25beab6cb | |||
901449b0b1 | |||
a9f2766a8b | |||
4e777572c9 | |||
90a8595a40 | |||
bf71eb448a | |||
2c29d272ad | |||
98aa2b9ff9 | |||
ea33a04d00 | |||
9963fcf849 | |||
ab93135b84 | |||
4a94cb85a2 | |||
b7e6854189 | |||
2b8a54f8ff | |||
a5dab0f61e | |||
824f1f24ff | |||
f4f5c3128f | |||
fdd42fd15f | |||
05a5e5eac1 | |||
c8e1cfcbee | |||
869dda9a45 | |||
e2c647ef91 | |||
05fdd94754 | |||
4a599b58ff | |||
05792826bc | |||
fbf7ad4295 | |||
6c1c0c867e | |||
5c0eb92d81 | |||
1e88412a8f | |||
f97ce6afef | |||
879476d8e0 | |||
6d584cf008 | |||
8efa299c65 | |||
b6e7ad187a | |||
5ef73ca9aa | |||
c50518a4ca | |||
4c98780bdb | |||
856fd2a33b | |||
581bbfe255 | |||
b4e1edaa64 | |||
025f6407e2 | |||
10c0d83fa5 | |||
9a6ec14cbf | |||
f77fec0c3c | |||
5d970cf5bd | |||
58e186440b | |||
6a39caa204 | |||
91f81d4c8e | |||
2b81b53dfa | |||
dfd8c4e4b8 | |||
c9c50e16ec | |||
eff856d8e5 | |||
90a369f0b6 | |||
ba05b4f024 | |||
3e90c3072a | |||
12946fbe46 | |||
70f923714c | |||
7cd394b0fb | |||
0bca098707 | |||
d47a7f48bd | |||
f181c60209 | |||
784c34f784 | |||
03fa5387ac | |||
1ea0b8a9df | |||
566e4a4196 | |||
61265604fb | |||
29909e7f44 | |||
3232a83965 | |||
c816bbdb6e | |||
4f25ab10e9 | |||
f04099c5de | |||
fdb82f5fb8 | |||
75d4c47384 | |||
bd4c2b5245 | |||
d60dba2de0 | |||
51a3043dfd | |||
7098bcec8c | |||
6d65512531 | |||
3ed336fa0e | |||
b26b1cd32f | |||
54db842d16 | |||
31a0085efb | |||
715355e148 | |||
55dfacea8d | |||
55c744cc00 | |||
7e903fde5b | |||
d702113fb5 | |||
4f44a067b0 | |||
44818e6d14 | |||
325131dd30 | |||
38eeda6e8b | |||
1eb59fb9b5 | |||
1c60aa9769 | |||
735e4cc3bc | |||
e9dd9df0a0 | |||
032b15efe0 | |||
256826d9c7 | |||
c273b29dec | |||
c19a038d47 | |||
95bc013e97 | |||
7ddd547190 | |||
38e34093cf | |||
dd1ebb5915 | |||
df1cdbe921 | |||
7846ea8acc | |||
1dc0d5f96a | |||
712ffb3e31 | |||
2a4111868c | |||
123701ed76 | |||
28dce8783f | |||
3781b62d35 | |||
859f062267 | |||
15425d01bc | |||
0642364a44 | |||
cfdbfa3d58 | |||
e9a6c0ba58 | |||
466b018319 | |||
d16b6fe61e | |||
7a75fcda44 | |||
8d289ab01d | |||
363a9689b4 | |||
40c7497efe | |||
6ccb1ff114 | |||
1d2593208a | |||
a7bdef69e2 | |||
d9ea647925 | |||
6673289c33 | |||
822af4f7f5 | |||
3155c90396 | |||
1dbfedce4c | |||
3ab5b5a79d | |||
6cbc14f2b2 | |||
75d0fc4749 | |||
ea161af4e5 | |||
0bf5f97fe9 | |||
b9f1bcf0e4 | |||
22a4117109 | |||
e0da99a973 | |||
b2630a0920 | |||
5ae20459dd | |||
587da478a6 | |||
419bb9eba6 | |||
82f1c2766c | |||
fc53f3721a | |||
345ac75aac | |||
32db27af78 | |||
4e956d5d1d | |||
61f8144280 | |||
ae03c70dfc | |||
e986a0a4f2 | |||
b85fe0e72a | |||
03f47d0a78 | |||
3f8f5cd200 | |||
aa6bd4438a | |||
22fb02c4e6 | |||
373880e582 | |||
8f525ab399 | |||
be1996752a | |||
2bcb629d78 | |||
aae5962f6a | |||
282b430b1f | |||
c47dfa1fb8 | |||
8db137882c | |||
79d1feff9c | |||
2f32bd877a | |||
22bc3bc3f9 | |||
6846f1e78a | |||
4d55935bd8 | |||
9c328690f8 | |||
b60dd1e9b4 | |||
86bcc49972 | |||
088745cf3b | |||
8cdfef7861 | |||
a0bb7059c1 | |||
853ecd2408 | |||
33421258b6 | |||
c221484fc3 | |||
d9deb571ed | |||
42d07c74d7 | |||
1366c49f1f | |||
ee6548aa50 | |||
a5c0958adf | |||
fd880d8465 | |||
a323fb7bb5 | |||
1948b00008 | |||
dbbbc4f9c9 | |||
51f2a78dcf | |||
5128bc02bb | |||
4f4aa62479 | |||
c267e7b3c2 | |||
3faeb5a556 | |||
0bc578b8fc | |||
661848c5e7 | |||
75fc7a2d1f | |||
4f8a0bad25 | |||
fb29653ed7 | |||
ffa8cf3ec3 | |||
8532e9c8e0 | |||
e04dfe96af | |||
193a1b3f4e | |||
62afa2f28d | |||
207f7ec309 | |||
e0a6bc1d4a | |||
5c994e4a24 | |||
d94578a420 | |||
0a0de018a5 | |||
a1d217e12b | |||
e102339637 | |||
7124d44b92 | |||
767dfd9947 | |||
87170ab067 | |||
74ac0f5862 | |||
f5144d49b1 | |||
95b6cb21f2 | |||
c858c0dc79 | |||
18e26d975b | |||
d41f933e7b | |||
65dabefa3b | |||
44e8603a6d | |||
16fd5456aa | |||
089f22d903 | |||
fc3a6c6984 | |||
1ab285f573 | |||
aa56c66a3c | |||
920462bdcc | |||
482bc462d3 | |||
de82424fb2 | |||
d487e43766 | |||
6494375a53 | |||
4466166f8b | |||
3aa34b59a5 | |||
c04b00d09d | |||
6e67c7532a | |||
5f8ebd81d7 | |||
79b5109953 | |||
60938c8c9d | |||
49a8afd126 | |||
dbad5dd611 | |||
a41404bd8a | |||
4b06fe73f2 | |||
1c6907c636 | |||
7184c02bb6 | |||
8a94aa10a4 | |||
9e75c1463a | |||
a94b88424e | |||
7ad1afee89 | |||
292827a311 | |||
f8ed23cc1e | |||
922ce2e312 | |||
7a385ddc8b | |||
2254f31bec | |||
77a74d84e2 | |||
5b868e6d5e | |||
889d048ca3 | |||
8b73549355 | |||
c6466a6da9 | |||
45b4fa0e96 | |||
bf29409a45 | |||
503c888838 | |||
1d14c8cb6b | |||
49d0d01f9f | |||
ed4978c31b | |||
3728ddbf24 | |||
8f2ca92f02 | |||
ce54d268f2 | |||
cd850b111d | |||
2486dabd8a | |||
4f3a60ac90 | |||
98c31cf07b | |||
9256afd439 |
16
.github/dependabot.yml
vendored
16
.github/dependabot.yml
vendored
@ -6,3 +6,19 @@ updates:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
#only allow patch updates for locale-data - this has to be updated manually due to codegen
|
||||
- dependency-name: pocketmine/locale-data
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
|
BIN
.github/readme/pocketmine-dark.png
vendored
Normal file
BIN
.github/readme/pocketmine-dark.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
.github/readme/pocketmine.png
vendored
Normal file
BIN
.github/readme/pocketmine.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
97
.github/workflows/build-docker-image.yml
vendored
Normal file
97
.github/workflows/build-docker-image.yml
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
name: Update Docker Hub images
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Update Docker Hub images
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Clone pmmp/PocketMine-Docker repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: pmmp/PocketMine-Docker
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get tag names
|
||||
id: tag-name
|
||||
run: |
|
||||
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
echo ::set-output name=TAG_NAME::$VERSION
|
||||
echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1)
|
||||
echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2)
|
||||
|
||||
- name: Download new release information
|
||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||
|
||||
- name: Detect channel
|
||||
id: channel
|
||||
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
|
||||
|
||||
- name: Get name of Docker repository name
|
||||
id: docker-repo-name
|
||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
|
||||
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
|
||||
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:latest
|
||||
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
100
.github/workflows/discord-release-embed.php
vendored
Normal file
100
.github/workflows/discord-release-embed.php
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\utils\Internet;
|
||||
use function dirname;
|
||||
use function fwrite;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const STDERR;
|
||||
|
||||
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) : array{
|
||||
return [
|
||||
"embeds" => [
|
||||
[
|
||||
"title" => "New PocketMine-MP release: $version ($channel)",
|
||||
"description" => <<<DESCRIPTION
|
||||
$description
|
||||
|
||||
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
|
||||
DESCRIPTION,
|
||||
"url" => $detailsUrl,
|
||||
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if(count($argv) !== 5){
|
||||
fwrite(STDERR, "Required arguments: github repo, version, API token\n");
|
||||
exit(1);
|
||||
}
|
||||
[, $repo, $tagName, $token, $hookURL] = $argv;
|
||||
|
||||
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
|
||||
'Authorization: token ' . $token
|
||||
]);
|
||||
if($result === null){
|
||||
fwrite(STDERR, "failed to access GitHub API\n");
|
||||
return;
|
||||
}
|
||||
if($result->getCode() !== 200){
|
||||
fwrite(STDERR, "Error accessing GitHub API: " . $result->getCode() . "\n");
|
||||
fwrite(STDERR, $result->getBody() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$releaseInfoJson = json_decode($result->getBody(), true, JSON_THROW_ON_ERROR);
|
||||
if(!is_array($releaseInfoJson)){
|
||||
fwrite(STDERR, "Invalid release JSON returned from GitHub API\n");
|
||||
exit(1);
|
||||
}
|
||||
$buildInfoPath = 'https://github.com/' . $repo . '/releases/download/' . $tagName . '/build_info.json';
|
||||
|
||||
$buildInfoResult = Internet::getURL($buildInfoPath, extraHeaders: [
|
||||
'Authorization: token ' . $token
|
||||
]);
|
||||
if($buildInfoResult === null){
|
||||
fwrite(STDERR, "missing build_info.json\n");
|
||||
exit(1);
|
||||
}
|
||||
if($buildInfoResult->getCode() !== 200){
|
||||
fwrite(STDERR, "error accessing build_info.json: " . $buildInfoResult->getCode() . "\n");
|
||||
fwrite(STDERR, $buildInfoResult->getBody() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$buildInfoJson = json_decode($buildInfoResult->getBody(), true, JSON_THROW_ON_ERROR);
|
||||
if(!is_array($buildInfoJson)){
|
||||
fwrite(STDERR, "invalid build_info.json\n");
|
||||
exit(1);
|
||||
}
|
||||
$detailsUrl = $buildInfoJson["details_url"];
|
||||
$sourceUrl = $buildInfoJson["source_url"];
|
||||
$pharDownloadUrl = $buildInfoJson["download_url"];
|
||||
$buildLogUrl = $buildInfoJson["build_log_url"];
|
||||
|
||||
$description = $releaseInfoJson["body"];
|
||||
|
||||
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl);
|
||||
|
||||
$response = Internet::postURL(
|
||||
$hookURL,
|
||||
json_encode($discordPayload, JSON_THROW_ON_ERROR),
|
||||
extraHeaders: ['Content-Type: application/json']
|
||||
);
|
||||
if($response?->getCode() !== 204){
|
||||
fwrite(STDERR, "failed to send Discord webhook\n");
|
||||
fwrite(STDERR, $response?->getBody() ?? "no response body\n");
|
||||
exit(1);
|
||||
}
|
38
.github/workflows/discord-release-notify.yml
vendored
Normal file
38
.github/workflows/discord-release-notify.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Notify Discord webhook of release
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
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: Get actual tag name
|
||||
id: tag-name
|
||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
|
||||
- name: Run webhook post script
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
|
15
.github/workflows/draft-release.yml
vendored
15
.github/workflows/draft-release.yml
vendored
@ -13,17 +13,17 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.12.0
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -55,12 +55,13 @@ jobs:
|
||||
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
|
||||
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);')
|
||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
|
||||
echo ::set-output name=CHANGELOG_SUFFIX::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;')
|
||||
|
||||
- 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 }} > 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 }} > build_info.json
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: release_artifacts
|
||||
path: |
|
||||
@ -69,7 +70,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.8.6
|
||||
uses: ncipollo/release-action@v1.12.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
@ -80,4 +81,4 @@ jobs:
|
||||
body: |
|
||||
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
|
||||
|
||||
Please see the [changelogs](/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.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.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
|
50
.github/workflows/main.yml
vendored
50
.github/workflows/main.yml
vendored
@ -9,18 +9,20 @@ jobs:
|
||||
build-php:
|
||||
name: Prepare PHP
|
||||
runs-on: ${{ matrix.image }}
|
||||
concurrency: php-build-${{ matrix.php }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.14]
|
||||
php: [8.0.27, 8.1.14, 8.2.1]
|
||||
|
||||
steps:
|
||||
- name: Build and prepare PHP cache
|
||||
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
|
||||
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
@ -31,22 +33,23 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.14]
|
||||
php: [8.0.27, 8.1.14, 8.2.1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
|
||||
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -69,22 +72,23 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.14]
|
||||
php: [8.0.27, 8.1.14, 8.2.1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
|
||||
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -107,24 +111,25 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.14]
|
||||
php: [8.0.27, 8.1.14, 8.2.1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
|
||||
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -147,22 +152,23 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.14]
|
||||
php: [8.0.27, 8.1.14, 8.2.1]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
|
||||
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "4"
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -192,13 +198,15 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.15.0
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer:3.2
|
||||
tools: php-cs-fixer:3.11
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
11
.github/workflows/support.yml
vendored
11
.github/workflows/support.yml
vendored
@ -8,12 +8,19 @@ jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v2
|
||||
- uses: dessant/support-requests@v3
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
support-label: "Support request"
|
||||
issue-comment: >
|
||||
Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
|
||||
Hi, we only accept **bug reports** on this issue tracker, but this issue looks like a support request.
|
||||
|
||||
|
||||
Instead of creating an issue, try the following:
|
||||
|
||||
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
|
||||
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||
|
4
.github/workflows/update-php-versions.php
vendored
4
.github/workflows/update-php-versions.php
vendored
@ -22,7 +22,9 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"8.0"
|
||||
"8.0",
|
||||
"8.1",
|
||||
"8.2"
|
||||
];
|
||||
|
||||
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
|
||||
|
2
.github/workflows/update-updater-api.yml
vendored
2
.github/workflows/update-updater-api.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- name: Install jq
|
||||
run: sudo apt update && sudo apt install jq -y
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: pmmp/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
5
.idea/codeStyles/Project.xml
generated
5
.idea/codeStyles/Project.xml
generated
@ -62,6 +62,11 @@
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Shell Script">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="neon">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
|
2
.idea/fileTemplates/includes/PHP File Header.php
generated
2
.idea/fileTemplates/includes/PHP File Header.php
generated
@ -16,6 +16,6 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
@ -42,11 +42,41 @@ return (new PhpCsFixer\Config)
|
||||
'import_functions' => true,
|
||||
'import_classes' => null,
|
||||
],
|
||||
'header_comment' => [
|
||||
'comment_type' => 'comment',
|
||||
'header' => <<<BODY
|
||||
|
||||
____ _ _ __ __ _ __ __ ____
|
||||
| _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
| |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
| __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
|_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
|
||||
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/
|
||||
|
||||
|
||||
BODY,
|
||||
'location' => 'after_open'
|
||||
],
|
||||
'indentation_type' => true,
|
||||
'logical_operators' => true,
|
||||
'native_constant_invocation' => [
|
||||
'scope' => 'namespaced'
|
||||
],
|
||||
'native_function_invocation' => [
|
||||
'scope' => 'namespaced',
|
||||
'include' => ['@all'],
|
||||
],
|
||||
'new_with_braces' => [
|
||||
'named_class' => true,
|
||||
'anonymous_class' => false,
|
||||
],
|
||||
'no_closing_tag' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
@ -65,6 +95,12 @@ return (new PhpCsFixer\Config)
|
||||
],
|
||||
'sort_algorithm' => 'alpha'
|
||||
],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'vertical',
|
||||
'tags' => [
|
||||
'param',
|
||||
]
|
||||
],
|
||||
'phpdoc_line_span' => [
|
||||
'property' => 'single',
|
||||
'method' => null,
|
||||
|
@ -18,6 +18,32 @@ Larger contributions like feature additions should be preceded by a [Change Prop
|
||||
## Other things you'll need
|
||||
- [git](https://git-scm.com/)
|
||||
|
||||
## Choosing a target branch
|
||||
PocketMine-MP has three primary branches of development.
|
||||
|
||||
| Type of change | `stable` | `next-minor` | `next-major` |
|
||||
|:---------------|:--------:|:------------:|:------------:|
|
||||
| Bug fixes | ✔️ | ✔️ | ✔️ |
|
||||
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
|
||||
| Cleaning up code | ❌ | ✔️ | ✔️ |
|
||||
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
|
||||
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
|
||||
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
|
||||
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
|
||||
| Removal of API | ❌ | ❌ | ✔️ |
|
||||
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
|
||||
|
||||
### Notes
|
||||
- **Non-disruptive** means that usage should not be significantly altered by the change.
|
||||
- Examples of **non-disruptive** changes include adding new commands, or gameplay features like blocks and items.
|
||||
- Examples of **disruptive** changes include changing the way the server is run, world format changes (since those require downtime for the user to convert their world).
|
||||
- **API** includes all public and protected classes, functions and constants (unless marked as `@internal`).
|
||||
- Private members are not part of the API, **unless in a trait**.
|
||||
|
||||
## Making a pull request
|
||||
The basic procedure to create a pull request is:
|
||||
1. [Fork the repository on GitHub](https://github.com/pmmp/PocketMine-MP/fork). This gives you your own copy of the repository to make changes to.
|
||||
|
13
README.md
13
README.md
@ -1,5 +1,13 @@
|
||||
<p align="center">
|
||||
<a href="https://pmmp.io"><img src="http://cdn.pocketmine.net/img/PocketMine-MP-h.png"></img></a><br>
|
||||
<a href="https://pmmp.io">
|
||||
<!--[if IE]>
|
||||
<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" />
|
||||
</picture>
|
||||
</a><br>
|
||||
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
|
||||
</p>
|
||||
|
||||
@ -27,7 +35,8 @@
|
||||
## For developers
|
||||
* [Building and running from source](BUILDING.md)
|
||||
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
|
||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
||||
* [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 `next-major` 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 Guidelines](CONTRIBUTING.md)
|
||||
|
@ -7,10 +7,11 @@ GitHub is public and anyone can see the issues you post on the issue tracker, in
|
||||
|
||||
**WARNING: You may put live servers at risk by reporting a vulnerability on the GitHub issue tracker.**
|
||||
|
||||
**Contact us** by sending an email to [**team@pmmp.io**](mailto:team@pmmp.io?subject=Security%20Vulnerability%20in%20PocketMine-MP). Include the following information:
|
||||
**Contact us** by sending an email to [**security@pmmp.io**](mailto:security@pmmp.io). Include the following information:
|
||||
|
||||
- Version of PocketMine-MP
|
||||
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
|
||||
- Your GitHub username, if you wish to be credited for reporting the problem in the security advisory
|
||||
|
||||
Please note that we can't guarantee a reply to every email.
|
||||
|
||||
|
@ -17,14 +17,14 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 5){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number>");
|
||||
if(count($argv) !== 6){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -40,4 +40,5 @@ echo json_encode([
|
||||
"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]",
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
|
||||
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -25,7 +25,7 @@ namespace pocketmine\build\generate_known_translation_apis;
|
||||
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\utils\Utils;
|
||||
use Webmozart\PathUtil\Path;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function dirname;
|
||||
@ -75,7 +75,7 @@ const SHARED_HEADER = <<<'HEADER'
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -29,17 +29,21 @@ use function count;
|
||||
use function dirname;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function is_dir;
|
||||
use function ksort;
|
||||
use function mb_strtoupper;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function str_ends_with;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
use const SORT_STRING;
|
||||
use const STDERR;
|
||||
|
||||
if(count($argv) !== 2){
|
||||
die("Provide a path to process");
|
||||
fwrite(STDERR, "Provide a path to process\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +62,7 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
|
||||
$memberLines = [];
|
||||
foreach($members as $name => $member){
|
||||
$reflect = new \ReflectionClass($member);
|
||||
while($reflect !== false and $reflect->isAnonymous()){
|
||||
while($reflect !== false && $reflect->isAnonymous()){
|
||||
$reflect = $reflect->getParentClass();
|
||||
}
|
||||
if($reflect === false){
|
||||
@ -80,29 +84,24 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
|
||||
if(substr($file, -4) !== ".php"){
|
||||
continue;
|
||||
}
|
||||
function processFile(string $file) : void{
|
||||
$contents = file_get_contents($file);
|
||||
if($contents === false){
|
||||
throw new \RuntimeException("Failed to get contents of $file");
|
||||
}
|
||||
|
||||
if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
$shortClassName = basename($file, ".php");
|
||||
$className = $matches[1] . "\\" . $shortClassName;
|
||||
if(!class_exists($className)){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
$reflect = new \ReflectionClass($className);
|
||||
$docComment = $reflect->getDocComment();
|
||||
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
echo "Found registry in $file\n";
|
||||
|
||||
@ -116,3 +115,18 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
|
||||
echo "No changes made to file $file\n";
|
||||
}
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(is_dir($argv[1])){
|
||||
/** @var string $file */
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
|
||||
if(!str_ends_with($file, ".php")){
|
||||
continue;
|
||||
}
|
||||
|
||||
processFile($file);
|
||||
}
|
||||
}else{
|
||||
processFile($argv[1]);
|
||||
}
|
||||
|
@ -17,12 +17,13 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\make_release;
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\VersionInfo;
|
||||
@ -30,7 +31,6 @@ use function array_keys;
|
||||
use function array_map;
|
||||
use function dirname;
|
||||
use function fgets;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function getopt;
|
||||
@ -50,7 +50,7 @@ use const STR_PAD_LEFT;
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
|
||||
$versionInfo = file_get_contents($versionInfoPath);
|
||||
$versionInfo = Filesystem::fileGetContents($versionInfoPath);
|
||||
$versionInfo = preg_replace(
|
||||
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
|
||||
'$1const BASE_VERSION = "' . $newVersion . '";',
|
||||
|
Submodule build/php updated: bd329dba08...fb297eb511
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -40,12 +40,13 @@ use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function unlink;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @param string[] $strings
|
||||
* @param string[] $strings
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -413,6 +413,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
|
||||
|
||||
### Command
|
||||
- The following classes have been removed:
|
||||
- `PluginIdentifiableCommand` - use `PluginOwned` and `PluginOwnedTrait`
|
||||
- `RemoteConsoleCommandSender`
|
||||
- The following API methods have signature changes:
|
||||
- `Command->setPermission()` argument is now mandatory (but still nullable).
|
||||
@ -1054,6 +1055,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
|
||||
- `Player->addWindow()`: use `Player->setCurrentWindow()` instead
|
||||
- `Player->dataPacket()`: replaced by `NetworkSession->sendDataPacket()`
|
||||
- `Player->getAddress()`: replaced by `NetworkSession->getIp()`
|
||||
- `Player->getClientId()`: the client ID can be found in `PlayerInfo->getExtraData()`
|
||||
- `Player->getPing()`: moved to `NetworkSession`
|
||||
- `Player->getPort()`: moved to `NetworkSession`
|
||||
- `Player->getWindow()`: use `Player->getCurrentWindow()` instead
|
||||
@ -1069,6 +1071,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`
|
||||
- API version checks are now more strict. It is no longer legal to declare multiple minimum versions on the same major version. Doing so will now cause the plugin to fail to load with the message `Multiple minimum API versions found for some major versions`.
|
||||
- `plugin.yml` YAML commands loading is now internalized inside `PluginBase`.
|
||||
- `PluginManager->registerEvent()` now has a simpler signature: `registerEvent(string $event, \Closure $handler, int $priority, Plugin $plugin, bool $handleCancelled = false)`. The provided closure must accept the specified event class as its only parameter. See [Event API changes](#event) for more details.
|
||||
- The following classes have been added:
|
||||
- `PluginOwned`
|
||||
- The following classes have been removed:
|
||||
- `PluginLogger`
|
||||
- The following constants have been removed:
|
||||
@ -1627,3 +1631,21 @@ Released 25th January 2022.
|
||||
## Fixes
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
|
||||
# 4.0.9
|
||||
Released 5th February 2022.
|
||||
|
||||
## Fixes
|
||||
### Core
|
||||
- The spawn chunk of the default world is no longer loaded during shutdown. Previously, it would attempt to find a safe spawn to teleport players to, only to unload the target world of that safe spawn and not use it.
|
||||
- The spawn chunk of the default world is no longer loaded when unloading a non-default world containing zero players.
|
||||
- Fixed chunk version `8` in Bedrock worlds being treated as corrupted. These appeared in worlds between 1.2.13 and 1.8.0.
|
||||
|
||||
### API
|
||||
- Added missing bounds check to `Liquid->setDecay()`.
|
||||
- Fixed `StringToItemParser` returning concrete instead of concrete powder when given `<color>_concrete_powder`.
|
||||
|
||||
### Gameplay
|
||||
- Cobwebs now drop themselves when broken using shears.
|
||||
- Fixed spectator players being able to drop items.
|
||||
- Fixed collision shapes of Bell in different orientations.
|
||||
|
166
changelogs/4.1-beta.md
Normal file
166
changelogs/4.1-beta.md
Normal file
@ -0,0 +1,166 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.1.0-BETA1
|
||||
Released 22nd January 2022.
|
||||
|
||||
## General
|
||||
- Game mode names (e.g. `survival`, `creative`) may now be used for the `gamemode` property in `server.properties`.
|
||||
- Increased default maximum render distance to 16 chunks. Players with a render distance smaller than this will notice no difference.
|
||||
- The setup wizard now prompts for a maximum render distance value.
|
||||
- The setup wizard now prompts for an IPv6 port selection. Previously it would always use 19133.
|
||||
- `chunk-ticking.disable-block-ticking` now accepts block names like those used in the `/give` command.
|
||||
- The `/clear` command now behaves more like vanilla:
|
||||
- The order of inventories is now the same as Bedrock.
|
||||
- The cursor and offhand inventories are now cleared if necessary.
|
||||
|
||||
## Technical
|
||||
- `PlayerAuthInputPacket` is now used instead of `MovePlayerPacket` for processing movements. This improves position and rotation accuracy.
|
||||
- `&&` and `||` are now always used instead of `and` and `or`.
|
||||
- New version of `pocketmine/errorhandler` is used by this version, adding support for `ErrorToExceptionHandler::trap()`. This enables reliably capturing `E_WARNING` and `E_NOTICE` from functions such as `yaml_parse()` and friends.
|
||||
- New dependency versions are required by this version:
|
||||
- `pocketmine/bedrock-protocol` has been updated from 7.1.0 to [7.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.3.0%2Bbedrock-1.18.0).
|
||||
- `pocketmine/errorhandler` has been updated from 0.3.0 to [0.6.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.6.0).
|
||||
|
||||
## API
|
||||
### Block
|
||||
- The following classes have been added:
|
||||
- `Lectern`
|
||||
- `Pumpkin`
|
||||
- The following public API methods have been added:
|
||||
- `Block->getTypeId() : int` - returns an integer which uniquely identifies the block type, ignoring things like facing, colour etc.
|
||||
- `VanillaBlocks::LECTERN()`
|
||||
|
||||
### Entity
|
||||
- The following classes have been added:
|
||||
- `animation\ItemEntityStackSizeChangeAnimation`
|
||||
- The following public API methods have been added:
|
||||
- `object\ItemEntity->isMergeable(object\ItemEntity $other) : bool`
|
||||
- `object\ItemEntity->setStackSize(int $size) : void`
|
||||
- `object\ItemEntity->tryMergeInto(object\ItemEntity $other) : bool`
|
||||
- `ExperienceManager->canAttractXpOrbs() : bool`
|
||||
- `ExperienceManager->setCanAttractXpOrbs(bool $v = true) : void`
|
||||
- `Entity->getSize() : EntitySizeInfo`
|
||||
- `Living->isGliding() : bool`
|
||||
- `Living->isSwimming() : bool`
|
||||
- `Living->setGliding(bool $value = true) : void`
|
||||
- `Living->setSwimming(bool $value = true) : void`
|
||||
- The following protected API methods have been added:
|
||||
- `Entity->getBlocksIntersected(float $inset) : \Generator<int, Block, void, void>`
|
||||
|
||||
### Event
|
||||
- `BlockSpreadEvent` is now called when fire spreads to the positions of blocks it burns away.
|
||||
- `BlockFormEvent` is now called when concrete powder turns into concrete due to contact with water.
|
||||
- The following classes have been added:
|
||||
- `BlockMeltEvent` - called when ice or snow melts
|
||||
- `ChestPairEvent` - called when two chests try to form a pair
|
||||
- `PlayerToggleGlideEvent` - called when a player starts or stops gliding
|
||||
- `PlayerToggleSwimEvent` - called when a player starts or stops swimming
|
||||
|
||||
### Item
|
||||
- The following public API methods have been added:
|
||||
- `SplashPotion->getType() : PotionType`
|
||||
- `VanillaItems::AIR()`
|
||||
- The following API methods have been deprecated:
|
||||
- `ItemFactory::air()` - use `VanillaItems::AIR()` instead
|
||||
|
||||
### Player
|
||||
- The following public API methods have been added:
|
||||
- `Player->hasBlockCollision() : bool`
|
||||
- `Player->setHasBlockCollision(bool $value)` - allows controlling spectator-like no-clip behaviour without changing game mode
|
||||
- `Player->toggleSwim(bool $swim) : bool` - called by the network system when the client tries to start/stop swimming
|
||||
- `Player->toggleGlide(bool $glide) : bool` - called by the network system when the client tries to start/stop gliding
|
||||
|
||||
### Server
|
||||
- The following public API constants have been added:
|
||||
- `Server::DEFAULT_SERVER_NAME`
|
||||
- `Server::DEFAULT_MAX_PLAYERS`
|
||||
- `Server::DEFAULT_PORT_IPV4`
|
||||
- `Server::DEFAULT_PORT_IPV6`
|
||||
- `Server::DEFAULT_MAX_VIEW_DISTANCE`
|
||||
|
||||
### Utils
|
||||
- Config parsing errors are now always represented by `ConfigLoadException` and include the path to the file in the message.
|
||||
- Added `TextFormat::MINECOIN_GOLD`, and support for it to the various `TextFormat` methods.
|
||||
- The following public API methods have been added:
|
||||
- `Utils::assumeNotFalse()` - static analysis crutch to silence PHPStan errors without using `ignoreErrors` or `@phpstan-ignore-line`, which are both too coarse.
|
||||
- The following public API properties have been added:
|
||||
- `Terminal::$COLOR_MINECOIN_GOLD`
|
||||
- The following classes have been added:
|
||||
- `ConfigLoadException`
|
||||
- Fixed `Random->nextSignedInt()` to actually return a signed int. Previously it would return any integer value between 0 and 4,294,957,295.
|
||||
- Fixed `Random->nextSignedFloat()` to return a float between `-1.0` and `1.0`. Previously it would return any value between `0.0` and `2.0`.
|
||||
- `VersionString->getNumber()` output is now structured differently to fix overflow issues caused by the old format.
|
||||
|
||||
### World
|
||||
- The following classes have been added:
|
||||
- `sound\ItemUseOnBlockSound`
|
||||
- `sound\LecternPlaceBookSound`
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Fire now spreads.
|
||||
- Implemented lectern blocks.
|
||||
- Added missing sounds for hoeing grass and dirt.
|
||||
- Added missing sounds for using a shovel on grass to create grass path.
|
||||
- Pumpkins can now be carved using shears.
|
||||
|
||||
### Items
|
||||
- Dropped items of the same type now merge with each other.
|
||||
|
||||
### Misc
|
||||
- Implemented player swimming.
|
||||
|
||||
# 4.1.0-BETA2
|
||||
Released 27th January 2022.
|
||||
|
||||
## API
|
||||
### Block
|
||||
- The following API methods have been added:
|
||||
- `utils\BrewingStandSlot->getSlotNumber() : int`
|
||||
- `utils\FurnaceType->getCookSound() : Sound`
|
||||
- The following API constants have been added:
|
||||
- `tile\BrewingStand::BREW_TIME_TICKS`
|
||||
|
||||
### Crafting
|
||||
- The following API methods have been added:
|
||||
- `CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>`
|
||||
- `CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>`
|
||||
- `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void`
|
||||
- `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void`
|
||||
- The following classes have been added:
|
||||
- `BrewingRecipe`
|
||||
- `PotionContainerChangeRecipe`
|
||||
- `PotionTypeRecipe`
|
||||
|
||||
### Event
|
||||
- The following classes have been added:
|
||||
- `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed)
|
||||
- `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder
|
||||
- `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting
|
||||
|
||||
### World
|
||||
#### Sound
|
||||
- The following classes have been added:
|
||||
- `BlastFurnaceSound` - the sound made by a blast furnace during smelting
|
||||
- `FurnaceSound` - the sound made by a regular furnace during cooking or smelting
|
||||
- `PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed
|
||||
- `SmokerSound` - the sound made by a smoker during cooking
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Brewing stands can now be used for brewing potions.
|
||||
- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions).
|
||||
- Added missing sounds for furnace, blast furnace and smoker.
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- Cobwebs now drop themselves when mined using shears.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
- Fixed block updating bug introduced by beta1 which caused crops and other plants to never grow.
|
||||
|
||||
### Misc
|
||||
- Added a workaround for client hitbox size bug after swimming which caused the player to be able to fit into one-block-tall gaps.
|
142
changelogs/4.1.md
Normal file
142
changelogs/4.1.md
Normal file
@ -0,0 +1,142 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.1.0
|
||||
Released 7th February 2022.
|
||||
|
||||
## General
|
||||
- Game mode names (e.g. `survival`, `creative`) may now be used for the `gamemode` property in `server.properties`.
|
||||
- Increased default maximum render distance to 16 chunks. Players with a render distance smaller than this will notice no difference.
|
||||
- The setup wizard now prompts for a maximum render distance value.
|
||||
- The setup wizard now prompts for an IPv6 port selection. Previously it would always use 19133.
|
||||
- `chunk-ticking.disable-block-ticking` now accepts block names like those used in the `/give` command.
|
||||
- The `/clear` command now behaves more like vanilla:
|
||||
- The order of inventories is now the same as Bedrock.
|
||||
- The cursor and offhand inventories are now cleared if necessary.
|
||||
|
||||
## Technical
|
||||
- `PlayerAuthInputPacket` is now used instead of `MovePlayerPacket` for processing movements. This improves position and rotation accuracy.
|
||||
- `&&` and `||` are now always used instead of `and` and `or`.
|
||||
- New version of `pocketmine/errorhandler` is used by this version, adding support for `ErrorToExceptionHandler::trap()`. This enables reliably capturing `E_WARNING` and `E_NOTICE` from functions such as `yaml_parse()` and friends.
|
||||
- New dependency versions are required by this version:
|
||||
- `pocketmine/bedrock-protocol` has been updated from 7.1.0 to [7.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.3.0%2Bbedrock-1.18.0).
|
||||
- `pocketmine/errorhandler` has been updated from 0.3.0 to [0.6.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.6.0).
|
||||
|
||||
## API
|
||||
### Block
|
||||
- The following classes have been added:
|
||||
- `Lectern`
|
||||
- `Pumpkin`
|
||||
- The following public API methods have been added:
|
||||
- `Block->getTypeId() : int` - returns an integer which uniquely identifies the block type, ignoring things like facing, colour etc.
|
||||
- `VanillaBlocks::LECTERN()`
|
||||
- `utils\BrewingStandSlot->getSlotNumber() : int`
|
||||
- `utils\FurnaceType->getCookSound() : Sound`
|
||||
- The following API constants have been added:
|
||||
- `tile\BrewingStand::BREW_TIME_TICKS`
|
||||
|
||||
### Crafting
|
||||
- The following API methods have been added:
|
||||
- `CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>`
|
||||
- `CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>`
|
||||
- `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void`
|
||||
- `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void`
|
||||
- The following classes have been added:
|
||||
- `BrewingRecipe`
|
||||
- `PotionContainerChangeRecipe`
|
||||
- `PotionTypeRecipe`
|
||||
|
||||
### Entity
|
||||
- The following classes have been added:
|
||||
- `animation\ItemEntityStackSizeChangeAnimation`
|
||||
- The following public API methods have been added:
|
||||
- `object\ItemEntity->isMergeable(object\ItemEntity $other) : bool`
|
||||
- `object\ItemEntity->setStackSize(int $size) : void`
|
||||
- `object\ItemEntity->tryMergeInto(object\ItemEntity $other) : bool`
|
||||
- `ExperienceManager->canAttractXpOrbs() : bool`
|
||||
- `ExperienceManager->setCanAttractXpOrbs(bool $v = true) : void`
|
||||
- `Entity->getSize() : EntitySizeInfo`
|
||||
- `Living->isGliding() : bool`
|
||||
- `Living->isSwimming() : bool`
|
||||
- `Living->setGliding(bool $value = true) : void`
|
||||
- `Living->setSwimming(bool $value = true) : void`
|
||||
- The following protected API methods have been added:
|
||||
- `Entity->getBlocksIntersected(float $inset) : \Generator<int, Block, void, void>`
|
||||
|
||||
### Event
|
||||
- `BlockSpreadEvent` is now called when fire spreads to the positions of blocks it burns away.
|
||||
- `BlockFormEvent` is now called when concrete powder turns into concrete due to contact with water.
|
||||
- The following classes have been added:
|
||||
- `BlockMeltEvent` - called when ice or snow melts
|
||||
- `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed)
|
||||
- `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder
|
||||
- `ChestPairEvent` - called when two chests try to form a pair
|
||||
- `PlayerToggleGlideEvent` - called when a player starts or stops gliding
|
||||
- `PlayerToggleSwimEvent` - called when a player starts or stops swimming
|
||||
- `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting
|
||||
|
||||
### Item
|
||||
- The following public API methods have been added:
|
||||
- `SplashPotion->getType() : PotionType`
|
||||
- `VanillaItems::AIR()`
|
||||
- The following API methods have been deprecated:
|
||||
- `ItemFactory::air()` - use `VanillaItems::AIR()` instead
|
||||
|
||||
### Player
|
||||
- The following public API methods have been added:
|
||||
- `Player->hasBlockCollision() : bool`
|
||||
- `Player->setHasBlockCollision(bool $value)` - allows controlling spectator-like no-clip behaviour without changing game mode
|
||||
- `Player->toggleSwim(bool $swim) : bool` - called by the network system when the client tries to start/stop swimming
|
||||
- `Player->toggleGlide(bool $glide) : bool` - called by the network system when the client tries to start/stop gliding
|
||||
|
||||
### Server
|
||||
- The following public API constants have been added:
|
||||
- `Server::DEFAULT_SERVER_NAME`
|
||||
- `Server::DEFAULT_MAX_PLAYERS`
|
||||
- `Server::DEFAULT_PORT_IPV4`
|
||||
- `Server::DEFAULT_PORT_IPV6`
|
||||
- `Server::DEFAULT_MAX_VIEW_DISTANCE`
|
||||
|
||||
### Utils
|
||||
- Config parsing errors are now always represented by `ConfigLoadException` and include the path to the file in the message.
|
||||
- Added `TextFormat::MINECOIN_GOLD`, and support for it to the various `TextFormat` methods.
|
||||
- The following public API methods have been added:
|
||||
- `Utils::assumeNotFalse()` - static analysis crutch to silence PHPStan errors without using `ignoreErrors` or `@phpstan-ignore-line`, which are both too coarse.
|
||||
- The following public API properties have been added:
|
||||
- `Terminal::$COLOR_MINECOIN_GOLD`
|
||||
- The following classes have been added:
|
||||
- `ConfigLoadException`
|
||||
- Fixed `Random->nextSignedInt()` to actually return a signed int. Previously it would return any integer value between 0 and 4,294,957,295.
|
||||
- Fixed `Random->nextSignedFloat()` to return a float between `-1.0` and `1.0`. Previously it would return any value between `0.0` and `2.0`.
|
||||
- `VersionString->getNumber()` output is now structured differently to fix overflow issues caused by the old format.
|
||||
|
||||
### World
|
||||
- The following classes have been added:
|
||||
- `sound\BlastFurnaceSound` - the sound made by a blast furnace during smelting
|
||||
- `sound\FurnaceSound` - the sound made by a regular furnace during cooking or smelting
|
||||
- `sound\ItemUseOnBlockSound`
|
||||
- `sound\LecternPlaceBookSound`
|
||||
- `sound\PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed
|
||||
- `sound\SmokerSound` - the sound made by a smoker during cooking
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Fire now spreads.
|
||||
- Implemented lectern blocks.
|
||||
- Added missing sounds for hoeing grass and dirt.
|
||||
- Added missing sounds for using a shovel on grass to create grass path.
|
||||
- Pumpkins can now be carved using shears.
|
||||
- Brewing stands can now be used for brewing potions.
|
||||
- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions).
|
||||
- Added missing sounds for furnace, blast furnace and smoker.
|
||||
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
|
||||
- Cobwebs now drop themselves when mined using shears.
|
||||
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
|
||||
|
||||
### Items
|
||||
- Dropped items of the same type now merge with each other.
|
53
changelogs/4.10.md
Normal file
53
changelogs/4.10.md
Normal file
@ -0,0 +1,53 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.40**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.10.0
|
||||
Released 26th October 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.40.
|
||||
- Removed support for older versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed incorrect command descriptions showing in `/help` when multiple commands use the same name. Previously, the most recently registered command would show, even though it wouldn't actually be invoked.
|
||||
- Fixed splash potions affecting players in spectator mode.
|
||||
- Fixed `World->addParticle()` sending particles to players who couldn't possibly see them when a list of targets was used.
|
||||
- Fixed `World->addSound()` sending sounds to players who couldn't possibly hear them when a list of targets was used.
|
||||
|
||||
## Documentation
|
||||
- Improved type information available for various API methods in `World`.
|
||||
|
||||
# 4.10.1
|
||||
Released 7th November 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed spawning in the void if spawn terrain in a world is solid at the default spawn position.
|
||||
- Fixed totems of undying activating when the player has 1 HP remaining.
|
||||
- Fixed durable items such as tools becoming unbreakable when in stacks larger than 1. Now, the durability correctly resets when the tool breaks.
|
||||
- TPS below 12 now correctly shows as red in `/status`. Previously, it showed as orange due to a condition ordering bug.
|
||||
- Improved handling of missing arguments in user-defined `pocketmine.yml` command aliases. Previously, missing arguments would be filled with an empty string, which caused a variety of unexpected behaviour.
|
||||
|
||||
## Internals
|
||||
- Added validation for the array given to `BaseInventory->setContents()` to ensure that it contains only `Item` instances.
|
||||
- Silenced `PlayerAuthInputPacket` spam when the session is in the "spawn response" state.
|
||||
- Updated to PHPStan 1.9.
|
||||
|
||||
# 4.10.2
|
||||
Released 25th November 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed crashes on macOS and Linux when using console colours without the `TERM` environment variable set.
|
||||
- Fixed crashdumps not being generated when error messages contained invalid UTF-8 characters.
|
||||
|
||||
## Documentation
|
||||
- Clarified documentation of caching behaviour for `Internet::getIP()`.
|
||||
- Added and improved documentation for many `Inventory` methods.
|
||||
- Rewritten documentation for `PlayerCreationEvent` with warnings and more detail.
|
||||
|
||||
## Internals
|
||||
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.
|
92
changelogs/4.11-beta.md
Normal file
92
changelogs/4.11-beta.md
Normal file
@ -0,0 +1,92 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.40**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.11.0-BETA1
|
||||
Released 7th November 2022.
|
||||
|
||||
## General
|
||||
- Packet receive timings have now been split into two subcategories - Decode and Handle.
|
||||
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
|
||||
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
|
||||
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
|
||||
- Console command output now appears on the terminal only, and is not written to the log file.
|
||||
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
|
||||
- Introduced validation for the `--data` and `--plugins` command line options.
|
||||
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
|
||||
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
|
||||
|
||||
## Gameplay
|
||||
- Fixed supporting blocks of dead bush to be in line with vanilla.
|
||||
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
|
||||
- Fixed modifier values for Instant Damage and Regeneration effects.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
|
||||
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
|
||||
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
|
||||
|
||||
### `pocketmine`
|
||||
- The following API methods are now deprecated:
|
||||
- `Server->getPlayerByPrefix()`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
|
||||
- The following API methods are now deprecated:
|
||||
- `Living->hasLineOfSight()`
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->clearCustomColor() : $this`
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new API methods have been added:
|
||||
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
|
||||
|
||||
## Internals
|
||||
- Improved performance of `ContainerTrait` dropping items on block destroy. (24e72ec109c1442b09558df89b6833cf2f2e0ec7)
|
||||
- Avoid repeated calls to `Position->getWorld()` (use local variables). (2940547026db40ce76deb46e992870de3ead79ad)
|
||||
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. (e90abecf38d9c57635fa0497514bba7e546a2469)
|
||||
- Console polling is now done on the main thread (no longer a performance concern).
|
||||
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie.
|
||||
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged.
|
||||
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused.
|
||||
|
||||
# 4.11.0-BETA2
|
||||
Released 13th November 2022.
|
||||
|
||||
## Configuration
|
||||
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
|
||||
- The functionality of this setting has been removed, since it caused more problems than it solved.
|
||||
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
|
||||
|
||||
## Gameplay
|
||||
- Improved chunk random ticking:
|
||||
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
|
||||
- This change significantly improves crop and plant growth with large numbers of players, but may cause higher CPU usage.
|
||||
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
|
||||
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
|
||||
- Implemented Darkness effect.
|
||||
|
||||
## API
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
|
||||
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
|
||||
|
||||
## Internals
|
||||
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.
|
106
changelogs/4.11.md
Normal file
106
changelogs/4.11.md
Normal file
@ -0,0 +1,106 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.40**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.11.0
|
||||
Released 25th November 2022.
|
||||
|
||||
## General
|
||||
- Packet receive timings have now been split into two subcategories - Decode and Handle.
|
||||
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
|
||||
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
|
||||
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
|
||||
- Console command output now appears on the terminal only, and is not written to the log file.
|
||||
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
|
||||
- User-defined `pocketmine.yml` custom commands now use a generic description which makes clear the command is config-defined.
|
||||
- Introduced validation for the `--data` and `--plugins` command line options.
|
||||
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
|
||||
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
|
||||
- The file must contain the raw key bytes, and must not end with a newline.
|
||||
|
||||
## Configuration
|
||||
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
|
||||
- The functionality of this setting has been removed, since it caused more problems than it solved.
|
||||
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
|
||||
|
||||
## Gameplay
|
||||
- Fixed supporting blocks of dead bush to be in line with vanilla.
|
||||
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
|
||||
- Fixed missing sounds when adding, rotating, or removing items in item frames.
|
||||
- Fixed modifier values for Instant Damage and Regeneration effects.
|
||||
- Implemented Darkness effect.
|
||||
- Improved chunk random ticking:
|
||||
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
|
||||
- This change significantly improves crop and plant growth with large numbers of players.
|
||||
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
|
||||
- **Warning: This change will result in increased CPU usage if players are spread over a very large area.**
|
||||
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
|
||||
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
|
||||
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
|
||||
|
||||
### `pocketmine`
|
||||
- The following API methods are now deprecated:
|
||||
- `Server->getPlayerByPrefix()`
|
||||
|
||||
### `pocketmine\entity`
|
||||
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
|
||||
- The following API methods are now deprecated:
|
||||
- `Living->hasLineOfSight()`
|
||||
|
||||
### `pocketmine\event\block`
|
||||
- The following new classes have been added:
|
||||
- `BlockDeathEvent` - event called when coral or coral blocks die due to lack of water
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Armor->clearCustomColor() : $this`
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
|
||||
|
||||
### `pocketmine\lang`
|
||||
- The following new API methods have been added:
|
||||
- `public Language->getAll() : array<string, string>`
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new API methods have been added:
|
||||
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
|
||||
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added:
|
||||
- `ItemFrameAddItemSound`
|
||||
- `ItemFrameRemoveItemSound`
|
||||
- `ItemFrameRotateItemSound`
|
||||
|
||||
## Internals
|
||||
- Improved performance of `ContainerTrait` dropping items on block destroy. ([link](https://github.com/pmmp/PocketMine-MP/commits/24e72ec109c1442b09558df89b6833cf2f2e0ec7))
|
||||
- Avoid repeated calls to `Position->getWorld()` (use local variables). ([link](https://github.com/pmmp/PocketMine-MP/commit/2940547026db40ce76deb46e992870de3ead79ad))
|
||||
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. ([link](https://github.com/pmmp/PocketMine-MP/commit/e90abecf38d9c57635fa0497514bba7e546a2469))
|
||||
- Inventories are now mapped on a per-slot basis. This means that more than one inventory can be mapped to the same window ID, which is necessary for correctly handling "UI" inventories like crafting tables.
|
||||
- `InventoryManager->getWindow(int $windowId) : ?Inventory` is replaced by `locateWindowAndSlot` (see below).
|
||||
- Added `InventoryManager->locateWindowAndSlot(int $windowId, int $netSlotId) : array{Inventory, int}` - accepts a window ID and absolute slot ID, and returns the associated inventory and the slot relative to the inventory's own start (for use with `getItem()` etc.).
|
||||
- Slot offset mapping for "UI" inventories is now handled in `InventoryManager->createComplexSlotMapping()` instead of in `TypeConverter`.
|
||||
- Console polling is now done on the main thread (no longer a performance concern). ([link](https://github.com/pmmp/PocketMine-MP/commit/b3f03d7ae645de67a54b7300c09b94eeca16298e))
|
||||
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie. ([link](https://github.com/pmmp/PocketMine-MP/commit/2585160ca2c4df5758b8b980331307402ff9f0fb))
|
||||
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged. ([link](https://github.com/pmmp/PocketMine-MP/commit/83e5b0adb6fa0dddec377182bb1c7945ac8f7820))
|
||||
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused. ([link](https://github.com/pmmp/PocketMine-MP/commit/3feaa18f6c10c3a99c0deca75f57ec2d74b92ab4))
|
||||
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.
|
119
changelogs/4.12.md
Normal file
119
changelogs/4.12.md
Normal file
@ -0,0 +1,119 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.12.0
|
||||
Released 30th November 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.50.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.12.1
|
||||
Released 4th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed items glitching when dragging a stack of items across the crafting grid (desync issues).
|
||||
|
||||
# 4.12.2
|
||||
Released 15th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Folder used for plugins (optionally specified by `--plugins`) is no longer required to be writable.
|
||||
- Fixed broken writable check for server data folder (`is_writable()` broken on NFS and similar filesystems).
|
||||
- `Filesystem::createLockFile()` exceptions now include more information about why the lock file could not be created.
|
||||
- Fixed client-side item predictions not being rolled back when cancelling events such as `PlayerItemUseEvent`.
|
||||
|
||||
## Dependencies
|
||||
- Updated BedrockProtocol to [17.1.0](https://github.com/pmmp/BedrockProtocol/releases/tag/17.1.0+bedrock-1.19.50). This adds some missing `LevelSoundEvent` constants and fixes the values for `ContainerUIIds`.
|
||||
|
||||
# 4.12.3
|
||||
Released 28th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed unauthenticated connections taking up player count slots, preventing players from joining.
|
||||
- Fixed a possible crash in `World->tickChunk()` when plugins unload chunks during some events.
|
||||
- `/gamemode` will now report a failure to change game mode if the player is already in the requested game mode.
|
||||
|
||||
# 4.12.4
|
||||
Released 3rd January 2023.
|
||||
|
||||
## Fixes
|
||||
- Added workarounds for an active exploit being used to deny service to servers.
|
||||
|
||||
# 4.12.5
|
||||
Released 6th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Removed a workaround for an old client bug in custom form responses. The code contained a denial-of-service vulnerability.
|
||||
|
||||
# 4.12.6
|
||||
Released 7th January 2023.
|
||||
|
||||
## Changes
|
||||
- Added a new security measure to `NetworkSession` to detect and ban players who flood the server with packets.
|
||||
|
||||
# 4.12.7
|
||||
Released 8th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked when the server lags for too long.
|
||||
- Fixed players getting kicked when a debugging session is active and a breakpoint is hit.
|
||||
|
||||
# 4.12.8
|
||||
Released 9th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked during PvP.
|
||||
- Fixed players randomly getting kicked on Windows (improper rate limit handling wrt. 15ms timer resolution).
|
||||
|
||||
# 4.12.9
|
||||
Released 16th January 2023.
|
||||
|
||||
## Improvements
|
||||
### Timings
|
||||
- Added new timers:
|
||||
- `Server Mid-Tick Processing` - time spent processing Snooze interrupts between ticks (e.g. incoming network packets)
|
||||
- `Server Tick Update Cycle` - time spent processing regular per-tick updates (e.g. entity movement, world updates, etc.) (`Server->tick()`)
|
||||
- `Full Server Tick` timer now counts the total of `Server Mid-Tick Processing` and `Server Tick Update Cycle`, which generates more accurate performance metrics.
|
||||
- Previously, this timer only counted the time spent during regular per-tick updates, and the time recorded by `Server Mid-Tick Processing` was not included in the report at all.
|
||||
|
||||
## Fixes
|
||||
- Fixed blocks such as pressure plates being able to be placed without the correct supporting blocks if the clicked block was solid.
|
||||
- Pressure plates now self-destruct when the block below them is removed.
|
||||
- Fixed being unable to place blocks by clicking on the side of a bell (when the click doesn't result in ringing the bell).
|
||||
- Fixed various rotation-aware blocks (e.g. stairs) behaving incorrectly when placed by clicking on the side of a replaceable block (e.g. tall grass).
|
||||
- Fixed banners being able to be placed on top of blocks such as skulls.
|
||||
- Fixed server-side collision boxes of walls and glass (which should connect, but didn't). Note that wall connections still don't show client side - this just fixes the collision boxes.
|
||||
- Fixed `PlayerInteractEvent` with `LEFT_CLICK` sometimes firing before `BlockBreakEvent` when breaking blocks.
|
||||
|
||||
## Other changes
|
||||
- Increased packet batch budget for player sessions.
|
||||
|
||||
# 4.12.10
|
||||
Released 18th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed reported server load not including the time spent processing Snooze interrupts between ticks (e.g. incoming network packets).
|
||||
- Fixed `Connection Handler` entry in timings report not including time spent receiving packets.
|
||||
|
||||
## Note about server load & performance
|
||||
This version will report higher apparent server load than previous versions. The actual performance of the server is unchanged; the previous reported load was inaccurate.
|
||||
These bugs have been present for nearly 5 years (ever since the first introduction of Snooze in 3.0.0).
|
||||
|
||||
# 4.12.11
|
||||
Released 22nd January 2023.
|
||||
|
||||
## General
|
||||
- Code is now tested and analysed using PHP 8.2 in addition to 8.1 and 8.0.
|
||||
|
||||
## Fixes
|
||||
- Fixed pthreads 5.0.0 incorrectly being treated as compatible.
|
||||
- Fixed deprecation errors on PHP 8.2.
|
||||
|
||||
## Documentation
|
||||
- Updated documentation in `PlayerPreLoginEvent`.
|
94
changelogs/4.13-beta.md
Normal file
94
changelogs/4.13-beta.md
Normal file
@ -0,0 +1,94 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.13.0-BETA1
|
||||
Released 18th January 2023.
|
||||
|
||||
## Gameplay
|
||||
- Death message is now shown on the death screen when a player dies.
|
||||
- Armour damage is now only increased if the armour reduced the damage taken.
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
|
||||
|
||||
## Performance
|
||||
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
|
||||
|
||||
## Localization
|
||||
- Added localized description for the `/dumpmemory` command.
|
||||
|
||||
## Permissions
|
||||
- Added the following new core permissions:
|
||||
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
|
||||
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
|
||||
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
|
||||
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
|
||||
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
|
||||
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
|
||||
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
|
||||
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
|
||||
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
|
||||
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
|
||||
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
|
||||
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
|
||||
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
|
||||
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
|
||||
|
||||
## Internals
|
||||
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
|
||||
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
|
||||
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
|
||||
- Replaced hardcoded strings with constants in various places.
|
||||
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
|
||||
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
|
||||
- Added documentation for some internal methods.
|
||||
|
||||
## API
|
||||
### `pocketmine\command`
|
||||
- The following new API methods have been added:
|
||||
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
|
||||
|
||||
### `pocketmine\event\world`
|
||||
- The following new classes have been added:
|
||||
- `WorldSoundEvent` - called when a sound is played in a world
|
||||
- `WorldParticleEvent` - called when a particle is spawned in a world
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
|
||||
|
||||
### `pocketmine\lang`
|
||||
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new interfaces have been added:
|
||||
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
|
||||
- The following new classes have been added:
|
||||
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
|
||||
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
|
||||
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
|
||||
- The following API methods have been deprecated:
|
||||
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
|
||||
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning
|
94
changelogs/4.13.md
Normal file
94
changelogs/4.13.md
Normal file
@ -0,0 +1,94 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.13.0
|
||||
Released 30th January 2023.
|
||||
|
||||
## Gameplay
|
||||
- Death message is now shown on the death screen when a player dies.
|
||||
- Armour damage is now only increased if the armour reduced the damage taken.
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
|
||||
|
||||
## Performance
|
||||
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
|
||||
|
||||
## Localization
|
||||
- Added localized description for the `/dumpmemory` command.
|
||||
|
||||
## Permissions
|
||||
- Added the following new core permissions:
|
||||
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
|
||||
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
|
||||
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
|
||||
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
|
||||
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
|
||||
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
|
||||
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
|
||||
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
|
||||
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
|
||||
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
|
||||
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
|
||||
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
|
||||
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
|
||||
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
|
||||
|
||||
## Internals
|
||||
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
|
||||
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
|
||||
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
|
||||
- Replaced hardcoded strings with constants in various places.
|
||||
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
|
||||
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
|
||||
- Added documentation for some internal methods.
|
||||
|
||||
## API
|
||||
### `pocketmine\command`
|
||||
- The following new API methods have been added:
|
||||
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
|
||||
|
||||
### `pocketmine\event\world`
|
||||
- The following new classes have been added:
|
||||
- `WorldSoundEvent` - called when a sound is played in a world
|
||||
- `WorldParticleEvent` - called when a particle is spawned in a world
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
|
||||
|
||||
### `pocketmine\lang`
|
||||
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new interfaces have been added:
|
||||
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
|
||||
- The following new classes have been added:
|
||||
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
|
||||
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
|
||||
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
|
||||
- The following API methods have been deprecated:
|
||||
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
|
||||
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning
|
21
changelogs/4.14.md
Normal file
21
changelogs/4.14.md
Normal file
@ -0,0 +1,21 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.60**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.14.0
|
||||
Released 8th February 2023.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.60.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.14.1
|
||||
Released 15th February 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed all players getting kicked with `Receiving packets too fast` if a server tick takes longer than 5 seconds (e.g. because of autosave or GC).
|
||||
- Fixed players getting kicked when linking with entities.
|
14
changelogs/4.15.md
Normal file
14
changelogs/4.15.md
Normal file
@ -0,0 +1,14 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.62**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.15.0
|
||||
Released 17th February 2023.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.62.
|
||||
- Removed support for older versions.
|
121
changelogs/4.2.md
Normal file
121
changelogs/4.2.md
Normal file
@ -0,0 +1,121 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.10**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.2.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.18.10.
|
||||
|
||||
# 4.2.1
|
||||
Released 19th February 2022.
|
||||
|
||||
## General
|
||||
- Improved performance of `Item::nbtSerialize()` - this will improve performance during world saves.
|
||||
- Added more missing changes to the 4.0.0 changelog.
|
||||
|
||||
## Fixes
|
||||
- Fixed multiple players being able to sleep in the same bed.
|
||||
- Fixed hitbox not resetting properly after swimming or gliding.
|
||||
|
||||
# 4.2.2
|
||||
Released 2nd March 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed crash in `/dumpmemory` due to usage of non-printable string keys in `CraftingManager`. Array contents in memory dumps are now rendered as prettified key-value pairs.
|
||||
- Fixed output directory for `/dumpmemory`.
|
||||
- `PlayerInventory->isHotbarSlot()` now correctly returns `false` when given `9`.
|
||||
- Fixed ghost items left in the inventory when dropping tools while mining.
|
||||
|
||||
# 4.2.3
|
||||
Released 9th March 2022.
|
||||
|
||||
## Technical
|
||||
- Now analysed using PHPStan 1.4.8.
|
||||
- Now using `pocketmine/bedrock-protocol` [`8.0.1`](https://github.com/pmmp/BedrockProtocol/releases/tag/8.0.1%2Bbedrock-1.18.10).
|
||||
|
||||
## Fixes
|
||||
### Core
|
||||
- Fixed a memory leak and other bugs related to plugins disabling themselves during `onEnable()`.
|
||||
|
||||
### Gameplay
|
||||
- Sweet berry bushes now absorb fall damage.
|
||||
- Fixed mycelium spreading onto coarse dirt.
|
||||
- Fixed blocks placed during `Block->onIncinerate()` getting overwritten.
|
||||
- Fixed shulker boxes being unopenable when underwater.
|
||||
- Fixed invisible fire on top of transparent non-flammable blocks.
|
||||
|
||||
### API
|
||||
- Various APIs accepting `Vector3`, `Position` or `Location` no longer accept objects containing `INF` or `NaN` in any component. Previously, this was allowed, but would cause lots of obscure crashes later on.
|
||||
- `Entity->setRotation()` no longer accepts `INF` or `NaN`.
|
||||
- Fixed missing bounds check for `ItemFrame->setItemDropChance()`.
|
||||
|
||||
# 4.2.4
|
||||
Released 18th March 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed a crash when handling out-of-bounds meta values on the network.
|
||||
|
||||
# 4.2.5
|
||||
Released 28th March 2022.
|
||||
|
||||
## General
|
||||
- The layout of the human-readable part of crashdumps has been changed in an effort to improve the useful information density. It is hoped that this change will cause more useful information to be provided when people paste crash traces on Discord, since all the most important information is now at the top of the file.
|
||||
- Version, git hash, PHP version and OS have been moved to the top of the crashdump.
|
||||
- Backtrace has been moved above code sample.
|
||||
- Docker images are now built by GitHub Actions (first live test).
|
||||
|
||||
## Technical
|
||||
- The methods of `Inventory` and `BaseInventory` have been rearranged to improve coherency.
|
||||
|
||||
## Fixes
|
||||
### API
|
||||
- Enum members of enums created using `EnumTrait` are now able to have single-character names.
|
||||
- Registry members of registries created using `RegistryTrait` or `CloningRegistryTrait` now have their names checked for invalid characters.
|
||||
- `Entity::__construct()` now uses a guard variable to prevent it from being called multiple times unintentionally. This is necessary because `Entity::__construct()` has side effects.
|
||||
- Fixed `PlayerItemHeldEvent` not being called when the content of the held slot was changed (e.g. replacing the held item via inventory menu).
|
||||
|
||||
### Gameplay
|
||||
- Reduced the appearance of ghost items in unsupported gameplay scenarios using client prediction information. This fixes, for example, the appearance of ghost items when right-clicking on a filled flower pot.
|
||||
|
||||
# 4.2.6
|
||||
Released 1st April 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed buffer length underflow crash in `LoginPacket` handling.
|
||||
|
||||
# 4.2.7
|
||||
Released 15th April 2022.
|
||||
|
||||
## General
|
||||
- Added lots more documentation (in comments) about the `aliases` section in `pocketmine.yml`. You can read about this feature in the `aliases` section of the [updated `pocketmine.yml` template](/resources/pocketmine.yml).
|
||||
- Improved wording of documentation of `PlayerPreLoginEvent`.
|
||||
|
||||
## Fixes
|
||||
- Fixed core server crash when a plugin causes another plugin to be disabled during a scheduled task.
|
||||
- Fixed core server crash when loading a plugin with an abstract main class.
|
||||
- Fixed ghost items in many interaction situations (most notably, using projectiles while looking at an entity or block).
|
||||
- Implemented a workaround for a client teleport bug which led to player positions not updating properly when using ender pearls.
|
||||
- Fixed buggy movement when teleporting the player during `PlayerToggleSneakEvent`, `PlayerToggleSprintEvent`, `PlayerToggleSwimEvent` and `PlayerToggleGlideEvent`.
|
||||
|
||||
# 4.2.8
|
||||
Released 17th April 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed a memory leak in RakLib which could result in a server crash when players stay online for a long time.
|
||||
- Fixed server crash when attempting to load a corrupted empty resource pack.
|
||||
- Fixed users with the same name with differerently cased letters being able to duplicate items (userdata is matched by case-insensitive name).
|
||||
|
||||
# 4.2.9
|
||||
Released 19th April 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed several potential crashes when deserializing item NBT (due to insufficient validation of input data).
|
||||
|
||||
# 4.2.10
|
||||
Released 20th April 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed performance issue when chat messages received from the client contain many newlines. This security vulnerability was disclosed publicly necessitating a priority fix.
|
77
changelogs/4.3.md
Normal file
77
changelogs/4.3.md
Normal file
@ -0,0 +1,77 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.3.0
|
||||
Released 20th April 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.18.30.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.3.1
|
||||
Released 23rd April 2022.
|
||||
|
||||
## Fixes
|
||||
- Updated BedrockProtocol dependency to fix incorrect command argument types.
|
||||
- Creative players no longer die in the void.
|
||||
|
||||
# 4.3.2
|
||||
Released 10th May 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed an assertion failure in certain edge cases during world generation.
|
||||
- Fixed `Entity::setNameTagVisible()` not immediately showing results to players already online.
|
||||
|
||||
## Documentation
|
||||
- Added more documentation in the template `pocketmine.yml` for the `aliases` config section.
|
||||
- Removed useless doc comment in `PlayerChangeSkinEvent`.
|
||||
|
||||
# 4.3.3
|
||||
Released 16th May 2022.
|
||||
|
||||
## General
|
||||
- Improved display of parameters in exception stack trace logs.
|
||||
- Exception stack traces now include names for dynamic named arguments (i.e. arguments that don't match any parameter of the function), if any were given.
|
||||
- Note: Named arguments which do match parameters are not shown this way, since PHP reduces them to positional arguments for performance reasons.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when chunks are unloaded during chunk generation callbacks
|
||||
- Fixed dead coral fan items placing coral fans in the wrong orientation.
|
||||
- Fixed max stack size of boat items.
|
||||
|
||||
# 4.3.4
|
||||
Released 22nd May 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed `difficulty` in `server.properties` having no effect - it's now applied to newly generated worlds.
|
||||
- Note: this setting still doesn't behave the same way as vanilla due to potential disruption to existing servers.
|
||||
- Fixed paintings not working in newly generated worlds and some other cases.
|
||||
- Fixed inventory window switching breaking the inventory UI in some cases (e.g. pressing E while clicking a chest).
|
||||
- Fixed minecart items incorrectly stacking.
|
||||
- Fixed incorrect light levels in translucent blocks at the top of the world.
|
||||
- Fixed teleporting sleeping players causing broken behaviour on the sleeping player's client.
|
||||
- Fixed `EntityExplodeEvent->setYield()` accepting values outside the range 0-100.
|
||||
- Fixed `ExplosionPrimeEvent->setForce()` accepting negative values (later resulting in crashes).
|
||||
|
||||
## Documentation
|
||||
- Updated documentation for the following events:
|
||||
- `CommandEvent`
|
||||
- `EntityDespawnEvent`
|
||||
- `EntityExplodeEvent`
|
||||
- `EntitySpawnEvent`
|
||||
- `ExplosionPrimeEvent`
|
||||
- `InventoryTransactionEvent`
|
||||
- `ItemDespawnEvent`
|
||||
- `ItemSpawnEvent`
|
||||
- `PlayerCommandPreprocessEvent`
|
||||
- `PlayerDropItemEvent`
|
||||
- `PlayerItemHeldEvent`
|
||||
- `PlayerKickEvent`
|
||||
- `PlayerQuitEvent`
|
||||
- `PlayerTransferEvent`
|
||||
- `UpdateNotifyEvent`
|
77
changelogs/4.4-beta.md
Normal file
77
changelogs/4.4-beta.md
Normal file
@ -0,0 +1,77 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.4.0-BETA1
|
||||
Released 25th May 2022.
|
||||
|
||||
## General
|
||||
- The server will now shut itself down if any of the following errors occur during startup:
|
||||
- Any plugin fails to load or enable (plugins loaded by other plugins post-startup are **not** affected by this change) (**PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)**)
|
||||
- The motivation for this change is to prevent situations where plugins failing to load could result in adverse outcomes, such as a world protection plugin leaving a lobby unprotected from griefing.
|
||||
- If you encounter this problem, remove the offending plugin(s) or prevent it from loading using `plugin_list.yml`.
|
||||
- See **PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)** for more detail on this change.
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to load (worlds loaded by plugins are **not** affected by this change)
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
|
||||
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
|
||||
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
|
||||
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
|
||||
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
|
||||
|
||||
## Fixes
|
||||
- Block placement has been fixed in many places where it previously didn't work correctly (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**):
|
||||
- torches on top of slabs, upside-down stairs
|
||||
- torches on the back face of stairs
|
||||
- flower pots on top of fences
|
||||
- the list goes on and on ...
|
||||
- Fixed backslash escapes not getting properly removed from commands in some cases.
|
||||
- Fixed aliases defined in the `aliases` section of `pocketmine.yml` not being treated as quote-aware.
|
||||
|
||||
## Gameplay
|
||||
- Plants in flower pots can now be removed by right-clicking on the flower pot.
|
||||
- Leaves now have a 2% chance of dropping sticks when destroyed by hand (**PR [#5019](https://github.com/pmmp/PocketMine-MP/pull/5019)**).
|
||||
- Food exhaustion now matches Bedrock 1.18.30 (**PR [#5034](https://github.com/pmmp/PocketMine-MP/pull/5034)**).
|
||||
- Implemented Stonecutter block (**PR [#4732](https://github.com/pmmp/PocketMine-MP/pull/4732)**).
|
||||
|
||||
## API
|
||||
### Block
|
||||
- Added `Block->getSupportType(Facing) : SupportType` (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- This is used to determine the kind of support a block face can provide to a block (e.g. a torch) placed on it.
|
||||
- Added `utils\SupportType` enum (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- `tile\Spawnable->isDirty()` and `tile\Spawnable->setDirty()` are now `@deprecated`.
|
||||
|
||||
### Command
|
||||
- Added `CommandStringHelper::parseQuoteAware()`. This static method contains the code used by `SimpleCommandMap` used to parse quoted command arguments.
|
||||
|
||||
### Entity
|
||||
- Added `Human::emote()` (**PR [#4610](https://github.com/pmmp/PocketMine-MP/pull/4610)**)
|
||||
|
||||
### Event
|
||||
- `PlayerCommandPreprocessEvent` is now `@deprecated`, since its functionality is entirely replaced by other, general-purpose events.
|
||||
- Use `CommandEvent` to intercept commands.
|
||||
- Use `PlayerChatEvent` to intercept chat messages.
|
||||
- To convert a chat message into a command, pass it directly to `Server->dispatchCommand()` with the player as sender.
|
||||
- Added `PlayerPostChunkSendEvent` (**PR [#4937](https://github.com/pmmp/PocketMine-MP/pull/4937)**).
|
||||
- Added `PlayerDeathEvent->setKeepXp()` (**PR [#4015](https://github.com/pmmp/PocketMine-MP/pull/4015)**).
|
||||
- `InventoryCloseEvent` is now called **after** the target window has been removed. This fixes various feedback loops caused by trying to open new windows to a player while there was one still active.
|
||||
- As a side effect, this now means that `Player->getCurrentWindow()` will return `null` during `InventoryCloseEvent`. Use `InventoryCloseEvent->getInventory()` instead.
|
||||
|
||||
### Item
|
||||
- `StringToItemParser` now recognizes `cod`, `raw_cod` and `cooked_cod` aliases.
|
||||
|
||||
### Plugin
|
||||
- `DisablePluginException` may now be thrown from `Plugin::onEnable()` to make the server gracefully disable the plugin (without crashing) (**PR [#4780](https://github.com/pmmp/PocketMine-MP/pull/4780)**).
|
||||
- `PluginManager->registerEvent()` now returns the `RegisteredListener` created for the handler, to permit unregistering it later.
|
||||
|
||||
## Internals
|
||||
- Private property declarations now use typed properties (PHP 7.4) and promoted constructor properties (PHP 8.0) wherever possible.
|
||||
- Protected and public properties remain unchanged, since they can't be changed without breaking subclasses.
|
||||
- Promoted constructor properties are only used when it's consistently possible to promote most or all properties in a class.
|
||||
- Simplified and improved legibility of `FormattedCommandAlias`.
|
||||
- Added unit tests for the quote-aware command parser used by `SimpleCommandMap`.
|
||||
- Various hardcoded values in `block` package classes have been moved to private constants to improve readability.
|
||||
- Added various constants used in the `LevelDB` world provider.
|
97
changelogs/4.4.md
Normal file
97
changelogs/4.4.md
Normal file
@ -0,0 +1,97 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.4.0
|
||||
Released 1st June 2022.
|
||||
|
||||
## General
|
||||
- The server will now shut itself down if any of the following errors occur during startup:
|
||||
- Any plugin fails to load or enable (plugins loaded by other plugins post-startup are **not** affected by this change) (**PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)**)
|
||||
- The motivation for this change is to prevent situations where plugins failing to load could result in adverse outcomes, such as a world protection plugin leaving a lobby unprotected from griefing.
|
||||
- If you encounter this problem, remove the offending plugin(s) or prevent it from loading using `plugin_list.yml`.
|
||||
- See **PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)** for more detail on this change.
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to load (worlds loaded by plugins are **not** affected by this change)
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
|
||||
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
|
||||
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
|
||||
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
|
||||
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
|
||||
|
||||
## Fixes
|
||||
- Block placement has been fixed in many places where it previously didn't work correctly (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**):
|
||||
- torches on top of slabs, upside-down stairs
|
||||
- torches on the back face of stairs
|
||||
- flower pots on top of fences
|
||||
- the list goes on and on ...
|
||||
- Fixed backslash escapes not getting properly removed from commands in some cases.
|
||||
- Fixed aliases defined in the `aliases` section of `pocketmine.yml` not being treated as quote-aware.
|
||||
|
||||
## Gameplay
|
||||
- Plants in flower pots can now be removed by right-clicking on the flower pot.
|
||||
- Leaves now have a 2% chance of dropping sticks when destroyed by hand (**PR [#5019](https://github.com/pmmp/PocketMine-MP/pull/5019)**).
|
||||
- Food exhaustion now matches Bedrock 1.18.30 (**PR [#5034](https://github.com/pmmp/PocketMine-MP/pull/5034)**).
|
||||
- Implemented Stonecutter block (**PR [#4732](https://github.com/pmmp/PocketMine-MP/pull/4732)**).
|
||||
|
||||
## API
|
||||
### Block
|
||||
- Added `Block->getSupportType(Facing) : SupportType` (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- This is used to determine the kind of support a block face can provide to a block (e.g. a torch) placed on it.
|
||||
- Added `utils\SupportType` enum (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- `tile\Spawnable->isDirty()` and `tile\Spawnable->setDirty()` are now `@deprecated`.
|
||||
|
||||
### Command
|
||||
- Added `CommandStringHelper::parseQuoteAware()`. This static method contains the code used by `SimpleCommandMap` used to parse quoted command arguments.
|
||||
|
||||
### Entity
|
||||
- Added `Human::emote()` (**PR [#4610](https://github.com/pmmp/PocketMine-MP/pull/4610)**)
|
||||
|
||||
### Event
|
||||
- `PlayerCommandPreprocessEvent` is now `@deprecated`, since its functionality is entirely replaced by other, general-purpose events.
|
||||
- Use `CommandEvent` to intercept commands.
|
||||
- Use `PlayerChatEvent` to intercept chat messages.
|
||||
- To convert a chat message into a command, pass it directly to `Server->dispatchCommand()` with the player as sender.
|
||||
- Added `PlayerPostChunkSendEvent` (**PR [#4937](https://github.com/pmmp/PocketMine-MP/pull/4937)**).
|
||||
- Added `PlayerDeathEvent->setKeepXp()` (**PR [#4015](https://github.com/pmmp/PocketMine-MP/pull/4015)**).
|
||||
- `InventoryCloseEvent` is now called **after** the target window has been removed. This fixes various feedback loops caused by trying to open new windows to a player while there was one still active.
|
||||
- As a side effect, this now means that `Player->getCurrentWindow()` will return `null` during `InventoryCloseEvent`. Use `InventoryCloseEvent->getInventory()` instead.
|
||||
|
||||
### Item
|
||||
- `StringToItemParser` now recognizes `cod`, `raw_cod` and `cooked_cod` aliases.
|
||||
|
||||
### Plugin
|
||||
- `DisablePluginException` may now be thrown from `Plugin::onEnable()` to make the server gracefully disable the plugin (without crashing) (**PR [#4780](https://github.com/pmmp/PocketMine-MP/pull/4780)**).
|
||||
- `PluginManager->registerEvent()` now returns the `RegisteredListener` created for the handler, to permit unregistering it later.
|
||||
|
||||
## Internals
|
||||
- Private property declarations now use typed properties (PHP 7.4) and promoted constructor properties (PHP 8.0) wherever possible.
|
||||
- Protected and public properties remain unchanged, since they can't be changed without breaking subclasses.
|
||||
- Promoted constructor properties are only used when it's consistently possible to promote most or all properties in a class.
|
||||
- Simplified and improved legibility of `FormattedCommandAlias`.
|
||||
- Added unit tests for the quote-aware command parser used by `SimpleCommandMap`.
|
||||
- Various hardcoded values in `block` package classes have been moved to private constants to improve readability.
|
||||
- Added various constants used in the `LevelDB` world provider.
|
||||
|
||||
# 4.4.1
|
||||
Released 5th June 2022.
|
||||
|
||||
## General
|
||||
- The server process will now exit with an error code if plugins, worlds or network interfaces failed to start.
|
||||
|
||||
## Fixes
|
||||
- Fixed graylisted plugins preventing the server from starting.
|
||||
- Fixed `composer make-devtools` command.
|
||||
- Fixed the `Maximum memory (manager)` units being incorrectly displayed in `/status`.
|
||||
- Fixed `Player->removeCurrentWindow()` breaking inventory windows.
|
||||
|
||||
# 4.4.2
|
||||
Released 7th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed a crash when arbitrary item IDs appeared in network items in some cases.
|
||||
- Fixed saved paintings being deleted when loaded from disk (regression from 4.3.4).
|
||||
- Fixed max stack size of fishing rods.
|
28
changelogs/4.5.md
Normal file
28
changelogs/4.5.md
Normal file
@ -0,0 +1,28 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.5.0
|
||||
Released 7th June 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.0.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.5.1
|
||||
Released 8th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed commands defined in `pocketmine.yml` `aliases` not passing the correct arguments.
|
||||
- Updated BedrockProtocol to fix command argument types displayed on client-side command suggestions.
|
||||
|
||||
# 4.5.2
|
||||
Released 29th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed terrain getting redrawn when flying in spectator mode (or when using `Player->setHasBlockCollision(false)`).
|
||||
- Fixed skulls with the `noDrops` flag set being treated as unknown blocks.
|
42
changelogs/4.6.md
Normal file
42
changelogs/4.6.md
Normal file
@ -0,0 +1,42 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.10**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.6.0
|
||||
Released 13th July 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.10.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.6.1
|
||||
Released 22nd July 2022.
|
||||
|
||||
## Tools
|
||||
- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers).
|
||||
|
||||
## API
|
||||
- Updated documentation for `AsyncTask`.
|
||||
|
||||
## Fixes
|
||||
- Fixed incorrect items being displayed in item frames.
|
||||
- Fixed books not showing in lecterns.
|
||||
- Fixed incorrect damage interval of Wither status effect.
|
||||
- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15).
|
||||
- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof.
|
||||
- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil.
|
||||
|
||||
# 4.6.2
|
||||
Released 6th August 2022.
|
||||
|
||||
## Core
|
||||
- Improved server-side performance of `PlayerAuthInputPacket` handler.
|
||||
- Improved client-side performance of `FloatingTextParticle` by using an invisible falling block entity. This offered a roughly 5x performance improvement over using tiny invisible players in local testing.
|
||||
|
||||
## Fixes
|
||||
- Fixed assert failures and debug spam on debug Minecraft clients related to abilities in `AddPlayerPacket`.
|
||||
- Fixed crash in `ReversePriorityQueue` on PHP 8.1 by adding `#[ReturnTypeWillChange]` attribute.
|
46
changelogs/4.7.md
Normal file
46
changelogs/4.7.md
Normal file
@ -0,0 +1,46 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.20**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.7.0
|
||||
Released 9th August 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.20.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.7.1
|
||||
Released 14th August 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when loading items from disk which have negative meta values.
|
||||
- Fixed Turtle Master potions not giving any effects.
|
||||
- Unimplemented items are no longer craftable.
|
||||
- Fixed incorrect items appearing in item frames (due to an obsolete workaround for 1.19.10).
|
||||
|
||||
# 4.7.2
|
||||
Released 16th August 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed crash when processing player skins with invalid geometry data.
|
||||
- Fixed spectator players being able to pick blocks using mousewheel click.
|
||||
- Improved supporting requirements for sugarcane.
|
||||
|
||||
# 4.7.3
|
||||
Released 22nd August 2022.
|
||||
|
||||
## General
|
||||
- Added complete translations for Spanish and Vietnamese.
|
||||
- All continuous integration (static analysis, unit tests, integration tests) are now performed on PHP 8.1 as well as 8.0.
|
||||
- InventoryTransaction now verifies that stack sizes of items after the transaction don't exceed the maximum stack size of the item type or the containing inventory.
|
||||
|
||||
## Fixes
|
||||
- Fixed Normal generator crash on PHP 8.1.
|
||||
- Fixed a race condition during async worker shutdown that could lead to tasks executing in the wrong order. This (very rarely) led to a crash in `PopulationTask` due to its preceding `GeneratorRegisterTask` not being executed.
|
||||
- Fixed `/give` accepting negative amounts or amounts larger than 32767 (vanilla max).
|
||||
- Fixed placement conditions for vines (no longer able to be placed on the side of cacti).
|
||||
- Fixed incorrect documentation of `SignText::__construct()`.
|
23
changelogs/4.8.md
Normal file
23
changelogs/4.8.md
Normal file
@ -0,0 +1,23 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.21**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.8.0
|
||||
Released 24th August 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.21.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.8.1
|
||||
Released 26th August 2022.
|
||||
|
||||
## General
|
||||
- Crashdumps now include JIT mode information for use by the Crash Archive.
|
||||
|
||||
## Fixes
|
||||
- Fixed uninitialized offset error in `DyeColorIdMap` when given invalid dye color IDs.
|
36
changelogs/4.9.md
Normal file
36
changelogs/4.9.md
Normal file
@ -0,0 +1,36 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.9.0
|
||||
Released 20th September 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.30.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.9.1
|
||||
Released 11th October 2022.
|
||||
|
||||
## Documentation
|
||||
- Added and improved documentation for many API methods in `Player` and `Block`.
|
||||
- Added missing `@internal` tag for `TaskHandler->setNextRun()`, `TaskHandler->remove()` and `TaskHandler->run()`.
|
||||
|
||||
## Fixes
|
||||
- Flight state is now locked by the server in spectator mode. This prevents any attempt by the client to toggle flight mode.
|
||||
- Fixed entity health exceeding its max health after the expiry of Health Boost effect.
|
||||
- Fixed burp sound not being played when a player eats food.
|
||||
- Fixed placement conditions for mushrooms - they can now only be placed when the light level at the target is <= 12, or on podzol or mycelium.
|
||||
- Fixed sign text appearing to change colour and/or glow when using dye on a sign - since this feature is not yet implemented, no change should occur.
|
||||
- Fixed players drowning when sprint-swimming on the surface of water.
|
||||
|
||||
## Internals
|
||||
- Added more detailed debug logging during the player login sequence.
|
||||
- Silenced debug spam during `PreSpawnPacketHandler`, considerably reducing debug noise when players join.
|
||||
- Fixed an edge case in `InventoryManager->removeWindow()`. This bug didn't have any effect on stable versions, but caused a `next-minor` development version to crash.
|
||||
- `Item`s returned by event getters are now cloned if modifying the result will have no useful side effects.
|
||||
- Updated `pocketmine/bedrock-data` to [`1.11.1`](https://github.com/pmmp/BedrockData/tree/1.11.1%2Bbedrock-1.19.30), which reduces bandwidth consumption during logins by not sending useless biome generation data.
|
@ -34,14 +34,14 @@
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"fgrosse/phpasn1": "^2.3",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"pocketmine/bedrock-data": "~1.5.0+bedrock-1.18.0",
|
||||
"pocketmine/bedrock-protocol": "~7.1.0+bedrock-1.18.0",
|
||||
"pocketmine/bedrock-data": "~1.14.0+bedrock-1.19.60",
|
||||
"pocketmine/bedrock-protocol": "~19.2.0+bedrock-1.19.62",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
"pocketmine/color": "^0.2.0",
|
||||
"pocketmine/errorhandler": "^0.3.0",
|
||||
"pocketmine/locale-data": "~2.3.0",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.18.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
@ -50,12 +50,13 @@
|
||||
"pocketmine/raklib-ipc": "^0.1.0",
|
||||
"pocketmine/snooze": "^0.3.0",
|
||||
"ramsey/uuid": "^4.1",
|
||||
"symfony/filesystem": "^5.4",
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.3.3",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpstan/phpstan": "1.9.17",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
},
|
||||
"autoload": {
|
||||
@ -79,7 +80,7 @@
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
|
1026
composer.lock
generated
1026
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.15
|
||||
# Doxyfile 1.9.3
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@ -93,14 +93,6 @@ ALLOW_UNICODE_NAMES = NO
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all generated output in the proper direction.
|
||||
# Possible values are: None, LTR, RTL and Context.
|
||||
# The default value is: None.
|
||||
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
|
||||
# descriptions after the members that are listed in the file and class
|
||||
# documentation (similar to Javadoc). Set to NO to disable this.
|
||||
@ -197,6 +189,16 @@ SHORT_NAMES = NO
|
||||
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
|
||||
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
|
||||
# such as
|
||||
# /***************
|
||||
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
|
||||
# Javadoc-style will behave just like regular comments and it will not be
|
||||
# interpreted by doxygen.
|
||||
# The default value is: NO.
|
||||
|
||||
JAVADOC_BANNER = NO
|
||||
|
||||
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
|
||||
# line (until the first dot) of a Qt-style comment as the brief description. If
|
||||
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
|
||||
@ -217,6 +219,14 @@ QT_AUTOBRIEF = NO
|
||||
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
|
||||
# By default Python docstrings are displayed as preformatted text and doxygen's
|
||||
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
|
||||
# doxygen's special commands can be used and the contents of the docstring
|
||||
# documentation blocks is shown as doxygen documentation.
|
||||
# The default value is: YES.
|
||||
|
||||
PYTHON_DOCSTRING = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
||||
# documentation from any documented member that it re-implements.
|
||||
# The default value is: YES.
|
||||
@ -240,25 +250,19 @@ TAB_SIZE = 4
|
||||
# the documentation. An alias has the form:
|
||||
# name=value
|
||||
# For example adding
|
||||
# "sideeffect=@par Side Effects:\n"
|
||||
# "sideeffect=@par Side Effects:^^"
|
||||
# will allow you to put the command \sideeffect (or @sideeffect) in the
|
||||
# documentation, which will result in a user-defined paragraph with heading
|
||||
# "Side Effects:". You can put \n's in the value part of an alias to insert
|
||||
# newlines (in the resulting output). You can put ^^ in the value part of an
|
||||
# alias to insert a newline as if a physical newline was in the original file.
|
||||
# When you need a literal { or } or , in the value part of an alias you have to
|
||||
# escape them by means of a backslash (\), this can lead to conflicts with the
|
||||
# commands \{ and \} for these it is advised to use the version @{ and @} or use
|
||||
# a double escape (\\{ and \\})
|
||||
# "Side Effects:". Note that you cannot put \n's in the value part of an alias
|
||||
# to insert newlines (in the resulting output). You can put ^^ in the value part
|
||||
# of an alias to insert a newline as if a physical newline was in the original
|
||||
# file. When you need a literal { or } or , in the value part of an alias you
|
||||
# have to escape them by means of a backslash (\), this can lead to conflicts
|
||||
# with the commands \{ and \} for these it is advised to use the version @{ and
|
||||
# @} or use a double escape (\\{ and \\})
|
||||
|
||||
ALIASES =
|
||||
|
||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||
# will allow you to use the command class in the itcl::class meaning.
|
||||
|
||||
TCL_SUBST =
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C. For
|
||||
# instance, some of the names that are used will be different. The list of all
|
||||
@ -299,19 +303,22 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
||||
# parses. With this tag you can assign which parser to use for a given
|
||||
# extension. Doxygen has a built-in mapping, but you can override or extend it
|
||||
# using this tag. The format is ext=language, where ext is a file extension, and
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
|
||||
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
|
||||
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
|
||||
# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
|
||||
# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
|
||||
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
|
||||
# tries to guess whether the code is fixed or free formatted code, this is the
|
||||
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
|
||||
# .inc files as Fortran files (default is PHP), and .f files as C (default is
|
||||
# Fortran), use: inc=Fortran f=C.
|
||||
# default for Fortran type files). For instance to make doxygen treat .inc files
|
||||
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
|
||||
# use: inc=Fortran f=C.
|
||||
#
|
||||
# Note: For files without extension you can use no_extension as a placeholder.
|
||||
#
|
||||
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
|
||||
# the files are not read by doxygen.
|
||||
# the files are not read by doxygen. When specifying no_extension you should add
|
||||
# * to the FILE_PATTERNS.
|
||||
#
|
||||
# Note see also the list of default file extension mappings.
|
||||
|
||||
EXTENSION_MAPPING =
|
||||
|
||||
@ -329,7 +336,7 @@ MARKDOWN_SUPPORT = YES
|
||||
# to that level are automatically included in the table of contents, even if
|
||||
# they do not have an id attribute.
|
||||
# Note: This feature currently applies only to Markdown headings.
|
||||
# Minimum value: 0, maximum value: 99, default value: 0.
|
||||
# Minimum value: 0, maximum value: 99, default value: 5.
|
||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||
|
||||
TOC_INCLUDE_HEADINGS = 0
|
||||
@ -445,6 +452,19 @@ TYPEDEF_HIDES_STRUCT = NO
|
||||
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
|
||||
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
|
||||
# during processing. When set to 0 doxygen will based this on the number of
|
||||
# cores available in the system. You can set it explicitly to a value larger
|
||||
# than 0 to get more control over the balance between CPU load and processing
|
||||
# speed. At this moment only the input processing can be done using multiple
|
||||
# threads. Since this is still an experimental feature the default is set to 1,
|
||||
# which effectively disables parallel processing. Please report any issues you
|
||||
# encounter. Generating dot graphs in parallel is controlled by the
|
||||
# DOT_NUM_THREADS setting.
|
||||
# Minimum value: 0, maximum value: 32, default value: 1.
|
||||
|
||||
NUM_PROC_THREADS = 1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
@ -465,6 +485,12 @@ EXTRACT_ALL = NO
|
||||
|
||||
EXTRACT_PRIVATE = NO
|
||||
|
||||
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
|
||||
# methods of a class will be included in the documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
|
||||
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
|
||||
# scope will be included in the documentation.
|
||||
# The default value is: NO.
|
||||
@ -502,6 +528,13 @@ EXTRACT_LOCAL_METHODS = YES
|
||||
|
||||
EXTRACT_ANON_NSPACES = YES
|
||||
|
||||
# If this flag is set to YES, the name of an unnamed parameter in a declaration
|
||||
# will be determined by the corresponding definition. By default unnamed
|
||||
# parameters remain unnamed in the output.
|
||||
# The default value is: YES.
|
||||
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||
# undocumented members inside documented classes or files. If set to NO these
|
||||
# members will be included in the various overviews, but no documentation
|
||||
@ -519,8 +552,8 @@ HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
|
||||
# (class|struct|union) declarations. If set to NO, these declarations will be
|
||||
# included in the documentation.
|
||||
# declarations. If set to NO, these declarations will be included in the
|
||||
# documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
@ -539,11 +572,18 @@ HIDE_IN_BODY_DOCS = YES
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
|
||||
# names in lower-case letters. If set to YES, upper-case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# and Mac users are advised to set this option to NO.
|
||||
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
|
||||
# able to match the capabilities of the underlying filesystem. In case the
|
||||
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||
# whose names only differ in casing), the option must be set to YES to properly
|
||||
# deal with such files in case they appear in the input. For filesystems that
|
||||
# are not case sensitive the option should be be set to NO to properly deal with
|
||||
# output files written for symbols that only differ in casing, such as for two
|
||||
# classes, one named CLASS and the other named Class, and to also support
|
||||
# references to files without having to specify the exact matching casing. On
|
||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||
# YES.
|
||||
# The default value is: system dependent.
|
||||
|
||||
CASE_SENSE_NAMES = NO
|
||||
@ -562,6 +602,12 @@ HIDE_SCOPE_NAMES = NO
|
||||
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
|
||||
# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
|
||||
# will show which file needs to be included to use the class.
|
||||
# The default value is: YES.
|
||||
|
||||
SHOW_HEADERFILE = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
|
||||
# the files that are included by a file in the documentation of that file.
|
||||
# The default value is: YES.
|
||||
@ -719,7 +765,8 @@ FILE_VERSION_FILTER =
|
||||
# output files in an output format independent way. To create the layout file
|
||||
# that represents doxygen's defaults, run doxygen with the -l option. You can
|
||||
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
|
||||
# will be used as the name of the layout file.
|
||||
# will be used as the name of the layout file. See also section "Changing the
|
||||
# layout of pages" for information.
|
||||
#
|
||||
# Note that if you run doxygen from a directory containing a file called
|
||||
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
||||
@ -765,24 +812,35 @@ WARNINGS = NO
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
|
||||
# potential errors in the documentation, such as not documenting some parameters
|
||||
# in a documented function, or documenting parameters that don't exist or using
|
||||
# markup commands wrongly.
|
||||
# potential errors in the documentation, such as documenting some parameters in
|
||||
# a documented function twice, or documenting parameters that don't exist or
|
||||
# using markup commands wrongly.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
|
||||
# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
|
||||
# function parameter documentation. If set to NO, doxygen will accept that some
|
||||
# parameters have no documentation without warning.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_INCOMPLETE_DOC = YES
|
||||
|
||||
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
|
||||
# are documented, but have no documentation for their parameters or return
|
||||
# value. If set to NO, doxygen will only warn about wrong or incomplete
|
||||
# parameter documentation, but not about the absence of documentation. If
|
||||
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
|
||||
# value. If set to NO, doxygen will only warn about wrong parameter
|
||||
# documentation, but not about the absence of documentation. If EXTRACT_ALL is
|
||||
# set to YES then this flag will automatically be disabled. See also
|
||||
# WARN_IF_INCOMPLETE_DOC
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_NO_PARAMDOC = NO
|
||||
|
||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||
# a warning is encountered.
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
@ -799,7 +857,10 @@ WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
|
||||
# messages should be written. If left blank the output is written to standard
|
||||
# error (stderr).
|
||||
# error (stderr). In case the file specified cannot be opened for writing the
|
||||
# warning and error messages are written to standard error. When as file - is
|
||||
# specified the warning and error messages are written to standard output
|
||||
# (stdout).
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
@ -820,8 +881,8 @@ INPUT = ../src \
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# documentation (see:
|
||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
@ -834,11 +895,15 @@ INPUT_ENCODING = UTF-8
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# read by doxygen.
|
||||
#
|
||||
# Note the list of default checked file patterns might differ from the list of
|
||||
# default file extension mappings.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
|
||||
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
|
||||
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS = *.php
|
||||
|
||||
@ -883,7 +948,7 @@ EXCLUDE_PATTERNS = */bin/* \
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# AClass::ANamespace, ANamespace::*Test
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
@ -1059,16 +1124,24 @@ USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
|
||||
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
|
||||
# cost of reduced performance. This can be particularly helpful with template
|
||||
# rich C++ code for which doxygen's built-in parser lacks the necessary type
|
||||
# information.
|
||||
# clang parser (see:
|
||||
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
|
||||
# performance. This can be particularly helpful with template rich C++ code for
|
||||
# which doxygen's built-in parser lacks the necessary type information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
|
||||
# tag is set to YES then doxygen will add the directory of each input to the
|
||||
# include path.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||
# line options that you would normally use when invoking the compiler. Note that
|
||||
# the include paths will already be set by doxygen for the files and directories
|
||||
@ -1078,10 +1151,13 @@ CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_OPTIONS =
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the clang parser with the
|
||||
# path to the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
|
||||
# were built. This is equivalent to specifying the "-p" option to a clang tool,
|
||||
# such as clang-check. These options will then be passed to the parser.
|
||||
# path to the directory containing a file called compile_commands.json. This
|
||||
# file is the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
|
||||
# options used when the source files were built. This is equivalent to
|
||||
# specifying the -p option to a clang tool, such as clang-check. These options
|
||||
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
|
||||
# will be added as well.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
|
||||
@ -1098,13 +1174,6 @@ CLANG_DATABASE_PATH =
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
|
||||
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
|
||||
# which the alphabetical index list will be split.
|
||||
# Minimum value: 1, maximum value: 20, default value: 5.
|
||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all classes will
|
||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||
@ -1204,7 +1273,7 @@ HTML_EXTRA_FILES =
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
# this color. Hue is specified as an angle on a colorwheel, see
|
||||
# this color. Hue is specified as an angle on a color-wheel, see
|
||||
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
|
||||
# purple, and 360 is red again.
|
||||
@ -1214,7 +1283,7 @@ HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
|
||||
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
|
||||
# in the HTML output. For a value of 0 the output will use grayscales only. A
|
||||
# in the HTML output. For a value of 0 the output will use gray-scales only. A
|
||||
# value of 255 will produce the most vivid colors.
|
||||
# Minimum value: 0, maximum value: 255, default value: 100.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
@ -1239,13 +1308,13 @@ HTML_COLORSTYLE_GAMMA = 80
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
# are dynamically created via Javascript. If disabled, the navigation index will
|
||||
# are dynamically created via JavaScript. If disabled, the navigation index will
|
||||
# consists of multiple levels of tabs that are statically embedded in every HTML
|
||||
# page. Disable this option to support browsers that do not have Javascript,
|
||||
# page. Disable this option to support browsers that do not have JavaScript,
|
||||
# like the Qt help browser.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
@ -1275,10 +1344,11 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
|
||||
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
||||
# that directory and running make install will install the docset in
|
||||
# environment (see:
|
||||
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
|
||||
# create a documentation set, doxygen will generate a Makefile in the HTML
|
||||
# output directory. Running make will produce the docset in that directory and
|
||||
# running make install will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
||||
# genXcode/_index.html for more information.
|
||||
@ -1295,6 +1365,13 @@ GENERATE_DOCSET = NO
|
||||
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
|
||||
# This tag determines the URL of the docset feed. A documentation feed provides
|
||||
# an umbrella under which multiple documentation sets from a single provider
|
||||
# (such as a company or product suite) can be grouped.
|
||||
# This tag requires that the tag GENERATE_DOCSET is set to YES.
|
||||
|
||||
DOCSET_FEEDURL =
|
||||
|
||||
# This tag specifies a string that should uniquely identify the documentation
|
||||
# set bundle. This should be a reverse domain-name style string, e.g.
|
||||
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
|
||||
@ -1320,8 +1397,12 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# Windows.
|
||||
# on Windows. In the beginning of 2021 Microsoft took the original page, with
|
||||
# a.o. the download links, offline the HTML help workshop was already many years
|
||||
# in maintenance mode). You can download the HTML help workshop from the web
|
||||
# archives at Installation executable (see:
|
||||
# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
|
||||
# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
|
||||
#
|
||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
|
||||
@ -1351,7 +1432,7 @@ CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
|
||||
# The GENERATE_CHI flag controls if a separate .chi index file is generated
|
||||
# (YES) or that it should be included in the master .chm file (NO).
|
||||
# (YES) or that it should be included in the main .chm file (NO).
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
||||
|
||||
@ -1396,7 +1477,8 @@ QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||
# Project output. For more information please see Qt Help Project / Namespace
|
||||
# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@ -1404,8 +1486,8 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
||||
# folders).
|
||||
# Folders (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@ -1413,30 +1495,30 @@ QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
||||
# project's filter section matches. Qt Help Project / Filter Attributes (see:
|
||||
# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
|
||||
# The QHG_LOCATION tag can be used to specify the location of Qt's
|
||||
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
|
||||
# generated .qhp file.
|
||||
# The QHG_LOCATION tag can be used to specify the location (absolute path
|
||||
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
|
||||
# run qhelpgenerator on the generated .qhp file.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHG_LOCATION =
|
||||
@ -1479,16 +1561,28 @@ DISABLE_INDEX = NO
|
||||
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
|
||||
# (i.e. any modern browser). Windows users are probably better off using the
|
||||
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
|
||||
# further fine-tune the look of the index. As an example, the default style
|
||||
# sheet generated by doxygen has an example that shows how to put an image at
|
||||
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
|
||||
# the same information as the tab index, you could consider setting
|
||||
# DISABLE_INDEX to YES when enabling this option.
|
||||
# further fine tune the look of the index (see "Fine-tuning the output"). As an
|
||||
# example, the default style sheet generated by doxygen has an example that
|
||||
# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
|
||||
# Since the tree basically has the same information as the tab index, you could
|
||||
# consider setting DISABLE_INDEX to YES when enabling this option.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
GENERATE_TREEVIEW = YES
|
||||
|
||||
# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
|
||||
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
|
||||
# area (value NO) or if it should extend to the full height of the window (value
|
||||
# YES). Setting this to YES gives a layout similar to
|
||||
# https://docs.readthedocs.io with more room for contents, but less room for the
|
||||
# project logo, title, and description. If either GENERATE_TREEVIEW or
|
||||
# DISABLE_INDEX is set to NO, this option has no effect.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
FULL_SIDEBAR = NO
|
||||
|
||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||
# doxygen will group on one line in the generated HTML documentation.
|
||||
#
|
||||
@ -1513,6 +1607,24 @@ TREEVIEW_WIDTH = 250
|
||||
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
|
||||
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
|
||||
# addresses.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
OBFUSCATE_EMAILS = YES
|
||||
|
||||
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
|
||||
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
|
||||
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
|
||||
# the HTML output. These images will generally look nicer at scaled resolutions.
|
||||
# Possible values are: png (the default) and svg (looks nicer but requires the
|
||||
# pdf2svg or inkscape tool).
|
||||
# The default value is: png.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_FORMULA_FORMAT = png
|
||||
|
||||
# Use this tag to change the font size of LaTeX formulas included as images in
|
||||
# the HTML documentation. When you change the font size after a successful
|
||||
# doxygen run you need to manually remove any form_*.png images from the HTML
|
||||
@ -1533,8 +1645,14 @@ FORMULA_FONTSIZE = 10
|
||||
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||
# the section "Including formulas" for details.
|
||||
|
||||
FORMULA_MACROFILE =
|
||||
|
||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
|
||||
# https://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# https://www.mathjax.org) which uses client side JavaScript for the rendering
|
||||
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
|
||||
# installed or if you want to formulas look prettier in the HTML output. When
|
||||
# enabled you may also need to install MathJax separately and configure the path
|
||||
@ -1544,11 +1662,29 @@ FORMULA_TRANSPARENT = YES
|
||||
|
||||
USE_MATHJAX = YES
|
||||
|
||||
# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
|
||||
# Note that the different versions of MathJax have different requirements with
|
||||
# regards to the different settings, so it is possible that also other MathJax
|
||||
# settings have to be changed when switching between the different MathJax
|
||||
# versions.
|
||||
# Possible values are: MathJax_2 and MathJax_3.
|
||||
# The default value is: MathJax_2.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_VERSION = MathJax_2
|
||||
|
||||
# When MathJax is enabled you can set the default output format to be used for
|
||||
# the MathJax output. See the MathJax site (see:
|
||||
# http://docs.mathjax.org/en/latest/output.html) for more details.
|
||||
# the MathJax output. For more details about the output format see MathJax
|
||||
# version 2 (see:
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
|
||||
# (see:
|
||||
# http://docs.mathjax.org/en/latest/web/components/output.html).
|
||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||
# compatibility), NativeMML (i.e. MathML) and SVG.
|
||||
# compatibility. This is the name for Mathjax version 2, for MathJax version 3
|
||||
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
|
||||
# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
|
||||
# is the name for Mathjax version 3, for MathJax version 2 this will be
|
||||
# translated into HTML-CSS) and SVG.
|
||||
# The default value is: HTML-CSS.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@ -1561,22 +1697,29 @@ MATHJAX_FORMAT = HTML-CSS
|
||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
|
||||
# Content Delivery Network so you can quickly see the result without installing
|
||||
# MathJax. However, it is strongly recommended to install a local copy of
|
||||
# MathJax from https://www.mathjax.org before deployment.
|
||||
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
|
||||
# MathJax from https://www.mathjax.org before deployment. The default value is:
|
||||
# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
|
||||
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||
# extension names that should be enabled during MathJax rendering. For example
|
||||
# for MathJax version 2 (see
|
||||
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
|
||||
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
||||
# For example for MathJax version 3 (see
|
||||
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
||||
# MATHJAX_EXTENSIONS = ams
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_EXTENSIONS =
|
||||
|
||||
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
||||
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
|
||||
# (see:
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
|
||||
# example see the documentation.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@ -1604,7 +1747,7 @@ MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
|
||||
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
||||
# implemented using a web server instead of a web client using Javascript. There
|
||||
# implemented using a web server instead of a web client using JavaScript. There
|
||||
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
|
||||
# setting. When disabled, doxygen will generate a PHP script for searching and
|
||||
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
|
||||
@ -1623,7 +1766,8 @@ SERVER_BASED_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/).
|
||||
# Xapian (see:
|
||||
# https://xapian.org/).
|
||||
#
|
||||
# See the section "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
@ -1636,8 +1780,9 @@ EXTERNAL_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
||||
# Searching" for details.
|
||||
# Xapian (see:
|
||||
# https://xapian.org/). See the section "External Indexing and Searching" for
|
||||
# details.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
SEARCHENGINE_URL =
|
||||
@ -1708,10 +1853,11 @@ LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
|
||||
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
|
||||
# generate index for LaTeX.
|
||||
# generate index for LaTeX. In case there is no backslash (\) as first character
|
||||
# it will be automatically added in the LaTeX code.
|
||||
# Note: This tag is used in the generated output file (.tex).
|
||||
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
|
||||
# The default value is: \makeindex.
|
||||
# The default value is: makeindex.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_MAKEINDEX_CMD = \makeindex
|
||||
@ -1745,29 +1891,31 @@ PAPER_TYPE = a4
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
|
||||
# generated LaTeX document. The header should contain everything until the first
|
||||
# chapter. If it is left blank doxygen will generate a standard header. See
|
||||
# section "Doxygen usage" for information on how to let doxygen write the
|
||||
# default header to a separate file.
|
||||
# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
|
||||
# the generated LaTeX document. The header should contain everything until the
|
||||
# first chapter. If it is left blank doxygen will generate a standard header. It
|
||||
# is highly recommended to start with a default header using
|
||||
# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
|
||||
# and then modify the file new_header.tex. See also section "Doxygen usage" for
|
||||
# information on how to generate the default header that doxygen normally uses.
|
||||
#
|
||||
# Note: Only use a user-defined header if you know what you are doing! The
|
||||
# following commands have a special meaning inside the header: $title,
|
||||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
|
||||
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
|
||||
# string, for the replacement values of the other commands the user is referred
|
||||
# to HTML_HEADER.
|
||||
# Note: Only use a user-defined header if you know what you are doing!
|
||||
# Note: The header is subject to change so you typically have to regenerate the
|
||||
# default header when upgrading to a newer version of doxygen. The following
|
||||
# commands have a special meaning inside the header (and footer): For a
|
||||
# description of the possible markers and block names see the documentation.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
|
||||
# generated LaTeX document. The footer should contain everything after the last
|
||||
# chapter. If it is left blank doxygen will generate a standard footer. See
|
||||
# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
|
||||
# the generated LaTeX document. The footer should contain everything after the
|
||||
# last chapter. If it is left blank doxygen will generate a standard footer. See
|
||||
# LATEX_HEADER for more information on how to generate a default footer and what
|
||||
# special commands can be used inside the footer.
|
||||
#
|
||||
# Note: Only use a user-defined footer if you know what you are doing!
|
||||
# special commands can be used inside the footer. See also section "Doxygen
|
||||
# usage" for information on how to generate the default footer that doxygen
|
||||
# normally uses. Note: Only use a user-defined footer if you know what you are
|
||||
# doing!
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_FOOTER =
|
||||
@ -1800,9 +1948,11 @@ LATEX_EXTRA_FILES =
|
||||
|
||||
PDF_HYPERLINKS = YES
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
|
||||
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
|
||||
# higher quality PDF documentation.
|
||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
|
||||
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
|
||||
# files. Set this option to YES, to get a higher quality PDF documentation.
|
||||
#
|
||||
# See also section LATEX_CMD_NAME for selecting the engine.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@ -1810,8 +1960,7 @@ USE_PDFLATEX = YES
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||
# if errors occur, instead of asking the user for help. This option is also used
|
||||
# when generating formulas in HTML.
|
||||
# if errors occur, instead of asking the user for help.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@ -1824,16 +1973,6 @@ LATEX_BATCHMODE = NO
|
||||
|
||||
LATEX_HIDE_INDICES = NO
|
||||
|
||||
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
|
||||
# code with syntax highlighting in the LaTeX output.
|
||||
#
|
||||
# Note that which sources are shown also depends on other settings such as
|
||||
# SOURCE_BROWSER.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_SOURCE_CODE = NO
|
||||
|
||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
||||
# bibliography, e.g. plainnat, or ieeetr. See
|
||||
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
@ -1914,16 +2053,6 @@ RTF_STYLESHEET_FILE =
|
||||
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
|
||||
# with syntax highlighting in the RTF output.
|
||||
#
|
||||
# Note that which sources are shown also depends on other settings such as
|
||||
# SOURCE_BROWSER.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_RTF is set to YES.
|
||||
|
||||
RTF_SOURCE_CODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
@ -2020,15 +2149,6 @@ GENERATE_DOCBOOK = NO
|
||||
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
|
||||
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
|
||||
# program listings (including syntax highlighting and cross-referencing
|
||||
# information) to the DOCBOOK output. Note that enabling this will significantly
|
||||
# increase the size of the DOCBOOK output.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
|
||||
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
@ -2203,34 +2323,10 @@ EXTERNAL_GROUPS = YES
|
||||
|
||||
EXTERNAL_PAGES = YES
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of 'which perl').
|
||||
# The default file (with absolute path) is: /usr/bin/perl.
|
||||
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
|
||||
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
|
||||
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
|
||||
# disabled, but it is recommended to install and use dot, since it yields more
|
||||
# powerful graphs.
|
||||
# The default value is: YES.
|
||||
|
||||
CLASS_DIAGRAMS = NO
|
||||
|
||||
# You can define message sequence charts within doxygen comments using the \msc
|
||||
# command. Doxygen will then run the mscgen tool (see:
|
||||
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
|
||||
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
|
||||
# the mscgen tool resides. If left empty the tool is assumed to be found in the
|
||||
# default search path.
|
||||
|
||||
MSCGEN_PATH =
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
@ -2287,11 +2383,14 @@ DOT_FONTSIZE = 10
|
||||
|
||||
DOT_FONTPATH =
|
||||
|
||||
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
|
||||
# each documented class showing the direct and indirect inheritance relations.
|
||||
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
|
||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect inheritance
|
||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||
# links.
|
||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
@ -2328,10 +2427,32 @@ UML_LOOK = YES
|
||||
# but if the number exceeds 15, the total amount of fields shown is limited to
|
||||
# 10.
|
||||
# Minimum value: 0, maximum value: 100, default value: 10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
|
||||
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
|
||||
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
|
||||
# tag is set to YES, doxygen will add type and arguments for attributes and
|
||||
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
|
||||
# will not generate fields with class member information in the UML graphs. The
|
||||
# class diagrams will look similar to the default class diagrams but using UML
|
||||
# notation for the relationships.
|
||||
# Possible values are: NO, YES and NONE.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
DOT_UML_DETAILS = NO
|
||||
|
||||
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
|
||||
# to display on a single line. If the actual line length exceeds this threshold
|
||||
# significantly it will wrapped across multiple lines. Some heuristics are apply
|
||||
# to avoid ugly line breaks.
|
||||
# Minimum value: 0, maximum value: 1000, default value: 17.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
|
||||
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
|
||||
# collaboration graphs will show the relations between templates and their
|
||||
# instances.
|
||||
@ -2398,6 +2519,13 @@ GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
DIRECTORY_GRAPH = YES
|
||||
|
||||
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
|
||||
# of child directories generated in directory dependency graphs by dot.
|
||||
# Minimum value: 1, maximum value: 25, default value: 1.
|
||||
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
|
||||
|
||||
DIR_GRAPH_MAX_DEPTH = 1
|
||||
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. For an explanation of the image formats see the section
|
||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||
@ -2451,10 +2579,10 @@ MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
|
||||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
|
||||
# path where java can find the plantuml.jar file. If left blank, it is assumed
|
||||
# PlantUML is not used or called during a preprocessing step. Doxygen will
|
||||
# generate a warning when it encounters a \startuml command in this case and
|
||||
# will not generate output for the diagram.
|
||||
# path where java can find the plantuml.jar file or to the filename of jar file
|
||||
# to be used. If left blank, it is assumed PlantUML is not used or called during
|
||||
# a preprocessing step. Doxygen will generate a warning when it encounters a
|
||||
# \startuml command in this case and will not generate output for the diagram.
|
||||
|
||||
PLANTUML_JAR_PATH =
|
||||
|
||||
@ -2516,14 +2644,18 @@ DOT_MULTI_TARGETS = YES
|
||||
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
|
||||
# explaining the meaning of the various boxes and arrows in the dot generated
|
||||
# graphs.
|
||||
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
|
||||
# graphical representation for inheritance and collaboration diagrams is used.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
|
||||
# files that are used to generate the various graphs.
|
||||
#
|
||||
# Note: This setting is not only used for dot files but also for msc temporary
|
||||
# files.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
@ -1,4 +1,5 @@
|
||||
includes:
|
||||
- tests/phpstan/analyse-for-current-php-version.neon.php
|
||||
- tests/phpstan/configs/actual-problems.neon
|
||||
- tests/phpstan/configs/gc-hacks.neon
|
||||
- tests/phpstan/configs/impossible-generics.neon
|
||||
|
@ -119,8 +119,6 @@ chunk-sending:
|
||||
spawn-radius: 4
|
||||
|
||||
chunk-ticking:
|
||||
#Max amount of chunks processed each tick
|
||||
per-tick: 40
|
||||
#Radius of chunks around a player to tick
|
||||
tick-radius: 3
|
||||
#Number of blocks inside ticking areas' subchunks that get ticked every tick. Higher values will accelerate events
|
||||
@ -128,7 +126,9 @@ chunk-ticking:
|
||||
blocks-per-subchunk-per-tick: 3
|
||||
#IDs of blocks not to perform random ticking on.
|
||||
disable-block-ticking:
|
||||
#- 2 # grass
|
||||
#- grass
|
||||
#- ice
|
||||
#- fire
|
||||
|
||||
chunk-generation:
|
||||
#Max. amount of chunks in the waiting queue to be populated
|
||||
@ -166,15 +166,45 @@ timings:
|
||||
host: timings.pmmp.io
|
||||
|
||||
console:
|
||||
#Whether to accept commands via the console. If disabled, anything typed on the console will be ignored.
|
||||
#Useful to save resources on headless servers where the console is never used (e.g. hosted server, Docker, etc.)
|
||||
enable-input: true
|
||||
#Choose whether to enable server stats reporting on the console title.
|
||||
#NOTE: The title ticker will be disabled regardless if console colours are not enabled.
|
||||
title-tick: true
|
||||
|
||||
aliases:
|
||||
#Examples:
|
||||
#showtheversion: version
|
||||
##This section allows you to add, remove or remap command aliases.
|
||||
##A single alias can call one or more other commands (or aliases).
|
||||
##Aliases defined here will override any command aliases declared by plugins or PocketMine-MP itself.
|
||||
|
||||
##To remove an alias, set it to [], like so (note that prefixed aliases like "pocketmine:stop" will remain and can't
|
||||
##be removed):
|
||||
#stop: []
|
||||
|
||||
##Commands are not removed, only their aliases. You can still refer to a command using its full (prefixed)
|
||||
##name, even if all its aliases are overwritten. The full name is usually something like "pocketmine:commandname" or
|
||||
##"pluginname:commandname".
|
||||
#abort: [pocketmine:stop]
|
||||
|
||||
##To add an alias, list the command(s) that it calls:
|
||||
#showtheversion: [version]
|
||||
#savestop: [save-all, stop]
|
||||
|
||||
##To invoke another command with arguments, use $1 to pass the first argument, $2 for the second etc:
|
||||
#giveadmin: [op $1] ## `giveadmin alex` -> `op alex`
|
||||
#kill: [suicide, say "I tried to kill $1"] ## `kill alex` -> `suicide` + `say "I tried to kill alex"`
|
||||
#giverandom: [give $1 $2, say "Someone has just received a $2!"] ## `giverandom alex diamond` -> `give alex diamond` + `say "Someone has just received a diamond!"`
|
||||
|
||||
##To make arguments mandatory (so that the command fails if they are not provided), use $$, e.g. $$1, $$2:
|
||||
#makeadmin: [op $$1] ## `makeadmin alex` -> `op alex`, `makeadmin` with no arguments = error
|
||||
|
||||
##To pass through a range of arguments, put a - (hyphen) after the index:
|
||||
#tpalias: [tp $1-] ## `tpalias 256 70 256` -> `tp 256 70 256` - this passes arguments 1 and everything after it to the `tp` command
|
||||
|
||||
##To change an existing command alias and make it do something else:
|
||||
#tp: [suicide]
|
||||
|
||||
worlds:
|
||||
#These settings will override the generator set in server.properties and allows loading multiple worlds
|
||||
#Example:
|
||||
|
@ -10,3 +10,4 @@ resource_stack:
|
||||
# - natural.zip
|
||||
# - vanilla.zip
|
||||
#If you want to force clients to use vanilla resources, you must place a vanilla resource pack in your resources folder and add it to the stack here.
|
||||
#To specify a resource encryption key, put the key in the <resource>.key file alongside the resource pack. Example: vanilla.zip.key
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -28,10 +28,9 @@ use pocketmine\network\mcpe\cache\ChunkCache;
|
||||
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use Webmozart\PathUtil\Path;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function arsort;
|
||||
use function count;
|
||||
use function fclose;
|
||||
@ -65,12 +64,14 @@ use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
class MemoryManager{
|
||||
|
||||
private Server $server;
|
||||
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
|
||||
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
|
||||
private const DEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private int $memoryLimit;
|
||||
private int $globalMemoryLimit;
|
||||
@ -98,8 +99,9 @@ class MemoryManager{
|
||||
|
||||
private \Logger $logger;
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->server = $server;
|
||||
public function __construct(
|
||||
private Server $server
|
||||
){
|
||||
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
|
||||
|
||||
$this->init($server->getConfigGroup());
|
||||
@ -115,20 +117,12 @@ class MemoryManager{
|
||||
if($m <= 0){
|
||||
$defaultMemory = 0;
|
||||
}else{
|
||||
switch(mb_strtoupper($matches[2])){
|
||||
case "K":
|
||||
$defaultMemory = intdiv($m, 1024);
|
||||
break;
|
||||
case "M":
|
||||
$defaultMemory = $m;
|
||||
break;
|
||||
case "G":
|
||||
$defaultMemory = $m * 1024;
|
||||
break;
|
||||
default:
|
||||
$defaultMemory = $m;
|
||||
break;
|
||||
}
|
||||
$defaultMemory = match(mb_strtoupper($matches[2])){
|
||||
"K" => intdiv($m, 1024),
|
||||
"M" => $m,
|
||||
"G" => $m * 1024,
|
||||
default => $m,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,11 +135,11 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
|
||||
$this->checkRate = $config->getPropertyInt("memory.check-rate", 20);
|
||||
$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", 30);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", 36000);
|
||||
$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);
|
||||
|
||||
@ -168,14 +162,14 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
public function canUseChunkCache() : bool{
|
||||
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
||||
return !$this->lowMemory || !$this->lowMemDisableChunkCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the allowed chunk radius based on the current memory usage.
|
||||
*/
|
||||
public function getViewDistance(int $distance) : int{
|
||||
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||
return ($this->lowMemory && $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,18 +208,18 @@ class MemoryManager{
|
||||
public function check() : void{
|
||||
Timings::$memoryManager->startTiming();
|
||||
|
||||
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
|
||||
if(($this->memoryLimit > 0 || $this->globalMemoryLimit > 0) && ++$this->checkTicker >= $this->checkRate){
|
||||
$this->checkTicker = 0;
|
||||
$memory = Process::getAdvancedMemoryUsage();
|
||||
$trigger = false;
|
||||
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
|
||||
if($this->memoryLimit > 0 && $memory[0] > $this->memoryLimit){
|
||||
$trigger = 0;
|
||||
}elseif($this->globalMemoryLimit > 0 and $memory[1] > $this->globalMemoryLimit){
|
||||
}elseif($this->globalMemoryLimit > 0 && $memory[1] > $this->globalMemoryLimit){
|
||||
$trigger = 1;
|
||||
}
|
||||
|
||||
if($trigger !== false){
|
||||
if($this->lowMemory and $this->continuousTrigger){
|
||||
if($this->lowMemory && $this->continuousTrigger){
|
||||
if(++$this->continuousTriggerTicker >= $this->continuousTriggerRate){
|
||||
$this->continuousTriggerTicker = 0;
|
||||
$this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0, ++$this->continuousTriggerCount);
|
||||
@ -240,7 +234,7 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
if($this->garbageCollectionPeriod > 0 and ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
|
||||
if($this->garbageCollectionPeriod > 0 && ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
|
||||
$this->garbageCollectionTicker = 0;
|
||||
$this->triggerGarbageCollector();
|
||||
}
|
||||
@ -288,11 +282,10 @@ class MemoryManager{
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
*
|
||||
* @param mixed $startingObject
|
||||
* @param mixed $startingObject
|
||||
*/
|
||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
$hardLimit = ini_get('memory_limit');
|
||||
if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist");
|
||||
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
|
||||
@ -300,7 +293,7 @@ class MemoryManager{
|
||||
mkdir($outputFolder, 0777, true);
|
||||
}
|
||||
|
||||
$obData = fopen(Path::join($outputFolder, "objects.js"), "wb+");
|
||||
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
|
||||
|
||||
$objects = [];
|
||||
|
||||
@ -318,7 +311,7 @@ class MemoryManager{
|
||||
$reflection = new \ReflectionClass($className);
|
||||
$staticProperties[$className] = [];
|
||||
foreach($reflection->getProperties() as $property){
|
||||
if(!$property->isStatic() or $property->getDeclaringClass()->getName() !== $className){
|
||||
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -352,7 +345,7 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $staticCount static properties");
|
||||
|
||||
$globalVariables = [];
|
||||
@ -379,7 +372,7 @@ class MemoryManager{
|
||||
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $globalCount global variables");
|
||||
|
||||
foreach(get_defined_functions()["user"] as $function){
|
||||
@ -394,14 +387,14 @@ class MemoryManager{
|
||||
$functionStaticVarsCount += count($vars);
|
||||
}
|
||||
}
|
||||
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $functionStaticVarsCount function static variables");
|
||||
|
||||
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
|
||||
do{
|
||||
$continue = false;
|
||||
foreach($objects as $hash => $object){
|
||||
foreach(Utils::stringifyKeys($objects) as $hash => $object){
|
||||
if(!is_object($object)){
|
||||
continue;
|
||||
}
|
||||
@ -460,7 +453,7 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
||||
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
|
||||
}
|
||||
|
||||
}while($continue);
|
||||
@ -469,11 +462,11 @@ class MemoryManager{
|
||||
|
||||
fclose($obData);
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
$logger->info("Finished!");
|
||||
|
||||
@ -483,9 +476,14 @@ class MemoryManager{
|
||||
|
||||
/**
|
||||
* @param mixed $from
|
||||
* @param object[] $objects reference parameter
|
||||
* @param object[] $objects reference parameter
|
||||
* @param int[] $refCounts reference parameter
|
||||
*
|
||||
* @phpstan-param array<string, object> $objects
|
||||
* @phpstan-param array<string, int> $refCounts
|
||||
* @phpstan-param-out array<string, object> $objects
|
||||
* @phpstan-param-out array<string, int> $refCounts
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||
@ -509,8 +507,13 @@ class MemoryManager{
|
||||
return "(error) ARRAY RECURSION LIMIT REACHED";
|
||||
}
|
||||
$data = [];
|
||||
$numeric = 0;
|
||||
foreach($from as $key => $value){
|
||||
$data[$key] = self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||
$data[$numeric] = [
|
||||
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
];
|
||||
$numeric++;
|
||||
}
|
||||
}elseif(is_string($from)){
|
||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
|
@ -32,15 +32,21 @@ namespace pocketmine {
|
||||
use pocketmine\utils\ServerKiller;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\Timezone;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
use Webmozart\PathUtil\Path;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function defined;
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function getcwd;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function phpversion;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function strpos;
|
||||
use function realpath;
|
||||
use function version_compare;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
@ -112,18 +118,16 @@ namespace pocketmine {
|
||||
}
|
||||
}
|
||||
|
||||
if(extension_loaded("pthreads")){
|
||||
$pthreads_version = phpversion("pthreads");
|
||||
if(($pthreads_version = phpversion("pthreads")) !== false){
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") > 0){
|
||||
if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") >= 0){
|
||||
$messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version.";
|
||||
}
|
||||
}
|
||||
|
||||
if(extension_loaded("leveldb")){
|
||||
$leveldb_version = phpversion("leveldb");
|
||||
if(($leveldb_version = phpversion("leveldb")) !== false){
|
||||
if(version_compare($leveldb_version, "0.2.1") < 0){
|
||||
$messages[] = "php-leveldb >= 0.2.1 is required, while you have $leveldb_version.";
|
||||
}
|
||||
@ -160,7 +164,7 @@ namespace pocketmine {
|
||||
if(PHP_DEBUG !== 0){
|
||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||
}
|
||||
if(extension_loaded("xdebug")){
|
||||
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
||||
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
|
||||
}
|
||||
if(((int) ini_get('zend.assertions')) !== -1){
|
||||
@ -176,10 +180,10 @@ namespace pocketmine {
|
||||
|
||||
|
||||
--------------------------------------- ! WARNING ! ---------------------------------------
|
||||
You're using PHP 8.0 with JIT enabled. This provides significant performance improvements.
|
||||
You're using PHP with JIT enabled. This provides significant performance improvements.
|
||||
HOWEVER, it is EXPERIMENTAL, and has already been seen to cause weird and unexpected bugs.
|
||||
Proceed with caution.
|
||||
If you want to report any bugs, make sure to mention that you are using PHP 8.0 with JIT.
|
||||
If you want to report any bugs, make sure to mention that you have enabled PHP JIT.
|
||||
To turn off JIT, change `opcache.jit` to `0` in your php.ini file.
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
@ -200,6 +204,22 @@ JIT_WARNING
|
||||
ini_set('assert.exception', '1');
|
||||
}
|
||||
|
||||
function getopt_string(string $opt) : ?string{
|
||||
$opts = getopt("", ["$opt:"]);
|
||||
if(isset($opts[$opt])){
|
||||
if(is_string($opts[$opt])){
|
||||
return $opts[$opt];
|
||||
}
|
||||
if(is_array($opts[$opt])){
|
||||
critical_error("Cannot specify --$opt multiple times");
|
||||
}else{
|
||||
critical_error("Missing value for --$opt");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
@ -251,26 +271,42 @@ JIT_WARNING
|
||||
|
||||
ErrorToExceptionHandler::set();
|
||||
|
||||
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
|
||||
|
||||
$dataPath = isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR;
|
||||
$pluginPath = isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR;
|
||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||
$dataPath = getopt_string("data") ?? $cwd;
|
||||
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
||||
|
||||
if(!file_exists($dataPath)){
|
||||
mkdir($dataPath, 0777, true);
|
||||
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
||||
critical_error("Unable to create/access data directory at $dataPath. Check that the target location is accessible by the current user.");
|
||||
exit(1);
|
||||
}
|
||||
//this has to be done after we're sure the data path exists
|
||||
$dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$lockFilePath = Path::join($dataPath, 'server.lock');
|
||||
if(($pid = Filesystem::createLockFile($lockFilePath)) !== null){
|
||||
try{
|
||||
$pid = Filesystem::createLockFile($lockFilePath);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
critical_error($e->getMessage());
|
||||
critical_error("Please ensure that there is enough space on the disk and that the current user has read/write permissions to the selected data directory $dataPath.");
|
||||
exit(1);
|
||||
}
|
||||
if($pid !== null){
|
||||
critical_error("Another " . VersionInfo::NAME . " instance (PID $pid) is already using this folder (" . realpath($dataPath) . ").");
|
||||
critical_error("Please stop the other server first before running a new one.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!@mkdir($pluginPath, 0777, true) && !is_dir($pluginPath)){
|
||||
critical_error("Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
|
||||
exit(1);
|
||||
}
|
||||
$pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
|
||||
|
||||
//Logger has a dependency on timezone
|
||||
Timezone::init();
|
||||
|
||||
$opts = getopt("", ["no-wizard", "enable-ansi", "disable-ansi"]);
|
||||
if(isset($opts["enable-ansi"])){
|
||||
Terminal::init(true);
|
||||
}elseif(isset($opts["disable-ansi"])){
|
||||
@ -286,7 +322,7 @@ JIT_WARNING
|
||||
|
||||
$exitCode = 0;
|
||||
do{
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) and !isset($opts["no-wizard"])){
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts["no-wizard"])){
|
||||
$installer = new SetupWizard($dataPath);
|
||||
if(!$installer->run()){
|
||||
$exitCode = -1;
|
||||
|
433
src/Server.php
433
src/Server.php
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -31,12 +31,11 @@ use pocketmine\command\Command;
|
||||
use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\SimpleCommandMap;
|
||||
use pocketmine\console\ConsoleCommandSender;
|
||||
use pocketmine\console\ConsoleReaderThread;
|
||||
use pocketmine\console\ConsoleReaderChildProcessDaemon;
|
||||
use pocketmine\crafting\CraftingManager;
|
||||
use pocketmine\crafting\CraftingManagerFromDataHelper;
|
||||
use pocketmine\crash\CrashDump;
|
||||
use pocketmine\crash\CrashDumpRenderer;
|
||||
use pocketmine\data\java\GameModeIdMap;
|
||||
use pocketmine\entity\EntityDataHelper;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\HandlerListManager;
|
||||
@ -50,10 +49,7 @@ use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\lang\Language;
|
||||
use pocketmine\lang\LanguageNotFoundException;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\nbt\BigEndianNbtSerializer;
|
||||
use pocketmine\nbt\NbtDataException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
||||
use pocketmine\network\mcpe\compression\Compressor;
|
||||
@ -73,9 +69,13 @@ use pocketmine\network\query\QueryInfo;
|
||||
use pocketmine\network\upnp\UPnPNetworkInterface;
|
||||
use pocketmine\permission\BanList;
|
||||
use pocketmine\permission\DefaultPermissions;
|
||||
use pocketmine\player\DatFilePlayerDataProvider;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\OfflinePlayer;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\player\PlayerDataLoadException;
|
||||
use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\Plugin;
|
||||
@ -89,12 +89,12 @@ use pocketmine\promise\PromiseResolver;
|
||||
use pocketmine\resourcepacks\ResourcePackManager;
|
||||
use pocketmine\scheduler\AsyncPool;
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\snooze\SleeperNotifier;
|
||||
use pocketmine\stats\SendUsageTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\updater\UpdateChecker;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\BroadcastLoggerForwarder;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Internet;
|
||||
@ -106,17 +106,18 @@ use pocketmine\utils\SignalHandler;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\WorldProviderManager;
|
||||
use pocketmine\world\format\io\WritableWorldProviderManagerEntry;
|
||||
use pocketmine\world\generator\Generator;
|
||||
use pocketmine\world\generator\GeneratorManager;
|
||||
use pocketmine\world\generator\InvalidGeneratorOptionsException;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\world\WorldCreationOptions;
|
||||
use pocketmine\world\WorldManager;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Webmozart\PathUtil\Path;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_fill;
|
||||
use function array_sum;
|
||||
use function base64_encode;
|
||||
use function cli_set_process_title;
|
||||
@ -125,7 +126,6 @@ use function count;
|
||||
use function date;
|
||||
use function fclose;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function fopen;
|
||||
@ -133,6 +133,8 @@ use function get_class;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
@ -160,13 +162,9 @@ use function time;
|
||||
use function touch;
|
||||
use function trim;
|
||||
use function yaml_parse;
|
||||
use function zlib_decode;
|
||||
use function zlib_encode;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
use const PHP_INT_MAX;
|
||||
use const PTHREADS_INHERIT_NONE;
|
||||
use const ZLIB_ENCODING_GZIP;
|
||||
|
||||
/**
|
||||
* The class that manages everything
|
||||
@ -178,9 +176,36 @@ class Server{
|
||||
public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
|
||||
public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
|
||||
|
||||
public const DEFAULT_SERVER_NAME = VersionInfo::NAME . " Server";
|
||||
public const DEFAULT_MAX_PLAYERS = 20;
|
||||
public const DEFAULT_PORT_IPV4 = 19132;
|
||||
public const DEFAULT_PORT_IPV6 = 19133;
|
||||
public const DEFAULT_MAX_VIEW_DISTANCE = 16;
|
||||
|
||||
/**
|
||||
* Worlds, network, commands and most other things are polled this many times per second on average.
|
||||
* Between ticks, the server will sleep to ensure that the average tick rate is maintained.
|
||||
* It may wake up between ticks if a Snooze notification source is triggered (e.g. to process network packets).
|
||||
*/
|
||||
public const TARGET_TICKS_PER_SECOND = 20;
|
||||
/**
|
||||
* The average time between ticks, in seconds.
|
||||
*/
|
||||
public const TARGET_SECONDS_PER_TICK = 1 / self::TARGET_TICKS_PER_SECOND;
|
||||
public const TARGET_NANOSECONDS_PER_TICK = 1_000_000_000 / self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
/**
|
||||
* The TPS threshold below which the server will generate log warnings.
|
||||
*/
|
||||
private const TPS_OVERLOAD_WARNING_THRESHOLD = self::TARGET_TICKS_PER_SECOND * 0.6;
|
||||
|
||||
private const TICKS_PER_WORLD_CACHE_CLEAR = 5 * self::TARGET_TICKS_PER_SECOND;
|
||||
private const TICKS_PER_TPS_OVERLOAD_WARNING = 5 * self::TARGET_TICKS_PER_SECOND;
|
||||
private const TICKS_PER_STATS_REPORT = 300 * self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private static ?Server $instance = null;
|
||||
|
||||
private SleeperHandler $tickSleeper;
|
||||
private TimeTrackingSleeperHandler $tickSleeper;
|
||||
|
||||
private BanList $banByName;
|
||||
|
||||
@ -196,7 +221,7 @@ class Server{
|
||||
|
||||
private PluginManager $pluginManager;
|
||||
|
||||
private float $profilingTickRate = 20;
|
||||
private float $profilingTickRate = self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private UpdateChecker $updater;
|
||||
|
||||
@ -206,10 +231,10 @@ class Server{
|
||||
private int $tickCounter = 0;
|
||||
private float $nextTick = 0;
|
||||
/** @var float[] */
|
||||
private array $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
|
||||
private array $tickAverage;
|
||||
/** @var float[] */
|
||||
private array $useAverage = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
private float $currentTPS = 20;
|
||||
private array $useAverage;
|
||||
private float $currentTPS = self::TARGET_TICKS_PER_SECOND;
|
||||
private float $currentUse = 0;
|
||||
private float $startTime;
|
||||
|
||||
@ -217,11 +242,10 @@ class Server{
|
||||
|
||||
private int $sendUsageTicker = 0;
|
||||
|
||||
private \AttachableThreadedLogger $logger;
|
||||
|
||||
private MemoryManager $memoryManager;
|
||||
|
||||
private ConsoleReaderThread $console;
|
||||
private ?ConsoleReaderChildProcessDaemon $console = null;
|
||||
private ?ConsoleCommandSender $consoleSender = null;
|
||||
|
||||
private SimpleCommandMap $commandMap;
|
||||
|
||||
@ -243,10 +267,11 @@ class Server{
|
||||
|
||||
private UuidInterface $serverID;
|
||||
|
||||
private \DynamicClassLoader $autoloader;
|
||||
private string $dataPath;
|
||||
private string $pluginPath;
|
||||
|
||||
private PlayerDataProvider $playerDataProvider;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @phpstan-var array<string, string>
|
||||
@ -324,15 +349,15 @@ class Server{
|
||||
}
|
||||
|
||||
public function getPort() : int{
|
||||
return $this->configGroup->getConfigInt("server-port", 19132);
|
||||
return $this->configGroup->getConfigInt("server-port", self::DEFAULT_PORT_IPV4);
|
||||
}
|
||||
|
||||
public function getPortV6() : int{
|
||||
return $this->configGroup->getConfigInt("server-portv6", 19133);
|
||||
return $this->configGroup->getConfigInt("server-portv6", self::DEFAULT_PORT_IPV6);
|
||||
}
|
||||
|
||||
public function getViewDistance() : int{
|
||||
return max(2, $this->configGroup->getConfigInt("view-distance", 8));
|
||||
return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_MAX_VIEW_DISTANCE));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -357,7 +382,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function getGamemode() : GameMode{
|
||||
return GameModeIdMap::getInstance()->fromId($this->configGroup->getConfigInt("gamemode", 0)) ?? GameMode::SURVIVAL();
|
||||
return GameMode::fromString($this->configGroup->getConfigString("gamemode", GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
|
||||
}
|
||||
|
||||
public function getForceGamemode() : bool{
|
||||
@ -380,7 +405,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function getMotd() : string{
|
||||
return $this->configGroup->getConfigString("motd", VersionInfo::NAME . " Server");
|
||||
return $this->configGroup->getConfigString("motd", self::DEFAULT_SERVER_NAME);
|
||||
}
|
||||
|
||||
public function getLoader() : \DynamicClassLoader{
|
||||
@ -480,49 +505,22 @@ class Server{
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getPlayerDataPath(string $username) : string{
|
||||
return Path::join($this->getDataPath(), 'players', strtolower($username) . '.dat');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server has stored any saved data for this player.
|
||||
*/
|
||||
public function hasOfflinePlayerData(string $name) : bool{
|
||||
return file_exists($this->getPlayerDataPath($name));
|
||||
}
|
||||
|
||||
private function handleCorruptedPlayerData(string $name) : void{
|
||||
$path = $this->getPlayerDataPath($name);
|
||||
rename($path, $path . '.bak');
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return $this->playerDataProvider->hasData($name);
|
||||
}
|
||||
|
||||
public function getOfflinePlayerData(string $name) : ?CompoundTag{
|
||||
return Timings::$syncPlayerDataLoad->time(function() use ($name) : ?CompoundTag{
|
||||
$name = strtolower($name);
|
||||
$path = $this->getPlayerDataPath($name);
|
||||
|
||||
if(file_exists($path)){
|
||||
$contents = @file_get_contents($path);
|
||||
if($contents === false){
|
||||
throw new \RuntimeException("Failed to read player data file \"$path\" (permission denied?)");
|
||||
}
|
||||
$decompressed = @zlib_decode($contents);
|
||||
if($decompressed === false){
|
||||
$this->logger->debug("Failed to decompress raw player data for \"$name\"");
|
||||
$this->handleCorruptedPlayerData($name);
|
||||
return null;
|
||||
}
|
||||
|
||||
try{
|
||||
return (new BigEndianNbtSerializer())->read($decompressed)->mustGetCompoundTag();
|
||||
}catch(NbtDataException $e){ //corrupt data
|
||||
$this->logger->debug("Failed to decode NBT data for \"$name\": " . $e->getMessage());
|
||||
$this->handleCorruptedPlayerData($name);
|
||||
return null;
|
||||
}
|
||||
try{
|
||||
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)));
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -536,14 +534,9 @@ class Server{
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{
|
||||
$nbt = new BigEndianNbtSerializer();
|
||||
$contents = zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP);
|
||||
if($contents === false){
|
||||
throw new AssumptionFailedError("zlib_encode() failed unexpectedly");
|
||||
}
|
||||
try{
|
||||
Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents);
|
||||
}catch(\RuntimeException | \ErrorException $e){
|
||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||
}catch(PlayerDataSaveException $e){
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
@ -559,54 +552,55 @@ class Server{
|
||||
$ev->call();
|
||||
$class = $ev->getPlayerClass();
|
||||
|
||||
if($offlinePlayerData !== null and ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString("Level", ""))) !== null){
|
||||
if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString(Player::TAG_LEVEL, ""))) !== null){
|
||||
$playerPos = EntityDataHelper::parseLocation($offlinePlayerData, $world);
|
||||
$spawn = $playerPos->asVector3();
|
||||
}else{
|
||||
$world = $this->worldManager->getDefaultWorld();
|
||||
if($world === null){
|
||||
throw new AssumptionFailedError("Default world should always be loaded");
|
||||
}
|
||||
$playerPos = null;
|
||||
$spawn = $world->getSpawnLocation();
|
||||
}
|
||||
/** @phpstan-var PromiseResolver<Player> $playerPromiseResolver */
|
||||
$playerPromiseResolver = new PromiseResolver();
|
||||
$world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion(
|
||||
function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
|
||||
if(!$session->isConnected()){
|
||||
$playerPromiseResolver->reject();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stick with the original spawn at the time of generation request, even if it changed since then.
|
||||
* This is because we know for sure that that chunk will be generated, but the one at the new location
|
||||
* might not be, and it would be much more complex to go back and redo the whole thing.
|
||||
*
|
||||
* TODO: this relies on the assumption that getSafeSpawn() will only alter the Y coordinate of the
|
||||
* provided position. If this assumption is broken, we'll start seeing crashes in here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see Player::__construct()
|
||||
* @var Player $player
|
||||
*/
|
||||
$player = new $class($this, $session, $playerInfo, $authenticated, $playerPos ?? Location::fromObject($world->getSafeSpawn($spawn), $world), $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
|
||||
}
|
||||
$playerPromiseResolver->resolve($player);
|
||||
},
|
||||
static function() use ($playerPromiseResolver, $session) : void{
|
||||
if($session->isConnected()){
|
||||
$session->disconnect("Spawn terrain generation failed");
|
||||
}
|
||||
$playerPromiseResolver->reject();
|
||||
$createPlayer = function(Location $location) use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $offlinePlayerData) : void{
|
||||
$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
|
||||
}
|
||||
);
|
||||
$playerPromiseResolver->resolve($player);
|
||||
};
|
||||
|
||||
if($playerPos === null){ //new player or no valid position due to world not being loaded
|
||||
$world->requestSafeSpawn()->onCompletion(
|
||||
function(Position $spawn) use ($createPlayer, $playerPromiseResolver, $session, $world) : void{
|
||||
if(!$session->isConnected()){
|
||||
$playerPromiseResolver->reject();
|
||||
return;
|
||||
}
|
||||
$createPlayer(Location::fromObject($spawn, $world));
|
||||
},
|
||||
function() use ($playerPromiseResolver, $session) : void{
|
||||
if($session->isConnected()){
|
||||
//TODO: this needs to be localized - this might be reached if the spawn world was unloaded while the player was logging in
|
||||
$session->disconnect("Failed to find a safe spawn location");
|
||||
}
|
||||
$playerPromiseResolver->reject();
|
||||
}
|
||||
);
|
||||
}else{ //returning player with a valid position - safe spawn not required
|
||||
$createPlayer($playerPos);
|
||||
}
|
||||
|
||||
return $playerPromiseResolver->getPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method's results are unpredictable. The string "Steve" will return the player named "SteveJobs",
|
||||
* until another player named "SteveJ" joins the server, at which point it will return that player instead. Prefer
|
||||
* filtering the results of {@link Server::getOnlinePlayers()} yourself.
|
||||
*
|
||||
* Returns an online player whose name begins with or equals the given string (case insensitive).
|
||||
* The closest match will be returned, or null if there are no online matches.
|
||||
*
|
||||
@ -719,7 +713,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function isWhitelisted(string $name) : bool{
|
||||
return !$this->hasWhitelist() or $this->operators->exists($name, true) or $this->whitelist->exists($name, true);
|
||||
return !$this->hasWhitelist() || $this->operators->exists($name, true) || $this->whitelist->exists($name, true);
|
||||
}
|
||||
|
||||
public function isOp(string $name) : bool{
|
||||
@ -763,16 +757,22 @@ class Server{
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function __construct(\DynamicClassLoader $autoloader, \AttachableThreadedLogger $logger, string $dataPath, string $pluginPath){
|
||||
public function __construct(
|
||||
private \DynamicClassLoader $autoloader,
|
||||
private \AttachableThreadedLogger $logger,
|
||||
string $dataPath,
|
||||
string $pluginPath
|
||||
){
|
||||
if(self::$instance !== null){
|
||||
throw new \LogicException("Only one server instance can exist at once");
|
||||
}
|
||||
self::$instance = $this;
|
||||
$this->startTime = microtime(true);
|
||||
$this->tickAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, self::TARGET_TICKS_PER_SECOND);
|
||||
$this->useAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, 0);
|
||||
|
||||
$this->tickSleeper = new SleeperHandler();
|
||||
$this->autoloader = $autoloader;
|
||||
$this->logger = $logger;
|
||||
Timings::init();
|
||||
$this->tickSleeper = new TimeTrackingSleeperHandler(Timings::$serverInterrupts);
|
||||
|
||||
$this->signalHandler = new SignalHandler(function() : void{
|
||||
$this->logger->info("Received signal interrupt, stopping the server");
|
||||
@ -797,7 +797,7 @@ class Server{
|
||||
$this->logger->info("Loading server configuration");
|
||||
$pocketmineYmlPath = Path::join($this->dataPath, "pocketmine.yml");
|
||||
if(!file_exists($pocketmineYmlPath)){
|
||||
$content = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml"));
|
||||
$content = Filesystem::fileGetContents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml"));
|
||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||
$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
|
||||
}
|
||||
@ -807,13 +807,13 @@ class Server{
|
||||
$this->configGroup = new ServerConfigGroup(
|
||||
new Config($pocketmineYmlPath, Config::YAML, []),
|
||||
new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [
|
||||
"motd" => VersionInfo::NAME . " Server",
|
||||
"server-port" => 19132,
|
||||
"server-portv6" => 19133,
|
||||
"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" => 20,
|
||||
"gamemode" => 0,
|
||||
"max-players" => self::DEFAULT_MAX_PLAYERS,
|
||||
"gamemode" => GameMode::SURVIVAL()->name(),
|
||||
"force-gamemode" => false,
|
||||
"hardcore" => false,
|
||||
"pvp" => true,
|
||||
@ -824,7 +824,7 @@ class Server{
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"auto-save" => true,
|
||||
"view-distance" => 8,
|
||||
"view-distance" => self::DEFAULT_MAX_VIEW_DISTANCE,
|
||||
"xbox-auth" => true,
|
||||
"language" => "eng"
|
||||
])
|
||||
@ -858,7 +858,7 @@ class Server{
|
||||
$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_error5("https://github.com/pmmp/PocketMine-MP/releases")));
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -893,7 +893,7 @@ class Server{
|
||||
}
|
||||
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6);
|
||||
if($netCompressionLevel < 1 or $netCompressionLevel > 9){
|
||||
if($netCompressionLevel < 1 || $netCompressionLevel > 9){
|
||||
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 6");
|
||||
$netCompressionLevel = 6;
|
||||
}
|
||||
@ -910,7 +910,7 @@ class Server{
|
||||
|
||||
$bannedTxt = Path::join($this->dataPath, "banned.txt");
|
||||
$bannedPlayersTxt = Path::join($this->dataPath, "banned-players.txt");
|
||||
if(file_exists($bannedTxt) and !file_exists($bannedPlayersTxt)){
|
||||
if(file_exists($bannedTxt) && !file_exists($bannedPlayersTxt)){
|
||||
@rename($bannedTxt, $bannedPlayersTxt);
|
||||
}
|
||||
@touch($bannedPlayersTxt);
|
||||
@ -921,7 +921,7 @@ class Server{
|
||||
$this->banByIP = new BanList($bannedIpsTxt);
|
||||
$this->banByIP->load();
|
||||
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", 20);
|
||||
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", self::DEFAULT_MAX_PLAYERS);
|
||||
|
||||
$this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true);
|
||||
if($this->onlineMode){
|
||||
@ -932,7 +932,7 @@ class Server{
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
if($this->configGroup->getConfigBool("hardcore", false) and $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
if($this->configGroup->getConfigBool("hardcore", false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
@ -952,9 +952,8 @@ class Server{
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
Timings::init();
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", 20);
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
DefaultPermissions::registerCorePermissions();
|
||||
|
||||
@ -970,10 +969,10 @@ class Server{
|
||||
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
|
||||
}
|
||||
try{
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(file_get_contents($graylistFile)));
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
@ -982,7 +981,7 @@ class Server{
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null and
|
||||
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null &&
|
||||
$format instanceof WritableWorldProviderManagerEntry
|
||||
){
|
||||
$providerManager->setDefault($format);
|
||||
@ -992,29 +991,47 @@ 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", 6000));
|
||||
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
|
||||
|
||||
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("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"]);
|
||||
|
||||
$this->pluginManager->loadPlugins($this->pluginPath);
|
||||
$this->enablePlugins(PluginEnableOrder::STARTUP());
|
||||
|
||||
if(!$this->startupPrepareWorlds()){
|
||||
$loadErrorCount = 0;
|
||||
$this->pluginManager->loadPlugins($this->pluginPath, $loadErrorCount);
|
||||
if($loadErrorCount > 0){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someLoadErrors()));
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
if(!$this->enablePlugins(PluginEnableOrder::STARTUP())){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->startupPrepareWorlds()){
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->enablePlugins(PluginEnableOrder::POSTWORLD())){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->enablePlugins(PluginEnableOrder::POSTWORLD());
|
||||
|
||||
if(!$this->startupPrepareNetworkInterfaces()){
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
|
||||
$this->sendUsageTicker = 6000;
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_OPEN);
|
||||
}
|
||||
|
||||
@ -1024,22 +1041,14 @@ class Server{
|
||||
$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)))));
|
||||
|
||||
//TODO: move console parts to a separate component
|
||||
$consoleSender = new ConsoleCommandSender($this, $this->language);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $consoleSender);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $consoleSender);
|
||||
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);
|
||||
|
||||
$consoleNotifier = new SleeperNotifier();
|
||||
$commandBuffer = new \Threaded();
|
||||
$this->console = new ConsoleReaderThread($commandBuffer, $consoleNotifier);
|
||||
$this->tickSleeper->addNotifier($consoleNotifier, function() use ($commandBuffer, $consoleSender) : void{
|
||||
Timings::$serverCommand->startTiming();
|
||||
while(($line = $commandBuffer->shift()) !== null){
|
||||
$this->dispatchCommand($consoleSender, (string) $line);
|
||||
}
|
||||
Timings::$serverCommand->stopTiming();
|
||||
});
|
||||
$this->console->start(PTHREADS_INHERIT_NONE);
|
||||
//TODO: move console parts to a separate component
|
||||
if($this->configGroup->getPropertyBool("console.enable-input", true)){
|
||||
$this->console = new ConsoleReaderChildProcessDaemon($this->logger);
|
||||
}
|
||||
|
||||
$this->tickProcessor();
|
||||
$this->forceShutdown();
|
||||
@ -1070,13 +1079,21 @@ class Server{
|
||||
return $generatorEntry->getGeneratorClass();
|
||||
};
|
||||
|
||||
$anyWorldFailedToLoad = false;
|
||||
|
||||
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
|
||||
if($options === null){
|
||||
$options = [];
|
||||
}elseif(!is_array($options)){
|
||||
//TODO: this probably should be an error
|
||||
continue;
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($name, true) && !$this->worldManager->isWorldGenerated($name)){
|
||||
if(!$this->worldManager->loadWorld($name, true)){
|
||||
if($this->worldManager->isWorldGenerated($name)){
|
||||
//allow checking if other worlds are loadable, so the user gets all the errors in one go
|
||||
$anyWorldFailedToLoad = true;
|
||||
continue;
|
||||
}
|
||||
$creationOptions = WorldCreationOptions::create();
|
||||
//TODO: error checking
|
||||
|
||||
@ -1085,11 +1102,13 @@ class Server{
|
||||
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $name);
|
||||
if($generatorClass === null){
|
||||
$anyWorldFailedToLoad = true;
|
||||
continue;
|
||||
}
|
||||
$creationOptions->setGeneratorClass($generatorClass);
|
||||
$creationOptions->setGeneratorOptions($generatorOptions);
|
||||
|
||||
$creationOptions->setDifficulty($this->getDifficulty());
|
||||
if(isset($options["difficulty"]) && is_string($options["difficulty"])){
|
||||
$creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"]));
|
||||
}
|
||||
@ -1112,33 +1131,39 @@ class Server{
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString("level-name", "world");
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($default, true) && !$this->worldManager->isWorldGenerated($default)){
|
||||
if(!$this->worldManager->loadWorld($default, true)){
|
||||
if($this->worldManager->isWorldGenerated($default)){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
|
||||
return false;
|
||||
}
|
||||
$generatorName = $this->configGroup->getConfigString("level-type");
|
||||
$generatorOptions = $this->configGroup->getConfigString("generator-settings");
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||
if($generatorClass !== null){
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
->setGeneratorClass($generatorClass)
|
||||
->setGeneratorOptions($generatorOptions);
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
|
||||
if($convertedSeed !== null){
|
||||
$creationOptions->setSeed($convertedSeed);
|
||||
}
|
||||
$this->worldManager->generateWorld($default, $creationOptions);
|
||||
|
||||
if($generatorClass === null){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
return false;
|
||||
}
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
->setGeneratorClass($generatorClass)
|
||||
->setGeneratorOptions($generatorOptions);
|
||||
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
|
||||
if($convertedSeed !== null){
|
||||
$creationOptions->setSeed($convertedSeed);
|
||||
}
|
||||
$creationOptions->setDifficulty($this->getDifficulty());
|
||||
$this->worldManager->generateWorld($default, $creationOptions);
|
||||
}
|
||||
|
||||
$world = $this->worldManager->getWorldByName($default);
|
||||
if($world === null){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->forceShutdown();
|
||||
|
||||
return false;
|
||||
throw new AssumptionFailedError("We just loaded/generated the default world, so it must exist");
|
||||
}
|
||||
$this->worldManager->setDefaultWorld($world);
|
||||
}
|
||||
|
||||
return true;
|
||||
return !$anyWorldFailedToLoad;
|
||||
}
|
||||
|
||||
private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{
|
||||
@ -1235,7 +1260,7 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CommandSender[]|null $recipients
|
||||
* @param CommandSender[]|null $recipients
|
||||
*/
|
||||
public function broadcastMessage(Translatable|string $message, ?array $recipients = null) : int{
|
||||
$recipients = $recipients ?? $this->getBroadcastChannelSubscribers(self::BROADCAST_CHANNEL_USERS);
|
||||
@ -1288,9 +1313,9 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
* @param int $fadeOut Duration in ticks for fade-out.
|
||||
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
|
||||
* @param int $stay Duration in ticks to stay on screen for
|
||||
* @param int $fadeOut Duration in ticks for fade-out.
|
||||
* @param Player[]|null $recipients
|
||||
*/
|
||||
public function broadcastTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1, ?array $recipients = null) : int{
|
||||
@ -1377,16 +1402,21 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
public function enablePlugins(PluginEnableOrder $type) : void{
|
||||
public function enablePlugins(PluginEnableOrder $type) : bool{
|
||||
$allSuccess = true;
|
||||
foreach($this->pluginManager->getPlugins() as $plugin){
|
||||
if(!$plugin->isEnabled() and $plugin->getDescription()->getOrder()->equals($type)){
|
||||
$this->pluginManager->enablePlugin($plugin);
|
||||
if(!$plugin->isEnabled() && $plugin->getDescription()->getOrder()->equals($type)){
|
||||
if(!$this->pluginManager->enablePlugin($plugin)){
|
||||
$allSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($type->equals(PluginEnableOrder::POSTWORLD())){
|
||||
$this->commandMap->registerServerAliases();
|
||||
}
|
||||
|
||||
return $allSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1416,6 +1446,11 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
private function forceShutdownExit() : void{
|
||||
$this->forceShutdown();
|
||||
Process::kill(Process::pid(), true);
|
||||
}
|
||||
|
||||
public function forceShutdown() : void{
|
||||
if($this->hasStopped){
|
||||
return;
|
||||
@ -1426,7 +1461,7 @@ class Server{
|
||||
}
|
||||
|
||||
if($this->isRunning){
|
||||
$this->logger->emergency("Forcing server shutdown");
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_forcingShutdown()));
|
||||
}
|
||||
try{
|
||||
if(!$this->isRunning()){
|
||||
@ -1466,7 +1501,7 @@ class Server{
|
||||
$this->configGroup->save();
|
||||
}
|
||||
|
||||
if(isset($this->console)){
|
||||
if($this->console !== null){
|
||||
$this->getLogger()->debug("Closing console");
|
||||
$this->console->quit();
|
||||
}
|
||||
@ -1570,7 +1605,8 @@ class Server{
|
||||
|
||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
||||
$crashInterval = 120; //2 minutes
|
||||
if(file_exists($stamp) and !($report = (filemtime($stamp) + $crashInterval < time()))){
|
||||
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
||||
$report = false;
|
||||
$this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago");
|
||||
}
|
||||
@touch($stamp); //update file timestamp
|
||||
@ -1578,7 +1614,7 @@ class Server{
|
||||
$plugin = $dump->getData()->plugin;
|
||||
if($plugin !== ""){
|
||||
$p = $this->pluginManager->getPlugin($plugin);
|
||||
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
|
||||
if($p instanceof Plugin && !($p->getPluginLoader() instanceof PharPluginLoader)){
|
||||
$this->logger->debug("Not sending crashdump due to caused by non-phar plugin");
|
||||
$report = false;
|
||||
}
|
||||
@ -1588,7 +1624,7 @@ class Server{
|
||||
$report = false;
|
||||
}
|
||||
|
||||
if(strrpos(VersionInfo::GIT_HASH(), "-dirty") !== false or VersionInfo::GIT_HASH() === str_repeat("00", 20)){
|
||||
if(strrpos(VersionInfo::GIT_HASH(), "-dirty") !== false || VersionInfo::GIT_HASH() === str_repeat("00", 20)){
|
||||
$this->logger->debug("Not sending crashdump due to locally modified");
|
||||
$report = false; //Don't send crashdumps for locally modified builds
|
||||
}
|
||||
@ -1603,13 +1639,15 @@ class Server{
|
||||
"reportPaste" => base64_encode($dump->getEncodedData())
|
||||
], 10, [], $postUrlError);
|
||||
|
||||
if($reply !== null and ($data = json_decode($reply->getBody())) !== null){
|
||||
if(isset($data->crashId) and isset($data->crashUrl)){
|
||||
if($reply !== null && is_object($data = json_decode($reply->getBody()))){
|
||||
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)));
|
||||
}elseif(isset($data->error)){
|
||||
}elseif(isset($data->error) && is_string($data->error)){
|
||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||
}else{
|
||||
$this->logger->emergency("Invalid JSON response received from crash archive: " . $reply->getBody());
|
||||
}
|
||||
}else{
|
||||
$this->logger->emergency("Failed to communicate with crash archive: $postUrlError");
|
||||
@ -1661,7 +1699,7 @@ class Server{
|
||||
public function addOnlinePlayer(Player $player) : bool{
|
||||
$ev = new PlayerLoginEvent($player, "Plugin reason");
|
||||
$ev->call();
|
||||
if($ev->isCancelled() or !$player->isConnected()){
|
||||
if($ev->isCancelled() || !$player->isConnected()){
|
||||
$player->disconnect($ev->getKickMessage());
|
||||
|
||||
return false;
|
||||
@ -1670,7 +1708,7 @@ class Server{
|
||||
$session = $player->getNetworkSession();
|
||||
$position = $player->getPosition();
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_player_logIn(
|
||||
TextFormat::AQUA . $player->getName() . TextFormat::WHITE,
|
||||
TextFormat::AQUA . $player->getName() . TextFormat::RESET,
|
||||
$session->getIp(),
|
||||
(string) $session->getPort(),
|
||||
(string) $player->getId(),
|
||||
@ -1775,11 +1813,11 @@ class Server{
|
||||
$this->network->tick();
|
||||
Timings::$connection->stopTiming();
|
||||
|
||||
if(($this->tickCounter % 20) === 0){
|
||||
if(($this->tickCounter % self::TARGET_TICKS_PER_SECOND) === 0){
|
||||
if($this->doTitleTick){
|
||||
$this->titleTick();
|
||||
}
|
||||
$this->currentTPS = 20;
|
||||
$this->currentTPS = self::TARGET_TICKS_PER_SECOND;
|
||||
$this->currentUse = 0;
|
||||
|
||||
$queryRegenerateEvent = new QueryRegenerateEvent(new QueryInfo($this));
|
||||
@ -1790,39 +1828,50 @@ class Server{
|
||||
$this->network->getBandwidthTracker()->rotateAverageHistory();
|
||||
}
|
||||
|
||||
if($this->sendUsageTicker > 0 and --$this->sendUsageTicker === 0){
|
||||
$this->sendUsageTicker = 6000;
|
||||
if($this->sendUsageTicker > 0 && --$this->sendUsageTicker === 0){
|
||||
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
|
||||
$this->sendUsage(SendUsageTask::TYPE_STATUS);
|
||||
}
|
||||
|
||||
if(($this->tickCounter % 100) === 0){
|
||||
if(($this->tickCounter % self::TICKS_PER_WORLD_CACHE_CLEAR) === 0){
|
||||
foreach($this->worldManager->getWorlds() as $world){
|
||||
$world->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
if($this->getTicksPerSecondAverage() < 12){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
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->getMemoryManager()->check();
|
||||
|
||||
if($this->console !== null){
|
||||
Timings::$serverCommand->startTiming();
|
||||
while(($line = $this->console->readLine()) !== null){
|
||||
$this->consoleSender ??= new ConsoleCommandSender($this, $this->language);
|
||||
$this->dispatchCommand($this->consoleSender, $line);
|
||||
}
|
||||
Timings::$serverCommand->stopTiming();
|
||||
}
|
||||
|
||||
Timings::$serverTick->stopTiming();
|
||||
|
||||
$now = microtime(true);
|
||||
$this->currentTPS = min(20, 1 / max(0.001, $now - $tickTime));
|
||||
$this->currentUse = min(1, ($now - $tickTime) / 0.05);
|
||||
$totalTickTimeSeconds = $now - $tickTime + ($this->tickSleeper->getNotificationProcessingTime() / 1_000_000_000);
|
||||
$this->currentTPS = min(self::TARGET_TICKS_PER_SECOND, 1 / max(0.001, $totalTickTimeSeconds));
|
||||
$this->currentUse = min(1, $totalTickTimeSeconds / self::TARGET_SECONDS_PER_TICK);
|
||||
|
||||
TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate);
|
||||
|
||||
$idx = $this->tickCounter % 20;
|
||||
$idx = $this->tickCounter % self::TARGET_TICKS_PER_SECOND;
|
||||
$this->tickAverage[$idx] = $this->currentTPS;
|
||||
$this->useAverage[$idx] = $this->currentUse;
|
||||
$this->tickSleeper->resetNotificationProcessingTime();
|
||||
|
||||
if(($this->nextTick - $tickTime) < -1){
|
||||
$this->nextTick = $tickTime;
|
||||
}else{
|
||||
$this->nextTick += 0.05;
|
||||
$this->nextTick += self::TARGET_SECONDS_PER_TICK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -32,25 +32,19 @@ use function is_string;
|
||||
use function strtolower;
|
||||
|
||||
final class ServerConfigGroup{
|
||||
|
||||
/** @var Config */
|
||||
private $pocketmineYml;
|
||||
/** @var Config */
|
||||
private $serverProperties;
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @phpstan-var array<string, mixed>
|
||||
*/
|
||||
private $propertyCache = [];
|
||||
private array $propertyCache = [];
|
||||
|
||||
public function __construct(Config $pocketmineYml, Config $serverProperties){
|
||||
$this->pocketmineYml = $pocketmineYml;
|
||||
$this->serverProperties = $serverProperties;
|
||||
}
|
||||
public function __construct(
|
||||
private Config $pocketmineYml,
|
||||
private Config $serverProperties
|
||||
){}
|
||||
|
||||
/**
|
||||
* @param mixed $defaultValue
|
||||
* @param mixed $defaultValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
|
64
src/TimeTrackingSleeperHandler.php
Normal file
64
src/TimeTrackingSleeperHandler.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?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;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
* Custom Snooze sleeper handler which captures notification processing time.
|
||||
* @internal
|
||||
*/
|
||||
final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
public function getNotificationProcessingTime() : int{ return $this->notificationProcessingTimeNs; }
|
||||
|
||||
/**
|
||||
* Resets the notification processing time tracker to zero.
|
||||
*/
|
||||
public function resetNotificationProcessingTime() : void{ $this->notificationProcessingTimeNs = 0; }
|
||||
|
||||
public function processNotifications() : void{
|
||||
$startTime = hrtime(true);
|
||||
$this->timings->startTiming();
|
||||
try{
|
||||
parent::processNotifications();
|
||||
}finally{
|
||||
$this->notificationProcessingTimeNs += hrtime(true) - $startTime;
|
||||
$this->timings->stopTiming();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.0.8";
|
||||
public const BASE_VERSION = "4.15.0";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
@ -39,8 +39,7 @@ final class VersionInfo{
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/** @var string|null */
|
||||
private static $gitHash = null;
|
||||
private static ?string $gitHash = null;
|
||||
|
||||
public static function GIT_HASH() : string{
|
||||
if(self::$gitHash === null){
|
||||
@ -79,8 +78,7 @@ final class VersionInfo{
|
||||
return self::$buildNumber;
|
||||
}
|
||||
|
||||
/** @var VersionString|null */
|
||||
private static $fullVersion = null;
|
||||
private static ?VersionString $fullVersion = null;
|
||||
|
||||
public static function VERSION() : VersionString{
|
||||
if(self::$fullVersion === null){
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,22 +17,16 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
/**
|
||||
* Air block
|
||||
*/
|
||||
class Air extends Transparent{
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
return true;
|
||||
}
|
||||
class Air extends Flowable{
|
||||
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
@ -41,15 +35,4 @@ class Air extends Transparent{
|
||||
public function canBePlaced() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -28,6 +28,7 @@ use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -39,7 +40,11 @@ class Anvil extends Transparent implements Fallable{
|
||||
use FallableTrait;
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
private int $damage = 0;
|
||||
public const UNDAMAGED = 0;
|
||||
public const SLIGHTLY_DAMAGED = 1;
|
||||
public const VERY_DAMAGED = 2;
|
||||
|
||||
private int $damage = self::UNDAMAGED;
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->damage << 2);
|
||||
@ -47,7 +52,7 @@ class Anvil extends Transparent implements Fallable{
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3);
|
||||
$this->damage = BlockDataSerializer::readBoundedInt("damage", $stateMeta >> 2, 0, 2);
|
||||
$this->damage = BlockDataSerializer::readBoundedInt("damage", $stateMeta >> 2, self::UNDAMAGED, self::VERY_DAMAGED);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
@ -62,8 +67,8 @@ class Anvil extends Transparent implements Fallable{
|
||||
|
||||
/** @return $this */
|
||||
public function setDamage(int $damage) : self{
|
||||
if($damage < 0 || $damage > 2){
|
||||
throw new \InvalidArgumentException("Damage must be in range 0-2");
|
||||
if($damage < self::UNDAMAGED || $damage > self::VERY_DAMAGED){
|
||||
throw new \InvalidArgumentException("Damage must be in range " . self::UNDAMAGED . " ... " . self::VERY_DAMAGED);
|
||||
}
|
||||
$this->damage = $damage;
|
||||
return $this;
|
||||
@ -76,6 +81,10 @@ class Anvil extends Transparent implements Fallable{
|
||||
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCurrentWindow(new AnvilInventory($this->position));
|
||||
|
@ -17,13 +17,14 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Bamboo as ItemBamboo;
|
||||
use pocketmine\item\Fertilizer;
|
||||
@ -100,6 +101,10 @@ class Bamboo extends Transparent{
|
||||
return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
private static function getOffsetSeed(int $x, int $y, int $z) : int{
|
||||
$p1 = gmp_mul($z, 0x6ebfff5);
|
||||
$p2 = gmp_mul($x, 0x2fc20f);
|
||||
@ -159,9 +164,10 @@ class Bamboo extends Transparent{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$below = $this->position->getWorld()->getBlock($this->position->down());
|
||||
if(!$this->canBeSupportedBy($below) and !$below->isSameType($this)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
$below = $world->getBlock($this->position->down());
|
||||
if(!$this->canBeSupportedBy($below) && !$below->isSameType($this)){
|
||||
$world->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +213,7 @@ class Bamboo extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
$tx = new BlockTransaction($world);
|
||||
foreach($newBlocks as $idx => $newBlock){
|
||||
$tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -36,14 +36,14 @@ final class BambooSapling extends Flowable{
|
||||
private bool $ready = false;
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->ready = ($stateMeta & BlockLegacyMetadata::SAPLING_FLAG_READY) !== 0;
|
||||
$this->ready = ($stateMeta & BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY) !== 0;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->ready ? BlockLegacyMetadata::SAPLING_FLAG_READY : 0;
|
||||
return $this->ready ? BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY : 0;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{ return 0b1000; }
|
||||
public function getStateBitmask() : int{ return 0b1; }
|
||||
|
||||
public function isReady() : bool{ return $this->ready; }
|
||||
|
||||
@ -82,8 +82,9 @@ final class BambooSapling extends Flowable{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->position->getWorld()->getBlock($this->position->down()))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){
|
||||
$world->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -27,6 +27,7 @@ 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\data\bedrock\DyeColorIdMap;
|
||||
use pocketmine\item\Banner as ItemBanner;
|
||||
use pocketmine\item\Item;
|
||||
@ -86,7 +87,7 @@ abstract class BaseBanner extends Transparent{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
* @param BannerPatternLayer[] $patterns
|
||||
*
|
||||
* @phpstan-param list<BannerPatternLayer> $patterns
|
||||
* @return $this
|
||||
@ -107,7 +108,18 @@ abstract class BaseBanner extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->isSolid();
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
|
||||
return false;
|
||||
}
|
||||
if($item instanceof ItemBanner){
|
||||
$this->color = $item->getColor();
|
||||
$this->setPatterns($item->getPatterns());
|
||||
@ -119,7 +131,7 @@ abstract class BaseBanner extends Transparent{
|
||||
abstract protected function getSupportingFace() : int;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->getSupportingFace())->getId() === BlockLegacyIds::AIR){
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
@ -130,7 +142,7 @@ abstract class BaseBanner extends Transparent{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
$drop = $this->asItem();
|
||||
if($drop instanceof ItemBanner and count($this->patterns) > 0){
|
||||
if($drop instanceof ItemBanner && count($this->patterns) > 0){
|
||||
$drop->setPatterns($this->patterns);
|
||||
}
|
||||
|
||||
@ -139,7 +151,7 @@ abstract class BaseBanner extends Transparent{
|
||||
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$result = $this->asItem();
|
||||
if($addUserData and $result instanceof ItemBanner and count($this->patterns) > 0){
|
||||
if($addUserData && $result instanceof ItemBanner && count($this->patterns) > 0){
|
||||
$result->setPatterns($this->patterns);
|
||||
}
|
||||
return $result;
|
||||
|
@ -17,41 +17,26 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\CoralTypeTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\BlockDeathEvent;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
abstract class BaseCoral extends Transparent{
|
||||
|
||||
protected CoralType $coralType;
|
||||
protected bool $dead = false;
|
||||
use CoralTypeTrait;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
|
||||
parent::__construct($idInfo, $name, $breakInfo);
|
||||
$this->coralType = CoralType::TUBE();
|
||||
}
|
||||
|
||||
public function getCoralType() : CoralType{ return $this->coralType; }
|
||||
|
||||
/** @return $this */
|
||||
public function setCoralType(CoralType $coralType) : self{
|
||||
$this->coralType = $coralType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isDead() : bool{ return $this->dead; }
|
||||
|
||||
/** @return $this */
|
||||
public function setDead(bool $dead) : self{
|
||||
$this->dead = $dead;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->dead){
|
||||
$world = $this->position->getWorld();
|
||||
@ -66,7 +51,11 @@ abstract class BaseCoral extends Transparent{
|
||||
|
||||
//TODO: check water inside the block itself (not supported on the API yet)
|
||||
if(!$hasWater){
|
||||
$world->setBlock($this->position, $this->setDead(true));
|
||||
$ev = new BlockDeathEvent($this, $this->setDead(true));
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($this->position, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,4 +71,8 @@ abstract class BaseCoral extends Transparent{
|
||||
public function isSolid() : bool{ return false; }
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{ return []; }
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -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)->isTransparent()){
|
||||
if($blockReplace->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ abstract class BaseRail extends Flowable{
|
||||
}
|
||||
|
||||
if(
|
||||
$other instanceof BaseRail and
|
||||
$other instanceof BaseRail &&
|
||||
in_array($otherConnection, $other->getCurrentShapeConnections(), true)
|
||||
){
|
||||
$connections[] = $connection;
|
||||
@ -162,6 +162,7 @@ abstract class BaseRail extends Flowable{
|
||||
$thisConnections = $this->getConnectedDirections();
|
||||
$changed = false;
|
||||
|
||||
$world = $this->position->getWorld();
|
||||
do{
|
||||
$possible = $this->getPossibleConnectionDirections($thisConnections);
|
||||
$continue = false;
|
||||
@ -179,7 +180,7 @@ abstract class BaseRail extends Flowable{
|
||||
$otherSide |= RailConnectionInfo::FLAG_ASCEND;
|
||||
}
|
||||
|
||||
if(!($other instanceof BaseRail) or count($otherConnections = $other->getConnectedDirections()) >= 2){
|
||||
if(!($other instanceof BaseRail) || count($otherConnections = $other->getConnectedDirections()) >= 2){
|
||||
//we can only connect to a rail that has less than 2 connections
|
||||
continue;
|
||||
}
|
||||
@ -189,7 +190,7 @@ abstract class BaseRail extends Flowable{
|
||||
if(isset($otherPossible[$otherSide])){
|
||||
$otherConnections[] = $otherSide;
|
||||
$other->setConnections($otherConnections);
|
||||
$this->position->getWorld()->setBlock($other->position, $other);
|
||||
$world->setBlock($other->position, $other);
|
||||
|
||||
$changed = true;
|
||||
$thisConnections[] = $thisSide;
|
||||
@ -202,7 +203,7 @@ abstract class BaseRail extends Flowable{
|
||||
|
||||
if($changed){
|
||||
$this->setConnections($thisConnections);
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,12 +221,13 @@ abstract class BaseRail extends Flowable{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::DOWN)->isTransparent()){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
if(!$this->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->getSupportType(Facing::UP)->hasEdgeSupport()){
|
||||
$world->useBreakOn($this->position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Sign as TileSign;
|
||||
use pocketmine\block\utils\SignText;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\SignChangeEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
@ -77,6 +78,10 @@ abstract class BaseSign extends Transparent{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
abstract protected function getSupportingFace() : int;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -28,6 +28,7 @@ use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\ColoredTrait;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\bedrock\DyeColorIdMap;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
@ -94,6 +95,10 @@ class Bed extends Transparent{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function isHeadPart() : bool{
|
||||
return $this->head;
|
||||
}
|
||||
@ -120,7 +125,7 @@ class Bed extends Transparent{
|
||||
|
||||
public function getOtherHalf() : ?Bed{
|
||||
$other = $this->getSide($this->getOtherHalfSide());
|
||||
if($other instanceof Bed and $other->head !== $this->head and $other->facing === $this->facing){
|
||||
if($other instanceof Bed && $other->head !== $this->head && $other->facing === $this->facing){
|
||||
return $other;
|
||||
}
|
||||
|
||||
@ -135,14 +140,14 @@ class Bed extends Transparent{
|
||||
$player->sendMessage(TextFormat::GRAY . "This bed is incomplete");
|
||||
|
||||
return true;
|
||||
}elseif($playerPos->distanceSquared($this->position) > 4 and $playerPos->distanceSquared($other->position) > 4){
|
||||
}elseif($playerPos->distanceSquared($this->position) > 4 && $playerPos->distanceSquared($other->position) > 4){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY));
|
||||
return true;
|
||||
}
|
||||
|
||||
$time = $this->position->getWorld()->getTimeOfDay();
|
||||
|
||||
$isNight = ($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE);
|
||||
$isNight = ($time >= World::TIME_NIGHT && $time < World::TIME_SUNRISE);
|
||||
|
||||
if(!$isNight){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_noSleep()->prefix(TextFormat::GRAY));
|
||||
@ -166,7 +171,7 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(($other = $this->getOtherHalf()) !== null and $other->occupied !== $this->occupied){
|
||||
if(!$this->head && ($other = $this->getOtherHalf()) !== null && $other->occupied !== $this->occupied){
|
||||
$this->occupied = $other->occupied;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
}
|
||||
@ -181,12 +186,11 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
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->isTransparent()){
|
||||
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
|
||||
|
||||
$next = $this->getSide($this->getOtherHalfSide());
|
||||
if($next->canBeReplaced() and !$next->getSide(Facing::DOWN)->isTransparent()){
|
||||
if($next->canBeReplaced() && $this->canBeSupportedBy($next->getSide(Facing::DOWN))){
|
||||
$nextState = clone $this;
|
||||
$nextState->head = true;
|
||||
$tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState);
|
||||
@ -216,4 +220,8 @@ class Bed extends Transparent{
|
||||
|
||||
return parent::getAffectedBlocks();
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -30,7 +30,7 @@ use function mt_rand;
|
||||
class Beetroot extends Crops{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if($this->age >= 7){
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return [
|
||||
VanillaItems::BEETROOT(),
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(mt_rand(0, 3))
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -28,7 +28,9 @@ use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
@ -78,6 +80,32 @@ final class Bell extends Transparent{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR())){
|
||||
return [
|
||||
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
|
||||
];
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
return [
|
||||
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
|
||||
];
|
||||
}
|
||||
|
||||
$box = AxisAlignedBB::one()
|
||||
->squash(Facing::axis(Facing::rotateY($this->facing, true)), 1 / 4)
|
||||
->trim(Facing::UP, 1 / 16)
|
||||
->trim(Facing::DOWN, 1 / 4);
|
||||
|
||||
return [
|
||||
$this->attachmentType->equals(BellAttachmentType::ONE_WALL()) ? $box->trim($this->facing, 3 / 16) : $box
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function getAttachmentType() : BellAttachmentType{ return $this->attachmentType; }
|
||||
|
||||
/** @return $this */
|
||||
@ -86,14 +114,13 @@ final class Bell extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
//TODO: this isn't the actual logic, but it's the closest approximation we can support for now
|
||||
return $block->isSolid();
|
||||
private function canBeSupportedBy(Block $block, int $face) : bool{
|
||||
return !$block->getSupportType($face)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::UP){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
@ -101,18 +128,18 @@ final class Bell extends Transparent{
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR());
|
||||
}elseif($face === Facing::DOWN){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
|
||||
return false;
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING());
|
||||
}else{
|
||||
$this->setFacing($face);
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($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)))){
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
|
||||
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
|
||||
}
|
||||
}
|
||||
@ -121,10 +148,10 @@ final class Bell extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))))
|
||||
($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);
|
||||
}
|
||||
@ -133,28 +160,28 @@ final class Bell extends Transparent{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$faceHit = Facing::opposite($player->getHorizontalFacing());
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
$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))
|
||||
)
|
||||
){
|
||||
$this->ring($faceHit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ring(int $faceHit) : void{
|
||||
$this->position->getWorld()->addSound($this->position, new BellRingSound());
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
$world->addSound($this->position, new BellRingSound());
|
||||
$tile = $world->getTile($this->position);
|
||||
if($tile instanceof TileBell){
|
||||
$this->position->getWorld()->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
|
||||
$world->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -29,6 +29,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Spawnable;
|
||||
use pocketmine\block\tile\Tile;
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
@ -61,7 +62,7 @@ class Block{
|
||||
protected ?array $collisionBoxes = null;
|
||||
|
||||
/**
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
*/
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
|
||||
if(($idInfo->getVariant() & $this->getStateBitmask()) !== 0){
|
||||
@ -77,25 +78,47 @@ class Block{
|
||||
$this->position = clone $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about how to identify and store this block type, such as its legacy
|
||||
* numeric ID(s), tile type (if any), and legacy variant metadata.
|
||||
*/
|
||||
public function getIdInfo() : BlockIdentifier{
|
||||
return $this->idInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the printable English name of the block.
|
||||
*/
|
||||
public function getName() : string{
|
||||
return $this->fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy numeric Minecraft block ID.
|
||||
*/
|
||||
public function getId() : int{
|
||||
return $this->idInfo->getBlockId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store
|
||||
* blocks in chunks at runtime.
|
||||
*
|
||||
* This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
|
||||
*/
|
||||
public function getFullId() : int{
|
||||
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block as an item.
|
||||
* State information such as facing, powered/unpowered, open/closed, etc., is discarded.
|
||||
* Type information such as colour, wood type, etc. is preserved.
|
||||
*/
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::getInstance()->get(
|
||||
$this->idInfo->getItemId(),
|
||||
@ -103,6 +126,12 @@ class Block{
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
|
||||
* things for different blocks.
|
||||
*/
|
||||
public function getMeta() : int{
|
||||
$stateMeta = $this->writeStateToMeta();
|
||||
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
|
||||
@ -115,6 +144,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns a bitmask used to extract state bits from block metadata.
|
||||
* This is used to remove unwanted information from the legacy meta value when getting the block as an item.
|
||||
*/
|
||||
public function getStateBitmask() : int{
|
||||
return 0;
|
||||
@ -142,37 +172,52 @@ class Block{
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes information about the block into the world. This writes the blockstate ID into the chunk, and creates
|
||||
* and/or removes tiles as necessary.
|
||||
*
|
||||
* Note: Do not call this directly. Pass the block to {@link World::setBlock()} instead.
|
||||
*/
|
||||
public function writeStateToWorld() : void{
|
||||
$this->position->getWorld()->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
|
||||
$world = $this->position->getWorld();
|
||||
$world->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
|
||||
|
||||
$tileType = $this->idInfo->getTileClass();
|
||||
$oldTile = $this->position->getWorld()->getTile($this->position);
|
||||
$oldTile = $world->getTile($this->position);
|
||||
if($oldTile !== null){
|
||||
if($tileType === null or !($oldTile instanceof $tileType)){
|
||||
if($tileType === null || !($oldTile instanceof $tileType)){
|
||||
$oldTile->close();
|
||||
$oldTile = null;
|
||||
}elseif($oldTile instanceof Spawnable){
|
||||
$oldTile->setDirty(); //destroy old network cache
|
||||
$oldTile->clearSpawnCompoundCache(); //destroy old network cache
|
||||
}
|
||||
}
|
||||
if($oldTile === null and $tileType !== null){
|
||||
if($oldTile === null && $tileType !== null){
|
||||
/**
|
||||
* @var Tile $tile
|
||||
* @see Tile::__construct()
|
||||
*/
|
||||
$tile = new $tileType($this->position->getWorld(), $this->position->asVector3());
|
||||
$this->position->getWorld()->addTile($tile);
|
||||
$tile = new $tileType($world, $this->position->asVector3());
|
||||
$world->addTile($tile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given block has an equivalent type to this one. This compares base legacy ID and variant.
|
||||
* Returns a type ID that identifies this type of block. This does not include information like facing, open/closed,
|
||||
* powered/unpowered, etc.
|
||||
*/
|
||||
public function getTypeId() : int{
|
||||
return ($this->idInfo->getBlockId() << Block::INTERNAL_METADATA_BITS) | $this->idInfo->getVariant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given block has an equivalent type to this one. This compares the type IDs.
|
||||
*
|
||||
* Note: This ignores additional IDs used to represent additional states. This means that, for example, a lit
|
||||
* furnace and unlit furnace are considered the same type.
|
||||
*/
|
||||
public function isSameType(Block $other) : bool{
|
||||
return $this->idInfo->getBlockId() === $other->idInfo->getBlockId() and $this->idInfo->getVariant() === $other->idInfo->getVariant();
|
||||
return $this->getTypeId() === $other->getTypeId();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,22 +234,44 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can be replaced by another block placed in the same position.
|
||||
*/
|
||||
public function canBeReplaced() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can replace the given block in the given placement conditions.
|
||||
* This is used to allow slabs of the same type to combine into double slabs.
|
||||
*/
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return $blockReplace->canBeReplaced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
|
||||
* itself, but may be multiple blocks in some cases (such as doors).
|
||||
*
|
||||
* @param BlockTransaction $tx Blocks to be set should be added to this transaction (do not modify thr world directly)
|
||||
* @param Item $item Item used to place the block
|
||||
* @param Block $blockReplace Block expected to be replaced
|
||||
* @param Block $blockClicked Block that was clicked using the item
|
||||
* @param int $face Face of the clicked block which was clicked
|
||||
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
|
||||
* @param Player|null $player Player who placed the block, or null if it was not a player
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$tx->addBlock($blockReplace->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called immediately after the block has been placed in the world. Since placement uses a block transaction, some
|
||||
* things may not be possible until after the transaction has been executed.
|
||||
*/
|
||||
public function onPostPlace() : void{
|
||||
|
||||
}
|
||||
@ -220,10 +287,11 @@ class Block{
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*/
|
||||
public function onBreak(Item $item, ?Player $player = null) : bool{
|
||||
if(($t = $this->position->getWorld()->getTile($this->position)) !== null){
|
||||
$world = $this->position->getWorld();
|
||||
if(($t = $world->getTile($this->position)) !== null){
|
||||
$t->onBlockDestroyed();
|
||||
}
|
||||
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
|
||||
$world->setBlock($this->position, VanillaBlocks::AIR());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -243,7 +311,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Called when this block is randomly updated due to chunk ticking.
|
||||
* WARNING: This will not be called if ticksRandomly() does not return true!
|
||||
* WARNING: This will not be called if {@link Block::ticksRandomly()} does not return true!
|
||||
*/
|
||||
public function onRandomTick() : void{
|
||||
|
||||
@ -264,8 +332,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is attacked (left-clicked). This is called when a player left-clicks the block to try and
|
||||
* start to break it in survival mode.
|
||||
* Called when this block is attacked (left-clicked) by a player attempting to start breaking it in survival.
|
||||
*
|
||||
* @return bool if an action took place, prevents starting to break the block if true.
|
||||
*/
|
||||
@ -273,11 +340,19 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a multiplier applied to the velocity of entities moving on top of this block. A higher value will make
|
||||
* the block more slippery (like ice).
|
||||
*
|
||||
* @return float 0.0-1.0
|
||||
*/
|
||||
public function getFrictionFactor() : float{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of light emitted by this block.
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getLightLevel() : int{
|
||||
@ -320,10 +395,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether entities can climb up this block.
|
||||
*/
|
||||
@ -331,10 +402,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function getPosition() : Position{
|
||||
return $this->position;
|
||||
}
|
||||
@ -353,7 +420,7 @@ class Block{
|
||||
*/
|
||||
public function getDrops(Item $item) : array{
|
||||
if($this->breakInfo->isToolCompatible($item)){
|
||||
if($this->isAffectedBySilkTouch() and $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
|
||||
if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
|
||||
return $this->getSilkTouchDrops($item);
|
||||
}
|
||||
|
||||
@ -394,7 +461,7 @@ class Block{
|
||||
* Returns how much XP will be dropped by breaking this block with the given item.
|
||||
*/
|
||||
public function getXpDropForTool(Item $item) : int{
|
||||
if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) or !$this->breakInfo->isToolCompatible($item)){
|
||||
if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) || !$this->breakInfo->isToolCompatible($item)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -417,6 +484,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns the item that players will equip when middle-clicking on this block.
|
||||
* If addUserData is true, additional data may be added, such as banner patterns, chest contents, etc.
|
||||
*/
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$item = $this->asItem();
|
||||
@ -540,7 +608,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
* Returns whether any of the block's collision boxes intersect with the given AxisAlignedBB.
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||
foreach($this->getCollisionBoxes() as $bb2){
|
||||
@ -552,10 +620,21 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block has actions to be executed when an entity enters its cell (full cube space).
|
||||
*
|
||||
* @see Block::onEntityInside()
|
||||
*/
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity's bounding box clips inside this block's cell. Note that the entity may not be intersecting
|
||||
* with the collision box or bounding box.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} returns false.
|
||||
*
|
||||
* @return bool Whether the block is still the same after the intersection. If it changed (e.g. due to an explosive
|
||||
* being ignited), this should return false.
|
||||
*/
|
||||
@ -563,6 +642,19 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a direction vector describing which way an entity intersecting this block should be pushed.
|
||||
* This is used by liquids to push entities in liquid currents.
|
||||
*
|
||||
* The returned vector is summed with vectors from every other block the entity is intersecting, and normalized to
|
||||
* produce a final direction vector.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} does not return true!
|
||||
*/
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity lands on this block (usually due to falling).
|
||||
* @return float|null The new vertical velocity of the entity, or null if unchanged.
|
||||
@ -572,6 +664,13 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of collision bounding boxes for this block.
|
||||
* These are used for:
|
||||
* - entity movement collision checks (to ensure entities can't clip through blocks)
|
||||
* - projectile flight paths
|
||||
* - block placement (to ensure the player can't place blocks inside itself or another entity)
|
||||
* - anti-cheat checks in plugins
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
final public function getCollisionBoxes() : array{
|
||||
@ -602,12 +701,24 @@ class Block{
|
||||
return [AxisAlignedBB::one()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of support that the block can provide on the given face. This is used to determine whether
|
||||
* blocks placed on the given face can be supported by this block.
|
||||
*/
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::FULL();
|
||||
}
|
||||
|
||||
public function isFullCube() : bool{
|
||||
$bb = $this->getCollisionBoxes();
|
||||
|
||||
return count($bb) === 1 and $bb[0]->getAverageEdgeLength() >= 1 and $bb[0]->isCube();
|
||||
return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a ray trace along the line between the two positions using the block's collision boxes.
|
||||
* Returns the intersection point closest to pos1, or null if no intersection occurred.
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(count($bbs) === 0){
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -38,18 +38,17 @@ class BlockBreakInfo{
|
||||
*/
|
||||
public const INCOMPATIBLE_TOOL_MULTIPLIER = 5.0;
|
||||
|
||||
private float $hardness;
|
||||
private float $blastResistance;
|
||||
private int $toolType;
|
||||
private int $toolHarvestLevel;
|
||||
|
||||
/**
|
||||
* @param float|null $blastResistance default 5x hardness
|
||||
*/
|
||||
public function __construct(float $hardness, int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0, ?float $blastResistance = null){
|
||||
$this->hardness = $hardness;
|
||||
$this->toolType = $toolType;
|
||||
$this->toolHarvestLevel = $toolHarvestLevel;
|
||||
public function __construct(
|
||||
private float $hardness,
|
||||
private int $toolType = BlockToolType::NONE,
|
||||
private int $toolHarvestLevel = 0,
|
||||
?float $blastResistance = null
|
||||
){
|
||||
$this->blastResistance = $blastResistance ?? $hardness * 5;
|
||||
}
|
||||
|
||||
@ -119,8 +118,8 @@ class BlockBreakInfo{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->toolType === BlockToolType::NONE or $this->toolHarvestLevel === 0 or (
|
||||
($this->toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel);
|
||||
return $this->toolType === BlockToolType::NONE || $this->toolHarvestLevel === 0 || (
|
||||
($this->toolType & $tool->getBlockToolType()) !== 0 && $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,16 +17,18 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\BlockBreakInfo as BreakInfo;
|
||||
use pocketmine\block\BlockIdentifier as BID;
|
||||
use pocketmine\block\BlockIdentifierFlattened as BIDFlattened;
|
||||
use pocketmine\block\BlockLegacyIds as Ids;
|
||||
use pocketmine\block\BlockLegacyMetadata as Meta;
|
||||
use pocketmine\block\BlockToolType as ToolType;
|
||||
use pocketmine\block\tile\Banner as TileBanner;
|
||||
use pocketmine\block\tile\Barrel as TileBarrel;
|
||||
use pocketmine\block\tile\Beacon as TileBeacon;
|
||||
@ -43,6 +45,7 @@ use pocketmine\block\tile\FlowerPot as TileFlowerPot;
|
||||
use pocketmine\block\tile\Hopper as TileHopper;
|
||||
use pocketmine\block\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\block\tile\Jukebox as TileJukebox;
|
||||
use pocketmine\block\tile\Lectern as TileLectern;
|
||||
use pocketmine\block\tile\MonsterSpawner as TileMonsterSpawner;
|
||||
use pocketmine\block\tile\NormalFurnace as TileNormalFurnace;
|
||||
use pocketmine\block\tile\Note as TileNote;
|
||||
@ -73,7 +76,7 @@ class BlockFactory{
|
||||
* @var \SplFixedArray|Block[]
|
||||
* @phpstan-var \SplFixedArray<Block>
|
||||
*/
|
||||
private $fullList;
|
||||
private \SplFixedArray $fullList;
|
||||
|
||||
/**
|
||||
* @var \SplFixedArray|int[]
|
||||
@ -85,22 +88,22 @@ class BlockFactory{
|
||||
* @var \SplFixedArray|int[]
|
||||
* @phpstan-var \SplFixedArray<int>
|
||||
*/
|
||||
public $light;
|
||||
public \SplFixedArray $light;
|
||||
/**
|
||||
* @var \SplFixedArray|int[]
|
||||
* @phpstan-var \SplFixedArray<int>
|
||||
*/
|
||||
public $lightFilter;
|
||||
public \SplFixedArray $lightFilter;
|
||||
/**
|
||||
* @var \SplFixedArray|bool[]
|
||||
* @phpstan-var \SplFixedArray<bool>
|
||||
*/
|
||||
public $blocksDirectSkyLight;
|
||||
public \SplFixedArray $blocksDirectSkyLight;
|
||||
/**
|
||||
* @var \SplFixedArray|float[]
|
||||
* @phpstan-var \SplFixedArray<float>
|
||||
*/
|
||||
public $blastResistance;
|
||||
public \SplFixedArray $blastResistance;
|
||||
|
||||
public function __construct(){
|
||||
$this->fullList = new \SplFixedArray(1024 << Block::INTERNAL_METADATA_BITS);
|
||||
@ -111,183 +114,184 @@ class BlockFactory{
|
||||
$this->blocksDirectSkyLight = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, false));
|
||||
$this->blastResistance = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 0.0));
|
||||
|
||||
$railBreakInfo = new BlockBreakInfo(0.7);
|
||||
$railBreakInfo = new BreakInfo(0.7);
|
||||
$this->registerAllMeta(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo));
|
||||
$this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0)));
|
||||
$this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, BlockToolType::AXE) extends BlockBreakInfo{
|
||||
$this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BreakInfo::indestructible(-1.0)));
|
||||
$this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, ToolType::AXE) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
if($item->getBlockToolType() === BlockToolType::SWORD){
|
||||
if($item->getBlockToolType() === ToolType::SWORD){
|
||||
return 0.0;
|
||||
}
|
||||
return parent::getBreakTime($item);
|
||||
}
|
||||
}));
|
||||
$this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BreakInfo::instant()));
|
||||
|
||||
$bannerBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$bannerBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$this->registerAllMeta(new FloorBanner(new BID(Ids::STANDING_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Banner", $bannerBreakInfo));
|
||||
$this->registerAllMeta(new WallBanner(new BID(Ids::WALL_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Wall Banner", $bannerBreakInfo));
|
||||
$this->registerAllMeta(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BlockBreakInfo(3.0)));
|
||||
$this->registerAllMeta(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BlockBreakInfo(0.2)));
|
||||
$this->registerAllMeta(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BreakInfo(3.0)));
|
||||
$this->registerAllMeta(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BreakInfo(0.2)));
|
||||
$this->registerAllMeta(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BreakInfo::indestructible()));
|
||||
|
||||
$this->registerAllMeta(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BlockBreakInfo(2.8, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BlockBreakInfo(1.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BreakInfo(2.8, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BreakInfo(1.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$bricksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$bricksBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::BRICK_STAIRS, 0), "Brick Stairs", $bricksBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::BRICK_BLOCK, 0), "Bricks", $bricksBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BlockBreakInfo(0.4)));
|
||||
$this->registerAllMeta(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BreakInfo(0.4)));
|
||||
$this->registerAllMeta(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BreakInfo::instant()));
|
||||
|
||||
$chestBreakInfo = new BlockBreakInfo(2.5, BlockToolType::AXE);
|
||||
$chestBreakInfo = new BreakInfo(2.5, ToolType::AXE);
|
||||
$this->registerAllMeta(new Chest(new BID(Ids::CHEST, 0, null, TileChest::class), "Chest", $chestBreakInfo));
|
||||
$this->registerAllMeta(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$cobblestoneBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$cobblestoneBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta($cobblestone = new Opaque(new BID(Ids::COBBLESTONE, 0), "Cobblestone", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::MOSSY_COBBLESTONE, 0), "Mossy Cobblestone", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::COBBLESTONE_STAIRS, 0), "Cobblestone Stairs", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::MOSSY_COBBLESTONE_STAIRS, 0), "Mossy Cobblestone Stairs", $cobblestoneBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BlockBreakInfo(4.0, BlockToolType::SWORD | BlockToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BlockBreakInfo(0.2, BlockToolType::AXE, 0, 15.0)));
|
||||
$this->registerAllMeta(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BlockBreakInfo(7.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BlockBreakInfo(0.2, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BreakInfo(4.0, ToolType::SWORD | ToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BreakInfo(0.2, ToolType::AXE, 0, 15.0)));
|
||||
$this->registerAllMeta(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BreakInfo(7.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BreakInfo(0.2, ToolType::AXE)));
|
||||
$this->registerAllMeta(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BreakInfo::instant(ToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new DetectorRail(new BID(Ids::DETECTOR_RAIL, 0), "Detector Rail", $railBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BlockBreakInfo::instant()),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BreakInfo::instant()),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
);
|
||||
$this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BlockBreakInfo(0.5, BlockToolType::NONE, 0, 12.5)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0)));
|
||||
$this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BreakInfo(0.5, ToolType::NONE, 0, 12.5)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0)));
|
||||
|
||||
$endBrickBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 4.0);
|
||||
$endBrickBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 4.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_BRICKS, 0), "End Stone Bricks", $endBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::END_BRICK_STAIRS, 0), "End Stone Brick Stairs", $endBrickBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BlockBreakInfo(22.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0)));
|
||||
$this->registerAllMeta(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5)));
|
||||
$this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BreakInfo(22.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0)));
|
||||
$this->registerAllMeta(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BreakInfo(2.5, ToolType::AXE, 0, 2.5)));
|
||||
$this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BreakInfo::instant()));
|
||||
$this->registerAllMeta(
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BreakInfo::instant()),
|
||||
);
|
||||
$this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BlockBreakInfo(2.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BreakInfo(2.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$glassBreakInfo = new BlockBreakInfo(0.3);
|
||||
$glassBreakInfo = new BreakInfo(0.3);
|
||||
$this->registerAllMeta(new Glass(new BID(Ids::GLASS, 0), "Glass", $glassBreakInfo));
|
||||
$this->registerAllMeta(new GlassPane(new BID(Ids::GLASS_PANE, 0), "Glass Pane", $glassBreakInfo));
|
||||
$this->registerAllMeta(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BlockBreakInfo(10.0, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0)));
|
||||
$this->registerAllMeta(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BlockBreakInfo(0.3, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BreakInfo(10.0, ToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0)));
|
||||
$this->registerAllMeta(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BreakInfo(0.3, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
|
||||
$grassBreakInfo = new BlockBreakInfo(0.6, BlockToolType::SHOVEL);
|
||||
$grassBreakInfo = new BreakInfo(0.6, ToolType::SHOVEL);
|
||||
$this->registerAllMeta(new Grass(new BID(Ids::GRASS, 0), "Grass", $grassBreakInfo));
|
||||
$this->registerAllMeta(new GrassPath(new BID(Ids::GRASS_PATH, 0), "Grass Path", $grassBreakInfo));
|
||||
$this->registerAllMeta(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
|
||||
$hardenedClayBreakInfo = new BlockBreakInfo(1.25, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 21.0);
|
||||
$hardenedClayBreakInfo = new BreakInfo(1.25, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 21.0);
|
||||
$this->registerAllMeta(new HardenedClay(new BID(Ids::HARDENED_CLAY, 0), "Hardened Clay", $hardenedClayBreakInfo));
|
||||
|
||||
$hardenedGlassBreakInfo = new BlockBreakInfo(10.0);
|
||||
$hardenedGlassBreakInfo = new BreakInfo(10.0);
|
||||
$this->registerAllMeta(new HardenedGlass(new BID(Ids::HARD_GLASS, 0), "Hardened Glass", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new HardenedGlassPane(new BID(Ids::HARD_GLASS_PANE, 0), "Hardened Glass Pane", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0)));
|
||||
$this->registerAllMeta(new Ice(new BID(Ids::ICE, 0), "Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0)));
|
||||
$this->registerAllMeta(new Ice(new BID(Ids::ICE, 0), "Ice", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
|
||||
$updateBlockBreakInfo = new BlockBreakInfo(1.0);
|
||||
$updateBlockBreakInfo = new BreakInfo(1.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE, 0), "update!", $updateBlockBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE2, 0), "ate!upd", $updateBlockBreakInfo));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BreakInfo::indestructible()));
|
||||
|
||||
$ironBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel(), 30.0);
|
||||
$ironBreakInfo = new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_BLOCK, 0), "Iron Block", $ironBreakInfo));
|
||||
$this->registerAllMeta(new Thin(new BID(Ids::IRON_BARS, 0), "Iron Bars", $ironBreakInfo));
|
||||
$ironDoorBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0);
|
||||
$ironDoorBreakInfo = new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0);
|
||||
$this->registerAllMeta(new Door(new BID(Ids::IRON_DOOR_BLOCK, 0, ItemIds::IRON_DOOR), "Iron Door", $ironDoorBreakInfo));
|
||||
$this->registerAllMeta(new Trapdoor(new BID(Ids::IRON_TRAPDOOR, 0), "Iron Trapdoor", $ironDoorBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BlockBreakInfo(0.25)));
|
||||
$this->registerAllMeta(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BlockBreakInfo(0.8, BlockToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
|
||||
$this->registerAllMeta(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BlockBreakInfo(0.4, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BlockBreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BlockBreakInfo(1.0, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BreakInfo(0.25)));
|
||||
$this->registerAllMeta(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BreakInfo(0.8, ToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
|
||||
$this->registerAllMeta(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BreakInfo(0.4, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new Lectern(new BID(Ids::LECTERN, 0, ItemIds::LECTERN, TileLectern::class), "Lectern", new BreakInfo(2.0, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BreakInfo(1.0, ToolType::AXE)));
|
||||
$this->registerAllMeta(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
|
||||
$netherBrickBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$netherBrickBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_BRICK_BLOCK, 0), "Nether Bricks", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::RED_NETHER_BRICK, 0), "Red Nether Bricks", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Fence(new BID(Ids::NETHER_BRICK_FENCE, 0), "Nether Brick Fence", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::NETHER_BRICK_STAIRS, 0), "Nether Brick Stairs", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::RED_NETHER_BRICK_STAIRS, 0), "Red Nether Brick Stairs", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0)));
|
||||
$this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0, BlockToolType::HOE)));
|
||||
$this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BlockBreakInfo(35.0 /* 50 in PC */, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BreakInfo::indestructible(0.0)));
|
||||
$this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BreakInfo(1.0, ToolType::HOE)));
|
||||
$this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BreakInfo(0.4, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BreakInfo(0.8, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BreakInfo(35.0 /* 50 in PC */, ToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new PoweredRail(new BID(Ids::GOLDEN_RAIL, 0), "Powered Rail", $railBreakInfo));
|
||||
|
||||
$prismarineBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$prismarineBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_NORMAL), "Prismarine", $prismarineBreakInfo),
|
||||
new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_DARK), "Dark Prismarine", $prismarineBreakInfo),
|
||||
@ -297,21 +301,21 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::DARK_PRISMARINE_STAIRS, 0), "Dark Prismarine Stairs", $prismarineBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo));
|
||||
|
||||
$pumpkinBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$this->registerAllMeta($pumpkin = new Opaque(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo));
|
||||
$pumpkinBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$this->registerAllMeta(new Pumpkin(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo));
|
||||
$this->registerAllMeta(new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN, 0), "Carved Pumpkin", $pumpkinBreakInfo));
|
||||
$this->registerAllMeta(new LitPumpkin(new BID(Ids::JACK_O_LANTERN, 0), "Jack o'Lantern", $pumpkinBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BreakInfo::instant()));
|
||||
|
||||
$purpurBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$purpurBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_NORMAL), "Purpur Block", $purpurBreakInfo),
|
||||
new SimplePillar(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_PILLAR), "Purpur Pillar", $purpurBreakInfo)
|
||||
);
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::PURPUR_STAIRS, 0), "Purpur Stairs", $purpurBreakInfo));
|
||||
|
||||
$quartzBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$quartzBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_NORMAL), "Quartz Block", $quartzBreakInfo),
|
||||
new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_CHISELED), "Chiseled Quartz Block", $quartzBreakInfo),
|
||||
@ -322,33 +326,33 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_QUARTZ_STAIRS, 0), "Smooth Quartz Stairs", $quartzBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Rail(new BID(Ids::RAIL, 0), "Rail", $railBreakInfo));
|
||||
$this->registerAllMeta(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BlockBreakInfo(0.3)));
|
||||
$this->registerAllMeta(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BreakInfo(0.3)));
|
||||
$this->registerAllMeta(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BreakInfo::instant()));
|
||||
|
||||
$sandBreakInfo = new BlockBreakInfo(0.5, BlockToolType::SHOVEL);
|
||||
$sandBreakInfo = new BreakInfo(0.5, ToolType::SHOVEL);
|
||||
$this->registerAllMeta(
|
||||
new Sand(new BID(Ids::SAND, 0), "Sand", $sandBreakInfo),
|
||||
new Sand(new BID(Ids::SAND, 1), "Red Sand", $sandBreakInfo)
|
||||
);
|
||||
$this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BlockBreakInfo(0.3)));
|
||||
$this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BlockBreakInfo(1.0)));
|
||||
$this->registerAllMeta(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BlockBreakInfo(0.2, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BlockBreakInfo(0.1, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BlockBreakInfo(0.6, BlockToolType::HOE)));
|
||||
$shulkerBoxBreakInfo = new BlockBreakInfo(2, BlockToolType::PICKAXE);
|
||||
$this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BreakInfo(0.3)));
|
||||
$this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BreakInfo(1.0)));
|
||||
$this->registerAllMeta(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BreakInfo(0.2, ToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BreakInfo(0.1, ToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BreakInfo(0.6, ToolType::HOE)));
|
||||
$shulkerBoxBreakInfo = new BreakInfo(2, ToolType::PICKAXE);
|
||||
$this->registerAllMeta(new ShulkerBox(new BID(Ids::UNDYED_SHULKER_BOX, 0, null, TileShulkerBox::class), "Shulker Box", $shulkerBoxBreakInfo));
|
||||
|
||||
$stoneBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$stoneBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
$stone = new class(new BID(Ids::STONE, Meta::STONE_NORMAL), "Stone", $stoneBreakInfo) extends Opaque{
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
@ -372,7 +376,7 @@ class BlockFactory{
|
||||
$crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo),
|
||||
$chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo)
|
||||
);
|
||||
$infestedStoneBreakInfo = new BlockBreakInfo(0.75, BlockToolType::PICKAXE);
|
||||
$infestedStoneBreakInfo = new BreakInfo(0.75, ToolType::PICKAXE);
|
||||
$this->registerAllMeta(
|
||||
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone),
|
||||
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick),
|
||||
@ -391,84 +395,92 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::POLISHED_GRANITE_STAIRS, 0), "Polished Granite Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::STONE_BRICK_STAIRS, 0), "Stone Brick Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::MOSSY_STONE_BRICK_STAIRS, 0), "Mossy Stone Brick Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Stonecutter(new BID(Ids::STONECUTTER_BLOCK, 0, ItemIds::STONECUTTER_BLOCK), "Stonecutter", new BreakInfo(3.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
//TODO: in the future this won't be the same for all the types
|
||||
$stoneSlabBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo));
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BlockBreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BlockBreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BlockBreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BlockBreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo));
|
||||
$this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BlockBreakInfo::instant()));
|
||||
$stoneSlabBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
|
||||
$weightedPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$getStoneSlabId = static fn(int $stoneSlabId, int $meta) => BlockLegacyIdHelper::getStoneSlabIdentifier($stoneSlabId, $meta);
|
||||
foreach([
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo),
|
||||
new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo),
|
||||
] as $slabType){
|
||||
$this->registerSlabWithDoubleHighBitsRemapping($slabType);
|
||||
}
|
||||
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Legacy Stonecutter", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BreakInfo::instant()));
|
||||
$this->registerAllMeta(
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BreakInfo::instant(ToolType::SHEARS, 1))
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo));
|
||||
$this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BreakInfo(0.2, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BreakInfo::instant()));
|
||||
|
||||
$weightedPressurePlateBreakInfo = new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo));
|
||||
$this->registerAllMeta(new WeightedPressurePlateLight(new BID(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Light", $weightedPressurePlateBreakInfo));
|
||||
$this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BreakInfo::instant()));
|
||||
|
||||
$planksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE, 0, 15.0);
|
||||
$leavesBreakInfo = new class(0.2, BlockToolType::HOE) extends BlockBreakInfo{
|
||||
$planksBreakInfo = new BreakInfo(2.0, ToolType::AXE, 0, 15.0);
|
||||
$leavesBreakInfo = new class(0.2, ToolType::HOE) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
if($item->getBlockToolType() === BlockToolType::SHEARS){
|
||||
if($item->getBlockToolType() === ToolType::SHEARS){
|
||||
return 0.0;
|
||||
}
|
||||
return parent::getBreakTime($item);
|
||||
}
|
||||
};
|
||||
$signBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$logBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE);
|
||||
$woodenDoorBreakInfo = new BlockBreakInfo(3.0, BlockToolType::AXE, 0, 15.0);
|
||||
$woodenButtonBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE);
|
||||
$woodenPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE);
|
||||
$signBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$logBreakInfo = new BreakInfo(2.0, ToolType::AXE);
|
||||
$woodenDoorBreakInfo = new BreakInfo(3.0, ToolType::AXE, 0, 15.0);
|
||||
$woodenButtonBreakInfo = new BreakInfo(0.5, ToolType::AXE);
|
||||
$woodenPressurePlateBreakInfo = new BreakInfo(0.5, ToolType::AXE);
|
||||
|
||||
$planks = [];
|
||||
$saplings = [];
|
||||
@ -479,7 +491,7 @@ class BlockFactory{
|
||||
$magicNumber = $treeType->getMagicNumber();
|
||||
$name = $treeType->getDisplayName();
|
||||
$planks[] = new Planks(new BID(Ids::PLANKS, $magicNumber), $name . " Planks", $planksBreakInfo);
|
||||
$saplings[] = new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BlockBreakInfo::instant(), $treeType);
|
||||
$saplings[] = new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BreakInfo::instant(), $treeType);
|
||||
$fences[] = new WoodenFence(new BID(Ids::FENCE, $magicNumber), $name . " Fence", $planksBreakInfo);
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new WoodenSlab(new BIDFlattened(Ids::WOODEN_SLAB, [Ids::DOUBLE_WOODEN_SLAB], $magicNumber), $name, $planksBreakInfo));
|
||||
|
||||
@ -511,27 +523,26 @@ class BlockFactory{
|
||||
$this->registerAllMeta(...$leaves);
|
||||
$this->registerAllMeta(...$allSidedLogs);
|
||||
|
||||
static $sandstoneTypes = [
|
||||
Meta::SANDSTONE_NORMAL => "",
|
||||
Meta::SANDSTONE_CHISELED => "Chiseled ",
|
||||
Meta::SANDSTONE_CUT => "Cut ",
|
||||
Meta::SANDSTONE_SMOOTH => "Smooth "
|
||||
];
|
||||
$sandstoneBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$sandstoneBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::RED_SANDSTONE_STAIRS, 0), "Red Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SANDSTONE_STAIRS, 0), "Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$sandstones = [];
|
||||
$redSandstones = [];
|
||||
foreach($sandstoneTypes as $variant => $prefix){
|
||||
foreach([
|
||||
Meta::SANDSTONE_NORMAL => "",
|
||||
Meta::SANDSTONE_CHISELED => "Chiseled ",
|
||||
Meta::SANDSTONE_CUT => "Cut ",
|
||||
Meta::SANDSTONE_SMOOTH => "Smooth "
|
||||
] as $variant => $prefix){
|
||||
$sandstones[] = new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo);
|
||||
$redSandstones[] = new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo);
|
||||
}
|
||||
$this->registerAllMeta(...$sandstones);
|
||||
$this->registerAllMeta(...$redSandstones);
|
||||
|
||||
$glazedTerracottaBreakInfo = new BlockBreakInfo(1.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$glazedTerracottaBreakInfo = new BreakInfo(1.4, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
foreach(DyeColor::getAll() as $color){
|
||||
$coloredName = function(string $name) use($color) : string{
|
||||
return $color->getDisplayName() . " " . $name;
|
||||
@ -544,13 +555,13 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new StainedHardenedClay(new BID(Ids::STAINED_CLAY, 0), "Stained Clay", $hardenedClayBreakInfo));
|
||||
$this->registerAllMeta(new StainedHardenedGlass(new BID(Ids::HARD_STAINED_GLASS, 0), "Stained Hardened Glass", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new StainedHardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, 0), "Stained Hardened Glass Pane", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BlockBreakInfo(0.1)));
|
||||
$this->registerAllMeta(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BlockBreakInfo(1.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, BlockToolType::SHEARS) extends BlockBreakInfo{
|
||||
$this->registerAllMeta(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BreakInfo(0.1)));
|
||||
$this->registerAllMeta(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BreakInfo(1.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, ToolType::SHEARS) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$time = parent::getBreakTime($item);
|
||||
if($item->getBlockToolType() === BlockToolType::SHEARS){
|
||||
if($item->getBlockToolType() === ToolType::SHEARS){
|
||||
$time *= 3; //shears break compatible blocks 15x faster, but wool 5x
|
||||
}
|
||||
|
||||
@ -559,7 +570,7 @@ class BlockFactory{
|
||||
}));
|
||||
|
||||
//TODO: in the future these won't all have the same hardness; they only do now because of the old metadata crap
|
||||
$wallBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$wallBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_COBBLESTONE), "Cobblestone Wall", $wallBreakInfo),
|
||||
new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_ANDESITE), "Andesite Wall", $wallBreakInfo),
|
||||
@ -579,7 +590,7 @@ class BlockFactory{
|
||||
|
||||
$this->registerElements();
|
||||
|
||||
$chemistryTableBreakInfo = new BlockBreakInfo(2.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$chemistryTableBreakInfo = new BreakInfo(2.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(
|
||||
new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_COMPOUND_CREATOR), "Compound Creator", $chemistryTableBreakInfo),
|
||||
new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_ELEMENT_CONSTRUCTOR), "Element Constructor", $chemistryTableBreakInfo),
|
||||
@ -594,17 +605,17 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Coral(
|
||||
new BID(Ids::CORAL, 0),
|
||||
"Coral",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
$this->registerAllMeta(new FloorCoralFan(
|
||||
new BlockIdentifierFlattened(Ids::CORAL_FAN, [Ids::CORAL_FAN_DEAD], 0, ItemIds::CORAL_FAN),
|
||||
"Coral Fan",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
$this->registerAllMeta(new WallCoralFan(
|
||||
new BlockIdentifierFlattened(Ids::CORAL_FAN_HANG, [Ids::CORAL_FAN_HANG2, Ids::CORAL_FAN_HANG3], 0, ItemIds::CORAL_FAN),
|
||||
"Wall Coral Fan",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
|
||||
//region --- auto-generated TODOs for bedrock-1.11.0 ---
|
||||
@ -626,7 +637,6 @@ class BlockFactory{
|
||||
//TODO: minecraft:jigsaw
|
||||
//TODO: minecraft:kelp
|
||||
//TODO: minecraft:lava_cauldron
|
||||
//TODO: minecraft:lectern
|
||||
//TODO: minecraft:movingBlock
|
||||
//TODO: minecraft:observer
|
||||
//TODO: minecraft:piston
|
||||
@ -636,7 +646,6 @@ class BlockFactory{
|
||||
//TODO: minecraft:seagrass
|
||||
//TODO: minecraft:smithing_table
|
||||
//TODO: minecraft:sticky_piston
|
||||
//TODO: minecraft:stonecutter_block
|
||||
//TODO: minecraft:structure_block
|
||||
//TODO: minecraft:turtle_egg
|
||||
//endregion
|
||||
@ -748,7 +757,7 @@ class BlockFactory{
|
||||
//shrooms have to be handled one by one because some metas are variants and others aren't, and they can't be
|
||||
//separated by a bitmask
|
||||
|
||||
$mushroomBlockBreakInfo = new BlockBreakInfo(0.2, BlockToolType::AXE);
|
||||
$mushroomBlockBreakInfo = new BreakInfo(0.2, ToolType::AXE);
|
||||
|
||||
$mushroomBlocks = [
|
||||
new BrownMushroomBlock(new BID(Ids::BROWN_MUSHROOM_BLOCK, 0), "Brown Mushroom Block", $mushroomBlockBreakInfo),
|
||||
@ -792,7 +801,7 @@ class BlockFactory{
|
||||
}
|
||||
|
||||
private function registerElements() : void{
|
||||
$instaBreak = BlockBreakInfo::instant();
|
||||
$instaBreak = BreakInfo::instant();
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::ELEMENT_0, 0), "???", $instaBreak));
|
||||
|
||||
$this->registerAllMeta(new Element(new BID(Ids::ELEMENT_1, 0), "Hydrogen", $instaBreak, "h", 1, 5));
|
||||
@ -959,7 +968,7 @@ class BlockFactory{
|
||||
* NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
|
||||
* will not automatically appear there.
|
||||
*
|
||||
* @param bool $override Whether to override existing registrations
|
||||
* @param bool $override Whether to override existing registrations
|
||||
*
|
||||
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
||||
* $override parameter.
|
||||
@ -973,7 +982,7 @@ class BlockFactory{
|
||||
}
|
||||
|
||||
foreach($block->getIdInfo()->getAllBlockIds() as $id){
|
||||
if(!$override and $this->isRegistered($id, $variant)){
|
||||
if(!$override && $this->isRegistered($id, $variant)){
|
||||
throw new \InvalidArgumentException("Block registration $id:$variant conflicts with an existing block");
|
||||
}
|
||||
|
||||
@ -982,7 +991,7 @@ class BlockFactory{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!$override and $this->isRegistered($id, $m)){
|
||||
if(!$override && $this->isRegistered($id, $m)){
|
||||
throw new \InvalidArgumentException("Block registration " . get_class($block) . " has states which conflict with other blocks");
|
||||
}
|
||||
|
||||
@ -1035,7 +1044,7 @@ class BlockFactory{
|
||||
* Deserializes a block from the provided legacy ID and legacy meta.
|
||||
*/
|
||||
public function get(int $id, int $meta) : Block{
|
||||
if($meta < 0 or $meta >= (1 << Block::INTERNAL_METADATA_BITS)){
|
||||
if($meta < 0 || $meta >= (1 << Block::INTERNAL_METADATA_BITS)){
|
||||
throw new \InvalidArgumentException("Block meta value $meta is out of bounds");
|
||||
}
|
||||
|
||||
@ -1046,7 +1055,7 @@ class BlockFactory{
|
||||
if($this->fullList[$index] !== null){
|
||||
$block = clone $this->fullList[$index];
|
||||
}else{
|
||||
$block = new UnknownBlock(new BID($id, $meta), BlockBreakInfo::instant());
|
||||
$block = new UnknownBlock(new BID($id, $meta), BreakInfo::instant());
|
||||
}
|
||||
|
||||
return $block;
|
||||
@ -1061,7 +1070,7 @@ class BlockFactory{
|
||||
*/
|
||||
public function isRegistered(int $id, int $meta = 0) : bool{
|
||||
$b = $this->fullList[($id << Block::INTERNAL_METADATA_BITS) | $meta];
|
||||
return $b !== null and !($b instanceof UnknownBlock);
|
||||
return $b !== null && !($b instanceof UnknownBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -27,25 +27,18 @@ use pocketmine\block\tile\Tile;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
class BlockIdentifier{
|
||||
|
||||
private int $blockId;
|
||||
private int $variant;
|
||||
private ?int $itemId;
|
||||
/** @phpstan-var class-string<Tile>|null */
|
||||
private ?string $tileClass;
|
||||
|
||||
/**
|
||||
* @phpstan-param class-string<Tile>|null $tileClass
|
||||
*/
|
||||
public function __construct(int $blockId, int $variant, ?int $itemId = null, ?string $tileClass = null){
|
||||
$this->blockId = $blockId;
|
||||
$this->variant = $variant;
|
||||
$this->itemId = $itemId;
|
||||
|
||||
public function __construct(
|
||||
private int $blockId,
|
||||
private int $variant,
|
||||
private ?int $itemId = null,
|
||||
private ?string $tileClass = null
|
||||
){
|
||||
if($tileClass !== null){
|
||||
Utils::testValidInstance($tileClass, Tile::class);
|
||||
}
|
||||
$this->tileClass = $tileClass;
|
||||
}
|
||||
|
||||
public function getBlockId() : int{
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -42,6 +42,8 @@ final class BlockLegacyMetadata{
|
||||
public const BAMBOO_LEAF_SIZE_SHIFT = 1;
|
||||
public const BAMBOO_LEAF_SIZE_MASK = 0x03;
|
||||
|
||||
public const BAMBOO_SAPLING_FLAG_READY = 0x01;
|
||||
|
||||
public const BARREL_FLAG_OPEN = 0x08;
|
||||
|
||||
public const BED_FLAG_HEAD = 0x08;
|
||||
@ -142,6 +144,8 @@ final class BlockLegacyMetadata{
|
||||
public const LEAVES_FLAG_NO_DECAY = 0x04;
|
||||
public const LEAVES_FLAG_CHECK_DECAY = 0x08;
|
||||
|
||||
public const LECTERN_FLAG_POWERED = 0x04;
|
||||
|
||||
public const LEVER_FLAG_POWERED = 0x08;
|
||||
|
||||
public const LIQUID_FLAG_FALLING = 0x08;
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
|
||||
use pocketmine\block\utils\BrewingStandSlot;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
@ -83,6 +84,10 @@ class BrewingStand extends Transparent{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function hasSlot(BrewingStandSlot $slot) : bool{
|
||||
return array_key_exists($slot->id(), $this->slots);
|
||||
}
|
||||
@ -116,7 +121,7 @@ class BrewingStand extends Transparent{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$stand = $this->position->getWorld()->getTile($this->position);
|
||||
if($stand instanceof TileBrewingStand and $stand->canOpenWith($item->getCustomName())){
|
||||
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){
|
||||
$player->setCurrentWindow($stand->getInventory());
|
||||
}
|
||||
}
|
||||
@ -125,6 +130,25 @@ class BrewingStand extends Transparent{
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
//TODO
|
||||
$world = $this->position->getWorld();
|
||||
$brewing = $world->getTile($this->position);
|
||||
if($brewing instanceof TileBrewingStand){
|
||||
if($brewing->onUpdate()){
|
||||
$world->scheduleDelayedBlockUpdate($this->position, 1);
|
||||
}
|
||||
|
||||
$changed = false;
|
||||
foreach(BrewingStandSlot::getAll() as $slot){
|
||||
$occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber());
|
||||
if($occupied !== $this->hasSlot($slot)){
|
||||
$this->setSlot($slot, $occupied);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -61,9 +61,11 @@ abstract class Button extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
//TODO: check valid target block
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract protected function getActivationTime() : int;
|
||||
@ -71,9 +73,10 @@ abstract class Button extends Flowable{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->pressed){
|
||||
$this->pressed = true;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, $this->getActivationTime());
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->scheduleDelayedBlockUpdate($this->position, $this->getActivationTime());
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -82,8 +85,19 @@ abstract class Button extends Flowable{
|
||||
public function onScheduledUpdate() : void{
|
||||
if($this->pressed){
|
||||
$this->pressed = false;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
|
||||
$world = $this->position->getWorld();
|
||||
$world->setBlock($this->position, $this);
|
||||
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
|
||||
}
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $support, int $face) : bool{
|
||||
return $support->getSupportType($face)->hasCenterSupport();
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,14 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
@ -36,6 +37,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
class Cactus extends Transparent{
|
||||
public const MAX_AGE = 15;
|
||||
|
||||
protected int $age = 0;
|
||||
|
||||
@ -44,7 +46,7 @@ class Cactus extends Transparent{
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, 15);
|
||||
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, self::MAX_AGE);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
@ -55,8 +57,8 @@ class Cactus extends Transparent{
|
||||
|
||||
/** @return $this */
|
||||
public function setAge(int $age) : self{
|
||||
if($age < 0 || $age > 15){
|
||||
throw new \InvalidArgumentException("Age must be in range 0-15");
|
||||
if($age < 0 || $age > self::MAX_AGE){
|
||||
throw new \InvalidArgumentException("Age must be in range 0 ... " . self::MAX_AGE);
|
||||
}
|
||||
$this->age = $age;
|
||||
return $this;
|
||||
@ -70,10 +72,14 @@ class Cactus extends Transparent{
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
static $shrinkSize = 1 / 16;
|
||||
$shrinkSize = 1 / 16;
|
||||
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
$entity->attack($ev);
|
||||
@ -82,13 +88,14 @@ class Cactus extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if($down->getId() !== BlockLegacyIds::SAND and !$down->isSameType($this)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->isSolid()){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
$world->useBreakOn($this->position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -101,35 +108,36 @@ class Cactus extends Transparent{
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
|
||||
if($this->age === 15){
|
||||
$world = $this->position->getWorld();
|
||||
if($this->age === self::MAX_AGE){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
if(!$this->position->getWorld()->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){
|
||||
if(!$world->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){
|
||||
break;
|
||||
}
|
||||
$b = $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
|
||||
$b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
|
||||
if($b->getId() === BlockLegacyIds::AIR){
|
||||
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->position->getWorld()->setBlock($b->position, $ev->getNewState());
|
||||
$world->setBlock($b->position, $ev->getNewState());
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->age = 0;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$world->setBlock($this->position, $this);
|
||||
}else{
|
||||
++$this->age;
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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->getId() === BlockLegacyIds::SAND or $down->isSameType($this)){
|
||||
if($down->getId() === BlockLegacyIds::SAND || $down->isSameType($this)){
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
if($this->getSide($side)->isSolid()){
|
||||
return false;
|
||||
|
@ -17,13 +17,14 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\entity\effect\EffectInstance;
|
||||
use pocketmine\entity\FoodSource;
|
||||
use pocketmine\entity\Living;
|
||||
@ -35,6 +36,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
class Cake extends Transparent implements FoodSource{
|
||||
public const MAX_BITES = 6;
|
||||
|
||||
protected int $bites = 0;
|
||||
|
||||
@ -43,7 +45,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->bites = BlockDataSerializer::readBoundedInt("bites", $stateMeta, 0, 6);
|
||||
$this->bites = BlockDataSerializer::readBoundedInt("bites", $stateMeta, 0, self::MAX_BITES);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
@ -62,12 +64,16 @@ class Cake extends Transparent implements FoodSource{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function getBites() : int{ return $this->bites; }
|
||||
|
||||
/** @return $this */
|
||||
public function setBites(int $bites) : self{
|
||||
if($bites < 0 || $bites > 6){
|
||||
throw new \InvalidArgumentException("Bites must be in range 0-6");
|
||||
if($bites < 0 || $bites > self::MAX_BITES){
|
||||
throw new \InvalidArgumentException("Bites must be in range 0 ... " . self::MAX_BITES);
|
||||
}
|
||||
$this->bites = $bites;
|
||||
return $this;
|
||||
@ -118,7 +124,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
public function getResidue(){
|
||||
$clone = clone $this;
|
||||
$clone->bites++;
|
||||
if($clone->bites > 6){
|
||||
if($clone->bites > self::MAX_BITES){
|
||||
$clone = VanillaBlocks::AIR();
|
||||
}
|
||||
return $clone;
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -31,7 +31,7 @@ class Carrot extends Crops{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::CARROT()->setCount($this->age >= 7 ? mt_rand(1, 4) : 1)
|
||||
VanillaItems::CARROT()->setCount($this->age >= self::MAX_AGE ? mt_rand(1, 4) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -26,6 +26,8 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Chest as TileChest;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\event\block\ChestPairEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -44,20 +46,28 @@ class Chest extends Transparent{
|
||||
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function onPostPlace() : void{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
$world = $this->position->getWorld();
|
||||
$tile = $world->getTile($this->position);
|
||||
if($tile instanceof TileChest){
|
||||
foreach([
|
||||
Facing::rotateY($this->facing, true),
|
||||
Facing::rotateY($this->facing, false)
|
||||
] as $side){
|
||||
foreach([false, true] as $clockwise){
|
||||
$side = Facing::rotateY($this->facing, $clockwise);
|
||||
$c = $this->getSide($side);
|
||||
if($c instanceof Chest and $c->isSameType($this) and $c->facing === $this->facing){
|
||||
$pair = $this->position->getWorld()->getTile($c->position);
|
||||
if($pair instanceof TileChest and !$pair->isPaired()){
|
||||
$pair->pairWith($tile);
|
||||
$tile->pairWith($pair);
|
||||
break;
|
||||
if($c instanceof Chest && $c->isSameType($this) && $c->facing === $this->facing){
|
||||
$pair = $world->getTile($c->position);
|
||||
if($pair instanceof TileChest && !$pair->isPaired()){
|
||||
[$left, $right] = $clockwise ? [$c, $this] : [$this, $c];
|
||||
$ev = new ChestPairEvent($left, $right);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled() && $world->getBlock($this->position)->isSameType($this) && $world->getBlock($c->position)->isSameType($c)){
|
||||
$pair->pairWith($tile);
|
||||
$tile->pairWith($pair);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,8 +80,8 @@ class Chest extends Transparent{
|
||||
$chest = $this->position->getWorld()->getTile($this->position);
|
||||
if($chest instanceof TileChest){
|
||||
if(
|
||||
!$this->getSide(Facing::UP)->isTransparent() or
|
||||
(($pair = $chest->getPair()) !== null and !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) or
|
||||
!$this->getSide(Facing::UP)->isTransparent() ||
|
||||
(($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) ||
|
||||
!$chest->canOpenWith($item->getCustomName())
|
||||
){
|
||||
return true;
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -39,6 +39,9 @@ class Cobweb extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
|
||||
return [$this->asItem()];
|
||||
}
|
||||
return [
|
||||
VanillaItems::STRING()
|
||||
];
|
||||
|
@ -17,7 +17,7 @@
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\block\utils\TreeType;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
@ -41,6 +42,8 @@ use function mt_rand;
|
||||
class CocoaBlock extends Transparent{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
public const MAX_AGE = 2;
|
||||
|
||||
protected int $age = 0;
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
@ -49,7 +52,7 @@ class CocoaBlock extends Transparent{
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = Facing::opposite(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
|
||||
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta >> 2, 0, 2);
|
||||
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta >> 2, 0, self::MAX_AGE);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
@ -60,8 +63,8 @@ class CocoaBlock extends Transparent{
|
||||
|
||||
/** @return $this */
|
||||
public function setAge(int $age) : self{
|
||||
if($age < 0 || $age > 2){
|
||||
throw new \InvalidArgumentException("Age must be in range 0-2");
|
||||
if($age < 0 || $age > self::MAX_AGE){
|
||||
throw new \InvalidArgumentException("Age must be in range 0 ... " . self::MAX_AGE);
|
||||
}
|
||||
$this->age = $age;
|
||||
return $this;
|
||||
@ -81,12 +84,16 @@ class CocoaBlock extends Transparent{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
private function canAttachTo(Block $block) : bool{
|
||||
return $block instanceof Wood && $block->getTreeType()->equals(TreeType::JUNGLE());
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(Facing::axis($face) !== Axis::Y and $this->canAttachTo($blockClicked)){
|
||||
if(Facing::axis($face) !== Axis::Y && $this->canAttachTo($blockClicked)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
@ -121,7 +128,7 @@ class CocoaBlock extends Transparent{
|
||||
}
|
||||
|
||||
private function grow() : bool{
|
||||
if($this->age < 2){
|
||||
if($this->age < self::MAX_AGE){
|
||||
$block = clone $this;
|
||||
$block->age++;
|
||||
$ev = new BlockGrowEvent($this, $block);
|
||||
@ -136,7 +143,7 @@ class CocoaBlock extends Transparent{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::COCOA_BEANS()->setCount($this->age === 2 ? mt_rand(2, 3) : 1)
|
||||
VanillaItems::COCOA_BEANS()->setCount($this->age === self::MAX_AGE ? mt_rand(2, 3) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user