mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-12 20:35:11 +00:00
Compare commits
1364 Commits
before-psr
...
3.19.3
Author | SHA1 | Date | |
---|---|---|---|
afb21c1df2 | |||
988be2a96b | |||
afe67f7502 | |||
b257348a3a | |||
12c66d3362 | |||
92fd2d35a4 | |||
61077c48f1 | |||
e0c61071e1 | |||
813d431208 | |||
ee112b992d | |||
c9b33e2b9f | |||
2f2be84b12 | |||
5a7736b179 | |||
e648f1c91e | |||
5116e11cea | |||
9c05e37fbe | |||
fb4796f35e | |||
0c2ba66078 | |||
c29cd8e2eb | |||
a13b0c98a1 | |||
e6ff908e18 | |||
c47ecb55c0 | |||
c19d2fe891 | |||
f195f24f4f | |||
4b5f279a3e | |||
89260d788c | |||
a7cd081002 | |||
361be8fe36 | |||
b01e4ab417 | |||
177b963d8e | |||
8d1a1628de | |||
6f80b8979d | |||
3c8eb29d4e | |||
b94bbf6f5e | |||
314a8a1297 | |||
547503e8f4 | |||
f74ff1fcd4 | |||
6c351357ab | |||
3433406cff | |||
b307cd0aa1 | |||
c9b83d7276 | |||
e22b6ff566 | |||
af88f49a21 | |||
599d5253db | |||
54cb5ee0fa | |||
cdae8b42eb | |||
a45a4a91ae | |||
21378b7f27 | |||
502aed41b0 | |||
125837324f | |||
609dff1aae | |||
b03212053c | |||
fd4ac885bb | |||
f35886f18a | |||
a9eaa55427 | |||
5c41f79be4 | |||
34c2b62ffe | |||
e42a691da9 | |||
3b3fb5e662 | |||
01ffe8bf57 | |||
4abf4aecad | |||
b29f83ee99 | |||
4bc57f00b8 | |||
ff61e1e018 | |||
fb20bb3832 | |||
3333df31df | |||
c09fcb2df2 | |||
c7cdaeae85 | |||
4416cd5a28 | |||
cb93095857 | |||
c8f396ecbc | |||
cb06be615a | |||
0d3c11699c | |||
3667e95ff6 | |||
0e2dc51ec8 | |||
eaf85b028a | |||
9479a1a0ab | |||
1bb2d162ab | |||
ee868bcccc | |||
cbc8576d4a | |||
edcf296086 | |||
9e27c47116 | |||
a0368a843e | |||
3f64906263 | |||
19bb8a00df | |||
4816a66fb8 | |||
06f4e1e4c2 | |||
5b8166c1f0 | |||
30c5cad5b3 | |||
a7a7fe3895 | |||
55ac2f07dc | |||
0660888029 | |||
0476e6bcfc | |||
72bd37e442 | |||
f95fcecb5b | |||
61391b6e23 | |||
fbb6f1f81c | |||
712df04bc4 | |||
1563e25378 | |||
ed84252942 | |||
3d90625020 | |||
9f6b914925 | |||
0e614ea8fd | |||
401bd09d60 | |||
649671cc69 | |||
e755e1dc23 | |||
e34a444dde | |||
78f9985377 | |||
fac2bd3379 | |||
fcfd51dfc7 | |||
ccc76cf338 | |||
10a73488ed | |||
9c5114084b | |||
11630ab1aa | |||
a3068b39a2 | |||
edbc73a72c | |||
3a0c8dd594 | |||
16fa26405a | |||
57423540f0 | |||
8f8821c904 | |||
094102fe92 | |||
2aef83e7d7 | |||
5c3e78e1d3 | |||
18666e5a60 | |||
f72163c173 | |||
7407e504b6 | |||
0e396dc47d | |||
d2204da1d5 | |||
2a51269305 | |||
928041ddf1 | |||
007f4f9350 | |||
46e9f0cec6 | |||
606d56b55d | |||
78a62a8b27 | |||
c5bdd7dd64 | |||
8ee37a3033 | |||
7e3e63f342 | |||
8ef1e54e20 | |||
eaf3a86981 | |||
317a48d9b0 | |||
bc14660e55 | |||
b1bb9fbd1c | |||
96181f8cf5 | |||
4771e3dc28 | |||
2e9117d102 | |||
06493da7d9 | |||
bd303b1062 | |||
fe731b9018 | |||
1a24afc6d1 | |||
bef906b0f0 | |||
37e8dd6444 | |||
02ee0f23c0 | |||
cda472333c | |||
47cf58be8a | |||
ccf9691927 | |||
16fa958416 | |||
bac57c159f | |||
38b2d83799 | |||
c134b1cd8a | |||
62deafda48 | |||
31b6df4376 | |||
b296ae1b87 | |||
f9e42b716a | |||
34c1d455a7 | |||
af8936dba5 | |||
e8ffab1787 | |||
ecc1e1f698 | |||
ea5931e274 | |||
988cf7f535 | |||
e156fb47e8 | |||
efc5f34877 | |||
dd0d8842d5 | |||
7bdc564ccc | |||
69fff23f1a | |||
ae43698e88 | |||
0987e03c03 | |||
97c124edf9 | |||
56501178b7 | |||
da663deea1 | |||
972c911485 | |||
0d8858f948 | |||
da71540fce | |||
ec9b39862b | |||
efca8077d5 | |||
5066d5225b | |||
aefaf73685 | |||
15401d740f | |||
5920b0ba40 | |||
dea75a0687 | |||
873e8740e0 | |||
260c55f23a | |||
9ed430acb9 | |||
f0241043de | |||
135f1c95e4 | |||
5431807e43 | |||
d49ae832e8 | |||
ff9d013005 | |||
b0e1317818 | |||
8653afb0fb | |||
995b56aaa0 | |||
3ecddf312d | |||
470243ca6f | |||
3f21e59917 | |||
fdd74a4f46 | |||
a43b46a93c | |||
0604dfc9e5 | |||
dd2c3db285 | |||
c95e283507 | |||
6afbd1f55c | |||
0682c93f5a | |||
da90ae85da | |||
e87127f309 | |||
0237a50d90 | |||
8b53e4150e | |||
1c43538238 | |||
68887105b2 | |||
104e90b794 | |||
994062f6dc | |||
69a41a5ed4 | |||
3903b70ef5 | |||
692e63ad7c | |||
4d1be4d41d | |||
5f0310a8b6 | |||
9b01fb3d89 | |||
f28405fcfb | |||
9c07c206f6 | |||
d0d701f232 | |||
07cae8a129 | |||
6869ee1c2d | |||
26155acff2 | |||
b550cf5163 | |||
48fa19fdcd | |||
bac986d0b2 | |||
215bac8dd7 | |||
3709ba172b | |||
ef034f2d68 | |||
ab18332572 | |||
48595630fc | |||
4102205ba6 | |||
9e85ee4a7a | |||
e8e6b9304c | |||
23849b7f63 | |||
d2f68836c6 | |||
d19db5d2e4 | |||
98cdc80d37 | |||
8273f789ee | |||
29eccba5f0 | |||
9984b15de6 | |||
6ea01e0dd4 | |||
46331df7db | |||
691c49fb32 | |||
db815360d1 | |||
6e297168c2 | |||
95dbb00d4c | |||
50e29a5ed8 | |||
9f3fb935b5 | |||
e30b1ee2c7 | |||
574b7f6343 | |||
e8b6b56330 | |||
c368ebb5e7 | |||
fa920aa868 | |||
a421d32273 | |||
6c21c23444 | |||
55e0d9c520 | |||
37ee3f2775 | |||
bfdcc12e81 | |||
b2299e08e0 | |||
d7741050c5 | |||
6cff08cd65 | |||
fec42f16ba | |||
deb0cee8a0 | |||
c0dafe7872 | |||
340881d590 | |||
e2e960e43d | |||
500fd2d842 | |||
0b550b346b | |||
1424114cf2 | |||
a8980a0f67 | |||
69aa7c5ac1 | |||
11b74868ee | |||
9a53de0903 | |||
0f8101d4a6 | |||
55ecac4c80 | |||
2a1d1e90a2 | |||
4444a79468 | |||
4cbeee3ab8 | |||
a251960c1c | |||
52f734799e | |||
42171f6e06 | |||
1fe4fdc67c | |||
af4f30d1c8 | |||
3e2926441d | |||
0b33762be0 | |||
e6f89213dc | |||
f8d249b240 | |||
b39afa20d1 | |||
7027a9b972 | |||
b02f3f4090 | |||
8564912149 | |||
873535f719 | |||
78f4fcf6ab | |||
90b749c260 | |||
d5398b2781 | |||
d7a66ad755 | |||
b3f88e7b73 | |||
55adc1ef63 | |||
868d236ddc | |||
59e9c84806 | |||
a110317d1b | |||
b169d89291 | |||
74bef7f423 | |||
8db7867881 | |||
d8f8afe531 | |||
7dabf305f8 | |||
ed0053d0ee | |||
28255e35d1 | |||
0fc9170bbf | |||
7e2efae024 | |||
e9fa07b550 | |||
8ac32824a2 | |||
1322defead | |||
d084b7a34b | |||
c2d0605b1e | |||
0ff0b33047 | |||
114df07622 | |||
4a88db7f43 | |||
d3ea29d527 | |||
d2f1a3cf5b | |||
f9c2ed6200 | |||
e47a711494 | |||
2ea7a9e216 | |||
9f60484212 | |||
3031d89ec5 | |||
883e135bc0 | |||
4448f603a6 | |||
9365525efa | |||
17bee5e349 | |||
c6e0753c3e | |||
2ae7ba275b | |||
6aa0a82341 | |||
0af08a7375 | |||
81c1613e5d | |||
9cf8f608d8 | |||
dd4f26a9cf | |||
f976545f56 | |||
9929fb0abd | |||
37e453b875 | |||
b7578fef9c | |||
09eb904f6b | |||
b47d6bbc22 | |||
aa26ddf8b1 | |||
119c72980f | |||
eba888449d | |||
dac76f0e0f | |||
89fe8f7f10 | |||
2d77b1e364 | |||
e59a4296f8 | |||
6856761946 | |||
4fe3401182 | |||
e80ad22702 | |||
c22ab37372 | |||
1f9d672cfc | |||
974cbae725 | |||
b53f88027e | |||
9a0f723dff | |||
ab2003a85d | |||
4befd9095a | |||
06623d788a | |||
730ee74a65 | |||
700e0afee0 | |||
4b9712fdee | |||
dbd015b866 | |||
a498b0415a | |||
5b01cf72dd | |||
ec21c2baa0 | |||
11a0d9b502 | |||
a7fc245291 | |||
6db51e2380 | |||
d6f35f2342 | |||
d1df72ec78 | |||
9bd6d5c67e | |||
aaa23361d1 | |||
691d92a959 | |||
50101663f2 | |||
e369966890 | |||
63f57841de | |||
ac3bba0a11 | |||
1ff3df6ff0 | |||
4e29b216bf | |||
809dad2ac8 | |||
e238d583b8 | |||
3f89bd7bff | |||
8da7e789fd | |||
0766952f39 | |||
eeee1fbe73 | |||
46c224da86 | |||
3c001b310f | |||
198a106b9f | |||
1f5e0bc96d | |||
41f7c07703 | |||
f0a0c9a85f | |||
5b620d964e | |||
756840f11d | |||
df2c3136c9 | |||
a6b5cddd5a | |||
5b9453af43 | |||
8bba25f4f5 | |||
f9bd7016aa | |||
213406fc60 | |||
7ff6e5895e | |||
2e6b62fdec | |||
4fc5b9772a | |||
5d4880b0a7 | |||
2b1a0e1e72 | |||
cd022f1592 | |||
4ae3fd7734 | |||
b2249f93c0 | |||
303344783a | |||
75e0844ff5 | |||
18fabf5466 | |||
2751c59979 | |||
d99ffbd66c | |||
a34f3261cb | |||
8ce0022de6 | |||
fb6491ddeb | |||
3b961d0e5f | |||
a60fc4cc28 | |||
b747899fdd | |||
57b6451e16 | |||
8cf025a2df | |||
8480ee82ea | |||
a6c1b7bf9c | |||
c267137fde | |||
461bc94236 | |||
4fed08bcd4 | |||
e990c5a0a5 | |||
c616d9bb7c | |||
81051441ba | |||
3ecae0db19 | |||
c5bbb2bcbc | |||
24a2889758 | |||
60b26a7ea8 | |||
22b52f03d1 | |||
df76c02e7a | |||
d343187e58 | |||
c5ad127854 | |||
0f6dc9082a | |||
2b6dcbc2e2 | |||
763c8ebfe3 | |||
c572e9bb6a | |||
89521f166d | |||
49d3a42120 | |||
c523595e85 | |||
7c7e4f2093 | |||
88c1014f03 | |||
e32180ce93 | |||
e105578be0 | |||
a9d98bdf73 | |||
c601352777 | |||
77c71e22b2 | |||
1c13ba5656 | |||
f970be0e4d | |||
11a3f9f1b9 | |||
09771849ae | |||
57a310230a | |||
130c55d9f1 | |||
2712befa82 | |||
a4e250a3e6 | |||
23b97d8e2d | |||
1fb5043eb1 | |||
b0b1b29de4 | |||
1c3b641e37 | |||
f3063e797f | |||
8dcc88712c | |||
04191ec44a | |||
62ea7c93a9 | |||
cf06b5b8cf | |||
a8ec51daac | |||
6a7b77fee2 | |||
da42c8d020 | |||
b902f9ded0 | |||
9bb8a8f761 | |||
63b14a083c | |||
627a7c951a | |||
bb2685ca65 | |||
d38709a7ae | |||
b559a65346 | |||
b92a2ded8a | |||
22f25dfbdb | |||
6bf840c72e | |||
745be19a56 | |||
e05bee5ffb | |||
087ba0cc1d | |||
d8d994351b | |||
0029efa370 | |||
df13e967fd | |||
097c260dbb | |||
a219b727f2 | |||
710c162604 | |||
409c8c1703 | |||
376926c700 | |||
c3fabe833e | |||
3e09ff5350 | |||
7255065106 | |||
a7f10d8ccf | |||
76f1add3b3 | |||
fcc9e62c65 | |||
42613618a5 | |||
1bbeb62457 | |||
64893426fa | |||
3d50aafcc4 | |||
50fed41642 | |||
3f971a0c65 | |||
a27b29897c | |||
a90132a30e | |||
dfbd857771 | |||
323d96d5c1 | |||
f495ba1d0b | |||
643cf0ebf8 | |||
1614206a6d | |||
0ae2c6302a | |||
4f59c1b26c | |||
00916ade0c | |||
f4ee2912db | |||
a0de9b0d46 | |||
03e8cd3ed4 | |||
7af4e70f64 | |||
c864647cd1 | |||
92ed9e6125 | |||
c32026333f | |||
915224c8e5 | |||
734bc6c4a7 | |||
d36b24c518 | |||
d554d8060b | |||
b48243fd09 | |||
5c63e06b0f | |||
3be83e09f2 | |||
f24be2b055 | |||
92cffc00d0 | |||
e87e974323 | |||
a3f6338626 | |||
21aef97ba7 | |||
ed0d1978aa | |||
d64561b0b1 | |||
d234d3e45e | |||
5056754cea | |||
2dc3cf8162 | |||
8c5a81cf5c | |||
2b58f2bafd | |||
5dadf12374 | |||
0d4e473bdd | |||
11cedc4011 | |||
3f2455f090 | |||
9d26a224a2 | |||
c4ad390463 | |||
42e14f749e | |||
484557935e | |||
485f573955 | |||
71e0521286 | |||
3f07f06874 | |||
10279e11ed | |||
673e444456 | |||
89c49d77c6 | |||
c3a795e876 | |||
4199c3796f | |||
ecbf21acea | |||
45c89d084c | |||
56f90a2901 | |||
bf6af269c8 | |||
73d1f84072 | |||
a29424f5b3 | |||
ff3af492f8 | |||
80b804f7aa | |||
3a78735982 | |||
ab32784c74 | |||
816234a379 | |||
b7bf92a5e9 | |||
dcca000ead | |||
c4ea51f985 | |||
8202bb1cd8 | |||
b75758e35e | |||
38a06f76f8 | |||
84f99ed418 | |||
fd63f19199 | |||
66d44aa814 | |||
f3089f577e | |||
9516ef1632 | |||
e982a57cb5 | |||
f57fa2252b | |||
02cc370855 | |||
0a5d14a840 | |||
3ec2994d7f | |||
da4a2d8552 | |||
dc9351b024 | |||
786f416f2e | |||
a67d2ae978 | |||
089180fef4 | |||
15baf09339 | |||
083dde8395 | |||
fffa4b9501 | |||
22b5de09b4 | |||
71a8b0340c | |||
e544055bbc | |||
8f5db7c297 | |||
a5edfa368e | |||
27f55e4c96 | |||
9b6b3f50a1 | |||
1fb0ba6fc0 | |||
f1d378468e | |||
9ebd6d6b0f | |||
58e32086c0 | |||
8c0d441a13 | |||
25fb5140a2 | |||
f5a49b6d55 | |||
189f12a644 | |||
5a8917f6f2 | |||
f3e436592a | |||
35747874f6 | |||
59445902b8 | |||
2eb62c85f6 | |||
ad2a39bf13 | |||
0847358070 | |||
8766d4050c | |||
54f41dc145 | |||
ded45bddfe | |||
b044550475 | |||
a70fa15690 | |||
bd1d7b8d75 | |||
1513a0e092 | |||
c4150d4520 | |||
2f47597d75 | |||
56883f9ff9 | |||
7cdd26add5 | |||
717b866605 | |||
ef97c8f99e | |||
84932ce908 | |||
6bfc309a0a | |||
06e8c6a3ad | |||
71271a0e03 | |||
f87e96026c | |||
b63ad032a9 | |||
d9b0e373bb | |||
8e1b3edd2c | |||
32262d9bb5 | |||
4c1b10b24b | |||
61dc9d7f6b | |||
da9731ef59 | |||
e6f64c609e | |||
8c7fbf379b | |||
3d2ca457f8 | |||
1579f41056 | |||
34a3e0d8b1 | |||
d42217ff57 | |||
70a4f73d73 | |||
7d43dffac4 | |||
804a062c3a | |||
22a4639162 | |||
39d02a67d2 | |||
77d45bf116 | |||
f79182852b | |||
a107ad7404 | |||
7a072931df | |||
f428a9bf52 | |||
2e720b48d9 | |||
a6e79bedf5 | |||
a5ba570fdf | |||
0d5164af02 | |||
534af770f8 | |||
619a9892e5 | |||
63b109f23e | |||
79ed377c7a | |||
2da8ce7a20 | |||
959dd4cbf1 | |||
0a3788f9ac | |||
cdda74ef93 | |||
bbe428a874 | |||
755919c496 | |||
88b216a17b | |||
8020912448 | |||
5571ae05b5 | |||
bc985198a0 | |||
27b2710c56 | |||
1755b25808 | |||
a78133d0e3 | |||
a51a16a55c | |||
099562d582 | |||
ae76e8f08f | |||
42a08e7e4a | |||
b193d9f919 | |||
24d64eedab | |||
0c9d16f1ef | |||
d246933e3e | |||
41d7b8c0e4 | |||
2622c34542 | |||
5c9419b55c | |||
83c40f4502 | |||
372202b3dc | |||
917c744266 | |||
2281fe4e67 | |||
cf538d83bf | |||
7e9c38a9d9 | |||
ccad97727f | |||
e3ebf8bb61 | |||
cb6b59a52a | |||
53dbbd5f97 | |||
51908ec45a | |||
a2543ff80d | |||
20f3030709 | |||
3aa58f54dc | |||
6e08b622b3 | |||
5c12a95151 | |||
604900d4c5 | |||
5f07c5df1c | |||
6422ed7722 | |||
5f33ef35e3 | |||
ec949840b2 | |||
e45e84b236 | |||
dfe68c9788 | |||
35b8f0bf25 | |||
d4dc1c8a0c | |||
517f9a3c3a | |||
636c35dcf1 | |||
d22f0da1de | |||
310de5a2b2 | |||
06a9c98ded | |||
5c7b05c2ba | |||
9c86763322 | |||
35490ca41c | |||
47c7872c88 | |||
f84abcd1fe | |||
b5dd147ec7 | |||
f8ce01e2fd | |||
3907a2b6ba | |||
0dd68e587f | |||
1171cd2493 | |||
330e93e5e3 | |||
e2579e0a2a | |||
2020fcd18e | |||
5a9a576bfa | |||
b8caf34e62 | |||
456d9a722a | |||
344c980cff | |||
167492087f | |||
db215283a2 | |||
6a507bb149 | |||
dc757c25c8 | |||
73267ae077 | |||
a72e6ee706 | |||
8ec0a4d0d6 | |||
89ea7f0a76 | |||
df65f1009c | |||
a6ca37429c | |||
4bf9fb278b | |||
15d81154e6 | |||
93e5c80962 | |||
c19ab97610 | |||
dbaf851be7 | |||
7aa8bd18d3 | |||
53067c26d7 | |||
04581e2700 | |||
93597dcd50 | |||
778814a35e | |||
3cd1da196a | |||
365d4a1592 | |||
2d7f37ac47 | |||
50fcdd6e7e | |||
10317527e4 | |||
46ac4cbca1 | |||
cb9e79b398 | |||
2f1fad2745 | |||
44182dccbd | |||
2f3d2d4a0b | |||
8ac7f7f11f | |||
dbe7caab7b | |||
b581fab31a | |||
7b7dfc36d1 | |||
d63d6b73f6 | |||
a860ccd259 | |||
2bb497b716 | |||
613bd40601 | |||
398b636759 | |||
19bd283807 | |||
20d1a048dd | |||
15b76a24b7 | |||
2d51971b84 | |||
f08e411cad | |||
1257378198 | |||
758a68aa2c | |||
bfce478e72 | |||
681dd469a2 | |||
3edbea8545 | |||
ada8cbb545 | |||
0ac5e03ce9 | |||
9b02b8e51e | |||
6c7dada232 | |||
25bc95cd1e | |||
213bf8366a | |||
4e693e91e6 | |||
a1622fa345 | |||
0ec869932f | |||
79acaa3253 | |||
da3742b39e | |||
d26fcf7dee | |||
812424a619 | |||
1bdc61dd5f | |||
86fc33fe26 | |||
70eb41470c | |||
3a5709bf5e | |||
5ad66c3c9b | |||
7885b54824 | |||
532dc0fb6f | |||
54ccc330d5 | |||
e12618c705 | |||
7d5f2eac8d | |||
e964dd2ca8 | |||
dbb594f130 | |||
8f434b9edd | |||
34972c3327 | |||
037c34d961 | |||
4518d9d9ce | |||
1a5228e7a6 | |||
495bfda044 | |||
41b1fa7b48 | |||
e689fd545b | |||
889cd5e206 | |||
e1ddf90695 | |||
2f325b8c91 | |||
ac4f00be81 | |||
914450c30b | |||
25554f0d61 | |||
e1a61cb51a | |||
fe5620f097 | |||
faef4e8736 | |||
0d19f6c968 | |||
ecf662bf74 | |||
8cba2e0346 | |||
dfc8a6ffdd | |||
262728b091 | |||
4572ec8175 | |||
0f6949ac34 | |||
df8e0cf1f5 | |||
ad87c11ae1 | |||
fa82cb26d8 | |||
fd2a7797bd | |||
e5a2cfb65f | |||
b96bb7d824 | |||
896cca0778 | |||
59cf8e95f0 | |||
99038c752c | |||
88afedd1e8 | |||
c43e21235d | |||
3f7e7352fb | |||
32d6ea0fba | |||
28c787371a | |||
dba14c9f08 | |||
0e35ee8cb7 | |||
da5b7f47df | |||
d418dd7a09 | |||
f3209ccc33 | |||
4a4c28cd8c | |||
eba8d77034 | |||
13e4772f98 | |||
4bc2f28c6d | |||
663469dfa7 | |||
963abb718f | |||
1f2fb73297 | |||
ff55b520b9 | |||
cedd8abf0c | |||
496732999c | |||
6a8105f5a0 | |||
0a566f8218 | |||
829dd02eea | |||
b11c350b2b | |||
f624e36faf | |||
14ce9c10bb | |||
b27aaaeeb2 | |||
f1083bd9c4 | |||
199fa61aef | |||
af82a6bbe1 | |||
004f7ef82e | |||
89ebd2b880 | |||
799183e13e | |||
260ac47588 | |||
4ff4434a22 | |||
5d8bb84269 | |||
9eebfa7cc3 | |||
d3021c6281 | |||
9097d6c4d3 | |||
da43ae82fe | |||
60b405d944 | |||
92a752053d | |||
0537c66849 | |||
d94995e161 | |||
58bc08838b | |||
fc0619ee6e | |||
a5764b3ae9 | |||
8bf469f7fc | |||
3b9a5c5ccc | |||
4c36ca58e2 | |||
a67fa5c007 | |||
839a789180 | |||
e61c3e8bf6 | |||
7ce6c8aa13 | |||
9abcc99c10 | |||
5c8a625d88 | |||
259f0425a9 | |||
9cdea43794 | |||
e007fad5b8 | |||
5cf2fcbbb7 | |||
9e6cbb5b6a | |||
64b3d02974 | |||
640df1003c | |||
2b402e525a | |||
e2871fad8e | |||
41d02003c2 | |||
156ecd9bd8 | |||
fa7736efbb | |||
d71a7ff2fa | |||
8184a6b114 | |||
b8d44ff162 | |||
f6611a38bc | |||
24ed823d96 | |||
f624871b3f | |||
9cd6b3e1c7 | |||
aad1eb5b3e | |||
bff5bf25ae | |||
cda90fd7f1 | |||
9f44adf04a | |||
c4793241f5 | |||
7532c609fb | |||
13f28d8454 | |||
5a97c378fc | |||
e5d62ec901 | |||
cfd975009e | |||
73257ffde7 | |||
8252bea699 | |||
ea935a1af5 | |||
e8a5fa8a37 | |||
db734675d8 | |||
6ede56015d | |||
5334099fbf | |||
82e9072223 | |||
2c11742f9e | |||
bd4a63b668 | |||
cd36af46bf | |||
aa7d55e21d | |||
31e8efa6d1 | |||
facca13139 | |||
fffeeddca6 | |||
e6ba3ce8a6 | |||
11cae2f0c0 | |||
f5a18df835 | |||
1cc7027f92 | |||
8776b71d63 | |||
0b9d0f3cdc | |||
e419d76367 | |||
36cde9f352 | |||
05c602a044 | |||
0db7e57a15 | |||
205e47c0c4 | |||
e328d00cca | |||
ccbcc14600 | |||
e544bc0d4b | |||
fd27227cc7 | |||
b42966f61b | |||
ca86ec2ec2 | |||
97b6183404 | |||
0587d03c03 | |||
c7f1b605f2 | |||
f069df65a8 | |||
1e624e7bb9 | |||
f16a530849 | |||
7137b8a8a4 | |||
ab57914322 | |||
260869c0d5 | |||
9135877da1 | |||
07cb603231 | |||
f59094e6d6 | |||
d8acae5495 | |||
239fe909be | |||
c22576a266 | |||
bac788fd00 | |||
f6d96c5827 | |||
b1458db47b | |||
2d2c9379cd | |||
3400771770 | |||
e12ecaf629 | |||
1303cbfe02 | |||
ad4a211cba | |||
d1e56c4611 | |||
d9bbab54f4 | |||
07cf4eb7a9 | |||
50a7663369 | |||
651ef500a3 | |||
30f2e75278 | |||
2cfc25b4f8 | |||
5bded9cff8 | |||
5816ff85ba | |||
8f7d8347ee | |||
3614d9a78d | |||
818d0e19ab | |||
17720041a3 | |||
c329ff7d4f | |||
8794292788 | |||
0a39e580e9 | |||
c4580dd56d | |||
fab81d28bc | |||
039478223e | |||
64b5db4bf2 | |||
c85f4256c7 | |||
1192b8bdf1 | |||
6dcd2a4ece | |||
3fff0a0656 | |||
e1e1bfa5e3 | |||
1eedac87b2 | |||
cda3e6f4dc | |||
e6a58e2690 | |||
27350c4673 | |||
0d5704b156 | |||
f355044626 | |||
4794ba236a | |||
6490a49c70 | |||
5cd7e11b29 | |||
08e3b8ffdc | |||
9232f4509c | |||
cef77907c6 | |||
06ec8b8397 | |||
ee08286eca | |||
a83211f96a | |||
0b3c4ee496 | |||
54de518634 | |||
a908197907 | |||
3e23a568ca | |||
dadc5c1b87 | |||
a37d740111 | |||
2de0ec02ba | |||
d83820477f | |||
8726604899 | |||
9cbe378e8c | |||
494660102e | |||
216138a37e | |||
b08c38f8f9 | |||
911b6feaf9 | |||
2cb6990698 | |||
f7d66613df | |||
95c32d26df | |||
9e1f6a2486 | |||
870c66d1fe | |||
76994f15ac | |||
cf73d74bd0 | |||
37a8d95464 | |||
9a4b72add5 | |||
919534d978 | |||
cb598155a4 | |||
00888fdc55 | |||
77795ae3bc | |||
f39fc7e525 | |||
77f7595e0e | |||
e8d3a25028 | |||
1370930ea9 | |||
1a467420e3 | |||
70c3008b7b | |||
46930b98b7 | |||
92be8c8ec0 | |||
62069bc7af | |||
26230c1f9b | |||
a9fafbc5eb | |||
b8778cb791 | |||
73c5fe5cf9 | |||
b3cfa5a3a0 | |||
6127a02a8b | |||
dbca36e5e2 | |||
1171bae691 | |||
494f8e8251 | |||
3c9af56e06 | |||
40a2211a5a | |||
0196aa21d7 | |||
833f3e574b | |||
a386ff8ce7 | |||
e6c3b0fc0d | |||
9568364277 | |||
73d4ff6b52 | |||
7e98aa1497 | |||
f00c69c513 | |||
50a4c42f3f | |||
6b61efcfc8 | |||
1a99938e4b | |||
a4d68fb32b | |||
02fcfcc383 | |||
5682cc8d53 | |||
4eb59c0372 | |||
3486db3f1b | |||
733d530ed0 | |||
c10ce84035 | |||
82d9e481d2 | |||
d27c7f7141 | |||
394c999710 | |||
6399dacba7 | |||
b6bbf655d7 | |||
3d2c018442 | |||
da8c54cf8b | |||
8e984a1bc3 | |||
124e60301a | |||
4d13c48e5c | |||
9159e8f002 | |||
f5aa461945 | |||
16817ff301 | |||
18863b1098 | |||
e3cffca34b | |||
d20d9fb689 | |||
09961b5cd0 | |||
7b1ae2a822 | |||
8ecf5e02b9 | |||
39c607cbd5 | |||
d867ffc60d | |||
71a472e0eb | |||
c57eb26fd5 | |||
c35d91a104 | |||
9fc260fb1a | |||
e65bc5c3ae | |||
73d0f799c2 | |||
ecb2e6e3af | |||
7b75b6928d | |||
753a8a6937 | |||
bc76b1cafe | |||
2ae37cc1c5 | |||
00e415fc79 | |||
9a67192f74 | |||
dbbe1f2d5c | |||
740f0a2314 | |||
7fdfe947b0 | |||
b7c4379700 | |||
20b7418916 | |||
85521f5e7a | |||
f37ea6a203 | |||
abf8081ebc | |||
8594cb3e74 | |||
d155de35ed | |||
e37c8e3a5d | |||
e38c0c0fe1 | |||
ce27c03774 | |||
c4a8781b5c | |||
dbab8b5733 | |||
2b08bbc7b1 | |||
17037f5e9c | |||
fee3c17148 | |||
25e6cb74b3 | |||
8d2e59222e | |||
cd778661c2 | |||
c2afc05e7c | |||
9be95bf263 | |||
4b65e1cbe1 | |||
5caae37768 | |||
92e1811b06 | |||
293c2710d0 | |||
8a7017fd6b | |||
15f8886958 | |||
3226a9dc6a | |||
1a1e3ff63b | |||
ea413d0882 | |||
0890b5fc99 | |||
163ed225f2 | |||
a4a6d3e094 | |||
ecbf3e9722 | |||
47a959dace | |||
3968f85c82 | |||
d8188b807a | |||
8e68655fc7 | |||
6d109bfc6f | |||
b7a5a53c9d | |||
76bd0f452c | |||
363556e9b6 | |||
6f08853b29 | |||
42d8357821 | |||
4cfceeeb8e | |||
3e4e0d51df | |||
f2ac63d235 | |||
5d17405b92 | |||
3dd53ad998 | |||
a303c4b294 | |||
fa56290bb4 | |||
01d6cbe9c3 | |||
f682c16740 | |||
74c09dc202 | |||
0917b67573 | |||
5cb0eafcb2 | |||
221e6db47d | |||
8d06018d81 | |||
600e16d9f6 | |||
4340349db7 | |||
cb76f8a5df | |||
6105198313 | |||
c96ba13c23 | |||
c8d0cb315b | |||
be9c413a9e | |||
3e4366b30d | |||
7f3460190b | |||
10d44292e1 | |||
70f81334ae | |||
ead572fab9 | |||
ef8e286277 | |||
ba5a5981a0 | |||
c428596009 | |||
a81d8dd6d5 | |||
5bcbef90ea | |||
1c67f094e3 | |||
99d350914e | |||
49a9e0a880 | |||
7b152def7d | |||
3eb78fb0ff | |||
38c759c86e | |||
314ce1d012 | |||
7fcd40df15 | |||
ba39327b28 | |||
8d2e3894ef | |||
8ee0fbccc5 | |||
fe4354959b | |||
19377c86a4 | |||
fb23aade34 | |||
57e9fe78a3 | |||
6b97281c58 | |||
da67a085fc | |||
e2fc7cdf88 | |||
635bb08fb9 | |||
308d9ce3a8 | |||
5a76c38363 | |||
54530da6c1 | |||
dd55a0bccd | |||
f03bd982b5 | |||
025cb73bf5 | |||
2a6ffb5aa9 | |||
d53b84386f | |||
a7ed933b37 | |||
29cc9283f8 | |||
e60962c31f | |||
f6b5301e17 | |||
73b923e3a1 | |||
d2e4eb40b3 | |||
6a31628e78 | |||
bfb1ad1327 | |||
dfa603c335 | |||
eef979db4c | |||
6166c90bfd | |||
35d1d0080a | |||
3bacb1a9cb | |||
898af49e97 | |||
3061eb4157 | |||
b8d1d8f212 | |||
8c6189775b | |||
932418b951 | |||
95812252d6 | |||
7dec912d15 | |||
dbd36d66ae | |||
40b4166a6e | |||
51d18ffb89 | |||
af3c7b7c76 | |||
3511ac010d | |||
cac3c356a5 | |||
07f19dd4a1 | |||
17a17c31f3 | |||
75742b487f | |||
4e9a2b6d8c | |||
4ea907ae1a | |||
8b912c1363 | |||
080209c469 | |||
5b11ddee35 | |||
3b7ded0ba3 | |||
c5d3e9be76 | |||
714f4dc023 | |||
a86bcd5110 | |||
7ffc477d76 | |||
4cb0b319c0 | |||
5ebe9859e9 | |||
cd2b60a860 | |||
5edff79f5f | |||
0c91d568b4 | |||
35fabc7765 | |||
b5a98a993f | |||
0840ba8067 | |||
274cf58ccf | |||
1bce5d0bc2 | |||
0d5d5e21a8 | |||
a145e18c1e | |||
d1ca779c1a | |||
abbb8bbf55 | |||
86c7870427 | |||
48080b7f90 | |||
b216fb8910 | |||
d3171d6a8e | |||
c063a4da29 | |||
cc79dfa64c | |||
d6b9950901 | |||
1815fe5b46 | |||
3e993250d8 | |||
1163ac1d7a | |||
9a51ba697a | |||
32ad9d0c1a | |||
0591458ef6 | |||
3d840e969d | |||
d1b70bd400 | |||
29f002b32c | |||
da17ade575 | |||
f0c36f3413 | |||
77d8f133f1 | |||
43ebb23085 | |||
e198c8fa8b | |||
cc3285c8fe | |||
305c63ba4d | |||
acaa0e33b0 | |||
f63857deed | |||
eda3d9b5e4 | |||
c3872619cd | |||
39cc590829 | |||
f347345bb3 | |||
bb05cfb36c | |||
7d5c3c9b46 | |||
cff2d37add | |||
447477c5fb | |||
abdbb2bf0e | |||
783c13926f | |||
45329ddf67 | |||
20af789963 | |||
93cb9390e0 | |||
0aed7f86f5 | |||
bf44bd016d | |||
04e4a36653 | |||
7439e1971d | |||
b961b4e003 | |||
d9eac8fc0a | |||
aeeee5eb53 | |||
13994055d9 | |||
247875e3d5 | |||
ee60a7bc36 | |||
348c2a599b | |||
562b47a1e5 | |||
4e060bc13f | |||
2807f14fcd | |||
f0539f4898 | |||
63d7e7b811 | |||
4da06078ed | |||
8a6381c3fa | |||
d0d61597c7 | |||
7a2a4e2aa3 | |||
e41a2c0792 | |||
11a6e04a28 | |||
70b1ac856d | |||
d724374d1a | |||
a19143cae7 | |||
1be6783c34 | |||
092edc9d43 | |||
2ba8eac27f | |||
25ff90b2c6 | |||
b912ae78bc | |||
677d43028a | |||
7bfb55ec9a | |||
2f61d42518 | |||
dbb669b156 | |||
4d0e8741fe | |||
53dc6e2050 | |||
807b860cfe | |||
d756500928 | |||
7ef27a1a21 | |||
eeddaced9f | |||
c237ff538c |
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Help & support on Discord
|
||||
url: https://discord.gg/bmSAZBG
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on Discord instead.
|
||||
- name: Help & support on forums
|
||||
url: https://forums.pmmp.io
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on forums instead.
|
||||
- name: Documentation
|
||||
url: https://pmmp.rtfd.io
|
||||
about: PocketMine-MP documentation
|
1
.github/ISSUE_TEMPLATE/crash.md
vendored
1
.github/ISSUE_TEMPLATE/crash.md
vendored
@ -9,6 +9,7 @@ assignees: ''
|
||||
|
||||
<!--- submit crashdump files to https://crash.pmmp.io -->
|
||||
<!--- or, copy the data between ===BEGIN CRASH DUMP=== and ===END CRASH DUMP and paste it on a site like https://pastebin.com -->
|
||||
<!--- DON'T JUST PASTE the crashdump into an issue -->
|
||||
Link to crashdump:
|
||||
|
||||
<!--- write additional information about the crash to help us find the problem -->
|
||||
|
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
14
.github/ISSUE_TEMPLATE/help---support.md
vendored
@ -1,14 +0,0 @@
|
||||
---
|
||||
name: Help & support
|
||||
about: We don't accept support requests here. Try the links on the README.
|
||||
title: ''
|
||||
labels: Support request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
We don't accept support requests on the issue tracker. Please try the following links instead:
|
||||
|
||||
Documentation: http://pmmp.rtfd.io
|
||||
Forums: https://forums.pmmp.io
|
||||
Discord: https://discord.gg/bge7dYQ
|
@ -1,12 +0,0 @@
|
||||
---
|
||||
name: Security/DoS vulnerability
|
||||
about: 'Bug or exploit that can be used to attack servers (hint: don''t report it
|
||||
on a public issue tracker)'
|
||||
title: ''
|
||||
labels: 'Auto: Spam'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please DO NOT report security vulnerabilities here.
|
||||
Instead, send an email to team@pmmp.io or contact a developer directly, IN PRIVATE.
|
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: composer
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
16
.github/support.yml
vendored
16
.github/support.yml
vendored
@ -1,16 +0,0 @@
|
||||
# Configuration for support-requests - https://github.com/dessant/support-requests
|
||||
|
||||
# Label used to mark issues as support requests
|
||||
supportLabel: "Support request"
|
||||
# Comment to post on issues marked as support requests. Add a link
|
||||
# to a support page, or set to `false` to disable
|
||||
supportComment: >
|
||||
Thanks, but this issue tracker 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).
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bge7dYQ) | [Forums](https://forums.pmmp.io)
|
||||
|
||||
# Whether to close issues marked as support requests
|
||||
close: true
|
||||
# Whether to lock issues marked as support requests
|
||||
lock: false
|
281
.github/workflows/main.yml
vendored
Normal file
281
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,281 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-php:
|
||||
name: Prepare PHP
|
||||
runs-on: ${{ matrix.image }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.28, 7.4.19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2 #needed for build.sh
|
||||
- name: Check for PHP build cache
|
||||
id: php-build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "./bin"
|
||||
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
|
||||
|
||||
- name: Compile PHP
|
||||
if: steps.php-build-cache.outputs.cache-hit != 'true'
|
||||
run: ./tests/gh-actions/build.sh "${{ matrix.php }}"
|
||||
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.28, 7.4.19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Restore PHP build cache
|
||||
id: php-build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "./bin"
|
||||
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
|
||||
|
||||
- name: Kill build on PHP build cache miss (should never happen)
|
||||
if: steps.php-build-cache.outputs.cache-hit != 'true'
|
||||
run: exit 1
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.28, 7.4.19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Restore PHP build cache
|
||||
id: php-build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "./bin"
|
||||
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
|
||||
|
||||
- name: Kill build on PHP build cache miss (should never happen)
|
||||
if: steps.php-build-cache.outputs.cache-hit != 'true'
|
||||
run: exit 1
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||
|
||||
integration:
|
||||
name: Integration tests
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.28, 7.4.19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Restore PHP build cache
|
||||
id: php-build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "./bin"
|
||||
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
|
||||
|
||||
- name: Kill build on PHP build cache miss (should never happen)
|
||||
if: steps.php-build-cache.outputs.cache-hit != 'true'
|
||||
run: exit 1
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run integration tests
|
||||
run: ./tests/travis.sh -t4
|
||||
|
||||
preprocessor:
|
||||
name: Preprocessor tests
|
||||
needs: build-php
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [7.3.28, 7.4.19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Restore PHP build cache
|
||||
id: php-build-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "./bin"
|
||||
key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}"
|
||||
|
||||
- name: Kill build on PHP build cache miss (should never happen)
|
||||
if: steps.php-build-cache.outputs.cache-hit != 'true'
|
||||
run: exit 1
|
||||
|
||||
- name: Install cached PHP's dependencies
|
||||
if: steps.php-build-cache.outputs.cache-hit == 'true'
|
||||
run: ./tests/gh-actions/install-dependencies.sh
|
||||
|
||||
- name: Prefix PHP to PATH
|
||||
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Composer
|
||||
run: curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: php composer.phar install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run preprocessor
|
||||
run: |
|
||||
PM_PREPROCESSOR_PATH="$GITHUB_WORKSPACE/build/preprocessor"
|
||||
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path=src --multisize || (echo "Preprocessor exited with code $?" && exit 1)
|
||||
|
||||
#dump the diff of preprocessor replacements to a patch in case it has bugs
|
||||
git diff > preprocessor_diff.patch
|
||||
|
||||
VENDOR_PM="$GITHUB_WORKSPACE/vendor"
|
||||
VENDOR_PM_BACKUP="$GITHUB_WORKSPACE/vendor-before-preprocess"
|
||||
cp -r "$VENDOR_PM" "$VENDOR_PM_BACKUP"
|
||||
for f in $(ls $VENDOR_PM/pocketmine); do
|
||||
echo "Processing directory \"$f\"..."
|
||||
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path="$VENDOR_PM/pocketmine/$f" --multisize || (echo "Preprocessor exited with code $?" && exit 1)
|
||||
echo "Checking for changes in \"$f\"..."
|
||||
DIFF=$(git diff --no-index "$VENDOR_PM_BACKUP/pocketmine/$f" "$VENDOR_PM/pocketmine/$f" || true)
|
||||
if [ "$DIFF" != "" ]; then
|
||||
PATCH="$GITHUB_WORKSPACE/preprocessor_diff_$f.patch"
|
||||
echo "$DIFF" > "$PATCH"
|
||||
echo "Generated patch file \"$PATCH\""
|
||||
else
|
||||
echo "No diff generated for \"$f\" (preprocessor made no changes)"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Upload preprocessor diffs
|
||||
uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: preprocessor_diffs_${{ matrix.php }}_${{ matrix.image }}
|
||||
path: ${{ github.workspace }}/preprocessor_diff*.patch
|
||||
|
||||
codestyle:
|
||||
name: Code Style checks
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.9.0
|
||||
with:
|
||||
php-version: 7.4
|
||||
tools: php-cs-fixer
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff
|
22
.github/workflows/support.yml
vendored
Normal file
22
.github/workflows/support.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: 'Manage support request issues'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled, unlabeled, reopened]
|
||||
|
||||
jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v2
|
||||
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).
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||
|
||||
close-issue: true
|
||||
lock-issue: false
|
51
.github/workflows/update-php-versions.php
vendored
Normal file
51
.github/workflows/update-php-versions.php
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"7.3",
|
||||
"7.4",
|
||||
"8.0"
|
||||
];
|
||||
|
||||
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
|
||||
$newWorkflowFile = $workflowFile;
|
||||
foreach(VERSIONS as $v){
|
||||
$releaseInfo = file_get_contents("https://secure.php.net/releases?json&version=$v");
|
||||
if($releaseInfo === false){
|
||||
throw new \RuntimeException("Failed to contact php.net API");
|
||||
}
|
||||
$data = json_decode($releaseInfo, true);
|
||||
if(!is_array($data) || !isset($data["version"]) || !is_string($data["version"]) || preg_match('/^\d+\.\d+\.\d+(-[A-Za-z\d]+)?$/', $data["version"]) === 0){
|
||||
throw new \RuntimeException("Invalid data returned by API");
|
||||
}
|
||||
$updated = preg_replace("/$v\.\d+/", $data["version"], $newWorkflowFile);
|
||||
if($updated !== $newWorkflowFile){
|
||||
echo "Updated $v revision to " . $data["version"] . "\n";
|
||||
}
|
||||
$newWorkflowFile = $updated;
|
||||
}
|
||||
|
||||
if($workflowFile !== $newWorkflowFile){
|
||||
echo "Writing modified workflow file\n";
|
||||
file_put_contents(__DIR__ . '/main.yml', $newWorkflowFile);
|
||||
}
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
players/*
|
||||
worlds/*
|
||||
world_conversion_backups/*
|
||||
plugin_data/*
|
||||
plugins/*
|
||||
bin*/*
|
||||
@ -11,13 +10,15 @@ crashdumps/*
|
||||
*.phar
|
||||
server.properties
|
||||
/pocketmine.yml
|
||||
/plugin_list.yml
|
||||
memory_dumps/*
|
||||
resource_packs/
|
||||
server.lock
|
||||
/phpstan.neon
|
||||
|
||||
# Common IDEs
|
||||
.idea/
|
||||
.idea/*
|
||||
!.idea/codeStyles/
|
||||
!.idea/fileTemplates/
|
||||
nbproject/*
|
||||
|
||||
# Windows image file caches
|
||||
@ -42,3 +43,10 @@ test_data/*
|
||||
|
||||
# Doxygen
|
||||
Documentation/*
|
||||
|
||||
# PHPUnit
|
||||
/.phpunit.result.cache
|
||||
|
||||
# php-cs-fixer
|
||||
/.php_cs.cache
|
||||
/.php-cs-fixer.cache
|
||||
|
19
.gitmodules
vendored
19
.gitmodules
vendored
@ -1,12 +1,15 @@
|
||||
[submodule "resources/locale"]
|
||||
path = resources/locale
|
||||
url = https://github.com/pmmp/PocketMine-Language.git
|
||||
[submodule "src/pocketmine/lang/locale"]
|
||||
path = src/pocketmine/lang/locale
|
||||
url = https://github.com/pmmp/Language.git
|
||||
[submodule "tests/preprocessor"]
|
||||
path = build/preprocessor
|
||||
url = https://github.com/pmmp/preprocessor.git
|
||||
[submodule "tests/plugins/PocketMine-DevTools"]
|
||||
path = tests/plugins/PocketMine-DevTools
|
||||
url = https://github.com/pmmp/PocketMine-DevTools.git
|
||||
[submodule "resources/vanilla"]
|
||||
path = resources/vanilla
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
[submodule "src/pocketmine/resources/vanilla"]
|
||||
path = src/pocketmine/resources/vanilla
|
||||
url = https://github.com/pmmp/BedrockData.git
|
||||
|
71
.idea/codeStyles/Project.xml
generated
Normal file
71
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,71 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_TEXT_WRAP" value="0" />
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="thead,tbody,tfoot" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<PHPCodeStyleSettings>
|
||||
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
|
||||
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
|
||||
<option name="SPACES_WITHIN_SHORT_ECHO_TAGS" value="false" />
|
||||
<option name="SPACE_BEFORE_CLOSURE_LEFT_PARENTHESIS" value="false" />
|
||||
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_COLON_IN_RETURN_TYPE" value="true" />
|
||||
</PHPCodeStyleSettings>
|
||||
<editorconfig>
|
||||
<option name="ENABLED" value="false" />
|
||||
</editorconfig>
|
||||
<codeStyleSettings language="HTML">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="PHP">
|
||||
<option name="CLASS_BRACE_STYLE" value="1" />
|
||||
<option name="METHOD_BRACE_STYLE" value="1" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
|
||||
<option name="SPACE_AFTER_TYPE_CAST" value="true" />
|
||||
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
|
||||
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_METHOD_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_IF_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_ELSE_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_FOR_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_DO_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_SWITCH_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_TRY_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_FINALLY_LBRACE" value="false" />
|
||||
<option name="SPACE_BEFORE_ELSE_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_WHILE_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_CATCH_KEYWORD" value="false" />
|
||||
<option name="SPACE_BEFORE_FINALLY_KEYWORD" value="false" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="neon">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
8
.idea/fileTemplates/code/PHP Constructor.php
generated
Normal file
8
.idea/fileTemplates/code/PHP Constructor.php
generated
Normal file
@ -0,0 +1,8 @@
|
||||
#if(${THROWS_DOC} != "")
|
||||
/**
|
||||
${THROWS_DOC}
|
||||
*/
|
||||
#end
|
||||
public function __construct(${PARAM_LIST}) {
|
||||
${BODY}
|
||||
}
|
6
.idea/fileTemplates/code/PHP Fluent Setter Method.php
generated
Normal file
6
.idea/fileTemplates/code/PHP Fluent Setter Method.php
generated
Normal file
@ -0,0 +1,6 @@
|
||||
/** @return $this */
|
||||
public function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #else#end$${PARAM_NAME})#if(${RETURN_TYPE}): self#else#end
|
||||
{
|
||||
$this->${FIELD_NAME} = $${PARAM_NAME};
|
||||
return $this;
|
||||
}
|
3
.idea/fileTemplates/code/PHP Getter Method.php
generated
Normal file
3
.idea/fileTemplates/code/PHP Getter Method.php
generated
Normal file
@ -0,0 +1,3 @@
|
||||
#if(${TYPE_HINT} != ${RETURN_TYPE} && ${TYPE_HINT} != "")/** @return ${TYPE_HINT} */#end
|
||||
public ${STATIC} function ${GET_OR_IS}${NAME}()#if(${RETURN_TYPE}): ${RETURN_TYPE}#else#end
|
||||
{ return #if(${STATIC} == "static")self::$${FIELD_NAME};#else$this->${FIELD_NAME};#end }
|
2
.idea/fileTemplates/code/PHP Setter Method.php
generated
Normal file
2
.idea/fileTemplates/code/PHP Setter Method.php
generated
Normal file
@ -0,0 +1,2 @@
|
||||
public ${STATIC} function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #end$${PARAM_NAME})#if (${VOID_RETURN_TYPE}):void #end
|
||||
{#if (${STATIC} == "static") self::$${FIELD_NAME} = $${PARAM_NAME}; #else $this->${FIELD_NAME} = $${PARAM_NAME}; #end}
|
0
.idea/fileTemplates/includes/PHP Class Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Class Doc Comment.php
generated
Normal file
21
.idea/fileTemplates/includes/PHP File Header.php
generated
Normal file
21
.idea/fileTemplates/includes/PHP File Header.php
generated
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* 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);
|
5
.idea/fileTemplates/includes/PHP Function Doc Comment.php
generated
Normal file
5
.idea/fileTemplates/includes/PHP Function Doc Comment.php
generated
Normal file
@ -0,0 +1,5 @@
|
||||
#if (${THROWS_DOC} != "")
|
||||
/**
|
||||
${THROWS_DOC}
|
||||
*/
|
||||
#end
|
0
.idea/fileTemplates/includes/PHP Interface Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Interface Doc Comment.php
generated
Normal file
1
.idea/fileTemplates/includes/PHP Property Doc Comment.php
generated
Normal file
1
.idea/fileTemplates/includes/PHP Property Doc Comment.php
generated
Normal file
@ -0,0 +1 @@
|
||||
/** @var ${TYPE_HINT} */
|
0
.idea/fileTemplates/includes/PHP Trait Doc Comment.php
generated
Normal file
0
.idea/fileTemplates/includes/PHP Trait Doc Comment.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Class.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Class.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
final class ${NAME} {
|
||||
|
||||
}
|
4
.idea/fileTemplates/internal/PHP File.php
generated
Normal file
4
.idea/fileTemplates/internal/PHP File.php
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
|
10
.idea/fileTemplates/internal/PHP Interface.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Interface.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
interface ${NAME} {
|
||||
|
||||
}
|
10
.idea/fileTemplates/internal/PHP Trait.php
generated
Normal file
10
.idea/fileTemplates/internal/PHP Trait.php
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
#parse("PHP File Header.php")
|
||||
|
||||
#if (${NAMESPACE})
|
||||
namespace ${NAMESPACE};
|
||||
#end
|
||||
|
||||
trait ${NAME} {
|
||||
|
||||
}
|
71
.php-cs-fixer.php
Normal file
71
.php-cs-fixer.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/src')
|
||||
->in(__DIR__ . '/build')
|
||||
->in(__DIR__ . '/tests')
|
||||
->notPath('plugins/DevTools')
|
||||
->notPath('preprocessor')
|
||||
->notContains('#ifndef COMPILE') //preprocessor will break if these are changed
|
||||
->notName('PocketMine.php');
|
||||
|
||||
return (new PhpCsFixer\Config)
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'align_multiline_comment' => [
|
||||
'comment_type' => 'phpdocs_only'
|
||||
],
|
||||
'array_indentation' => true,
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short'
|
||||
],
|
||||
'blank_line_after_namespace' => true,
|
||||
'blank_line_after_opening_tag' => true,
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'declare'
|
||||
]
|
||||
],
|
||||
'cast_spaces' => [
|
||||
'space' => 'single'
|
||||
],
|
||||
'concat_space' => [
|
||||
'spacing' => 'one'
|
||||
],
|
||||
'declare_strict_types' => true,
|
||||
'elseif' => true,
|
||||
'global_namespace_import' => [
|
||||
'import_constants' => true,
|
||||
'import_functions' => true,
|
||||
'import_classes' => null,
|
||||
],
|
||||
'indentation_type' => true,
|
||||
'native_function_invocation' => [
|
||||
'scope' => 'namespaced'
|
||||
],
|
||||
'no_closing_tag' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
'no_superfluous_phpdoc_tags' => [
|
||||
'allow_mixed' => true,
|
||||
],
|
||||
'no_trailing_whitespace' => true,
|
||||
'no_trailing_whitespace_in_comment' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
'no_unused_imports' => true,
|
||||
'ordered_imports' => [
|
||||
'imports_order' => [
|
||||
'class',
|
||||
'function',
|
||||
'const',
|
||||
],
|
||||
'sort_algorithm' => 'alpha'
|
||||
],
|
||||
'phpdoc_trim' => true,
|
||||
'phpdoc_trim_consecutive_blank_line_separation' => true,
|
||||
'single_import_per_statement' => true,
|
||||
'strict_param' => true,
|
||||
])
|
||||
->setFinder($finder)
|
||||
->setIndent("\t")
|
||||
->setLineEnding("\n");
|
46
.travis.yml
46
.travis.yml
@ -1,46 +0,0 @@
|
||||
dist: xenial
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
|
||||
before_script:
|
||||
- LEVELDB_VERSION=f1463cb0b2486b0caf7d42ca3c7684545e875f04
|
||||
- curl -fsSL "https://github.com/pmmp/leveldb-mcpe/archive/f1463cb0b2486b0caf7d42ca3c7684545e875f04.tar.gz" | tar -zx
|
||||
- mv leveldb-mcpe-$LEVELDB_VERSION leveldb-mcpe
|
||||
- cd leveldb-mcpe && make -j4 && mv out-shared/libleveldb.* . && cd ..
|
||||
- git clone https://github.com/reeze/php-leveldb.git leveldb
|
||||
- cd leveldb
|
||||
- git checkout 9bcae79f71b81a5c3ea6f67e45ae9ae9fb2775a5
|
||||
- phpize
|
||||
- ./configure --with-leveldb=../leveldb-mcpe && make && make install
|
||||
- cd ..
|
||||
- git clone https://github.com/pmmp/ext-chunkutils2.git chunkutils
|
||||
- cd chunkutils
|
||||
- git checkout d8d762a597ac0da6f333f862096d6af0e6286b75
|
||||
- phpize
|
||||
- ./configure && make && make install
|
||||
- cd ..
|
||||
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.4
|
||||
- pecl install channel://pecl.php.net/crypto-0.3.1
|
||||
- pecl install channel://pecl.php.net/ds-1.2.8
|
||||
- git clone https://github.com/pmmp/pthreads.git
|
||||
- cd pthreads
|
||||
- git checkout 6ca019c58b4fa09ee2ff490f2444e34bef0773d0
|
||||
- phpize
|
||||
- ./configure
|
||||
- make
|
||||
- make install
|
||||
- cd ..
|
||||
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- echo "extension=chunkutils2.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- echo "extension=leveldb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- composer install
|
||||
|
||||
script:
|
||||
- ./tests/travis.sh -t4
|
||||
|
||||
notifications:
|
||||
email: false
|
44
BUILDING.md
Normal file
44
BUILDING.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Building
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 7.3 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries.
|
||||
|
||||
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-7.4-Aggregate)
|
||||
- [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php`
|
||||
|
||||
If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`.
|
||||
|
||||
## Setting up environment
|
||||
1. `git clone --recursive https://github.com/pmmp/PocketMine-MP.git`
|
||||
2. `composer install`
|
||||
|
||||
## Checking out a different branch to build
|
||||
1. `git checkout <branch to checkout>`
|
||||
2. `git submodule update --init`
|
||||
3. Re-run `composer install` to synchronize dependencies.
|
||||
|
||||
## Optimizing for release builds
|
||||
1. Add the flags `--no-dev --classmap-authoritative` to your `composer install` command. This will reduce build size and improve autoloading speed.
|
||||
2. Preprocess the source code by running `build/preprocessor/PreProcessor.php`. Usage instructions are provided in `build/preprocessor/README.md`.
|
||||
|
||||
### Note
|
||||
Preprocessor requires that the `cpp` (c preprocessor) is available in your PATH.
|
||||
|
||||
## Building `PocketMine-MP.phar`
|
||||
Run `composer make-server` using your preferred PHP binary. It'll drop a `PocketMine-MP.phar` into the current working directory.
|
||||
|
||||
You can also use the `--out` option to change the output filename.
|
||||
|
||||
There is a bug in PHP that might cause an error which looks like this:
|
||||
```
|
||||
Fatal error: Uncaught BadMethodCallException: unable to create temporary file in PocketMine-MP/build/server-phar.php:119
|
||||
```
|
||||
You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 7.4.16 or 8.0.3.
|
||||
|
||||
## Running PocketMine-MP from source code
|
||||
Run `src/pocketmine/PocketMine.php` using your preferred PHP binary.
|
@ -116,7 +116,7 @@ class ExampleClass{
|
||||
<!-- TODO: RFC and voting on the forums instead -->
|
||||
### RFC and Voting
|
||||
* These are big Pull Requests or contributions that change important behavior.
|
||||
* RFCs will be tagged with the *PR: RFC* label
|
||||
* RFCs will be tagged with the *Type: Request For Comments* label
|
||||
* A vote will be held once the RFC is ready. All users can vote commenting on the Pull Request
|
||||
* Comments MUST use "Yes" or "No" on the FIRST sentence to signify the vote, except when they don't want it to be counted.
|
||||
* If your comment is a voting comment, specify the reason of your vote or it won't be counted.
|
||||
|
23
README.md
23
README.md
@ -3,27 +3,36 @@
|
||||
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
|
||||
</p>
|
||||
|
||||
[](https://travis-ci.org/pmmp/PocketMine-MP)
|
||||
<p align="center">
|
||||
<img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" />
|
||||
<a href="https://github.com/pmmp/PocketMine-MP/releases"><img src="https://img.shields.io/github/v/tag/pmmp/PocketMine-MP?label=release&logo=github" alt="GitHub tag (latest semver)" /></a>
|
||||
<a href="https://hub.docker.com/r/pmmp/pocketmine-mp"><img src="https://img.shields.io/docker/v/pmmp/pocketmine-mp?logo=docker&label=image" alt="Docker image version (latest semver)" /></a>
|
||||
<a href="https://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
|
||||
</p>
|
||||
|
||||
### Getting started
|
||||
## Getting started
|
||||
- [Documentation](http://pmmp.readthedocs.org/)
|
||||
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
|
||||
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
|
||||
- [Plugin repository](https://poggit.pmmp.io/plugins)
|
||||
|
||||
### Discussion
|
||||
## Discussion/Help
|
||||
- [Forums](https://forums.pmmp.io/)
|
||||
- [Community Discord](https://discord.gg/bge7dYQ)
|
||||
- [Discord](https://discord.gg/bmSAZBG)
|
||||
- [StackOverflow](https://stackoverflow.com/tags/pocketmine)
|
||||
|
||||
### For developers
|
||||
## 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
|
||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
* [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)
|
||||
|
||||
### Donate
|
||||
## Donate
|
||||
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
|
||||
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
|
||||
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
|
||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||
|
||||
## Licensing information
|
||||
|
33
SECURITY.md
Normal file
33
SECURITY.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
The following release lines are currently receiving active security updates and bug fixes:
|
||||
|
||||
| Version | Supported |
|
||||
| -------- | ------------------ |
|
||||
| 3.15.x | :white_check_mark: |
|
||||
| < 3.15.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
**DO NOT report vulnerabilities on the GitHub issue tracker.**
|
||||
GitHub is public and anyone can see the issues you post on the issue tracker, including people who would exploit vulnerabilities for their own gain.
|
||||
|
||||
**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:
|
||||
|
||||
- Version of PocketMine-MP
|
||||
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
|
||||
|
||||
Please note that we can't guarantee a reply to every email.
|
||||
|
||||
## FAQ
|
||||
### Do you offer a bug bounty?
|
||||
No.
|
||||
|
||||
### How soon can I expect a fix for a vulnerability I've reported?
|
||||
This depends on the nature of the problem. We can't provide any general ETA (nor would it be wise to provide one).
|
||||
In general, it depends on when developers have time to look into the problem, how complex the problem is to fix, and how many users it impacts.
|
||||
|
||||
When a fix for a severe vulnerability is pushed, a patch release for the target version will usually be released within 24 hours so that users can update.
|
@ -21,14 +21,13 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build_script;
|
||||
namespace pocketmine\build\make_release;
|
||||
|
||||
use pocketmine\utils\VersionString;
|
||||
use function dirname;
|
||||
use function fgets;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function preg_quote;
|
||||
use function preg_replace;
|
||||
use function sleep;
|
||||
use function sprintf;
|
||||
@ -36,21 +35,8 @@ use function system;
|
||||
use const pocketmine\BASE_VERSION;
|
||||
use const STDIN;
|
||||
|
||||
require_once dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(isset($argv[1])){
|
||||
$currentVer = new VersionString($argv[1]);
|
||||
}else{
|
||||
$currentVer = new VersionString(BASE_VERSION);
|
||||
}
|
||||
$nextVer = new VersionString(sprintf(
|
||||
"%u.%u.%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch() + 1
|
||||
));
|
||||
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
|
||||
$versionInfo = file_get_contents($versionInfoPath);
|
||||
$versionInfo = preg_replace(
|
||||
@ -60,22 +46,43 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
|
||||
);
|
||||
$versionInfo = preg_replace(
|
||||
'/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
|
||||
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false'). ';',
|
||||
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';',
|
||||
$versionInfo
|
||||
);
|
||||
file_put_contents($versionInfoPath, $versionInfo);
|
||||
}
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
|
||||
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
system('git add "' . dirname(__DIR__) . '/changelogs"');
|
||||
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
|
||||
system('git tag ' . $currentVer->getBaseVersion());
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
|
||||
system('git add "' . $versionInfoPath . '"');
|
||||
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
|
||||
echo "pushing changes in 10 seconds\n";
|
||||
sleep(10);
|
||||
system('git push origin HEAD ' . $currentVer->getBaseVersion());
|
||||
/**
|
||||
* @param string[] $argv
|
||||
* @phpstan-param list<string> $argv
|
||||
*/
|
||||
function main(array $argv) : void{
|
||||
if(isset($argv[1])){
|
||||
$currentVer = new VersionString($argv[1]);
|
||||
}else{
|
||||
$currentVer = new VersionString(BASE_VERSION);
|
||||
}
|
||||
$nextVer = new VersionString(sprintf(
|
||||
"%u.%u.%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch() + 1
|
||||
));
|
||||
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
|
||||
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
system('git add "' . dirname(__DIR__) . '/changelogs"');
|
||||
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
|
||||
system('git tag ' . $currentVer->getBaseVersion());
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
|
||||
system('git add "' . $versionInfoPath . '"');
|
||||
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
|
||||
echo "pushing changes in 5 seconds\n";
|
||||
sleep(5);
|
||||
system('git push origin HEAD ' . $currentVer->getBaseVersion());
|
||||
}
|
||||
|
||||
main($argv);
|
||||
|
1
build/php
Submodule
1
build/php
Submodule
Submodule build/php added at 0a0ac2abb3
Submodule build/preprocessor updated: 4d4d2a74a6...1b9304de61
176
build/server-phar.php
Normal file
176
build/server-phar.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\server_phar;
|
||||
|
||||
use pocketmine\utils\Git;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function file_exists;
|
||||
use function getcwd;
|
||||
use function getopt;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function microtime;
|
||||
use function preg_quote;
|
||||
use function realpath;
|
||||
use function round;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function unlink;
|
||||
use const PHP_EOL;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @param string[] $strings
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function preg_quote_array(array $strings, string $delim) : array{
|
||||
return array_map(function(string $str) use ($delim) : string{ return preg_quote($str, $delim); }, $strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $includedPaths
|
||||
* @param mixed[] $metadata
|
||||
* @phpstan-param array<string, mixed> $metadata
|
||||
*
|
||||
* @return \Generator|string[]
|
||||
*/
|
||||
function buildPhar(string $pharPath, string $basePath, array $includedPaths, array $metadata, string $stub, int $signatureAlgo = \Phar::SHA1, ?int $compression = null){
|
||||
$basePath = rtrim(str_replace("/", DIRECTORY_SEPARATOR, $basePath), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$includedPaths = array_map(function(string $path) : string{
|
||||
return rtrim(str_replace("/", DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}, $includedPaths);
|
||||
yield "Creating output file $pharPath";
|
||||
if(file_exists($pharPath)){
|
||||
yield "Phar file already exists, overwriting...";
|
||||
try{
|
||||
\Phar::unlinkArchive($pharPath);
|
||||
}catch(\PharException $e){
|
||||
//unlinkArchive() doesn't like dodgy phars
|
||||
unlink($pharPath);
|
||||
}
|
||||
}
|
||||
|
||||
yield "Adding files...";
|
||||
|
||||
$start = microtime(true);
|
||||
$phar = new \Phar($pharPath);
|
||||
$phar->setMetadata($metadata);
|
||||
$phar->setStub($stub);
|
||||
$phar->setSignatureAlgorithm($signatureAlgo);
|
||||
$phar->startBuffering();
|
||||
|
||||
//If paths contain any of these, they will be excluded
|
||||
$excludedSubstrings = preg_quote_array([
|
||||
realpath($pharPath), //don't add the phar to itself
|
||||
], '/');
|
||||
|
||||
$folderPatterns = preg_quote_array([
|
||||
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR,
|
||||
DIRECTORY_SEPARATOR . '.' //"Hidden" files, git dirs etc
|
||||
], '/');
|
||||
|
||||
//Only exclude these within the basedir, otherwise the project won't get built if it itself is in a directory that matches these patterns
|
||||
$basePattern = preg_quote(rtrim($basePath, DIRECTORY_SEPARATOR), '/');
|
||||
foreach($folderPatterns as $p){
|
||||
$excludedSubstrings[] = $basePattern . '.*' . $p;
|
||||
}
|
||||
|
||||
$regex = sprintf('/^(?!.*(%s))^%s(%s).*/i',
|
||||
implode('|', $excludedSubstrings), //String may not contain any of these substrings
|
||||
preg_quote($basePath, '/'), //String must start with this path...
|
||||
implode('|', preg_quote_array($includedPaths, '/')) //... and must be followed by one of these relative paths, if any were specified. If none, this will produce a null capturing group which will allow anything.
|
||||
);
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($basePath, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::CURRENT_AS_PATHNAME); //can't use fileinfo because of symlinks
|
||||
$iterator = new \RecursiveIteratorIterator($directory);
|
||||
$regexIterator = new \RegexIterator($iterator, $regex);
|
||||
|
||||
$count = count($phar->buildFromIterator($regexIterator, $basePath));
|
||||
yield "Added $count files";
|
||||
|
||||
if($compression !== null){
|
||||
yield "Compressing files...";
|
||||
$phar->compressFiles($compression);
|
||||
yield "Finished compression";
|
||||
}
|
||||
$phar->stopBuffering();
|
||||
|
||||
yield "Done in " . round(microtime(true) - $start, 3) . "s";
|
||||
}
|
||||
|
||||
function main() : void{
|
||||
if(ini_get("phar.readonly") == 1){
|
||||
echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
if(file_exists(dirname(__DIR__) . '/vendor/phpunit')){
|
||||
echo "Remove Composer dev dependencies before building (composer install --no-dev)" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$opts = getopt("", ["out:", "git:"]);
|
||||
if(isset($opts["git"])){
|
||||
$gitHash = $opts["git"];
|
||||
}else{
|
||||
$gitHash = Git::getRepositoryStatePretty(dirname(__DIR__));
|
||||
echo "Git hash detected as $gitHash" . PHP_EOL;
|
||||
}
|
||||
foreach(buildPhar(
|
||||
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
|
||||
dirname(__DIR__) . DIRECTORY_SEPARATOR,
|
||||
[
|
||||
'src',
|
||||
'vendor'
|
||||
],
|
||||
[
|
||||
'git' => $gitHash
|
||||
],
|
||||
<<<'STUB'
|
||||
<?php
|
||||
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
if(!is_readable($tmpDir) or !is_writable($tmpDir)){
|
||||
echo "ERROR: tmpdir $tmpDir is not accessible." . PHP_EOL;
|
||||
echo "Check that the directory exists, and that the current user has read/write permissions for it." . PHP_EOL;
|
||||
echo "Alternatively, set 'sys_temp_dir' to a different directory in your php.ini file." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require("phar://" . __FILE__ . "/src/pocketmine/PocketMine.php");
|
||||
__HALT_COMPILER();
|
||||
STUB
|
||||
,
|
||||
\Phar::SHA1,
|
||||
\Phar::GZ
|
||||
) as $line){
|
||||
echo $line . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
20
changelogs/3.10.md
Normal file
20
changelogs/3.10.md
Normal file
@ -0,0 +1,20 @@
|
||||
**For Minecraft: Bedrock Edition 1.13.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.10.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.13.0
|
||||
- Removed compatibility with 1.12.0
|
||||
|
||||
## Note about skins
|
||||
PocketMine-MP **does not support skins made in the Charactor Creator** (known as Persona skins), due to technical changes which would require premature backwards compatibility breaks. The dev team has decided not to support Persona yet.
|
||||
These skins will be **replaced with a random solid-colour skin. This is not a bug.**
|
||||
Skins chosen from the Classic tab (classic skins) will continue to work as normal.
|
||||
|
||||
# 3.10.1
|
||||
- Fixed custom plugin-created skins being invisible when no geometry name was specified.
|
||||
- Updated RakLib to 0.12.6 to fix security bugs.
|
97
changelogs/3.11.md
Normal file
97
changelogs/3.11.md
Normal file
@ -0,0 +1,97 @@
|
||||
**For Minecraft: Bedrock Edition 1.14.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.11.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.14.0
|
||||
- Removed compatibility with 1.13.0
|
||||
|
||||
# 3.11.1
|
||||
- Fixed blocks with incorrect properties when placed or interacted with.
|
||||
|
||||
# 3.11.2
|
||||
## Core
|
||||
- PHPStan 0.12.3 with level 5 is now used for automated static analysis.
|
||||
- Fixed a possible crash when plugins override the `EnderChest` tile class with something incompatible.
|
||||
- Fixed disconnected players being considered as never played.
|
||||
- Fixed enchantments with IDs outside the range 0-255 in item NBT crashing the server.
|
||||
- Fixed particles rendering incorrectly.
|
||||
- Timings handlers are no longer able to underflow; they now throw exceptions when attempting to be stopped more times than they were started.
|
||||
- Fixed explosion rays getting stuck in empty subchunks (possible incorrect behaviour in large caves).
|
||||
- Fixed bad tile/entity NBT data being propagated from world providers in some cases.
|
||||
- Fixed a possible crash when detecting timezone on CentOS.
|
||||
- Fixed many cases of incorrectly documented types in the API found by PHPStan.
|
||||
- Generation tasks no longer assume that generator instances stored in TLS are always valid, fixing a possible crash.
|
||||
|
||||
## Protocol
|
||||
- Fixed skin animation image corruption in LoginPacket handling caused by incorrect data handling.
|
||||
- Fixed skin animation extra data not being decoded from LoginPacket.
|
||||
- `SkinImage` now throws `InvalidArgumentException` if it receives an unexpected amount of bytes for the given image heigh/width.
|
||||
- Fixed broken code in `PlayerAuthInputPacket::create()`.
|
||||
- Removed some dead constants from `NetworkInventoryAction`.
|
||||
|
||||
# 3.11.3
|
||||
- Fixed some PHPStan false-positives in release builds.
|
||||
- Git hash is now correctly detected for source builds when the working directory is not the repository root.
|
||||
- Added a specialized build script `build/server-phar.php` for creating server phars.
|
||||
- Fixed timings crashing the server.
|
||||
- Timings chains now work correctly.
|
||||
- Fixed some minor timing errors in chained timings.
|
||||
- Forcing resource packs no longer causes removal of client-sided resource packs. If this behaviour is desired, use a vanilla resource pack at the bottom of your resource stack (as was necessary for non-forced packs).
|
||||
- Added documentation to the API to clarify that effect durations are in ticks.
|
||||
|
||||
# 3.11.4
|
||||
- Fixed performance issue in leaf decay.
|
||||
- Fixed entity position desync when entities stop moving, but still have velocity on the client.
|
||||
- Fixed a crash when encountering truncated `level.dat` files in LevelDB worlds.
|
||||
- Core code is now analyzed using PHPStan level 6.
|
||||
- The core constants `pocketmine\PATH` and `pocketmine\RESOURCE_PATH` are now unconditionally available when including the Composer autoloader.
|
||||
- Populate type information in lots of places where it was previously missing; this will improve the quality of static analysis for plugins.
|
||||
- `MainLogger::logException()` now logs previous exceptions recursively.
|
||||
- `MainLogger::logException()` now always logs exceptions as `critical`.
|
||||
|
||||
# 3.11.5
|
||||
- PHPStan and PHPUnit are now managed as Composer dev dependencies.
|
||||
- Core code is now analyzed using PHPStan level 6 (full, including iterable types checking).
|
||||
- Improved type information available to PHPStan in many areas.
|
||||
- Mass-removal of useless PHPDoc.
|
||||
- Fixed incorrect documentation of `Internet::getURL()`, `Internet::postURL()` and `Internet::simpleCurl()`.
|
||||
- Fixed crash on use of case-mismatched recursive command aliases.
|
||||
- Basic build instructions are now provided in `BUILDING.md`.
|
||||
- `build/server-phar.php` now uses GZIP compression on created phars, providing a 75% size reduction.
|
||||
- `ClientboundMapItemDataPacket` now uses `MapDecoration` objects for decorations instead of associative arrays.
|
||||
- Updated Composer dependencies to get bug fixes in `pocketmine/nbt` and other libraries.
|
||||
- Packages `pocketmine/classloader` and `pocketmine/log` are now required; these provide classes previously part of `pocketmine/spl`. This change has no effect on API compatibility.
|
||||
|
||||
# 3.11.6
|
||||
- Core code, tests and build scripts are now analyzed using `phpstan-strict-rules` and `phpstan-phpunit` rules.
|
||||
- Added more PHPStan-specific type annotations to improve static analysis.
|
||||
- Fixed more incorrect PHPDoc types.
|
||||
- Added a workaround for player movement not working since 1.14.30.
|
||||
- Fixed lava and water buckets being edible since 1.13.
|
||||
- `AutoUpdater` is now created before any plugins are loaded.
|
||||
- Fixed trees not generating below y=2 in custom generators.
|
||||
- Fixed crash when opening a chest improperly unpaired from its pair (destroyed, setBlock(), unloaded, etc.).
|
||||
- `ThreadManager` is now lazily initialized.
|
||||
- Removed raw NBT storage from `Item` internals. The following methods are now deprecated:
|
||||
- `Item::setCompoundTag()`
|
||||
|
||||
# 3.11.7
|
||||
- Build system: Fixed crash reports of Jenkins builds being rejected by the crash archive as invalid.
|
||||
- Introduced a new dependency on `pocketmine/log-pthreads`, which contains classes separated from `pocketmine/log`.
|
||||
- Fixed minimum composer stability preventing any newer version of `pocketmine/pocketmine-mp` being installed than 3.3.4 by replacing `daverandom/callback-validator` with [`pocketmine/callback-validator`](https://github.com/pmmp/CallbackValidator).
|
||||
- Fixed every player seeing eating particles when any player eats.
|
||||
- Fixed setting held item not working during `BlockBreakEvent`, `PlayerInteractEvent` and `EntityDamageEvent`.
|
||||
- Fixed some incorrect documented types in `PlayerQuitEvent` reported by PHPStan.
|
||||
- Fixed documentation of `Item->pop()` return value.
|
||||
- Fixed server crash on encountering corrupted compressed data stored in region files.
|
||||
- Protocol: Split screen header is now properly accounted for during decoding. Note that split screen is still not supported natively, but their packets can be decoded properly now.
|
||||
- Protocol: Fixed wrong order of fields in `UpdateTradePacket`.
|
||||
- Protocol: Fixed loss of `fullSkinId` when decoding network skins.
|
||||
- Fixed RCON not being able to bind to port after a fast server restart.
|
||||
|
||||
|
58
changelogs/3.12.md
Normal file
58
changelogs/3.12.md
Normal file
@ -0,0 +1,58 @@
|
||||
**For Minecraft: Bedrock Edition 1.14.60**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.12.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.14.60
|
||||
- Removed compatibility with 1.14.0-1.14.30
|
||||
|
||||
# 3.12.1
|
||||
- Fixed parsing of single-line doc comments for event handlers, e.g. `/** @ignoreCancelled */` should now work correctly.
|
||||
- The server will no longer crash on failure to load `level.dat` contents, but will gracefully shutdown instead without producing a crashdump.
|
||||
- Fixed some bugs in login verification that could cause undefined behaviour.
|
||||
- Fixed item-use behaviour when sneaking - sneaking and clicking a block with an empty hand, and sneaking and using an item, both now follow vanilla behaviour.
|
||||
- `start.sh` will now work on platforms where `/bin/bash` is not available, as long as `/usr/bin/env` knows where bash is.
|
||||
|
||||
# 3.12.2
|
||||
- Fixed permission default timings not being reported in timings reports (they were never stopped, only started).
|
||||
- Resource packs with a directory tree like `pack.zip/MyPack/manifest.json` are now supported. Note that the manifest closest to the root will be used.
|
||||
- Fixed `SkinImage` height and width being inverted at the protocol layer.
|
||||
- Fixed blocks being able to be placed inside the spawn protection radius by clicking the side of a block outside the radius.
|
||||
- Fixed server crash when `network.compression-level` is overridden by a CLI parameter.
|
||||
- Fixed moving entities spawning themselves to players registered on chunks when the players haven't received the chunk yet.
|
||||
- Cocoa pods now drop cocoa beans when broken instead of the block itself.
|
||||
|
||||
# 3.12.3
|
||||
- Core code is now analyzed using PHPStan level 8 (using baselines). While not all the code is level 8 compliant, this does mean that new code will be held to a higher standard, ensuring quality going forwards.
|
||||
- Players no longer burn when melee-attacked by other players. (vanilla parity)
|
||||
- Arrows shot by burning players are no longer on fire. (vanilla parity)
|
||||
- Fixed a crash that could occur with plugins on Unix filesystems that had backslashes in their names.
|
||||
- Cleaned up a whole bunch of unknowns in the protocol layer. Many new constants have been added.
|
||||
- Fixed player walking sounds.
|
||||
- Default generation queue size has been raised to 32 (previously 8). The previous default was selected in a time when PHP was much less performant than it is today, and in today's world it just needlessly slows things down.
|
||||
- Double plants are now burned away by fire.
|
||||
- Snow layers can now be stacked. (vanilla parity)
|
||||
- Resource pack sending chunk size has been reduced to 128 KB (previously 1 MB). This change was made after analyzing the effects that larger pack chunk sizes have on RakNet. Given the technical evidence, a smaller size, while slightly less bandwidth-efficient, should be more manageable for RakNet due to lower split reassembly overhead and reduced memory pressure.
|
||||
- Fixed "switching" (an exploit often complained about by PvP players). Now, the previous damage is subtracted from current damage when an entity is attacked while on cooldown. This means that attacking with a wooden sword and then diamond sword while attack cooldown is active will only deal as much damage as the diamond sword would have, instead of the combined total. This can be controlled using the `EntityDamageEvent::MODIFIER_PREVIOUS_DAMAGE_COOLDOWN` modifier. (vanilla parity)
|
||||
- Fixed projectiles knocking mobs back in unexpected directions on collision.
|
||||
- Fixed inventories not being synchronized on failed inventory transactions.
|
||||
- Vector3s decoded from packets are no longer rounded directly. Instead, the player movement handler takes responsibility for rounding the coordinates to prevent anti cheat doing something it's not supposed to.
|
||||
- `mobflame` particle can now be spawned using the `/particle` command.
|
||||
- Fixed several internal errors that could occur while modifying writable books.
|
||||
- Fixed swapping writable book pages not working in some cases.
|
||||
- `WritableBook->getPageText()` no longer throws an exception when the page doesn't exist, but returns null (as it was originally intended to).
|
||||
|
||||
# 3.12.4
|
||||
- Fixed absorption hearts not being consumed.
|
||||
|
||||
# 3.12.5
|
||||
- Fixed broken attack cooldowns.
|
||||
|
||||
# 3.12.6
|
||||
- Fixed entities not getting movement updates after teleports.
|
||||
- Fixed slow flight in spectator mode when starting from the ground and after teleportation.
|
||||
- Errors communicating with the crash archive on automatic crash submission are now logged.
|
131
changelogs/3.13.md
Normal file
131
changelogs/3.13.md
Normal file
@ -0,0 +1,131 @@
|
||||
**For Minecraft: Bedrock Edition 1.14.60**
|
||||
|
||||
This is a feature release, containing various minor API additions, deprecations and a few minor features.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.13.0
|
||||
## Core
|
||||
- PHP 7.3.0 or newer is now required.
|
||||
- Player movement processing has been revamped. It's now more tolerant of network lag and doesn't have as many problems with falling.
|
||||
|
||||
## User Interface
|
||||
- `/time` now supports additional aliases `noon`, `sunset`, `midnight` and `sunrise`.
|
||||
- Removed warnings when a plugin registers a handler for a deprecated event. Since this warning is developer-focused, and too specific to be useful, it just caused annoyance and confusion to users who didn't know what it meant.
|
||||
|
||||
## API
|
||||
### General
|
||||
- It's now possible to require a specific operating system using the `os` directive in `plugin.yml`. More information about this directive can be found in the [developer documentation](https://github.com/pmmp/DeveloperDocs).
|
||||
|
||||
### Player
|
||||
- `Player->resetItemCooldown()` now accepts a second parameter, allowing plugins to provide a custom duration.
|
||||
- The following methods have been deprecated and have recommended replacements:
|
||||
- `Player->addTitle()` -> `Player->sendTitle()`
|
||||
- `Player->addSubTitle()` -> `Player->sendSubTitle()`
|
||||
- `Player->addActionBarMessage()` -> `Player->sendActionBarMessage()`
|
||||
|
||||
### Event
|
||||
- The following methods have been deprecated:
|
||||
- `EntityDespawnEvent->getType()`
|
||||
- `EntityDespawnEvent->getPosition()`
|
||||
- `EntityDespawnEvent->isCreature()`
|
||||
- `EntityDespawnEvent->isHuman()`
|
||||
- `EntityDespawnEvent->isProjectile()`
|
||||
- `EntityDespawnEvent->isVehicle()`
|
||||
- `EntityDespawnEvent->isItem()`
|
||||
- `EntitySpawnEvent->getType()`
|
||||
- `EntitySpawnEvent->getPosition()`
|
||||
- `EntitySpawnEvent->isCreature()`
|
||||
- `EntitySpawnEvent->isHuman()`
|
||||
- `EntitySpawnEvent->isProjectile()`
|
||||
- `EntitySpawnEvent->isVehicle()`
|
||||
- `EntitySpawnEvent->isItem()`
|
||||
- Added the following API methods:
|
||||
- `EntityDeathEvent->getXpDropAmount()`
|
||||
- `EntityDeathEvent->setXpDropAmount()`
|
||||
- `PlayerDeathEvent::__construct()` now accepts a fourth (optional) parameter `int $xp`.
|
||||
- `EntityDeathEvent::__construct()` now accepts a third (optional) parameter `int $xp`.
|
||||
|
||||
### Inventory
|
||||
- The following classes have been deprecated:
|
||||
- `Recipe`
|
||||
- The following methods have been deprecated:
|
||||
- `CraftingManager->registerRecipe()`
|
||||
- `Recipe->registerToCraftingManager()` (and all its implementations)
|
||||
|
||||
### Item
|
||||
- New `Enchantment` type ID constants have been added.
|
||||
- `ItemFactory::fromStringSingle()` has been added. This works exactly the same as `ItemFactory::fromString()`, but it has a return type of `Item` instead of `Item|Item[]` (more static analysis friendly).
|
||||
|
||||
### Level
|
||||
- Added the following API methods:
|
||||
- `Position->getLevelNonNull()`: this is the same as `Position->getLevel()`, but throws an `AssumptionFailedError` if the level is null or invalid (more static analysis friendly).
|
||||
- `Level->getTimeOfDay()`
|
||||
- The following constants have been changed:
|
||||
- `Level::TIME_DAY` now has a value of `1000`
|
||||
- `Level::TIME_NIGHT` now has a value of `13000`
|
||||
- Added the following constants:
|
||||
- `Level::TIME_MIDNIGHT`
|
||||
- `Level::TIME_NOON`
|
||||
- The following types of particles now accept optional `Color` parameters in the constructor:
|
||||
- `EnchantParticle`
|
||||
- `InstantEnchantParticle`
|
||||
|
||||
### Network
|
||||
- Added the following API methods:
|
||||
- `RakLibInterface->setPacketLimit()`
|
||||
|
||||
### Scheduler
|
||||
AsyncTask thread-local storage has been improved, making it simpler and easier to use.
|
||||
- `AsyncTask->fetchLocal()` no longer deletes stored thread-local data. Instead, the storage behaves more like properties, and gets deleted when the AsyncTask object goes out of scope.
|
||||
- `AsyncTask->peekLocal()` has been `@deprecated` (use `fetchLocal()` instead).
|
||||
- Notices are no longer emitted if an async task doesn't fetch its locally stored data.
|
||||
- The following methods have been deprecated:
|
||||
- `AsyncTask->getFromThreadStore()` (use its worker's corresponding method)
|
||||
- `AsyncTask->saveToThreadStore()` (use its worker's corresponding method)
|
||||
- `AsyncTask->removeFromThreadStore()` (use its worker's corresponding method)
|
||||
|
||||
### Utils
|
||||
- The following functions have been deprecated and have recommended replacements:
|
||||
- `Utils::getMemoryUsage()` -> split into `Process::getMemoryUsage()` and `Process::getAdvancedMemoryUsage()` (not 1:1 replacement!!)
|
||||
- `Utils::getRealMemoryUsage()` -> `Process::getRealMemoryUsage()`
|
||||
- `Utils::getThreadCount()` -> `Process::getThreadCount()`
|
||||
- `Utils::kill()` -> `Process::kill()`
|
||||
- `Utils::execute()` -> `Process::execute()`
|
||||
- Added the following constants:
|
||||
- `Utils::OS_WINDOWS`
|
||||
- `Utils::OS_IOS`
|
||||
- `Utils::OS_MACOS`
|
||||
- `Utils::OS_ANDROID`
|
||||
- `Utils::OS_LINUX`
|
||||
- `Utils::OS_BSD`
|
||||
- `Utils::OS_UNKNOWN`
|
||||
- Added the following API methods:
|
||||
- `Config->getPath()`
|
||||
- `Utils::recursiveUnlink()`
|
||||
- `Terminal::write()`
|
||||
- `Terminal::writeLine()`
|
||||
|
||||
# 3.13.1
|
||||
- Fixed issues with `server.lock` not being unlocked on some platforms. Now, the server explicitly releases it before exiting.
|
||||
- `/timings` now sends a usage message when using an unknown subcommand. Previously, it would just give no output.
|
||||
- `/whitelist` now sends a usage message when using an unknown subcommand. Previously, it would just give no output.
|
||||
- The output from `/timings` is now broadcasted on the `pocketmine.broadcast.admin` broadcast channel for auditability, similarly to other operator commands.
|
||||
- Fixed `ShapedRecipe` deprecation warning on PHP 7.4.
|
||||
- Fixed some potential crashes with Bedrock worlds when chunk data is corrupted or missing.
|
||||
- Fixed a bug in region handling that caused region loaders to overestimate the amount of space used in the file. This resulted in an up to 4 MB growth of the file size every time the region was reloaded after writing a chunk.
|
||||
- Region handlers now try to reuse free space in region files before putting the chunk at the end of the file. Previously, space was only reused if the new version of the chunk was <= the size of the old. This fixes endless growth of region files.
|
||||
- Regions now never directly overwrite old copies of chunks when saving; instead they try to find an alternative location (preferring unused space within the file first). This avoids chunk corruption on power failure (the old copy of the chunk won't be damaged, so a rollback might occur instead), and as happy side effect, causes oversized regions to gradually shrink towards their most packed state over time, saving disk space.
|
||||
- Regions now have a hard size cap at 64 GB. This is because the header pointers will overflow beyond 64 GB (besides, a normal region shouldn't be this big anyway).
|
||||
- Fixed a crash that could occur when reading a too-short region header.
|
||||
- `VerifyLoginTask` now only copies JWTs to verify instead of the entire login packet. This reduces the amount of data copied between threads, improving performance.
|
||||
- Added a fast-fail check to `VerifyLoginTask` by checking the JWT header's `x5u` against the expected public key.
|
||||
- `Skin->validate()` now throws `InvalidSkinException` instead of `\InvalidArgumentException`.
|
||||
- A debug message is now logged when a player is kicked for having an invalid skin, giving a brief line of detail why.
|
||||
- Fixed players not being kicked for having an invalid `resourcePatch`.
|
||||
- Fixed block meta value of cake being preserved when using pick-block.
|
||||
- Fixed explosions not fully destroying multi-block objects like beds and doors.
|
40
changelogs/3.14.md
Normal file
40
changelogs/3.14.md
Normal file
@ -0,0 +1,40 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.14.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.0.
|
||||
- Removed compatibility with 1.14.60.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.14.1
|
||||
- All skins are now trusted, bypassing the client-side trusted skin setting. Note that this means that NSFW skin filtering will **not** apply.
|
||||
- Fixed projectile motion being altered by ladders.
|
||||
- Fixed client-sided crashes when pressing E repeatedly very quickly on a high-latency connection.
|
||||
- `/plugins`, `/whitelist list`, `/banlist` and `/list` now show output in alphabetical order.
|
||||
- Some `pocketmine\event` APIs which accept arrays now have more robust type checking, fixing type errors caused by plugin input occurring in core code.
|
||||
- `Attribute::getAttributeByName()` is now aware of the `minecraft:lava_movement` attribute.
|
||||
|
||||
# 3.14.2
|
||||
- Exception stack traces are now logged as CRITICAL. It's hoped that users will recognize that they are just as important as the error message and not leave them out when asking for help with errors on Discord.
|
||||
- `TaskScheduler` no longer accepts tasks that already have a handler. This fixes undefined behaviour which occurs when scheduling the same task instance twice, but it does break plugins such as **MyPlot** which unintentionally used this buggy behaviour.
|
||||
- Players will now correctly receive the needed number of spawn chunks if they are teleported between `PlayerLoginEvent` and `PlayerJoinEvent`. This fixes a bug that could occur when teleporting players in delayed tasks between login and join.
|
||||
- `PlayerRespawnEvent->setRespawnPosition()` now throws an exception if the provided `Position` has an invalid world associated with it (null or unloaded).
|
||||
- Fixed a crash that occurred when stats reporting was enabled.
|
||||
|
||||
# 3.14.3
|
||||
- Fixed deprecation error when running `/whitelist list` on PHP 7.4.
|
||||
- Fixed podzol breaking animation being incorrect (incorrect hardness).
|
||||
- `Entity::getSaveId()` now reports the class name in the message thrown for unregistered entities.
|
||||
- Fixed `CraftingManager->validate()` producing different results when called multiple times for the same transaction.
|
||||
- Fixed various issues with batch-crafting items using the recipe book and shift-clicking.
|
||||
- `tests/plugins/PocketMine-DevTools` submodule has been renamed to `tests/plugins/DevTools`.
|
54
changelogs/3.15.md
Normal file
54
changelogs/3.15.md
Normal file
@ -0,0 +1,54 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.20**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.15.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.20.
|
||||
- Removed compatibility with 1.16.0.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.15.1
|
||||
- Fixed various PHP 7.4 compatibility issues in Composer dependencies (primarily callback-validator).
|
||||
- Fixed LevelDB worlds with corrupted `level.dat` crashing the server instead of failing gracefully.
|
||||
- Fixed error spam when using strings for layers in flatworld presets (`e.g. bedrock,3xdirt,grass`).
|
||||
- Fixed blocks not getting updated properly on explosions.
|
||||
- Fixed `BlockGrowEvent` not being called when sugarcane grows.
|
||||
- Potato crops now drop poisonous potatoes when harvested.
|
||||
- Fixed the wrong number of potatoes being dropped when harvesting potato crops.
|
||||
- Players no longer get pullbacks when sprinting on slabs, stairs and various other blocks when `player.anti-cheat.allow-movement-cheats` is set to `false`. (This bug has been around for over 5 years, so many of you will be used to its existence.)
|
||||
- Fixed entity collision box calculation not taking clip distance into account.
|
||||
- Entities now step up the correct height of the target block, instead of jumping into the air 0.6 blocks and falling back down.
|
||||
|
||||
# 3.15.2
|
||||
- Fixed issues with preloading `SubChunk`.
|
||||
- `/gc` and automatic garbage collection will now release unused heap blocks back to the OS. Previously, the PHP process might hold onto these blocks indefinitely even when not used, causing elevated real memory usage.
|
||||
- Added some documentation to `FurnaceBurnEvent`.
|
||||
|
||||
# 3.15.3
|
||||
- Fixed fall damage accumulation over continuous knockbacks (e.g. combo attacks in PvP).
|
||||
- Fixed a bug in `Human->addXp()` that would cause a crash when saving player data.
|
||||
- `Human->addXp()` will no longer modify the target's total XP if `PlayerExperienceChangeEvent` was cancelled.
|
||||
- `AsyncPool->getTaskQueueSizes()` has been added to allow external detection of async pool overload. This is planned to be implemented as a core feature in the future, but it hasn't been done yet.
|
||||
- `BaseInventory->canAddItem()` behaviour now matches `addItem()` by considering the max stack size of the given item.
|
||||
- Fixed a bug in generator options handling for worlds loaded via `pocketmine.yml`. This fix has the following side effects:
|
||||
- It's now possible to provide generator options as an `options` key when loading a world via `pocketmine.yml`.
|
||||
- If generator options are not provided, the options from `server.properties` will be used, instead of using an empty preset. (It's not clear whether this is desired behaviour, but it was clearly intended, since there is code to do this which was broken until this release. As such, this behaviour is subject to change in the future.)
|
||||
- Fixed a bug in region-based world loading where some files without filename extensions and names containing a region filename extension (e.g a file named `amca` in a McRegion world) would cause the world not to load. These files are now ignored.
|
||||
- Default network compression level has been lowered to 6, due to level 7 being 25% more expensive for only a marginal improvement in bandwidth.
|
||||
- Fixed a performance issue with chunk requesting when players trigger chunk generation on first join.
|
||||
- Setup wizard will now always show IP information, even if the user chose to skip the setup wizard when prompted. (This doesn't affect `--no-wizard` in any way.)
|
||||
- `Maximum memory (system)` is no longer reported in `/status` due to having a misleading output (it was the same as the current memory usage).
|
||||
- The `Player Chunk Send` timer on timings reports now actually reports measurements of chunk sending, not chunk loading.
|
||||
- A new parent timer `World Load` has been added to timings reports, which aggregates timings from `syncChunkLoad` and subtimings from all worlds.
|
||||
|
||||
# 3.15.4
|
||||
- Fixed a bug in the inventory transaction system that caused the server to freeze under some circumstances.
|
24
changelogs/3.16.md
Normal file
24
changelogs/3.16.md
Normal file
@ -0,0 +1,24 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.100**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.16.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.100.
|
||||
- Removed compatibility with earlier versions.
|
||||
- Added new custom composer commands `make-server` and `make-devtools` to ease setting up a development environment and building the server.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.16.1
|
||||
- Fixed incorrect encoding of skins in the protocol.
|
||||
- `/version` no longer crashes when a plugin provides `string[]` for the `author` field in `plugin.yml`.
|
||||
- `author` in `plugin.yml` now accepts arrays, just like `authors`.
|
||||
- Fixed `HellBiome` never being registered.
|
63
changelogs/3.17.md
Normal file
63
changelogs/3.17.md
Normal file
@ -0,0 +1,63 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.200**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.17.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.200.
|
||||
- Removed compatibility with earlier versions.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.17.1
|
||||
- Fixed some instances of plugin-caused crashes not being detected (eval()'d code, custom plugin paths).
|
||||
- Server uptime is now included in crash reports.
|
||||
- Hoes now take damage when used to break sponges.
|
||||
- Using lava as fuel in a furnace now leaves behind an empty bucket.
|
||||
|
||||
# 3.17.2
|
||||
- Fixed region header corruption when chunks with larger-than-expected lengths are found. These chunks are now treated as corrupted, instead of automatically attempting to salvage them (which usually fails anyway).
|
||||
- `RegionLoader->removeChunk()` now allows the space used by the removed chunk to be reused by future region saves.
|
||||
- Extracted `Living->applyConsumptionResults()` from `Living->consumeObject()` (preparation for a future bug fix).
|
||||
|
||||
# 3.17.3
|
||||
- Improved performance of chunk loading in Region-based worlds.
|
||||
- Improved performance of region header validation in Region-based worlds (indirect improvement to chunk loading performance).
|
||||
- Fixed some PHP 8.0 language-level compatibility issues.
|
||||
- Source installations will now exit with an error when Composer dependencies are not in sync with the current Git revision. Now, it's required to run `composer install` after every git pull to make sure the correct dependency versions are installed.
|
||||
|
||||
# 3.17.4
|
||||
- Removed `readline` support. This hasn't been maintained for many years, never worked correctly, and isn't thread-safe in any case.
|
||||
- Fixed false-positives of region corruption in Region-based worlds (outdated file stat cache).
|
||||
- Fixed more deprecation warnings on PHP 8.0 (optional parameter before required).
|
||||
- `CraftItemEvent->getInputs()` now returns a list starting at offset 0, instead of random offsets. (Note that the contents still won't be ordered.)
|
||||
- `CraftItemEvent->getOutputs()` now returns a list starting at offset 0, instead of random offsets. (Note that the contents still won't be ordered.)
|
||||
- Fixed a bug that broke synchronized building, bridging, towering and more.
|
||||
- Objects in memory dumps no longer show inherited properties multiple times.
|
||||
|
||||
# 3.17.5
|
||||
- Reduced CPU wastage by the logger thread.
|
||||
- Fixed LevelDB deprecation errors on PHP 8.0.
|
||||
- Added some protocol changes for 1.16.200 which were previously overlooked.
|
||||
- Player XUIDs are now tracked. If a player's XUID does not match the previously recorded XUID when they next join the server, they will be kicked. This can be disabled by the `player.verify-xuid` setting in `pocketmine.yml`.
|
||||
- `BUILDING.md` now has a note about `build/server-phar.php`'s compression bug (a bug in PHP).
|
||||
|
||||
# 3.17.6
|
||||
- Fixed core race conditions that could have led to server freezes (race conditions in pmmp/Snooze).
|
||||
- The log message about Xbox Live authentication being enabled has been reduced to INFO, and the tip on how to turn it off removed (disabling it should usually only be done by power users anyway).
|
||||
- Fixed `PlayerMoveEvent->getFrom()` returning incorrect results for players who experienced movement reversions.
|
||||
- Fixed a bug in `ResourcePackClientResponsePacket` decoding that caused unexpected results when decoding the packet twice.
|
||||
- XUID verification now compares XUIDs against players who are already on the server to detect mismatches to avoid unnecessary loading of playerdata.
|
||||
- Fixed an inventory duplication bug which could occur when the same player joined with two devices at the same time.
|
||||
- Fixed cursor item not being synced on inventory transaction rollbacks.
|
||||
- Fixed items with TAG_Float in their NBT not being able to be moved around in the inventory.
|
||||
|
||||
# 3.17.7
|
||||
- Fixed crash caused by preprocessor in 3.17.6.
|
31
changelogs/3.18.md
Normal file
31
changelogs/3.18.md
Normal file
@ -0,0 +1,31 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.210**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.18.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.210.
|
||||
- Removed compatibility with earlier versions.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
- Items can't be removed from item frames in Survival mode
|
||||
|
||||
# 3.18.1
|
||||
- UPnP is now supported on all platforms instead of just Windows. Note that it's still experimental. Please file issues for any bugs that you find.
|
||||
- Fixed server joining when default game mode is set to Spectator mode.
|
||||
- Fixed items not being able to be removed from item frames in Survival mode.
|
||||
- Fixed field order in ClientCacheBlobStatusPacket (hits and misses were inverted).
|
||||
- Fixed a deadlock that could occur when MainLogger->syncFlushBuffer() was used (usually only used during exception logging).
|
||||
- Updated constants for various things in the protocol.
|
||||
|
||||
# 3.18.2
|
||||
- Fixed `InventoryCloseEvent` not being called on server-initiated inventory closures.
|
||||
- `PlayerToggleFlightEvent` may now be pre-cancelled if the player attempted to enable flight when flying was not allowed. This replaces the previous behaviour of kicking the player.
|
||||
- Fixed being unable to change the item in hand from the inventory window when looking at an entity.
|
26
changelogs/3.19.md
Normal file
26
changelogs/3.19.md
Normal file
@ -0,0 +1,26 @@
|
||||
**For Minecraft: Bedrock Edition 1.16.220**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 3.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.
|
||||
|
||||
# 3.19.0
|
||||
- Added support for Minecraft: Bedrock Edition 1.16.220.
|
||||
- Removed compatibility with earlier versions.
|
||||
|
||||
## Known issues (please don't open issues for these)
|
||||
- Walls don't connect to each other
|
||||
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
|
||||
- New blocks, items & mobs aren't implemented
|
||||
- Nether doesn't exist
|
||||
|
||||
# 3.19.1
|
||||
- Fixed some particles not working since 1.16.220.
|
||||
- Fixed issues with creative inventory items appearing in the wrong places since 1.16.220.
|
||||
- `Item->removeEnchantment()` now removes the `ench` tag from item NBT when removing the only enchantment on an item.
|
||||
- Fixed temporary memory leak of repeating tasks which cancelled themselves during their `onRun()` handler (they were pushed back onto the task queue even though cancelled, and only removed at their next attempted repeat).
|
||||
|
||||
# 3.19.2
|
||||
- Signs can now only be edited by the player who placed them. They will become finalized if the chunk containing them is unloaded and reloaded, or if the creating player quits the server.
|
@ -57,3 +57,73 @@ Plugin developers should **only** update their required API to this version if y
|
||||
- Fixed a memory leak on async task removal in error conditions.
|
||||
- Fixed scheduled block updates (for example liquid) triggering chunk reloading. This could cause a significant performance issue in some conditions.
|
||||
- Fixed some minor cosmetic issues in documentation.
|
||||
|
||||
# 3.9.4
|
||||
- Fixed a memory leak when scheduled updates were pending on a chunk being unloaded.
|
||||
- Fixed plugin detection in crashdumps. Previously `src/pocketmine` anywhere in the path would cause the error to be considered a core crash, regardless of the preceding path.
|
||||
- Fixed entity metadata types for 1.12. The SLOT type was removed and a COMPOUND_TAG type added. This change involves changes to internal API which may break plugins. **See the warning at the top of this changelog about API versioning.**
|
||||
- Fixed random and base populator amounts of trees and tallgrass never being initialized. This bug had no obvious effect, but may have become a problem in future PHP versions.
|
||||
- The following internal methods have been marked as `@deprecated` and documentation warnings added:
|
||||
- `Entity->getBlocksAround()`
|
||||
- `Entity->despawnFrom()`
|
||||
- `Entity->despawnFromAll()`
|
||||
- Fixed plugin `softdepend` not influencing load order when a soft-depended plugin had an unresolved soft dependency of its own.
|
||||
- Fixed endless falling of sand on top of fences.
|
||||
|
||||
# 3.9.5
|
||||
- Fixed some issues with multiple consecutive commas inside quotes in form responses.
|
||||
- Fixed server crash when the manifest json does not contain a json object in a resource pack.
|
||||
- Ender pearls no longer collide with blocks that do not have any collision boxes.
|
||||
|
||||
# 3.9.6
|
||||
- Updated Composer dependencies to their latest versions.
|
||||
- Prevent clients repeating the resource pack sequence. This fixes error spam with bugged 1.12 clients.
|
||||
- `Internet::simpleCurl()` now includes the PocketMine-MP version in the user-agent string.
|
||||
- Spawn protection is now disabled by default in the setup wizard.
|
||||
- Default difficulty is now NORMAL(2) instead of EASY(1).
|
||||
- Fixed crashing on corrupted world manifest and unsupported world formats.
|
||||
- Fixed `/transferserver` being usable without appropriate permissions.
|
||||
- `RegionLoader->removeChunk()` now writes the region header as appropriate.
|
||||
- Fixed performance issue when loading large regions (bug in header validation).
|
||||
- Fixed skin geometry being removed when the JSON contained comments.
|
||||
- Added new constants to `EventPacket`.
|
||||
- Added encode/decode for `StructureTemplateDataExportRequestPacket` and `StructureTemplateDataExportResponsePacket`.
|
||||
- Fixed broken type asserts in `LevelChunkPacket::withCache()` and `ClientCacheMissResponsePacket::create()`.
|
||||
- `types\CommandParameter` field `byte1` has been renamed to `flags`.
|
||||
- Cleaned up public interface of `AvailableCommandsPacket`, removing fields which exposed details of the encoding scheme.
|
||||
- Improved documentation for the following API methods:
|
||||
- `pocketmine\item\Item`:
|
||||
- `addCreativeItem()`
|
||||
- `removeCreativeItem()`
|
||||
- `clearCreativeItems()`
|
||||
- `pocketmine\level\Explosion`:
|
||||
- `explodeA()`
|
||||
- `explodeB()`
|
||||
- Fixed various cosmetic documentation inconsistencies in the core and dependencies.
|
||||
|
||||
# 3.9.7
|
||||
- Fixed a crash that could occur during timezone detection.
|
||||
- Squid no longer spin around constantly in enclosed spaces. Their performance impact is reduced.
|
||||
- Cleaned up the bootstrap file.
|
||||
|
||||
# 3.9.8
|
||||
- Added [PHPStan](https://github.com/phpstan/phpstan) configuration. PHPStan is now used on CI for automated QA, which should improve stability and quality going forward.
|
||||
- The following constants are now autoloaded when loading the Composer autoloader:
|
||||
- `pocketmine\NAME`
|
||||
- `pocketmine\BASE_VERSION`
|
||||
- `pocketmine\IS_DEVELOPMENT_BUILD`
|
||||
- `pocketmine\BUILD_NUMBER`
|
||||
- `INT32_MIN`
|
||||
- `INT32_MAX`
|
||||
- `INT32_MASK`
|
||||
- Fixed memory leaks and crashes caused by plugin use of `Player->showPlayer()` and `Entity->spawnTo()`.
|
||||
- Fixed crashes that could occur when tile classes were overridden with classes incompatible with the originals.
|
||||
- Fixed improper handling of non-Compound root NBT tags on network itemstack decoding.
|
||||
- Fixed paintings dropping multiple items when destroyed by block updates.
|
||||
- Fixed `var_dump()` not showing private and protected properties of `DataPacket` subclasses.
|
||||
- Fixed overloads with zero arguments being missing when decoding `AvailableCommandsPacket`.
|
||||
- `CraftingDataPacket` now retains the `cleanRecipes` field when decoding.
|
||||
- Fixed `Block->getMetadata()` returning null (non-iterable).
|
||||
- `PlayerChatEvent` documentation has been updated to specify that `CommandSender` recipients are accepted. This behaviour was already present in previous versions, but incorrectly documented.
|
||||
- Fixed various issues with PHPDoc comments reported by PHPStan.
|
||||
- Fixed various minor code nits reported by PHPStan.
|
||||
|
@ -1,765 +0,0 @@
|
||||
# 4.0.0-SNAPSHOT-1907XX (2019-07-XX)
|
||||
|
||||
This major version features substantial changes throughout the core, including significant API changes, new world format support, performance improvements and a network revamp.
|
||||
|
||||
## Core
|
||||
### General
|
||||
- A new "plugin greylist" feature has been introduced, which allows whitelisting or blacklisting plugins from loading.
|
||||
- The `/reload` command has been removed.
|
||||
- The `/effect` command no longer supports numeric IDs - it's now required to use names.
|
||||
- Remote console (RCON) has been removed. The [RconServer](https://github.com/pmmp/RconServer) plugin is provided as a substitute.
|
||||
- Spawn protection has been removed. The [BasicSpawnProtection](https://github.com/pmmp/BasicSpawnProtection) plugin is provided as a substitute.
|
||||
- CTRL+C signal handling has been removed. The [PcntlSignalHandler](https://github.com/pmmp/PcntlSignalHandler) plugin is provided as a substitute.
|
||||
- Player movement anti-cheat has been removed. Its corresponding `pocketmine.yml` setting `player.anti-cheat.allow-movement-cheats` has been removed.
|
||||
- The `pocketmine_chunkutils` PHP extension has been dropped.
|
||||
- New PHP extensions are required by this version:
|
||||
- [ds](https://github.com/php-ds/ext-ds)
|
||||
- [chunkutils2](https://github.com/pmmp/ext-chunkutils2)
|
||||
|
||||
### World format support
|
||||
- Modern Minecraft Bedrock world formats are now supported.
|
||||
- Automatic conversion of deprecated world formats is now implemented.
|
||||
- The following world formats have been deprecated and will be **automatically converted on load to a new format**:
|
||||
- `mcregion`
|
||||
- `anvil`
|
||||
- `pmanvil`
|
||||
- 256 build-height is now supported in all worlds (facilitated by automatic conversion).
|
||||
- Extended blocks are now supported (facilitated by automatic conversion).
|
||||
- Unsupported world formats no longer causes a crash, but a graceful shutdown instead.
|
||||
- World corruption no longer causes a crash.
|
||||
|
||||
### Logger revamp
|
||||
- Many components now have a dedicated logger which automatically adds [prefixes] to their messages.
|
||||
- Main logger now includes milliseconds in timestamps.
|
||||
|
||||
### Network
|
||||
This version features substantial changes to the network system, improving coherency, reliability and modularity.
|
||||
|
||||
#### Minecraft Bedrock packet encryption
|
||||
- This fixes replay attacks where hackers steal and replay player logins.
|
||||
- A new setting has been added to `pocketmine.yml`: `network.enable-encryption` which is `true` by default.
|
||||
|
||||
#### Packet receive error handling has been overhauled
|
||||
- Only `BadPacketException` is now caught during packet decode and handling. This requires that all decoding MUST perform proper data error checking.
|
||||
- Throwing a `BadPacketException` from decoding will now cause players to be kicked with the message `Packet processing error`.
|
||||
- The disconnect message includes a random hex ID to help server owners identify the problems reported by their players.
|
||||
- Throwing any other exception will now cause a server crash. `Internal server error` has been removed.
|
||||
- It is now illegal to send a clientbound packet to the server. Doing so will result in the client being kicked with the message `Unexpected non-serverbound packet`.
|
||||
|
||||
#### New packet handler system
|
||||
- Packet handlers have been separated from NetworkSession into a dedicated packet handler structure.
|
||||
- A network session may have exactly 1 handler at a time, which is mutable and may be replaced at any time. This allows packet handling logic to be broken up into multiple stages:
|
||||
- preventing undefined behaviour when sending wrong packets at the wrong time (they'll now be silently dropped)
|
||||
- allowing the existence of ephemeral state-specific logic (for example stricter resource packs download checks)
|
||||
- Packet handlers are now almost entirely absent from `Player` and instead appear in their own dedicated units.
|
||||
- Almost all game logic that was previously locked up inside packet handlers in `Player` has been extracted into new API methods. See Player API changes for details.
|
||||
|
||||
## API
|
||||
### General
|
||||
- Most places which previously allowed `callable` now only allow `\Closure`. This is because closures have more consistent behaviour and are more performant.
|
||||
- `void` and `?nullable` parameter and return types have been applied in many places.
|
||||
- Everything in the `pocketmine\metadata` namespace and related implementations have been removed.
|
||||
|
||||
### Block
|
||||
- Blocks with IDs >= 256 are now supported.
|
||||
- Block state and variant metadata have been separated.
|
||||
- Variant is considered an extension of ID and is immutable.
|
||||
- `Block->setDamage()` has been removed. `Block->readStateFromData()` is now used for state deserialization.
|
||||
- Tile entities are now created and deleted automatically when `World->setBlock()` is used with a block that requires a tile entity.
|
||||
- Some tile entities' API has been exposed on their corresponding `Block` classes, with the tile entity classes being deprecated.
|
||||
- The `pocketmine\tile` namespace has been relocated to `pocketmine\block\tile`.
|
||||
- `Block->recalculateBoundingBox()` and `Block->recalculateCollisionBoxes()` are now expected to return AABBs relative to `0,0,0` instead of their own position.
|
||||
- Block break-info has been extracted into a new dynamic `BlockBreakInfo` unit. The following methods have been moved:
|
||||
- `Block->getBlastResistance()` -> `BlockBreakInfo->getBlastResistance()`
|
||||
- `Block->getBreakTime()` -> `BlockBreakInfo->getBreakTime()`
|
||||
- `Block->getHardness()` -> `BlockBreakInfo->getHardness()`
|
||||
- `Block->getToolHarvestLevel()` -> `BlockBreakInfo->getToolHarvestLevel()`
|
||||
- `Block->getToolType()` -> `BlockBreakInfo->getToolType()`
|
||||
- `Block->isBreakable()` -> `BlockBreakInfo->isBreakable()`
|
||||
- `Block->isCompatibleWithTool()` -> `BlockBreakInfo->isToolCompatible()`
|
||||
- The following API methods have been added:
|
||||
- `Block->asItem()`: returns an itemstack corresponding to the block
|
||||
- `Block->isSameState()`: returns whether the block is the same as the parameter, including state information
|
||||
- `Block->isSameType()`: returns whether the block is the same as the parameter, without state information
|
||||
- The following hooks have been added:
|
||||
- `Block->onAttack()`: called when a player in survival left-clicks the block to try to start breaking it
|
||||
- `Block->onPostPlace()`: called directly after placement in the world, handles things like rail connections and chest pairing
|
||||
- The following API methods have been renamed:
|
||||
- `Block->getDamage()` -> `Block->getMeta()`
|
||||
- `Block->onActivate()` -> `Block->onInteract()`
|
||||
- `Block->onEntityCollide()` -> `Block->onEntityInside()`
|
||||
- The following API methods have changed signatures:
|
||||
- `Block->onInteract()` now has the signature `onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool`
|
||||
- The following API methods have been removed:
|
||||
- `Block->canPassThrough()`
|
||||
- `Block->setDamage()`
|
||||
- `Block::get()`: this was superseded by `BlockFactory::get()` a long time ago
|
||||
- The following classes have been renamed:
|
||||
- `BlockIds` -> `BlockLegacyIds`
|
||||
- `CobblestoneWall` -> `Wall`
|
||||
- `NoteBlock` -> `Note`
|
||||
- `SignPost` -> `Sign`
|
||||
- `StandingBanner` -> `Banner`
|
||||
- The following classes have been removed:
|
||||
- `Bricks`
|
||||
- `BurningFurnace`
|
||||
- `CobblestoneStairs`
|
||||
- `Dandelion`
|
||||
- `DoubleSlab`
|
||||
- `DoubleStoneSlab`
|
||||
- `EndStone`
|
||||
- `GlowingRedstoneOre`
|
||||
- `GoldOre`
|
||||
- `Gold`
|
||||
- `IronDoor`
|
||||
- `IronOre`
|
||||
- `IronTrapdoor`
|
||||
- `Iron`
|
||||
- `Lapis`
|
||||
- `NetherBrickFence`
|
||||
- `NetherBrickStairs`
|
||||
- `Obsidian`
|
||||
- `PurpurStairs`
|
||||
- `Purpur`
|
||||
- `QuartzStairs`
|
||||
- `Quartz`
|
||||
- `RedSandstoneStairs`
|
||||
- `RedSandstone`
|
||||
- `SandstoneStairs`
|
||||
- `Sandstone`
|
||||
- `StainedClay`
|
||||
- `StainedGlassPane`
|
||||
- `StainedGlass`
|
||||
- `StoneBrickStairs`
|
||||
- `StoneBricks`
|
||||
- `StoneSlab2`
|
||||
- `StoneSlab`
|
||||
- `Stone`
|
||||
- `WallBanner`
|
||||
- `WallSign`
|
||||
- `Wood2`
|
||||
- `BlockToolType` constants have been renamed to remove the `TYPE_` prefix.
|
||||
|
||||
### Command
|
||||
- The following classes have been removed:
|
||||
- `RemoteConsoleCommandSender`
|
||||
- The following API methods have signature changes:
|
||||
- `Command->setPermission()` argument is now mandatory (but still nullable).
|
||||
- `CommandSender->setScreenLineHeight()` argument is now mandatory (but still nullable).
|
||||
|
||||
### Entity
|
||||
#### General
|
||||
- The following API methods have been added:
|
||||
- `ItemEntity->getDespawnDelay()`
|
||||
- `ItemEntity->setDespawnDelay()`
|
||||
- `Human->getHungerManager()`
|
||||
- `Human->getXpManager()`
|
||||
- The following methods have signature changes:
|
||||
- `Entity->entityBaseTick()` is now `protected`.
|
||||
- `Entity->move()` is now `protected`.
|
||||
- `Living->knockBack()` now accepts `float, float, float` (the first two parameters have been removed).
|
||||
- `Living->getEffects()` now returns `EffectManager` instead of `Effect[]`.
|
||||
- The following classes have been added:
|
||||
- `effect\EffectManager`: contains effect-management functionality extracted from `Living`
|
||||
- `HungerManager`: contains hunger-management functionality extracted from `Human`
|
||||
- `ExperienceManager`: contains XP-management functionality extracted from `Human`
|
||||
- The following API methods have been moved / renamed:
|
||||
- `Living->removeAllEffects()` -> `EffectManager->clear()`
|
||||
- `Living->removeEffect()` -> `EffectManager->remove()`
|
||||
- `Living->addEffect()` -> `EffectManager->add()`
|
||||
- `Living->getEffect()` -> `EffectManager->get()`
|
||||
- `Living->hasEffect()` -> `EffectManager->has()`
|
||||
- `Living->hasEffects()` -> `EffectManager->hasEffects()`
|
||||
- `Living->getEffects()` -> `EffectManager->all()`
|
||||
- `Human->getFood()` -> `HungerManager->getFood()`
|
||||
- `Human->setFood()` -> `HungerManager->setFood()`
|
||||
- `Human->getMaxFood()` -> `HungerManager->getMaxFood()`
|
||||
- `Human->addFood()` -> `HungerManager->addFood()`
|
||||
- `Human->isHungry()` -> `HungerManager->isHungry()`
|
||||
- `Human->getSaturation()` -> `HungerManager->getSaturation()`
|
||||
- `Human->setSaturation()` -> `HungerManager->setSaturation()`
|
||||
- `Human->addSaturation()` -> `HungerManager->addSaturation()`
|
||||
- `Human->getExhaustion()` -> `HungerManager->getExhaustion()`
|
||||
- `Human->setExhaustion()` -> `HungerManager->setExhaustion()`
|
||||
- `Human->exhaust()` -> `HungerManager->exhaust()`
|
||||
- `Human->getXpLevel()` -> `ExperienceManager->getXpLevel()`
|
||||
- `Human->setXpLevel()` -> `ExperienceManager->setXpLevel()`
|
||||
- `Human->addXpLevels()` -> `ExperienceManager->addXpLevels()`
|
||||
- `Human->subtractXpLevels()` -> `ExperienceManager->subtractXpLevels()`
|
||||
- `Human->getXpProgress()` -> `ExperienceManager->getXpProgress()`
|
||||
- `Human->setXpProgress()` -> `ExperienceManager->setXpProgress()`
|
||||
- `Human->getRemainderXp()` -> `ExperienceManager->getRemainderXp()`
|
||||
- `Human->getCurrentTotalXp()` -> `ExperienceManager->getCurrentTotalXp()`
|
||||
- `Human->setCurrentTotalXp()` -> `ExperienceManager->setCurrentTotalXp()`
|
||||
- `Human->addXp()` -> `ExperienceManager->addXp()`
|
||||
- `Human->subtractXp()` -> `ExperienceManager->subtractXp()`
|
||||
- `Human->getLifetimeTotalXp()` -> `ExperienceManager->getLifetimeTotalXp()`
|
||||
- `Human->setLifetimeTotalXp()` -> `ExperienceManager->setLifetimeTotalXp()`
|
||||
- `Human->canPickupXp()` -> `ExperienceManager->canPickupXp()`
|
||||
- `Human->onPickupXp()` -> `ExperienceManager->onPickupXp()`
|
||||
- `Human->resetXpCooldown()` -> `ExperienceManager->resetXpCooldown()`
|
||||
- The following API methods have been removed:
|
||||
- `Human->getRawUniqueId()`: use `Human->getUniqueId()->toBinary()` instead
|
||||
- The following classes have been removed:
|
||||
- `Creature`
|
||||
- `Damageable`
|
||||
- `Monster`
|
||||
- `NPC`
|
||||
- `Rideable`
|
||||
- `Vehicle`
|
||||
- `Skin` now throws exceptions on creation if given invalid data.
|
||||
|
||||
#### Effect
|
||||
- All `Effect` related classes have been moved to the `pocketmine\entity\effect` namespace.
|
||||
- Effect functionality embedded in the `Effect` class has been separated out into several classes. The following classes have been added:
|
||||
- `AbsorptionEffect`
|
||||
- `HealthBoostEffect`
|
||||
- `HungerEffect`
|
||||
- `InstantDamageEffect`
|
||||
- `InstantEffect`
|
||||
- `InstantHealthEffect`
|
||||
- `InvisibilityEffect`
|
||||
- `LevitationEffect`
|
||||
- `PoisonEffect`
|
||||
- `RegenerationEffect`
|
||||
- `SaturationEffect`
|
||||
- `SlownessEffect`
|
||||
- `SpeedEffect`
|
||||
- `WitherEffect`
|
||||
- Negative effect amplifiers are now explicitly disallowed due to undefined behaviour they created.
|
||||
- The following API methods have been renamed:
|
||||
- `Effect::registerEffect()` -> `Effect::register()`
|
||||
- `Effect::getEffect()` -> `Effect::get()`
|
||||
- `Effect::getEffectByName()` -> `Effect::fromString()`
|
||||
- Static getter methods for all registered enchantment types have been added. `Effect::getEffect(Effect::WHATEVER)` should be replaced by `VanillaEffects::WHATEVER()`.
|
||||
- All effect registry functionality has been removed from the `Effect` base class and migrated to the `VanillaEffects` class.
|
||||
|
||||
#### Removal of runtime entity NBT
|
||||
- Entities no longer keep their NBT alive at runtime.
|
||||
- `Entity->namedtag` has been removed.
|
||||
- `Entity->saveNBT()` now returns a newly created `CompoundTag` instead of modifying the previous one in-place.
|
||||
- `Entity->initEntity()` now accepts a `CompoundTag` parameter.
|
||||
|
||||
#### Entity creation
|
||||
- Entity class overriding is now explicitly supported, without needing to touch save IDs.
|
||||
- Entity classes can be overridden using `EntityFactory::override()`. The provided replacement class **must** be a subclass of the existing class. If the existing class isn't there, an exception will be thrown.
|
||||
- Attempting to register an entity to a save ID that is already registered will now cause an exception to be thrown.
|
||||
- Registering entities will now throw exceptions on error cases instead of returning `false`.
|
||||
- Entity creation has now been split into two paths:
|
||||
- `EntityFactory::create()`: Creates an entity by the given class. This accepts arguments to be passed to the entity constructor. This function is guaranteed to return an entity which is an instanceof the given class.
|
||||
- `EntityFactory::createFromData()`: Creates an entity from save data. This may return any `Entity` class or `NULL`. This function is internal and shouldn't be used by plugins.
|
||||
- It is no longer possible to directly create an entity by save ID. This is discouraged because save IDs are internal and format-dependent.
|
||||
- The following API methods have been moved:
|
||||
- `Entity::registerEntity()` -> `EntityFactory::register()`
|
||||
- `Entity::createEntity()` -> `EntityFactory::create()`
|
||||
- `Entity::getKnownEntityTypes()` -> `EntityFactory::getKnownTypes()`
|
||||
- `Entity::createBaseNBT()` -> `EntityFactory::createBaseNBT()`
|
||||
- The following API methods have been removed:
|
||||
- `Entity->getSaveId()`
|
||||
|
||||
#### WIP removal of entity network metadata
|
||||
- All network metadata related constants have been removed from the `Entity` class and moved to the protocol layer. It is intended to remove network metadata from the API entirely, but this has not yet been completed.
|
||||
- `Entity::DATA_FLAG_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\EntityMetadataFlags`.
|
||||
- `Entity::DATA_TYPE_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\EntityMetadataTypes`.
|
||||
- `Entity::DATA_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\EntityMetadataProperties`.
|
||||
- `DataPropertyManager` has been moved to the `pocketmine\network\mcpe\protocol\types` namespace, and as such isn't considered part of the API anymore.
|
||||
|
||||
### Event
|
||||
#### Internal event system no longer depends on `Listener`s
|
||||
- The internal event processing system no longer depends on `Listener` objects. Arbitrary closures can now be used, provided that they satisfy the standard requirements to be a handler.
|
||||
- This change improves performance of event handler calling by approximately 15%. This does not include anything plugins are doing.
|
||||
- The following classes have been removed:
|
||||
- `pocketmine\plugin\EventExecutor`
|
||||
- `pocketmine\plugin\MethodEventExecutor`
|
||||
- `RegisteredListener->__construct()` now requires `Closure` instead of `Listener, EventExecutor` as the leading parameters.
|
||||
- `RegisteredListener->getListener()` has been removed.
|
||||
|
||||
#### Default cancelled handling behaviour has changed
|
||||
- Handler functions will now **not receive cancelled events by default**. This is a **silent BC break**, i.e. it won't raise errors, but it might cause bugs.
|
||||
- `@ignoreCancelled` is now no longer respected.
|
||||
- `@handleCancelled` has been added. This allows opting _into_ receiving cancelled events (it's the opposite of `@ignoreCancelled`).
|
||||
|
||||
#### `PlayerPreLoginEvent` changes
|
||||
- The `Player` object no longer exists at this phase of the login. Instead, a `PlayerInfo` object is provided, along with connection information.
|
||||
- Ban, server-full and whitelist checks are now centralized to `PlayerPreLoginEvent`. It's no longer necessary (or possible) to intercept `PlayerKickEvent` to handle these types of disconnects.
|
||||
- Multiple kick reasons may be set to ensure that the player is still removed if there are other reasons for them to be disconnected and one of them is cleared. For example, if a player is banned and the server is full, clearing the ban flag will still cause the player to be disconnected because the server is full.
|
||||
- Plugins may set custom kick reasons. Any custom reason has absolute priority.
|
||||
- If multiple flags are set, the kick message corresponding to the highest priority reason will be shown. The priority (as of this snapshot) is as follows:
|
||||
- Custom (highest priority)
|
||||
- Server full
|
||||
- Whitelisted
|
||||
- Banned
|
||||
- The `PlayerPreLoginEvent::KICK_REASON_PRIORITY` constant contains a list of kick reason priorities, highest first.
|
||||
- The following constants have been added:
|
||||
- `PlayerPreLoginEvent::KICK_REASON_PLUGIN`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_SERVER_FULL`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_BANNED`
|
||||
- `PlayerPreLoginEvent::KICK_REASON_PRIORITY`: ordered list of kick reason priorities, highest first
|
||||
- The following API methods have been added:
|
||||
- `PlayerPreLoginEvent->clearAllKickReasons()`
|
||||
- `PlayerPreLoginEvent->clearKickReason()`
|
||||
- `PlayerPreLoginEvent->getFinalKickMessage()`: the message to be shown to the player with the current reason list in place
|
||||
- `PlayerPreLoginEvent->getIp()`
|
||||
- `PlayerPreLoginEvent->getKickReasons()`: returns an array of flags indicating kick reasons, must be empty to allow joining
|
||||
- `PlayerPreLoginEvent->getPlayerInfo()`
|
||||
- `PlayerPreLoginEvent->getPort()`
|
||||
- `PlayerPreLoginEvent->isAllowed()`
|
||||
- `PlayerPreLoginEvent->isAuthRequired()`: whether XBL authentication will be enforced
|
||||
- `PlayerPreLoginEvent->isKickReasonSet()`
|
||||
- `PlayerPreLoginEvent->setAuthRequired()`
|
||||
- `PlayerPreLoginEvent->setKickReason()`
|
||||
- The following API methods have been changed:
|
||||
- `PlayerPreLoginEvent->getKickMessage()` now has the signature `getKickMessage(int $flag) : ?string`
|
||||
- The following API methods have been removed:
|
||||
- `PlayerPreLoginEvent->setKickMessage()`
|
||||
- `PlayerPreLoginEvent->getPlayer()`
|
||||
|
||||
#### Other changes
|
||||
- Disconnecting players during events no longer crashes the server (although it might cause other side effects).
|
||||
- `PlayerKickEvent` is no longer fired for disconnects that occur before the player completes the initial login sequence (i.e. completing downloading resource packs).
|
||||
- Cancellable events must now implement `CancellableTrait` to get the cancellable components needed to satisfy interface requirements.
|
||||
- `PlayerInteractEvent` is no longer fired when a player activates an item. This fixes the age-old complaint of `PlayerInteractEvent` firing multiple times when interacting once. The following constants have been removed:
|
||||
- `PlayerInteractEvent::LEFT_CLICK_AIR`
|
||||
- `PlayerInteractEvent::RIGHT_CLICK_AIR`
|
||||
- `PlayerInteractEvent::PHYSICAL`
|
||||
- The following events have been added:
|
||||
- `PlayerItemUseEvent`: player activating their held item, for example to throw it.
|
||||
- `BlockTeleportEvent`: block teleporting, for example dragon egg when attacked.
|
||||
- The following events have been removed:
|
||||
- `EntityArmorChangeEvent`
|
||||
- `EntityInventoryChangeEvent`
|
||||
- `EntityLevelChangeEvent` - `EntityTeleportEvent` with world checks should be used instead.
|
||||
- `NetworkInterfaceCrashEvent`
|
||||
- `PlayerCheatEvent`
|
||||
- `PlayerIllegalMoveEvent`
|
||||
- The following API methods have been added:
|
||||
- `EntityDeathEvent->getXpDropAmount()`
|
||||
- `EntityDeathEvent->setXpDropAmount()`
|
||||
- `PlayerDeathEvent->getXpDropAmount()`
|
||||
- `PlayerDeathEvent->setXpDropAmount()`
|
||||
- The following API methods have been removed:
|
||||
- `PlayerPreLoginEvent->getPlayer()`
|
||||
- The following API methods have been moved:
|
||||
- `Event->isCancelled()` -> `CancellableTrait->isCancelled()`: this was a stub which threw `BadMethodCallException` if the class didn't implement `Cancellable`; now this is simply not available on non-cancellable events
|
||||
- `Event->setCancelled()` -> `CancellableTrait->setCancelled()`
|
||||
- `HandlerList::unregisterAll()` -> `HandlerListManager->unregisterAll()`
|
||||
- `HandlerList::getHandlerListFor()` -> `HandlerListManager->getListFor()`
|
||||
- `HandlerList::getHandlerLists()` -> `HandlerListManager->getAll()`
|
||||
- The following classes have been moved:
|
||||
- `pocketmine\plugin\RegisteredListener` -> `pocketmine\event\RegisteredListener`
|
||||
|
||||
### Inventory
|
||||
- All crafting and recipe related classes have been moved to the `pocketmine\crafting` namespace.
|
||||
- The following classes have been added:
|
||||
- `CallbackInventoryChangeListener`
|
||||
- `CreativeInventory`: contains the creative functionality previously embedded in `pocketmine\item\Item`, see Item changes for details
|
||||
- `InventoryChangeListener`: allows listening (but not interfering with) events in an inventory.
|
||||
- `transaction\CreateItemAction`
|
||||
- `transaction\DestroyItemAction`
|
||||
- The following classes have been renamed:
|
||||
- `ContainerInventory` -> `BlockInventory`
|
||||
- The following classes have been removed:
|
||||
- `CustomInventory`
|
||||
- `InventoryEventProcessor`
|
||||
- `Recipe`
|
||||
- `transaction\CreativeInventoryAction`
|
||||
- The following API methods have been added:
|
||||
- `Inventory->addChangeListeners()`
|
||||
- `Inventory->getChangeListeners()`
|
||||
- `Inventory->removeChangeListeners()`
|
||||
- `Inventory->swap()`: swaps the contents of two slots
|
||||
- The following API methods have been removed:
|
||||
- `BaseInventory->getDefaultSize()`
|
||||
- `BaseInventory->setSize()`
|
||||
- `Inventory->close()`
|
||||
- `Inventory->dropContents()`
|
||||
- `Inventory->getName()`
|
||||
- `Inventory->getTitle()`
|
||||
- `Inventory->onSlotChange()`
|
||||
- `Inventory->open()`
|
||||
- `Inventory->sendContents()`
|
||||
- `Inventory->sendSlot()`
|
||||
- `InventoryAction->onExecuteFail()`
|
||||
- `InventoryAction->onExecuteSuccess()`
|
||||
- `PlayerInventory->sendCreativeContents()`
|
||||
- The following API methods have signature changes:
|
||||
- `Inventory->clear()` now returns `void` instead of `bool`.
|
||||
- `Inventory->setItem()` now returns `void` instead of `bool`.
|
||||
- `InventoryAction->execute()` now returns `void` instead of `bool`.
|
||||
- `BaseInventory->construct()` no longer accepts a list of items to initialize with.
|
||||
- `PlayerInventory->setItemInHand()` now sends the update to viewers of the player.
|
||||
|
||||
### Item
|
||||
#### General
|
||||
- `Item->count` is no longer public.
|
||||
- The hierarchy of writable books has been changed: `WritableBook` and `WrittenBook` now extend `WritableBookBase`.
|
||||
- The following API methods have signature changes:
|
||||
- `WritableBookBase->setPages()` now accepts `WritableBookPage[]` instead of `CompoundTag[]`.
|
||||
- `ItemFactory::get()` no longer accepts `string` for the `tags` parameter.
|
||||
- `ItemFactory::fromString()` no longer accepts a `$multiple` parameter and now only returns `Item`, not `Item|Item[]`.
|
||||
- The following methods are now fluent:
|
||||
- `WritableBookBase->setPages()`
|
||||
- `Item->addEnchantment()`
|
||||
- `Item->removeEnchantment()`
|
||||
- `Item->removeEnchantments()`
|
||||
- `Armor->setCustomColor()`
|
||||
- `WrittenBook->setTitle()`
|
||||
- `WrittenBook->setAuthor()`
|
||||
- `WrittenBook->setGeneration()`
|
||||
- The following API methods have been removed:
|
||||
- `Item->getNamedTagEntry()`
|
||||
- `Item->removeNamedTagEntry()`
|
||||
- `Item->setDamage()`: "Damage" is now immutable for all items except `Durable` descendents.
|
||||
- `Item->setNamedTagEntry()`
|
||||
- `Item::get()`: this was superseded by `ItemFactory::get()` a long time ago
|
||||
- `Item::fromString()`: this was superseded by `ItemFactory::fromString()` a long time ago
|
||||
- `Item->setCompoundTag()`
|
||||
- `Item->getCompoundTag()`
|
||||
- `Item->hasCompoundTag()`
|
||||
- `ProjectileItem->getProjectileEntityType()`
|
||||
- The following methods have been renamed:
|
||||
- `Item->getDamage()` -> `Item->getMeta()`
|
||||
- The following methods have been moved to `pocketmine\inventory\CreativeInventory`:
|
||||
- `Item::addCreativeItem()` -> `CreativeInventory::add()`
|
||||
- `Item::clearCreativeItems()` -> `CreativeInventory::clear()`
|
||||
- `Item::getCreativeItemIndex()` -> `CreativeInventory::getItemIndex()`
|
||||
- `Item::getCreativeItems()` -> `CreativeInventory::getAll()`
|
||||
- `Item::initCreativeItems()` -> `CreativeInventory::init()`
|
||||
- `Item::isCreativeItem()` -> `CreativeInventory::contains()`
|
||||
- `Item::removeCreativeItem()` -> `CreativeInventory::remove()`
|
||||
- The following classes have been added:
|
||||
- `ArmorTypeInfo`
|
||||
- `Boots`
|
||||
- `Chestplate`
|
||||
- `Fertilizer`
|
||||
- `Helmet`
|
||||
- `Leggings`
|
||||
- `LiquidBucket`
|
||||
- `MilkBucket`
|
||||
- `WritableBookBase`
|
||||
- `WritableBookPage`
|
||||
- The following API methods have been added:
|
||||
- `Armor->getArmorSlot()`
|
||||
- `ProjectileItem->getProjectileEntityClass()`: returns the class of projectile to be created when thrown
|
||||
- The following classes have been removed:
|
||||
- `ChainBoots`
|
||||
- `ChainChestplate`
|
||||
- `ChainHelmet`
|
||||
- `ChainLeggings`
|
||||
- `DiamondBoots`
|
||||
- `DiamondChestplate`
|
||||
- `DiamondHelmet`
|
||||
- `DiamondLeggings`
|
||||
- `GoldBoots`
|
||||
- `GoldChestplate`
|
||||
- `GoldHelmet`
|
||||
- `GoldLeggings`
|
||||
- `IronBoots`
|
||||
- `IronChesplate`
|
||||
- `IronHelmet`
|
||||
- `IronLeggings`
|
||||
- `LeatherBoots`
|
||||
- `LeatherCap`
|
||||
- `LeatherPants`
|
||||
- `LeatherTunic`
|
||||
|
||||
#### NBT handling
|
||||
- Serialized NBT byte array caches are no longer stored on itemstacks. These caches were a premature optimization used for network layer serialization and as such were dependent on the network NBT format.
|
||||
- Internal NBT usage has been marginalized. It's no longer necessary to immediately write changes to NBT. The following hooks have been added:
|
||||
- `Item->serializeCompoundTag()`
|
||||
- `Item->deserializeCompoundTag()`
|
||||
- It's planned to remove runtime NBT from items completely, but this currently presents unresolved backwards-compatibility problems.
|
||||
|
||||
#### Enchantment
|
||||
- The following API methods have been renamed:
|
||||
- `Enchantment::registerEnchantment()` -> `Enchantment::register()`
|
||||
- `Enchantment::getEnchantment()` -> `Enchantment::get()`
|
||||
- `Enchantment::getEnchantmentByName()` -> `Enchantment::fromString()`
|
||||
- Static getter methods for all registered enchantment types have been added. `Enchantment::getEnchantment(Enchantment::WHATEVER)` should be replaced by `Enchantment::WHATEVER()`.
|
||||
|
||||
### Lang
|
||||
- The following classes have been renamed:
|
||||
- `BaseLang` -> `Language`
|
||||
- `LanguageNotFoundException` has been added. This is thrown when trying to construct a `Language` which doesn't exist in the server files.
|
||||
|
||||
|
||||
### Network
|
||||
- The following fields have been removed:
|
||||
- `Network::$BATCH_THRESHOLD`
|
||||
- The following classes have been renamed:
|
||||
- `SourceInterface` -> `NetworkInterface`
|
||||
- `AdvancedSourceInterface` -> `AdvancedNetworkInterface`
|
||||
- The following classes have been moved:
|
||||
- `CompressBatchedTask` -> `mcpe\CompressBatchTask`
|
||||
- `level\format\io\ChunkRequestTask` -> `mcpe\ChunkRequestTask`
|
||||
- `mcpe\RakLibInterface` -> `mcpe\raklib\RakLibInterface`
|
||||
- The following classes have been removed:
|
||||
- `mcpe\PlayerNetworkSessionAdapter`
|
||||
- The following methods have been removed:
|
||||
- `NetworkInterface->putPacket()`
|
||||
- `NetworkInterface->close()`
|
||||
- `NetworkInterface->emergencyShutdown()`
|
||||
- `NetworkInterface` now represents a more generic interface to be implemented by any network component, as opposed to specifically a player network interface.
|
||||
- Everything under the `rcon` subnamespace has been removed.
|
||||
- `upnp\UPnP` has significant changes. It's now a network component instead of a pair of static methods.
|
||||
|
||||
### Permission
|
||||
- Added `PermissibleDelegateTrait` to reduce boilerplate for users of `PermissibleBase`. This trait is used by `ConsoleCommandSender` and `Player`.
|
||||
- The following API methods have been moved:
|
||||
- `Permission::getByName()` -> `PermissionParser::defaultFromString()`
|
||||
- `Permission::loadPermissions()` -> `PermissionParser::loadPermissions()`
|
||||
- `Permission::loadPermission()` -> `PermissionParser::loadPermission()`
|
||||
- The following API methods have been added:
|
||||
- `PermissionParser::emitPermissions()`
|
||||
- The following API methods have changes:
|
||||
- `PermissionParser::defaultFromString()` now throws `InvalidArgumentException` on unknown values.
|
||||
|
||||
### Player
|
||||
- The following classes have moved to the new `pocketmine\player` namespace:
|
||||
- `Achievement`
|
||||
- `GameMode`
|
||||
- `IPlayer`
|
||||
- `OfflinePlayer`
|
||||
- `PlayerInfo`
|
||||
- `Player`
|
||||
- The following constants have been removed:
|
||||
- `Player::SURVIVAL` - use `GameMode::SURVIVAL()`
|
||||
- `Player::CREATIVE` - use `GameMode::CREATIVE()`
|
||||
- `Player::ADVENTURE` - use `GameMode::ADVENTURE()`
|
||||
- `Player::SPECTATOR` - use `GameMode::SPECTATOR()`
|
||||
- `Player::VIEW` - use `GameMode::SPECTATOR()`
|
||||
- (almost) all packet handlers have been removed from `Player`. They are now encapsulated within the network layer.
|
||||
- The following API methods have been added:
|
||||
- `Player->attackBlock()`: attack (left click) the target block, e.g. to start destroying it (survival)
|
||||
- `Player->attackEntity()`: melee-attack (left click) the target entity (if within range)
|
||||
- `Player->breakBlock()`: destroy the target block in the current world (immediately)
|
||||
- `Player->consumeHeldItem()`: consume the previously activated item, e.g. eating food
|
||||
- `Player->continueBreakBlock()`: punch the target block during destruction in survival, advancing break animation and creating particles
|
||||
- `Player->hasFiniteResources()`
|
||||
- `Player->interactBlock()`: interact (right click) the target block in the current world
|
||||
- `Player->interactEntity()`: interact (right click) the target entity, e.g. to apply a nametag (not implemented yet)
|
||||
- `Player->pickBlock()`: picks (mousewheel click) the target block in the current world
|
||||
- `Player->releaseHeldItem()`: release the previously activated item, e.g. shooting a bow
|
||||
- `Player->selectHotbarSlot()`: select the specified hotbar slot
|
||||
- `Player->stopBreakBlock()`: cease attacking a previously attacked block
|
||||
- `Player->toggleFlight()`: tries to start / stop flying (fires events, may be cancelled)
|
||||
- `Player->updateNextPosition()`: sets the player's next attempted move location (fires events, may be cancelled)
|
||||
- `Player->useHeldItem()`: activate the held item, e.g. throwing a snowball
|
||||
- The following API methods have been removed:
|
||||
- `Player->addActionBarMessage()`: replaced by `sendActionBarMessage()`
|
||||
- `Player->addSubTitle()`: replaced by `sendSubTitle()`
|
||||
- `Player->addTitle()`: replaced by `sendTitle()`
|
||||
- `Player->getAddress()`: replaced by `NetworkSession->getIp()`
|
||||
- `Player->getPing()`: moved to `NetworkSession`
|
||||
- `Player->getPort()`: moved to `NetworkSession`
|
||||
- `Player->updatePing()`: moved to `NetworkSession`
|
||||
|
||||
|
||||
### Plugin
|
||||
- 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 removed:
|
||||
- `PluginLogger`
|
||||
- The following interface requirements have been removed:
|
||||
- `Plugin->onEnable()`: this is now internalized inside `PluginBase`
|
||||
- `Plugin->onDisable()`: same as above
|
||||
- `Plugin->onLoad()`: same as above
|
||||
- `Plugin` no longer extends `CommandExecutor`. This means that `Plugin` implementations don't need to implement `onCommand()` anymore.
|
||||
- The following hook methods have changed visibility:
|
||||
- `PluginBase->onEnable()` changed from `public` to `protected`
|
||||
- `PluginBase->onDisable()` changed from `public` to `protected`
|
||||
- `PluginBase->onLoad()` changed from `public` to `protected`
|
||||
- The following hook methods have been renamed:
|
||||
- `Plugin->setEnabled()` -> `Plugin->onEnableStateChange()`. This change was made to force plugin developers misusing this hook to stop, and to give it a name that better describes what it does.
|
||||
- The following (deprecated) API methods have been removed:
|
||||
- `PluginManager->callEvent()`: use `Event->call()` instead
|
||||
- `PluginManager->addPermission()`: use `PermissionManager` instead
|
||||
- `PluginManager->getDefaultPermSubscriptions()`: use `PermissionManager` instead
|
||||
- `PluginManager->getDefaultPermissions()`: use `PermissionManager` instead
|
||||
- `PluginManager->getPermission()`: use `PermissionManager` instead
|
||||
- `PluginManager->getPermissionSubscriptions()`: use `PermissionManager` instead
|
||||
- `PluginManager->getPermissions()`: use `PermissionManager` instead
|
||||
- `PluginManager->recalculatePermissionDefaults()`: use `PermissionManager` instead
|
||||
- `PluginManager->removePermission()`: use `PermissionManager` instead
|
||||
- `PluginManager->subscribeToDefaultPerms()`: use `PermissionManager` instead
|
||||
- `PluginManager->subscribeToPermission()`: use `PermissionManager` instead
|
||||
- `PluginManager->unsubscribeFromDefaultPerms()`: use `PermissionManager` instead
|
||||
- `PluginManager->unsubscribeFromPermission()`: use `PermissionManager` instead
|
||||
- It is no longer permitted to throw exceptions from `PluginBase->onEnable()` or `PluginBase->onLoad()`. Doing so will now cause the server to crash.
|
||||
|
||||
### Scheduler
|
||||
#### Thread-local storage for AsyncTasks
|
||||
- TLS has been completely rewritten in this release to be self contained, more robust and easier to use.
|
||||
- Now behaves more like simple properties. `storeLocal()` writes, `fetchLocal()` reads.
|
||||
- Self-contained and doesn't depend on the async pool to clean up after it.
|
||||
- Values are automatically removed from storage when the `AsyncTask` is garbage-collected, just like a regular property.
|
||||
- Supports storing multiple values, differentiated by string names.
|
||||
- `fetchLocal()` can now be used multiple times. It no longer deletes the stored value.
|
||||
- The following classes have been removed:
|
||||
- `FileWriteTask`
|
||||
- The following methods have been removed:
|
||||
- `AsyncTask->peekLocal()`: use `fetchLocal()` instead
|
||||
- The following methods have signature changes:
|
||||
- `AsyncTask->storeLocal()` now has the signature `storeLocal(string $key, mixed $complexData) : void`
|
||||
- `AsyncTask->fetchLocal()` now has the signature `fetchLocal(string $key) : mixed`
|
||||
|
||||
#### Other changes
|
||||
- `AsyncPool` uses a new, significantly more performant algorithm for task collection.
|
||||
- `BulkCurlTask` has had the `$complexData` constructor parameter removed.
|
||||
- `pocketmine\Collectable` has been removed, and is no longer extended by `AsyncTask`.
|
||||
- The following hooks have been added:
|
||||
- `AsyncTask->onError()`: called on the main thread when an uncontrolled error was detected in the async task, such as a memory failure
|
||||
- The following hooks have signature changes:
|
||||
- `AsyncTask->onCompletion()` no longer accepts a `Server` parameter, and has a `void` return type.
|
||||
- `AsyncTask->onProgressUpdate()` no longer accepts a `Server` parameter, and has a `void` return type.
|
||||
- The following API methods have been removed:
|
||||
- `AsyncTask->getFromThreadStore()`: use `AsyncTask->worker->getFromThreadStore()`
|
||||
- `AsyncTask->removeFromThreadStore()`: use `AsyncTask->worker->removeFromThreadStore()`
|
||||
- `AsyncTask->saveToThreadStore()`: use `AsyncTask->worker->saveToThreadStore()`
|
||||
|
||||
### Server
|
||||
- The following API methods have been removed:
|
||||
- `reloadWhitelist()`
|
||||
- `getLevelMetadata()`
|
||||
- `getPlayerMetadata()`
|
||||
- `getEntityMetadata()`
|
||||
- `getDefaultGamemode()`
|
||||
- `getLoggedInPlayers()`
|
||||
- `onPlayerLogout()`
|
||||
- `addPlayer()`
|
||||
- `removePlayer()`
|
||||
- `reload()`
|
||||
- `getSpawnRadius()`
|
||||
- `enablePlugin()`
|
||||
- `disablePlugin()`
|
||||
- `getGamemodeString()` - replaced by `pocketmine\player\GameMode->getTranslationKey()`
|
||||
- `getGamemodeName()` - replaced by `pocketmine\player\GameMode->name()`
|
||||
- `getGamemodeFromString()` - replaced by `GameMode::fromString()`
|
||||
- The following API methods have changed:
|
||||
- `getOfflinePlayerData()` no longer creates data when it doesn't exist.
|
||||
|
||||
### Level / World
|
||||
#### General
|
||||
- All references to `Level` in the context of "world" have been changed to `World`.
|
||||
- The `pocketmine\level` namespace has been renamed to `pocketmine\world`
|
||||
- All classes containing the world `Level` in the name in the "world" context have been changed to `World`.
|
||||
- `Position->getLevel()` has been renamed to `Position->getWorld()`, and `Position->level` has been renamed to `Position->world`.
|
||||
- Extracted a `WorldManager` unit from `Server`
|
||||
- `Server->findEntity()` -> `WorldManager->findEntity()`
|
||||
- `Server->generateLevel()` -> `WorldManager->generateWorld()`
|
||||
- `Server->getAutoSave()` -> `WorldManager->getAutoSave()`
|
||||
- `Server->getDefaultLevel()` -> `WorldManager->getDefaultWorld()`
|
||||
- `Server->getLevel()` -> `WorldManager->getWorld()`
|
||||
- `Server->getLevelByName()` -> `WorldManager->getWorldByName()`
|
||||
- `Server->getLevels()` -> `WorldManager->getWorlds()`
|
||||
- `Server->isLevelGenerated()` -> `WorldManager->isWorldGenerated()`
|
||||
- `Server->isLevelLoaded()` -> `WorldManager->isWorldLoaded()`
|
||||
- `Server->loadLevel()` -> `WorldManager->loadWorld()`
|
||||
- `Server->setAutoSave()` -> `WorldManager->setAutoSave()`
|
||||
- `Server->setDefaultLevel()` -> `WorldManager->setDefaultWorld()`
|
||||
- `Server->unloadLevel()` -> `WorldManager->unloadWorld()`
|
||||
- Added `WorldManager->getAutoSaveTicks()` and `WorldManager->setAutoSaveTicks()` to allow controlling the autosave interval.
|
||||
- The following classes have been added:
|
||||
- `BlockTransaction`: allows creating batch commits of block changes with validation conditions - if any block can't be applied, the whole transaction fails to apply.
|
||||
- `ChunkListenerNoOpTrait`: contains default no-op stubs for chunk listener implementations
|
||||
- `ChunkListener`: interface allowing subscribing to events happening on a given chunk
|
||||
- The following API methods have been added:
|
||||
- `World->registerChunkListener()`
|
||||
- `World->unregisterChunkListener()`
|
||||
- The following API methods have been removed:
|
||||
- `ChunkLoader->getLoaderId()` (now object ID is used)
|
||||
|
||||
- The following API methods have changed signatures:
|
||||
- `World->addParticle()` now has the signature `addParticle(Vector3 $pos, Particle $particle, ?Player[] $players = null) : void`
|
||||
- `World->addSound()` now has the signature `addSound(?Vector3 $pos, Sound $sound, ?Player[] $players = null) : void`
|
||||
- `World->getRandomTickedBlocks()` now returns `bool[]` instead of `SplFixedArray`.
|
||||
- `World->addRandomTickedBlock()` now accepts `Block` instead of `int, int`.
|
||||
- `World->removeRandomTickedBlock()` now accepts `Block` instead of `int, int`.
|
||||
- `World->setBlock()` has had the `$direct` parameter removed.
|
||||
- The following API methods have been renamed / moved:
|
||||
- `Level->getCollisionCubes()` -> `World->getCollisionBoxes()`
|
||||
- Extracted a unit `pocketmine\world\format\io\FastChunkSerializer` from `Chunk`:
|
||||
- `Chunk->fastDeserialize()` -> `FastChunkSerializer::deserialize()`
|
||||
- `Chunk->fastSerialize()` -> `FastChunkSerializer::serialize()`
|
||||
- A `ChunkListener` interface has been extracted from `ChunkLoader`. The following methods have been moved:
|
||||
- `ChunkLoader->onBlockChanged()` -> `ChunkListener->onBlockChanged()`
|
||||
- `ChunkLoader->onChunkChanged()` -> `ChunkListener->onChunkChanged()`
|
||||
- `ChunkLoader->onChunkLoaded()` -> `ChunkListener->onChunkLoaded()`
|
||||
- `ChunkLoader->onChunkPopulated()` -> `ChunkListener->onChunkPopulated()`
|
||||
- `ChunkLoader->onChunkUnloaded()` -> `ChunkListener->onChunkUnloaded()`
|
||||
|
||||
#### Particles
|
||||
- `pocketmine\world\particle\Particle` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface.
|
||||
- Added the following `Particle` classes:
|
||||
- `DragonEggTeleportParticle`
|
||||
- `PunchBlockParticle`
|
||||
|
||||
#### Sounds
|
||||
- `pocketmine\world\sound\Sound` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface.
|
||||
- `Sound->encode()` now accepts `?\pocketmine\math\Vector3`. `NULL` may be passed for sounds which are global.
|
||||
- Added the following classes:
|
||||
- `ArrowHitSound`
|
||||
- `BlockBreakSound`
|
||||
- `BlockPlaceSound`
|
||||
- `BowShootSound`
|
||||
- `BucketEmptyLavaSound`
|
||||
- `BucketEmptyWaterSound`
|
||||
- `BucketFillLavaSound`
|
||||
- `BucketFillWaterSound`
|
||||
- `ChestCloseSound`
|
||||
- `ChestOpenSound`
|
||||
- `EnderChestCloseSound`
|
||||
- `EnderChestOpenSound`
|
||||
- `ExplodeSound`
|
||||
- `FlintSteelSound`
|
||||
- `ItemBreakSound`
|
||||
- `NoteInstrument`
|
||||
- `NoteSound`
|
||||
- `PaintingPlaceSound`
|
||||
- `PotionSplashSound`
|
||||
- `RedstonePowerOffSound`
|
||||
- `RedstonePowerOnSound`
|
||||
- `ThrowSound`
|
||||
- `XpCollectSound`
|
||||
- `XpLevelUpSound`
|
||||
|
||||
### Utils
|
||||
- `Terminal::hasFormattingCodes()` no longer auto-detects the availability of formatting codes. Instead it's necessary to use `Terminal::init()` with no parameters to initialize, or `true` or `false` to override.
|
||||
- `Config->save()` no longer catches exceptions thrown during emitting to disk.
|
||||
- The following new classes have been added:
|
||||
- `InternetException`
|
||||
- `Internet`
|
||||
- `Process`
|
||||
- The following API methods have been added:
|
||||
- `Color::fromRGBA()`
|
||||
- `Config->getPath()`: returns the path to the config on disk
|
||||
- `Terminal::write()`: emits a Minecraft-formatted text line without newline
|
||||
- `Terminal::writeLine()`: emits a Minecraft-formatted text line with newline
|
||||
- `Utils::recursiveUnlink()`: recursively deletes a directory and its contents
|
||||
- The following deprecated API redirects have been removed:
|
||||
- `Utils::execute()`: moved to `Process`
|
||||
- `Utils::getIP()`: moved to `Internet`
|
||||
- `Utils::getMemoryUsage()`: moved to `Process`
|
||||
- `Utils::getRealMemoryUsage()`: moved to `Process`
|
||||
- `Utils::getThreadCount()`: moved to `Process`
|
||||
- `Utils::getURL()`: moved to `Internet`
|
||||
- `Utils::kill()`: moved to `Process`
|
||||
- `Utils::postURL()`: moved to `Internet`
|
||||
- `Utils::simpleCurl()`: moved to `Internet`
|
||||
- The following API fields have been removed / hidden:
|
||||
- `Utils::$ip`
|
||||
- `Utils::$online`
|
||||
- `Utils::$os`
|
||||
- The following API methods have signature changes:
|
||||
- `Internet::simpleCurl()` now requires a `Closure` for its `onSuccess` parameter instead of `callable`.
|
||||
- The following API methods have been removed:
|
||||
- `Color->setA()`
|
||||
- `Color->setR()`
|
||||
- `Color->setG()`
|
||||
- `Color->setB()`
|
||||
- `Color->toABGR()`
|
||||
- `Color->toBGRA()`
|
||||
- `Color::fromABGR()`
|
||||
- `Utils::getCallableIdentifier()`
|
@ -5,75 +5,70 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": ">=7.2.0",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php-64bit": "*",
|
||||
"ext-bcmath": "*",
|
||||
"ext-chunkutils2": "^0.1.0",
|
||||
"ext-curl": "*",
|
||||
"ext-crypto": "^0.3.1",
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-date": "*",
|
||||
"ext-ds": "^1.2.7",
|
||||
"ext-gmp": "*",
|
||||
"ext-hash": "*",
|
||||
"ext-json": "*",
|
||||
"ext-leveldb": "^0.2.1",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pthreads": "~3.2.0",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
"ext-spl": "*",
|
||||
"ext-yaml": ">=2.0.0",
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"mdanter/ecc": "^0.5.0",
|
||||
"pocketmine/raklib": "dev-master",
|
||||
"pocketmine/spl": "dev-master",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"pocketmine/binaryutils": "^0.1.9",
|
||||
"pocketmine/nbt": "dev-master",
|
||||
"pocketmine/math": "dev-master",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.1.0",
|
||||
"pocketmine/log": "^0.2.0",
|
||||
"pocketmine/log-pthreads": "^0.1.0",
|
||||
"pocketmine/math": "^0.2.0",
|
||||
"pocketmine/nbt": "^0.2.18",
|
||||
"pocketmine/raklib": "^0.12.7",
|
||||
"pocketmine/snooze": "^0.1.0",
|
||||
"daverandom/callback-validator": "dev-master",
|
||||
"adhocore/json-comment": "^0.0.7",
|
||||
"particle/validator": "^2.3"
|
||||
"pocketmine/spl": "^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "0.12.88",
|
||||
"phpstan/phpstan-phpunit": "^0.12.6",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.2",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"": ["src"]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"src/pocketmine/CoreConstants.php",
|
||||
"src/pocketmine/GlobalConstants.php",
|
||||
"src/pocketmine/VersionInfo.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"pocketmine\\": "tests/phpunit/"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/RakLib"
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.3.0"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/SPL"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/BinaryUtils"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/NBT"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/Math"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/Snooze"
|
||||
}
|
||||
]
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/DevTools/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
2927
composer.lock
generated
2927
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,6 @@ This site contains auto-generated API documentation for PocketMine-MP (and depen
|
||||
This site can be accessed via https://apidoc.pmmp.io.
|
||||
|
||||
### Additional developer resources
|
||||
- [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||
- [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
|
||||
- [DeveloperDocs](https://github.com/pmmp/DeveloperDocs/) - Reference, guides and specifications for the PocketMine-MP API
|
||||
- [DeveloperDocs](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
|
||||
|
49
phpstan.neon.dist
Normal file
49
phpstan.neon.dist
Normal file
@ -0,0 +1,49 @@
|
||||
includes:
|
||||
- tests/phpstan/configs/actual-problems.neon
|
||||
- tests/phpstan/configs/check-explicit-mixed-baseline.neon
|
||||
- tests/phpstan/configs/gc-hacks.neon
|
||||
- tests/phpstan/configs/l7-baseline.neon
|
||||
- tests/phpstan/configs/l8-baseline.neon
|
||||
- tests/phpstan/configs/php-bugs.neon
|
||||
- tests/phpstan/configs/phpstan-bugs.neon
|
||||
- tests/phpstan/configs/phpunit-wiring-tests.neon
|
||||
- tests/phpstan/configs/pthreads-bugs.neon
|
||||
- tests/phpstan/configs/runtime-type-checks.neon
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
parameters:
|
||||
level: 8
|
||||
checkExplicitMixed: true
|
||||
checkMissingCallableSignature: true
|
||||
bootstrapFiles:
|
||||
- tests/phpstan/bootstrap.php
|
||||
scanDirectories:
|
||||
- tests/plugins/TesterPlugin
|
||||
scanFiles:
|
||||
- src/pocketmine/PocketMine.php
|
||||
- build/make-release.php
|
||||
- build/server-phar.php
|
||||
paths:
|
||||
- src
|
||||
- build/make-release.php
|
||||
- build/server-phar.php
|
||||
- tests/phpunit
|
||||
- tests/plugins/TesterPlugin
|
||||
dynamicConstantNames:
|
||||
- pocketmine\IS_DEVELOPMENT_BUILD
|
||||
- pocketmine\DEBUG
|
||||
stubFiles:
|
||||
- tests/phpstan/stubs/pthreads.stub
|
||||
- tests/phpstan/stubs/chunkutils.stub
|
||||
- tests/phpstan/stubs/leveldb.stub
|
||||
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
|
||||
staticReflectionClassNamePatterns:
|
||||
- "#^COM$#"
|
||||
typeAliases:
|
||||
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
|
||||
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,
|
||||
#we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway.
|
||||
anyCallable: 'callable(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
||||
anyClosure: '\Closure(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed'
|
Submodule resources/locale deleted from 8718542e62
@ -1,8 +0,0 @@
|
||||
#This configuration file allows you to control which plugins are loaded on your server.
|
||||
|
||||
#List behaviour
|
||||
# - blacklist: Only plugins which ARE NOT listed will load.
|
||||
# - whitelist: Only plugins which ARE listed will load.
|
||||
mode: blacklist
|
||||
#List names of plugins here.
|
||||
plugins: []
|
Submodule resources/vanilla deleted from b5a8c68c42
137
src/pocketmine/Achievement.php
Normal file
137
src/pocketmine/Achievement.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?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\lang\TranslationContainer;
|
||||
use pocketmine\utils\TextFormat;
|
||||
|
||||
/**
|
||||
* Handles the achievement list and a bit more
|
||||
*/
|
||||
abstract class Achievement{
|
||||
/** @var array[] */
|
||||
public static $list = [
|
||||
/*"openInventory" => array(
|
||||
"name" => "Taking Inventory",
|
||||
"requires" => [],
|
||||
),*/
|
||||
"mineWood" => [
|
||||
"name" => "Getting Wood",
|
||||
"requires" => [ //"openInventory",
|
||||
]
|
||||
],
|
||||
"buildWorkBench" => [
|
||||
"name" => "Benchmarking",
|
||||
"requires" => [
|
||||
"mineWood"
|
||||
]
|
||||
],
|
||||
"buildPickaxe" => [
|
||||
"name" => "Time to Mine!",
|
||||
"requires" => [
|
||||
"buildWorkBench"
|
||||
]
|
||||
],
|
||||
"buildFurnace" => [
|
||||
"name" => "Hot Topic",
|
||||
"requires" => [
|
||||
"buildPickaxe"
|
||||
]
|
||||
],
|
||||
"acquireIron" => [
|
||||
"name" => "Acquire hardware",
|
||||
"requires" => [
|
||||
"buildFurnace"
|
||||
]
|
||||
],
|
||||
"buildHoe" => [
|
||||
"name" => "Time to Farm!",
|
||||
"requires" => [
|
||||
"buildWorkBench"
|
||||
]
|
||||
],
|
||||
"makeBread" => [
|
||||
"name" => "Bake Bread",
|
||||
"requires" => [
|
||||
"buildHoe"
|
||||
]
|
||||
],
|
||||
"bakeCake" => [
|
||||
"name" => "The Lie",
|
||||
"requires" => [
|
||||
"buildHoe"
|
||||
]
|
||||
],
|
||||
"buildBetterPickaxe" => [
|
||||
"name" => "Getting an Upgrade",
|
||||
"requires" => [
|
||||
"buildPickaxe"
|
||||
]
|
||||
],
|
||||
"buildSword" => [
|
||||
"name" => "Time to Strike!",
|
||||
"requires" => [
|
||||
"buildWorkBench"
|
||||
]
|
||||
],
|
||||
"diamonds" => [
|
||||
"name" => "DIAMONDS!",
|
||||
"requires" => [
|
||||
"acquireIron"
|
||||
]
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
public static function broadcast(Player $player, string $achievementId) : bool{
|
||||
if(isset(Achievement::$list[$achievementId])){
|
||||
$translation = new TranslationContainer("chat.type.achievement", [$player->getDisplayName(), TextFormat::GREEN . Achievement::$list[$achievementId]["name"] . TextFormat::RESET]);
|
||||
if(Server::getInstance()->getConfigBool("announce-player-achievements", true)){
|
||||
Server::getInstance()->broadcastMessage($translation);
|
||||
}else{
|
||||
$player->sendMessage($translation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $requires
|
||||
*/
|
||||
public static function add(string $achievementId, string $achievementName, array $requires = []) : bool{
|
||||
if(!isset(Achievement::$list[$achievementId])){
|
||||
Achievement::$list[$achievementId] = [
|
||||
"name" => $achievementName,
|
||||
"requires" => $requires
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -21,18 +21,21 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world\particle;
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
abstract class Collectable extends \Threaded{
|
||||
|
||||
interface Particle{
|
||||
/** @var bool */
|
||||
private $isGarbage = false;
|
||||
|
||||
public function isGarbage() : bool{
|
||||
return $this->isGarbage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Vector3 $pos
|
||||
*
|
||||
* @return ClientboundPacket|ClientboundPacket[]
|
||||
* @return void
|
||||
*/
|
||||
public function encode(Vector3 $pos);
|
||||
|
||||
public function setGarbage(){
|
||||
$this->isGarbage = true;
|
||||
}
|
||||
}
|
37
src/pocketmine/CoreConstants.php
Normal file
37
src/pocketmine/CoreConstants.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?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 function define;
|
||||
use function defined;
|
||||
use function dirname;
|
||||
|
||||
// composer autoload doesn't use require_once and also pthreads can inherit things
|
||||
if(defined('pocketmine\_CORE_CONSTANTS_INCLUDED')){
|
||||
return;
|
||||
}
|
||||
define('pocketmine\_CORE_CONSTANTS_INCLUDED', true);
|
||||
|
||||
define('pocketmine\PATH', dirname(__DIR__, 2) . '/');
|
||||
define('pocketmine\RESOURCE_PATH', __DIR__ . '/resources/');
|
@ -23,12 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\plugin\PluginBase;
|
||||
use pocketmine\plugin\PluginLoadOrder;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use raklib\RakLib;
|
||||
use function base64_encode;
|
||||
use function date;
|
||||
use function error_get_last;
|
||||
@ -45,6 +47,7 @@ use function is_resource;
|
||||
use function json_encode;
|
||||
use function json_last_error_msg;
|
||||
use function max;
|
||||
use function microtime;
|
||||
use function mkdir;
|
||||
use function ob_end_clean;
|
||||
use function ob_get_contents;
|
||||
@ -53,13 +56,27 @@ use function php_uname;
|
||||
use function phpinfo;
|
||||
use function phpversion;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function str_split;
|
||||
use function strpos;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use function time;
|
||||
use function zend_version;
|
||||
use function zlib_encode;
|
||||
use const E_COMPILE_ERROR;
|
||||
use const E_COMPILE_WARNING;
|
||||
use const E_CORE_ERROR;
|
||||
use const E_CORE_WARNING;
|
||||
use const E_DEPRECATED;
|
||||
use const E_ERROR;
|
||||
use const E_NOTICE;
|
||||
use const E_PARSE;
|
||||
use const E_RECOVERABLE_ERROR;
|
||||
use const E_STRICT;
|
||||
use const E_USER_DEPRECATED;
|
||||
use const E_USER_ERROR;
|
||||
use const E_USER_NOTICE;
|
||||
use const E_USER_WARNING;
|
||||
use const E_WARNING;
|
||||
use const FILE_IGNORE_NEW_LINES;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const PHP_EOL;
|
||||
@ -73,7 +90,7 @@ class CrashDump{
|
||||
* having their content changed, version format changing, etc.
|
||||
* It is not necessary to increase this when adding new fields.
|
||||
*/
|
||||
private const FORMAT_VERSION = 2;
|
||||
private const FORMAT_VERSION = 4;
|
||||
|
||||
private const PLUGIN_INVOLVEMENT_NONE = "none";
|
||||
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
|
||||
@ -81,8 +98,14 @@ class CrashDump{
|
||||
|
||||
/** @var Server */
|
||||
private $server;
|
||||
/** @var resource */
|
||||
private $fp;
|
||||
/** @var float */
|
||||
private $time;
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @phpstan-var array<string, mixed>
|
||||
*/
|
||||
private $data = [];
|
||||
/** @var string */
|
||||
private $encodedData = "";
|
||||
@ -90,19 +113,21 @@ class CrashDump{
|
||||
private $path;
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->time = time();
|
||||
$this->time = microtime(true);
|
||||
$this->server = $server;
|
||||
if(!is_dir($this->server->getDataPath() . "crashdumps")){
|
||||
mkdir($this->server->getDataPath() . "crashdumps");
|
||||
}
|
||||
$this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", $this->time) . ".log";
|
||||
$this->fp = @fopen($this->path, "wb");
|
||||
if(!is_resource($this->fp)){
|
||||
$this->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log";
|
||||
$fp = @fopen($this->path, "wb");
|
||||
if(!is_resource($fp)){
|
||||
throw new \RuntimeException("Could not create Crash Dump");
|
||||
}
|
||||
$this->fp = $fp;
|
||||
$this->data["format_version"] = self::FORMAT_VERSION;
|
||||
$this->data["time"] = $this->time;
|
||||
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time));
|
||||
$this->data["uptime"] = $this->time - \pocketmine\START_TIME;
|
||||
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->time));
|
||||
$this->addLine();
|
||||
$this->baseCrash();
|
||||
$this->generalData();
|
||||
@ -119,10 +144,17 @@ class CrashDump{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function getEncodedData() : string{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEncodedData(){
|
||||
return $this->encodedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
public function getData() : array{
|
||||
return $this->data;
|
||||
}
|
||||
@ -136,7 +168,9 @@ class CrashDump{
|
||||
if($json === false){
|
||||
throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg());
|
||||
}
|
||||
$this->encodedData = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9);
|
||||
$zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9);
|
||||
if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed");
|
||||
$this->encodedData = $zlibEncoded;
|
||||
foreach(str_split(base64_encode($this->encodedData), 76) as $line){
|
||||
$this->addLine($line);
|
||||
}
|
||||
@ -159,7 +193,7 @@ class CrashDump{
|
||||
"depends" => $d->getDepend(),
|
||||
"softDepends" => $d->getSoftDepend(),
|
||||
"main" => $d->getMain(),
|
||||
"load" => strtoupper($d->getOrder()->name()),
|
||||
"load" => $d->getOrder() === PluginLoadOrder::POSTWORLD ? "POSTWORLD" : "STARTUP",
|
||||
"website" => $d->getWebsite()
|
||||
];
|
||||
$this->addLine($d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . " for API(s) " . implode(", ", $d->getCompatibleApis()));
|
||||
@ -172,9 +206,16 @@ class CrashDump{
|
||||
|
||||
if($this->server->getProperty("auto-report.send-settings", true) !== false){
|
||||
$this->data["parameters"] = (array) $argv;
|
||||
$this->data["server.properties"] = @file_get_contents($this->server->getDataPath() . "server.properties");
|
||||
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $this->data["server.properties"]);
|
||||
$this->data["pocketmine.yml"] = @file_get_contents($this->server->getDataPath() . "pocketmine.yml");
|
||||
if(($serverDotProperties = @file_get_contents($this->server->getDataPath() . "server.properties")) !== false){
|
||||
$this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties);
|
||||
}else{
|
||||
$this->data["server.properties"] = $serverDotProperties;
|
||||
}
|
||||
if(($pocketmineDotYml = @file_get_contents($this->server->getDataPath() . "pocketmine.yml")) !== false){
|
||||
$this->data["pocketmine.yml"] = $pocketmineDotYml;
|
||||
}else{
|
||||
$this->data["pocketmine.yml"] = "";
|
||||
}
|
||||
}else{
|
||||
$this->data["pocketmine.yml"] = "";
|
||||
$this->data["server.properties"] = "";
|
||||
@ -200,15 +241,31 @@ class CrashDump{
|
||||
if(isset($lastExceptionError)){
|
||||
$error = $lastExceptionError;
|
||||
}else{
|
||||
$error = (array) error_get_last();
|
||||
$error = error_get_last();
|
||||
if($error === null){
|
||||
throw new \RuntimeException("Crash error information missing - did something use exit()?");
|
||||
}
|
||||
$error["trace"] = Utils::currentTrace(3); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
|
||||
$errorConversion = [
|
||||
E_ERROR => "E_ERROR",
|
||||
E_WARNING => "E_WARNING",
|
||||
E_PARSE => "E_PARSE",
|
||||
E_NOTICE => "E_NOTICE",
|
||||
E_CORE_ERROR => "E_CORE_ERROR",
|
||||
E_CORE_WARNING => "E_CORE_WARNING",
|
||||
E_COMPILE_ERROR => "E_COMPILE_ERROR",
|
||||
E_COMPILE_WARNING => "E_COMPILE_WARNING",
|
||||
E_USER_ERROR => "E_USER_ERROR",
|
||||
E_USER_WARNING => "E_USER_WARNING",
|
||||
E_USER_NOTICE => "E_USER_NOTICE",
|
||||
E_STRICT => "E_STRICT",
|
||||
E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
|
||||
E_DEPRECATED => "E_DEPRECATED",
|
||||
E_USER_DEPRECATED => "E_USER_DEPRECATED"
|
||||
];
|
||||
$error["fullFile"] = $error["file"];
|
||||
$error["file"] = Utils::cleanPath($error["file"]);
|
||||
try{
|
||||
$error["type"] = \ErrorUtils::errorTypeToString($error["type"]);
|
||||
}catch(\InvalidArgumentException $e){
|
||||
//pass
|
||||
}
|
||||
$error["type"] = $errorConversion[$error["type"]] ?? $error["type"];
|
||||
if(($pos = strpos($error["message"], "\n")) !== false){
|
||||
$error["message"] = substr($error["message"], 0, $pos);
|
||||
}
|
||||
@ -247,9 +304,11 @@ class CrashDump{
|
||||
|
||||
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
|
||||
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||
$this->data["code"][$l + 1] = $file[$l];
|
||||
if($file !== false){
|
||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||
$this->data["code"][$l + 1] = $file[$l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,8 +321,8 @@ class CrashDump{
|
||||
}
|
||||
|
||||
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
|
||||
$frameCleanPath = Utils::cleanPath($filePath); //this will be empty in phar stub
|
||||
if(strpos($frameCleanPath, "plugins") === 0 and file_exists($filePath)){
|
||||
$frameCleanPath = Utils::cleanPath($filePath);
|
||||
if(strpos($frameCleanPath, Utils::CLEAN_PATH_SRC_PREFIX) !== 0){
|
||||
$this->addLine();
|
||||
if($crashFrame){
|
||||
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
||||
@ -273,15 +332,17 @@ class CrashDump{
|
||||
$this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_INDIRECT;
|
||||
}
|
||||
|
||||
$reflection = new \ReflectionClass(PluginBase::class);
|
||||
$file = $reflection->getProperty("file");
|
||||
$file->setAccessible(true);
|
||||
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
|
||||
$filePath = Utils::cleanPath($file->getValue($plugin));
|
||||
if(strpos($frameCleanPath, $filePath) === 0){
|
||||
$this->data["plugin"] = $plugin->getName();
|
||||
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
|
||||
break;
|
||||
if(file_exists($filePath)){
|
||||
$reflection = new \ReflectionClass(PluginBase::class);
|
||||
$file = $reflection->getProperty("file");
|
||||
$file->setAccessible(true);
|
||||
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
|
||||
$filePath = Utils::cleanPath($file->getValue($plugin));
|
||||
if(strpos($frameCleanPath, $filePath) === 0){
|
||||
$this->data["plugin"] = $plugin->getName();
|
||||
$this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -291,6 +352,15 @@ class CrashDump{
|
||||
|
||||
private function generalData() : void{
|
||||
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
||||
$composerLibraries = [];
|
||||
foreach(InstalledVersions::getInstalledPackages() as $package){
|
||||
$composerLibraries[$package] = sprintf(
|
||||
"%s@%s",
|
||||
InstalledVersions::getPrettyVersion($package) ?? "unknown",
|
||||
InstalledVersions::getReference($package) ?? "unknown"
|
||||
);
|
||||
}
|
||||
|
||||
$this->data["general"] = [];
|
||||
$this->data["general"]["name"] = $this->server->getName();
|
||||
$this->data["general"]["base_version"] = \pocketmine\BASE_VERSION;
|
||||
@ -298,25 +368,39 @@ class CrashDump{
|
||||
$this->data["general"]["is_dev"] = \pocketmine\IS_DEVELOPMENT_BUILD;
|
||||
$this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL;
|
||||
$this->data["general"]["git"] = \pocketmine\GIT_COMMIT;
|
||||
$this->data["general"]["raklib"] = RakLib::VERSION;
|
||||
$this->data["general"]["uname"] = php_uname("a");
|
||||
$this->data["general"]["php"] = phpversion();
|
||||
$this->data["general"]["zend"] = zend_version();
|
||||
$this->data["general"]["php_os"] = PHP_OS;
|
||||
$this->data["general"]["os"] = Utils::getOS();
|
||||
$this->data["general"]["composer_libraries"] = $composerLibraries;
|
||||
$this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]");
|
||||
$this->addLine("Git commit: " . GIT_COMMIT);
|
||||
$this->addLine("Git commit: " . \pocketmine\GIT_COMMIT);
|
||||
$this->addLine("uname -a: " . php_uname("a"));
|
||||
$this->addLine("PHP Version: " . phpversion());
|
||||
$this->addLine("Zend version: " . zend_version());
|
||||
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
|
||||
$this->addLine("Composer libraries: ");
|
||||
foreach($composerLibraries as $library => $libraryVersion){
|
||||
$this->addLine("- $library $libraryVersion");
|
||||
}
|
||||
}
|
||||
|
||||
public function addLine($line = "") : void{
|
||||
/**
|
||||
* @param string $line
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addLine($line = ""){
|
||||
fwrite($this->fp, $line . PHP_EOL);
|
||||
}
|
||||
|
||||
public function add($str) : void{
|
||||
/**
|
||||
* @param string $str
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($str){
|
||||
fwrite($this->fp, $str);
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,12 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class HardenedGlass extends Transparent{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(10.0));
|
||||
}
|
||||
// composer autoload doesn't use require_once and also pthreads can inherit things
|
||||
if(defined('pocketmine\_GLOBAL_CONSTANTS_INCLUDED')){
|
||||
return;
|
||||
}
|
||||
define('pocketmine\_GLOBAL_CONSTANTS_INCLUDED', true);
|
||||
|
||||
const INT32_MIN = -0x80000000;
|
||||
const INT32_MAX = 0x7fffffff;
|
||||
const INT32_MASK = 0xffffffff;
|
@ -21,60 +21,45 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\player;
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\permission\ServerOperator;
|
||||
|
||||
interface IPlayer extends ServerOperator{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOnline() : bool;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isBanned() : bool;
|
||||
|
||||
/**
|
||||
* @param bool $banned
|
||||
* @return void
|
||||
*/
|
||||
public function setBanned(bool $banned) : void;
|
||||
public function setBanned(bool $banned);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isWhitelisted() : bool;
|
||||
|
||||
/**
|
||||
* @param bool $value
|
||||
* @return void
|
||||
*/
|
||||
public function setWhitelisted(bool $value) : void;
|
||||
public function setWhitelisted(bool $value);
|
||||
|
||||
/**
|
||||
* @return Player|null
|
||||
*/
|
||||
public function getPlayer() : ?Player;
|
||||
public function getPlayer();
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getFirstPlayed() : ?int;
|
||||
public function getFirstPlayed();
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getLastPlayed() : ?int;
|
||||
public function getLastPlayed();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPlayedBefore() : bool;
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ use pocketmine\event\server\LowMemoryEvent;
|
||||
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 function arsort;
|
||||
@ -39,6 +40,7 @@ use function fwrite;
|
||||
use function gc_collect_cycles;
|
||||
use function gc_disable;
|
||||
use function gc_enable;
|
||||
use function gc_mem_caches;
|
||||
use function get_class;
|
||||
use function get_declared_classes;
|
||||
use function implode;
|
||||
@ -49,6 +51,7 @@ use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function mb_strtoupper;
|
||||
use function min;
|
||||
use function mkdir;
|
||||
use function preg_match;
|
||||
@ -57,7 +60,6 @@ use function round;
|
||||
use function spl_object_hash;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
@ -110,12 +112,8 @@ class MemoryManager{
|
||||
/** @var bool */
|
||||
private $dumpWorkers = true;
|
||||
|
||||
/** @var \Logger */
|
||||
private $logger;
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->server = $server;
|
||||
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
|
||||
|
||||
$this->init();
|
||||
}
|
||||
@ -130,7 +128,7 @@ class MemoryManager{
|
||||
if($m <= 0){
|
||||
$defaultMemory = 0;
|
||||
}else{
|
||||
switch(strtoupper($matches[2])){
|
||||
switch(mb_strtoupper($matches[2])){
|
||||
case "K":
|
||||
$defaultMemory = $m / 1024;
|
||||
break;
|
||||
@ -174,58 +172,38 @@ class MemoryManager{
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLowMemory() : bool{
|
||||
return $this->lowMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getGlobalMemoryLimit() : int{
|
||||
return $this->globalMemoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function canUseChunkCache() : bool{
|
||||
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the allowed chunk radius based on the current memory usage.
|
||||
*
|
||||
* @param int $distance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getViewDistance(int $distance) : int{
|
||||
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? (int) min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers garbage collection and cache cleanup to try and free memory.
|
||||
*
|
||||
* @param int $memory
|
||||
* @param int $limit
|
||||
* @param bool $global
|
||||
* @param int $triggerCount
|
||||
* @return void
|
||||
*/
|
||||
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0) : void{
|
||||
$this->logger->debug(sprintf("%sLow memory triggered, limit %gMB, using %gMB",
|
||||
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
|
||||
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||
if($this->lowMemClearWorldCache){
|
||||
foreach($this->server->getWorldManager()->getWorlds() as $world){
|
||||
$world->clearCache(true);
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->clearCache(true);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->lowMemChunkGC){
|
||||
foreach($this->server->getWorldManager()->getWorlds() as $world){
|
||||
$world->doChunkGarbageCollection();
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->doChunkGarbageCollection();
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,18 +215,20 @@ class MemoryManager{
|
||||
$cycles = $this->triggerGarbageCollector();
|
||||
}
|
||||
|
||||
$this->logger->debug(sprintf("Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
|
||||
$this->server->getLogger()->debug(sprintf("[Memory Manager] Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every tick to update the memory manager state.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check() : void{
|
||||
public function check(){
|
||||
Timings::$memoryManagerTimer->startTiming();
|
||||
|
||||
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
|
||||
$this->checkTicker = 0;
|
||||
$memory = Process::getMemoryUsage(true);
|
||||
$memory = Process::getAdvancedMemoryUsage();
|
||||
$trigger = false;
|
||||
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
|
||||
$trigger = 0;
|
||||
@ -280,16 +260,13 @@ class MemoryManager{
|
||||
Timings::$memoryManagerTimer->stopTiming();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function triggerGarbageCollector() : int{
|
||||
Timings::$garbageCollectorTimer->startTiming();
|
||||
|
||||
if($this->garbageCollectionAsync){
|
||||
$pool = $this->server->getAsyncPool();
|
||||
if(($w = $pool->shutdownUnusedWorkers()) > 0){
|
||||
$this->logger->debug("Shut down $w idle async pool workers");
|
||||
$this->server->getLogger()->debug("Shut down $w idle async pool workers");
|
||||
}
|
||||
foreach($pool->getRunningWorkers() as $i){
|
||||
$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
|
||||
@ -297,6 +274,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$cycles = gc_collect_cycles();
|
||||
gc_mem_caches();
|
||||
|
||||
Timings::$garbageCollectorTimer->stopTiming();
|
||||
|
||||
@ -306,14 +284,11 @@ class MemoryManager{
|
||||
/**
|
||||
* Dumps the server memory into the specified output folder.
|
||||
*
|
||||
* @param string $outputFolder
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
* @return void
|
||||
*/
|
||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize) : void{
|
||||
$logger = new \PrefixedLogger($this->server->getLogger(), "Memory Dump");
|
||||
$logger->notice("After the memory dump is done, the server might crash");
|
||||
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
|
||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $this->server->getLogger());
|
||||
|
||||
if($this->dumpWorkers){
|
||||
$pool = $this->server->getAsyncPool();
|
||||
@ -327,15 +302,13 @@ class MemoryManager{
|
||||
* Static memory dumper accessible from any thread.
|
||||
*
|
||||
* @param mixed $startingObject
|
||||
* @param string $outputFolder
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
* @param \Logger $logger
|
||||
*
|
||||
* @return void
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
|
||||
$hardLimit = ini_get('memory_limit');
|
||||
if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
|
||||
@ -369,7 +342,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$staticCount++;
|
||||
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
if(count($staticProperties[$className]) === 0){
|
||||
@ -378,7 +351,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
$logger->info("Wrote $staticCount static properties");
|
||||
$logger->info("[Dump] Wrote $staticCount static properties");
|
||||
|
||||
if(isset($GLOBALS)){ //This might be null if we're on a different thread
|
||||
$globalVariables = [];
|
||||
@ -402,14 +375,14 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$globalCount++;
|
||||
self::continueDump($value, $globalVariables[$varName], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
$logger->info("Wrote $globalCount global variables");
|
||||
$logger->info("[Dump] Wrote $globalCount global variables");
|
||||
}
|
||||
|
||||
self::continueDump($startingObject, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
|
||||
do{
|
||||
$continue = false;
|
||||
@ -435,8 +408,8 @@ class MemoryManager{
|
||||
"properties" => []
|
||||
];
|
||||
|
||||
if($reflection->getParentClass()){
|
||||
$info["parent"] = $reflection->getParentClass()->getName();
|
||||
if(($parent = $reflection->getParentClass()) !== false){
|
||||
$info["parent"] = $parent->getName();
|
||||
}
|
||||
|
||||
if(count($reflection->getInterfaceNames()) > 0){
|
||||
@ -450,24 +423,27 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$name = $property->getName();
|
||||
if($reflection !== $original and !$property->isPublic()){
|
||||
$name = $reflection->getName() . ":" . $name;
|
||||
if($reflection !== $original){
|
||||
if($property->isPrivate()){
|
||||
$name = $reflection->getName() . ":" . $name;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!$property->isPublic()){
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
self::continueDump($property->getValue($object), $info["properties"][$name], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
||||
}
|
||||
|
||||
|
||||
}while($continue);
|
||||
|
||||
$logger->info("Wrote " . count($objects) . " objects");
|
||||
$logger->info("[Dump] Wrote " . count($objects) . " objects");
|
||||
|
||||
fclose($obData);
|
||||
|
||||
@ -477,7 +453,7 @@ class MemoryManager{
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
$logger->info("Finished!");
|
||||
$logger->info("[Dump] Finished!");
|
||||
|
||||
ini_set('memory_limit', $hardLimit);
|
||||
gc_enable();
|
||||
@ -485,17 +461,14 @@ class MemoryManager{
|
||||
|
||||
/**
|
||||
* @param mixed $from
|
||||
* @param mixed &$data
|
||||
* @param object[] &$objects
|
||||
* @param int[] &$refCounts
|
||||
* @param int $recursion
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
* @param object[] $objects reference parameter
|
||||
* @param int[] $refCounts reference parameter
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : void{
|
||||
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||
if($maxNesting <= 0){
|
||||
$data = "(error) NESTING LIMIT REACHED";
|
||||
return;
|
||||
return "(error) NESTING LIMIT REACHED";
|
||||
}
|
||||
|
||||
--$maxNesting;
|
||||
@ -511,12 +484,11 @@ class MemoryManager{
|
||||
$data = "(object) $hash@" . get_class($from);
|
||||
}elseif(is_array($from)){
|
||||
if($recursion >= 5){
|
||||
$data = "(error) ARRAY RECURSION LIMIT REACHED";
|
||||
return;
|
||||
return "(error) ARRAY RECURSION LIMIT REACHED";
|
||||
}
|
||||
$data = [];
|
||||
foreach($from as $key => $value){
|
||||
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||
$data[$key] = self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}elseif(is_string($from)){
|
||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
@ -525,5 +497,7 @@ class MemoryManager{
|
||||
}else{
|
||||
$data = $from;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -21,13 +21,14 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\player;
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\plugin\Plugin;
|
||||
|
||||
class OfflinePlayer implements IPlayer{
|
||||
class OfflinePlayer implements IPlayer, Metadatable{
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
@ -36,14 +37,12 @@ class OfflinePlayer implements IPlayer{
|
||||
/** @var CompoundTag|null */
|
||||
private $namedtag = null;
|
||||
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(Server $server, string $name){
|
||||
$this->server = $server;
|
||||
$this->name = $name;
|
||||
$this->namedtag = $this->server->getOfflinePlayerData($this->name);
|
||||
if($this->server->hasOfflinePlayerData($this->name)){
|
||||
$this->namedtag = $this->server->getOfflinePlayerData($this->name);
|
||||
}
|
||||
}
|
||||
|
||||
public function isOnline() : bool{
|
||||
@ -54,6 +53,9 @@ class OfflinePlayer implements IPlayer{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
*/
|
||||
public function getServer(){
|
||||
return $this->server;
|
||||
}
|
||||
@ -62,7 +64,7 @@ class OfflinePlayer implements IPlayer{
|
||||
return $this->server->isOp($this->name);
|
||||
}
|
||||
|
||||
public function setOp(bool $value) : void{
|
||||
public function setOp(bool $value){
|
||||
if($value === $this->isOp()){
|
||||
return;
|
||||
}
|
||||
@ -78,8 +80,8 @@ class OfflinePlayer implements IPlayer{
|
||||
return $this->server->getNameBans()->isBanned($this->name);
|
||||
}
|
||||
|
||||
public function setBanned(bool $banned) : void{
|
||||
if($banned){
|
||||
public function setBanned(bool $value){
|
||||
if($value){
|
||||
$this->server->getNameBans()->addBan($this->name, null, null, null);
|
||||
}else{
|
||||
$this->server->getNameBans()->remove($this->name);
|
||||
@ -90,7 +92,7 @@ class OfflinePlayer implements IPlayer{
|
||||
return $this->server->isWhitelisted($this->name);
|
||||
}
|
||||
|
||||
public function setWhitelisted(bool $value) : void{
|
||||
public function setWhitelisted(bool $value){
|
||||
if($value){
|
||||
$this->server->addWhitelist($this->name);
|
||||
}else{
|
||||
@ -98,19 +100,35 @@ class OfflinePlayer implements IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
public function getPlayer() : ?Player{
|
||||
public function getPlayer(){
|
||||
return $this->server->getPlayerExact($this->name);
|
||||
}
|
||||
|
||||
public function getFirstPlayed() : ?int{
|
||||
return ($this->namedtag !== null and $this->namedtag->hasTag("firstPlayed", LongTag::class)) ? $this->namedtag->getInt("firstPlayed") : null;
|
||||
public function getFirstPlayed(){
|
||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
|
||||
}
|
||||
|
||||
public function getLastPlayed() : ?int{
|
||||
return ($this->namedtag !== null and $this->namedtag->hasTag("lastPlayed", LongTag::class)) ? $this->namedtag->getLong("lastPlayed") : null;
|
||||
public function getLastPlayed(){
|
||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
|
||||
}
|
||||
|
||||
public function hasPlayedBefore() : bool{
|
||||
return $this->namedtag !== null;
|
||||
return $this->namedtag instanceof CompoundTag;
|
||||
}
|
||||
|
||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||
$this->server->getPlayerMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
|
||||
}
|
||||
|
||||
public function getMetadata(string $metadataKey){
|
||||
return $this->server->getPlayerMetadata()->getMetadata($this, $metadataKey);
|
||||
}
|
||||
|
||||
public function hasMetadata(string $metadataKey) : bool{
|
||||
return $this->server->getPlayerMetadata()->hasMetadata($this, $metadataKey);
|
||||
}
|
||||
|
||||
public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
|
||||
$this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
|
||||
}
|
||||
}
|
4214
src/pocketmine/Player.php
Normal file
4214
src/pocketmine/Player.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,26 +21,27 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {
|
||||
const INT32_MIN = -0x80000000;
|
||||
const INT32_MAX = 0x7fffffff;
|
||||
}
|
||||
|
||||
namespace pocketmine {
|
||||
|
||||
use pocketmine\thread\ThreadManager;
|
||||
use Composer\InstalledVersions;
|
||||
use pocketmine\utils\Git;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\ServerKiller;
|
||||
use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\Timezone;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "7.2.0";
|
||||
const MIN_PHP_VERSION = "7.3.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
function critical_error($message){
|
||||
echo "[ERROR] $message" . PHP_EOL;
|
||||
}
|
||||
@ -58,32 +59,26 @@ namespace pocketmine {
|
||||
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
||||
//If PHP version isn't high enough, anything below might break, so don't bother checking it.
|
||||
return [
|
||||
\pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "."
|
||||
"PHP >= " . MIN_PHP_VERSION . " is required, but you have PHP " . PHP_VERSION . "."
|
||||
];
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
|
||||
if(PHP_INT_SIZE < 8){
|
||||
$messages[] = "Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.";
|
||||
$messages[] = "32-bit systems/PHP are no longer supported. Please upgrade to a 64-bit system, or use a 64-bit PHP binary if this is a 64-bit system.";
|
||||
}
|
||||
|
||||
if(php_sapi_name() !== "cli"){
|
||||
$messages[] = "You must run " . \pocketmine\NAME . " using the CLI.";
|
||||
$messages[] = "Only PHP CLI is supported.";
|
||||
}
|
||||
|
||||
$extensions = [
|
||||
"bcmath" => "BC Math",
|
||||
"chunkutils2" => "PocketMine ChunkUtils v2",
|
||||
"curl" => "cURL",
|
||||
"crypto" => "php-crypto",
|
||||
"ctype" => "ctype",
|
||||
"date" => "Date",
|
||||
"ds" => "Data Structures",
|
||||
"gmp" => "GMP",
|
||||
"hash" => "Hash",
|
||||
"json" => "JSON",
|
||||
"leveldb" => "LevelDB",
|
||||
"mbstring" => "Multibyte String",
|
||||
"openssl" => "OpenSSL",
|
||||
"pcre" => "PCRE",
|
||||
@ -127,8 +122,41 @@ namespace pocketmine {
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Logger $logger
|
||||
* @return void
|
||||
*/
|
||||
function emit_performance_warnings(\Logger $logger){
|
||||
if(extension_loaded("xdebug")){
|
||||
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
|
||||
}
|
||||
if(!extension_loaded("pocketmine_chunkutils")){
|
||||
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
|
||||
}
|
||||
if(((int) ini_get('zend.assertions')) !== -1){
|
||||
$logger->warning("Debugging assertions are enabled. This may degrade performance. To disable them, set `zend.assertions = -1` in php.ini.");
|
||||
}
|
||||
if(\Phar::running(true) === ""){
|
||||
$logger->warning("Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function set_ini_entries(){
|
||||
ini_set("allow_url_fopen", '1');
|
||||
ini_set("display_errors", '1');
|
||||
ini_set("display_startup_errors", '1');
|
||||
ini_set("default_charset", "utf-8");
|
||||
ini_set('assert.exception', '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function server(){
|
||||
if(!empty($messages = check_platform_dependencies())){
|
||||
if(count($messages = check_platform_dependencies()) > 0){
|
||||
echo PHP_EOL;
|
||||
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
|
||||
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
|
||||
@ -142,50 +170,54 @@ namespace pocketmine {
|
||||
unset($messages);
|
||||
|
||||
error_reporting(-1);
|
||||
|
||||
if(\Phar::running(true) !== ""){
|
||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
||||
}else{
|
||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
set_ini_entries();
|
||||
|
||||
$opts = getopt("", ["bootstrap:"]);
|
||||
if(isset($opts["bootstrap"])){
|
||||
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
|
||||
$bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"];
|
||||
}else{
|
||||
$bootstrap = \pocketmine\PATH . 'vendor/autoload.php';
|
||||
$bootstrap = dirname(__FILE__, 3) . '/vendor/autoload.php';
|
||||
}
|
||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
|
||||
|
||||
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
||||
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
if(extension_loaded('parallel')){
|
||||
\parallel\bootstrap(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
}
|
||||
}else{
|
||||
if($bootstrap === false or !is_file($bootstrap)){
|
||||
critical_error("Composer autoloader not found at " . $bootstrap);
|
||||
critical_error("Please install/update Composer dependencies or use provided builds.");
|
||||
exit(1);
|
||||
}
|
||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
|
||||
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
|
||||
\ErrorUtils::setErrorExceptionHandler();
|
||||
set_error_handler([Utils::class, 'errorExceptionHandler']);
|
||||
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
||||
*/
|
||||
$autoloader = new \BaseClassLoader();
|
||||
$autoloader->register(false);
|
||||
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
||||
define('pocketmine\VERSION', $version->getFullVersion(true));
|
||||
|
||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
||||
$gitHash = str_repeat("00", 20);
|
||||
|
||||
ini_set("allow_url_fopen", '1');
|
||||
ini_set("display_errors", '1');
|
||||
ini_set("display_startup_errors", '1');
|
||||
ini_set("default_charset", "utf-8");
|
||||
if(\Phar::running(true) === ""){
|
||||
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
|
||||
}else{
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$meta = $phar->getMetadata();
|
||||
if(isset($meta["git"])){
|
||||
$gitHash = $meta["git"];
|
||||
}
|
||||
}
|
||||
|
||||
ini_set("memory_limit", '-1');
|
||||
define('pocketmine\GIT_COMMIT', $gitHash);
|
||||
|
||||
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'resources' . DIRECTORY_SEPARATOR);
|
||||
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
|
||||
if($composerGitHash !== null){
|
||||
$currentGitHash = explode("-", \pocketmine\GIT_COMMIT)[0];
|
||||
if($currentGitHash !== $composerGitHash){
|
||||
critical_error("Composer dependencies and/or autoloader are out of sync.");
|
||||
critical_error("- Current revision is $currentGitHash");
|
||||
critical_error("- Composer dependencies were last synchronized for revision $composerGitHash");
|
||||
critical_error("Out-of-sync Composer dependencies may result in crashes and classes not being found.");
|
||||
critical_error("Please synchronize Composer dependencies before running the server.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
|
||||
|
||||
@ -196,8 +228,12 @@ namespace pocketmine {
|
||||
mkdir(\pocketmine\DATA, 0777, true);
|
||||
}
|
||||
|
||||
define('pocketmine\LOCK_FILE_PATH', \pocketmine\DATA . 'server.lock');
|
||||
define('pocketmine\LOCK_FILE', fopen(\pocketmine\LOCK_FILE_PATH, "a+b"));
|
||||
$lockFile = fopen(\pocketmine\DATA . 'server.lock', "a+b");
|
||||
if($lockFile === false){
|
||||
critical_error("Unable to open server.lock file. Please check that the current user has read/write permissions to it.");
|
||||
exit(1);
|
||||
}
|
||||
define('pocketmine\LOCK_FILE', $lockFile);
|
||||
if(!flock(\pocketmine\LOCK_FILE, LOCK_EX | LOCK_NB)){
|
||||
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the
|
||||
//other server wrote its PID and released exclusive lock before we get our lock
|
||||
@ -213,7 +249,7 @@ namespace pocketmine {
|
||||
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
|
||||
|
||||
//Logger has a dependency on timezone
|
||||
Timezone::init();
|
||||
$tzError = Timezone::init();
|
||||
|
||||
if(isset($opts["enable-ansi"])){
|
||||
Terminal::init(true);
|
||||
@ -224,41 +260,14 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||
\GlobalLogger::set($logger);
|
||||
$logger->registerStatic();
|
||||
|
||||
if(extension_loaded("xdebug")){
|
||||
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
||||
foreach($tzError as $e){
|
||||
$logger->warning($e);
|
||||
}
|
||||
unset($tzError);
|
||||
|
||||
if(\Phar::running(true) === ""){
|
||||
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
|
||||
}
|
||||
|
||||
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
||||
define('pocketmine\VERSION', $version->getFullVersion(true));
|
||||
|
||||
$gitHash = str_repeat("00", 20);
|
||||
|
||||
if(\Phar::running(true) === ""){
|
||||
if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
|
||||
$gitHash = trim($out);
|
||||
if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified
|
||||
$gitHash .= "-dirty";
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$meta = $phar->getMetadata();
|
||||
if(isset($meta["git"])){
|
||||
$gitHash = $meta["git"];
|
||||
}
|
||||
}
|
||||
|
||||
define('pocketmine\GIT_COMMIT', $gitHash);
|
||||
|
||||
|
||||
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
|
||||
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
|
||||
emit_performance_warnings($logger);
|
||||
|
||||
$exitCode = 0;
|
||||
do{
|
||||
@ -272,7 +281,13 @@ namespace pocketmine {
|
||||
|
||||
//TODO: move this to a Server field
|
||||
define('pocketmine\START_TIME', microtime(true));
|
||||
ThreadManager::init();
|
||||
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
||||
*/
|
||||
$autoloader = new \BaseClassLoader();
|
||||
$autoloader->register(false);
|
||||
|
||||
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
|
||||
|
||||
$logger->info("Stopping other threads");
|
||||
@ -282,10 +297,8 @@ namespace pocketmine {
|
||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||
|
||||
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||
if(\pocketmine\DEBUG > 1){
|
||||
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
Process::kill(getmypid());
|
||||
$logger->debug("Some threads could not be stopped, performing a force-kill");
|
||||
Process::kill(Process::pid());
|
||||
}
|
||||
}while(false);
|
||||
|
||||
@ -294,6 +307,14 @@ namespace pocketmine {
|
||||
|
||||
echo Terminal::$FORMAT_RESET . PHP_EOL;
|
||||
|
||||
if(!flock(\pocketmine\LOCK_FILE, LOCK_UN)){
|
||||
critical_error("Failed to release the server.lock file.");
|
||||
}
|
||||
|
||||
if(!fclose(\pocketmine\LOCK_FILE)){
|
||||
critical_error("Could not close server.lock resource.");
|
||||
}
|
||||
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,24 +21,34 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\thread;
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\Server;
|
||||
use function error_reporting;
|
||||
use const PTHREADS_INHERIT_ALL;
|
||||
|
||||
/**
|
||||
* This class must be extended by all custom threading classes
|
||||
*/
|
||||
abstract class Thread extends \Thread{
|
||||
|
||||
trait CommonThreadPartsTrait{
|
||||
/** @var \ClassLoader|null */
|
||||
protected $classLoader;
|
||||
/** @var string|null */
|
||||
protected $composerAutoloaderPath;
|
||||
|
||||
/** @var bool */
|
||||
protected $isKilled = false;
|
||||
|
||||
/**
|
||||
* @return \ClassLoader|null
|
||||
*/
|
||||
public function getClassLoader(){
|
||||
return $this->classLoader;
|
||||
}
|
||||
|
||||
public function setClassLoader(?\ClassLoader $loader = null) : void{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setClassLoader(\ClassLoader $loader = null){
|
||||
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||
|
||||
if($loader === null){
|
||||
@ -53,8 +63,10 @@ trait CommonThreadPartsTrait{
|
||||
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
|
||||
* If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
|
||||
* (unless you are using a custom autoloader).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerClassLoader() : void{
|
||||
public function registerClassLoader(){
|
||||
if($this->composerAutoloaderPath !== null){
|
||||
require $this->composerAutoloaderPath;
|
||||
}
|
||||
@ -63,18 +75,33 @@ trait CommonThreadPartsTrait{
|
||||
}
|
||||
}
|
||||
|
||||
final public function run() : void{
|
||||
error_reporting(-1);
|
||||
$this->registerClassLoader();
|
||||
//set this after the autoloader is registered
|
||||
\ErrorUtils::setErrorExceptionHandler();
|
||||
$this->onRun();
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||
ThreadManager::getInstance()->add($this);
|
||||
|
||||
if($this->getClassLoader() === null){
|
||||
$this->setClassLoader();
|
||||
}
|
||||
return parent::start($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs code on the thread.
|
||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function onRun() : void;
|
||||
public function quit(){
|
||||
$this->isKilled = true;
|
||||
|
||||
if(!$this->isJoined()){
|
||||
$this->notify();
|
||||
$this->join();
|
||||
}
|
||||
|
||||
ThreadManager::getInstance()->remove($this);
|
||||
}
|
||||
|
||||
public function getThreadName() : string{
|
||||
return (new \ReflectionClass($this))->getShortName();
|
@ -21,41 +21,53 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\thread;
|
||||
namespace pocketmine;
|
||||
|
||||
use function spl_object_id;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use function spl_object_hash;
|
||||
|
||||
class ThreadManager extends \Volatile{
|
||||
|
||||
/** @var ThreadManager */
|
||||
/** @var ThreadManager|null */
|
||||
private static $instance = null;
|
||||
|
||||
public static function init() : void{
|
||||
/**
|
||||
* @deprecated
|
||||
* @return void
|
||||
*/
|
||||
public static function init(){
|
||||
self::$instance = new ThreadManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ThreadManager
|
||||
*/
|
||||
public static function getInstance() : ThreadManager{
|
||||
public static function getInstance(){
|
||||
if(self::$instance === null){
|
||||
self::$instance = new ThreadManager();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Worker|Thread $thread
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($thread) : void{
|
||||
public function add($thread){
|
||||
if($thread instanceof Thread or $thread instanceof Worker){
|
||||
$this->{spl_object_id($thread)} = $thread;
|
||||
$this[spl_object_hash($thread)] = $thread;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Worker|Thread $thread
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove($thread) : void{
|
||||
public function remove($thread){
|
||||
if($thread instanceof Thread or $thread instanceof Worker){
|
||||
unset($this->{spl_object_id($thread)});
|
||||
unset($this[spl_object_hash($thread)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +84,7 @@ class ThreadManager extends \Volatile{
|
||||
}
|
||||
|
||||
public function stopAll() : int{
|
||||
$logger = \GlobalLogger::get();
|
||||
$logger = MainLogger::getLogger();
|
||||
|
||||
$erroredThreads = 0;
|
||||
|
@ -19,9 +19,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use function defined;
|
||||
|
||||
// composer autoload doesn't use require_once and also pthreads can inherit things
|
||||
// TODO: drop this file and use a final class with constants
|
||||
if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
|
||||
return;
|
||||
}
|
||||
const _VERSION_INFO_INCLUDED = true;
|
||||
|
||||
const NAME = "PocketMine-MP";
|
||||
const BASE_VERSION = "4.0.0";
|
||||
const IS_DEVELOPMENT_BUILD = true;
|
||||
const BASE_VERSION = "3.19.3";
|
||||
const IS_DEVELOPMENT_BUILD = false;
|
||||
const BUILD_NUMBER = 0;
|
||||
|
110
src/pocketmine/Worker.php
Normal file
110
src/pocketmine/Worker.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?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 const PTHREADS_INHERIT_ALL;
|
||||
|
||||
/**
|
||||
* This class must be extended by all custom threading classes
|
||||
*/
|
||||
abstract class Worker extends \Worker{
|
||||
|
||||
/** @var \ClassLoader|null */
|
||||
protected $classLoader;
|
||||
/** @var string|null */
|
||||
protected $composerAutoloaderPath;
|
||||
|
||||
/** @var bool */
|
||||
protected $isKilled = false;
|
||||
|
||||
/**
|
||||
* @return \ClassLoader|null
|
||||
*/
|
||||
public function getClassLoader(){
|
||||
return $this->classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setClassLoader(\ClassLoader $loader = null){
|
||||
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||
|
||||
if($loader === null){
|
||||
$loader = Server::getInstance()->getLoader();
|
||||
}
|
||||
$this->classLoader = $loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the class loader for this thread.
|
||||
*
|
||||
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
|
||||
* If you do not do this, you will not be able to use new classes that were not loaded when the thread was started
|
||||
* (unless you are using a custom autoloader).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerClassLoader(){
|
||||
if($this->composerAutoloaderPath !== null){
|
||||
require $this->composerAutoloaderPath;
|
||||
}
|
||||
if($this->classLoader !== null){
|
||||
$this->classLoader->register(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||
ThreadManager::getInstance()->add($this);
|
||||
|
||||
if($this->getClassLoader() === null){
|
||||
$this->setClassLoader();
|
||||
}
|
||||
return parent::start($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function quit(){
|
||||
$this->isKilled = true;
|
||||
|
||||
if(!$this->isShutdown()){
|
||||
while($this->unstack() !== null);
|
||||
$this->notify();
|
||||
$this->shutdown();
|
||||
}
|
||||
|
||||
ThreadManager::getInstance()->remove($this);
|
||||
}
|
||||
|
||||
public function getThreadName() : string{
|
||||
return (new \ReflectionClass($this))->getShortName();
|
||||
}
|
||||
}
|
@ -25,5 +25,11 @@ namespace pocketmine\block;
|
||||
|
||||
class ActivatorRail extends RedstoneRail{
|
||||
|
||||
protected $id = self::ACTIVATOR_RAIL;
|
||||
|
||||
public function getName() : string{
|
||||
return "Activator Rail";
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
/**
|
||||
@ -30,8 +31,22 @@ use pocketmine\math\AxisAlignedBB;
|
||||
*/
|
||||
class Air extends Transparent{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? BlockBreakInfo::indestructible(0.0));
|
||||
protected $id = self::AIR;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Air";
|
||||
}
|
||||
|
||||
public function canPassThrough() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
@ -57,4 +72,12 @@ class Air extends Transparent{
|
||||
public function getCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -23,60 +23,93 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\inventory\AnvilInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\item\TieredTool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Anvil extends Transparent implements Fallable{
|
||||
use FallableTrait;
|
||||
class Anvil extends Fallable{
|
||||
|
||||
/** @var int */
|
||||
protected $facing = Facing::NORTH;
|
||||
public const TYPE_NORMAL = 0;
|
||||
public const TYPE_SLIGHTLY_DAMAGED = 4;
|
||||
public const TYPE_VERY_DAMAGED = 8;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0));
|
||||
protected $id = self::ANVIL;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing);
|
||||
public function isTransparent() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta);
|
||||
public function getHardness() : float{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b11;
|
||||
public function getBlastResistance() : float{
|
||||
return 6000;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8);
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x0c;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::TYPE_NORMAL => "Anvil",
|
||||
self::TYPE_SLIGHTLY_DAMAGED => "Slightly Damaged Anvil",
|
||||
self::TYPE_VERY_DAMAGED => "Very Damaged Anvil"
|
||||
];
|
||||
return $names[$this->getVariant()] ?? "Anvil";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$inset = 0.125;
|
||||
|
||||
if(($this->meta & 0x01) !== 0){ //east/west
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + $inset,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1 - $inset
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $inset,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1 - $inset,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCurrentWindow(new AnvilInventory($this));
|
||||
$player->addWindow(new AnvilInventory($this));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->facing = Facing::rotateY($player->getHorizontalFacing(), true);
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function tickFalling() : ?Block{
|
||||
return null;
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$direction = ($player !== null ? $player->getDirection() : 0) & 0x03;
|
||||
$this->meta = $this->getVariant() | $direction;
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
}
|
||||
|
@ -1,194 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use Ds\Deque;
|
||||
use pocketmine\block\tile\Banner as TileBanner;
|
||||
use pocketmine\block\utils\BannerPattern;
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\item\Banner as ItemBanner;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function assert;
|
||||
use function floor;
|
||||
|
||||
class Banner extends Transparent{
|
||||
/** @var BlockIdentifierFlattened */
|
||||
protected $idInfo;
|
||||
|
||||
//TODO: conditionally useless properties, find a way to fix
|
||||
|
||||
/** @var int */
|
||||
protected $rotation = 0;
|
||||
|
||||
/** @var int */
|
||||
protected $facing = Facing::UP;
|
||||
|
||||
/** @var DyeColor */
|
||||
protected $baseColor;
|
||||
|
||||
/** @var Deque|BannerPattern[] */
|
||||
protected $patterns;
|
||||
|
||||
public function __construct(BlockIdentifierFlattened $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(1.0, BlockToolType::AXE));
|
||||
$this->baseColor = DyeColor::BLACK();
|
||||
$this->patterns = new Deque();
|
||||
}
|
||||
|
||||
public function __clone(){
|
||||
$this->patterns = $this->patterns->map(Utils::cloneCallback());
|
||||
}
|
||||
|
||||
public function getId() : int{
|
||||
return $this->facing === Facing::UP ? parent::getId() : $this->idInfo->getSecondId();
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
if($this->facing === Facing::UP){
|
||||
return $this->rotation;
|
||||
}
|
||||
return BlockDataSerializer::writeHorizontalFacing($this->facing);
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
if($id === $this->idInfo->getSecondId()){
|
||||
$this->facing = BlockDataSerializer::readHorizontalFacing($stateMeta);
|
||||
}else{
|
||||
$this->facing = Facing::UP;
|
||||
$this->rotation = $stateMeta;
|
||||
}
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : void{
|
||||
parent::readStateFromWorld();
|
||||
$tile = $this->world->getTile($this);
|
||||
if($tile instanceof TileBanner){
|
||||
$this->baseColor = $tile->getBaseColor();
|
||||
$this->setPatterns($tile->getPatterns());
|
||||
}
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
$tile = $this->world->getTile($this);
|
||||
assert($tile instanceof TileBanner);
|
||||
$tile->setBaseColor($this->baseColor);
|
||||
$tile->setPatterns($this->patterns);
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: interface method? this is only the BASE colour...
|
||||
* @return DyeColor
|
||||
*/
|
||||
public function getColor() : DyeColor{
|
||||
return $this->baseColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deque|BannerPattern[]
|
||||
*/
|
||||
public function getPatterns() : Deque{
|
||||
return $this->patterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Deque|BannerPattern[] $patterns
|
||||
*/
|
||||
public function setPatterns(Deque $patterns) : void{
|
||||
$checked = $patterns->filter(function($v){ return $v instanceof BannerPattern; });
|
||||
if($checked->count() !== $patterns->count()){
|
||||
throw new \TypeError("Deque must only contain " . BannerPattern::class . " objects");
|
||||
}
|
||||
$this->patterns = $checked;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($item instanceof ItemBanner){
|
||||
$this->baseColor = $item->getColor();
|
||||
$this->setPatterns($item->getPatterns());
|
||||
}
|
||||
if($face !== Facing::DOWN){
|
||||
$this->facing = $face;
|
||||
if($face === Facing::UP){
|
||||
$this->rotation = $player !== null ? ((int) floor((($player->yaw + 180) * 16 / 360) + 0.5)) & 0x0f : 0;
|
||||
}
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::opposite($this->facing))->getId() === BlockLegacyIds::AIR){
|
||||
$this->getWorld()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::get(ItemIds::BANNER, $this->baseColor->getInvertedMagicNumber());
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
$drop = $this->asItem();
|
||||
if($drop instanceof ItemBanner and !$this->patterns->isEmpty()){
|
||||
$drop->setPatterns($this->patterns);
|
||||
}
|
||||
|
||||
return [$drop];
|
||||
}
|
||||
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$result = $this->asItem();
|
||||
if($addUserData and $result instanceof ItemBanner and !$this->patterns->isEmpty()){
|
||||
$result->setPatterns($this->patterns);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -23,12 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\Player;
|
||||
use function array_map;
|
||||
use function array_reverse;
|
||||
use function array_search;
|
||||
@ -39,76 +36,74 @@ use function in_array;
|
||||
|
||||
abstract class BaseRail extends Flowable{
|
||||
|
||||
public const STRAIGHT_NORTH_SOUTH = 0;
|
||||
public const STRAIGHT_EAST_WEST = 1;
|
||||
public const ASCENDING_EAST = 2;
|
||||
public const ASCENDING_WEST = 3;
|
||||
public const ASCENDING_NORTH = 4;
|
||||
public const ASCENDING_SOUTH = 5;
|
||||
|
||||
private const ASCENDING_SIDES = [
|
||||
self::ASCENDING_NORTH => Vector3::SIDE_NORTH,
|
||||
self::ASCENDING_EAST => Vector3::SIDE_EAST,
|
||||
self::ASCENDING_SOUTH => Vector3::SIDE_SOUTH,
|
||||
self::ASCENDING_WEST => Vector3::SIDE_WEST
|
||||
];
|
||||
|
||||
protected const FLAG_ASCEND = 1 << 24; //used to indicate direction-up
|
||||
|
||||
protected const CONNECTIONS = [
|
||||
//straights
|
||||
BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH => [
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH
|
||||
self::STRAIGHT_NORTH_SOUTH => [
|
||||
Vector3::SIDE_NORTH,
|
||||
Vector3::SIDE_SOUTH
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_STRAIGHT_EAST_WEST => [
|
||||
Facing::EAST,
|
||||
Facing::WEST
|
||||
self::STRAIGHT_EAST_WEST => [
|
||||
Vector3::SIDE_EAST,
|
||||
Vector3::SIDE_WEST
|
||||
],
|
||||
|
||||
//ascending
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_EAST => [
|
||||
Facing::WEST,
|
||||
Facing::EAST | self::FLAG_ASCEND
|
||||
self::ASCENDING_EAST => [
|
||||
Vector3::SIDE_WEST,
|
||||
Vector3::SIDE_EAST | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_WEST => [
|
||||
Facing::EAST,
|
||||
Facing::WEST | self::FLAG_ASCEND
|
||||
self::ASCENDING_WEST => [
|
||||
Vector3::SIDE_EAST,
|
||||
Vector3::SIDE_WEST | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_NORTH => [
|
||||
Facing::SOUTH,
|
||||
Facing::NORTH | self::FLAG_ASCEND
|
||||
self::ASCENDING_NORTH => [
|
||||
Vector3::SIDE_SOUTH,
|
||||
Vector3::SIDE_NORTH | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_SOUTH => [
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH | self::FLAG_ASCEND
|
||||
self::ASCENDING_SOUTH => [
|
||||
Vector3::SIDE_NORTH,
|
||||
Vector3::SIDE_SOUTH | self::FLAG_ASCEND
|
||||
]
|
||||
];
|
||||
|
||||
/** @var int[] */
|
||||
protected $connections = [];
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.7));
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
if(empty($this->connections)){
|
||||
return BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
|
||||
}
|
||||
return $this->getMetaForState($this->connections);
|
||||
public function getHardness() : float{
|
||||
return 0.7;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$connections = $this->getConnectionsFromMeta($stateMeta);
|
||||
if($connections === null){
|
||||
throw new InvalidBlockStateException("Invalid rail type meta $stateMeta");
|
||||
}
|
||||
$this->connections = $connections;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
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()){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true)){
|
||||
$this->tryReconnect();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onPostPlace() : void{
|
||||
$this->tryReconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $connections
|
||||
* @param int[][] $lookup
|
||||
* @phpstan-param array<int, list<int>> $lookup
|
||||
*/
|
||||
protected static function searchState(array $connections, array $lookup) : int{
|
||||
$meta = array_search($connections, $lookup, true);
|
||||
if($meta === false){
|
||||
@ -124,9 +119,7 @@ abstract class BaseRail extends Flowable{
|
||||
/**
|
||||
* Returns a meta value for the rail with the given connections.
|
||||
*
|
||||
* @param array $connections
|
||||
*
|
||||
* @return int
|
||||
* @param int[] $connections
|
||||
*
|
||||
* @throws \InvalidArgumentException if no state matches the given connections
|
||||
*/
|
||||
@ -137,11 +130,9 @@ abstract class BaseRail extends Flowable{
|
||||
/**
|
||||
* Returns the connection directions of this rail (depending on the current block state)
|
||||
*
|
||||
* @param int $meta
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
abstract protected function getConnectionsFromMeta(int $meta) : ?array;
|
||||
abstract protected function getConnectionsForState() : array;
|
||||
|
||||
/**
|
||||
* Returns all the directions this rail is already connected in.
|
||||
@ -153,21 +144,21 @@ abstract class BaseRail extends Flowable{
|
||||
$connections = [];
|
||||
|
||||
/** @var int $connection */
|
||||
foreach($this->connections as $connection){
|
||||
foreach($this->getConnectionsForState() as $connection){
|
||||
$other = $this->getSide($connection & ~self::FLAG_ASCEND);
|
||||
$otherConnection = Facing::opposite($connection & ~self::FLAG_ASCEND);
|
||||
$otherConnection = Vector3::getOppositeSide($connection & ~self::FLAG_ASCEND);
|
||||
|
||||
if(($connection & self::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
$other = $other->getSide(Vector3::SIDE_UP);
|
||||
|
||||
}elseif(!($other instanceof BaseRail)){ //check for rail sloping up to meet this one
|
||||
$other = $other->getSide(Facing::DOWN);
|
||||
$other = $other->getSide(Vector3::SIDE_DOWN);
|
||||
$otherConnection |= self::FLAG_ASCEND;
|
||||
}
|
||||
|
||||
if(
|
||||
$other instanceof BaseRail and
|
||||
in_array($otherConnection, $other->connections, true)
|
||||
in_array($otherConnection, $other->getConnectionsForState(), true)
|
||||
){
|
||||
$connections[] = $connection;
|
||||
}
|
||||
@ -176,15 +167,21 @@ abstract class BaseRail extends Flowable{
|
||||
return $connections;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $constraints
|
||||
*
|
||||
* @return true[]
|
||||
* @phpstan-return array<int, true>
|
||||
*/
|
||||
private function getPossibleConnectionDirections(array $constraints) : array{
|
||||
switch(count($constraints)){
|
||||
case 0:
|
||||
//No constraints, can connect in any direction
|
||||
$possible = [
|
||||
Facing::NORTH => true,
|
||||
Facing::SOUTH => true,
|
||||
Facing::WEST => true,
|
||||
Facing::EAST => true
|
||||
Vector3::SIDE_NORTH => true,
|
||||
Vector3::SIDE_SOUTH => true,
|
||||
Vector3::SIDE_WEST => true,
|
||||
Vector3::SIDE_EAST => true
|
||||
];
|
||||
foreach($possible as $p => $_){
|
||||
$possible[$p | self::FLAG_ASCEND] = true;
|
||||
@ -200,8 +197,12 @@ abstract class BaseRail extends Flowable{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true[]
|
||||
* @phpstan-return array<int, true>
|
||||
*/
|
||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||
$opposite = Facing::opposite($constraint & ~self::FLAG_ASCEND);
|
||||
$opposite = Vector3::getOppositeSide($constraint & ~self::FLAG_ASCEND);
|
||||
|
||||
$possible = [$opposite => true];
|
||||
|
||||
@ -222,15 +223,15 @@ abstract class BaseRail extends Flowable{
|
||||
$continue = false;
|
||||
|
||||
foreach($possible as $thisSide => $_){
|
||||
$otherSide = Facing::opposite($thisSide & ~self::FLAG_ASCEND);
|
||||
$otherSide = Vector3::getOppositeSide($thisSide & ~self::FLAG_ASCEND);
|
||||
|
||||
$other = $this->getSide($thisSide & ~self::FLAG_ASCEND);
|
||||
|
||||
if(($thisSide & self::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
$other = $other->getSide(Vector3::SIDE_UP);
|
||||
|
||||
}elseif(!($other instanceof BaseRail)){ //check if other rails can slope up to meet this one
|
||||
$other = $other->getSide(Facing::DOWN);
|
||||
$other = $other->getSide(Vector3::SIDE_DOWN);
|
||||
$otherSide |= self::FLAG_ASCEND;
|
||||
}
|
||||
|
||||
@ -243,8 +244,7 @@ abstract class BaseRail extends Flowable{
|
||||
|
||||
if(isset($otherPossible[$otherSide])){
|
||||
$otherConnections[] = $otherSide;
|
||||
$other->setConnections($otherConnections);
|
||||
$other->world->setBlock($other, $other);
|
||||
$other->updateState($otherConnections);
|
||||
|
||||
$changed = true;
|
||||
$thisConnections[] = $thisSide;
|
||||
@ -256,31 +256,34 @@ abstract class BaseRail extends Flowable{
|
||||
}while($continue);
|
||||
|
||||
if($changed){
|
||||
$this->setConnections($thisConnections);
|
||||
$this->world->setBlock($this, $this);
|
||||
$this->updateState($thisConnections);
|
||||
}
|
||||
}
|
||||
|
||||
private function setConnections(array $connections) : void{
|
||||
/**
|
||||
* @param int[] $connections
|
||||
*/
|
||||
private function updateState(array $connections) : void{
|
||||
if(count($connections) === 1){
|
||||
$connections[] = Facing::opposite($connections[0] & ~self::FLAG_ASCEND);
|
||||
$connections[] = Vector3::getOppositeSide($connections[0] & ~self::FLAG_ASCEND);
|
||||
}elseif(count($connections) !== 2){
|
||||
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
|
||||
}
|
||||
|
||||
$this->connections = $connections;
|
||||
$this->meta = $this->getMetaForState($connections);
|
||||
$this->level->setBlock($this, $this, false, false); //avoid recursion
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::DOWN)->isTransparent()){
|
||||
$this->world->useBreakOn($this);
|
||||
}else{
|
||||
foreach($this->connections as $connection){
|
||||
if(($connection & self::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~self::FLAG_ASCEND)->isTransparent()){
|
||||
$this->world->useBreakOn($this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() or (
|
||||
isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
|
||||
$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
|
||||
)){
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -23,116 +23,109 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Bed as TileBed;
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\item\Bed as ItemBed;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\lang\TranslationContainer;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Bed as TileBed;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\World;
|
||||
|
||||
class Bed extends Transparent{
|
||||
public const BITFLAG_OCCUPIED = 0x04;
|
||||
public const BITFLAG_HEAD = 0x08;
|
||||
|
||||
/** @var int */
|
||||
protected $facing = Facing::NORTH;
|
||||
/** @var bool */
|
||||
protected $occupied = false;
|
||||
/** @var bool */
|
||||
protected $head = false;
|
||||
/** @var DyeColor */
|
||||
protected $color;
|
||||
protected $id = self::BED_BLOCK;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.2));
|
||||
$this->color = DyeColor::RED();
|
||||
protected $itemId = Item::BED;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) |
|
||||
($this->occupied ? BlockLegacyMetadata::BED_FLAG_OCCUPIED : 0) |
|
||||
($this->head ? BlockLegacyMetadata::BED_FLAG_HEAD : 0);
|
||||
public function getHardness() : float{
|
||||
return 0.2;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
|
||||
$this->occupied = ($stateMeta & BlockLegacyMetadata::BED_FLAG_OCCUPIED) !== 0;
|
||||
$this->head = ($stateMeta & BlockLegacyMetadata::BED_FLAG_HEAD) !== 0;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : void{
|
||||
parent::readStateFromWorld();
|
||||
//read extra state information from the tile - this is an ugly hack
|
||||
$tile = $this->world->getTile($this);
|
||||
if($tile instanceof TileBed){
|
||||
$this->color = $tile->getColor();
|
||||
}
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
//extra block properties storage hack
|
||||
$tile = $this->world->getTile($this);
|
||||
if($tile instanceof TileBed){
|
||||
$tile->setColor($this->color);
|
||||
}
|
||||
public function getName() : string{
|
||||
return "Bed Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return AxisAlignedBB::one()->trim(Facing::UP, 7 / 16);
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 0.5625,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
|
||||
public function isHeadPart() : bool{
|
||||
return $this->head;
|
||||
return ($this->meta & self::BITFLAG_HEAD) !== 0;
|
||||
}
|
||||
|
||||
public function isOccupied() : bool{
|
||||
return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @return void
|
||||
*/
|
||||
public function isOccupied() : bool{
|
||||
return $this->occupied;
|
||||
}
|
||||
public function setOccupied(bool $occupied = true){
|
||||
if($occupied){
|
||||
$this->meta |= self::BITFLAG_OCCUPIED;
|
||||
}else{
|
||||
$this->meta &= ~self::BITFLAG_OCCUPIED;
|
||||
}
|
||||
|
||||
public function setOccupied(bool $occupied = true) : void{
|
||||
$this->occupied = $occupied;
|
||||
$this->world->setBlock($this, $this, false);
|
||||
$this->getLevelNonNull()->setBlock($this, $this, false, false);
|
||||
|
||||
if(($other = $this->getOtherHalf()) !== null){
|
||||
$other->occupied = $occupied;
|
||||
$this->world->setBlock($other, $other, false);
|
||||
if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
|
||||
$other->setOccupied($occupied);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function getOtherHalfSide() : int{
|
||||
return $this->head ? Facing::opposite($this->facing) : $this->facing;
|
||||
public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{
|
||||
$rotation = $meta & 0x03;
|
||||
$side = -1;
|
||||
|
||||
switch($rotation){
|
||||
case 0x00: //South
|
||||
$side = Vector3::SIDE_SOUTH;
|
||||
break;
|
||||
case 0x01: //West
|
||||
$side = Vector3::SIDE_WEST;
|
||||
break;
|
||||
case 0x02: //North
|
||||
$side = Vector3::SIDE_NORTH;
|
||||
break;
|
||||
case 0x03: //East
|
||||
$side = Vector3::SIDE_EAST;
|
||||
break;
|
||||
}
|
||||
|
||||
if($isHead){
|
||||
$side = Vector3::getOppositeSide($side);
|
||||
}
|
||||
|
||||
return $side;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Bed|null
|
||||
*/
|
||||
public function getOtherHalf() : ?Bed{
|
||||
$other = $this->getSide($this->getOtherHalfSide());
|
||||
if($other instanceof Bed and $other->head !== $this->head and $other->facing === $this->facing){
|
||||
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
||||
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
||||
return $other;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$other = $this->getOtherHalf();
|
||||
if($other === null){
|
||||
@ -144,9 +137,9 @@ class Bed extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
$time = $this->getWorld()->getTimeOfDay();
|
||||
$time = $this->getLevelNonNull()->getTimeOfDay();
|
||||
|
||||
$isNight = ($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE);
|
||||
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
||||
|
||||
if(!$isNight){
|
||||
$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.noSleep"));
|
||||
@ -169,19 +162,18 @@ class Bed extends Transparent{
|
||||
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($item instanceof ItemBed){ //TODO: the item should do this
|
||||
$this->color = $item->getColor();
|
||||
}
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if(!$down->isTransparent()){
|
||||
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
|
||||
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
||||
$next = $this->getSide(self::getOtherHalfSide($meta));
|
||||
if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||
$this->getLevelNonNull()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||
|
||||
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($next, $face, $item, $player));
|
||||
|
||||
$next = $this->getSide($this->getOtherHalfSide());
|
||||
if($next->canBeReplaced() and !$next->getSide(Facing::DOWN)->isTransparent()){
|
||||
$nextState = clone $this;
|
||||
$nextState->head = true;
|
||||
$tx->addBlock($blockReplace, $this)->addBlock($next, $nextState);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -189,16 +181,29 @@ class Bed extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($this->head){
|
||||
return parent::getDrops($item);
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if($this->isHeadPart()){
|
||||
return [$this->getItem()];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::get($this->idInfo->getItemId(), $this->color->getMagicNumber());
|
||||
public function getPickedItem() : Item{
|
||||
return $this->getItem();
|
||||
}
|
||||
|
||||
private function getItem() : Item{
|
||||
$tile = $this->getLevelNonNull()->getTile($this);
|
||||
if($tile instanceof TileBed){
|
||||
return ItemFactory::get($this->getItemId(), $tile->getColor());
|
||||
}
|
||||
|
||||
return ItemFactory::get($this->getItemId(), 14); //Red
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAffectedBlocks() : array{
|
||||
|
@ -23,28 +23,29 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class Bedrock extends Opaque{
|
||||
use pocketmine\item\Item;
|
||||
|
||||
/** @var bool */
|
||||
private $burnsForever = false;
|
||||
class Bedrock extends Solid{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? BlockBreakInfo::indestructible());
|
||||
protected $id = self::BEDROCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->burnsForever = ($stateMeta & BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN) !== 0;
|
||||
public function getName() : string{
|
||||
return "Bedrock";
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->burnsForever ? BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN : 0;
|
||||
public function getHardness() : float{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1;
|
||||
public function getBlastResistance() : float{
|
||||
return 18000000;
|
||||
}
|
||||
|
||||
public function burnsForever() : bool{
|
||||
return $this->burnsForever;
|
||||
public function isBreakable(Item $item) : bool{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -24,25 +24,35 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use function mt_rand;
|
||||
|
||||
class Beetroot extends Crops{
|
||||
|
||||
protected $id = self::BEETROOT_BLOCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Beetroot Block";
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if($this->age >= 7){
|
||||
if($this->meta >= 0x07){
|
||||
return [
|
||||
VanillaItems::BEETROOT(),
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(mt_rand(0, 3))
|
||||
ItemFactory::get(Item::BEETROOT),
|
||||
ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
VanillaItems::BEETROOT_SEEDS()
|
||||
ItemFactory::get(Item::BEETROOT_SEEDS)
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
return VanillaItems::BEETROOT_SEEDS();
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::BEETROOT_SEEDS);
|
||||
}
|
||||
}
|
||||
|
@ -26,197 +26,122 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Spawnable;
|
||||
use pocketmine\block\tile\Tile;
|
||||
use pocketmine\block\tile\TileFactory;
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function dechex;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
class Block extends Position{
|
||||
class Block extends Position implements BlockIds, Metadatable{
|
||||
|
||||
/** @var BlockIdentifier */
|
||||
protected $idInfo;
|
||||
/**
|
||||
* Returns a new Block instance with the specified ID, meta and position.
|
||||
*
|
||||
* This function redirects to {@link BlockFactory#get}.
|
||||
*/
|
||||
public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
|
||||
return BlockFactory::get($id, $meta, $pos);
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
/** @var int */
|
||||
protected $id;
|
||||
/** @var int */
|
||||
protected $meta = 0;
|
||||
/** @var string|null */
|
||||
protected $fallbackName;
|
||||
/** @var int|null */
|
||||
protected $itemId;
|
||||
|
||||
/** @var BlockBreakInfo */
|
||||
protected $breakInfo;
|
||||
|
||||
|
||||
/** @var AxisAlignedBB */
|
||||
/** @var AxisAlignedBB|null */
|
||||
protected $boundingBox = null;
|
||||
|
||||
/** @var AxisAlignedBB[]|null */
|
||||
protected $collisionBoxes = null;
|
||||
|
||||
/**
|
||||
* @param BlockIdentifier $idInfo
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
* @param BlockBreakInfo $breakInfo
|
||||
* @param int $id The block type's ID, 0-255
|
||||
* @param int $meta Meta value of the block type
|
||||
* @param string|null $name English name of the block type (TODO: implement translations)
|
||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||
*/
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
|
||||
if(($idInfo->getVariant() & $this->getStateBitmask()) !== 0){
|
||||
throw new \InvalidArgumentException("Variant 0x" . dechex($idInfo->getVariant()) . " collides with state bitmask 0x" . dechex($this->getStateBitmask()));
|
||||
}
|
||||
$this->idInfo = $idInfo;
|
||||
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
|
||||
$this->id = $id;
|
||||
$this->meta = $meta;
|
||||
$this->fallbackName = $name;
|
||||
$this->breakInfo = $breakInfo;
|
||||
$this->itemId = $itemId;
|
||||
}
|
||||
|
||||
public function getIdInfo() : BlockIdentifier{
|
||||
return $this->idInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string{
|
||||
return $this->fallbackName;
|
||||
return $this->fallbackName ?? "Unknown";
|
||||
}
|
||||
|
||||
final public function getId() : int{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* Returns the ID of the item form of the block.
|
||||
* Used for drops for blocks (some blocks such as doors have a different item ID).
|
||||
*/
|
||||
public function getId() : int{
|
||||
return $this->idInfo->getBlockId();
|
||||
public function getItemId() : int{
|
||||
return $this->itemId ?? $this->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return int
|
||||
*/
|
||||
public function getFullId() : int{
|
||||
return ($this->getId() << 4) | $this->getMeta();
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::get($this->idInfo->getItemId(), $this->idInfo->getVariant());
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @return int
|
||||
*/
|
||||
public function getRuntimeId() : int{
|
||||
return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getMeta());
|
||||
return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMeta() : int{
|
||||
$stateMeta = $this->writeStateToMeta();
|
||||
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
|
||||
return $this->idInfo->getVariant() | $stateMeta;
|
||||
final public function getDamage() : int{
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a bitmask used to extract state bits from block metadata.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStateBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param int $stateMeta
|
||||
*
|
||||
* @throws InvalidBlockStateException
|
||||
*/
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is created, set, or has a neighbouring block update, to re-detect dynamic properties which
|
||||
* are not saved on the world.
|
||||
*
|
||||
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
|
||||
* AABBs and force recalculation.
|
||||
*/
|
||||
public function readStateFromWorld() : void{
|
||||
$this->boundingBox = null;
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
$this->world->getChunkAtPosition($this)->setFullBlock($this->x & 0xf, $this->y, $this->z & 0xf, $this->getFullId());
|
||||
|
||||
$tileType = $this->idInfo->getTileClass();
|
||||
$oldTile = $this->world->getTile($this);
|
||||
if($oldTile !== null){
|
||||
if($tileType === null or !($oldTile instanceof $tileType)){
|
||||
$oldTile->close();
|
||||
$oldTile = null;
|
||||
}elseif($oldTile instanceof Spawnable){
|
||||
$oldTile->setDirty(); //destroy old network cache
|
||||
}
|
||||
}
|
||||
if($oldTile === null and $tileType !== null){
|
||||
$this->world->addTile(TileFactory::create($tileType, $this->world, $this->asVector3()));
|
||||
final public function setDamage(int $meta) : void{
|
||||
if($meta < 0 or $meta > 0xf){
|
||||
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
||||
}
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given block has an equivalent type to this one. This compares base legacy ID and variant.
|
||||
* Bitmask to use to remove superfluous information from block meta when getting its item form or name.
|
||||
* This defaults to -1 (don't remove any data). Used to remove rotation data and bitflags from block drops.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param Block $other
|
||||
*
|
||||
* @return bool
|
||||
* If your block should not have any meta value when it's dropped as an item, override this to return 0 in
|
||||
* descendent classes.
|
||||
*/
|
||||
public function isSameType(Block $other) : bool{
|
||||
return $this->idInfo->getBlockId() === $other->idInfo->getBlockId() and $this->idInfo->getVariant() === $other->idInfo->getVariant();
|
||||
public function getVariantBitmask() : int{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given block has the same type and properties as this block.
|
||||
*
|
||||
* @param Block $other
|
||||
*
|
||||
* @return bool
|
||||
* Returns the block meta, stripped of non-variant flags.
|
||||
*/
|
||||
public function isSameState(Block $other) : bool{
|
||||
return $this->isSameType($other) and $this->writeStateToMeta() === $other->writeStateToMeta();
|
||||
public function getVariant() : int{
|
||||
return $this->meta & $this->getVariantBitmask();
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
* @return bool
|
||||
*/
|
||||
public function canBePlaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeReplaced() : bool{
|
||||
return false;
|
||||
}
|
||||
@ -227,49 +152,82 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
* @param BlockTransaction $tx
|
||||
* @param Item $item
|
||||
* @param Block $blockReplace
|
||||
* @param Block $blockClicked
|
||||
* @param int $face
|
||||
* @param Vector3 $clickVector
|
||||
* @param Player|null $player
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$tx->addBlock($blockReplace, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onPostPlace() : void{
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
return $this->getLevelNonNull()->setBlock($this, $this, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about the destruction requirements of this block.
|
||||
*
|
||||
* @return BlockBreakInfo
|
||||
* Returns if the block can be broken with an specific Item
|
||||
*/
|
||||
public function getBreakInfo() : BlockBreakInfo{
|
||||
return $this->breakInfo;
|
||||
public function isBreakable(Item $item) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level of tool required to harvest this block (for normal blocks). When the tool type matches the
|
||||
* block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
|
||||
* successfully harvest the block.
|
||||
*
|
||||
* If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
|
||||
* Otherwise, 1 should be returned if a tool is required, 0 if not.
|
||||
*
|
||||
* @see Item::getBlockToolHarvestLevel()
|
||||
*/
|
||||
public function getToolHarvestLevel() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
|
||||
* harvest level requirement.
|
||||
*
|
||||
* In most cases this is also used to determine whether block drops should be created or not, except in some
|
||||
* special cases such as vines.
|
||||
*/
|
||||
public function isCompatibleWithTool(Item $tool) : bool{
|
||||
if($this->getHardness() < 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$toolType = $this->getToolType();
|
||||
$harvestLevel = $this->getToolHarvestLevel();
|
||||
return $toolType === BlockToolType::TYPE_NONE or $harvestLevel === 0 or (
|
||||
($toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $harvestLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Player|null $player
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function onBreak(Item $item, ?Player $player = null) : bool{
|
||||
if(($t = $this->world->getTile($this)) !== null){
|
||||
$t->onBlockDestroyed();
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seconds that this block takes to be broken using an specific Item
|
||||
*
|
||||
* @throws \InvalidArgumentException if the item efficiency is not a positive number
|
||||
*/
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$base = $this->getHardness();
|
||||
if($this->isCompatibleWithTool($item)){
|
||||
$base *= 1.5;
|
||||
}else{
|
||||
$base *= 5;
|
||||
}
|
||||
$this->getWorld()->setBlock($this, VanillaBlocks::AIR());
|
||||
return true;
|
||||
|
||||
$efficiency = $item->getMiningEfficiency($this);
|
||||
if($efficiency <= 0){
|
||||
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
|
||||
}
|
||||
|
||||
$base /= $efficiency;
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,8 +239,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns whether random block updates will be done on this block.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ticksRandomly() : bool{
|
||||
return false;
|
||||
@ -297,43 +253,33 @@ class Block extends Position{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is updated by the delayed blockupdate scheduler in the world.
|
||||
* Called when this block is updated by the delayed blockupdate scheduler in the level.
|
||||
*/
|
||||
public function onScheduledUpdate() : void{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Do actions when interacted by Item. Returns if it has done anything
|
||||
*
|
||||
* @param Item $item
|
||||
* @param int $face
|
||||
* @param Vector3 $clickVector
|
||||
* @param Player|null $player
|
||||
*
|
||||
* @return bool
|
||||
* Do actions when activated by Item. Returns if it has done anything
|
||||
*/
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param int $face
|
||||
* @param Player|null $player
|
||||
*
|
||||
* @return bool if an action took place, prevents starting to break the block if true.
|
||||
* Returns a base value used to compute block break times.
|
||||
*/
|
||||
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
|
||||
return false;
|
||||
public function getHardness() : float{
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
* Returns the block's resistance to explosions. Usually 5x hardness.
|
||||
*/
|
||||
public function getBlastResistance() : float{
|
||||
return $this->getHardness() * 5;
|
||||
}
|
||||
|
||||
public function getFrictionFactor() : float{
|
||||
return 0.6;
|
||||
}
|
||||
@ -352,7 +298,7 @@ class Block extends Position{
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getLightFilter() : int{
|
||||
return $this->isTransparent() ? 0 : 15;
|
||||
return 15;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,16 +307,11 @@ class Block extends Position{
|
||||
* Examples of this behaviour include leaves and cobwebs.
|
||||
*
|
||||
* Light-diffusing blocks are included by the heightmap.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function diffusesSkyLight() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransparent() : bool{
|
||||
return false;
|
||||
}
|
||||
@ -381,7 +322,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* AKA: Block->isFlowable
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeFlowedInto() : bool{
|
||||
return false;
|
||||
@ -391,44 +331,40 @@ class Block extends Position{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canPassThrough() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether entities can climb up this block.
|
||||
* @return bool
|
||||
*/
|
||||
public function canClimb() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param World $world
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
* Sets the block position to a new Position object
|
||||
*/
|
||||
final public function position(World $world, int $x, int $y, int $z) : void{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
$this->z = $z;
|
||||
$this->world = $world;
|
||||
final public function position(Position $v) : void{
|
||||
$this->x = (int) $v->x;
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
$this->level = $v->level;
|
||||
$this->boundingBox = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of Item objects to be dropped
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getDrops(Item $item) : array{
|
||||
if($this->breakInfo->isToolCompatible($item)){
|
||||
if($this->isAffectedBySilkTouch() and $item->hasEnchantment(Enchantment::SILK_TOUCH())){
|
||||
if($this->isCompatibleWithTool($item)){
|
||||
if($this->isAffectedBySilkTouch() and $item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
||||
return $this->getSilkTouchDrops($item);
|
||||
}
|
||||
|
||||
@ -441,34 +377,30 @@ class Block extends Position{
|
||||
/**
|
||||
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [$this->asItem()];
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getVariant())
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getSilkTouchDrops(Item $item) : array{
|
||||
return [$this->asItem()];
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getVariant())
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how much XP will be dropped by breaking this block with the given item.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getXpDropForTool(Item $item) : int{
|
||||
if($item->hasEnchantment(Enchantment::SILK_TOUCH()) or !$this->breakInfo->isToolCompatible($item)){
|
||||
if($item->hasEnchantment(Enchantment::SILK_TOUCH) or !$this->isCompatibleWithTool($item)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -477,8 +409,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns how much XP this block will drop when broken with an appropriate tool.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getXpDropAmount() : int{
|
||||
return 0;
|
||||
@ -487,8 +417,6 @@ class Block extends Position{
|
||||
/**
|
||||
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
|
||||
* themselves anyway, this is implicitly true.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
@ -496,29 +424,13 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns the item that players will equip when middle-clicking on this block.
|
||||
*
|
||||
* @param bool $addUserData
|
||||
*
|
||||
* @return Item
|
||||
*/
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$item = $this->asItem();
|
||||
if($addUserData){
|
||||
$tile = $this->world->getTile($this);
|
||||
if($tile instanceof Tile){
|
||||
$nbt = $tile->getCleanedNBT();
|
||||
if($nbt instanceof CompoundTag){
|
||||
$item->setCustomBlockData($nbt);
|
||||
$item->setLore(["+(DATA)"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $item;
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get($this->getItemId(), $this->getVariant());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in ticks which the block will fuel a furnace for.
|
||||
* @return int
|
||||
*/
|
||||
public function getFuelTime() : int{
|
||||
return 0;
|
||||
@ -527,8 +439,6 @@ class Block extends Position{
|
||||
/**
|
||||
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
|
||||
* fire.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFlameEncouragement() : int{
|
||||
return 0;
|
||||
@ -536,8 +446,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFlammability() : int{
|
||||
return 0;
|
||||
@ -545,8 +453,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns whether fire lit on this block will burn indefinitely.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function burnsForever() : bool{
|
||||
return false;
|
||||
@ -554,8 +460,6 @@ class Block extends Position{
|
||||
|
||||
/**
|
||||
* Returns whether this block can catch fire.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFlammable() : bool{
|
||||
return $this->getFlammability() > 0;
|
||||
@ -571,17 +475,14 @@ class Block extends Position{
|
||||
/**
|
||||
* Returns the Block on the side $side, works like Vector3::getSide()
|
||||
*
|
||||
* @param int $side
|
||||
* @param int $step
|
||||
*
|
||||
* @return Block
|
||||
*/
|
||||
public function getSide(int $side, int $step = 1){
|
||||
if($this->isValid()){
|
||||
return $this->getWorld()->getBlock(Vector3::getSide($side, $step));
|
||||
return $this->getLevelNonNull()->getBlock(Vector3::getSide($side, $step));
|
||||
}
|
||||
|
||||
throw new \InvalidStateException("Block does not have a valid world");
|
||||
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -591,10 +492,10 @@ class Block extends Position{
|
||||
*/
|
||||
public function getHorizontalSides() : array{
|
||||
return [
|
||||
$this->getSide(Facing::NORTH),
|
||||
$this->getSide(Facing::SOUTH),
|
||||
$this->getSide(Facing::WEST),
|
||||
$this->getSide(Facing::EAST)
|
||||
$this->getSide(Vector3::SIDE_NORTH),
|
||||
$this->getSide(Vector3::SIDE_SOUTH),
|
||||
$this->getSide(Vector3::SIDE_WEST),
|
||||
$this->getSide(Vector3::SIDE_EAST)
|
||||
];
|
||||
}
|
||||
|
||||
@ -606,8 +507,8 @@ class Block extends Position{
|
||||
public function getAllSides() : array{
|
||||
return array_merge(
|
||||
[
|
||||
$this->getSide(Facing::DOWN),
|
||||
$this->getSide(Facing::UP)
|
||||
$this->getSide(Vector3::SIDE_DOWN),
|
||||
$this->getSide(Vector3::SIDE_UP)
|
||||
],
|
||||
$this->getHorizontalSides()
|
||||
);
|
||||
@ -627,15 +528,11 @@ class Block extends Position{
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(){
|
||||
return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getMeta() . ")";
|
||||
return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getDamage() . ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
*
|
||||
* @param AxisAlignedBB $bb
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||
foreach($this->getCollisionBoxes() as $bb2){
|
||||
@ -647,13 +544,7 @@ class Block extends Position{
|
||||
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.
|
||||
*
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function onEntityInside(Entity $entity) : void{
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
|
||||
}
|
||||
|
||||
@ -663,9 +554,6 @@ class Block extends Position{
|
||||
public function getCollisionBoxes() : array{
|
||||
if($this->collisionBoxes === null){
|
||||
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||
foreach($this->collisionBoxes as $bb){
|
||||
$bb->offset($this->x, $this->y, $this->z);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->collisionBoxes;
|
||||
@ -675,42 +563,43 @@ class Block extends Position{
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($bb = $this->recalculateBoundingBox()){
|
||||
if(($bb = $this->recalculateBoundingBox()) !== null){
|
||||
return [$bb];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB|null
|
||||
*/
|
||||
public function getBoundingBox() : ?AxisAlignedBB{
|
||||
if($this->boundingBox === null){
|
||||
$this->boundingBox = $this->recalculateBoundingBox();
|
||||
if($this->boundingBox !== null){
|
||||
$this->boundingBox->offset($this->x, $this->y, $this->z);
|
||||
}
|
||||
}
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB|null
|
||||
*/
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return AxisAlignedBB::one();
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Vector3 $pos1
|
||||
* @param Vector3 $pos2
|
||||
*
|
||||
* @return RayTraceResult|null
|
||||
* Clears any cached precomputed objects, such as bounding boxes. This is called on block neighbour update and when
|
||||
* the block is set into the world to remove any outdated precomputed things such as AABBs and force recalculation.
|
||||
*/
|
||||
public function clearCaches() : void{
|
||||
$this->boundingBox = null;
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(empty($bbs)){
|
||||
if(count($bbs) === 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -735,15 +624,31 @@ class Block extends Position{
|
||||
return $currentHit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self $self
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function cast(self $self){
|
||||
if(!($self instanceof static)){
|
||||
throw new \TypeError("Cannot cast from " . self::class . " to " . static::class);
|
||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||
if($this->isValid()){
|
||||
$this->level->getBlockMetadata()->setMetadata($this, $metadataKey, $newMetadataValue);
|
||||
}
|
||||
}
|
||||
|
||||
public function getMetadata(string $metadataKey){
|
||||
if($this->isValid()){
|
||||
return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function hasMetadata(string $metadataKey) : bool{
|
||||
if($this->isValid()){
|
||||
return $this->level->getBlockMetadata()->hasMetadata($this, $metadataKey);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function removeMetadata(string $metadataKey, Plugin $owningPlugin){
|
||||
if($this->isValid()){
|
||||
$this->level->getBlockMetadata()->removeMetadata($this, $metadataKey, $owningPlugin);
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
}
|
||||
|
@ -1,165 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use function get_class;
|
||||
|
||||
class BlockBreakInfo{
|
||||
|
||||
/** @var float */
|
||||
private $hardness;
|
||||
/** @var float */
|
||||
private $blastResistance;
|
||||
/** @var int */
|
||||
private $toolType;
|
||||
/** @var int */
|
||||
private $toolHarvestLevel;
|
||||
|
||||
/**
|
||||
* @param float $hardness
|
||||
* @param int $toolType
|
||||
* @param 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;
|
||||
$this->blastResistance = $blastResistance ?? $hardness * 5;
|
||||
}
|
||||
|
||||
public static function instant(int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0) : self{
|
||||
return new self(0.0, $toolType, $toolHarvestLevel, 0.0);
|
||||
}
|
||||
|
||||
public static function indestructible(float $blastResistance = 18000000.0) : self{
|
||||
return new self(-1.0, BlockToolType::NONE, 0, $blastResistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a base value used to compute block break times.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getHardness() : float{
|
||||
return $this->hardness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block can be broken at all.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isBreakable() : bool{
|
||||
return $this->hardness >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can be instantly broken.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function breaksInstantly() : bool{
|
||||
return $this->hardness == 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block's resistance to explosions. Usually 5x hardness.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getBlastResistance() : float{
|
||||
return $this->blastResistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getToolType() : int{
|
||||
return $this->toolType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level of tool required to harvest the block (for normal blocks). When the tool type matches the
|
||||
* block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
|
||||
* successfully harvest the block.
|
||||
*
|
||||
* If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
|
||||
* Otherwise, 1 should be returned if a tool is required, 0 if not.
|
||||
*
|
||||
* @see Item::getBlockToolHarvestLevel()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getToolHarvestLevel() : int{
|
||||
return $this->toolHarvestLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
|
||||
* harvest level requirement.
|
||||
*
|
||||
* In most cases this is also used to determine whether block drops should be created or not, except in some
|
||||
* special cases such as vines.
|
||||
*
|
||||
* @param Item $tool
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isToolCompatible(Item $tool) : bool{
|
||||
if($this->hardness < 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->toolType === BlockToolType::NONE or $this->toolHarvestLevel === 0 or (
|
||||
($this->toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seconds that this block takes to be broken using an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return float
|
||||
* @throws \InvalidArgumentException if the item efficiency is not a positive number
|
||||
*/
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$base = $this->hardness;
|
||||
if($this->isToolCompatible($item)){
|
||||
$base *= 1.5;
|
||||
}else{
|
||||
$base *= 5;
|
||||
}
|
||||
|
||||
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
|
||||
if($efficiency <= 0){
|
||||
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
|
||||
}
|
||||
|
||||
$base /= $efficiency;
|
||||
|
||||
return $base;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class BlockIdentifier{
|
||||
|
||||
/** @var int */
|
||||
private $blockId;
|
||||
/** @var int */
|
||||
private $variant;
|
||||
/** @var int|null */
|
||||
private $itemId;
|
||||
/** @var string|null */
|
||||
private $tileClass;
|
||||
|
||||
public function __construct(int $blockId, int $variant = 0, ?int $itemId = null, ?string $tileClass = null){
|
||||
$this->blockId = $blockId;
|
||||
$this->variant = $variant;
|
||||
$this->itemId = $itemId;
|
||||
$this->tileClass = $tileClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getBlockId() : int{
|
||||
return $this->blockId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getAllBlockIds() : array{
|
||||
return [$this->blockId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getVariant() : int{
|
||||
return $this->variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getItemId() : int{
|
||||
return $this->itemId ?? ($this->blockId > 255 ? 255 - $this->blockId : $this->blockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTileClass() : ?string{
|
||||
return $this->tileClass;
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
interface BlockLegacyIds{
|
||||
interface BlockIds{
|
||||
|
||||
public const AIR = 0;
|
||||
public const STONE = 1;
|
||||
@ -42,7 +42,7 @@ interface BlockLegacyIds{
|
||||
public const GOLD_ORE = 14;
|
||||
public const IRON_ORE = 15;
|
||||
public const COAL_ORE = 16;
|
||||
public const LOG = 17;
|
||||
public const LOG = 17, WOOD = 17;
|
||||
public const LEAVES = 18;
|
||||
public const SPONGE = 19;
|
||||
public const GLASS = 20;
|
||||
@ -61,7 +61,7 @@ interface BlockLegacyIds{
|
||||
public const PISTON = 33;
|
||||
public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
|
||||
public const WOOL = 35;
|
||||
public const ELEMENT_0 = 36;
|
||||
|
||||
public const DANDELION = 37, YELLOW_FLOWER = 37;
|
||||
public const POPPY = 38, RED_FLOWER = 38;
|
||||
public const BROWN_MUSHROOM = 39;
|
||||
@ -187,11 +187,11 @@ interface BlockLegacyIds{
|
||||
public const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
|
||||
public const STAINED_GLASS_PANE = 160;
|
||||
public const LEAVES2 = 161;
|
||||
public const LOG2 = 162;
|
||||
public const LOG2 = 162, WOOD2 = 162;
|
||||
public const ACACIA_STAIRS = 163;
|
||||
public const DARK_OAK_STAIRS = 164;
|
||||
public const SLIME = 165, SLIME_BLOCK = 165;
|
||||
public const GLOW_STICK = 166;
|
||||
|
||||
public const IRON_TRAPDOOR = 167;
|
||||
public const PRISMARINE = 168;
|
||||
public const SEALANTERN = 169, SEA_LANTERN = 169;
|
||||
@ -215,9 +215,7 @@ interface BlockLegacyIds{
|
||||
public const ACACIA_FENCE_GATE = 187;
|
||||
public const REPEATING_COMMAND_BLOCK = 188;
|
||||
public const CHAIN_COMMAND_BLOCK = 189;
|
||||
public const HARD_GLASS_PANE = 190;
|
||||
public const HARD_STAINED_GLASS_PANE = 191;
|
||||
public const CHEMICAL_HEAT = 192;
|
||||
|
||||
public const SPRUCE_DOOR_BLOCK = 193;
|
||||
public const BIRCH_DOOR_BLOCK = 194;
|
||||
public const JUNGLE_DOOR_BLOCK = 195;
|
||||
@ -227,9 +225,9 @@ interface BlockLegacyIds{
|
||||
public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
|
||||
public const CHORUS_FLOWER = 200;
|
||||
public const PURPUR_BLOCK = 201;
|
||||
public const COLORED_TORCH_RG = 202;
|
||||
|
||||
public const PURPUR_STAIRS = 203;
|
||||
public const COLORED_TORCH_BP = 204;
|
||||
|
||||
public const UNDYED_SHULKER_BOX = 205;
|
||||
public const END_BRICKS = 206;
|
||||
public const FROSTED_ICE = 207;
|
||||
@ -261,8 +259,7 @@ interface BlockLegacyIds{
|
||||
public const BLACK_GLAZED_TERRACOTTA = 235;
|
||||
public const CONCRETE = 236;
|
||||
public const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
|
||||
public const CHEMISTRY_TABLE = 238;
|
||||
public const UNDERWATER_TORCH = 239;
|
||||
|
||||
public const CHORUS_PLANT = 240;
|
||||
public const STAINED_GLASS = 241;
|
||||
|
||||
@ -276,222 +273,7 @@ interface BlockLegacyIds{
|
||||
public const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
||||
public const OBSERVER = 251;
|
||||
public const STRUCTURE_BLOCK = 252;
|
||||
public const HARD_GLASS = 253;
|
||||
public const HARD_STAINED_GLASS = 254;
|
||||
|
||||
public const RESERVED6 = 255;
|
||||
|
||||
public const PRISMARINE_STAIRS = 257;
|
||||
public const DARK_PRISMARINE_STAIRS = 258;
|
||||
public const PRISMARINE_BRICKS_STAIRS = 259;
|
||||
public const STRIPPED_SPRUCE_LOG = 260;
|
||||
public const STRIPPED_BIRCH_LOG = 261;
|
||||
public const STRIPPED_JUNGLE_LOG = 262;
|
||||
public const STRIPPED_ACACIA_LOG = 263;
|
||||
public const STRIPPED_DARK_OAK_LOG = 264;
|
||||
public const STRIPPED_OAK_LOG = 265;
|
||||
public const BLUE_ICE = 266;
|
||||
public const ELEMENT_1 = 267;
|
||||
public const ELEMENT_2 = 268;
|
||||
public const ELEMENT_3 = 269;
|
||||
public const ELEMENT_4 = 270;
|
||||
public const ELEMENT_5 = 271;
|
||||
public const ELEMENT_6 = 272;
|
||||
public const ELEMENT_7 = 273;
|
||||
public const ELEMENT_8 = 274;
|
||||
public const ELEMENT_9 = 275;
|
||||
public const ELEMENT_10 = 276;
|
||||
public const ELEMENT_11 = 277;
|
||||
public const ELEMENT_12 = 278;
|
||||
public const ELEMENT_13 = 279;
|
||||
public const ELEMENT_14 = 280;
|
||||
public const ELEMENT_15 = 281;
|
||||
public const ELEMENT_16 = 282;
|
||||
public const ELEMENT_17 = 283;
|
||||
public const ELEMENT_18 = 284;
|
||||
public const ELEMENT_19 = 285;
|
||||
public const ELEMENT_20 = 286;
|
||||
public const ELEMENT_21 = 287;
|
||||
public const ELEMENT_22 = 288;
|
||||
public const ELEMENT_23 = 289;
|
||||
public const ELEMENT_24 = 290;
|
||||
public const ELEMENT_25 = 291;
|
||||
public const ELEMENT_26 = 292;
|
||||
public const ELEMENT_27 = 293;
|
||||
public const ELEMENT_28 = 294;
|
||||
public const ELEMENT_29 = 295;
|
||||
public const ELEMENT_30 = 296;
|
||||
public const ELEMENT_31 = 297;
|
||||
public const ELEMENT_32 = 298;
|
||||
public const ELEMENT_33 = 299;
|
||||
public const ELEMENT_34 = 300;
|
||||
public const ELEMENT_35 = 301;
|
||||
public const ELEMENT_36 = 302;
|
||||
public const ELEMENT_37 = 303;
|
||||
public const ELEMENT_38 = 304;
|
||||
public const ELEMENT_39 = 305;
|
||||
public const ELEMENT_40 = 306;
|
||||
public const ELEMENT_41 = 307;
|
||||
public const ELEMENT_42 = 308;
|
||||
public const ELEMENT_43 = 309;
|
||||
public const ELEMENT_44 = 310;
|
||||
public const ELEMENT_45 = 311;
|
||||
public const ELEMENT_46 = 312;
|
||||
public const ELEMENT_47 = 313;
|
||||
public const ELEMENT_48 = 314;
|
||||
public const ELEMENT_49 = 315;
|
||||
public const ELEMENT_50 = 316;
|
||||
public const ELEMENT_51 = 317;
|
||||
public const ELEMENT_52 = 318;
|
||||
public const ELEMENT_53 = 319;
|
||||
public const ELEMENT_54 = 320;
|
||||
public const ELEMENT_55 = 321;
|
||||
public const ELEMENT_56 = 322;
|
||||
public const ELEMENT_57 = 323;
|
||||
public const ELEMENT_58 = 324;
|
||||
public const ELEMENT_59 = 325;
|
||||
public const ELEMENT_60 = 326;
|
||||
public const ELEMENT_61 = 327;
|
||||
public const ELEMENT_62 = 328;
|
||||
public const ELEMENT_63 = 329;
|
||||
public const ELEMENT_64 = 330;
|
||||
public const ELEMENT_65 = 331;
|
||||
public const ELEMENT_66 = 332;
|
||||
public const ELEMENT_67 = 333;
|
||||
public const ELEMENT_68 = 334;
|
||||
public const ELEMENT_69 = 335;
|
||||
public const ELEMENT_70 = 336;
|
||||
public const ELEMENT_71 = 337;
|
||||
public const ELEMENT_72 = 338;
|
||||
public const ELEMENT_73 = 339;
|
||||
public const ELEMENT_74 = 340;
|
||||
public const ELEMENT_75 = 341;
|
||||
public const ELEMENT_76 = 342;
|
||||
public const ELEMENT_77 = 343;
|
||||
public const ELEMENT_78 = 344;
|
||||
public const ELEMENT_79 = 345;
|
||||
public const ELEMENT_80 = 346;
|
||||
public const ELEMENT_81 = 347;
|
||||
public const ELEMENT_82 = 348;
|
||||
public const ELEMENT_83 = 349;
|
||||
public const ELEMENT_84 = 350;
|
||||
public const ELEMENT_85 = 351;
|
||||
public const ELEMENT_86 = 352;
|
||||
public const ELEMENT_87 = 353;
|
||||
public const ELEMENT_88 = 354;
|
||||
public const ELEMENT_89 = 355;
|
||||
public const ELEMENT_90 = 356;
|
||||
public const ELEMENT_91 = 357;
|
||||
public const ELEMENT_92 = 358;
|
||||
public const ELEMENT_93 = 359;
|
||||
public const ELEMENT_94 = 360;
|
||||
public const ELEMENT_95 = 361;
|
||||
public const ELEMENT_96 = 362;
|
||||
public const ELEMENT_97 = 363;
|
||||
public const ELEMENT_98 = 364;
|
||||
public const ELEMENT_99 = 365;
|
||||
public const ELEMENT_100 = 366;
|
||||
public const ELEMENT_101 = 367;
|
||||
public const ELEMENT_102 = 368;
|
||||
public const ELEMENT_103 = 369;
|
||||
public const ELEMENT_104 = 370;
|
||||
public const ELEMENT_105 = 371;
|
||||
public const ELEMENT_106 = 372;
|
||||
public const ELEMENT_107 = 373;
|
||||
public const ELEMENT_108 = 374;
|
||||
public const ELEMENT_109 = 375;
|
||||
public const ELEMENT_110 = 376;
|
||||
public const ELEMENT_111 = 377;
|
||||
public const ELEMENT_112 = 378;
|
||||
public const ELEMENT_113 = 379;
|
||||
public const ELEMENT_114 = 380;
|
||||
public const ELEMENT_115 = 381;
|
||||
public const ELEMENT_116 = 382;
|
||||
public const ELEMENT_117 = 383;
|
||||
public const ELEMENT_118 = 384;
|
||||
public const SEAGRASS = 385;
|
||||
public const CORAL = 386;
|
||||
public const CORAL_BLOCK = 387;
|
||||
public const CORAL_FAN = 388;
|
||||
public const CORAL_FAN_DEAD = 389;
|
||||
public const CORAL_FAN_HANG = 390;
|
||||
public const CORAL_FAN_HANG2 = 391;
|
||||
public const CORAL_FAN_HANG3 = 392;
|
||||
public const KELP = 393;
|
||||
public const DRIED_KELP_BLOCK = 394;
|
||||
public const ACACIA_BUTTON = 395;
|
||||
public const BIRCH_BUTTON = 396;
|
||||
public const DARK_OAK_BUTTON = 397;
|
||||
public const JUNGLE_BUTTON = 398;
|
||||
public const SPRUCE_BUTTON = 399;
|
||||
public const ACACIA_TRAPDOOR = 400;
|
||||
public const BIRCH_TRAPDOOR = 401;
|
||||
public const DARK_OAK_TRAPDOOR = 402;
|
||||
public const JUNGLE_TRAPDOOR = 403;
|
||||
public const SPRUCE_TRAPDOOR = 404;
|
||||
public const ACACIA_PRESSURE_PLATE = 405;
|
||||
public const BIRCH_PRESSURE_PLATE = 406;
|
||||
public const DARK_OAK_PRESSURE_PLATE = 407;
|
||||
public const JUNGLE_PRESSURE_PLATE = 408;
|
||||
public const SPRUCE_PRESSURE_PLATE = 409;
|
||||
public const CARVED_PUMPKIN = 410;
|
||||
public const SEA_PICKLE = 411;
|
||||
public const CONDUIT = 412;
|
||||
|
||||
public const TURTLE_EGG = 414;
|
||||
public const BUBBLE_COLUMN = 415;
|
||||
public const BARRIER = 416;
|
||||
public const STONE_SLAB3 = 417;
|
||||
public const BAMBOO = 418;
|
||||
public const BAMBOO_SAPLING = 419;
|
||||
public const SCAFFOLDING = 420;
|
||||
public const STONE_SLAB4 = 421;
|
||||
public const DOUBLE_STONE_SLAB3 = 422;
|
||||
public const DOUBLE_STONE_SLAB4 = 423;
|
||||
public const GRANITE_STAIRS = 424;
|
||||
public const DIORITE_STAIRS = 425;
|
||||
public const ANDESITE_STAIRS = 426;
|
||||
public const POLISHED_GRANITE_STAIRS = 427;
|
||||
public const POLISHED_DIORITE_STAIRS = 428;
|
||||
public const POLISHED_ANDESITE_STAIRS = 429;
|
||||
public const MOSSY_STONE_BRICK_STAIRS = 430;
|
||||
public const SMOOTH_RED_SANDSTONE_STAIRS = 431;
|
||||
public const SMOOTH_SANDSTONE_STAIRS = 432;
|
||||
public const END_BRICK_STAIRS = 433;
|
||||
public const MOSSY_COBBLESTONE_STAIRS = 434;
|
||||
public const NORMAL_STONE_STAIRS = 435;
|
||||
public const SPRUCE_STANDING_SIGN = 436;
|
||||
public const SPRUCE_WALL_SIGN = 437;
|
||||
public const SMOOTH_STONE = 438;
|
||||
public const RED_NETHER_BRICK_STAIRS = 439;
|
||||
public const SMOOTH_QUARTZ_STAIRS = 440;
|
||||
public const BIRCH_STANDING_SIGN = 441;
|
||||
public const BIRCH_WALL_SIGN = 442;
|
||||
public const JUNGLE_STANDING_SIGN = 443;
|
||||
public const JUNGLE_WALL_SIGN = 444;
|
||||
public const ACACIA_STANDING_SIGN = 445;
|
||||
public const ACACIA_WALL_SIGN = 446;
|
||||
public const DARKOAK_STANDING_SIGN = 447;
|
||||
public const DARKOAK_WALL_SIGN = 448;
|
||||
public const LECTERN = 449;
|
||||
public const GRINDSTONE = 450;
|
||||
public const BLAST_FURNACE = 451;
|
||||
public const STONECUTTER_BLOCK = 452;
|
||||
public const SMOKER = 453;
|
||||
public const LIT_SMOKER = 454;
|
||||
public const CARTOGRAPHY_TABLE = 455;
|
||||
public const FLETCHING_TABLE = 456;
|
||||
public const SMITHING_TABLE = 457;
|
||||
public const BARREL = 458;
|
||||
public const LOOM = 459;
|
||||
|
||||
public const BELL = 461;
|
||||
public const SWEET_BERRY_BUSH = 462;
|
||||
public const LANTERN = 463;
|
||||
public const CAMPFIRE = 464;
|
||||
public const LAVA_CAULDRON = 465;
|
||||
public const JIGSAW = 466;
|
||||
public const WOOD = 467;
|
||||
public const COMPOSTER = 468;
|
||||
public const LIT_BLAST_FURNACE = 469;
|
||||
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Constants for legacy metadata for various blocks.
|
||||
*/
|
||||
interface BlockLegacyMetadata{
|
||||
|
||||
public const ANVIL_NORMAL = 0;
|
||||
public const ANVIL_SLIGHTLY_DAMAGED = 4;
|
||||
public const ANVIL_VERY_DAMAGED = 8;
|
||||
|
||||
public const BED_FLAG_HEAD = 0x08;
|
||||
public const BED_FLAG_OCCUPIED = 0x04;
|
||||
|
||||
public const BEDROCK_FLAG_INFINIBURN = 0x01;
|
||||
|
||||
public const BREWING_STAND_FLAG_EAST = 0x01;
|
||||
public const BREWING_STAND_FLAG_SOUTHWEST = 0x02;
|
||||
public const BREWING_STAND_FLAG_NORTHWEST = 0x04;
|
||||
|
||||
public const BUTTON_FLAG_POWERED = 0x08;
|
||||
|
||||
public const COLORED_TORCH_BP_BLUE = 0;
|
||||
public const COLORED_TORCH_BP_PURPLE = 8;
|
||||
public const COLORED_TORCH_RG_RED = 0;
|
||||
public const COLORED_TORCH_RG_GREEN = 8;
|
||||
|
||||
public const DIRT_NORMAL = 0;
|
||||
public const DIRT_COARSE = 1;
|
||||
|
||||
public const DOOR_FLAG_TOP = 0x08;
|
||||
public const DOOR_BOTTOM_FLAG_OPEN = 0x04;
|
||||
public const DOOR_TOP_FLAG_RIGHT = 0x01;
|
||||
public const DOOR_TOP_FLAG_POWERED = 0x02;
|
||||
|
||||
public const DOUBLE_PLANT_SUNFLOWER = 0;
|
||||
public const DOUBLE_PLANT_LILAC = 1;
|
||||
public const DOUBLE_PLANT_TALLGRASS = 2;
|
||||
public const DOUBLE_PLANT_LARGE_FERN = 3;
|
||||
public const DOUBLE_PLANT_ROSE_BUSH = 4;
|
||||
public const DOUBLE_PLANT_PEONY = 5;
|
||||
|
||||
public const DOUBLE_PLANT_FLAG_TOP = 0x08;
|
||||
|
||||
public const END_PORTAL_FRAME_FLAG_EYE = 0x04;
|
||||
|
||||
public const FENCE_GATE_FLAG_OPEN = 0x04;
|
||||
public const FENCE_GATE_FLAG_IN_WALL = 0x08;
|
||||
|
||||
public const FLOWER_POPPY = 0;
|
||||
public const FLOWER_BLUE_ORCHID = 1;
|
||||
public const FLOWER_ALLIUM = 2;
|
||||
public const FLOWER_AZURE_BLUET = 3;
|
||||
public const FLOWER_RED_TULIP = 4;
|
||||
public const FLOWER_ORANGE_TULIP = 5;
|
||||
public const FLOWER_WHITE_TULIP = 6;
|
||||
public const FLOWER_PINK_TULIP = 7;
|
||||
public const FLOWER_OXEYE_DAISY = 8;
|
||||
public const FLOWER_CORNFLOWER = 9;
|
||||
public const FLOWER_LILY_OF_THE_VALLEY = 10;
|
||||
|
||||
public const FLOWER_POT_FLAG_OCCUPIED = 0x01;
|
||||
|
||||
public const HOPPER_FLAG_POWERED = 0x08;
|
||||
|
||||
public const INFESTED_STONE = 0;
|
||||
public const INFESTED_COBBLESTONE = 1;
|
||||
public const INFESTED_STONE_BRICK = 2;
|
||||
public const INFESTED_STONE_BRICK_MOSSY = 3;
|
||||
public const INFESTED_STONE_BRICK_CRACKED = 4;
|
||||
public const INFESTED_STONE_BRICK_CHISELED = 5;
|
||||
|
||||
public const ITEM_FRAME_FLAG_HAS_MAP = 0x04;
|
||||
|
||||
public const LANTERN_FLAG_HANGING = 0x01;
|
||||
|
||||
public const LEAVES_FLAG_NO_DECAY = 0x04;
|
||||
public const LEAVES_FLAG_CHECK_DECAY = 0x08;
|
||||
|
||||
public const LEVER_FLAG_POWERED = 0x08;
|
||||
|
||||
public const LIQUID_FLAG_FALLING = 0x08;
|
||||
|
||||
public const NETHER_PORTAL_AXIS_X = 1;
|
||||
public const NETHER_PORTAL_AXIS_Z = 2;
|
||||
|
||||
public const NETHER_REACTOR_INACTIVE = 0;
|
||||
public const NETHER_REACTOR_ACTIVE = 1;
|
||||
public const NETHER_REACTOR_USED = 2;
|
||||
|
||||
public const PRESSURE_PLATE_FLAG_POWERED = 0x01;
|
||||
|
||||
public const PRISMARINE_NORMAL = 0;
|
||||
public const PRISMARINE_DARK = 1;
|
||||
public const PRISMARINE_BRICKS = 2;
|
||||
|
||||
public const PURPUR_NORMAL = 0;
|
||||
public const PURPUR_PILLAR = 2;
|
||||
|
||||
public const QUARTZ_NORMAL = 0;
|
||||
public const QUARTZ_CHISELED = 1;
|
||||
public const QUARTZ_PILLAR = 2;
|
||||
public const QUARTZ_SMOOTH = 3;
|
||||
|
||||
public const RAIL_STRAIGHT_NORTH_SOUTH = 0;
|
||||
public const RAIL_STRAIGHT_EAST_WEST = 1;
|
||||
public const RAIL_ASCENDING_EAST = 2;
|
||||
public const RAIL_ASCENDING_WEST = 3;
|
||||
public const RAIL_ASCENDING_NORTH = 4;
|
||||
public const RAIL_ASCENDING_SOUTH = 5;
|
||||
public const RAIL_CURVE_SOUTHEAST = 6;
|
||||
public const RAIL_CURVE_SOUTHWEST = 7;
|
||||
public const RAIL_CURVE_NORTHWEST = 8;
|
||||
public const RAIL_CURVE_NORTHEAST = 9;
|
||||
|
||||
public const REDSTONE_COMPARATOR_FLAG_SUBTRACT = 0x04;
|
||||
public const REDSTONE_COMPARATOR_FLAG_POWERED = 0x08;
|
||||
|
||||
public const REDSTONE_RAIL_FLAG_POWERED = 0x08;
|
||||
|
||||
public const SANDSTONE_NORMAL = 0;
|
||||
public const SANDSTONE_CHISELED = 1;
|
||||
public const SANDSTONE_CUT = 2;
|
||||
public const SANDSTONE_SMOOTH = 3;
|
||||
|
||||
public const SAPLING_FLAG_READY = 0x08;
|
||||
|
||||
public const SEA_PICKLE_FLAG_NOT_UNDERWATER = 0x04;
|
||||
|
||||
public const SLAB_FLAG_UPPER = 0x08;
|
||||
|
||||
public const SPONGE_FLAG_WET = 0x01;
|
||||
|
||||
public const STAIR_FLAG_UPSIDE_DOWN = 0x04;
|
||||
|
||||
public const STONE_NORMAL = 0;
|
||||
public const STONE_GRANITE = 1;
|
||||
public const STONE_POLISHED_GRANITE = 2;
|
||||
public const STONE_DIORITE = 3;
|
||||
public const STONE_POLISHED_DIORITE = 4;
|
||||
public const STONE_ANDESITE = 5;
|
||||
public const STONE_POLISHED_ANDESITE = 6;
|
||||
|
||||
public const STONE_BRICK_NORMAL = 0;
|
||||
public const STONE_BRICK_MOSSY = 1;
|
||||
public const STONE_BRICK_CRACKED = 2;
|
||||
public const STONE_BRICK_CHISELED = 3;
|
||||
|
||||
public const STONE_SLAB_SMOOTH_STONE = 0;
|
||||
public const STONE_SLAB_SANDSTONE = 1;
|
||||
public const STONE_SLAB_FAKE_WOODEN = 2;
|
||||
public const STONE_SLAB_COBBLESTONE = 3;
|
||||
public const STONE_SLAB_BRICK = 4;
|
||||
public const STONE_SLAB_STONE_BRICK = 5;
|
||||
public const STONE_SLAB_QUARTZ = 6;
|
||||
public const STONE_SLAB_NETHER_BRICK = 7;
|
||||
public const STONE_SLAB2_RED_SANDSTONE = 0;
|
||||
public const STONE_SLAB2_PURPUR = 1;
|
||||
public const STONE_SLAB2_PRISMARINE = 2;
|
||||
public const STONE_SLAB2_DARK_PRISMARINE = 3;
|
||||
public const STONE_SLAB2_PRISMARINE_BRICKS = 4;
|
||||
public const STONE_SLAB2_MOSSY_COBBLESTONE = 5;
|
||||
public const STONE_SLAB2_SMOOTH_SANDSTONE = 6;
|
||||
public const STONE_SLAB2_RED_NETHER_BRICK = 7;
|
||||
public const STONE_SLAB3_END_STONE_BRICK = 0;
|
||||
public const STONE_SLAB3_SMOOTH_RED_SANDSTONE = 1;
|
||||
public const STONE_SLAB3_POLISHED_ANDESITE = 2;
|
||||
public const STONE_SLAB3_ANDESITE = 3;
|
||||
public const STONE_SLAB3_DIORITE = 4;
|
||||
public const STONE_SLAB3_POLISHED_DIORITE = 5;
|
||||
public const STONE_SLAB3_GRANITE = 6;
|
||||
public const STONE_SLAB3_POLISHED_GRANITE = 7;
|
||||
public const STONE_SLAB4_MOSSY_STONE_BRICK = 0;
|
||||
public const STONE_SLAB4_SMOOTH_QUARTZ = 1;
|
||||
public const STONE_SLAB4_STONE = 2;
|
||||
public const STONE_SLAB4_CUT_SANDSTONE = 3;
|
||||
public const STONE_SLAB4_CUT_RED_SANDSTONE = 4;
|
||||
|
||||
public const TALLGRASS_NORMAL = 1;
|
||||
public const TALLGRASS_FERN = 2;
|
||||
|
||||
public const TNT_NORMAL = 0;
|
||||
public const TNT_UNDERWATER = 2;
|
||||
|
||||
public const TNT_FLAG_UNSTABLE = 0x01;
|
||||
|
||||
public const TRAPDOOR_FLAG_UPPER = 0x04;
|
||||
public const TRAPDOOR_FLAG_OPEN = 0x08;
|
||||
|
||||
public const TRIPWIRE_FLAG_TRIGGERED = 0x01;
|
||||
public const TRIPWIRE_FLAG_SUSPENDED = 0x02;
|
||||
public const TRIPWIRE_FLAG_CONNECTED = 0x04;
|
||||
public const TRIPWIRE_FLAG_DISARMED = 0x08;
|
||||
|
||||
public const TRIPWIRE_HOOK_FLAG_CONNECTED = 0x04;
|
||||
public const TRIPWIRE_HOOK_FLAG_POWERED = 0x08;
|
||||
|
||||
public const VINE_FLAG_SOUTH = 0x01;
|
||||
public const VINE_FLAG_WEST = 0x02;
|
||||
public const VINE_FLAG_NORTH = 0x04;
|
||||
public const VINE_FLAG_EAST = 0x08;
|
||||
|
||||
public const WALL_COBBLESTONE = 0;
|
||||
public const WALL_MOSSY_COBBLESTONE = 1;
|
||||
public const WALL_GRANITE = 2;
|
||||
public const WALL_DIORITE = 3;
|
||||
public const WALL_ANDESITE = 4;
|
||||
public const WALL_SANDSTONE = 5;
|
||||
public const WALL_BRICK = 6;
|
||||
public const WALL_STONE_BRICK = 7;
|
||||
public const WALL_MOSSY_STONE_BRICK = 8;
|
||||
public const WALL_NETHER_BRICK = 9;
|
||||
public const WALL_END_STONE_BRICK = 10;
|
||||
public const WALL_PRISMARINE = 11;
|
||||
public const WALL_RED_SANDSTONE = 12;
|
||||
public const WALL_RED_NETHER_BRICK = 13;
|
||||
}
|
@ -29,11 +29,12 @@ namespace pocketmine\block;
|
||||
*/
|
||||
interface BlockToolType{
|
||||
|
||||
public const NONE = 0;
|
||||
public const SWORD = 1 << 0;
|
||||
public const SHOVEL = 1 << 1;
|
||||
public const PICKAXE = 1 << 2;
|
||||
public const AXE = 1 << 3;
|
||||
public const SHEARS = 1 << 4;
|
||||
public const TYPE_NONE = 0;
|
||||
public const TYPE_SWORD = 1 << 0;
|
||||
public const TYPE_SHOVEL = 1 << 1;
|
||||
public const TYPE_PICKAXE = 1 << 2;
|
||||
public const TYPE_AXE = 1 << 3;
|
||||
public const TYPE_SHEARS = 1 << 4;
|
||||
public const TYPE_HOE = 1 << 5;
|
||||
|
||||
}
|
||||
|
@ -23,13 +23,42 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationTrait;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\block\utils\PillarRotationHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\TieredTool;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class BoneBlock extends Opaque{
|
||||
use PillarRotationTrait;
|
||||
class BoneBlock extends Solid{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()));
|
||||
protected $id = Block::BONE_BLOCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Bone Block";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x03;
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,31 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\item\ItemFactory;
|
||||
|
||||
class Bookshelf extends Opaque{
|
||||
class Bookshelf extends Solid{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(1.5, BlockToolType::AXE));
|
||||
protected $id = self::BOOKSHELF;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Bookshelf";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_AXE;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::BOOK()->setCount(3)
|
||||
ItemFactory::get(Item::BOOK, 0, 3)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,53 +23,38 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\item\TieredTool;
|
||||
|
||||
class BrewingStand extends Transparent{
|
||||
|
||||
/** @var bool */
|
||||
protected $eastSlot = false;
|
||||
/** @var bool */
|
||||
protected $northwestSlot = false;
|
||||
/** @var bool */
|
||||
protected $southwestSlot = false;
|
||||
protected $id = self::BREWING_STAND_BLOCK;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()));
|
||||
protected $itemId = Item::BREWING_STAND;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return ($this->eastSlot ? BlockLegacyMetadata::BREWING_STAND_FLAG_EAST : 0) |
|
||||
($this->southwestSlot ? BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST : 0) |
|
||||
($this->northwestSlot ? BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST : 0);
|
||||
public function getName() : string{
|
||||
return "Brewing Stand";
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->eastSlot = ($stateMeta & BlockLegacyMetadata::BREWING_STAND_FLAG_EAST) !== 0;
|
||||
$this->southwestSlot = ($stateMeta & BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST) !== 0;
|
||||
$this->northwestSlot = ($stateMeta & BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST) !== 0;
|
||||
public function getHardness() : float{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b111;
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$stand = $this->getWorld()->getTile($this);
|
||||
if($stand instanceof TileBrewingStand and $stand->canOpenWith($item->getCustomName())){
|
||||
$player->setCurrentWindow($stand->getInventory());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
//TODO
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
55
src/pocketmine/block/BrickStairs.php
Normal file
55
src/pocketmine/block/BrickStairs.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\TieredTool;
|
||||
|
||||
class BrickStairs extends Stair{
|
||||
|
||||
protected $id = self::BRICK_STAIRS;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Brick Stairs";
|
||||
}
|
||||
}
|
55
src/pocketmine/block/Bricks.php
Normal file
55
src/pocketmine/block/Bricks.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\TieredTool;
|
||||
|
||||
class Bricks extends Solid{
|
||||
|
||||
protected $id = self::BRICK_BLOCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Bricks";
|
||||
}
|
||||
}
|
@ -25,6 +25,12 @@ namespace pocketmine\block;
|
||||
|
||||
class BrownMushroom extends RedMushroom{
|
||||
|
||||
protected $id = self::BROWN_MUSHROOM;
|
||||
|
||||
public function getName() : string{
|
||||
return "Brown Mushroom";
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 1;
|
||||
}
|
||||
|
@ -28,9 +28,15 @@ use function mt_rand;
|
||||
|
||||
class BrownMushroomBlock extends RedMushroomBlock{
|
||||
|
||||
protected $id = Block::BROWN_MUSHROOM_BLOCK;
|
||||
|
||||
public function getName() : string{
|
||||
return "Brown Mushroom Block";
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaBlocks::BROWN_MUSHROOM()->asItem()->setCount(mt_rand(0, 2))
|
||||
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
}
|
||||
|
101
src/pocketmine/block/BurningFurnace.php
Normal file
101
src/pocketmine/block/BurningFurnace.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\TieredTool;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Furnace as TileFurnace;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class BurningFurnace extends Solid{
|
||||
|
||||
protected $id = self::BURNING_FURNACE;
|
||||
|
||||
protected $itemId = self::FURNACE;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Burning Furnace";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 3.5;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return BlockToolType::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getToolHarvestLevel() : int{
|
||||
return TieredTool::TIER_WOODEN;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 13;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$faces = [
|
||||
0 => 4,
|
||||
1 => 2,
|
||||
2 => 5,
|
||||
3 => 3
|
||||
];
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->getLevelNonNull()->getTile($this);
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this));
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$furnace->canOpenWith($item->getCustomName())){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->addWindow($furnace->getInventory());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -23,60 +23,29 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\RedstonePowerOffSound;
|
||||
use pocketmine\world\sound\RedstonePowerOnSound;
|
||||
use pocketmine\Player;
|
||||
|
||||
abstract class Button extends Flowable{
|
||||
|
||||
/** @var int */
|
||||
protected $facing = Facing::DOWN;
|
||||
/** @var bool */
|
||||
protected $powered = false;
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return BlockDataSerializer::writeFacing($this->facing) | ($this->powered ? BlockLegacyMetadata::BUTTON_FLAG_POWERED : 0);
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
//TODO: in PC it's (6 - facing) for every meta except 0 (down)
|
||||
$this->facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
|
||||
$this->powered = ($stateMeta & BlockLegacyMetadata::BUTTON_FLAG_POWERED) !== 0;
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function place(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);
|
||||
$this->meta = $face;
|
||||
|
||||
return $this->level->setBlock($this, $this, true, true);
|
||||
}
|
||||
|
||||
abstract protected function getActivationTime() : int;
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->powered){
|
||||
$this->powered = true;
|
||||
$this->world->setBlock($this, $this);
|
||||
$this->world->scheduleDelayedBlockUpdate($this, $this->getActivationTime());
|
||||
$this->world->addSound($this->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
//TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if($this->powered){
|
||||
$this->powered = false;
|
||||
$this->world->setBlock($this, $this);
|
||||
$this->world->addSound($this->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,62 +23,61 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Cactus extends Transparent{
|
||||
|
||||
/** @var int */
|
||||
protected $age = 0;
|
||||
protected $id = self::CACTUS;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.4));
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->age;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, 15);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
public function getHardness() : float{
|
||||
return 0.4;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
static $shrinkSize = 1 / 16;
|
||||
return AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize);
|
||||
public function getName() : string{
|
||||
return "Cactus";
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : void{
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y + 0.0625,
|
||||
$this->z + 0.0625,
|
||||
$this->x + 0.9375,
|
||||
$this->y + 0.9375,
|
||||
$this->z + 0.9375
|
||||
);
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
$entity->attack($ev);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if($down->getId() !== BlockLegacyIds::SAND and !$down->isSameType($this)){
|
||||
$this->getWorld()->useBreakOn($this);
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}else{
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->isSolid()){
|
||||
$this->getWorld()->useBreakOn($this);
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -90,42 +89,48 @@ class Cactus extends Transparent{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
|
||||
if($this->age === 15){
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||
if($this->meta === 0x0f){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getWorld()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === BlockLegacyIds::AIR){
|
||||
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
|
||||
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
break;
|
||||
}
|
||||
$this->getWorld()->setBlock($b, $ev->getNewState());
|
||||
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->age = 0;
|
||||
$this->getWorld()->setBlock($this, $this);
|
||||
$this->meta = 0;
|
||||
$this->getLevelNonNull()->setBlock($this, $this);
|
||||
}else{
|
||||
++$this->age;
|
||||
$this->getWorld()->setBlock($this, $this);
|
||||
++$this->meta;
|
||||
$this->getLevelNonNull()->setBlock($this, $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)){
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
if($this->getSide($side)->isSolid()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::SAND or $down->getId() === self::CACTUS){
|
||||
$block0 = $this->getSide(Vector3::SIDE_NORTH);
|
||||
$block1 = $this->getSide(Vector3::SIDE_SOUTH);
|
||||
$block2 = $this->getSide(Vector3::SIDE_WEST);
|
||||
$block3 = $this->getSide(Vector3::SIDE_EAST);
|
||||
if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){
|
||||
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -23,57 +23,60 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\entity\effect\EffectInstance;
|
||||
use pocketmine\entity\EffectInstance;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\item\FoodSource;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Cake extends Transparent implements FoodSource{
|
||||
|
||||
/** @var int */
|
||||
protected $bites = 0;
|
||||
protected $id = self::CAKE_BLOCK;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.5));
|
||||
protected $itemId = Item::CAKE;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->bites;
|
||||
public function getHardness() : float{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->bites = BlockDataSerializer::readBoundedInt("bites", $stateMeta, 0, 6);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b111;
|
||||
public function getName() : string{
|
||||
return "Cake";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return AxisAlignedBB::one()
|
||||
->contract(1 / 16, 0, 1 / 16)
|
||||
->trim(Facing::UP, 0.5)
|
||||
->trim(Facing::WEST, $this->bites / 8);
|
||||
|
||||
$f = $this->getDamage() * 0.125; //1 slice width
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625 + $f,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
$this->x + 1 - 0.0625,
|
||||
$this->y + 0.5,
|
||||
$this->z + 1 - 0.0625
|
||||
);
|
||||
}
|
||||
|
||||
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::AIR){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){ //Replace with common break method
|
||||
$this->getWorld()->setBlock($this, VanillaBlocks::AIR());
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
||||
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +88,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$player->consumeObject($this);
|
||||
return true;
|
||||
@ -106,14 +109,18 @@ class Cake extends Transparent implements FoodSource{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getResidue(){
|
||||
$clone = clone $this;
|
||||
$clone->bites++;
|
||||
if($clone->bites > 6){
|
||||
$clone = VanillaBlocks::AIR();
|
||||
$clone->meta++;
|
||||
if($clone->meta > 0x06){
|
||||
$clone = BlockFactory::get(Block::AIR);
|
||||
}
|
||||
return $clone;
|
||||
}
|
||||
@ -126,6 +133,6 @@ class Cake extends Transparent implements FoodSource{
|
||||
}
|
||||
|
||||
public function onConsume(Living $consumer) : void{
|
||||
$this->world->setBlock($this, $this->getResidue());
|
||||
$this->level->setBlock($this, $this->getResidue());
|
||||
}
|
||||
}
|
||||
|
@ -23,39 +23,58 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\ColorBlockMetaHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Carpet extends Flowable{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
||||
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.1));
|
||||
protected $id = self::CARPET;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0.1;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return AxisAlignedBB::one()->trim(Facing::UP, 15 / 16);
|
||||
public function getName() : string{
|
||||
return ColorBlockMetaHelper::getColorFromMeta($this->getVariant()) . " Carpet";
|
||||
}
|
||||
|
||||
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::AIR){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 0.0625,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){
|
||||
$this->getWorld()->useBreakOn($this);
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||
$this->getLevelNonNull()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,18 +24,28 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use function mt_rand;
|
||||
|
||||
class Carrot extends Crops{
|
||||
|
||||
protected $id = self::CARROT_BLOCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Carrot Block";
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::CARROT()->setCount($this->age >= 7 ? mt_rand(1, 4) : 1)
|
||||
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
return VanillaItems::CARROT();
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::CARROT);
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockDataSerializer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
class CarvedPumpkin extends Opaque{
|
||||
|
||||
/** @var int */
|
||||
protected $facing = Facing::NORTH;
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
|
||||
}
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing);
|
||||
}
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b11;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user