mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
973 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
6b4d8b91c6 | |||
8f5eb7ef37 | |||
23b00bea5b | |||
0ea9a08963 | |||
18a1bfe4dd | |||
2d3562c687 | |||
cde2c10c1d | |||
87fb42cabd | |||
cb40484a2e | |||
6566dd8c8f | |||
1e65ac0d85 | |||
e75a08a5a3 | |||
cb247a5f28 | |||
bb048fb361 | |||
95dfff727e | |||
d55889d85f | |||
99f65f19ac | |||
581eeee01d | |||
17341d7406 | |||
04c0cd142d | |||
9e993aa83f | |||
fab12707ae | |||
51f299f196 | |||
2bb52cf811 | |||
6afc689529 | |||
5a17a0d1aa | |||
b38c81c96f | |||
0fabc0c199 | |||
ec5598dbb1 | |||
7b98d203f4 | |||
4635b93f4d | |||
a8433697ad | |||
680cdb8e3e | |||
eaa78fe849 | |||
eedea4998b | |||
4e5a80c481 | |||
4d54dc30c1 | |||
ac5339414a | |||
9fd922fe6a | |||
fdaf9dce73 | |||
732e27751c | |||
932c489de1 |
2
.github/ISSUE_TEMPLATE/help---support.md
vendored
2
.github/ISSUE_TEMPLATE/help---support.md
vendored
@ -11,4 +11,4 @@ We don't accept support requests on the issue tracker. Please try the following
|
|||||||
|
|
||||||
Documentation: http://pmmp.rtfd.io
|
Documentation: http://pmmp.rtfd.io
|
||||||
Forums: https://forums.pmmp.io
|
Forums: https://forums.pmmp.io
|
||||||
Discord: https://discord.gg/bge7dYQ
|
Discord: https://discord.gg/bmSAZBG
|
||||||
|
4
.github/support.yml
vendored
4
.github/support.yml
vendored
@ -5,10 +5,10 @@ supportLabel: "Support request"
|
|||||||
# Comment to post on issues marked as support requests. Add a link
|
# Comment to post on issues marked as support requests. Add a link
|
||||||
# to a support page, or set to `false` to disable
|
# to a support page, or set to `false` to disable
|
||||||
supportComment: >
|
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).
|
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/bge7dYQ) | [Forums](https://forums.pmmp.io)
|
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||||
|
|
||||||
# Whether to close issues marked as support requests
|
# Whether to close issues marked as support requests
|
||||||
close: true
|
close: true
|
||||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -13,6 +13,7 @@ server.properties
|
|||||||
memory_dumps/*
|
memory_dumps/*
|
||||||
resource_packs/
|
resource_packs/
|
||||||
server.lock
|
server.lock
|
||||||
|
/phpstan.neon
|
||||||
|
|
||||||
# Common IDEs
|
# Common IDEs
|
||||||
.idea/
|
.idea/
|
||||||
@ -40,3 +41,9 @@ test_data/*
|
|||||||
|
|
||||||
# Doxygen
|
# Doxygen
|
||||||
Documentation/*
|
Documentation/*
|
||||||
|
|
||||||
|
# PHPUnit
|
||||||
|
/.phpunit.result.cache
|
||||||
|
|
||||||
|
# php-cs-fixer
|
||||||
|
/.php_cs.cache
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,6 +7,9 @@
|
|||||||
[submodule "tests/plugins/PocketMine-DevTools"]
|
[submodule "tests/plugins/PocketMine-DevTools"]
|
||||||
path = tests/plugins/PocketMine-DevTools
|
path = tests/plugins/PocketMine-DevTools
|
||||||
url = https://github.com/pmmp/PocketMine-DevTools.git
|
url = https://github.com/pmmp/PocketMine-DevTools.git
|
||||||
|
[submodule "build/php"]
|
||||||
|
path = build/php
|
||||||
|
url = https://github.com/pmmp/php-build-scripts.git
|
||||||
[submodule "src/pocketmine/resources/vanilla"]
|
[submodule "src/pocketmine/resources/vanilla"]
|
||||||
path = src/pocketmine/resources/vanilla
|
path = src/pocketmine/resources/vanilla
|
||||||
url = https://github.com/pmmp/BedrockData.git
|
url = https://github.com/pmmp/BedrockData.git
|
||||||
|
17
.travis.yml
17
.travis.yml
@ -1,25 +1,32 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 7.2
|
|
||||||
- 7.3
|
- 7.3
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
- phpenv config-rm xdebug.ini
|
||||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.4
|
- echo | pecl install channel://pecl.php.net/yaml-2.1.0
|
||||||
- git clone https://github.com/pmmp/pthreads.git
|
- git clone https://github.com/pmmp/pthreads.git
|
||||||
- cd pthreads
|
- cd pthreads
|
||||||
- git checkout 6ca019c58b4fa09ee2ff490f2444e34bef0773d0
|
- git checkout 646dac62ae0d48c1ada7b007e15575fb84f7d71d
|
||||||
- phpize
|
- phpize
|
||||||
- ./configure
|
- ./configure
|
||||||
- make
|
- make
|
||||||
- make install
|
- make install
|
||||||
- cd ..
|
- cd ..
|
||||||
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||||
- composer install
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||||
|
- ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||||
|
- composer install --no-dev --prefer-dist
|
||||||
- ./tests/travis.sh -t4
|
- ./tests/travis.sh -t4
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.composer/cache/files
|
||||||
|
- $HOME/.composer/cache/vcs
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
38
BUILDING.md
Normal file
38
BUILDING.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# 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.3-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 `build/server-phar.php` 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.
|
||||||
|
|
||||||
|
## Running PocketMine-MP from source code
|
||||||
|
Run `src/pocketmine/PocketMine.php` using your preferred PHP binary.
|
15
README.md
15
README.md
@ -3,27 +3,30 @@
|
|||||||
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
|
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://travis-ci.org/pmmp/PocketMine-MP)
|
[](https://travis-ci.com/pmmp/PocketMine-MP)
|
||||||
|
|
||||||
### Getting started
|
## Getting started
|
||||||
- [Documentation](http://pmmp.readthedocs.org/)
|
- [Documentation](http://pmmp.readthedocs.org/)
|
||||||
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
|
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
|
||||||
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
|
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
|
||||||
- [Plugin repository](https://poggit.pmmp.io/plugins)
|
- [Plugin repository](https://poggit.pmmp.io/plugins)
|
||||||
|
|
||||||
### Discussion
|
## Discussion/Help
|
||||||
- [Forums](https://forums.pmmp.io/)
|
- [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)
|
||||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
* [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/PocketMine-DevTools/) - Development tools plugin for creating plugins
|
||||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||||
|
|
||||||
### Donate
|
## Donate
|
||||||
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
|
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear`
|
||||||
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
|
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
|
||||||
|
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
|
||||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||||
|
|
||||||
## Licensing information
|
## Licensing information
|
||||||
|
@ -21,14 +21,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\build_script;
|
namespace pocketmine\build\make_release;
|
||||||
|
|
||||||
use pocketmine\utils\VersionString;
|
use pocketmine\utils\VersionString;
|
||||||
use function dirname;
|
use function dirname;
|
||||||
use function fgets;
|
use function fgets;
|
||||||
use function file_get_contents;
|
use function file_get_contents;
|
||||||
use function file_put_contents;
|
use function file_put_contents;
|
||||||
use function preg_quote;
|
|
||||||
use function preg_replace;
|
use function preg_replace;
|
||||||
use function sleep;
|
use function sleep;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
@ -36,20 +35,8 @@ use function system;
|
|||||||
use const pocketmine\BASE_VERSION;
|
use const pocketmine\BASE_VERSION;
|
||||||
use const STDIN;
|
use const STDIN;
|
||||||
|
|
||||||
require_once dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
|
|
||||||
require_once dirname(__DIR__) . '/vendor/autoload.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{
|
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev) : void{
|
||||||
$versionInfo = file_get_contents($versionInfoPath);
|
$versionInfo = file_get_contents($versionInfoPath);
|
||||||
@ -60,22 +47,45 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev
|
|||||||
);
|
);
|
||||||
$versionInfo = preg_replace(
|
$versionInfo = preg_replace(
|
||||||
'/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
|
'/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
|
||||||
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false'). ';',
|
'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';',
|
||||||
$versionInfo
|
$versionInfo
|
||||||
);
|
);
|
||||||
file_put_contents($versionInfoPath, $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);
|
* @param string[] $argv
|
||||||
system('git add "' . dirname(__DIR__) . '/changelogs"');
|
* @phpstan-param list<string> $argv
|
||||||
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
|
*/
|
||||||
system('git tag ' . $currentVer->getBaseVersion());
|
function main(array $argv) : void{
|
||||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);
|
if(isset($argv[1])){
|
||||||
system('git add "' . $versionInfoPath . '"');
|
$currentVer = new VersionString($argv[1]);
|
||||||
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
|
}else{
|
||||||
echo "pushing changes in 10 seconds\n";
|
$currentVer = new VersionString(BASE_VERSION);
|
||||||
sleep(10);
|
}
|
||||||
system('git push origin HEAD ' . $currentVer->getBaseVersion());
|
$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());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
|
||||||
|
main($argv);
|
||||||
|
}
|
||||||
|
1
build/php
Submodule
1
build/php
Submodule
Submodule build/php added at cec63c3093
Submodule build/preprocessor updated: b01f50c50e...da363df5f1
174
build/server-phar.php
Normal file
174
build/server-phar.php
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?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 defined;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
|
||||||
|
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.
|
17
changelogs/3.14.md
Normal file
17
changelogs/3.14.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
**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
|
@ -52,3 +52,78 @@ Plugin developers should **only** update their required API to this version if y
|
|||||||
- Fixed `Item->setCustomName()` with an empty string leaving behind an empty tag.
|
- Fixed `Item->setCustomName()` with an empty string leaving behind an empty tag.
|
||||||
- Fixed incorrect positioning of bucket empty sound.
|
- Fixed incorrect positioning of bucket empty sound.
|
||||||
- Fixed some incorrect tag parsing in `/give` involving quoted numbers.
|
- Fixed some incorrect tag parsing in `/give` involving quoted numbers.
|
||||||
|
|
||||||
|
# 3.9.3
|
||||||
|
- 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.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"homepage": "https://pmmp.io",
|
"homepage": "https://pmmp.io",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2.0",
|
"php": ">=7.3.0",
|
||||||
"php-64bit": "*",
|
"php-64bit": "*",
|
||||||
"ext-bcmath": "*",
|
"ext-bcmath": "*",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
@ -24,49 +24,38 @@
|
|||||||
"ext-yaml": ">=2.0.0",
|
"ext-yaml": ">=2.0.0",
|
||||||
"ext-zip": "*",
|
"ext-zip": "*",
|
||||||
"ext-zlib": ">=1.2.11",
|
"ext-zlib": ">=1.2.11",
|
||||||
"pocketmine/raklib": "^0.12.5",
|
"pocketmine/raklib": "^0.12.7",
|
||||||
"pocketmine/spl": "^0.3.0",
|
"pocketmine/spl": "^0.4.0",
|
||||||
"pocketmine/binaryutils": "^0.1.9",
|
"pocketmine/binaryutils": "^0.1.9",
|
||||||
"pocketmine/nbt": "^0.2.10",
|
"pocketmine/nbt": "^0.2.10",
|
||||||
"pocketmine/math": "^0.2.0",
|
"pocketmine/math": "^0.2.0",
|
||||||
"pocketmine/snooze": "^0.1.0",
|
"pocketmine/snooze": "^0.1.0",
|
||||||
"daverandom/callback-validator": "dev-master",
|
"pocketmine/classloader": "^0.1.0",
|
||||||
"adhocore/json-comment": "^0.0.7"
|
"pocketmine/log": "^0.2.0",
|
||||||
|
"pocketmine/log-pthreads": "^0.1.0",
|
||||||
|
"pocketmine/callback-validator": "^1.0.1",
|
||||||
|
"adhocore/json-comment": "^0.1.0",
|
||||||
|
"ocramius/package-versions": "^1.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "0.12.29",
|
||||||
|
"phpstan/phpstan-phpunit": "^0.12.6",
|
||||||
|
"phpstan/phpstan-strict-rules": "^0.12.2",
|
||||||
|
"phpunit/phpunit": "^9.2"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"": ["src"]
|
"": ["src"]
|
||||||
}
|
},
|
||||||
|
"files": [
|
||||||
|
"src/pocketmine/CoreConstants.php",
|
||||||
|
"src/pocketmine/GlobalConstants.php",
|
||||||
|
"src/pocketmine/VersionInfo.php"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"pocketmine\\": "tests/phpunit/"
|
"pocketmine\\": "tests/phpunit/"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "vcs",
|
|
||||||
"url": "https://github.com/pmmp/RakLib"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
2284
composer.lock
generated
2284
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1565,7 +1565,7 @@ MATHJAX_FORMAT = HTML-CSS
|
|||||||
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
|
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
|
||||||
|
|
||||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||||
# extension names that should be enabled during MathJax rendering. For example
|
# extension names that should be enabled during MathJax rendering. For example
|
||||||
|
41
phpstan.neon.dist
Normal file
41
phpstan.neon.dist
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
includes:
|
||||||
|
- tests/phpstan/configs/actual-problems.neon
|
||||||
|
- tests/phpstan/configs/check-explicit-mixed-baseline.neon
|
||||||
|
- tests/phpstan/configs/com-dotnet-magic.neon
|
||||||
|
- tests/phpstan/configs/custom-leveldb.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
|
||||||
|
bootstrapFiles:
|
||||||
|
- tests/phpstan/bootstrap.php
|
||||||
|
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
|
||||||
|
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$#"
|
@ -30,9 +30,7 @@ use pocketmine\utils\TextFormat;
|
|||||||
* Handles the achievement list and a bit more
|
* Handles the achievement list and a bit more
|
||||||
*/
|
*/
|
||||||
abstract class Achievement{
|
abstract class Achievement{
|
||||||
/**
|
/** @var array[] */
|
||||||
* @var array[]
|
|
||||||
*/
|
|
||||||
public static $list = [
|
public static $list = [
|
||||||
/*"openInventory" => array(
|
/*"openInventory" => array(
|
||||||
"name" => "Taking Inventory",
|
"name" => "Taking Inventory",
|
||||||
@ -106,13 +104,6 @@ abstract class Achievement{
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Player $player
|
|
||||||
* @param string $achievementId
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function broadcast(Player $player, string $achievementId) : bool{
|
public static function broadcast(Player $player, string $achievementId) : bool{
|
||||||
if(isset(Achievement::$list[$achievementId])){
|
if(isset(Achievement::$list[$achievementId])){
|
||||||
$translation = new TranslationContainer("chat.type.achievement", [$player->getDisplayName(), TextFormat::GREEN . Achievement::$list[$achievementId]["name"] . TextFormat::RESET]);
|
$translation = new TranslationContainer("chat.type.achievement", [$player->getDisplayName(), TextFormat::GREEN . Achievement::$list[$achievementId]["name"] . TextFormat::RESET]);
|
||||||
@ -129,11 +120,7 @@ abstract class Achievement{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $achievementId
|
* @param string[] $requires
|
||||||
* @param string $achievementName
|
|
||||||
* @param array $requires
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public static function add(string $achievementId, string $achievementName, array $requires = []) : bool{
|
public static function add(string $achievementId, string $achievementName, array $requires = []) : bool{
|
||||||
if(!isset(Achievement::$list[$achievementId])){
|
if(!isset(Achievement::$list[$achievementId])){
|
||||||
|
@ -25,12 +25,16 @@ namespace pocketmine;
|
|||||||
|
|
||||||
abstract class Collectable extends \Threaded{
|
abstract class Collectable extends \Threaded{
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
private $isGarbage = false;
|
private $isGarbage = false;
|
||||||
|
|
||||||
public function isGarbage() : bool{
|
public function isGarbage() : bool{
|
||||||
return $this->isGarbage;
|
return $this->isGarbage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setGarbage(){
|
public function setGarbage(){
|
||||||
$this->isGarbage = true;
|
$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,13 +23,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
|
use PackageVersions\Versions;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\plugin\PluginBase;
|
use pocketmine\plugin\PluginBase;
|
||||||
use pocketmine\plugin\PluginLoadOrder;
|
use pocketmine\plugin\PluginLoadOrder;
|
||||||
use pocketmine\plugin\PluginManager;
|
use pocketmine\plugin\PluginManager;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
use pocketmine\utils\VersionString;
|
use pocketmine\utils\VersionString;
|
||||||
use raklib\RakLib;
|
|
||||||
use function base64_encode;
|
use function base64_encode;
|
||||||
use function date;
|
use function date;
|
||||||
use function error_get_last;
|
use function error_get_last;
|
||||||
@ -88,7 +88,7 @@ class CrashDump{
|
|||||||
* having their content changed, version format changing, etc.
|
* having their content changed, version format changing, etc.
|
||||||
* It is not necessary to increase this when adding new fields.
|
* It is not necessary to increase this when adding new fields.
|
||||||
*/
|
*/
|
||||||
private const FORMAT_VERSION = 2;
|
private const FORMAT_VERSION = 3;
|
||||||
|
|
||||||
private const PLUGIN_INVOLVEMENT_NONE = "none";
|
private const PLUGIN_INVOLVEMENT_NONE = "none";
|
||||||
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
|
private const PLUGIN_INVOLVEMENT_DIRECT = "direct";
|
||||||
@ -96,8 +96,14 @@ class CrashDump{
|
|||||||
|
|
||||||
/** @var Server */
|
/** @var Server */
|
||||||
private $server;
|
private $server;
|
||||||
|
/** @var resource */
|
||||||
private $fp;
|
private $fp;
|
||||||
|
/** @var int */
|
||||||
private $time;
|
private $time;
|
||||||
|
/**
|
||||||
|
* @var mixed[]
|
||||||
|
* @phpstan-var array<string, mixed>
|
||||||
|
*/
|
||||||
private $data = [];
|
private $data = [];
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $encodedData = "";
|
private $encodedData = "";
|
||||||
@ -111,10 +117,11 @@ class CrashDump{
|
|||||||
mkdir($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->path = $this->server->getDataPath() . "crashdumps/" . date("D_M_j-H.i.s-T_Y", $this->time) . ".log";
|
||||||
$this->fp = @fopen($this->path, "wb");
|
$fp = @fopen($this->path, "wb");
|
||||||
if(!is_resource($this->fp)){
|
if(!is_resource($fp)){
|
||||||
throw new \RuntimeException("Could not create Crash Dump");
|
throw new \RuntimeException("Could not create Crash Dump");
|
||||||
}
|
}
|
||||||
|
$this->fp = $fp;
|
||||||
$this->data["format_version"] = self::FORMAT_VERSION;
|
$this->data["format_version"] = self::FORMAT_VERSION;
|
||||||
$this->data["time"] = $this->time;
|
$this->data["time"] = $this->time;
|
||||||
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time));
|
$this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", $this->time));
|
||||||
@ -134,15 +141,22 @@ class CrashDump{
|
|||||||
return $this->path;
|
return $this->path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getEncodedData(){
|
public function getEncodedData(){
|
||||||
return $this->encodedData;
|
return $this->encodedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
* @phpstan-return array<string, mixed>
|
||||||
|
*/
|
||||||
public function getData() : array{
|
public function getData() : array{
|
||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function encodeData(){
|
private function encodeData() : void{
|
||||||
$this->addLine();
|
$this->addLine();
|
||||||
$this->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------");
|
$this->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------");
|
||||||
$this->addLine();
|
$this->addLine();
|
||||||
@ -158,7 +172,7 @@ class CrashDump{
|
|||||||
$this->addLine("===END CRASH DUMP===");
|
$this->addLine("===END CRASH DUMP===");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function pluginsData(){
|
private function pluginsData() : void{
|
||||||
if($this->server->getPluginManager() instanceof PluginManager){
|
if($this->server->getPluginManager() instanceof PluginManager){
|
||||||
$this->addLine();
|
$this->addLine();
|
||||||
$this->addLine("Loaded plugins:");
|
$this->addLine("Loaded plugins:");
|
||||||
@ -182,7 +196,7 @@ class CrashDump{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function extraData(){
|
private function extraData() : void{
|
||||||
global $argv;
|
global $argv;
|
||||||
|
|
||||||
if($this->server->getProperty("auto-report.send-settings", true) !== false){
|
if($this->server->getProperty("auto-report.send-settings", true) !== false){
|
||||||
@ -209,13 +223,16 @@ class CrashDump{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function baseCrash(){
|
private function baseCrash() : void{
|
||||||
global $lastExceptionError, $lastError;
|
global $lastExceptionError, $lastError;
|
||||||
|
|
||||||
if(isset($lastExceptionError)){
|
if(isset($lastExceptionError)){
|
||||||
$error = $lastExceptionError;
|
$error = $lastExceptionError;
|
||||||
}else{
|
}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
|
$error["trace"] = Utils::currentTrace(3); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
|
||||||
$errorConversion = [
|
$errorConversion = [
|
||||||
E_ERROR => "E_ERROR",
|
E_ERROR => "E_ERROR",
|
||||||
@ -275,9 +292,11 @@ class CrashDump{
|
|||||||
|
|
||||||
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
|
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
|
||||||
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
||||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
if($file !== false){
|
||||||
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||||
$this->data["code"][$l + 1] = $file[$l];
|
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||||
|
$this->data["code"][$l + 1] = $file[$l];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +310,7 @@ class CrashDump{
|
|||||||
|
|
||||||
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
|
private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{
|
||||||
$frameCleanPath = Utils::cleanPath($filePath); //this will be empty in phar stub
|
$frameCleanPath = Utils::cleanPath($filePath); //this will be empty in phar stub
|
||||||
if($frameCleanPath !== "" and strpos($frameCleanPath, "src/pocketmine/") === false and strpos($frameCleanPath, "vendor/pocketmine/") === false and file_exists($filePath)){
|
if(strpos($frameCleanPath, "plugins") === 0 and file_exists($filePath)){
|
||||||
$this->addLine();
|
$this->addLine();
|
||||||
if($crashFrame){
|
if($crashFrame){
|
||||||
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
||||||
@ -317,7 +336,7 @@ class CrashDump{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generalData(){
|
private function generalData() : void{
|
||||||
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
||||||
$this->data["general"] = [];
|
$this->data["general"] = [];
|
||||||
$this->data["general"]["name"] = $this->server->getName();
|
$this->data["general"]["name"] = $this->server->getName();
|
||||||
@ -326,24 +345,38 @@ class CrashDump{
|
|||||||
$this->data["general"]["is_dev"] = \pocketmine\IS_DEVELOPMENT_BUILD;
|
$this->data["general"]["is_dev"] = \pocketmine\IS_DEVELOPMENT_BUILD;
|
||||||
$this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL;
|
$this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL;
|
||||||
$this->data["general"]["git"] = \pocketmine\GIT_COMMIT;
|
$this->data["general"]["git"] = \pocketmine\GIT_COMMIT;
|
||||||
$this->data["general"]["raklib"] = RakLib::VERSION;
|
|
||||||
$this->data["general"]["uname"] = php_uname("a");
|
$this->data["general"]["uname"] = php_uname("a");
|
||||||
$this->data["general"]["php"] = phpversion();
|
$this->data["general"]["php"] = phpversion();
|
||||||
$this->data["general"]["zend"] = zend_version();
|
$this->data["general"]["zend"] = zend_version();
|
||||||
$this->data["general"]["php_os"] = PHP_OS;
|
$this->data["general"]["php_os"] = PHP_OS;
|
||||||
$this->data["general"]["os"] = Utils::getOS();
|
$this->data["general"]["os"] = Utils::getOS();
|
||||||
|
$this->data["general"]["composer_libraries"] = Versions::VERSIONS;
|
||||||
$this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]");
|
$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("uname -a: " . php_uname("a"));
|
||||||
$this->addLine("PHP Version: " . phpversion());
|
$this->addLine("PHP Version: " . phpversion());
|
||||||
$this->addLine("Zend version: " . zend_version());
|
$this->addLine("Zend version: " . zend_version());
|
||||||
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
|
$this->addLine("OS : " . PHP_OS . ", " . Utils::getOS());
|
||||||
|
$this->addLine("Composer libraries: ");
|
||||||
|
foreach(Versions::VERSIONS as $library => $libraryVersion){
|
||||||
|
$this->addLine("- $library $libraryVersion");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $line
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function addLine($line = ""){
|
public function addLine($line = ""){
|
||||||
fwrite($this->fp, $line . PHP_EOL);
|
fwrite($this->fp, $line . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $str
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function add($str){
|
public function add($str){
|
||||||
fwrite($this->fp, $str);
|
fwrite($this->fp, $str);
|
||||||
}
|
}
|
||||||
|
32
src/pocketmine/GlobalConstants.php
Normal file
32
src/pocketmine/GlobalConstants.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?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);
|
||||||
|
|
||||||
|
// 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;
|
@ -27,33 +27,21 @@ use pocketmine\permission\ServerOperator;
|
|||||||
|
|
||||||
interface IPlayer extends ServerOperator{
|
interface IPlayer extends ServerOperator{
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isOnline() : bool;
|
public function isOnline() : bool;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName() : string;
|
public function getName() : string;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isBanned() : bool;
|
public function isBanned() : bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $banned
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setBanned(bool $banned);
|
public function setBanned(bool $banned);
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isWhitelisted() : bool;
|
public function isWhitelisted() : bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $value
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setWhitelisted(bool $value);
|
public function setWhitelisted(bool $value);
|
||||||
|
|
||||||
@ -72,9 +60,6 @@ interface IPlayer extends ServerOperator{
|
|||||||
*/
|
*/
|
||||||
public function getLastPlayed();
|
public function getLastPlayed();
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasPlayedBefore() : bool;
|
public function hasPlayedBefore() : bool;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ use pocketmine\event\server\LowMemoryEvent;
|
|||||||
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||||
use pocketmine\scheduler\GarbageCollectionTask;
|
use pocketmine\scheduler\GarbageCollectionTask;
|
||||||
use pocketmine\timings\Timings;
|
use pocketmine\timings\Timings;
|
||||||
|
use pocketmine\utils\AssumptionFailedError;
|
||||||
|
use pocketmine\utils\Process;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
use function arsort;
|
use function arsort;
|
||||||
use function count;
|
use function count;
|
||||||
@ -48,6 +50,7 @@ use function is_object;
|
|||||||
use function is_resource;
|
use function is_resource;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
|
use function mb_strtoupper;
|
||||||
use function min;
|
use function min;
|
||||||
use function mkdir;
|
use function mkdir;
|
||||||
use function preg_match;
|
use function preg_match;
|
||||||
@ -56,7 +59,6 @@ use function round;
|
|||||||
use function spl_object_hash;
|
use function spl_object_hash;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
use function strtoupper;
|
|
||||||
use function substr;
|
use function substr;
|
||||||
use const JSON_PRETTY_PRINT;
|
use const JSON_PRETTY_PRINT;
|
||||||
use const JSON_UNESCAPED_SLASHES;
|
use const JSON_UNESCAPED_SLASHES;
|
||||||
@ -115,7 +117,7 @@ class MemoryManager{
|
|||||||
$this->init();
|
$this->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function init(){
|
private function init() : void{
|
||||||
$this->memoryLimit = ((int) $this->server->getProperty("memory.main-limit", 0)) * 1024 * 1024;
|
$this->memoryLimit = ((int) $this->server->getProperty("memory.main-limit", 0)) * 1024 * 1024;
|
||||||
|
|
||||||
$defaultMemory = 1024;
|
$defaultMemory = 1024;
|
||||||
@ -125,7 +127,7 @@ class MemoryManager{
|
|||||||
if($m <= 0){
|
if($m <= 0){
|
||||||
$defaultMemory = 0;
|
$defaultMemory = 0;
|
||||||
}else{
|
}else{
|
||||||
switch(strtoupper($matches[2])){
|
switch(mb_strtoupper($matches[2])){
|
||||||
case "K":
|
case "K":
|
||||||
$defaultMemory = $m / 1024;
|
$defaultMemory = $m / 1024;
|
||||||
break;
|
break;
|
||||||
@ -169,38 +171,25 @@ class MemoryManager{
|
|||||||
gc_enable();
|
gc_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isLowMemory() : bool{
|
public function isLowMemory() : bool{
|
||||||
return $this->lowMemory;
|
return $this->lowMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canUseChunkCache() : bool{
|
public function canUseChunkCache() : bool{
|
||||||
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the allowed chunk radius based on the current memory usage.
|
* Returns the allowed chunk radius based on the current memory usage.
|
||||||
*
|
|
||||||
* @param int $distance
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getViewDistance(int $distance) : 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.
|
* Triggers garbage collection and cache cleanup to try and free memory.
|
||||||
*
|
*
|
||||||
* @param int $memory
|
* @return void
|
||||||
* @param int $limit
|
|
||||||
* @param bool $global
|
|
||||||
* @param int $triggerCount
|
|
||||||
*/
|
*/
|
||||||
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
|
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",
|
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
||||||
@ -230,13 +219,15 @@ class MemoryManager{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called every tick to update the memory manager state.
|
* Called every tick to update the memory manager state.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function check(){
|
public function check(){
|
||||||
Timings::$memoryManagerTimer->startTiming();
|
Timings::$memoryManagerTimer->startTiming();
|
||||||
|
|
||||||
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
|
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
|
||||||
$this->checkTicker = 0;
|
$this->checkTicker = 0;
|
||||||
$memory = Utils::getMemoryUsage(true);
|
$memory = Process::getAdvancedMemoryUsage();
|
||||||
$trigger = false;
|
$trigger = false;
|
||||||
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
|
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
|
||||||
$trigger = 0;
|
$trigger = 0;
|
||||||
@ -268,9 +259,6 @@ class MemoryManager{
|
|||||||
Timings::$memoryManagerTimer->stopTiming();
|
Timings::$memoryManagerTimer->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function triggerGarbageCollector() : int{
|
public function triggerGarbageCollector() : int{
|
||||||
Timings::$garbageCollectorTimer->startTiming();
|
Timings::$garbageCollectorTimer->startTiming();
|
||||||
|
|
||||||
@ -294,9 +282,7 @@ class MemoryManager{
|
|||||||
/**
|
/**
|
||||||
* Dumps the server memory into the specified output folder.
|
* Dumps the server memory into the specified output folder.
|
||||||
*
|
*
|
||||||
* @param string $outputFolder
|
* @return void
|
||||||
* @param int $maxNesting
|
|
||||||
* @param int $maxStringSize
|
|
||||||
*/
|
*/
|
||||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||||
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||||
@ -314,15 +300,13 @@ class MemoryManager{
|
|||||||
* Static memory dumper accessible from any thread.
|
* Static memory dumper accessible from any thread.
|
||||||
*
|
*
|
||||||
* @param mixed $startingObject
|
* @param mixed $startingObject
|
||||||
* @param string $outputFolder
|
|
||||||
* @param int $maxNesting
|
|
||||||
* @param int $maxStringSize
|
|
||||||
* @param \Logger $logger
|
|
||||||
*
|
*
|
||||||
|
* @return void
|
||||||
* @throws \ReflectionException
|
* @throws \ReflectionException
|
||||||
*/
|
*/
|
||||||
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
|
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger){
|
||||||
$hardLimit = ini_get('memory_limit');
|
$hardLimit = ini_get('memory_limit');
|
||||||
|
if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist");
|
||||||
ini_set('memory_limit', '-1');
|
ini_set('memory_limit', '-1');
|
||||||
gc_disable();
|
gc_disable();
|
||||||
|
|
||||||
@ -356,7 +340,7 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$staticCount++;
|
$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){
|
if(count($staticProperties[$className]) === 0){
|
||||||
@ -389,14 +373,14 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$globalCount++;
|
$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));
|
file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
$logger->info("[Dump] 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{
|
do{
|
||||||
$continue = false;
|
$continue = false;
|
||||||
@ -422,8 +406,8 @@ class MemoryManager{
|
|||||||
"properties" => []
|
"properties" => []
|
||||||
];
|
];
|
||||||
|
|
||||||
if($reflection->getParentClass()){
|
if(($parent = $reflection->getParentClass()) !== false){
|
||||||
$info["parent"] = $reflection->getParentClass()->getName();
|
$info["parent"] = $parent->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($reflection->getInterfaceNames()) > 0){
|
if(count($reflection->getInterfaceNames()) > 0){
|
||||||
@ -444,14 +428,13 @@ class MemoryManager{
|
|||||||
$property->setAccessible(true);
|
$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");
|
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}while($continue);
|
}while($continue);
|
||||||
|
|
||||||
$logger->info("[Dump] Wrote " . count($objects) . " objects");
|
$logger->info("[Dump] Wrote " . count($objects) . " objects");
|
||||||
@ -472,17 +455,14 @@ class MemoryManager{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $from
|
* @param mixed $from
|
||||||
* @param mixed &$data
|
* @param object[] $objects reference parameter
|
||||||
* @param object[] &$objects
|
* @param int[] $refCounts reference parameter
|
||||||
* @param int[] &$refCounts
|
*
|
||||||
* @param int $recursion
|
* @return mixed
|
||||||
* @param int $maxNesting
|
|
||||||
* @param int $maxStringSize
|
|
||||||
*/
|
*/
|
||||||
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||||
if($maxNesting <= 0){
|
if($maxNesting <= 0){
|
||||||
$data = "(error) NESTING LIMIT REACHED";
|
return "(error) NESTING LIMIT REACHED";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--$maxNesting;
|
--$maxNesting;
|
||||||
@ -498,12 +478,11 @@ class MemoryManager{
|
|||||||
$data = "(object) $hash@" . get_class($from);
|
$data = "(object) $hash@" . get_class($from);
|
||||||
}elseif(is_array($from)){
|
}elseif(is_array($from)){
|
||||||
if($recursion >= 5){
|
if($recursion >= 5){
|
||||||
$data = "(error) ARRAY RECURSION LIMIT REACHED";
|
return "(error) ARRAY RECURSION LIMIT REACHED";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
$data = [];
|
$data = [];
|
||||||
foreach($from as $key => $value){
|
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)){
|
}elseif(is_string($from)){
|
||||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||||
@ -512,5 +491,7 @@ class MemoryManager{
|
|||||||
}else{
|
}else{
|
||||||
$data = $from;
|
$data = $from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,6 @@ class OfflinePlayer implements IPlayer, Metadatable{
|
|||||||
/** @var CompoundTag|null */
|
/** @var CompoundTag|null */
|
||||||
private $namedtag = null;
|
private $namedtag = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Server $server
|
|
||||||
* @param string $name
|
|
||||||
*/
|
|
||||||
public function __construct(Server $server, string $name){
|
public function __construct(Server $server, string $name){
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
@ -57,6 +53,9 @@ class OfflinePlayer implements IPlayer, Metadatable{
|
|||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Server
|
||||||
|
*/
|
||||||
public function getServer(){
|
public function getServer(){
|
||||||
return $this->server;
|
return $this->server;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -21,14 +21,11 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace {
|
|
||||||
const INT32_MIN = -0x80000000;
|
|
||||||
const INT32_MAX = 0x7fffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace pocketmine {
|
namespace pocketmine {
|
||||||
|
|
||||||
|
use pocketmine\utils\Git;
|
||||||
use pocketmine\utils\MainLogger;
|
use pocketmine\utils\MainLogger;
|
||||||
|
use pocketmine\utils\Process;
|
||||||
use pocketmine\utils\ServerKiller;
|
use pocketmine\utils\ServerKiller;
|
||||||
use pocketmine\utils\Terminal;
|
use pocketmine\utils\Terminal;
|
||||||
use pocketmine\utils\Timezone;
|
use pocketmine\utils\Timezone;
|
||||||
@ -38,8 +35,12 @@ namespace pocketmine {
|
|||||||
|
|
||||||
require_once __DIR__ . '/VersionInfo.php';
|
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){
|
function critical_error($message){
|
||||||
echo "[ERROR] $message" . PHP_EOL;
|
echo "[ERROR] $message" . PHP_EOL;
|
||||||
}
|
}
|
||||||
@ -57,18 +58,18 @@ namespace pocketmine {
|
|||||||
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
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.
|
//If PHP version isn't high enough, anything below might break, so don't bother checking it.
|
||||||
return [
|
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 = [];
|
$messages = [];
|
||||||
|
|
||||||
if(PHP_INT_SIZE < 8){
|
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"){
|
if(php_sapi_name() !== "cli"){
|
||||||
$messages[] = "You must run " . \pocketmine\NAME . " using the CLI.";
|
$messages[] = "Only PHP CLI is supported.";
|
||||||
}
|
}
|
||||||
|
|
||||||
$extensions = [
|
$extensions = [
|
||||||
@ -121,176 +122,185 @@ namespace pocketmine {
|
|||||||
return $messages;
|
return $messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($messages = check_platform_dependencies())){
|
/**
|
||||||
echo PHP_EOL;
|
* @param \Logger $logger
|
||||||
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
|
* @return void
|
||||||
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
|
|
||||||
foreach($messages as $m){
|
|
||||||
echo " - $m" . PHP_EOL;
|
|
||||||
}
|
|
||||||
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
|
|
||||||
echo PHP_EOL;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
unset($messages);
|
|
||||||
|
|
||||||
error_reporting(-1);
|
|
||||||
|
|
||||||
if(\Phar::running(true) !== ""){
|
|
||||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
|
||||||
}else{
|
|
||||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
$opts = getopt("", ["bootstrap:"]);
|
|
||||||
if(isset($opts["bootstrap"])){
|
|
||||||
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
|
|
||||||
}else{
|
|
||||||
$bootstrap = \pocketmine\PATH . '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);
|
|
||||||
}else{
|
|
||||||
critical_error("Composer autoloader not found at " . $bootstrap);
|
|
||||||
critical_error("Please install/update Composer dependencies or use provided builds.");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_error_handler([Utils::class, 'errorExceptionHandler']);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
|
||||||
*/
|
*/
|
||||||
$autoloader = new \BaseClassLoader();
|
function emit_performance_warnings(\Logger $logger){
|
||||||
$autoloader->register(false);
|
if(extension_loaded("xdebug")){
|
||||||
|
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
|
||||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
}
|
||||||
|
if(!extension_loaded("pocketmine_chunkutils")){
|
||||||
ini_set("allow_url_fopen", '1');
|
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
|
||||||
ini_set("display_errors", '1');
|
}
|
||||||
ini_set("display_startup_errors", '1');
|
if(((int) ini_get('zend.assertions')) !== -1){
|
||||||
ini_set("default_charset", "utf-8");
|
$logger->warning("Debugging assertions are enabled. This may degrade performance. To disable them, set `zend.assertions = -1` in php.ini.");
|
||||||
|
}
|
||||||
ini_set("memory_limit", '-1');
|
if(\Phar::running(true) === ""){
|
||||||
|
$logger->warning("Non-packaged installation detected. This will degrade autoloading speed and make startup times longer.");
|
||||||
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
|
}
|
||||||
|
|
||||||
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
|
|
||||||
|
|
||||||
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
|
||||||
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
|
||||||
|
|
||||||
if(!file_exists(\pocketmine\DATA)){
|
|
||||||
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"));
|
* @return void
|
||||||
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
|
function set_ini_entries(){
|
||||||
//other server wrote its PID and released exclusive lock before we get our lock
|
ini_set("allow_url_fopen", '1');
|
||||||
flock(\pocketmine\LOCK_FILE, LOCK_SH);
|
ini_set("display_errors", '1');
|
||||||
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
|
ini_set("display_startup_errors", '1');
|
||||||
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
|
ini_set("default_charset", "utf-8");
|
||||||
critical_error("Please stop the other server first before running a new one.");
|
ini_set('assert.exception', '1');
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ftruncate(\pocketmine\LOCK_FILE, 0);
|
|
||||||
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
|
|
||||||
fflush(\pocketmine\LOCK_FILE);
|
|
||||||
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
|
|
||||||
|
|
||||||
//Logger has a dependency on timezone
|
|
||||||
$tzError = Timezone::init();
|
|
||||||
|
|
||||||
if(isset($opts["enable-ansi"])){
|
|
||||||
Terminal::init(true);
|
|
||||||
}elseif(isset($opts["disable-ansi"])){
|
|
||||||
Terminal::init(false);
|
|
||||||
}else{
|
|
||||||
Terminal::init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
/**
|
||||||
$logger->registerStatic();
|
* @return void
|
||||||
|
*/
|
||||||
foreach($tzError as $e){
|
function server(){
|
||||||
$logger->warning($e);
|
if(count($messages = check_platform_dependencies()) > 0){
|
||||||
}
|
echo PHP_EOL;
|
||||||
unset($tzError);
|
$binary = version_compare(PHP_VERSION, "5.4") >= 0 ? PHP_BINARY : "unknown";
|
||||||
|
critical_error("Selected PHP binary ($binary) does not satisfy some requirements.");
|
||||||
if(extension_loaded("xdebug")){
|
foreach($messages as $m){
|
||||||
$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);
|
echo " - $m" . PHP_EOL;
|
||||||
}
|
|
||||||
if(!extension_loaded("pocketmine_chunkutils")){
|
|
||||||
$logger->warning("ChunkUtils extension is missing. Anvil-format worlds will experience degraded performance.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){
|
|
||||||
$gitHash = trim($out);
|
|
||||||
if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified
|
|
||||||
$gitHash .= "-dirty";
|
|
||||||
}
|
}
|
||||||
|
critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html.");
|
||||||
|
echo PHP_EOL;
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}else{
|
unset($messages);
|
||||||
$phar = new \Phar(\Phar::running(false));
|
|
||||||
$meta = $phar->getMetadata();
|
error_reporting(-1);
|
||||||
if(isset($meta["git"])){
|
set_ini_entries();
|
||||||
$gitHash = $meta["git"];
|
|
||||||
|
$opts = getopt("", ["bootstrap:"]);
|
||||||
|
if(isset($opts["bootstrap"])){
|
||||||
|
$bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"];
|
||||||
|
}else{
|
||||||
|
$bootstrap = dirname(__FILE__, 3) . '/vendor/autoload.php';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
define('pocketmine\GIT_COMMIT', $gitHash);
|
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);
|
||||||
|
|
||||||
|
set_error_handler([Utils::class, 'errorExceptionHandler']);
|
||||||
|
|
||||||
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
|
$version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER);
|
||||||
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
|
define('pocketmine\VERSION', $version->getFullVersion(true));
|
||||||
|
|
||||||
$exitCode = 0;
|
$gitHash = str_repeat("00", 20);
|
||||||
do{
|
|
||||||
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
|
if(\Phar::running(true) === ""){
|
||||||
$installer = new SetupWizard();
|
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
|
||||||
if(!$installer->run()){
|
}else{
|
||||||
$exitCode = -1;
|
$phar = new \Phar(\Phar::running(false));
|
||||||
break;
|
$meta = $phar->getMetadata();
|
||||||
|
if(isset($meta["git"])){
|
||||||
|
$gitHash = $meta["git"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move this to a Server field
|
define('pocketmine\GIT_COMMIT', $gitHash);
|
||||||
define('pocketmine\START_TIME', microtime(true));
|
|
||||||
ThreadManager::init();
|
|
||||||
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
|
|
||||||
|
|
||||||
$logger->info("Stopping other threads");
|
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]);
|
||||||
|
|
||||||
$killer = new ServerKiller(8);
|
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
||||||
$killer->start(PTHREADS_INHERIT_NONE);
|
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
||||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
|
||||||
|
|
||||||
if(ThreadManager::getInstance()->stopAll() > 0){
|
if(!file_exists(\pocketmine\DATA)){
|
||||||
if(\pocketmine\DEBUG > 1){
|
mkdir(\pocketmine\DATA, 0777, true);
|
||||||
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
|
||||||
}
|
|
||||||
Utils::kill(getmypid());
|
|
||||||
}
|
}
|
||||||
}while(false);
|
|
||||||
|
|
||||||
$logger->shutdown();
|
define('pocketmine\LOCK_FILE', fopen(\pocketmine\DATA . 'server.lock', "a+b"));
|
||||||
$logger->join();
|
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
|
||||||
|
flock(\pocketmine\LOCK_FILE, LOCK_SH);
|
||||||
|
$pid = stream_get_contents(\pocketmine\LOCK_FILE);
|
||||||
|
critical_error("Another " . \pocketmine\NAME . " instance (PID $pid) is already using this folder (" . realpath(\pocketmine\DATA) . ").");
|
||||||
|
critical_error("Please stop the other server first before running a new one.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ftruncate(\pocketmine\LOCK_FILE, 0);
|
||||||
|
fwrite(\pocketmine\LOCK_FILE, (string) getmypid());
|
||||||
|
fflush(\pocketmine\LOCK_FILE);
|
||||||
|
flock(\pocketmine\LOCK_FILE, LOCK_SH); //prevent acquiring an exclusive lock from another process, but allow reading
|
||||||
|
|
||||||
echo Terminal::$FORMAT_RESET . PHP_EOL;
|
//Logger has a dependency on timezone
|
||||||
|
$tzError = Timezone::init();
|
||||||
|
|
||||||
exit($exitCode);
|
if(isset($opts["enable-ansi"])){
|
||||||
|
Terminal::init(true);
|
||||||
|
}elseif(isset($opts["disable-ansi"])){
|
||||||
|
Terminal::init(false);
|
||||||
|
}else{
|
||||||
|
Terminal::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||||
|
$logger->registerStatic();
|
||||||
|
|
||||||
|
foreach($tzError as $e){
|
||||||
|
$logger->warning($e);
|
||||||
|
}
|
||||||
|
unset($tzError);
|
||||||
|
|
||||||
|
emit_performance_warnings($logger);
|
||||||
|
|
||||||
|
$exitCode = 0;
|
||||||
|
do{
|
||||||
|
if(!file_exists(\pocketmine\DATA . "server.properties") and !isset($opts["no-wizard"])){
|
||||||
|
$installer = new SetupWizard();
|
||||||
|
if(!$installer->run()){
|
||||||
|
$exitCode = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: move this to a Server field
|
||||||
|
define('pocketmine\START_TIME', microtime(true));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
|
||||||
|
$killer = new ServerKiller(8);
|
||||||
|
$killer->start(PTHREADS_INHERIT_NONE);
|
||||||
|
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||||
|
|
||||||
|
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||||
|
$logger->debug("Some threads could not be stopped, performing a force-kill");
|
||||||
|
Process::kill(getmypid());
|
||||||
|
}
|
||||||
|
}while(false);
|
||||||
|
|
||||||
|
$logger->shutdown();
|
||||||
|
$logger->join();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!defined('pocketmine\_PHPSTAN_ANALYSIS')){
|
||||||
|
\pocketmine\server();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
|
use const PTHREADS_INHERIT_ALL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class must be extended by all custom threading classes
|
* This class must be extended by all custom threading classes
|
||||||
*/
|
*/
|
||||||
@ -33,12 +35,19 @@ abstract class Thread extends \Thread{
|
|||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
protected $composerAutoloaderPath;
|
protected $composerAutoloaderPath;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
protected $isKilled = false;
|
protected $isKilled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \ClassLoader|null
|
||||||
|
*/
|
||||||
public function getClassLoader(){
|
public function getClassLoader(){
|
||||||
return $this->classLoader;
|
return $this->classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setClassLoader(\ClassLoader $loader = null){
|
public function setClassLoader(\ClassLoader $loader = null){
|
||||||
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||||
|
|
||||||
@ -54,6 +63,8 @@ abstract class Thread extends \Thread{
|
|||||||
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
|
* 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
|
* 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).
|
* (unless you are using a custom autoloader).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
if($this->composerAutoloaderPath !== null){
|
if($this->composerAutoloaderPath !== null){
|
||||||
@ -64,7 +75,10 @@ abstract class Thread extends \Thread{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if($this->getClassLoader() === null){
|
if($this->getClassLoader() === null){
|
||||||
@ -75,6 +89,8 @@ abstract class Thread extends \Thread{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function quit(){
|
public function quit(){
|
||||||
$this->isKilled = true;
|
$this->isKilled = true;
|
||||||
|
@ -28,9 +28,13 @@ use function spl_object_hash;
|
|||||||
|
|
||||||
class ThreadManager extends \Volatile{
|
class ThreadManager extends \Volatile{
|
||||||
|
|
||||||
/** @var ThreadManager */
|
/** @var ThreadManager|null */
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function init(){
|
public static function init(){
|
||||||
self::$instance = new ThreadManager();
|
self::$instance = new ThreadManager();
|
||||||
}
|
}
|
||||||
@ -39,24 +43,31 @@ class ThreadManager extends \Volatile{
|
|||||||
* @return ThreadManager
|
* @return ThreadManager
|
||||||
*/
|
*/
|
||||||
public static function getInstance(){
|
public static function getInstance(){
|
||||||
|
if(self::$instance === null){
|
||||||
|
self::$instance = new ThreadManager();
|
||||||
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Worker|Thread $thread
|
* @param Worker|Thread $thread
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function add($thread){
|
public function add($thread){
|
||||||
if($thread instanceof Thread or $thread instanceof Worker){
|
if($thread instanceof Thread or $thread instanceof Worker){
|
||||||
$this->{spl_object_hash($thread)} = $thread;
|
$this[spl_object_hash($thread)] = $thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Worker|Thread $thread
|
* @param Worker|Thread $thread
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function remove($thread){
|
public function remove($thread){
|
||||||
if($thread instanceof Thread or $thread instanceof Worker){
|
if($thread instanceof Thread or $thread instanceof Worker){
|
||||||
unset($this->{spl_object_hash($thread)});
|
unset($this[spl_object_hash($thread)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine;
|
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 NAME = "PocketMine-MP";
|
||||||
const BASE_VERSION = "3.9.2";
|
const BASE_VERSION = "3.14.0";
|
||||||
const IS_DEVELOPMENT_BUILD = false;
|
const IS_DEVELOPMENT_BUILD = false;
|
||||||
const BUILD_NUMBER = 0;
|
const BUILD_NUMBER = 0;
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
|
use const PTHREADS_INHERIT_ALL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class must be extended by all custom threading classes
|
* This class must be extended by all custom threading classes
|
||||||
*/
|
*/
|
||||||
@ -33,12 +35,19 @@ abstract class Worker extends \Worker{
|
|||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
protected $composerAutoloaderPath;
|
protected $composerAutoloaderPath;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
protected $isKilled = false;
|
protected $isKilled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \ClassLoader|null
|
||||||
|
*/
|
||||||
public function getClassLoader(){
|
public function getClassLoader(){
|
||||||
return $this->classLoader;
|
return $this->classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setClassLoader(\ClassLoader $loader = null){
|
public function setClassLoader(\ClassLoader $loader = null){
|
||||||
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||||
|
|
||||||
@ -54,6 +63,8 @@ abstract class Worker extends \Worker{
|
|||||||
* WARNING: This method MUST be called from any descendent threads' run() method to make autoloading usable.
|
* 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
|
* 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).
|
* (unless you are using a custom autoloader).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
if($this->composerAutoloaderPath !== null){
|
if($this->composerAutoloaderPath !== null){
|
||||||
@ -64,7 +75,10 @@ abstract class Worker extends \Worker{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if($this->getClassLoader() === null){
|
if($this->getClassLoader() === null){
|
||||||
@ -75,6 +89,8 @@ abstract class Worker extends \Worker{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
* Stops the thread using the best way possible. Try to stop it yourself before calling this.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function quit(){
|
public function quit(){
|
||||||
$this->isKilled = true;
|
$this->isKilled = true;
|
||||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Air block
|
* Air block
|
||||||
*/
|
*/
|
||||||
|
@ -78,7 +78,7 @@ class Anvil extends Fallable{
|
|||||||
public function recalculateBoundingBox() : ?AxisAlignedBB{
|
public function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
$inset = 0.125;
|
$inset = 0.125;
|
||||||
|
|
||||||
if($this->meta & 0x01){ //east/west
|
if(($this->meta & 0x01) !== 0){ //east/west
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -110,6 +110,6 @@ class Anvil extends Fallable{
|
|||||||
public function place(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{
|
||||||
$direction = ($player !== null ? $player->getDirection() : 0) & 0x03;
|
$direction = ($player !== null ? $player->getDirection() : 0) & 0x03;
|
||||||
$this->meta = $this->getVariant() | $direction;
|
$this->meta = $this->getVariant() | $direction;
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ abstract class BaseRail extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevel()->setBlock($blockReplace, $this, true, true)){
|
if(!$blockReplace->getSide(Vector3::SIDE_DOWN)->isTransparent() and $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true)){
|
||||||
$this->tryReconnect();
|
$this->tryReconnect();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -99,6 +99,11 @@ abstract class BaseRail extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $connections
|
||||||
|
* @param int[][] $lookup
|
||||||
|
* @phpstan-param array<int, list<int>> $lookup
|
||||||
|
*/
|
||||||
protected static function searchState(array $connections, array $lookup) : int{
|
protected static function searchState(array $connections, array $lookup) : int{
|
||||||
$meta = array_search($connections, $lookup, true);
|
$meta = array_search($connections, $lookup, true);
|
||||||
if($meta === false){
|
if($meta === false){
|
||||||
@ -114,9 +119,7 @@ abstract class BaseRail extends Flowable{
|
|||||||
/**
|
/**
|
||||||
* Returns a meta value for the rail with the given connections.
|
* Returns a meta value for the rail with the given connections.
|
||||||
*
|
*
|
||||||
* @param array $connections
|
* @param int[] $connections
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if no state matches the given connections
|
* @throws \InvalidArgumentException if no state matches the given connections
|
||||||
*/
|
*/
|
||||||
@ -164,6 +167,12 @@ abstract class BaseRail extends Flowable{
|
|||||||
return $connections;
|
return $connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $constraints
|
||||||
|
*
|
||||||
|
* @return true[]
|
||||||
|
* @phpstan-return array<int, true>
|
||||||
|
*/
|
||||||
private function getPossibleConnectionDirections(array $constraints) : array{
|
private function getPossibleConnectionDirections(array $constraints) : array{
|
||||||
switch(count($constraints)){
|
switch(count($constraints)){
|
||||||
case 0:
|
case 0:
|
||||||
@ -188,6 +197,10 @@ abstract class BaseRail extends Flowable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true[]
|
||||||
|
* @phpstan-return array<int, true>
|
||||||
|
*/
|
||||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||||
$opposite = Vector3::getOppositeSide($constraint & ~self::FLAG_ASCEND);
|
$opposite = Vector3::getOppositeSide($constraint & ~self::FLAG_ASCEND);
|
||||||
|
|
||||||
@ -247,6 +260,9 @@ abstract class BaseRail extends Flowable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $connections
|
||||||
|
*/
|
||||||
private function updateState(array $connections) : void{
|
private function updateState(array $connections) : void{
|
||||||
if(count($connections) === 1){
|
if(count($connections) === 1){
|
||||||
$connections[] = Vector3::getOppositeSide($connections[0] & ~self::FLAG_ASCEND);
|
$connections[] = Vector3::getOppositeSide($connections[0] & ~self::FLAG_ASCEND);
|
||||||
@ -263,7 +279,7 @@ abstract class BaseRail extends Flowable{
|
|||||||
isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
|
isset(self::ASCENDING_SIDES[$this->meta & 0x07]) and
|
||||||
$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
|
$this->getSide(self::ASCENDING_SIDES[$this->meta & 0x07])->isTransparent()
|
||||||
)){
|
)){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,13 +69,13 @@ class Bed extends Transparent{
|
|||||||
return ($this->meta & self::BITFLAG_HEAD) !== 0;
|
return ($this->meta & self::BITFLAG_HEAD) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isOccupied() : bool{
|
public function isOccupied() : bool{
|
||||||
return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
|
return ($this->meta & self::BITFLAG_OCCUPIED) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setOccupied(bool $occupied = true){
|
public function setOccupied(bool $occupied = true){
|
||||||
if($occupied){
|
if($occupied){
|
||||||
$this->meta |= self::BITFLAG_OCCUPIED;
|
$this->meta |= self::BITFLAG_OCCUPIED;
|
||||||
@ -83,19 +83,13 @@ class Bed extends Transparent{
|
|||||||
$this->meta &= ~self::BITFLAG_OCCUPIED;
|
$this->meta &= ~self::BITFLAG_OCCUPIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($this, $this, false, false);
|
$this->getLevelNonNull()->setBlock($this, $this, false, false);
|
||||||
|
|
||||||
if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
|
if(($other = $this->getOtherHalf()) !== null and $other->isOccupied() !== $occupied){
|
||||||
$other->setOccupied($occupied);
|
$other->setOccupied($occupied);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $meta
|
|
||||||
* @param bool $isHead
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{
|
public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{
|
||||||
$rotation = $meta & 0x03;
|
$rotation = $meta & 0x03;
|
||||||
$side = -1;
|
$side = -1;
|
||||||
@ -122,9 +116,6 @@ class Bed extends Transparent{
|
|||||||
return $side;
|
return $side;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Bed|null
|
|
||||||
*/
|
|
||||||
public function getOtherHalf() : ?Bed{
|
public function getOtherHalf() : ?Bed{
|
||||||
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
$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))){
|
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
||||||
@ -146,7 +137,7 @@ class Bed extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$time = $this->getLevel()->getTime() % Level::TIME_FULL;
|
$time = $this->getLevelNonNull()->getTimeOfDay();
|
||||||
|
|
||||||
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
||||||
|
|
||||||
@ -177,11 +168,11 @@ class Bed extends Transparent{
|
|||||||
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
||||||
$next = $this->getSide(self::getOtherHalfSide($meta));
|
$next = $this->getSide(self::getOtherHalfSide($meta));
|
||||||
if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($next->canBeReplaced() and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||||
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
$this->getLevelNonNull()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||||
|
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($this, $face, $item, $player));
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
Tile::createTile(Tile::BED, $this->getLevelNonNull(), TileBed::createNBT($next, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -203,7 +194,7 @@ class Bed extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function getItem() : Item{
|
private function getItem() : Item{
|
||||||
$tile = $this->getLevel()->getTile($this);
|
$tile = $this->getLevelNonNull()->getTile($this);
|
||||||
if($tile instanceof TileBed){
|
if($tile instanceof TileBed){
|
||||||
return ItemFactory::get($this->getItemId(), $tile->getColor());
|
return ItemFactory::get($this->getItemId(), $tile->getColor());
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,11 @@ use pocketmine\math\RayTraceResult;
|
|||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\metadata\Metadatable;
|
use pocketmine\metadata\Metadatable;
|
||||||
use pocketmine\metadata\MetadataValue;
|
use pocketmine\metadata\MetadataValue;
|
||||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\plugin\Plugin;
|
use pocketmine\plugin\Plugin;
|
||||||
use function array_merge;
|
use function array_merge;
|
||||||
|
use function count;
|
||||||
use function get_class;
|
use function get_class;
|
||||||
use const PHP_INT_MAX;
|
use const PHP_INT_MAX;
|
||||||
|
|
||||||
@ -49,12 +50,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* Returns a new Block instance with the specified ID, meta and position.
|
* Returns a new Block instance with the specified ID, meta and position.
|
||||||
*
|
*
|
||||||
* This function redirects to {@link BlockFactory#get}.
|
* This function redirects to {@link BlockFactory#get}.
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @param int $meta
|
|
||||||
* @param Position|null $pos
|
|
||||||
*
|
|
||||||
* @return Block
|
|
||||||
*/
|
*/
|
||||||
public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
|
public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
|
||||||
return BlockFactory::get($id, $meta, $pos);
|
return BlockFactory::get($id, $meta, $pos);
|
||||||
@ -69,10 +64,9 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/** @var int|null */
|
/** @var int|null */
|
||||||
protected $itemId;
|
protected $itemId;
|
||||||
|
|
||||||
/** @var AxisAlignedBB */
|
/** @var AxisAlignedBB|null */
|
||||||
protected $boundingBox = null;
|
protected $boundingBox = null;
|
||||||
|
|
||||||
|
|
||||||
/** @var AxisAlignedBB[]|null */
|
/** @var AxisAlignedBB[]|null */
|
||||||
protected $collisionBoxes = null;
|
protected $collisionBoxes = null;
|
||||||
|
|
||||||
@ -89,16 +83,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
$this->itemId = $itemId;
|
$this->itemId = $itemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return $this->fallbackName ?? "Unknown";
|
return $this->fallbackName ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
final public function getId() : int{
|
final public function getId() : int{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
@ -106,8 +94,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns the ID of the item form of the block.
|
* 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).
|
* Used for drops for blocks (some blocks such as doors have a different item ID).
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getItemId() : int{
|
public function getItemId() : int{
|
||||||
return $this->itemId ?? $this->getId();
|
return $this->itemId ?? $this->getId();
|
||||||
@ -115,22 +101,15 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getRuntimeId() : int{
|
public function getRuntimeId() : int{
|
||||||
return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage());
|
return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
final public function getDamage() : int{
|
final public function getDamage() : int{
|
||||||
return $this->meta;
|
return $this->meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $meta
|
|
||||||
*/
|
|
||||||
final public function setDamage(int $meta) : void{
|
final public function setDamage(int $meta) : void{
|
||||||
if($meta < 0 or $meta > 0xf){
|
if($meta < 0 or $meta > 0xf){
|
||||||
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
||||||
@ -144,8 +123,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
*
|
*
|
||||||
* If your block should not have any meta value when it's dropped as an item, override this to return 0 in
|
* If your block should not have any meta value when it's dropped as an item, override this to return 0 in
|
||||||
* descendent classes.
|
* descendent classes.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return -1;
|
return -1;
|
||||||
@ -153,24 +130,18 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the block meta, stripped of non-variant flags.
|
* Returns the block meta, stripped of non-variant flags.
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getVariant() : int{
|
public function getVariant() : int{
|
||||||
return $this->meta & $this->getVariantBitmask();
|
return $this->meta & $this->getVariantBitmask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AKA: Block->isPlaceable
|
* AKA: Block->isPlaceable
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function canBePlaced() : bool{
|
public function canBePlaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canBeReplaced() : bool{
|
public function canBeReplaced() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -181,34 +152,18 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||||
*
|
|
||||||
* @param Item $item
|
|
||||||
* @param Block $blockReplace
|
|
||||||
* @param Block $blockClicked
|
|
||||||
* @param int $face
|
|
||||||
* @param Vector3 $clickVector
|
|
||||||
* @param Player|null $player
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function place(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{
|
||||||
return $this->getLevel()->setBlock($this, $this, true, true);
|
return $this->getLevelNonNull()->setBlock($this, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the block can be broken with an specific Item
|
* Returns if the block can be broken with an specific Item
|
||||||
*
|
|
||||||
* @param Item $item
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isBreakable(Item $item) : bool{
|
public function isBreakable(Item $item) : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return BlockToolType::TYPE_NONE;
|
return BlockToolType::TYPE_NONE;
|
||||||
}
|
}
|
||||||
@ -222,8 +177,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* Otherwise, 1 should be returned if a tool is required, 0 if not.
|
* Otherwise, 1 should be returned if a tool is required, 0 if not.
|
||||||
*
|
*
|
||||||
* @see Item::getBlockToolHarvestLevel()
|
* @see Item::getBlockToolHarvestLevel()
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getToolHarvestLevel() : int{
|
public function getToolHarvestLevel() : int{
|
||||||
return 0;
|
return 0;
|
||||||
@ -235,10 +188,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
*
|
*
|
||||||
* In most cases this is also used to determine whether block drops should be created or not, except in some
|
* 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.
|
* special cases such as vines.
|
||||||
*
|
|
||||||
* @param Item $tool
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isCompatibleWithTool(Item $tool) : bool{
|
public function isCompatibleWithTool(Item $tool) : bool{
|
||||||
if($this->getHardness() < 0){
|
if($this->getHardness() < 0){
|
||||||
@ -253,23 +202,14 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the actions needed so the block is broken with the Item
|
* 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{
|
public function onBreak(Item $item, Player $player = null) : bool{
|
||||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
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
|
* 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
|
* @throws \InvalidArgumentException if the item efficiency is not a positive number
|
||||||
*/
|
*/
|
||||||
public function getBreakTime(Item $item) : float{
|
public function getBreakTime(Item $item) : float{
|
||||||
@ -299,8 +239,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether random block updates will be done on this block.
|
* Returns whether random block updates will be done on this block.
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function ticksRandomly() : bool{
|
public function ticksRandomly() : bool{
|
||||||
return false;
|
return false;
|
||||||
@ -323,11 +261,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Do actions when activated by Item. Returns if it has done anything
|
* Do actions when activated by Item. Returns if it has done anything
|
||||||
*
|
|
||||||
* @param Item $item
|
|
||||||
* @param Player|null $player
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
return false;
|
return false;
|
||||||
@ -335,7 +268,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a base value used to compute block break times.
|
* Returns a base value used to compute block break times.
|
||||||
* @return float
|
|
||||||
*/
|
*/
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 10;
|
return 10;
|
||||||
@ -343,15 +275,11 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the block's resistance to explosions. Usually 5x hardness.
|
* Returns the block's resistance to explosions. Usually 5x hardness.
|
||||||
* @return float
|
|
||||||
*/
|
*/
|
||||||
public function getBlastResistance() : float{
|
public function getBlastResistance() : float{
|
||||||
return $this->getHardness() * 5;
|
return $this->getHardness() * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getFrictionFactor() : float{
|
public function getFrictionFactor() : float{
|
||||||
return 0.6;
|
return 0.6;
|
||||||
}
|
}
|
||||||
@ -379,16 +307,11 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* Examples of this behaviour include leaves and cobwebs.
|
* Examples of this behaviour include leaves and cobwebs.
|
||||||
*
|
*
|
||||||
* Light-diffusing blocks are included by the heightmap.
|
* Light-diffusing blocks are included by the heightmap.
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function diffusesSkyLight() : bool{
|
public function diffusesSkyLight() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTransparent() : bool{
|
public function isTransparent() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -399,7 +322,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* AKA: Block->isFlowable
|
* AKA: Block->isFlowable
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function canBeFlowedInto() : bool{
|
public function canBeFlowedInto() : bool{
|
||||||
return false;
|
return false;
|
||||||
@ -415,21 +337,17 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether entities can climb up this block.
|
* Returns whether entities can climb up this block.
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function canClimb() : bool{
|
public function canClimb() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the block position to a new Position object
|
* Sets the block position to a new Position object
|
||||||
*
|
|
||||||
* @param Position $v
|
|
||||||
*/
|
*/
|
||||||
final public function position(Position $v) : void{
|
final public function position(Position $v) : void{
|
||||||
$this->x = (int) $v->x;
|
$this->x = (int) $v->x;
|
||||||
@ -442,8 +360,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns an array of Item objects to be dropped
|
* Returns an array of Item objects to be dropped
|
||||||
*
|
*
|
||||||
* @param Item $item
|
|
||||||
*
|
|
||||||
* @return Item[]
|
* @return Item[]
|
||||||
*/
|
*/
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
@ -461,8 +377,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
|
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
|
||||||
*
|
*
|
||||||
* @param Item $item
|
|
||||||
*
|
|
||||||
* @return Item[]
|
* @return Item[]
|
||||||
*/
|
*/
|
||||||
public function getDropsForCompatibleTool(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
@ -474,8 +388,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
|
* 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[]
|
* @return Item[]
|
||||||
*/
|
*/
|
||||||
public function getSilkTouchDrops(Item $item) : array{
|
public function getSilkTouchDrops(Item $item) : array{
|
||||||
@ -486,10 +398,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns how much XP will be dropped by breaking this block with the given item.
|
* 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{
|
public function getXpDropForTool(Item $item) : int{
|
||||||
if($item->hasEnchantment(Enchantment::SILK_TOUCH) or !$this->isCompatibleWithTool($item)){
|
if($item->hasEnchantment(Enchantment::SILK_TOUCH) or !$this->isCompatibleWithTool($item)){
|
||||||
@ -501,8 +409,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns how much XP this block will drop when broken with an appropriate tool.
|
* Returns how much XP this block will drop when broken with an appropriate tool.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
protected function getXpDropAmount() : int{
|
protected function getXpDropAmount() : int{
|
||||||
return 0;
|
return 0;
|
||||||
@ -511,8 +417,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
|
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
|
||||||
* themselves anyway, this is implicitly true.
|
* themselves anyway, this is implicitly true.
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return true;
|
return true;
|
||||||
@ -520,7 +424,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the item that players will equip when middle-clicking on this block.
|
* Returns the item that players will equip when middle-clicking on this block.
|
||||||
* @return Item
|
|
||||||
*/
|
*/
|
||||||
public function getPickedItem() : Item{
|
public function getPickedItem() : Item{
|
||||||
return ItemFactory::get($this->getItemId(), $this->getVariant());
|
return ItemFactory::get($this->getItemId(), $this->getVariant());
|
||||||
@ -528,7 +431,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time in ticks which the block will fuel a furnace for.
|
* Returns the time in ticks which the block will fuel a furnace for.
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
return 0;
|
return 0;
|
||||||
@ -537,8 +439,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
|
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
|
||||||
* fire.
|
* fire.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getFlameEncouragement() : int{
|
public function getFlameEncouragement() : int{
|
||||||
return 0;
|
return 0;
|
||||||
@ -546,8 +446,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
|
* Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getFlammability() : int{
|
public function getFlammability() : int{
|
||||||
return 0;
|
return 0;
|
||||||
@ -555,8 +453,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether fire lit on this block will burn indefinitely.
|
* Returns whether fire lit on this block will burn indefinitely.
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function burnsForever() : bool{
|
public function burnsForever() : bool{
|
||||||
return false;
|
return false;
|
||||||
@ -564,8 +460,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this block can catch fire.
|
* Returns whether this block can catch fire.
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isFlammable() : bool{
|
public function isFlammable() : bool{
|
||||||
return $this->getFlammability() > 0;
|
return $this->getFlammability() > 0;
|
||||||
@ -581,14 +475,11 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* Returns the Block on the side $side, works like Vector3::getSide()
|
* Returns the Block on the side $side, works like Vector3::getSide()
|
||||||
*
|
*
|
||||||
* @param int $side
|
|
||||||
* @param int $step
|
|
||||||
*
|
|
||||||
* @return Block
|
* @return Block
|
||||||
*/
|
*/
|
||||||
public function getSide(int $side, int $step = 1){
|
public function getSide(int $side, int $step = 1){
|
||||||
if($this->isValid()){
|
if($this->isValid()){
|
||||||
return $this->getLevel()->getBlock(Vector3::getSide($side, $step));
|
return $this->getLevelNonNull()->getBlock(Vector3::getSide($side, $step));
|
||||||
}
|
}
|
||||||
|
|
||||||
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
||||||
@ -642,10 +533,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for collision against an AxisAlignedBB
|
* Checks for collision against an AxisAlignedBB
|
||||||
*
|
|
||||||
* @param AxisAlignedBB $bb
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||||
foreach($this->getCollisionBoxes() as $bb2){
|
foreach($this->getCollisionBoxes() as $bb2){
|
||||||
@ -657,9 +544,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Entity $entity
|
|
||||||
*/
|
|
||||||
public function onEntityCollide(Entity $entity) : void{
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -679,16 +563,13 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return AxisAlignedBB[]
|
* @return AxisAlignedBB[]
|
||||||
*/
|
*/
|
||||||
protected function recalculateCollisionBoxes() : array{
|
protected function recalculateCollisionBoxes() : array{
|
||||||
if($bb = $this->recalculateBoundingBox()){
|
if(($bb = $this->recalculateBoundingBox()) !== null){
|
||||||
return [$bb];
|
return [$bb];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return AxisAlignedBB|null
|
|
||||||
*/
|
|
||||||
public function getBoundingBox() : ?AxisAlignedBB{
|
public function getBoundingBox() : ?AxisAlignedBB{
|
||||||
if($this->boundingBox === null){
|
if($this->boundingBox === null){
|
||||||
$this->boundingBox = $this->recalculateBoundingBox();
|
$this->boundingBox = $this->recalculateBoundingBox();
|
||||||
@ -696,9 +577,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->boundingBox;
|
return $this->boundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return AxisAlignedBB|null
|
|
||||||
*/
|
|
||||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
@ -719,15 +597,9 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
$this->collisionBoxes = null;
|
$this->collisionBoxes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Vector3 $pos1
|
|
||||||
* @param Vector3 $pos2
|
|
||||||
*
|
|
||||||
* @return RayTraceResult|null
|
|
||||||
*/
|
|
||||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||||
$bbs = $this->getCollisionBoxes();
|
$bbs = $this->getCollisionBoxes();
|
||||||
if(empty($bbs)){
|
if(count($bbs) === 0){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +635,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
|
return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasMetadata(string $metadataKey) : bool{
|
public function hasMetadata(string $metadataKey) : bool{
|
||||||
|
@ -25,30 +25,54 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Position;
|
use pocketmine\level\Position;
|
||||||
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
|
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||||
use function min;
|
use function min;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages block registration and instance creation
|
* Manages block registration and instance creation
|
||||||
*/
|
*/
|
||||||
class BlockFactory{
|
class BlockFactory{
|
||||||
/** @var \SplFixedArray<Block> */
|
/**
|
||||||
private static $fullList = null;
|
* @var \SplFixedArray|Block[]
|
||||||
|
* @phpstan-var \SplFixedArray<Block>
|
||||||
|
*/
|
||||||
|
private static $fullList;
|
||||||
|
|
||||||
/** @var \SplFixedArray<bool> */
|
/**
|
||||||
public static $solid = null;
|
* @var \SplFixedArray|bool[]
|
||||||
/** @var \SplFixedArray<bool> */
|
* @phpstan-var \SplFixedArray<bool>
|
||||||
public static $transparent = null;
|
*/
|
||||||
/** @var \SplFixedArray<float> */
|
public static $solid;
|
||||||
public static $hardness = null;
|
/**
|
||||||
/** @var \SplFixedArray<int> */
|
* @var \SplFixedArray|bool[]
|
||||||
public static $light = null;
|
* @phpstan-var \SplFixedArray<bool>
|
||||||
/** @var \SplFixedArray<int> */
|
*/
|
||||||
public static $lightFilter = null;
|
public static $transparent;
|
||||||
/** @var \SplFixedArray<bool> */
|
/**
|
||||||
public static $diffusesSkyLight = null;
|
* @var \SplFixedArray|float[]
|
||||||
/** @var \SplFixedArray<float> */
|
* @phpstan-var \SplFixedArray<float>
|
||||||
public static $blastResistance = null;
|
*/
|
||||||
|
public static $hardness;
|
||||||
|
/**
|
||||||
|
* @var \SplFixedArray|int[]
|
||||||
|
* @phpstan-var \SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
public static $light;
|
||||||
|
/**
|
||||||
|
* @var \SplFixedArray|int[]
|
||||||
|
* @phpstan-var \SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
public static $lightFilter;
|
||||||
|
/**
|
||||||
|
* @var \SplFixedArray|bool[]
|
||||||
|
* @phpstan-var \SplFixedArray<bool>
|
||||||
|
*/
|
||||||
|
public static $diffusesSkyLight;
|
||||||
|
/**
|
||||||
|
* @var \SplFixedArray|float[]
|
||||||
|
* @phpstan-var \SplFixedArray<float>
|
||||||
|
*/
|
||||||
|
public static $blastResistance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the block factory. By default this is called only once on server start, however you may wish to use
|
* Initializes the block factory. By default this is called only once on server start, however you may wish to use
|
||||||
@ -334,7 +358,6 @@ class BlockFactory{
|
|||||||
* NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
|
* NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
|
||||||
* will not automatically appear there.
|
* will not automatically appear there.
|
||||||
*
|
*
|
||||||
* @param Block $block
|
|
||||||
* @param bool $override Whether to override existing registrations
|
* @param bool $override Whether to override existing registrations
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
||||||
@ -364,12 +387,6 @@ class BlockFactory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new Block instance with the specified ID, meta and position.
|
* Returns a new Block instance with the specified ID, meta and position.
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @param int $meta
|
|
||||||
* @param Position $pos
|
|
||||||
*
|
|
||||||
* @return Block
|
|
||||||
*/
|
*/
|
||||||
public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
|
public static function get(int $id, int $meta = 0, Position $pos = null) : Block{
|
||||||
if($meta < 0 or $meta > 0xf){
|
if($meta < 0 or $meta > 0xf){
|
||||||
@ -398,7 +415,7 @@ class BlockFactory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @return \SplFixedArray
|
* @phpstan-return \SplFixedArray<Block>
|
||||||
*/
|
*/
|
||||||
public static function getBlockStatesArray() : \SplFixedArray{
|
public static function getBlockStatesArray() : \SplFixedArray{
|
||||||
return self::$fullList;
|
return self::$fullList;
|
||||||
@ -406,10 +423,6 @@ class BlockFactory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a specified block ID is already registered in the block factory.
|
* Returns whether a specified block ID is already registered in the block factory.
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public static function isRegistered(int $id) : bool{
|
public static function isRegistered(int $id) : bool{
|
||||||
$b = self::$fullList[$id << 4];
|
$b = self::$fullList[$id << 4];
|
||||||
@ -419,11 +432,6 @@ class BlockFactory{
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @param int $meta
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
|
public static function toStaticRuntimeId(int $id, int $meta = 0) : int{
|
||||||
return RuntimeBlockMapping::toStaticRuntimeId($id, $meta);
|
return RuntimeBlockMapping::toStaticRuntimeId($id, $meta);
|
||||||
@ -433,8 +441,6 @@ class BlockFactory{
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
* @param int $runtimeId
|
|
||||||
*
|
|
||||||
* @return int[] [id, meta]
|
* @return int[] [id, meta]
|
||||||
*/
|
*/
|
||||||
public static function fromStaticRuntimeId(int $runtimeId) : array{
|
public static function fromStaticRuntimeId(int $runtimeId) : array{
|
||||||
|
@ -55,7 +55,7 @@ class BoneBlock extends Solid{
|
|||||||
|
|
||||||
public function place(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{
|
||||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
|
@ -68,18 +68,21 @@ class BurningFurnace extends Solid{
|
|||||||
3 => 3
|
3 => 3
|
||||||
];
|
];
|
||||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$furnace = $this->getLevel()->getTile($this);
|
$furnace = $this->getLevelNonNull()->getTile($this);
|
||||||
if(!($furnace instanceof TileFurnace)){
|
if(!($furnace instanceof TileFurnace)){
|
||||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevelNonNull(), TileFurnace::createNBT($this));
|
||||||
|
if(!($furnace instanceof TileFurnace)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$furnace->canOpenWith($item->getCustomName())){
|
if(!$furnace->canOpenWith($item->getCustomName())){
|
||||||
|
@ -72,12 +72,12 @@ class Cactus extends Transparent{
|
|||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
|
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}else{
|
}else{
|
||||||
for($side = 2; $side <= 5; ++$side){
|
for($side = 2; $side <= 5; ++$side){
|
||||||
$b = $this->getSide($side);
|
$b = $this->getSide($side);
|
||||||
if($b->isSolid()){
|
if($b->isSolid()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,23 +92,23 @@ class Cactus extends Transparent{
|
|||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||||
if($this->meta === 0x0f){
|
if($this->meta === 0x0f){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
|
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS));
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||||
}else{
|
}else{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->meta = 0;
|
$this->meta = 0;
|
||||||
$this->getLevel()->setBlock($this, $this);
|
$this->getLevelNonNull()->setBlock($this, $this);
|
||||||
}else{
|
}else{
|
||||||
++$this->meta;
|
++$this->meta;
|
||||||
$this->getLevel()->setBlock($this, $this);
|
$this->getLevelNonNull()->setBlock($this, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ class Cactus extends Transparent{
|
|||||||
$block2 = $this->getSide(Vector3::SIDE_WEST);
|
$block2 = $this->getSide(Vector3::SIDE_WEST);
|
||||||
$block3 = $this->getSide(Vector3::SIDE_EAST);
|
$block3 = $this->getSide(Vector3::SIDE_EAST);
|
||||||
if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){
|
if(!$block0->isSolid() and !$block1->isSolid() and !$block2->isSolid() and !$block3->isSolid()){
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() !== self::AIR){
|
if($down->getId() !== self::AIR){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +109,10 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getVariantBitmask() : int{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Block
|
* @return Block
|
||||||
*/
|
*/
|
||||||
|
@ -64,7 +64,7 @@ class Carpet extends Flowable{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() !== self::AIR){
|
if($down->getId() !== self::AIR){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ class Carpet extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
$c = $this->getSide($side);
|
$c = $this->getSide($side);
|
||||||
if($c->getId() === $this->id and $c->getDamage() === $this->meta){
|
if($c->getId() === $this->id and $c->getDamage() === $this->meta){
|
||||||
$tile = $this->getLevel()->getTile($c);
|
$tile = $this->getLevelNonNull()->getTile($c);
|
||||||
if($tile instanceof TileChest and !$tile->isPaired()){
|
if($tile instanceof TileChest and !$tile->isPaired()){
|
||||||
$chest = $tile;
|
$chest = $tile;
|
||||||
break;
|
break;
|
||||||
@ -89,8 +89,8 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
$tile = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||||
$chest->pairWith($tile);
|
$chest->pairWith($tile);
|
||||||
@ -103,17 +103,20 @@ class Chest extends Transparent{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
|
|
||||||
$t = $this->getLevel()->getTile($this);
|
$t = $this->getLevelNonNull()->getTile($this);
|
||||||
$chest = null;
|
$chest = null;
|
||||||
if($t instanceof TileChest){
|
if($t instanceof TileChest){
|
||||||
$chest = $t;
|
$chest = $t;
|
||||||
}else{
|
}else{
|
||||||
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
$chest = Tile::createTile(Tile::CHEST, $this->getLevelNonNull(), TileChest::createNBT($this));
|
||||||
|
if(!($chest instanceof TileChest)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
!$this->getSide(Vector3::SIDE_UP)->isTransparent() or
|
!$this->getSide(Vector3::SIDE_UP)->isTransparent() or
|
||||||
($chest->isPaired() and !$chest->getPair()->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
|
(($pair = $chest->getPair()) !== null and !$pair->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
|
||||||
!$chest->canOpenWith($item->getCustomName())
|
!$chest->canOpenWith($item->getCustomName())
|
||||||
){
|
){
|
||||||
return true;
|
return true;
|
||||||
|
@ -111,6 +111,9 @@ class CobblestoneWall extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function canConnect(Block $block){
|
public function canConnect(Block $block){
|
||||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemFactory;
|
||||||
|
use pocketmine\item\ItemIds;
|
||||||
|
use function mt_rand;
|
||||||
|
|
||||||
class CocoaBlock extends Transparent{
|
class CocoaBlock extends Transparent{
|
||||||
|
|
||||||
protected $id = self::COCOA_BLOCK;
|
protected $id = self::COCOA_BLOCK;
|
||||||
@ -48,4 +53,14 @@ class CocoaBlock extends Transparent{
|
|||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [
|
||||||
|
ItemFactory::get(ItemIds::DYE, 3, ($this->meta >> 2) === 2 ? mt_rand(2, 3) : 1)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get(ItemIds::DYE, 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,16 +53,10 @@ class ConcretePowder extends Fallable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return null|Block
|
|
||||||
*/
|
|
||||||
public function tickFalling() : ?Block{
|
public function tickFalling() : ?Block{
|
||||||
return $this->checkAdjacentWater();
|
return $this->checkAdjacentWater();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return null|Block
|
|
||||||
*/
|
|
||||||
private function checkAdjacentWater() : ?Block{
|
private function checkAdjacentWater() : ?Block{
|
||||||
for($i = 1; $i < 6; ++$i){ //Do not check underneath
|
for($i = 1; $i < 6; ++$i){ //Do not check underneath
|
||||||
if($this->getSide($i) instanceof Water){
|
if($this->getSide($i) instanceof Water){
|
||||||
|
@ -25,6 +25,8 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\inventory\CraftingGrid;
|
use pocketmine\inventory\CraftingGrid;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class CraftingTable extends Solid{
|
class CraftingTable extends Solid{
|
||||||
@ -50,6 +52,16 @@ class CraftingTable extends Solid{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
|
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
|
||||||
|
|
||||||
|
//TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack allows
|
||||||
|
//it to carry on working approximately the same way as it did in 1.14
|
||||||
|
$pk = new ContainerOpenPacket();
|
||||||
|
$pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID;
|
||||||
|
$pk->type = WindowTypes::WORKBENCH;
|
||||||
|
$pk->x = $this->getFloorX();
|
||||||
|
$pk->y = $this->getFloorY();
|
||||||
|
$pk->z = $this->getFloorZ();
|
||||||
|
$player->sendDataPacket($pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -33,7 +33,7 @@ abstract class Crops extends Flowable{
|
|||||||
|
|
||||||
public function place(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{
|
||||||
if($blockReplace->getSide(Vector3::SIDE_DOWN)->getId() === Block::FARMLAND){
|
if($blockReplace->getSide(Vector3::SIDE_DOWN)->getId() === Block::FARMLAND){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -41,7 +41,6 @@ abstract class Crops extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($this->meta < 7 and $item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
if($this->meta < 7 and $item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||||
$block = clone $this;
|
$block = clone $this;
|
||||||
@ -53,10 +52,10 @@ abstract class Crops extends Flowable{
|
|||||||
$ev = new BlockGrowEvent($this, $block);
|
$ev = new BlockGrowEvent($this, $block);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$item->count--;
|
$item->pop();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -66,7 +65,7 @@ abstract class Crops extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::FARMLAND){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ abstract class Crops extends Flowable{
|
|||||||
$ev = new BlockGrowEvent($this, $block);
|
$ev = new BlockGrowEvent($this, $block);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,10 @@ class Dandelion extends Flowable{
|
|||||||
return "Dandelion";
|
return "Dandelion";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -53,7 +52,7 @@ class Dandelion extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class DeadBush extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ class Dirt extends Solid{
|
|||||||
if($item instanceof Hoe){
|
if($item instanceof Hoe){
|
||||||
$item->applyDamage(1);
|
$item->applyDamage(1);
|
||||||
if($this->meta === 1){
|
if($this->meta === 1){
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
}else{
|
}else{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -29,14 +29,13 @@ use pocketmine\math\AxisAlignedBB;
|
|||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
|
||||||
abstract class Door extends Transparent{
|
abstract class Door extends Transparent{
|
||||||
|
|
||||||
public function isSolid() : bool{
|
public function isSolid() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getFullDamage(){
|
private function getFullDamage() : int{
|
||||||
$damage = $this->getDamage();
|
$damage = $this->getDamage();
|
||||||
$isUp = ($damage & 0x08) > 0;
|
$isUp = ($damage & 0x08) > 0;
|
||||||
|
|
||||||
@ -202,9 +201,9 @@ abstract class Door extends Transparent{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){ //Replace with common break method
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false);
|
||||||
if($this->getSide(Vector3::SIDE_UP) instanceof Door){
|
if($this->getSide(Vector3::SIDE_UP) instanceof Door){
|
||||||
$this->getLevel()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
|
$this->getLevelNonNull()->setBlock($this->getSide(Vector3::SIDE_UP), BlockFactory::get(Block::AIR), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,8 +230,8 @@ abstract class Door extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->setDamage($player->getDirection() & 0x03);
|
$this->setDamage($player->getDirection() & 0x03);
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true); //Bottom
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true); //Bottom
|
||||||
$this->getLevel()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
|
$this->getLevelNonNull()->setBlock($blockUp, BlockFactory::get($this->getId(), $metaUp), true); //Top
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@ class DoublePlant extends Flowable{
|
|||||||
public function place(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{
|
||||||
$id = $blockReplace->getSide(Vector3::SIDE_DOWN)->getId();
|
$id = $blockReplace->getSide(Vector3::SIDE_DOWN)->getId();
|
||||||
if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){
|
if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, false, false);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, false, false);
|
||||||
$this->getLevel()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);
|
$this->getLevelNonNull()->setBlock($blockReplace->getSide(Vector3::SIDE_UP), BlockFactory::get($this->id, $this->meta | self::BITFLAG_TOP), false, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -68,10 +68,9 @@ class DoublePlant extends Flowable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this double-plant has a corresponding other half.
|
* Returns whether this double-plant has a corresponding other half.
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isValidHalfPlant() : bool{
|
public function isValidHalfPlant() : bool{
|
||||||
if($this->meta & self::BITFLAG_TOP){
|
if(($this->meta & self::BITFLAG_TOP) !== 0){
|
||||||
$other = $this->getSide(Vector3::SIDE_DOWN);
|
$other = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
}else{
|
}else{
|
||||||
$other = $this->getSide(Vector3::SIDE_UP);
|
$other = $this->getSide(Vector3::SIDE_UP);
|
||||||
@ -86,7 +85,7 @@ class DoublePlant extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){
|
if(!$this->isValidHalfPlant() or (($this->meta & self::BITFLAG_TOP) === 0 and $this->getSide(Vector3::SIDE_DOWN)->isTransparent())){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ class DoublePlant extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
if($this->meta & self::BITFLAG_TOP){
|
if(($this->meta & self::BITFLAG_TOP) !== 0){
|
||||||
if($this->isCompatibleWithTool($item)){
|
if($this->isCompatibleWithTool($item)){
|
||||||
return parent::getDrops($item);
|
return parent::getDrops($item);
|
||||||
}
|
}
|
||||||
@ -125,4 +124,12 @@ class DoublePlant extends Flowable{
|
|||||||
|
|
||||||
return parent::getAffectedBlocks();
|
return parent::getAffectedBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFlameEncouragement() : int{
|
||||||
|
return 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFlammability() : int{
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,9 @@ class EnchantingTable extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevelNonNull(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ class EnderChest extends Chest{
|
|||||||
|
|
||||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -78,12 +78,15 @@ class EnderChest extends Chest{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
|
|
||||||
$t = $this->getLevel()->getTile($this);
|
$t = $this->getLevelNonNull()->getTile($this);
|
||||||
$enderChest = null;
|
$enderChest = null;
|
||||||
if($t instanceof TileEnderChest){
|
if($t instanceof TileEnderChest){
|
||||||
$enderChest = $t;
|
$enderChest = $t;
|
||||||
}else{
|
}else{
|
||||||
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this));
|
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevelNonNull(), TileEnderChest::createNBT($this));
|
||||||
|
if(!($enderChest instanceof TileEnderChest)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->getSide(Vector3::SIDE_UP)->isTransparent()){
|
if(!$this->getSide(Vector3::SIDE_UP)->isTransparent()){
|
||||||
|
@ -37,7 +37,7 @@ abstract class Fallable extends Solid{
|
|||||||
$nbt->setInt("TileID", $this->getId());
|
$nbt->setInt("TileID", $this->getId());
|
||||||
$nbt->setByte("Data", $this->getDamage());
|
$nbt->setByte("Data", $this->getDamage());
|
||||||
|
|
||||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
|
$fall = Entity::createEntity("FallingSand", $this->getLevelNonNull(), $nbt);
|
||||||
|
|
||||||
if($fall !== null){
|
if($fall !== null){
|
||||||
$fall->spawnToAll();
|
$fall->spawnToAll();
|
||||||
@ -45,9 +45,6 @@ abstract class Fallable extends Solid{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return null|Block
|
|
||||||
*/
|
|
||||||
public function tickFalling() : ?Block{
|
public function tickFalling() : ?Block{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ class Farmland extends Transparent{
|
|||||||
return BlockToolType::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
use function count;
|
||||||
|
|
||||||
abstract class Fence extends Transparent{
|
abstract class Fence extends Transparent{
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ abstract class Fence extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($bbs)){
|
if(count($bbs) === 0){
|
||||||
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||||
return [
|
return [
|
||||||
new AxisAlignedBB(
|
new AxisAlignedBB(
|
||||||
@ -102,6 +103,9 @@ abstract class Fence extends Transparent{
|
|||||||
return $bbs;
|
return $bbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function canConnect(Block $block){
|
public function canConnect(Block $block){
|
||||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ class FenceGate extends Transparent{
|
|||||||
return BlockToolType::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
if(($this->getDamage() & 0x04) > 0){
|
if(($this->getDamage() & 0x04) > 0){
|
||||||
@ -70,7 +69,7 @@ class FenceGate extends Transparent{
|
|||||||
|
|
||||||
public function place(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{
|
||||||
$this->meta = ($player instanceof Player ? ($player->getDirection() - 1) & 0x03 : 0);
|
$this->meta = ($player instanceof Player ? ($player->getDirection() - 1) & 0x03 : 0);
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -86,7 +85,7 @@ class FenceGate extends Transparent{
|
|||||||
$this->meta |= (($player->getDirection() - 1) & 0x02);
|
$this->meta |= (($player->getDirection() - 1) & 0x02);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
$this->level->addSound(new DoorSound($this));
|
$this->level->addSound(new DoorSound($this));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ class Fire extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){
|
if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
}else{
|
}else{
|
||||||
$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
|
$this->level->scheduleDelayedBlockUpdate($this, mt_rand(30, 40));
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ class Flower extends Flowable{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ class Flower extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,19 +62,19 @@ class FlowerPot extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::FLOWER_POT, $this->getLevelNonNull(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
$pot = $this->getLevel()->getTile($this);
|
$pot = $this->getLevelNonNull()->getTile($this);
|
||||||
if(!($pot instanceof TileFlowerPot)){
|
if(!($pot instanceof TileFlowerPot)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ class FlowerPot extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
|
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
|
||||||
$this->getLevel()->setBlock($this, $this, true, false);
|
$this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||||
$pot->setItem($item->pop());
|
$pot->setItem($item->pop());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -96,7 +96,7 @@ class FlowerPot extends Flowable{
|
|||||||
public function getDropsForCompatibleTool(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
$items = parent::getDropsForCompatibleTool($item);
|
$items = parent::getDropsForCompatibleTool($item);
|
||||||
|
|
||||||
$tile = $this->getLevel()->getTile($this);
|
$tile = $this->getLevelNonNull()->getTile($this);
|
||||||
if($tile instanceof TileFlowerPot){
|
if($tile instanceof TileFlowerPot){
|
||||||
$item = $tile->getItem();
|
$item = $tile->getItem();
|
||||||
if($item->getId() !== Item::AIR){
|
if($item->getId() !== Item::AIR){
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class Furnace extends BurningFurnace{
|
class Furnace extends BurningFurnace{
|
||||||
|
|
||||||
protected $id = self::FURNACE;
|
protected $id = self::FURNACE;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* ____ _ _ __ __ _ __ __ ____
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
@ -54,7 +53,7 @@ class GlazedTerracotta extends Solid{
|
|||||||
$this->meta = $faces[(~($player->getDirection() - 1)) & 0x03];
|
$this->meta = $faces[(~($player->getDirection() - 1)) & 0x03];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\item\TieredTool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class GlowingObsidian extends Solid{
|
class GlowingObsidian extends Solid{
|
||||||
|
@ -53,6 +53,6 @@ class GlowingRedstoneOre extends RedstoneOre{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::REDSTONE_ORE, $this->meta), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,18 +99,18 @@ class Grass extends Solid{
|
|||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
|
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
|
||||||
$item->count--;
|
$item->pop();
|
||||||
TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2);
|
TallGrassObject::growGrass($this->getLevelNonNull(), $this, new Random(mt_rand()), 8, 2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($item instanceof Hoe){
|
}elseif($item instanceof Hoe){
|
||||||
$item->applyDamage(1);
|
$item->applyDamage(1);
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND));
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::FARMLAND));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($item instanceof Shovel and $this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR){
|
}elseif($item instanceof Shovel and $this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR){
|
||||||
$item->applyDamage(1);
|
$item->applyDamage(1);
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GRASS_PATH));
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GRASS_PATH));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class HayBale extends Solid{
|
|||||||
|
|
||||||
public function place(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{
|
||||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class Ice extends Transparent{
|
|||||||
|
|
||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
public function onBreak(Item $item, Player $player = null) : bool{
|
||||||
if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
||||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
|
return $this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::WATER), true);
|
||||||
}
|
}
|
||||||
return parent::onBreak($item, $player);
|
return parent::onBreak($item, $player);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,10 @@ class ItemFrame extends Flowable{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
$tile = $this->level->getTile($this);
|
$tile = $this->level->getTile($this);
|
||||||
if(!($tile instanceof TileItemFrame)){
|
if(!($tile instanceof TileItemFrame)){
|
||||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
|
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this));
|
||||||
|
if(!($tile instanceof TileItemFrame)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($tile->hasItem()){
|
if($tile->hasItem()){
|
||||||
@ -85,7 +88,7 @@ class ItemFrame extends Flowable{
|
|||||||
$this->meta = $faces[$face];
|
$this->meta = $faces[$face];
|
||||||
$this->level->setBlock($blockReplace, $this, true, true);
|
$this->level->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::ITEM_FRAME, $this->getLevelNonNull(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -90,7 +90,6 @@ class Ladder extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function place(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{
|
||||||
if(!$blockClicked->isTransparent()){
|
if(!$blockClicked->isTransparent()){
|
||||||
$faces = [
|
$faces = [
|
||||||
@ -101,7 +100,7 @@ class Ladder extends Transparent{
|
|||||||
];
|
];
|
||||||
if(isset($faces[$face])){
|
if(isset($faces[$face])){
|
||||||
$this->meta = $faces[$face];
|
$this->meta = $faces[$face];
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -115,8 +115,8 @@ class Lava extends Liquid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
$ret = $this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
$this->getLevelNonNull()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ class Leaves extends Transparent{
|
|||||||
public const DARK_OAK = 1;
|
public const DARK_OAK = 1;
|
||||||
|
|
||||||
protected $id = self::LEAVES;
|
protected $id = self::LEAVES;
|
||||||
|
/** @var int */
|
||||||
protected $woodType = self::WOOD;
|
protected $woodType = self::WOOD;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
@ -67,8 +68,11 @@ class Leaves extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
protected function findLog(Block $pos, array $visited, int $distance, ?int $fromSide = null) : bool{
|
* @param true[] $visited reference parameter
|
||||||
|
* @phpstan-param array<string, true> $visited
|
||||||
|
*/
|
||||||
|
protected function findLog(Block $pos, array &$visited, int $distance, ?int $fromSide = null) : bool{
|
||||||
$index = $pos->x . "." . $pos->y . "." . $pos->z;
|
$index = $pos->x . "." . $pos->y . "." . $pos->z;
|
||||||
if(isset($visited[$index])){
|
if(isset($visited[$index])){
|
||||||
return false;
|
return false;
|
||||||
@ -135,7 +139,7 @@ class Leaves extends Transparent{
|
|||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if(($this->meta & 0b00001100) === 0){
|
if(($this->meta & 0b00001100) === 0){
|
||||||
$this->meta |= 0x08;
|
$this->meta |= 0x08;
|
||||||
$this->getLevel()->setBlock($this, $this, true, false);
|
$this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,16 +155,16 @@ class Leaves extends Transparent{
|
|||||||
$ev = new LeavesDecayEvent($this);
|
$ev = new LeavesDecayEvent($this);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0)){
|
if($ev->isCancelled() or $this->findLog($this, $visited, 0)){
|
||||||
$this->getLevel()->setBlock($this, $this, false, false);
|
$this->getLevelNonNull()->setBlock($this, $this, false, false);
|
||||||
}else{
|
}else{
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
$this->meta |= 0x04;
|
$this->meta |= 0x04;
|
||||||
return $this->getLevel()->setBlock($this, $this, true);
|
return $this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
@ -168,7 +172,7 @@ class Leaves extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
if($item->getBlockToolType() & BlockToolType::TYPE_SHEARS){
|
if(($item->getBlockToolType() & BlockToolType::TYPE_SHEARS) !== 0){
|
||||||
return $this->getDropsForCompatibleTool($item);
|
return $this->getDropsForCompatibleTool($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ use pocketmine\item\ItemFactory;
|
|||||||
class Leaves2 extends Leaves{
|
class Leaves2 extends Leaves{
|
||||||
|
|
||||||
protected $id = self::LEAVES2;
|
protected $id = self::LEAVES2;
|
||||||
|
/** @var int */
|
||||||
protected $woodType = self::WOOD2;
|
protected $woodType = self::WOOD2;
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
|
@ -38,6 +38,7 @@ use function min;
|
|||||||
|
|
||||||
abstract class Liquid extends Transparent{
|
abstract class Liquid extends Transparent{
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
public $adjacentSources = 0;
|
public $adjacentSources = 0;
|
||||||
|
|
||||||
/** @var Vector3|null */
|
/** @var Vector3|null */
|
||||||
@ -90,6 +91,9 @@ abstract class Liquid extends Transparent{
|
|||||||
|
|
||||||
abstract public function getBucketEmptySound() : int;
|
abstract public function getBucketEmptySound() : int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
public function getFluidHeightPercent(){
|
public function getFluidHeightPercent(){
|
||||||
$d = $this->meta;
|
$d = $this->meta;
|
||||||
if($d >= 8){
|
if($d >= 8){
|
||||||
@ -207,8 +211,6 @@ abstract class Liquid extends Transparent{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns how many liquid levels are lost per block flowed horizontally. Affects how far the liquid can flow.
|
* Returns how many liquid levels are lost per block flowed horizontally. Affects how far the liquid can flow.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function getFlowDecayPerBlock() : int{
|
public function getFlowDecayPerBlock() : int{
|
||||||
return 1;
|
return 1;
|
||||||
@ -430,6 +432,9 @@ abstract class Liquid extends Transparent{
|
|||||||
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
|
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
protected function checkForHarden(){
|
protected function checkForHarden(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ class MelonStem extends Crops{
|
|||||||
$ev = new BlockGrowEvent($this, $block);
|
$ev = new BlockGrowEvent($this, $block);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
for($side = 2; $side <= 5; ++$side){
|
for($side = 2; $side <= 5; ++$side){
|
||||||
@ -64,7 +64,7 @@ class MelonStem extends Crops{
|
|||||||
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::MELON_BLOCK));
|
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::MELON_BLOCK));
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class MossyCobblestone extends Cobblestone{
|
class MossyCobblestone extends Cobblestone{
|
||||||
|
|
||||||
protected $id = self::MOSSY_COBBLESTONE;
|
protected $id = self::MOSSY_COBBLESTONE;
|
||||||
|
@ -64,13 +64,13 @@ class Mycelium extends Solid{
|
|||||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
$block = $this->getLevelNonNull()->getBlockAt($x, $y, $z);
|
||||||
if($block->getId() === Block::DIRT){
|
if($block->getId() === Block::DIRT){
|
||||||
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
||||||
$ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM));
|
$ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM));
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($block, $ev->getNewState());
|
$this->getLevelNonNull()->setBlock($block, $ev->getNewState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\event\block\BlockGrowEvent;
|
use pocketmine\event\block\BlockGrowEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
@ -47,7 +46,7 @@ class NetherWartPlant extends Flowable{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === Block::SOUL_SAND){
|
if($down->getId() === Block::SOUL_SAND){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, false, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, false, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -57,7 +56,7 @@ class NetherWartPlant extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::SOUL_SAND){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== Block::SOUL_SAND){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +71,7 @@ class NetherWartPlant extends Flowable{
|
|||||||
$ev = new BlockGrowEvent($this, $block);
|
$ev = new BlockGrowEvent($this, $block);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($this, $ev->getNewState(), false, true);
|
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class Pumpkin extends Solid{
|
|||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$this->meta = ((int) $player->getDirection() + 1) % 4;
|
$this->meta = ((int) $player->getDirection() + 1) % 4;
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ class PumpkinStem extends Crops{
|
|||||||
$ev = new BlockGrowEvent($this, $block);
|
$ev = new BlockGrowEvent($this, $block);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($this, $ev->getNewState(), true);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
for($side = 2; $side <= 5; ++$side){
|
for($side = 2; $side <= 5; ++$side){
|
||||||
@ -64,7 +64,7 @@ class PumpkinStem extends Crops{
|
|||||||
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::PUMPKIN));
|
$ev = new BlockGrowEvent($side, BlockFactory::get(Block::PUMPKIN));
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($side, $ev->getNewState(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ class Quartz extends Solid{
|
|||||||
if($this->getVariant() !== self::NORMAL){
|
if($this->getVariant() !== self::NORMAL){
|
||||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
}
|
}
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
|
@ -71,6 +71,7 @@ class Rail extends BaseRail{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||||
|
/** @var int[] $horizontal */
|
||||||
static $horizontal = [
|
static $horizontal = [
|
||||||
Vector3::SIDE_NORTH,
|
Vector3::SIDE_NORTH,
|
||||||
Vector3::SIDE_SOUTH,
|
Vector3::SIDE_SOUTH,
|
||||||
|
@ -45,14 +45,14 @@ class RedMushroom extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if(!$down->isTransparent()){
|
if(!$down->isTransparent()){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,16 @@ class RedstoneOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
return $this->getLevel()->setBlock($this, $this, true, false);
|
return $this->getLevelNonNull()->setBlock($this, $this, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||||
return false; //this shouldn't prevent block placement
|
return false; //this shouldn't prevent block placement
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
|
@ -59,7 +59,7 @@ class Sapling extends Flowable{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){
|
if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -70,9 +70,9 @@ class Sapling extends Flowable{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||||
//TODO: change log type
|
//TODO: change log type
|
||||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||||
|
|
||||||
$item->count--;
|
$item->pop();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ class Sapling extends Flowable{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,10 +93,10 @@ class Sapling extends Flowable{
|
|||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
if($this->level->getFullLightAt($this->x, $this->y, $this->z) >= 8 and mt_rand(1, 7) === 1){
|
if($this->level->getFullLightAt($this->x, $this->y, $this->z) >= 8 and mt_rand(1, 7) === 1){
|
||||||
if(($this->meta & 0x08) === 0x08){
|
if(($this->meta & 0x08) === 0x08){
|
||||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
Tree::growTree($this->getLevelNonNull(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||||
}else{
|
}else{
|
||||||
$this->meta |= 0x08;
|
$this->meta |= 0x08;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,19 +57,18 @@ class SignPost extends Transparent{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function place(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{
|
||||||
if($face !== Vector3::SIDE_DOWN){
|
if($face !== Vector3::SIDE_DOWN){
|
||||||
|
|
||||||
if($face === Vector3::SIDE_UP){
|
if($face === Vector3::SIDE_UP){
|
||||||
$this->meta = $player !== null ? (floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f) : 0;
|
$this->meta = $player !== null ? (floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f) : 0;
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||||
}else{
|
}else{
|
||||||
$this->meta = $face;
|
$this->meta = $face;
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,7 +78,7 @@ class SignPost extends Transparent{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +65,8 @@ class Skull extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->meta = $face;
|
$this->meta = $face;
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||||
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::SKULL, $this->getLevelNonNull(), TileSkull::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -56,11 +56,11 @@ abstract class Slab extends Transparent{
|
|||||||
$this->meta &= 0x07;
|
$this->meta &= 0x07;
|
||||||
if($face === Vector3::SIDE_DOWN){
|
if($face === Vector3::SIDE_DOWN){
|
||||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
|
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
|
||||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
$this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
@ -68,18 +68,18 @@ abstract class Slab extends Transparent{
|
|||||||
}
|
}
|
||||||
}elseif($face === Vector3::SIDE_UP){
|
}elseif($face === Vector3::SIDE_UP){
|
||||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
|
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
|
||||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
$this->getLevelNonNull()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else{ //TODO: collision
|
}else{ //TODO: collision
|
||||||
if($blockReplace->getId() === $this->id){
|
if($blockReplace->getId() === $this->id){
|
||||||
if($blockReplace->getVariant() === $this->getVariant()){
|
if($blockReplace->getVariant() === $this->getVariant()){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ abstract class Slab extends Transparent{
|
|||||||
if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
|
if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class SnowLayer extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced() : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return $this->meta < 7; //8 snow layers
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -57,10 +57,16 @@ class SnowLayer extends Flowable{
|
|||||||
return TieredTool::TIER_WOODEN;
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function canBeSupportedBy(Block $b) : bool{
|
||||||
|
return $b->isSolid() or ($b->getId() === $this->getId() and $b->getDamage() === 7);
|
||||||
|
}
|
||||||
|
|
||||||
public function place(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{
|
||||||
if($blockReplace->getSide(Vector3::SIDE_DOWN)->isSolid()){
|
if($blockReplace->getId() === $this->getId() and $blockReplace->getDamage() < 7){
|
||||||
//TODO: fix placement
|
$this->setDamage($blockReplace->getDamage() + 1);
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
}
|
||||||
|
if($this->canBeSupportedBy($blockReplace->getSide(Vector3::SIDE_DOWN))){
|
||||||
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -69,8 +75,8 @@ class SnowLayer extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if(!$this->getSide(Vector3::SIDE_DOWN)->isSolid()){
|
if(!$this->canBeSupportedBy($this->getSide(Vector3::SIDE_DOWN))){
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +86,7 @@ class SnowLayer extends Flowable{
|
|||||||
|
|
||||||
public function onRandomTick() : void{
|
public function onRandomTick() : void{
|
||||||
if($this->level->getBlockLightAt($this->x, $this->y, $this->z) >= 12){
|
if($this->level->getBlockLightAt($this->x, $this->y, $this->z) >= 12){
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class Sponge extends Solid{
|
class Sponge extends Solid{
|
||||||
|
|
||||||
protected $id = self::SPONGE;
|
protected $id = self::SPONGE;
|
||||||
|
@ -93,7 +93,7 @@ abstract class Stair extends Transparent{
|
|||||||
if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
||||||
$this->meta |= 0x04; //Upside-down stairs
|
$this->meta |= 0x04; //Upside-down stairs
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,13 @@ class StandingBanner extends Transparent{
|
|||||||
if($face !== Vector3::SIDE_DOWN){
|
if($face !== Vector3::SIDE_DOWN){
|
||||||
if($face === Vector3::SIDE_UP and $player !== null){
|
if($face === Vector3::SIDE_UP and $player !== null){
|
||||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
$this->getLevelNonNull()->setBlock($blockReplace, $this, true);
|
||||||
}else{
|
}else{
|
||||||
$this->meta = $face;
|
$this->meta = $face;
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player));
|
Tile::createTile(Tile::BANNER, $this->getLevelNonNull(), TileBanner::createNBT($this, $face, $item, $player));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class StandingBanner extends Transparent{
|
|||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,23 +46,23 @@ class Sugarcane extends Flowable{
|
|||||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
|
$ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK));
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
$this->getLevelNonNull()->setBlock($b, $ev->getNewState(), true);
|
||||||
}else{
|
}else{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->meta = 0;
|
$this->meta = 0;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$item->count--;
|
$item->pop();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class Sugarcane extends Flowable{
|
|||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->isTransparent() and $down->getId() !== self::SUGARCANE_BLOCK){
|
if($down->isTransparent() and $down->getId() !== self::SUGARCANE_BLOCK){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevelNonNull()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,17 +85,17 @@ class Sugarcane extends Flowable{
|
|||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||||
if($this->meta === 0x0F){
|
if($this->meta === 0x0F){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
$b = $this->getLevelNonNull()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
$this->getLevelNonNull()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->meta = 0;
|
$this->meta = 0;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
}else{
|
}else{
|
||||||
++$this->meta;
|
++$this->meta;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevelNonNull()->setBlock($this, $this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ class Sugarcane extends Flowable{
|
|||||||
public function place(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{
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === self::SUGARCANE_BLOCK){
|
if($down->getId() === self::SUGARCANE_BLOCK){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::SAND){
|
}elseif($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::SAND){
|
||||||
@ -112,7 +112,7 @@ class Sugarcane extends Flowable{
|
|||||||
$block2 = $down->getSide(Vector3::SIDE_WEST);
|
$block2 = $down->getSide(Vector3::SIDE_WEST);
|
||||||
$block3 = $down->getSide(Vector3::SIDE_EAST);
|
$block3 = $down->getSide(Vector3::SIDE_EAST);
|
||||||
if(($block0 instanceof Water) or ($block1 instanceof Water) or ($block2 instanceof Water) or ($block3 instanceof Water)){
|
if(($block0 instanceof Water) or ($block1 instanceof Water) or ($block2 instanceof Water) or ($block3 instanceof Water)){
|
||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -74,14 +74,17 @@ class TNT extends Solid{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function ignite(int $fuse = 80){
|
public function ignite(int $fuse = 80){
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
$this->getLevelNonNull()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
|
|
||||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||||
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
||||||
$nbt->setShort("Fuse", $fuse);
|
$nbt->setShort("Fuse", $fuse);
|
||||||
|
|
||||||
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt);
|
$tnt = Entity::createEntity("PrimedTNT", $this->getLevelNonNull(), $nbt);
|
||||||
|
|
||||||
if($tnt !== null){
|
if($tnt !== null){
|
||||||
$tnt->spawnToAll();
|
$tnt->spawnToAll();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user