mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-13 04:45:08 +00:00
Compare commits
976 Commits
api/3.0.0-
...
1.7dev-743
Author | SHA1 | Date | |
---|---|---|---|
a3fa8adf4a | |||
cacd0f5d8f | |||
3600542d78 | |||
e0ed877494 | |||
07bf1c9e22 | |||
b659a3d39f | |||
68b30108be | |||
f223fb2876 | |||
8bb785b7af | |||
806a2005d7 | |||
c794ced0ad | |||
f993358c5f | |||
1c12be6bf2 | |||
a1d9b8486e | |||
9397356ce4 | |||
e56e363dcc | |||
18b287c3ea | |||
9014eb72e9 | |||
82948726ed | |||
c601816586 | |||
d2d1df0447 | |||
f9b1afe4cf | |||
033cb8bd63 | |||
0ed9fcb641 | |||
efac23d4af | |||
48dc1c38f7 | |||
ffb3e2b47a | |||
ef816c0a52 | |||
3e35bc38e2 | |||
de0741f727 | |||
6fd4b9f1e2 | |||
6c8a1a5b80 | |||
3842ee15cf | |||
6c71b443e8 | |||
4a4900e5e7 | |||
26d4169fea | |||
7d88a8b315 | |||
41592a04b7 | |||
1d4bafb6ff | |||
28996f561f | |||
0658c0851b | |||
0df2064802 | |||
6543d96910 | |||
0bf5ab76fb | |||
8e1394bf53 | |||
6ddbdc9dc1 | |||
2a8be527d7 | |||
aca1422fca | |||
b0d0932ed9 | |||
fd5557861b | |||
1de7c5b114 | |||
2fb580db26 | |||
e5ca22a9a6 | |||
69ddaacc28 | |||
897a31e608 | |||
4943ff9dfc | |||
e36b38939c | |||
ecb3f9aeac | |||
f0696f77ef | |||
6813838754 | |||
65fe19ca71 | |||
a4f5cab12d | |||
29e06e30b2 | |||
3939e2d9dd | |||
2579438b84 | |||
95d42b9907 | |||
2eb6e075ae | |||
8f928915d9 | |||
3af8cf48b2 | |||
21c03670b6 | |||
0c868b16b6 | |||
1e67360048 | |||
3520dafd29 | |||
857b63ba8f | |||
9551e5b8e5 | |||
c7f15a556d | |||
efca9f0450 | |||
d728154e87 | |||
2e1a167bed | |||
6f6e3aaa21 | |||
9c65a2b890 | |||
beb5bf6dda | |||
7a5e5773b7 | |||
f1b0a4f1de | |||
751345c736 | |||
e850f34d76 | |||
8d7c65585c | |||
96f6362117 | |||
66c768d453 | |||
6fe7763db9 | |||
fda97decaa | |||
b3f44562e9 | |||
51350be190 | |||
7f4b5d282e | |||
94feecd44b | |||
45b02d92d4 | |||
fe4b5498e6 | |||
98b36fd73e | |||
07c7048433 | |||
f09cf92197 | |||
98eba11da5 | |||
a6c1e02847 | |||
b04cee12ea | |||
c4966404bb | |||
579c508761 | |||
43959bccb1 | |||
e6bd12dc2f | |||
7daca754b1 | |||
cb90e30bcf | |||
71d11c73f0 | |||
24116ba846 | |||
a0683dbb0f | |||
b6811b643c | |||
4d2549b50a | |||
1fb3274f37 | |||
6772a69c55 | |||
266a253c03 | |||
c62e1abf2f | |||
55f405f5c2 | |||
8fbd0e58f0 | |||
418d099a2e | |||
9d2eb5e911 | |||
b6c1124d50 | |||
03fda936a8 | |||
684fd46d09 | |||
90fc649441 | |||
0410df77aa | |||
0f30467f62 | |||
a84910f04c | |||
3ee225caec | |||
f963dbd10d | |||
debfbf0d93 | |||
5c37d298a6 | |||
3ca162f23f | |||
5f48433c95 | |||
33352638a9 | |||
db52501462 | |||
3a0cbd1cd4 | |||
1bdb68b7da | |||
6ce728169e | |||
06a3c7c478 | |||
70982c145b | |||
417f2d8998 | |||
7339c4ac2f | |||
43a0ede9d2 | |||
c747c7d025 | |||
c9e2e8980f | |||
9a956692de | |||
d30a6b60b7 | |||
41873bb115 | |||
8064152777 | |||
872df446bd | |||
376a615634 | |||
c16c9efdf3 | |||
c3cc6f9880 | |||
1e139743b8 | |||
bde0ba1100 | |||
50f273c041 | |||
db095f9705 | |||
f580f27ec7 | |||
a46029c0f6 | |||
1a615591e2 | |||
d19683b7dd | |||
f17b3b2a3b | |||
a0a2ea01bc | |||
5132ab6cd9 | |||
256bdf2581 | |||
8a3f8b4706 | |||
7264ce43ae | |||
66e475cbb8 | |||
1e896efff9 | |||
4db7a7e57f | |||
54b23968e7 | |||
bcb080e2b9 | |||
e5c58f9b04 | |||
af7aef70db | |||
3ea72a0bf9 | |||
be02fbb352 | |||
a67f7e3930 | |||
965c19375f | |||
63edcb8934 | |||
e7a012d69a | |||
99c55ac889 | |||
f14adf5827 | |||
c64b9ad63a | |||
dda71b06ae | |||
3c4dca7fdb | |||
ddbc5cf960 | |||
1edf69892a | |||
f10c2a2df2 | |||
3bbdc5ab5b | |||
082e3404c3 | |||
547833ae23 | |||
6e1df36188 | |||
329fe7d844 | |||
b7aaf54a6f | |||
6332814a04 | |||
9d4818d360 | |||
36f3accf4b | |||
8d08840ea4 | |||
7f0d0c9d63 | |||
bf55f03a3e | |||
a5c3fbdd7a | |||
a8bf2191b9 | |||
0688a86f57 | |||
2e11e448dd | |||
8bf275cb8b | |||
1896576a24 | |||
8f811c29d7 | |||
3a4f79629c | |||
375243860e | |||
a842a5319f | |||
c2b0f6af22 | |||
6490d99ac2 | |||
e0b063ac85 | |||
12ac2f4ac7 | |||
cc1951c7ba | |||
0e538ee51d | |||
1b4b832c8c | |||
4f8e4f0522 | |||
0ee78d2416 | |||
4c46087ffc | |||
bb3e72ea4b | |||
914e4c9a72 | |||
9fd7312629 | |||
24387d1efe | |||
3853938ef3 | |||
4ec8416f9a | |||
8aff793a4f | |||
d93ded9047 | |||
fbd04b0fe7 | |||
953f45c50f | |||
1822abc862 | |||
92e966686e | |||
3f50f88e2c | |||
532600ab67 | |||
78f8fe602c | |||
e75fbd7fb4 | |||
06f605879a | |||
4c7038f941 | |||
4bd4d42b82 | |||
f5ebfc3418 | |||
4ae278686c | |||
740786c99e | |||
6abf880e44 | |||
853411fa4f | |||
6e30d23254 | |||
717b36a983 | |||
90eed14cd6 | |||
4452e6ac93 | |||
66562f24fb | |||
56f1a6ba37 | |||
8c47a338df | |||
7c6535283e | |||
c669819bbb | |||
50f3231629 | |||
015cde2169 | |||
dc064dfa2e | |||
131a6a4d19 | |||
67a576722c | |||
b9b50dd5dc | |||
da3640357c | |||
0004e7429f | |||
e2e6b7516a | |||
b903161a5d | |||
99fe63b2a3 | |||
dbc180315e | |||
45983acc0d | |||
a02af1053f | |||
7de88b9040 | |||
58327d0514 | |||
db31d13f96 | |||
55d0684565 | |||
7e3cd24444 | |||
2088a43c56 | |||
3beccc47cd | |||
dfc2d1dfe6 | |||
1f1531810d | |||
a5fc77749f | |||
98cb7f2e10 | |||
e58db75396 | |||
a94c669730 | |||
45ee115b67 | |||
44e06f6a32 | |||
2e62c084a4 | |||
a3622dfa9d | |||
7c8a29151c | |||
8a90d159fe | |||
bf4076766e | |||
49dbd8b2c8 | |||
502dd14c67 | |||
74239eec69 | |||
3c936e1be8 | |||
16fd37a039 | |||
1ce961f688 | |||
d80f711d18 | |||
ebd3d207e4 | |||
31f0437c96 | |||
b06ca6eb0b | |||
67a09a9b16 | |||
51cec525ee | |||
a5f4dda918 | |||
e2d66ac96d | |||
d03fdd5f72 | |||
990a48d858 | |||
af68125872 | |||
5a0afa9f88 | |||
c301788864 | |||
472bf1a1ef | |||
1a4b653d07 | |||
d9f0546cb3 | |||
92a1f45175 | |||
0afe20c382 | |||
e94db980d7 | |||
2cb81b5f8d | |||
78cf875080 | |||
878f1bffb9 | |||
98ac6fc7be | |||
88318d740a | |||
d3e5733ea0 | |||
4703715063 | |||
523a7f0999 | |||
256527c953 | |||
b93691a177 | |||
48c5db4296 | |||
c564655f9b | |||
49301b0d74 | |||
8bc733514b | |||
c1a6711514 | |||
f477cfa1bf | |||
1f5f67e087 | |||
74967eed87 | |||
b88ffa3bdf | |||
79fd9b1c96 | |||
ed195e1167 | |||
667a54fd00 | |||
b22b493abb | |||
0badaeb8f4 | |||
c5ac6a7606 | |||
e9951b1b1f | |||
47f94eebd1 | |||
e9e22db1e7 | |||
75e469c380 | |||
686e1c4470 | |||
8d59843020 | |||
580b30b768 | |||
589ca45825 | |||
88ad43971a | |||
1fd9994056 | |||
808227d9a9 | |||
74b074753f | |||
3f854127ca | |||
9da19b5f15 | |||
78d24b9183 | |||
46afb7caf1 | |||
0ee452773d | |||
a39c9e8c8e | |||
32714d4564 | |||
feade9d982 | |||
373f085436 | |||
d2416d335e | |||
a8ad956b29 | |||
00a9ae6c95 | |||
a9df383346 | |||
19dc22d6b3 | |||
2fd61163bf | |||
5640bcb0b8 | |||
ea3c7383fb | |||
7e496afdd1 | |||
3bc3a0bb49 | |||
c75e62b38c | |||
3a80ec4db8 | |||
8abad33048 | |||
a91a4489d4 | |||
96348e0e44 | |||
dd8a772d43 | |||
dc553142c9 | |||
81fe00a0a5 | |||
6facd8b50f | |||
e709e3c653 | |||
eaba105614 | |||
12bbc764ec | |||
bee3c4f5cd | |||
bda40edebe | |||
5178373d8a | |||
28188e5ef4 | |||
7c2dccd2a6 | |||
adabfe78df | |||
0fdceb6736 | |||
ffa9a91a95 | |||
78bb951942 | |||
7508524b7b | |||
db4a8be240 | |||
3fe9963c84 | |||
db8a835a64 | |||
460d540dbc | |||
665130561e | |||
48a7627b96 | |||
235fc4cd2f | |||
e0654b85ba | |||
19315dfd06 | |||
f3ee605cd3 | |||
976d5583cc | |||
6adc813a7f | |||
769f3f75cd | |||
432d90bddd | |||
3a16985d45 | |||
bbbed22467 | |||
2794df34ab | |||
73cd195e76 | |||
0d2b171c2c | |||
aa399a1109 | |||
d4494687d1 | |||
6fe45a69c8 | |||
784ecef805 | |||
41f363d0c1 | |||
827ee5ff33 | |||
a4e955c0a4 | |||
733e61f815 | |||
0621d5c8ea | |||
a2d4baf8b9 | |||
23bc97e098 | |||
14e6e3694d | |||
0e64c3dad8 | |||
99f06c6c18 | |||
3ca9e6ae98 | |||
fd0b07a0aa | |||
6ece799998 | |||
a9c75a882a | |||
4437b67178 | |||
34d2047ac3 | |||
20d2ef9d38 | |||
eab7b93483 | |||
e84ab8fec2 | |||
a66a757f56 | |||
ddb7fd12f2 | |||
6ccb494f8d | |||
2ec7763bd6 | |||
d663887f9c | |||
6ebe3bfbea | |||
4533df17cf | |||
8ae663425f | |||
e95b1d4b00 | |||
8ad02c9a4e | |||
754e088ee8 | |||
451f5d0cd7 | |||
42ed03fd02 | |||
b51ec9e606 | |||
8d07f833fc | |||
372b97ba8f | |||
dea2942062 | |||
3614711a02 | |||
dcdea6a1f4 | |||
b7cd8dbfa9 | |||
1486b5aa71 | |||
f8e6438efe | |||
caf9eaa2da | |||
6db5596b00 | |||
4ed1a39638 | |||
a770e681dc | |||
a342a61037 | |||
91c256f1a9 | |||
93443992be | |||
ea09cc06c7 | |||
67af4d3b65 | |||
4a78bfaa18 | |||
bb6b100443 | |||
8aca373194 | |||
7e490ccdf2 | |||
991d321928 | |||
600d80331a | |||
f79e4237df | |||
6ce9e79cd5 | |||
e88aa385a3 | |||
5303a710ac | |||
dd085b35cc | |||
6ff1088a57 | |||
d1db27016e | |||
c55bc2d7e9 | |||
747477dfcf | |||
48fefae920 | |||
52d0ad8a61 | |||
bddd7e0eee | |||
883898682f | |||
daf457213d | |||
bd2cb85861 | |||
1d651046c9 | |||
1dea25d123 | |||
b6264d188e | |||
2635c85873 | |||
3b85e558ce | |||
d48880e31b | |||
93d60a9beb | |||
a82efc44aa | |||
6daa0135d5 | |||
08092f17e0 | |||
716c1f29b4 | |||
0072af95cb | |||
0df3b00de4 | |||
13e5718463 | |||
270e0c076c | |||
3765511317 | |||
8daa8deae9 | |||
e055ce9526 | |||
3ed8855894 | |||
f25255e46c | |||
7db8345424 | |||
bc7ba3b3c1 | |||
1dd2203ee5 | |||
554096953b | |||
55a1731da3 | |||
ba3fe20227 | |||
7b04049bb7 | |||
30211bee82 | |||
e318dc12a5 | |||
967ce99b03 | |||
9bdda54aec | |||
18e4e5364f | |||
98cfd0b398 | |||
a245615531 | |||
0a19a2611a | |||
50be26958a | |||
67c6fca0ed | |||
d99e9513b0 | |||
5a353012de | |||
087badcb48 | |||
d9769360fe | |||
9fb93985d6 | |||
2b22d5d8cc | |||
2db13bd114 | |||
11cc20972f | |||
4821e7386d | |||
584810780a | |||
55de75b914 | |||
2a1a17aa7a | |||
90165cf99d | |||
a4ca3f1d1c | |||
f783789e5a | |||
43be64baed | |||
5c92c8a9d3 | |||
d2dc49cd9c | |||
f148c366f9 | |||
91d84aaff4 | |||
6b78ba8c25 | |||
b9de2e8b4b | |||
15764543b4 | |||
2c34648c3d | |||
3e3157cbe1 | |||
07abd61f73 | |||
a456b7cfca | |||
ece37d1e19 | |||
cccaade00c | |||
7f0a961526 | |||
68ac4f538f | |||
f14b7cbf78 | |||
f4ff5d81ea | |||
28a840d161 | |||
292e462ea0 | |||
c8379efbce | |||
1b5746fd97 | |||
4a0ac01697 | |||
9bcb41fb21 | |||
20b86bdea8 | |||
0b1a9ba062 | |||
45b003ac2e | |||
769a50faa5 | |||
af85659c63 | |||
95fa1824c8 | |||
251d5d7946 | |||
3b5eb45ff5 | |||
fd847f02ad | |||
18d3a97466 | |||
04668d534d | |||
092cc2750f | |||
68809d992b | |||
1641183674 | |||
72531209bf | |||
8c6ab3e634 | |||
97e2d64592 | |||
a547e2cca8 | |||
cdebb62c35 | |||
2e73fd7f8c | |||
51906daad0 | |||
ce67bc620a | |||
bcefc3a54b | |||
f5378ab604 | |||
dab7cfde1c | |||
6e1318b522 | |||
cd8006e242 | |||
f5abed95ec | |||
489b9fc29b | |||
b524b841c5 | |||
41f292d995 | |||
fd8a562e02 | |||
cc553a157d | |||
a6d1cc27ec | |||
d8c90be5b8 | |||
060426ff12 | |||
eeea4fa06a | |||
401e33dd85 | |||
2893aac3ac | |||
c5c74c1898 | |||
423bea4b57 | |||
e3567faa94 | |||
4b5040dcc7 | |||
21c79b0645 | |||
7b5df10b6a | |||
c4fe9ad32d | |||
60b62a4890 | |||
061a9444cc | |||
3eb73ab468 | |||
15d6fd86e2 | |||
0c092a7ceb | |||
b9501ef415 | |||
5afe4fdb5b | |||
cc7ed7a28f | |||
7e9b89e48a | |||
63fccd4682 | |||
35e7aca88f | |||
9413f155ce | |||
6569fdbe04 | |||
d8b1757ebc | |||
8f0ee84277 | |||
b7a9e10d49 | |||
be2d134994 | |||
7b1bfc0520 | |||
59d9d6a7df | |||
8d095dff6c | |||
4981931c4a | |||
5dafabbec2 | |||
2a5d954c67 | |||
287f08cbd1 | |||
76469e1d5f | |||
c4c83e23ca | |||
eccc7bf7b3 | |||
78ca2f2e58 | |||
cef9c4621c | |||
151681bd80 | |||
327907988b | |||
97dbf61236 | |||
2be8b576ef | |||
6dbdefafdd | |||
9598b8cee4 | |||
246c6daef6 | |||
2601e35990 | |||
bdfd9c95dd | |||
cd44551d64 | |||
cebb4b35f6 | |||
7267f1a520 | |||
66a3354b31 | |||
ac7384a2b4 | |||
748beaaaa7 | |||
58788b4bc7 | |||
ae76ac82c8 | |||
e4000f8f03 | |||
ebcce43131 | |||
119913da30 | |||
1a88f59b23 | |||
fdfe70b9f2 | |||
3bda1473e7 | |||
29cd071108 | |||
1810088acf | |||
51e4a62e7b | |||
aa91183504 | |||
ae5aa31e7b | |||
7239dbbb1a | |||
3738ab1f8a | |||
8fafef2f7f | |||
5b9515b20f | |||
69e29236aa | |||
e8453b7872 | |||
00bf190e54 | |||
81dee2f9fc | |||
f6875705a1 | |||
d294d5a91b | |||
a7e9aa4bc1 | |||
628ff9449e | |||
7f5fe137d1 | |||
18448cbcb8 | |||
b0104099fe | |||
68195c64ce | |||
27aa51bac4 | |||
eac1d76e8b | |||
a8c6e14d02 | |||
bf68a6a9fc | |||
4dfd171af0 | |||
fc9c264e77 | |||
04ba41c58c | |||
736cc927ff | |||
4be7885ee4 | |||
7dc5dc3a9f | |||
f7ee78233b | |||
88807e8b22 | |||
5a6812357b | |||
ca401ec3f5 | |||
9bbebaa071 | |||
76117e7fa0 | |||
088a44ea3a | |||
b54f256fea | |||
c09d782503 | |||
b3b3ee7c56 | |||
ab5bbaa7bd | |||
afa37bd2aa | |||
49ac2555ce | |||
edd0189d59 | |||
b76b9d53fe | |||
42dd9d6abd | |||
9cd7f39c03 | |||
f6e30d4225 | |||
27798c69ee | |||
a33be643c4 | |||
a06ff3d96b | |||
e6cecabf3f | |||
c273a46537 | |||
c448f4a3b5 | |||
86b76bfcab | |||
7ba193dc2e | |||
f565791e41 | |||
bc0434913e | |||
9bc8d8db79 | |||
d0bf0ff083 | |||
7dc1fc54b1 | |||
bae42dc0d9 | |||
ab809f8a2b | |||
2162675b64 | |||
8f63117dac | |||
1c9b4f3e21 | |||
48d2d7e422 | |||
52bd042bde | |||
4b63a22f8c | |||
c47f1f572c | |||
7a77bb0402 | |||
90cb018de2 | |||
992c4ce6a0 | |||
78af87a572 | |||
c79a5509f6 | |||
827ee5d4f9 | |||
f5b0cbb337 | |||
18777a9041 | |||
13d50aff62 | |||
5b191327bc | |||
8811188e71 | |||
38fad4b963 | |||
e64076ec81 | |||
ccbdb77618 | |||
91c6086ae1 | |||
85ec7d9732 | |||
10f597cd64 | |||
6e5759b1d1 | |||
03d3e595d6 | |||
8ca59d12e9 | |||
89e4defa29 | |||
f5534a9ab0 | |||
28bce8d48c | |||
3c02a6a8ed | |||
6b0ac8adb8 | |||
38ec5da260 | |||
240cc3043a | |||
043ae487de | |||
f12701e582 | |||
6e961ae897 | |||
e1d10f595a | |||
178dd1b981 | |||
826ec90856 | |||
0523f26613 | |||
5190d9c1e2 | |||
c8fd0eaf8b | |||
53ef9b653a | |||
030cc4afb0 | |||
9bd7f771d3 | |||
10f6a0eef0 | |||
d0a96f35da | |||
65e908a403 | |||
d7091f4460 | |||
c6670b2e74 | |||
194278d986 | |||
0e2e9aab2e | |||
1b5fed983b | |||
5aba87b250 | |||
f01ce8e994 | |||
d89b8cf12e | |||
6aa9b081e9 | |||
dbed80386a | |||
cefad0444c | |||
ee052f91d4 | |||
ef6250967f | |||
61cfdac6a1 | |||
fd7fb10223 | |||
6897cb4774 | |||
8e7ad532f1 | |||
9e8366725a | |||
b14ecc18c4 | |||
55720d9f0a | |||
0262465a26 | |||
7996a7b08c | |||
4a1fc1bdf7 | |||
85b2b2ae2e | |||
38e11aae5e | |||
f0755d1659 | |||
fd33a65e3b | |||
7baadf9dad | |||
ca23864e4c | |||
8728547a11 | |||
90fb3c5e12 | |||
1fb6d12a6b | |||
1323d89139 | |||
136ab1dba1 | |||
8cae20e818 | |||
ff2b3bfa2a | |||
361b262d3a | |||
1fd7f441b4 | |||
3f56d6ddc8 | |||
1e4cbb0dd9 | |||
a99eee9def | |||
bdee746e46 | |||
642c7733cd | |||
c8199e14ad | |||
0f37bc35ba | |||
8dc3d019f6 | |||
bd64172750 | |||
0e51820dfb | |||
30d2318bb7 | |||
63634d7e7d | |||
d941bf8e74 | |||
8c9d9626ab | |||
6b34c47c96 | |||
77241e14ce | |||
15b08c1417 | |||
4d1daecd91 | |||
53e5db5142 | |||
ad72fe6232 | |||
8b33f711d0 | |||
319735db3a | |||
c283d87494 | |||
be27e03126 | |||
c1c290cd39 | |||
5267c571e9 | |||
0fac3b9a9d | |||
23a38400e2 | |||
297172d111 | |||
825d4f9702 | |||
1d31958ce6 | |||
130a60f2b2 | |||
07268e4b37 | |||
441efc4ae2 | |||
88bd7713c5 | |||
aaa3b6e59a | |||
25adac8859 | |||
8d0b881762 | |||
16cb75ef38 | |||
3b9689674d | |||
7f5d8cc900 | |||
8761256246 | |||
8c363cb571 | |||
10b765e17a | |||
0eb866bf25 | |||
c46caa38e1 | |||
17d949f476 | |||
c569f55933 | |||
01d8d216ca | |||
f1ccee505b | |||
a61adb5991 | |||
cae1a3bb4b | |||
6681bd250a | |||
38293913ee | |||
8493ce8a35 | |||
9b7868238c | |||
953c1ef4ec | |||
021a9a4820 | |||
5b7565664c | |||
ebdfbe6bb9 | |||
85ff236461 | |||
d7422d9283 | |||
fcb3c4820e | |||
c72ef605b9 | |||
e274f1b7f8 | |||
69514c5763 | |||
12c154badf | |||
c9ee206fe6 | |||
6877ac35eb | |||
78d49f8e66 | |||
de6ebc5791 | |||
2cff5a500c | |||
f077ba4748 | |||
dcf34b7188 | |||
ca84532640 | |||
75e32b11b7 | |||
9f44b2ed75 | |||
1c02c747ca | |||
a6c0f1512c | |||
604d8ecf9a | |||
5d75d3d5b6 | |||
8b13b520e0 | |||
00e4fff259 | |||
a06c934f4d | |||
5335ed9394 | |||
16aeb0ac85 | |||
8caabd3267 | |||
ddfe828445 | |||
67ad2d25b9 | |||
190f4dd6ab | |||
6d6283b7f3 | |||
a3d21de559 | |||
ece0692229 | |||
b5d2402c9b | |||
c7fd3eb725 | |||
5433a3f964 | |||
2c3d7c49f9 | |||
76acb1da7b | |||
17518195d1 | |||
2443a57234 | |||
95752ef542 | |||
da4c9cf404 | |||
770616d4ab | |||
445a67954d | |||
4250e99e3a | |||
121777375e | |||
93e149e91c | |||
1f70a7830e | |||
159b2e3d5e | |||
e0307411da | |||
e5e76d4c93 | |||
2688228a6f | |||
e15eefc58f | |||
8853452feb | |||
09c53552c1 | |||
1f6d325328 | |||
f35ca147bb | |||
b6fb2bca13 | |||
4f1302adf2 | |||
643e10037c | |||
eda2473e78 | |||
4b65fef957 | |||
fbe2567e58 | |||
5fc50aeda5 | |||
9be1b929a5 | |||
6480f7a989 | |||
1576a79644 | |||
02cbf800d0 | |||
5a4fbc6f5a | |||
83fcec3e94 | |||
5d436a06ec | |||
8958b3c51c | |||
c1ff7bbef4 | |||
74ee94b385 | |||
5208ad885c | |||
51be88c698 | |||
0dc8362536 | |||
9bae4d8ef6 | |||
bb4808c23e | |||
3025f76cd0 | |||
1e539c4e3b | |||
590003d7c1 | |||
72d40860f3 | |||
d3d1e32309 | |||
36d47a33f3 | |||
260179197b | |||
75644b5df2 | |||
3ad1b1ba7f | |||
b4c2305c7f | |||
1d0f0a2999 | |||
8ca37b3813 | |||
2ba601b6e9 | |||
7958fffa07 | |||
98e0a2ecba | |||
899e318a88 | |||
989505c42c | |||
d9da9accbc | |||
711d62b5eb | |||
49506659e0 | |||
7886918140 | |||
8a151dc373 | |||
58a12fdfa3 | |||
50dffeb6a1 | |||
63d2b341b9 | |||
77cd8e7799 |
19
.github/ISSUE_TEMPLATE.md
vendored
19
.github/ISSUE_TEMPLATE.md
vendored
@ -3,16 +3,17 @@
|
|||||||
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
|
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
|
||||||
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
||||||
- https://forums.pmmp.io - PMMP Forums
|
- https://forums.pmmp.io - PMMP Forums
|
||||||
-->
|
|
||||||
<!--- Any issues requesting updates to new versions of MCPE will be treated as spam. We do not need issues to tell us that there is a new version available. -->
|
|
||||||
<!---
|
|
||||||
Write a short description about the issue
|
|
||||||
|
|
||||||
If you are reporting a regression or unexpected behaviour, please include the below information:
|
Any issues requesting updates to new versions of MCPE will be treated as spam.
|
||||||
Expected result: What were you expecting to happen?
|
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
|
||||||
Actual result: What actually happened?
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!--- Write a short description about the issue -->
|
||||||
|
|
||||||
|
<!--- If you are reporting a regression or unexpected behaviour, please include the below information: -->
|
||||||
|
- Expected result: What were you expecting to happen?
|
||||||
|
- Actual result: What actually happened?
|
||||||
|
|
||||||
### Steps to reproduce the issue
|
### Steps to reproduce the issue
|
||||||
<!--- help us find the problem by adding steps to reproduce the issue -->
|
<!--- help us find the problem by adding steps to reproduce the issue -->
|
||||||
1. ...
|
1. ...
|
||||||
@ -21,9 +22,9 @@ Actual result: What actually happened?
|
|||||||
### OS and versions
|
### OS and versions
|
||||||
<!--- use the 'version' command in PocketMine-MP
|
<!--- use the 'version' command in PocketMine-MP
|
||||||
|
|
||||||
NOTE: LATEST is not a valid version. PocketMine version should include Jenkins build number and/or git commit hash.
|
NOTE: LATEST is not a valid version. PocketMine-MP version should include Jenkins build number and/or git commit hash.
|
||||||
|
|
||||||
NO support whatsoever will be provided for forks or spoons of PocketMine. Issues relating to non-official distributions will be closed as spam. Please send such issues to whoever is responsible for the fork or spoon you are using.
|
NO support whatsoever will be provided for third-party modified variants of PocketMine-MP. Issues relating to third-party modifications will be closed as spam.
|
||||||
|
|
||||||
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
||||||
-->
|
-->
|
||||||
|
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -33,4 +33,8 @@ Requires translations:
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
<!-- Attach scripts or actions to test this pull request, as well as the result -->
|
<!--
|
||||||
|
Details should be provided of tests done. Simply saying "tested" or equivalent is not acceptable.
|
||||||
|
|
||||||
|
Attach scripts or actions to test this pull request, as well as the result
|
||||||
|
-->
|
||||||
|
12
.gitignore
vendored
12
.gitignore
vendored
@ -1,8 +1,9 @@
|
|||||||
players/*
|
players/*
|
||||||
worlds/*
|
worlds/*
|
||||||
plugins/*
|
plugins/*
|
||||||
bin/*
|
bin*/*
|
||||||
timings/*
|
timings/*
|
||||||
|
crashdumps/*
|
||||||
*.log
|
*.log
|
||||||
*.txt
|
*.txt
|
||||||
*.phar
|
*.phar
|
||||||
@ -28,3 +29,12 @@ Desktop.ini
|
|||||||
# Sphinx-doc
|
# Sphinx-doc
|
||||||
/docs/build/
|
/docs/build/
|
||||||
!/docs/requirements.txt
|
!/docs/requirements.txt
|
||||||
|
|
||||||
|
# Composer
|
||||||
|
vendor/*
|
||||||
|
|
||||||
|
# Travis files
|
||||||
|
test_data/*
|
||||||
|
|
||||||
|
# Doxygen
|
||||||
|
Documentation/*
|
||||||
|
7
.gitmodules
vendored
7
.gitmodules
vendored
@ -1,10 +1,3 @@
|
|||||||
[submodule "src/raklib"]
|
|
||||||
path = src/raklib
|
|
||||||
url = https://github.com/pmmp/RakLib.git
|
|
||||||
branch = master
|
|
||||||
[submodule "src/spl"]
|
|
||||||
path = src/spl
|
|
||||||
url = https://github.com/pmmp/PocketMine-SPL.git
|
|
||||||
[submodule "src/pocketmine/lang/locale"]
|
[submodule "src/pocketmine/lang/locale"]
|
||||||
path = src/pocketmine/lang/locale
|
path = src/pocketmine/lang/locale
|
||||||
url = https://github.com/pmmp/PocketMine-Language.git
|
url = https://github.com/pmmp/PocketMine-Language.git
|
||||||
|
17
.travis.yml
17
.travis.yml
@ -1,12 +1,21 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 7.0
|
- 7.2
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- pecl install channel://pecl.php.net/pthreads-3.1.6
|
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||||
- pecl install channel://pecl.php.net/weakref-0.3.3
|
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
|
||||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.0
|
- git clone https://github.com/krakjoe/pthreads.git
|
||||||
|
- cd pthreads
|
||||||
|
- git checkout d32079fb4a88e6e008104d36dbbf0c2dd7deb403
|
||||||
|
- phpize
|
||||||
|
- ./configure
|
||||||
|
- make
|
||||||
|
- make install
|
||||||
|
- cd ..
|
||||||
|
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||||
|
- composer install
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./tests/travis.sh
|
- ./tests/travis.sh
|
||||||
|
@ -5,58 +5,48 @@
|
|||||||
|
|
||||||
## Creating an Issue
|
## Creating an Issue
|
||||||
- If you are reporting a bug:
|
- If you are reporting a bug:
|
||||||
- **make sure that you are using the latest supported version** before opening an issue.
|
- **make sure that you are using the latest supported version** before opening an issue.
|
||||||
- **test it on a clean test server, WITHOUT PLUGINS**, to see if the issue still occurs. If not then it may be a plugin issue. Please also indicate the result of such tests.
|
- **test it on a clean test server, WITHOUT PLUGINS**, to see if the issue still occurs. If not then it may be a plugin issue. Please also indicate the result of such tests.
|
||||||
|
- **[Search the issue tracker](https://github.com/pmmp/PocketMine-MP/issues?utf8=%E2%9C%93&q=is%3Aissue)** to check if anyone has already reported it, to avoid needlessly creating duplicate issues. Make sure you also check closed issues, as an issue you think is valid may already have been resolved.
|
||||||
- [Search the issue tracker](https://github.com/pmmp/PocketMine-MP/issues?utf8=%E2%9C%93&q=is%3Aissue) to check if anyone has already reported it, to avoid needlessly creating duplicate issues. Make sure you also check closed issues, as an issue you think is valid may already have been resolved.
|
- **Do not report plugin issues here.** If your issue is related to a plugin, contact the plugin's original author instead.
|
||||||
|
|
||||||
- If your issue is related to a plugin, **do not report here, contact the plugin's original author** instead.
|
|
||||||
|
|
||||||
- **Support requests are not bugs.** Issues such as "How do I do this" are not bugs and will be closed. If you need help, please see [here](README.md#discussion) and do not misuse our issue tracker.
|
- **Support requests are not bugs.** Issues such as "How do I do this" are not bugs and will be closed. If you need help, please see [here](README.md#discussion) and do not misuse our issue tracker.
|
||||||
|
|
||||||
- **No generic titles** such as "Question", "Help", "Crash Report" etc. A good issue report provides a quick summary in the title. If you just got a crash report but you don't understand it, please look for a line starting with `Message`. It summarizes the bug.
|
- **No generic titles** such as "Question", "Help", "Crash Report" etc. A good issue report provides a quick summary in the title. If you just got a crash report but you don't understand it, please look for a line starting with `Message`. It summarizes the bug.
|
||||||
|
- **Provide information in the issue body, not in the title.** No tags like `[BUG]` are allowed in the title, including `[SOLVED]` for solved issues.
|
||||||
- Information must be provided in the issue body, not in the title. No tags like `[BUG]` are allowed in the title, including `[SOLVED]` for solved issues.
|
- **No generic issue reports.** For bugs, it is the issue author's responsibility to provide us an issue that is **trackable, debuggable, reproducible, reported professionally and is an actual bug**.
|
||||||
|
<br>Valid issue reports must include instructions how to reproduce the issue or a crashdump/backtrace (unless the cause of the issue is obvious).
|
||||||
- Similarly, no generic issue reports. For bugs, it is the issue author's responsibility to provide us an issue that is **trackable, debuggable, reproducible, reported professionally and is an actual bug**.
|
<br>**If you do not provide us with a summary or instructions on how to reproduce the issue, it will be treated as spam and will therefore be closed.**
|
||||||
<br><br>Valid issue reports must include instructions how to reproduce the issue or a crashdump/backtrace (unless the cause of the issue is obvious).
|
<br>In simple words, if the issue cannot be properly confirmed to be valid or lacks required information, the issue will be closed until further information is provided.
|
||||||
<br><br>**If you do not provide us with a summary or instructions on how to reproduce the issue, it will be treated as spam and will therefore be closed.**
|
|
||||||
<br><br>In simple words, if the issue cannot be properly confirmed to be valid or lacks required information, the issue will be closed until further information is provided.
|
|
||||||
|
|
||||||
- To express appreciation, objection, confusion or other supported reactions on pull requests, issues or comments on them, use GitHub [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) rather than posting an individual comment with an emoji only. This helps keeping the issue/pull request conversation clean and readable.
|
- To express appreciation, objection, confusion or other supported reactions on pull requests, issues or comments on them, use GitHub [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) rather than posting an individual comment with an emoji only. This helps keeping the issue/pull request conversation clean and readable.
|
||||||
|
|
||||||
- If your issue is related to the PocketMine-MP website, forums, etc., please [talk to a human directly](README.md#discussion).
|
- If your issue is related to the PocketMine-MP website, forums, etc., please [talk to a human directly](README.md#discussion).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing Code
|
## Contributing
|
||||||
- To contribute code to the repository, [fork it on GitHub](https://github.com/pmmp/PocketMine-MP/fork), create a branch on your fork, and make your changes on your fork. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project to compare your branch to ours and propose your changes to our repository. We use the Pull Request system to allow members of the team to review changes before they are merged.
|
To contribute to the repository, [fork it on GitHub](https://github.com/pmmp/PocketMine-MP/fork), create a branch on your fork, and make your changes on your fork. You can then make a [pull request](https://github.com/pmmp/PocketMine-MP/pull/new) to the project to compare your branch to ours and propose your changes to our repository. We use the Pull Request system to allow members of the team to review changes before they are merged.
|
||||||
|
|
||||||
- By proposing a pull request to the project, you agree to your code being distributed within PocketMine-MP under the [LGPL license](LICENSE).
|
### Licensing
|
||||||
|
By proposing a pull request to the project, you agree to your code being distributed within PocketMine-MP under the [LGPL license](LICENSE).
|
||||||
|
|
||||||
- At PocketMine, **we enforce a very high standard for contributions**. This is because PocketMine-MP and its related projects are used very widely in production. While this might seem like we are being mean at times, **our priority is what is best for PocketMine-MP itself**. We try to ensure that our project's codebase is as clean as possible and ensure that only top-quality material makes it through to PocketMine-MP itself. **If a contribution does not live up to our standards, changes may be requested or the pull request may be closed.**
|
### Contribution standards
|
||||||
|
- **We enforce a very high standard for contributions**. This is because PocketMine-MP and its related projects are used very widely in production. While this might seem like we are being mean at times, **our priority is what is best for PocketMine-MP itself**.
|
||||||
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
|
We try to ensure that our project's codebase is as clean as possible and ensure that only top-quality material makes it through to PocketMine-MP itself.
|
||||||
|
- **If a contribution does not meet our standards, changes may be requested or the pull request may be closed.**
|
||||||
- **Avoid using GitHub Web Editor**. The web editor lacks most useful GIT features and **should only be used for very minor changes**. It is immediately clear if the web editor has been used, and if so the PR is more likely to be rejected. If you want to make serious contributions, **please learn how to use [GIT version control](https://git-scm.com/)**.
|
|
||||||
|
|
||||||
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit. **Cherry-picking is the politer way to copy somebody's changes** and retains all the original accreditation, so there is no need for copy-pasted commits with descriptions like `Some code, thanks @exampleperson`.
|
|
||||||
|
|
||||||
- In addition to the above, **make sure you can explain your changes**. If you can't provide a good explanation of changes, your PR may be rejected.
|
|
||||||
|
|
||||||
|
### Pull requests
|
||||||
- **Create a new branch for each pull request.** Do not create a pull request with commits that exist in another pull request.
|
- **Create a new branch for each pull request.** Do not create a pull request with commits that exist in another pull request.
|
||||||
|
|
||||||
- **Code should use the same style as in PocketMine-MP.** See [below](#code-syntax) for an example.
|
|
||||||
|
|
||||||
- **The code must be clear** and written in English, comments included.
|
|
||||||
|
|
||||||
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||||
|
- **Do not include multiple unrelated changes in one commit.** An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set. See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits. See the [documentation on `git add`](https://git-scm.com/docs/git-add) for information on how to isolate local changes for committing.
|
||||||
- **Try to stick to one change per commit.** This ensures that if you create a PR with several changes, we can decide which ones we wish to include and which ones not to include.
|
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
|
||||||
|
- **It is inadvisable to create large pull requests with lots of changes** unless this has been discussed with the team beforehand. Large pull requests are difficult to review, and such pull requests may end up being closed. The only exception is when all features in the pull request are related to each other, and share the same core changes.
|
||||||
- **It is inadvisable to create pull requests with large commits** unless this has been discussed with the team beforehand. Large pull requests are difficult to review, and such pull requests may end up being closed. The only exception is when all features in the pull request are related to each other, and share the same core changes.
|
|
||||||
|
|
||||||
- **You may be asked to rebase your pull request** if the branch becomes outdated and/or if possibly conflicting changes are made to the target branch. To see how to do this, read [this page](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request).
|
- **You may be asked to rebase your pull request** if the branch becomes outdated and/or if possibly conflicting changes are made to the target branch. To see how to do this, read [this page](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request).
|
||||||
|
- **Details should be provided of tests done.** Simply saying "Tested" or equivalent is not acceptable.
|
||||||
|
|
||||||
|
### Code contributions
|
||||||
|
- **Avoid using GitHub Web Editor**. The web editor lacks most useful GIT features and **should only be used for very minor changes**. It is immediately clear if the web editor has been used, and if so the PR is more likely to be rejected. If you want to make serious contributions, **please learn how to use [GIT version control](https://git-scm.com/)**.
|
||||||
|
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit. **Cherry-picking is the politer way to copy somebody's changes** and retains all the original accreditation, so there is no need for copy-pasted commits with descriptions like `Some code, thanks @exampleperson`.
|
||||||
|
- **Make sure you can explain your changes**. If you can't provide a good explanation of changes, your PR may be rejected.
|
||||||
|
- **Code should use the same style as in PocketMine-MP.** See [below](#code-syntax) for an example.
|
||||||
|
- **The code must be clear** and written in English, comments included.
|
||||||
|
|
||||||
|
|
||||||
**Thanks for contributing to PocketMine-MP!**
|
**Thanks for contributing to PocketMine-MP!**
|
||||||
@ -78,17 +68,18 @@ It is mainly [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accept
|
|||||||
- Strings SHOULD use the double quote `"` except when the single quote is required.
|
- Strings SHOULD use the double quote `"` except when the single quote is required.
|
||||||
- All code SHOULD have parameter and type declarations where possible.
|
- All code SHOULD have parameter and type declarations where possible.
|
||||||
- Strict types SHOULD be enabled on new files where it is sensible to do so.
|
- Strict types SHOULD be enabled on new files where it is sensible to do so.
|
||||||
|
- All constant declarations SHOULD be preceded by a visibility modifier.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\example;
|
namespace pocketmine\example;
|
||||||
|
|
||||||
class ExampleClass{
|
class ExampleClass{
|
||||||
|
|
||||||
const EXAMPLE_CLASS_CONSTANT = 1;
|
public const EXAMPLE_CLASS_CONSTANT = 1;
|
||||||
|
|
||||||
public $examplePublicVariable = "defaultValue";
|
public $examplePublicVariable = "defaultValue";
|
||||||
private $examplePrivateVariable;
|
private $examplePrivateVariable;
|
||||||
@ -99,7 +90,7 @@ class ExampleClass{
|
|||||||
* @param string $firstArgument the first argument
|
* @param string $firstArgument the first argument
|
||||||
* @param string|null $secondArgument default null
|
* @param string|null $secondArgument default null
|
||||||
*/
|
*/
|
||||||
public function __construct(string $firstArgument, &$secondArgument = null){
|
public function __construct(string $firstArgument, ?string &$secondArgument = null){
|
||||||
if($firstArgument === "exampleValue"){ //Remember to use === instead of == when possible
|
if($firstArgument === "exampleValue"){ //Remember to use === instead of == when possible
|
||||||
//do things
|
//do things
|
||||||
}elseif($firstArgument === "otherValue"){
|
}elseif($firstArgument === "otherValue"){
|
||||||
@ -119,7 +110,6 @@ class ExampleClass{
|
|||||||
public function doStuff(string $stuff) : string{
|
public function doStuff(string $stuff) : string{
|
||||||
return $stuff;
|
return $stuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -133,4 +123,4 @@ class ExampleClass{
|
|||||||
* After voting has been closed, no further votes will be counted.
|
* After voting has been closed, no further votes will be counted.
|
||||||
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
|
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
|
||||||
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
|
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
|
||||||
* RFCs with complex voting options will specify the vote percentage or other details.
|
* RFCs with complex voting options will specify the vote percentage or other details.
|
||||||
|
@ -10,7 +10,6 @@ If you don't find what you're looking for there, [talk to a human](#discussion).
|
|||||||
|
|
||||||
### Discussion
|
### Discussion
|
||||||
- [Forums](https://forums.pmmp.io/)
|
- [Forums](https://forums.pmmp.io/)
|
||||||
- [#pmmp + #pocketmine channel IRC](http://webchat.freenode.net/?channels=pmmp,pocketmine)
|
|
||||||
|
|
||||||
### Plugins
|
### Plugins
|
||||||
There are a very wide range of already-written plugins available which you can use to customise your server. Check out [Poggit](https://poggit.pmmp.io), or just search GitHub.
|
There are a very wide range of already-written plugins available which you can use to customise your server. Check out [Poggit](https://poggit.pmmp.io), or just search GitHub.
|
||||||
@ -23,7 +22,10 @@ There are a very wide range of already-written plugins available which you can u
|
|||||||
Yes you can! Contributions are welcomed provided that they comply with our [Contributing Guidelines](CONTRIBUTING.md). Please ensure you read the relevant sections of the guidelines carefully before making a Pull Request or opening an Issue.
|
Yes you can! Contributions are welcomed provided that they comply with our [Contributing Guidelines](CONTRIBUTING.md). Please ensure you read the relevant sections of the guidelines carefully before making a Pull Request or opening an Issue.
|
||||||
|
|
||||||
### Where can I get the latest .phar?
|
### Where can I get the latest .phar?
|
||||||
Head over to our [official Jenkins server](https://jenkins.pmmp.io/)
|
- Latest release builds can be found in our [GitHub releases](https://github.com/pmmp/PocketMine-MP/releases).
|
||||||
|
- Latest bleeding-edge development builds (and other builds in the build job channels) can be found on our [Jenkins server](https://jenkins.pmmp.io/).
|
||||||
|
|
||||||
|
**Note: Please avoid development builds unless there is no other alternative for what you need.** Development builds are subject to changes at any time without notice, and it is likely that your server or plugins might break without warning.
|
||||||
|
|
||||||
## Third-party Libraries/Protocols Used
|
## Third-party Libraries/Protocols Used
|
||||||
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
|
* __[PHP Sockets](http://php.net/manual/en/book.sockets.php)__
|
||||||
|
52
composer.json
Normal file
52
composer.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"name": "pocketmine/pocketmine-mp",
|
||||||
|
"description": "A server software for Minecraft: Pocket Edition written in PHP",
|
||||||
|
"type": "project",
|
||||||
|
"homepage": "https://pmmp.io",
|
||||||
|
"license": "LGPL-3.0",
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.0RC3",
|
||||||
|
"ext-bcmath": "*",
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-hash": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-phar": "*",
|
||||||
|
"ext-pthreads": ">=3.1.7dev",
|
||||||
|
"ext-reflection": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"ext-spl": "*",
|
||||||
|
"ext-yaml": ">=2.0.0",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": ">=1.2.11",
|
||||||
|
"pocketmine/raklib": "dev-master#eaa85c2b23bbc1a85030a621d4644c0e33e05950",
|
||||||
|
"pocketmine/pocketmine-spl": "^0.2.0",
|
||||||
|
"pocketmine/pocketmine-binaryutils": "dev-master#a7cd5303a3b215d26bf9be76682ce9311f40e887",
|
||||||
|
"pocketmine/pocketmine-nbt": "dev-master#f8934c0aed90d1f55452588f7ebef7c4519518a5"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"": ["src"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/pmmp/RakLib"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-SPL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-BinaryUtils"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-NBT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
178
composer.lock
generated
Normal file
178
composer.lock
generated
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "5997f272811ed1148e7699a33335a0d2",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "pocketmine/pocketmine-binaryutils",
|
||||||
|
"version": "dev-master",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-BinaryUtils.git",
|
||||||
|
"reference": "a7cd5303a3b215d26bf9be76682ce9311f40e887"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pmmp/PocketMine-BinaryUtils/zipball/a7cd5303a3b215d26bf9be76682ce9311f40e887",
|
||||||
|
"reference": "a7cd5303a3b215d26bf9be76682ce9311f40e887",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"pocketmine\\utils\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0"
|
||||||
|
],
|
||||||
|
"description": "Classes and methods for conveniently handling binary data",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/pmmp/PocketMine-BinaryUtils/tree/master",
|
||||||
|
"issues": "https://github.com/pmmp/PocketMine-BinaryUtils/issues"
|
||||||
|
},
|
||||||
|
"time": "2018-01-14T18:53:25+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pocketmine/pocketmine-nbt",
|
||||||
|
"version": "dev-master",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-NBT.git",
|
||||||
|
"reference": "f8934c0aed90d1f55452588f7ebef7c4519518a5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pmmp/PocketMine-NBT/zipball/f8934c0aed90d1f55452588f7ebef7c4519518a5",
|
||||||
|
"reference": "f8934c0aed90d1f55452588f7ebef7c4519518a5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.0",
|
||||||
|
"pocketmine/pocketmine-binaryutils": "dev-master#8bb34e771fee69abcc5482d17d2fa0b4f0e15a5e"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"pocketmine\\nbt\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0"
|
||||||
|
],
|
||||||
|
"description": "PHP library for working with Named Binary Tags",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/pmmp/PocketMine-NBT/tree/master",
|
||||||
|
"issues": "https://github.com/pmmp/PocketMine-NBT/issues"
|
||||||
|
},
|
||||||
|
"time": "2018-01-11T13:51:50+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pocketmine/pocketmine-spl",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pmmp/PocketMine-SPL.git",
|
||||||
|
"reference": "70c591a44b6c5aa541a1a55585764bed2b23148c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pmmp/PocketMine-SPL/zipball/70c591a44b6c5aa541a1a55585764bed2b23148c",
|
||||||
|
"reference": "70c591a44b6c5aa541a1a55585764bed2b23148c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"stubs"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"./"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0"
|
||||||
|
],
|
||||||
|
"description": "Standard library files required by PocketMine-MP and related projects",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/pmmp/PocketMine-SPL/tree/master"
|
||||||
|
},
|
||||||
|
"time": "2018-01-11T13:03:01+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pocketmine/raklib",
|
||||||
|
"version": "dev-master",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pmmp/RakLib.git",
|
||||||
|
"reference": "eaa85c2b23bbc1a85030a621d4644c0e33e05950"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/eaa85c2b23bbc1a85030a621d4644c0e33e05950",
|
||||||
|
"reference": "eaa85c2b23bbc1a85030a621d4644c0e33e05950",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-bcmath": "*",
|
||||||
|
"ext-pthreads": ">=3.1.7dev",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"php": ">=7.2.0RC3",
|
||||||
|
"pocketmine/pocketmine-binaryutils": "dev-master#a7cd5303a3b215d26bf9be76682ce9311f40e887",
|
||||||
|
"pocketmine/pocketmine-spl": "^0.2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"./"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0"
|
||||||
|
],
|
||||||
|
"description": "A RakNet server implementation written in PHP",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/pmmp/RakLib/tree/master",
|
||||||
|
"issues": "https://github.com/pmmp/RakLib/issues"
|
||||||
|
},
|
||||||
|
"time": "2018-01-27T15:38:43+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {
|
||||||
|
"php": 5,
|
||||||
|
"ext-pthreads": 20,
|
||||||
|
"pocketmine/raklib": 20,
|
||||||
|
"pocketmine/pocketmine-binaryutils": 20,
|
||||||
|
"pocketmine/pocketmine-nbt": 20
|
||||||
|
},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {
|
||||||
|
"php": ">=7.2.0RC3",
|
||||||
|
"ext-bcmath": "*",
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-hash": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-phar": "*",
|
||||||
|
"ext-pthreads": ">=3.1.7dev",
|
||||||
|
"ext-reflection": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"ext-spl": "*",
|
||||||
|
"ext-yaml": ">=2.0.0",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": ">=1.2.11"
|
||||||
|
},
|
||||||
|
"platform-dev": []
|
||||||
|
}
|
2322
doxygen.conf
Normal file
2322
doxygen.conf
Normal file
File diff suppressed because it is too large
Load Diff
@ -116,7 +116,7 @@ abstract class Achievement{
|
|||||||
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]);
|
||||||
if(Server::getInstance()->getConfigBoolean("announce-player-achievements", true) === true){
|
if(Server::getInstance()->getConfigBool("announce-player-achievements", true) === true){
|
||||||
Server::getInstance()->broadcastMessage($translation);
|
Server::getInstance()->broadcastMessage($translation);
|
||||||
}else{
|
}else{
|
||||||
$player->sendMessage($translation);
|
$player->sendMessage($translation);
|
||||||
|
@ -186,7 +186,7 @@ class CrashDump{
|
|||||||
$this->addLine("Line: " . $error["line"]);
|
$this->addLine("Line: " . $error["line"]);
|
||||||
$this->addLine("Type: " . $error["type"]);
|
$this->addLine("Type: " . $error["type"]);
|
||||||
|
|
||||||
if(strpos($error["file"], "src/pocketmine/") === false and strpos($error["file"], "src/raklib/") === false and file_exists($error["fullFile"])){
|
if(strpos($error["file"], "src/pocketmine/") === false and strpos($error["file"], "vendor/pocketmine/") === false and file_exists($error["fullFile"])){
|
||||||
$this->addLine();
|
$this->addLine();
|
||||||
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
||||||
$this->data["plugin"] = true;
|
$this->data["plugin"] = true;
|
||||||
@ -257,4 +257,4 @@ class CrashDump{
|
|||||||
fwrite($this->fp, $str);
|
fwrite($this->fp, $str);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ namespace pocketmine;
|
|||||||
|
|
||||||
use pocketmine\event\server\LowMemoryEvent;
|
use pocketmine\event\server\LowMemoryEvent;
|
||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
|
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||||
use pocketmine\scheduler\GarbageCollectionTask;
|
use pocketmine\scheduler\GarbageCollectionTask;
|
||||||
|
use pocketmine\utils\MainLogger;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
|
|
||||||
class MemoryManager{
|
class MemoryManager{
|
||||||
@ -63,16 +65,17 @@ class MemoryManager{
|
|||||||
private $garbageCollectionAsync;
|
private $garbageCollectionAsync;
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $chunkRadiusOverride;
|
private $lowMemChunkRadiusOverride;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $chunkCollect;
|
private $lowMemChunkGC;
|
||||||
/** @var bool */
|
|
||||||
private $chunkTrigger;
|
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $chunkCache;
|
private $lowMemDisableChunkCache;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $cacheTrigger;
|
private $lowMemClearWorldCache;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $dumpWorkers = true;
|
||||||
|
|
||||||
public function __construct(Server $server){
|
public function __construct(Server $server){
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
@ -124,13 +127,13 @@ class MemoryManager{
|
|||||||
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
|
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
|
||||||
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
|
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
|
||||||
|
|
||||||
$this->chunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
||||||
$this->chunkCollect = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
||||||
$this->chunkTrigger = (bool) $this->server->getProperty("memory.max-chunks.low-memory-trigger", true);
|
|
||||||
|
|
||||||
$this->chunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
||||||
$this->cacheTrigger = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
||||||
|
|
||||||
|
$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
|
||||||
gc_enable();
|
gc_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +148,7 @@ class MemoryManager{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function canUseChunkCache() : bool{
|
public function canUseChunkCache() : bool{
|
||||||
return !($this->lowMemory and $this->chunkTrigger);
|
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,7 +159,7 @@ class MemoryManager{
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getViewDistance(int $distance) : int{
|
public function getViewDistance(int $distance) : int{
|
||||||
return $this->lowMemory ? (int) min($this->chunkRadiusOverride, $distance) : $distance;
|
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? (int) min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,13 +173,13 @@ class MemoryManager{
|
|||||||
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",
|
||||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||||
if($this->cacheTrigger){
|
if($this->lowMemClearWorldCache){
|
||||||
foreach($this->server->getLevels() as $level){
|
foreach($this->server->getLevels() as $level){
|
||||||
$level->clearCache(true);
|
$level->clearCache(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->chunkTrigger and $this->chunkCollect){
|
if($this->lowMemChunkGC){
|
||||||
foreach($this->server->getLevels() as $level){
|
foreach($this->server->getLevels() as $level){
|
||||||
$level->doChunkGarbageCollection();
|
$level->doChunkGarbageCollection();
|
||||||
}
|
}
|
||||||
@ -261,6 +264,28 @@ class MemoryManager{
|
|||||||
* @param int $maxStringSize
|
* @param int $maxStringSize
|
||||||
*/
|
*/
|
||||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||||
|
MainLogger::getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||||
|
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize);
|
||||||
|
|
||||||
|
if($this->dumpWorkers){
|
||||||
|
$scheduler = $this->server->getScheduler();
|
||||||
|
for($i = 0, $size = $scheduler->getAsyncTaskPoolSize(); $i < $size; ++$i){
|
||||||
|
$scheduler->scheduleAsyncTaskToWorker(new DumpWorkerMemoryTask($outputFolder, $maxNesting, $maxStringSize), $i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static memory dumper accessible from any thread.
|
||||||
|
*
|
||||||
|
* @param mixed $startingObject
|
||||||
|
* @param string $outputFolder
|
||||||
|
* @param int $maxNesting
|
||||||
|
* @param int $maxStringSize
|
||||||
|
*
|
||||||
|
* @throws \ReflectionException
|
||||||
|
*/
|
||||||
|
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||||
$hardLimit = ini_get('memory_limit');
|
$hardLimit = ini_get('memory_limit');
|
||||||
ini_set('memory_limit', '-1');
|
ini_set('memory_limit', '-1');
|
||||||
gc_disable();
|
gc_disable();
|
||||||
@ -269,12 +294,8 @@ class MemoryManager{
|
|||||||
mkdir($outputFolder, 0777, true);
|
mkdir($outputFolder, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
|
||||||
|
|
||||||
$obData = fopen($outputFolder . "/objects.js", "wb+");
|
$obData = fopen($outputFolder . "/objects.js", "wb+");
|
||||||
|
|
||||||
$staticProperties = [];
|
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
$objects = [];
|
$objects = [];
|
||||||
@ -283,8 +304,10 @@ class MemoryManager{
|
|||||||
|
|
||||||
$instanceCounts = [];
|
$instanceCounts = [];
|
||||||
|
|
||||||
|
$staticProperties = [];
|
||||||
$staticCount = 0;
|
$staticCount = 0;
|
||||||
foreach($this->server->getLoader()->getClasses() as $className){
|
|
||||||
|
foreach(get_declared_classes() as $className){
|
||||||
$reflection = new \ReflectionClass($className);
|
$reflection = new \ReflectionClass($className);
|
||||||
$staticProperties[$className] = [];
|
$staticProperties[$className] = [];
|
||||||
foreach($reflection->getProperties() as $property){
|
foreach($reflection->getProperties() as $property){
|
||||||
@ -297,7 +320,7 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$staticCount++;
|
$staticCount++;
|
||||||
$this->continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($staticProperties[$className]) === 0){
|
if(count($staticProperties[$className]) === 0){
|
||||||
@ -305,9 +328,39 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "[Dump] Wrote $staticCount static properties\n";
|
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
MainLogger::getLogger()->info("[Dump] Wrote $staticCount static properties");
|
||||||
|
|
||||||
$this->continueDump($this->server, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
if(isset($GLOBALS)){ //This might be null if we're on a different thread
|
||||||
|
$globalVariables = [];
|
||||||
|
$globalCount = 0;
|
||||||
|
|
||||||
|
$ignoredGlobals = [
|
||||||
|
'GLOBALS' => true,
|
||||||
|
'_SERVER' => true,
|
||||||
|
'_REQUEST' => true,
|
||||||
|
'_POST' => true,
|
||||||
|
'_GET' => true,
|
||||||
|
'_FILES' => true,
|
||||||
|
'_ENV' => true,
|
||||||
|
'_COOKIE' => true,
|
||||||
|
'_SESSION' => true
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach($GLOBALS as $varName => $value){
|
||||||
|
if(isset($ignoredGlobals[$varName])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$globalCount++;
|
||||||
|
self::continueDump($value, $globalVariables[$varName], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
MainLogger::getLogger()->info("[Dump] Wrote $globalCount global variables");
|
||||||
|
}
|
||||||
|
|
||||||
|
self::continueDump($startingObject, $data, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||||
|
|
||||||
do{
|
do{
|
||||||
$continue = false;
|
$continue = false;
|
||||||
@ -349,25 +402,26 @@ class MemoryManager{
|
|||||||
if(!$property->isPublic()){
|
if(!$property->isPublic()){
|
||||||
$property->setAccessible(true);
|
$property->setAccessible(true);
|
||||||
}
|
}
|
||||||
$this->continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
self::continueDump($property->getValue($object), $info["properties"][$property->getName()], $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");
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "[Dump] Wrote " . count($objects) . " objects\n";
|
|
||||||
}while($continue);
|
}while($continue);
|
||||||
|
|
||||||
|
MainLogger::getLogger()->info("[Dump] Wrote " . count($objects) . " objects");
|
||||||
|
|
||||||
fclose($obData);
|
fclose($obData);
|
||||||
|
|
||||||
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
|
||||||
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
arsort($instanceCounts, SORT_NUMERIC);
|
arsort($instanceCounts, SORT_NUMERIC);
|
||||||
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
echo "[Dump] Finished!\n";
|
MainLogger::getLogger()->info("[Dump] Finished!");
|
||||||
|
|
||||||
ini_set('memory_limit', $hardLimit);
|
ini_set('memory_limit', $hardLimit);
|
||||||
gc_enable();
|
gc_enable();
|
||||||
@ -382,7 +436,7 @@ class MemoryManager{
|
|||||||
* @param int $maxNesting
|
* @param int $maxNesting
|
||||||
* @param int $maxStringSize
|
* @param int $maxStringSize
|
||||||
*/
|
*/
|
||||||
private function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||||
if($maxNesting <= 0){
|
if($maxNesting <= 0){
|
||||||
$data = "(error) NESTING LIMIT REACHED";
|
$data = "(error) NESTING LIMIT REACHED";
|
||||||
return;
|
return;
|
||||||
@ -406,7 +460,7 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
$data = [];
|
$data = [];
|
||||||
foreach($from as $key => $value){
|
foreach($from as $key => $value){
|
||||||
$this->continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
self::continueDump($value, $data[$key], $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);
|
||||||
|
@ -108,11 +108,11 @@ class OfflinePlayer implements IPlayer, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getFirstPlayed(){
|
public function getFirstPlayed(){
|
||||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag["firstPlayed"] : null;
|
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastPlayed(){
|
public function getLastPlayed(){
|
||||||
return $this->namedtag instanceof CompoundTag ? $this->namedtag["lastPlayed"] : null;
|
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasPlayedBefore() : bool{
|
public function hasPlayedBefore() : bool{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace pocketmine {
|
namespace pocketmine {
|
||||||
|
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\MainLogger;
|
use pocketmine\utils\MainLogger;
|
||||||
use pocketmine\utils\ServerKiller;
|
use pocketmine\utils\ServerKiller;
|
||||||
@ -78,9 +79,12 @@ namespace pocketmine {
|
|||||||
use pocketmine\wizard\SetupWizard;
|
use pocketmine\wizard\SetupWizard;
|
||||||
use raklib\RakLib;
|
use raklib\RakLib;
|
||||||
|
|
||||||
const VERSION = "1.6.2dev";
|
const NAME = "PocketMine-MP";
|
||||||
const API_VERSION = "3.0.0-ALPHA7";
|
const VERSION = "1.7dev";
|
||||||
const CODENAME = "Unleashed";
|
const API_VERSION = "3.0.0-ALPHA11";
|
||||||
|
const CODENAME = "[REDACTED]";
|
||||||
|
|
||||||
|
const MIN_PHP_VERSION = "7.2.0RC3";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Startup code. Do not look at it, it may harm you.
|
* Startup code. Do not look at it, it may harm you.
|
||||||
@ -89,9 +93,9 @@ namespace pocketmine {
|
|||||||
* Enjoy it as much as I did writing it. I don't want to do it again.
|
* Enjoy it as much as I did writing it. I don't want to do it again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
|
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
||||||
echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
|
echo "[CRITICAL] " . \pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "." . PHP_EOL;
|
||||||
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
|
echo "[CRITICAL] Please use the installer provided on the homepage, or update to a newer PHP version." . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,13 +107,15 @@ namespace pocketmine {
|
|||||||
|
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
|
|
||||||
set_error_handler(function($severity, $message, $file, $line){
|
function error_handler($severity, $message, $file, $line){
|
||||||
if(error_reporting() & $severity){
|
if(error_reporting() & $severity){
|
||||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||||
}else{ //stfu operator
|
}else{ //stfu operator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
set_error_handler('\pocketmine\error_handler');
|
||||||
|
|
||||||
if(!extension_loaded("phar")){
|
if(!extension_loaded("phar")){
|
||||||
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
||||||
@ -120,42 +126,38 @@ namespace pocketmine {
|
|||||||
if(\Phar::running(true) !== ""){
|
if(\Phar::running(true) !== ""){
|
||||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
define('pocketmine\PATH', \Phar::running(true) . "/");
|
||||||
}else{
|
}else{
|
||||||
define('pocketmine\PATH', realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requiredSplVer = "0.0.1";
|
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
|
||||||
if(!is_file(\pocketmine\PATH . "src/spl/version.php") or version_compare($requiredSplVer, require(\pocketmine\PATH . "src/spl/version.php")) > 0){
|
|
||||||
echo "[CRITICAL] Incompatible PocketMine-SPL submodule version ($requiredSplVer is required)." . PHP_EOL;
|
function composer_error_die($message){
|
||||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
echo "[CRITICAL] $message" . PHP_EOL;
|
||||||
|
echo "[CRITICAL] Please install/update Composer dependencies or use provided builds." . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!class_exists("ClassLoader", false)){
|
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
||||||
if(!is_file(\pocketmine\PATH . "src/spl/ClassLoader.php")){
|
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||||
echo "[CRITICAL] Unable to find the PocketMine-SPL library." . PHP_EOL;
|
}else{
|
||||||
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
|
composer_error_die("Composer autoloader not found.");
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
|
||||||
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$autoloader = new \BaseClassLoader();
|
|
||||||
$autoloader->addPath(\pocketmine\PATH . "src");
|
|
||||||
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
|
|
||||||
$autoloader->register(true);
|
|
||||||
|
|
||||||
if(!class_exists(RakLib::class)){
|
if(!class_exists(RakLib::class)){
|
||||||
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
|
composer_error_die("Unable to find the RakLib library.");
|
||||||
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
|
}
|
||||||
exit(1);
|
if(version_compare(RakLib::VERSION, "0.9.0") < 0){ //TODO: remove this check (it's managed by Composer now)
|
||||||
|
composer_error_die("RakLib version 0.9.0 is required, while you have version " . RakLib::VERSION . ".");
|
||||||
|
}
|
||||||
|
if(!class_exists(\BaseClassLoader::class)){
|
||||||
|
composer_error_die("Unable to find the PocketMine-SPL library.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(version_compare(RakLib::VERSION, "0.8.1") < 0){
|
/*
|
||||||
echo "[CRITICAL] RakLib version 0.8.1 is required, while you have version " . RakLib::VERSION . "." . PHP_EOL;
|
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
||||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
*/
|
||||||
exit(1);
|
$autoloader = new \BaseClassLoader();
|
||||||
}
|
$autoloader->register(false);
|
||||||
|
|
||||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
set_time_limit(0); //Who set it to 30 seconds?!?!
|
||||||
|
|
||||||
@ -167,10 +169,12 @@ namespace pocketmine {
|
|||||||
ini_set("memory_limit", '-1');
|
ini_set("memory_limit", '-1');
|
||||||
define('pocketmine\START_TIME', microtime(true));
|
define('pocketmine\START_TIME', microtime(true));
|
||||||
|
|
||||||
|
define('pocketmine\RESOURCE_PATH', \pocketmine\PATH . 'src' . DIRECTORY_SEPARATOR . 'pocketmine' . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-profiler"]);
|
$opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-profiler"]);
|
||||||
|
|
||||||
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
|
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 : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
define('pocketmine\PLUGIN_PATH', isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \realpath(\getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
Terminal::init();
|
Terminal::init();
|
||||||
|
|
||||||
@ -186,40 +190,51 @@ namespace pocketmine {
|
|||||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||||
$logger->registerStatic();
|
$logger->registerStatic();
|
||||||
|
|
||||||
if(!ini_get("date.timezone")){
|
do{
|
||||||
|
$timezone = ini_get("date.timezone");
|
||||||
|
if($timezone !== ""){
|
||||||
|
/*
|
||||||
|
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
||||||
|
* an incorrect timezone abbreviation in php.ini apparently.
|
||||||
|
*/
|
||||||
|
if(strpos($timezone, "/") === false){
|
||||||
|
$default_timezone = timezone_name_from_abbr($timezone);
|
||||||
|
if($default_timezone !== false){
|
||||||
|
ini_set("date.timezone", $default_timezone);
|
||||||
|
date_default_timezone_set($default_timezone);
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
//Bad php.ini value, try another method to detect timezone
|
||||||
|
$logger->warning("Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
||||||
//Success! Timezone has already been set and validated in the if statement.
|
//Success! Timezone has already been set and validated in the if statement.
|
||||||
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
|
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
|
||||||
ini_set("date.timezone", $timezone);
|
ini_set("date.timezone", $timezone);
|
||||||
}else{
|
break;
|
||||||
//If system timezone detection fails or timezone is an invalid value.
|
|
||||||
if($response = Utils::getURL("http://ip-api.com/json")
|
|
||||||
and $ip_geolocation_data = json_decode($response, true)
|
|
||||||
and $ip_geolocation_data['status'] !== 'fail'
|
|
||||||
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
|
||||||
){
|
|
||||||
//Again, for redundancy.
|
|
||||||
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
|
||||||
}else{
|
|
||||||
ini_set("date.timezone", "UTC");
|
|
||||||
date_default_timezone_set("UTC");
|
|
||||||
$logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
/*
|
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
|
||||||
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
and $ip_geolocation_data = json_decode($response, true)
|
||||||
* an incorrect timezone abbreviation in php.ini apparently.
|
and $ip_geolocation_data['status'] !== 'fail'
|
||||||
*/
|
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
||||||
$timezone = ini_get("date.timezone");
|
){
|
||||||
if(strpos($timezone, "/") === false){
|
//Again, for redundancy.
|
||||||
$default_timezone = timezone_name_from_abbr($timezone);
|
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
||||||
ini_set("date.timezone", $default_timezone);
|
break;
|
||||||
date_default_timezone_set($default_timezone);
|
|
||||||
}else{
|
|
||||||
date_default_timezone_set($timezone);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ini_set("date.timezone", "UTC");
|
||||||
|
date_default_timezone_set("UTC");
|
||||||
|
$logger->warning("Timezone could not be automatically determined or was set to an invalid value. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
||||||
|
}while(false);
|
||||||
|
|
||||||
|
|
||||||
function detect_system_timezone(){
|
function detect_system_timezone(){
|
||||||
switch(Utils::getOS()){
|
switch(Utils::getOS()){
|
||||||
@ -350,6 +365,10 @@ namespace pocketmine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function kill($pid){
|
function kill($pid){
|
||||||
|
global $logger;
|
||||||
|
if($logger instanceof MainLogger){
|
||||||
|
$logger->syncFlushBuffer();
|
||||||
|
}
|
||||||
switch(Utils::getOS()){
|
switch(Utils::getOS()){
|
||||||
case "win":
|
case "win":
|
||||||
exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL");
|
exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL");
|
||||||
@ -383,6 +402,12 @@ namespace pocketmine {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $start
|
||||||
|
* @param array|null $trace
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
function getTrace($start = 0, $trace = null){
|
function getTrace($start = 0, $trace = null){
|
||||||
if($trace === null){
|
if($trace === null){
|
||||||
if(function_exists("xdebug_get_function_stack")){
|
if(function_exists("xdebug_get_function_stack")){
|
||||||
@ -408,7 +433,7 @@ namespace pocketmine {
|
|||||||
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
||||||
}, $args));
|
}, $args));
|
||||||
}
|
}
|
||||||
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . ($trace[$i]["line"] ?? "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $messages;
|
return $messages;
|
||||||
@ -424,13 +449,13 @@ namespace pocketmine {
|
|||||||
$errors = 0;
|
$errors = 0;
|
||||||
|
|
||||||
if(PHP_INT_SIZE < 8){
|
if(PHP_INT_SIZE < 8){
|
||||||
$logger->critical("Running PocketMine-MP with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
|
$logger->critical("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.");
|
||||||
$exitCode = 1;
|
$exitCode = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(php_sapi_name() !== "cli"){
|
if(php_sapi_name() !== "cli"){
|
||||||
$logger->critical("You must run PocketMine-MP using the CLI.");
|
$logger->critical("You must run " . \pocketmine\NAME . " using the CLI.");
|
||||||
++$errors;
|
++$errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,15 +463,15 @@ namespace pocketmine {
|
|||||||
if(substr_count($pthreads_version, ".") < 2){
|
if(substr_count($pthreads_version, ".") < 2){
|
||||||
$pthreads_version = "0.$pthreads_version";
|
$pthreads_version = "0.$pthreads_version";
|
||||||
}
|
}
|
||||||
if(version_compare($pthreads_version, "3.1.5") < 0){
|
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
|
||||||
$logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
|
$logger->critical("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
|
||||||
++$errors;
|
++$errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(extension_loaded("leveldb")){
|
if(extension_loaded("leveldb")){
|
||||||
$leveldb_version = phpversion("leveldb");
|
$leveldb_version = phpversion("leveldb");
|
||||||
if(version_compare($leveldb_version, "0.2.0") < 0){
|
if(version_compare($leveldb_version, "0.2.1") < 0){
|
||||||
$logger->critical("php-leveldb >= 0.2.0 is required, while you have $leveldb_version");
|
$logger->critical("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
|
||||||
++$errors;
|
++$errors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,7 +487,7 @@ namespace pocketmine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(extension_loaded("xdebug")){
|
if(extension_loaded("xdebug")){
|
||||||
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running PocketMine with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
$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);
|
||||||
}
|
}
|
||||||
|
|
||||||
$extensions = [
|
$extensions = [
|
||||||
@ -470,8 +495,9 @@ namespace pocketmine {
|
|||||||
"curl" => "cURL",
|
"curl" => "cURL",
|
||||||
"json" => "JSON",
|
"json" => "JSON",
|
||||||
"mbstring" => "Multibyte String",
|
"mbstring" => "Multibyte String",
|
||||||
"yaml" => "YAML",
|
"openssl" => "OpenSSL",
|
||||||
"sockets" => "Sockets",
|
"sockets" => "Sockets",
|
||||||
|
"yaml" => "YAML",
|
||||||
"zip" => "Zip",
|
"zip" => "Zip",
|
||||||
"zlib" => "Zlib"
|
"zlib" => "Zlib"
|
||||||
];
|
];
|
||||||
@ -509,7 +535,6 @@ namespace pocketmine {
|
|||||||
define('pocketmine\GIT_COMMIT', $gitHash);
|
define('pocketmine\GIT_COMMIT', $gitHash);
|
||||||
|
|
||||||
|
|
||||||
@define("ENDIANNESS", (pack("d", 1) === "\77\360\0\0\0\0\0\0" ? Binary::BIG_ENDIAN : Binary::LITTLE_ENDIAN));
|
|
||||||
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
|
@define("INT32_MASK", is_int(0xffffffff) ? 0xffffffff : -1);
|
||||||
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
|
@ini_set("opcache.mmap_base", bin2hex(random_bytes(8))); //Fix OPCache address errors
|
||||||
|
|
||||||
@ -524,11 +549,11 @@ namespace pocketmine {
|
|||||||
|
|
||||||
|
|
||||||
if(\Phar::running(true) === ""){
|
if(\Phar::running(true) === ""){
|
||||||
$logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
|
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::init();
|
ThreadManager::init();
|
||||||
new Server($autoloader, $logger, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
|
new Server($autoloader, $logger, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
|
||||||
|
|
||||||
$logger->info("Stopping other threads");
|
$logger->info("Stopping other threads");
|
||||||
|
|
||||||
@ -536,19 +561,7 @@ namespace pocketmine {
|
|||||||
$killer->start();
|
$killer->start();
|
||||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||||
|
|
||||||
$erroredThreads = 0;
|
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||||
foreach(ThreadManager::getInstance()->getAll() as $id => $thread){
|
|
||||||
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
|
||||||
try{
|
|
||||||
$thread->quit();
|
|
||||||
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
|
||||||
}catch(\ThreadException $e){
|
|
||||||
++$erroredThreads;
|
|
||||||
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($erroredThreads > 0){
|
|
||||||
if(\pocketmine\DEBUG > 1){
|
if(\pocketmine\DEBUG > 1){
|
||||||
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ use pocketmine\command\SimpleCommandMap;
|
|||||||
use pocketmine\entity\Attribute;
|
use pocketmine\entity\Attribute;
|
||||||
use pocketmine\entity\Effect;
|
use pocketmine\entity\Effect;
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\event\HandlerList;
|
use pocketmine\event\HandlerList;
|
||||||
use pocketmine\event\level\LevelInitEvent;
|
use pocketmine\event\level\LevelInitEvent;
|
||||||
use pocketmine\event\level\LevelLoadEvent;
|
use pocketmine\event\level\LevelLoadEvent;
|
||||||
@ -45,9 +46,7 @@ use pocketmine\event\server\ServerCommandEvent;
|
|||||||
use pocketmine\event\TextContainer;
|
use pocketmine\event\TextContainer;
|
||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
use pocketmine\event\TimingsHandler;
|
use pocketmine\event\TimingsHandler;
|
||||||
use pocketmine\event\TranslationContainer;
|
|
||||||
use pocketmine\inventory\CraftingManager;
|
use pocketmine\inventory\CraftingManager;
|
||||||
use pocketmine\inventory\InventoryType;
|
|
||||||
use pocketmine\inventory\Recipe;
|
use pocketmine\inventory\Recipe;
|
||||||
use pocketmine\item\enchantment\Enchantment;
|
use pocketmine\item\enchantment\Enchantment;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
@ -68,6 +67,7 @@ use pocketmine\level\LevelException;
|
|||||||
use pocketmine\metadata\EntityMetadataStore;
|
use pocketmine\metadata\EntityMetadataStore;
|
||||||
use pocketmine\metadata\LevelMetadataStore;
|
use pocketmine\metadata\LevelMetadataStore;
|
||||||
use pocketmine\metadata\PlayerMetadataStore;
|
use pocketmine\metadata\PlayerMetadataStore;
|
||||||
|
use pocketmine\nbt\BigEndianNBTStream;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
use pocketmine\nbt\tag\ByteTag;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
@ -83,6 +83,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
|||||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||||
use pocketmine\network\mcpe\RakLibInterface;
|
use pocketmine\network\mcpe\RakLibInterface;
|
||||||
use pocketmine\network\Network;
|
use pocketmine\network\Network;
|
||||||
use pocketmine\network\query\QueryHandler;
|
use pocketmine\network\query\QueryHandler;
|
||||||
@ -114,8 +115,8 @@ use pocketmine\utils\VersionString;
|
|||||||
* The class that manages everything
|
* The class that manages everything
|
||||||
*/
|
*/
|
||||||
class Server{
|
class Server{
|
||||||
const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
|
public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
|
||||||
const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
|
public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
|
||||||
|
|
||||||
/** @var Server */
|
/** @var Server */
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
@ -194,6 +195,9 @@ class Server{
|
|||||||
/** @var int */
|
/** @var int */
|
||||||
private $maxPlayers;
|
private $maxPlayers;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $onlineMode = true;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $autoSave;
|
private $autoSave;
|
||||||
|
|
||||||
@ -231,7 +235,6 @@ class Server{
|
|||||||
private $serverID;
|
private $serverID;
|
||||||
|
|
||||||
private $autoloader;
|
private $autoloader;
|
||||||
private $filePath;
|
|
||||||
private $dataPath;
|
private $dataPath;
|
||||||
private $pluginPath;
|
private $pluginPath;
|
||||||
|
|
||||||
@ -273,7 +276,7 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "PocketMine-MP";
|
return \pocketmine\NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -315,7 +318,14 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getFilePath() : string{
|
public function getFilePath() : string{
|
||||||
return $this->filePath;
|
return \pocketmine\PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getResourcePath() : string{
|
||||||
|
return \pocketmine\RESOURCE_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,6 +349,24 @@ class Server{
|
|||||||
return $this->maxPlayers;
|
return $this->maxPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||||
|
* are not logged into Xbox Live will be disconnected.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getOnlineMode() : bool{
|
||||||
|
return $this->onlineMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias of {@link #getOnlineMode()}.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function requiresAuthentication() : bool{
|
||||||
|
return $this->getOnlineMode();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -406,7 +434,7 @@ class Server{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getGenerateStructures() : bool{
|
public function getGenerateStructures() : bool{
|
||||||
return $this->getConfigBoolean("generate-structures", true);
|
return $this->getConfigBool("generate-structures", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -420,7 +448,7 @@ class Server{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getForceGamemode() : bool{
|
public function getForceGamemode() : bool{
|
||||||
return $this->getConfigBoolean("force-gamemode", false);
|
return $this->getConfigBool("force-gamemode", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -494,36 +522,17 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $str
|
* @deprecated Moved to {@link Level#getDifficultyFromString}
|
||||||
*
|
*
|
||||||
|
* @param string $str
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getDifficultyFromString(string $str) : int{
|
public static function getDifficultyFromString(string $str) : int{
|
||||||
switch(strtolower(trim($str))){
|
return Level::getDifficultyFromString($str);
|
||||||
case "0":
|
|
||||||
case "peaceful":
|
|
||||||
case "p":
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case "1":
|
|
||||||
case "easy":
|
|
||||||
case "e":
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case "2":
|
|
||||||
case "normal":
|
|
||||||
case "n":
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case "3":
|
|
||||||
case "hard":
|
|
||||||
case "h":
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDifficulty() : int{
|
public function getDifficulty() : int{
|
||||||
@ -534,7 +543,7 @@ class Server{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasWhitelist() : bool{
|
public function hasWhitelist() : bool{
|
||||||
return $this->getConfigBoolean("white-list", false);
|
return $this->getConfigBool("white-list", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -548,14 +557,14 @@ class Server{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getAllowFlight() : bool{
|
public function getAllowFlight() : bool{
|
||||||
return $this->getConfigBoolean("allow-flight", false);
|
return $this->getConfigBool("allow-flight", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isHardcore() : bool{
|
public function isHardcore() : bool{
|
||||||
return $this->getConfigBoolean("hardcore", false);
|
return $this->getConfigBool("hardcore", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -569,7 +578,7 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getMotd() : string{
|
public function getMotd() : string{
|
||||||
return $this->getConfigString("motd", "Minecraft: PE Server");
|
return $this->getConfigString("motd", \pocketmine\NAME . " Server");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -741,7 +750,7 @@ class Server{
|
|||||||
if($this->shouldSavePlayerData()){
|
if($this->shouldSavePlayerData()){
|
||||||
if(file_exists($path . "$name.dat")){
|
if(file_exists($path . "$name.dat")){
|
||||||
try{
|
try{
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
$nbt = new BigEndianNBTStream();
|
||||||
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
|
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
|
||||||
|
|
||||||
return $nbt->getData();
|
return $nbt->getData();
|
||||||
@ -754,32 +763,35 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$spawn = $this->getDefaultLevel()->getSafeSpawn();
|
$spawn = $this->getDefaultLevel()->getSafeSpawn();
|
||||||
|
$currentTimeMillis = (int) (microtime(true) * 1000);
|
||||||
|
|
||||||
$nbt = new CompoundTag("", [
|
$nbt = new CompoundTag("", [
|
||||||
new LongTag("firstPlayed", (int) (microtime(true) * 1000)),
|
new LongTag("firstPlayed", $currentTimeMillis),
|
||||||
new LongTag("lastPlayed", (int) (microtime(true) * 1000)),
|
new LongTag("lastPlayed", $currentTimeMillis),
|
||||||
new ListTag("Pos", [
|
new ListTag("Pos", [
|
||||||
new DoubleTag("", $spawn->x),
|
new DoubleTag("", $spawn->x),
|
||||||
new DoubleTag("", $spawn->y),
|
new DoubleTag("", $spawn->y),
|
||||||
new DoubleTag("", $spawn->z)
|
new DoubleTag("", $spawn->z)
|
||||||
]),
|
], NBT::TAG_Double),
|
||||||
new StringTag("Level", $this->getDefaultLevel()->getName()),
|
new StringTag("Level", $this->getDefaultLevel()->getFolderName()),
|
||||||
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
|
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getFolderName()),
|
||||||
//new IntTag("SpawnX", (int) $spawn->x),
|
//new IntTag("SpawnX", (int) $spawn->x),
|
||||||
//new IntTag("SpawnY", (int) $spawn->y),
|
//new IntTag("SpawnY", (int) $spawn->y),
|
||||||
//new IntTag("SpawnZ", (int) $spawn->z),
|
//new IntTag("SpawnZ", (int) $spawn->z),
|
||||||
//new ByteTag("SpawnForced", 1), //TODO
|
//new ByteTag("SpawnForced", 1), //TODO
|
||||||
new ListTag("Inventory", []),
|
new ListTag("Inventory", [], NBT::TAG_Compound),
|
||||||
|
new ListTag("EnderChestInventory", [], NBT::TAG_Compound),
|
||||||
new CompoundTag("Achievements", []),
|
new CompoundTag("Achievements", []),
|
||||||
new IntTag("playerGameType", $this->getGamemode()),
|
new IntTag("playerGameType", $this->getGamemode()),
|
||||||
new ListTag("Motion", [
|
new ListTag("Motion", [
|
||||||
new DoubleTag("", 0.0),
|
new DoubleTag("", 0.0),
|
||||||
new DoubleTag("", 0.0),
|
new DoubleTag("", 0.0),
|
||||||
new DoubleTag("", 0.0)
|
new DoubleTag("", 0.0)
|
||||||
]),
|
], NBT::TAG_Double),
|
||||||
new ListTag("Rotation", [
|
new ListTag("Rotation", [
|
||||||
new FloatTag("", 0.0),
|
new FloatTag("", 0.0),
|
||||||
new FloatTag("", 0.0)
|
new FloatTag("", 0.0)
|
||||||
]),
|
], NBT::TAG_Float),
|
||||||
new FloatTag("FallDistance", 0.0),
|
new FloatTag("FallDistance", 0.0),
|
||||||
new ShortTag("Fire", 0),
|
new ShortTag("Fire", 0),
|
||||||
new ShortTag("Air", 300),
|
new ShortTag("Air", 300),
|
||||||
@ -787,10 +799,6 @@ class Server{
|
|||||||
new ByteTag("Invulnerable", 0),
|
new ByteTag("Invulnerable", 0),
|
||||||
new StringTag("NameTag", $name)
|
new StringTag("NameTag", $name)
|
||||||
]);
|
]);
|
||||||
$nbt->Pos->setTagType(NBT::TAG_Double);
|
|
||||||
$nbt->Inventory->setTagType(NBT::TAG_Compound);
|
|
||||||
$nbt->Motion->setTagType(NBT::TAG_Double);
|
|
||||||
$nbt->Rotation->setTagType(NBT::TAG_Float);
|
|
||||||
|
|
||||||
return $nbt;
|
return $nbt;
|
||||||
|
|
||||||
@ -808,7 +816,7 @@ class Server{
|
|||||||
$this->pluginManager->callEvent($ev);
|
$this->pluginManager->callEvent($ev);
|
||||||
|
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
$nbt = new BigEndianNBTStream();
|
||||||
try{
|
try{
|
||||||
$nbt->setData($ev->getSaveData());
|
$nbt->setData($ev->getSaveData());
|
||||||
|
|
||||||
@ -915,7 +923,7 @@ class Server{
|
|||||||
/**
|
/**
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getDefaultLevel(){
|
public function getDefaultLevel() : ?Level{
|
||||||
return $this->levelDefault;
|
return $this->levelDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,7 +934,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @param Level|null $level
|
* @param Level|null $level
|
||||||
*/
|
*/
|
||||||
public function setDefaultLevel($level){
|
public function setDefaultLevel(?Level $level) : void{
|
||||||
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
|
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
|
||||||
$this->levelDefault = $level;
|
$this->levelDefault = $level;
|
||||||
}
|
}
|
||||||
@ -946,12 +954,8 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getLevel(int $levelId){
|
public function getLevel(int $levelId) : ?Level{
|
||||||
if(isset($this->levels[$levelId])){
|
return $this->levels[$levelId] ?? null;
|
||||||
return $this->levels[$levelId];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -961,7 +965,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getLevelByName(string $name){
|
public function getLevelByName(string $name) : ?Level{
|
||||||
foreach($this->getLevels() as $level){
|
foreach($this->getLevels() as $level){
|
||||||
if($level->getFolderName() === $name){
|
if($level->getFolderName() === $name){
|
||||||
return $level;
|
return $level;
|
||||||
@ -983,13 +987,16 @@ class Server{
|
|||||||
if($level === $this->getDefaultLevel() and !$forceUnload){
|
if($level === $this->getDefaultLevel() and !$forceUnload){
|
||||||
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
|
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
|
||||||
}
|
}
|
||||||
if($level->unload($forceUnload) === true){
|
|
||||||
unset($this->levels[$level->getId()]);
|
|
||||||
|
|
||||||
return true;
|
return $level->unload($forceUnload);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* @internal
|
||||||
|
* @param Level $level
|
||||||
|
*/
|
||||||
|
public function removeLevel(Level $level) : void{
|
||||||
|
unset($this->levels[$level->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1084,7 +1091,7 @@ class Server{
|
|||||||
|
|
||||||
$level->setTickRate($this->baseTickRate);
|
$level->setTickRate($this->baseTickRate);
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.generateError", [$name, $e->getMessage()]));
|
$this->logger->error($this->getLanguage()->translateString("pocketmine.level.generationError", [$name, $e->getMessage()]));
|
||||||
$this->logger->logException($e);
|
$this->logger->logException($e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1095,8 +1102,9 @@ class Server{
|
|||||||
|
|
||||||
$this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));
|
$this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));
|
||||||
|
|
||||||
$centerX = $level->getSpawnLocation()->getX() >> 4;
|
$spawnLocation = $level->getSpawnLocation();
|
||||||
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
|
$centerX = $spawnLocation->x >> 4;
|
||||||
|
$centerZ = $spawnLocation->z >> 4;
|
||||||
|
|
||||||
$order = [];
|
$order = [];
|
||||||
|
|
||||||
@ -1236,7 +1244,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getConfigBoolean(string $variable, bool $defaultValue = false) : bool{
|
public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
|
||||||
$v = getopt("", ["$variable::"]);
|
$v = getopt("", ["$variable::"]);
|
||||||
if(isset($v[$variable])){
|
if(isset($v[$variable])){
|
||||||
$value = $v[$variable];
|
$value = $v[$variable];
|
||||||
@ -1258,6 +1266,18 @@ class Server{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
|
* @param string $variable
|
||||||
|
* @param bool $defaultValue
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getConfigBoolean(string $variable, bool $defaultValue = false) : bool{
|
||||||
|
return $this->getConfigBool($variable, $defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $variable
|
* @param string $variable
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
@ -1381,7 +1401,7 @@ class Server{
|
|||||||
if(is_array($value)){
|
if(is_array($value)){
|
||||||
$commands = $value;
|
$commands = $value;
|
||||||
}else{
|
}else{
|
||||||
$commands[] = $value;
|
$commands[] = (string) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[$key] = $commands;
|
$result[$key] = $commands;
|
||||||
@ -1395,6 +1415,9 @@ class Server{
|
|||||||
* @return Server
|
* @return Server
|
||||||
*/
|
*/
|
||||||
public static function getInstance() : Server{
|
public static function getInstance() : Server{
|
||||||
|
if(self::$instance === null){
|
||||||
|
throw new \RuntimeException("Attempt to retrieve Server instance outside server thread");
|
||||||
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1407,19 +1430,19 @@ class Server{
|
|||||||
/**
|
/**
|
||||||
* @param \ClassLoader $autoloader
|
* @param \ClassLoader $autoloader
|
||||||
* @param \ThreadedLogger $logger
|
* @param \ThreadedLogger $logger
|
||||||
* @param string $filePath
|
|
||||||
* @param string $dataPath
|
* @param string $dataPath
|
||||||
* @param string $pluginPath
|
* @param string $pluginPath
|
||||||
*/
|
*/
|
||||||
public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, string $filePath, string $dataPath, string $pluginPath){
|
public function __construct(\ClassLoader $autoloader, \ThreadedLogger $logger, string $dataPath, string $pluginPath){
|
||||||
|
if(self::$instance !== null){
|
||||||
|
throw new \InvalidStateException("Only one server instance can exist at once");
|
||||||
|
}
|
||||||
self::$instance = $this;
|
self::$instance = $this;
|
||||||
self::$sleeper = new \Threaded;
|
self::$sleeper = new \Threaded;
|
||||||
$this->autoloader = $autoloader;
|
$this->autoloader = $autoloader;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
$this->filePath = $filePath;
|
|
||||||
if(!file_exists($dataPath . "worlds/")){
|
if(!file_exists($dataPath . "worlds/")){
|
||||||
mkdir($dataPath . "worlds/", 0777);
|
mkdir($dataPath . "worlds/", 0777);
|
||||||
}
|
}
|
||||||
@ -1441,7 +1464,7 @@ class Server{
|
|||||||
|
|
||||||
$this->logger->info("Loading pocketmine.yml...");
|
$this->logger->info("Loading pocketmine.yml...");
|
||||||
if(!file_exists($this->dataPath . "pocketmine.yml")){
|
if(!file_exists($this->dataPath . "pocketmine.yml")){
|
||||||
$content = file_get_contents($this->filePath . "src/pocketmine/resources/pocketmine.yml");
|
$content = file_get_contents(\pocketmine\RESOURCE_PATH . "pocketmine.yml");
|
||||||
if($version->isDev()){
|
if($version->isDev()){
|
||||||
$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
|
$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
|
||||||
}
|
}
|
||||||
@ -1463,7 +1486,7 @@ class Server{
|
|||||||
|
|
||||||
$this->logger->info("Loading server properties...");
|
$this->logger->info("Loading server properties...");
|
||||||
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
||||||
"motd" => "Minecraft: PE Server",
|
"motd" => \pocketmine\NAME . " Server",
|
||||||
"server-port" => 19132,
|
"server-port" => 19132,
|
||||||
"white-list" => false,
|
"white-list" => false,
|
||||||
"announce-player-achievements" => true,
|
"announce-player-achievements" => true,
|
||||||
@ -1485,10 +1508,11 @@ class Server{
|
|||||||
"enable-rcon" => false,
|
"enable-rcon" => false,
|
||||||
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
||||||
"auto-save" => true,
|
"auto-save" => true,
|
||||||
"view-distance" => 8
|
"view-distance" => 8,
|
||||||
|
"xbox-auth" => true
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->forceLanguage = $this->getProperty("settings.force-language", false);
|
$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
|
||||||
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
|
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
|
||||||
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
||||||
|
|
||||||
@ -1503,6 +1527,8 @@ class Server{
|
|||||||
if($processors > 0){
|
if($processors > 0){
|
||||||
$poolSize = max(1, $processors);
|
$poolSize = max(1, $processors);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
$poolSize = (int) $poolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerScheduler::$WORKERS = $poolSize;
|
ServerScheduler::$WORKERS = $poolSize;
|
||||||
@ -1512,7 +1538,12 @@ class Server{
|
|||||||
}else{
|
}else{
|
||||||
Network::$BATCH_THRESHOLD = -1;
|
Network::$BATCH_THRESHOLD = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
|
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
|
||||||
|
if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
|
||||||
|
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
|
||||||
|
$this->networkCompressionLevel = 7;
|
||||||
|
}
|
||||||
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
|
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
|
||||||
|
|
||||||
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
||||||
@ -1524,7 +1555,7 @@ class Server{
|
|||||||
|
|
||||||
$this->scheduler = new ServerScheduler();
|
$this->scheduler = new ServerScheduler();
|
||||||
|
|
||||||
if($this->getConfigBoolean("enable-rcon", false) === true){
|
if($this->getConfigBool("enable-rcon", false) === true){
|
||||||
try{
|
try{
|
||||||
$this->rcon = new RCON(
|
$this->rcon = new RCON(
|
||||||
$this,
|
$this,
|
||||||
@ -1556,10 +1587,20 @@ class Server{
|
|||||||
$this->banByIP->load();
|
$this->banByIP->load();
|
||||||
|
|
||||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||||
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
$this->setAutoSave($this->getConfigBool("auto-save", true));
|
||||||
|
|
||||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
$this->onlineMode = $this->getConfigBool("xbox-auth", true);
|
||||||
$this->setConfigInt("difficulty", 3);
|
if($this->onlineMode){
|
||||||
|
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth", ["enabled", "will"]));
|
||||||
|
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty", ["disable", "false"]));
|
||||||
|
}else{
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth", ["disabled", "will not"]));
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty", ["enable", "true"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->getConfigBool("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||||
|
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(\pocketmine\DEBUG >= 0){
|
if(\pocketmine\DEBUG >= 0){
|
||||||
@ -1579,12 +1620,13 @@ class Server{
|
|||||||
|
|
||||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [
|
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [
|
||||||
$this->getName(),
|
$this->getName(),
|
||||||
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE,
|
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::RESET,
|
||||||
$this->getCodename(),
|
$this->getCodename(),
|
||||||
$this->getApiVersion()
|
$this->getApiVersion()
|
||||||
]));
|
]));
|
||||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
||||||
|
|
||||||
|
|
||||||
Timings::init();
|
Timings::init();
|
||||||
|
|
||||||
$this->consoleSender = new ConsoleCommandSender();
|
$this->consoleSender = new ConsoleCommandSender();
|
||||||
@ -1592,7 +1634,6 @@ class Server{
|
|||||||
|
|
||||||
Entity::init();
|
Entity::init();
|
||||||
Tile::init();
|
Tile::init();
|
||||||
InventoryType::init();
|
|
||||||
BlockFactory::init();
|
BlockFactory::init();
|
||||||
Enchantment::init();
|
Enchantment::init();
|
||||||
ItemFactory::init();
|
ItemFactory::init();
|
||||||
@ -1601,7 +1642,7 @@ class Server{
|
|||||||
Attribute::init();
|
Attribute::init();
|
||||||
$this->craftingManager = new CraftingManager();
|
$this->craftingManager = new CraftingManager();
|
||||||
|
|
||||||
$this->resourceManager = new ResourcePackManager($this, $this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR);
|
$this->resourceManager = new ResourcePackManager($this->getDataPath() . "resource_packs" . DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
||||||
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
|
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
|
||||||
@ -1626,35 +1667,37 @@ class Server{
|
|||||||
LevelProviderManager::addProvider(Anvil::class);
|
LevelProviderManager::addProvider(Anvil::class);
|
||||||
LevelProviderManager::addProvider(McRegion::class);
|
LevelProviderManager::addProvider(McRegion::class);
|
||||||
LevelProviderManager::addProvider(PMAnvil::class);
|
LevelProviderManager::addProvider(PMAnvil::class);
|
||||||
|
LevelProviderManager::addProvider(LevelDB::class);
|
||||||
if(extension_loaded("leveldb")){
|
if(extension_loaded("leveldb")){
|
||||||
$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
|
$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
|
||||||
LevelProviderManager::addProvider(LevelDB::class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Generator::addGenerator(Flat::class, "flat");
|
Generator::addGenerator(Flat::class, "flat");
|
||||||
Generator::addGenerator(Normal::class, "normal");
|
Generator::addGenerator(Normal::class, "normal");
|
||||||
Generator::addGenerator(Normal::class, "default");
|
Generator::addGenerator(Normal::class, "default");
|
||||||
Generator::addGenerator(Nether::class, "hell");
|
Generator::addGenerator(Nether::class, "hell");
|
||||||
Generator::addGenerator(Nether::class, "nether");
|
Generator::addGenerator(Nether::class, "nether");
|
||||||
|
|
||||||
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
|
foreach((array) $this->getProperty("worlds", []) as $name => $options){
|
||||||
|
if(!is_array($options)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if($this->loadLevel($name) === false){
|
if($this->loadLevel($name) === false){
|
||||||
$seed = $this->getProperty("worlds.$name.seed", time());
|
$seed = $options["seed"] ?? time();
|
||||||
if(is_string($seed) and !is_numeric($seed)){
|
if(is_string($seed) and !is_numeric($seed)){
|
||||||
$seed = Utils::javaStringHash($seed);
|
$seed = Utils::javaStringHash($seed);
|
||||||
}elseif(!is_int($seed)){
|
}elseif(!is_int($seed)){
|
||||||
$seed = (int) $seed;
|
$seed = (int) $seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
|
if(isset($options["generator"])){
|
||||||
$generator = Generator::getGenerator(array_shift($options));
|
$generatorOptions = explode(":", $options["generator"]);
|
||||||
if(count($options) > 0){
|
$generator = Generator::getGenerator(array_shift($generatorOptions));
|
||||||
$options = [
|
if(count($options) > 0){
|
||||||
"preset" => implode(":", $options)
|
$options["preset"] = implode(":", $generatorOptions);
|
||||||
];
|
}
|
||||||
}else{
|
}else{
|
||||||
$options = [];
|
$generator = Generator::getGenerator("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->generateLevel($name, $seed, $generator, $options);
|
$this->generateLevel($name, $seed, $generator, $options);
|
||||||
@ -1681,8 +1724,9 @@ class Server{
|
|||||||
$this->setDefaultLevel($this->getLevelByName($default));
|
$this->setDefaultLevel($this->getLevelByName($default));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($this->properties->hasChanged()){
|
||||||
$this->properties->save(true);
|
$this->properties->save(true);
|
||||||
|
}
|
||||||
|
|
||||||
if(!($this->getDefaultLevel() instanceof Level)){
|
if(!($this->getDefaultLevel() instanceof Level)){
|
||||||
$this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
|
$this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
|
||||||
@ -1886,17 +1930,9 @@ class Server{
|
|||||||
$pk->encode();
|
$pk->encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($immediate){
|
foreach($identifiers as $i){
|
||||||
foreach($identifiers as $i){
|
if(isset($this->players[$i])){
|
||||||
if(isset($this->players[$i])){
|
$this->players[$i]->sendDataPacket($pk, false, $immediate);
|
||||||
$this->players[$i]->directDataPacket($pk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
foreach($identifiers as $i){
|
|
||||||
if(isset($this->players[$i])){
|
|
||||||
$this->players[$i]->dataPacket($pk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1955,7 +1991,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$sender->sendMessage(new TranslationContainer(TextFormat::GOLD . "%commands.generic.notFound"));
|
$sender->sendMessage($this->getLanguage()->translateString(TextFormat::RED . "%commands.generic.notFound"));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1975,8 +2011,8 @@ class Server{
|
|||||||
$this->properties->reload();
|
$this->properties->reload();
|
||||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||||
|
|
||||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
if($this->getConfigBool("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||||
$this->setConfigInt("difficulty", 3);
|
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->banByIP->load();
|
$this->banByIP->load();
|
||||||
@ -2048,8 +2084,10 @@ class Server{
|
|||||||
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
|
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLogger()->debug("Saving properties");
|
if($this->properties->hasChanged()){
|
||||||
$this->properties->save();
|
$this->getLogger()->debug("Saving properties");
|
||||||
|
$this->properties->save();
|
||||||
|
}
|
||||||
|
|
||||||
$this->getLogger()->debug("Closing console");
|
$this->getLogger()->debug("Closing console");
|
||||||
$this->console->shutdown();
|
$this->console->shutdown();
|
||||||
@ -2058,11 +2096,13 @@ class Server{
|
|||||||
if($this->network instanceof Network){
|
if($this->network instanceof Network){
|
||||||
$this->getLogger()->debug("Stopping network interfaces");
|
$this->getLogger()->debug("Stopping network interfaces");
|
||||||
foreach($this->network->getInterfaces() as $interface){
|
foreach($this->network->getInterfaces() as $interface){
|
||||||
|
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
|
||||||
$interface->shutdown();
|
$interface->shutdown();
|
||||||
$this->network->unregisterInterface($interface);
|
$this->network->unregisterInterface($interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->getLogger()->debug("Collecting cycles");
|
||||||
gc_collect_cycles();
|
gc_collect_cycles();
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->logger->logException($e);
|
$this->logger->logException($e);
|
||||||
@ -2082,8 +2122,8 @@ class Server{
|
|||||||
/**
|
/**
|
||||||
* Starts the PocketMine-MP server and starts processing ticks and packets
|
* Starts the PocketMine-MP server and starts processing ticks and packets
|
||||||
*/
|
*/
|
||||||
public function start(){
|
private function start(){
|
||||||
if($this->getConfigBoolean("enable-query", true) === true){
|
if($this->getConfigBool("enable-query", true) === true){
|
||||||
$this->queryHandler = new QueryHandler();
|
$this->queryHandler = new QueryHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2125,6 +2165,10 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Throwable $e
|
||||||
|
* @param array|null $trace
|
||||||
|
*/
|
||||||
public function exceptionHandler(\Throwable $e, $trace = null){
|
public function exceptionHandler(\Throwable $e, $trace = null){
|
||||||
if($e === null){
|
if($e === null){
|
||||||
return;
|
return;
|
||||||
@ -2271,7 +2315,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function addOnlinePlayer(Player $player){
|
public function addOnlinePlayer(Player $player){
|
||||||
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
|
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
|
|
||||||
$this->playerList[$player->getRawUniqueId()] = $player;
|
$this->playerList[$player->getRawUniqueId()] = $player;
|
||||||
}
|
}
|
||||||
@ -2280,32 +2324,44 @@ class Server{
|
|||||||
if(isset($this->playerList[$player->getRawUniqueId()])){
|
if(isset($this->playerList[$player->getRawUniqueId()])){
|
||||||
unset($this->playerList[$player->getRawUniqueId()]);
|
unset($this->playerList[$player->getRawUniqueId()]);
|
||||||
|
|
||||||
$pk = new PlayerListPacket();
|
$this->removePlayerListData($player->getUniqueId());
|
||||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
|
||||||
$pk->entries[] = [$player->getUniqueId()];
|
|
||||||
$this->broadcastPacket($this->playerList, $pk);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePlayerListData(UUID $uuid, $entityId, $name, $skinId, $skinData, array $players = null){
|
/**
|
||||||
|
* @param UUID $uuid
|
||||||
|
* @param int $entityId
|
||||||
|
* @param string $name
|
||||||
|
* @param Skin $skin
|
||||||
|
* @param Player[]|null $players
|
||||||
|
*/
|
||||||
|
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
$pk->entries[] = [$uuid, $entityId, $name, $skinId, $skinData];
|
|
||||||
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
|
||||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UUID $uuid
|
||||||
|
* @param Player[]|null $players
|
||||||
|
*/
|
||||||
public function removePlayerListData(UUID $uuid, array $players = null){
|
public function removePlayerListData(UUID $uuid, array $players = null){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||||
$pk->entries[] = [$uuid];
|
$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
|
||||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player $p
|
||||||
|
*/
|
||||||
public function sendFullPlayerListData(Player $p){
|
public function sendFullPlayerListData(Player $p){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
foreach($this->playerList as $player){
|
foreach($this->playerList as $player){
|
||||||
$pk->entries[] = [$player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData()];
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
}
|
}
|
||||||
|
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk);
|
||||||
@ -2315,7 +2371,7 @@ class Server{
|
|||||||
foreach($this->players as $p){
|
foreach($this->players as $p){
|
||||||
if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
|
if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
|
||||||
$p->close("", "Login timeout");
|
$p->close("", "Login timeout");
|
||||||
}elseif($this->alwaysTickPlayers and $p->joined){
|
}elseif($this->alwaysTickPlayers and $p->spawned){
|
||||||
$p->onUpdate($currentTick);
|
$p->onUpdate($currentTick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2350,7 +2406,11 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->logger->critical($this->getLanguage()->translateString("pocketmine.level.tickError", [$level->getName(), $e->getMessage()]));
|
if(!$level->isClosed()){
|
||||||
|
$this->logger->critical($this->getLanguage()->translateString("pocketmine.level.tickError", [$level->getName(), $e->getMessage()]));
|
||||||
|
}else{
|
||||||
|
$this->logger->critical($this->getLanguage()->translateString("pocketmine.level.tickUnloadError", [$level->getName()]));
|
||||||
|
}
|
||||||
$this->logger->logException($e);
|
$this->logger->logException($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2360,7 +2420,7 @@ class Server{
|
|||||||
if($this->getAutoSave()){
|
if($this->getAutoSave()){
|
||||||
Timings::$worldSaveTimer->startTiming();
|
Timings::$worldSaveTimer->startTiming();
|
||||||
foreach($this->players as $index => $player){
|
foreach($this->players as $index => $player){
|
||||||
if($player->joined){
|
if($player->spawned){
|
||||||
$player->save(true);
|
$player->save(true);
|
||||||
}elseif(!$player->isConnected()){
|
}elseif(!$player->isConnected()){
|
||||||
$this->removePlayer($player);
|
$this->removePlayer($player);
|
||||||
@ -2375,7 +2435,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
|
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
|
||||||
if($this->getProperty("anonymous-statistics.enabled", true)){
|
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
|
||||||
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
||||||
}
|
}
|
||||||
$this->uniquePlayers = [];
|
$this->uniquePlayers = [];
|
||||||
@ -2426,8 +2486,6 @@ class Server{
|
|||||||
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
||||||
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
||||||
|
|
||||||
$this->network->resetStatistics();
|
|
||||||
|
|
||||||
Timings::$titleTickTimer->stopTiming();
|
Timings::$titleTickTimer->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2488,25 +2546,26 @@ class Server{
|
|||||||
$player->checkNetwork();
|
$player->checkNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($this->tickCounter & 0b1111) === 0){
|
if(($this->tickCounter % 20) === 0){
|
||||||
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
||||||
$this->titleTick();
|
$this->titleTick();
|
||||||
}
|
}
|
||||||
$this->currentTPS = 20;
|
$this->currentTPS = 20;
|
||||||
$this->currentUse = 0;
|
$this->currentUse = 0;
|
||||||
|
|
||||||
if(($this->tickCounter & 0b111111111) === 0){
|
$this->network->updateName();
|
||||||
try{
|
$this->network->resetStatistics();
|
||||||
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
}
|
||||||
if($this->queryHandler !== null){
|
|
||||||
$this->queryHandler->regenerateInfo();
|
|
||||||
}
|
|
||||||
}catch(\Throwable $e){
|
|
||||||
$this->logger->logException($e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getNetwork()->updateName();
|
if(($this->tickCounter & 0b111111111) === 0){
|
||||||
|
try{
|
||||||
|
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
||||||
|
if($this->queryHandler !== null){
|
||||||
|
$this->queryHandler->regenerateInfo();
|
||||||
|
}
|
||||||
|
}catch(\Throwable $e){
|
||||||
|
$this->logger->logException($e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
|
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
|
||||||
|
@ -30,6 +30,9 @@ abstract class Thread extends \Thread{
|
|||||||
|
|
||||||
/** @var \ClassLoader */
|
/** @var \ClassLoader */
|
||||||
protected $classLoader;
|
protected $classLoader;
|
||||||
|
/** @var string|null */
|
||||||
|
protected $composerAutoloaderPath;
|
||||||
|
|
||||||
protected $isKilled = false;
|
protected $isKilled = false;
|
||||||
|
|
||||||
public function getClassLoader(){
|
public function getClassLoader(){
|
||||||
@ -37,6 +40,8 @@ abstract class Thread extends \Thread{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setClassLoader(\ClassLoader $loader = null){
|
public function setClassLoader(\ClassLoader $loader = null){
|
||||||
|
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||||
|
|
||||||
if($loader === null){
|
if($loader === null){
|
||||||
$loader = Server::getInstance()->getLoader();
|
$loader = Server::getInstance()->getLoader();
|
||||||
}
|
}
|
||||||
@ -51,16 +56,15 @@ abstract class Thread extends \Thread{
|
|||||||
* (unless you are using a custom autoloader).
|
* (unless you are using a custom autoloader).
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
if(!interface_exists("ClassLoader", false)){
|
if($this->composerAutoloaderPath !== null){
|
||||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
require $this->composerAutoloaderPath;
|
||||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
|
||||||
}
|
}
|
||||||
if($this->classLoader !== null){
|
if($this->classLoader !== null){
|
||||||
$this->classLoader->register(true);
|
$this->classLoader->register(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
|
use pocketmine\utils\MainLogger;
|
||||||
|
|
||||||
class ThreadManager extends \Volatile{
|
class ThreadManager extends \Volatile{
|
||||||
|
|
||||||
/** @var ThreadManager */
|
/** @var ThreadManager */
|
||||||
@ -68,4 +70,23 @@ class ThreadManager extends \Volatile{
|
|||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function stopAll() : int{
|
||||||
|
$logger = MainLogger::getLogger();
|
||||||
|
|
||||||
|
$erroredThreads = 0;
|
||||||
|
|
||||||
|
foreach($this->getAll() as $thread){
|
||||||
|
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
||||||
|
try{
|
||||||
|
$thread->quit();
|
||||||
|
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
||||||
|
}catch(\ThreadException $e){
|
||||||
|
++$erroredThreads;
|
||||||
|
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $erroredThreads;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,6 +30,8 @@ abstract class Worker extends \Worker{
|
|||||||
|
|
||||||
/** @var \ClassLoader */
|
/** @var \ClassLoader */
|
||||||
protected $classLoader;
|
protected $classLoader;
|
||||||
|
/** @var string|null */
|
||||||
|
protected $composerAutoloaderPath;
|
||||||
|
|
||||||
protected $isKilled = false;
|
protected $isKilled = false;
|
||||||
|
|
||||||
@ -38,6 +40,8 @@ abstract class Worker extends \Worker{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setClassLoader(\ClassLoader $loader = null){
|
public function setClassLoader(\ClassLoader $loader = null){
|
||||||
|
$this->composerAutoloaderPath = \pocketmine\COMPOSER_AUTOLOADER_PATH;
|
||||||
|
|
||||||
if($loader === null){
|
if($loader === null){
|
||||||
$loader = Server::getInstance()->getLoader();
|
$loader = Server::getInstance()->getLoader();
|
||||||
}
|
}
|
||||||
@ -52,16 +56,15 @@ abstract class Worker extends \Worker{
|
|||||||
* (unless you are using a custom autoloader).
|
* (unless you are using a custom autoloader).
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
if(!interface_exists("ClassLoader", false)){
|
if($this->composerAutoloaderPath !== null){
|
||||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
require $this->composerAutoloaderPath;
|
||||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
|
||||||
}
|
}
|
||||||
if($this->classLoader !== null){
|
if($this->classLoader !== null){
|
||||||
$this->classLoader->register(true);
|
$this->classLoader->register(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +33,6 @@ use pocketmine\item\Item;
|
|||||||
class Air extends Transparent{
|
class Air extends Transparent{
|
||||||
|
|
||||||
protected $id = self::AIR;
|
protected $id = self::AIR;
|
||||||
protected $meta = 0;
|
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
@ -54,7 +54,7 @@ class Air extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,10 +66,14 @@ class Air extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
public function getBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCollisionBoxes() : array{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -78,4 +82,4 @@ class Air extends Transparent{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,26 +26,27 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\inventory\AnvilInventory;
|
use pocketmine\inventory\AnvilInventory;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Anvil extends Fallable{
|
class Anvil extends Fallable{
|
||||||
|
|
||||||
const TYPE_NORMAL = 0;
|
public const TYPE_NORMAL = 0;
|
||||||
const TYPE_SLIGHTLY_DAMAGED = 4;
|
public const TYPE_SLIGHTLY_DAMAGED = 4;
|
||||||
const TYPE_VERY_DAMAGED = 8;
|
public const TYPE_VERY_DAMAGED = 8;
|
||||||
|
|
||||||
protected $id = self::ANVIL;
|
protected $id = self::ANVIL;
|
||||||
|
|
||||||
public function isSolid() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isTransparent() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
@ -64,7 +65,35 @@ class Anvil extends Fallable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
$inset = 0.125;
|
||||||
|
|
||||||
|
if($this->meta & 0x01){ //east/west
|
||||||
|
return new AxisAlignedBB(
|
||||||
|
$this->x,
|
||||||
|
$this->y,
|
||||||
|
$this->z + $inset,
|
||||||
|
$this->x + 1,
|
||||||
|
$this->y + 1,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
return new AxisAlignedBB(
|
||||||
|
$this->x + $inset,
|
||||||
|
$this->y,
|
||||||
|
$this->z,
|
||||||
|
$this->x + 1 - $inset,
|
||||||
|
$this->y + 1,
|
||||||
|
$this->z + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
@ -75,19 +104,15 @@ class Anvil extends Fallable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->meta & 0x0c) | $direction;
|
$this->meta = ($this->meta & 0x0c) | $direction;
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
return [
|
||||||
return [
|
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x0c)
|
||||||
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x0c, 1)
|
];
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,18 +29,14 @@ use pocketmine\item\ItemFactory;
|
|||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Bed as TileBed;
|
use pocketmine\tile\Bed as TileBed;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
use pocketmine\utils\TextFormat;
|
use pocketmine\utils\TextFormat;
|
||||||
|
|
||||||
class Bed extends Transparent{
|
class Bed extends Transparent{
|
||||||
const BITFLAG_OCCUPIED = 0x04;
|
public const BITFLAG_OCCUPIED = 0x04;
|
||||||
const BITFLAG_HEAD = 0x08;
|
public const BITFLAG_HEAD = 0x08;
|
||||||
|
|
||||||
protected $id = self::BED_BLOCK;
|
protected $id = self::BED_BLOCK;
|
||||||
|
|
||||||
@ -58,7 +54,7 @@ class Bed extends Transparent{
|
|||||||
return "Bed Block";
|
return "Bed Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -129,7 +125,7 @@ class Bed extends Transparent{
|
|||||||
/**
|
/**
|
||||||
* @return Bed|null
|
* @return Bed|null
|
||||||
*/
|
*/
|
||||||
public function getOtherHalf(){
|
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))){
|
||||||
return $other;
|
return $other;
|
||||||
@ -146,7 +142,7 @@ class Bed extends Transparent{
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){
|
}elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){
|
||||||
//MCPE doesn't have messages for bed too far away
|
$player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.tooFar"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +171,7 @@ class Bed extends Transparent{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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()){
|
||||||
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
$meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03;
|
||||||
@ -184,20 +180,8 @@ class Bed extends Transparent{
|
|||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||||
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||||
|
|
||||||
$nbt = new CompoundTag("", [
|
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
||||||
new StringTag("id", Tile::BED),
|
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
||||||
new ByteTag("color", $item->getDamage() & 0x0f),
|
|
||||||
new IntTag("x", $blockReplace->x),
|
|
||||||
new IntTag("y", $blockReplace->y),
|
|
||||||
new IntTag("z", $blockReplace->z)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nbt2 = clone $nbt;
|
|
||||||
$nbt2["x"] = $next->x;
|
|
||||||
$nbt2["z"] = $next->z;
|
|
||||||
|
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt);
|
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt2);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -206,25 +190,16 @@ class Bed extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
|
||||||
if(($other = $this->getOtherHalf()) !== null){
|
|
||||||
$this->getLevel()->useBreakOn($other, $item, $player, $player !== null); //make sure tiles get removed
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($this->isHeadPart()){
|
if($this->isHeadPart()){
|
||||||
$tile = $this->getLevel()->getTile($this);
|
$tile = $this->getLevel()->getTile($this);
|
||||||
if($tile instanceof TileBed){
|
if($tile instanceof TileBed){
|
||||||
return [
|
return [
|
||||||
ItemFactory::get($this->getItemId(), $tile->getColor(), 1)
|
ItemFactory::get($this->getItemId(), $tile->getColor())
|
||||||
];
|
];
|
||||||
}else{
|
}else{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get($this->getItemId(), 14, 1) //Red
|
ItemFactory::get($this->getItemId(), 14) //Red
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,4 +207,15 @@ class Bed extends Transparent{
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAffectedBlocks() : array{
|
||||||
|
if(($other = $this->getOtherHalf()) !== null){
|
||||||
|
return [$this, $other];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getAffectedBlocks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,4 +49,4 @@ class Bedrock extends Solid{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,20 @@ class Beetroot extends Crops{
|
|||||||
return "Beetroot Block";
|
return "Beetroot Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if($this->meta >= 0x07){
|
if($this->meta >= 0x07){
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::BEETROOT, 0, 1),
|
ItemFactory::get(Item::BEETROOT),
|
||||||
ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))
|
ItemFactory::get(Item::BEETROOT_SEEDS, 0, mt_rand(0, 3))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::BEETROOT_SEEDS, 0, 1)
|
ItemFactory::get(Item::BEETROOT_SEEDS)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get(Item::BEETROOT_SEEDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,13 +27,13 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\item\enchantment\Enchantment;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\level\MovingObjectPosition;
|
|
||||||
use pocketmine\level\Position;
|
use pocketmine\level\Position;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
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;
|
||||||
@ -61,21 +61,25 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
protected $id;
|
protected $id;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
protected $meta = 0;
|
protected $meta = 0;
|
||||||
/** @var string */
|
/** @var string|null */
|
||||||
protected $fallbackName;
|
protected $fallbackName;
|
||||||
/** @var int|null */
|
/** @var int|null */
|
||||||
protected $itemId;
|
protected $itemId;
|
||||||
|
|
||||||
/** @var AxisAlignedBB */
|
/** @var AxisAlignedBB */
|
||||||
public $boundingBox = null;
|
protected $boundingBox = null;
|
||||||
|
|
||||||
|
|
||||||
|
/** @var AxisAlignedBB[]|null */
|
||||||
|
protected $collisionBoxes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $id The block type's ID, 0-255
|
* @param int $id The block type's ID, 0-255
|
||||||
* @param int $meta Meta value of the block type
|
* @param int $meta Meta value of the block type
|
||||||
* @param string $name English name of the block type (TODO: implement translations)
|
* @param string|null $name English name of the block type (TODO: implement translations)
|
||||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||||
*/
|
*/
|
||||||
public function __construct(int $id, int $meta = 0, string $name = "Unknown", int $itemId = null){
|
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
$this->fallbackName = $name;
|
$this->fallbackName = $name;
|
||||||
@ -86,7 +90,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return $this->fallbackName;
|
return $this->fallbackName ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,7 +120,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* @param int $meta
|
* @param int $meta
|
||||||
*/
|
*/
|
||||||
final public function setDamage(int $meta){
|
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");
|
||||||
}
|
}
|
||||||
@ -136,6 +140,34 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the block meta, stripped of non-variant flags.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getVariant() : int{
|
||||||
|
return $this->meta & $this->getVariantBitmask();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AKA: Block->isPlaceable
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function canBePlaced() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function canBeReplaced() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||||
|
return $blockReplace->canBeReplaced();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||||
*
|
*
|
||||||
@ -143,12 +175,12 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @param Block $blockReplace
|
* @param Block $blockReplace
|
||||||
* @param Block $blockClicked
|
* @param Block $blockClicked
|
||||||
* @param int $face
|
* @param int $face
|
||||||
* @param Vector3 $facePos
|
* @param Vector3 $clickVector
|
||||||
* @param Player|null $player
|
* @param Player|null $player
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($this, $this, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +195,51 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the level of tool required to harvest this block (for normal blocks). When the tool type matches the
|
||||||
|
* block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
|
||||||
|
* successfully harvest the block.
|
||||||
|
*
|
||||||
|
* If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
|
||||||
|
* Otherwise, 1 should be returned if a tool is required, 0 if not.
|
||||||
|
*
|
||||||
|
* @see Item::getBlockToolHarvestLevel()
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
|
||||||
|
* harvest level requirement.
|
||||||
|
*
|
||||||
|
* In most cases this is also used to determine whether block drops should be created or not, except in some
|
||||||
|
* special cases such as vines.
|
||||||
|
*
|
||||||
|
* @param Item $tool
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isCompatibleWithTool(Item $tool) : bool{
|
||||||
|
if($this->getHardness() < 0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$toolType = $this->getToolType();
|
||||||
|
$harvestLevel = $this->getToolHarvestLevel();
|
||||||
|
return $toolType === BlockToolType::TYPE_NONE or $harvestLevel === 0 or (
|
||||||
|
($toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $harvestLevel);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the actions needed so the block is broken with the Item
|
* Do the actions needed so the block is broken with the Item
|
||||||
*
|
*
|
||||||
@ -175,6 +252,42 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seconds that this block takes to be broken using an specific Item
|
||||||
|
*
|
||||||
|
* @param Item $item
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public function getBreakTime(Item $item) : float{
|
||||||
|
$base = $this->getHardness();
|
||||||
|
if($this->isCompatibleWithTool($item)){
|
||||||
|
$base *= 1.5;
|
||||||
|
}else{
|
||||||
|
$base *= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
$efficiency = $item->getMiningEfficiency($this);
|
||||||
|
if($efficiency <= 0){
|
||||||
|
throw new \RuntimeException("Item efficiency is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
$base /= $efficiency;
|
||||||
|
|
||||||
|
return $base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether random block updates will be done on this block.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function ticksRandomly() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires a block update on the Block
|
* Fires a block update on the Block
|
||||||
*
|
*
|
||||||
@ -222,13 +335,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->getHardness() * 5;
|
return $this->getHardness() * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getToolType() : int{
|
|
||||||
return Tool::TYPE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
@ -266,32 +372,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether random block updates will be done on this block.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function ticksRandomly() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AKA: Block->isPlaceable
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canBePlaced() : bool{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Block|null $with
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -328,7 +408,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +417,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
*
|
*
|
||||||
* @param Position $v
|
* @param Position $v
|
||||||
*/
|
*/
|
||||||
final public function position(Position $v){
|
final public function position(Position $v) : void{
|
||||||
$this->x = (int) $v->x;
|
$this->x = (int) $v->x;
|
||||||
$this->y = (int) $v->y;
|
$this->y = (int) $v->y;
|
||||||
$this->z = (int) $v->z;
|
$this->z = (int) $v->z;
|
||||||
@ -353,59 +433,59 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return Item[]
|
* @return Item[]
|
||||||
*/
|
*/
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
|
if($this->isCompatibleWithTool($item)){
|
||||||
|
if($this->isAffectedBySilkTouch() and $item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
||||||
|
return $this->getSilkTouchDrops($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getDropsForCompatibleTool($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
|
||||||
|
*
|
||||||
|
* @param Item $item
|
||||||
|
*
|
||||||
|
* @return Item[]
|
||||||
|
*/
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get($this->getItemId(), $this->getDamage() & $this->getVariantBitmask(), 1)
|
ItemFactory::get($this->getItemId(), $this->getVariant())
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the seconds that this block takes to be broken using an specific Item
|
* Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
|
||||||
*
|
*
|
||||||
* @param Item $item
|
* @param Item $item
|
||||||
*
|
*
|
||||||
* @return float
|
* @return Item[]
|
||||||
*/
|
*/
|
||||||
public function getBreakTime(Item $item) : float{
|
public function getSilkTouchDrops(Item $item) : array{
|
||||||
$base = $this->getHardness() * 1.5;
|
return [
|
||||||
if($this->canBeBrokenWith($item)){
|
ItemFactory::get($this->getItemId(), $this->getVariant())
|
||||||
if($this->getToolType() === Tool::TYPE_SHEARS and $item->isShears()){
|
];
|
||||||
$base /= 15;
|
|
||||||
}elseif(
|
|
||||||
($this->getToolType() === Tool::TYPE_PICKAXE and ($tier = $item->isPickaxe()) !== false) or
|
|
||||||
($this->getToolType() === Tool::TYPE_AXE and ($tier = $item->isAxe()) !== false) or
|
|
||||||
($this->getToolType() === Tool::TYPE_SHOVEL and ($tier = $item->isShovel()) !== false)
|
|
||||||
){
|
|
||||||
switch($tier){
|
|
||||||
case Tool::TIER_WOODEN:
|
|
||||||
$base /= 2;
|
|
||||||
break;
|
|
||||||
case Tool::TIER_STONE:
|
|
||||||
$base /= 4;
|
|
||||||
break;
|
|
||||||
case Tool::TIER_IRON:
|
|
||||||
$base /= 6;
|
|
||||||
break;
|
|
||||||
case Tool::TIER_DIAMOND:
|
|
||||||
$base /= 8;
|
|
||||||
break;
|
|
||||||
case Tool::TIER_GOLD:
|
|
||||||
$base /= 12;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$base *= 3.33;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->isSword()){
|
|
||||||
$base *= 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeBrokenWith(Item $item) : bool{
|
/**
|
||||||
return $this->getHardness() !== -1;
|
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself. Since most blocks drop
|
||||||
|
* themselves anyway, this is implicitly true.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item that players will equip when middle-clicking on this block.
|
||||||
|
* @return Item
|
||||||
|
*/
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get($this->getItemId(), $this->getVariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -417,7 +497,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Block on the side $side, works like Vector3::side()
|
* Returns the Block on the side $side, works like Vector3::getSide()
|
||||||
*
|
*
|
||||||
* @param int $side
|
* @param int $side
|
||||||
* @param int $step
|
* @param int $step
|
||||||
@ -432,6 +512,45 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getHorizontalSides() : array{
|
||||||
|
return [
|
||||||
|
$this->getSide(Vector3::SIDE_NORTH),
|
||||||
|
$this->getSide(Vector3::SIDE_SOUTH),
|
||||||
|
$this->getSide(Vector3::SIDE_WEST),
|
||||||
|
$this->getSide(Vector3::SIDE_EAST)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the six blocks around this block.
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getAllSides() : array{
|
||||||
|
return array_merge(
|
||||||
|
[
|
||||||
|
$this->getSide(Vector3::SIDE_DOWN),
|
||||||
|
$this->getSide(Vector3::SIDE_UP)
|
||||||
|
],
|
||||||
|
$this->getHorizontalSides()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of blocks that this block is part of. In most cases, only contains the block itself, but in cases
|
||||||
|
* such as double plants, beds and doors, will contain both halves.
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getAffectedBlocks() : array{
|
||||||
|
return [$this];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -447,22 +566,50 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||||
$bb2 = $this->getBoundingBox();
|
$bbs = $this->getCollisionBoxes();
|
||||||
|
|
||||||
return $bb2 !== null and $bb->intersectsWith($bb2);
|
foreach($bbs as $bb2){
|
||||||
|
if($bb->intersectsWith($bb2)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Entity $entity
|
* @param Entity $entity
|
||||||
*/
|
*/
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AxisAlignedBB[]
|
||||||
|
*/
|
||||||
|
public function getCollisionBoxes() : array{
|
||||||
|
if($this->collisionBoxes === null){
|
||||||
|
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->collisionBoxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AxisAlignedBB[]
|
||||||
|
*/
|
||||||
|
protected function recalculateCollisionBoxes() : array{
|
||||||
|
if($bb = $this->recalculateBoundingBox()){
|
||||||
|
return [$bb];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return AxisAlignedBB|null
|
* @return AxisAlignedBB|null
|
||||||
*/
|
*/
|
||||||
public function getBoundingBox(){
|
public function getBoundingBox() : ?AxisAlignedBB{
|
||||||
if($this->boundingBox === null){
|
if($this->boundingBox === null){
|
||||||
$this->boundingBox = $this->recalculateBoundingBox();
|
$this->boundingBox = $this->recalculateBoundingBox();
|
||||||
}
|
}
|
||||||
@ -472,7 +619,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* @return AxisAlignedBB|null
|
* @return AxisAlignedBB|null
|
||||||
*/
|
*/
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -483,92 +630,46 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears any cached precomputed objects, such as bounding boxes. This is called on block neighbour update and when
|
||||||
|
* the block is set into the world to remove any outdated precomputed things such as AABBs and force recalculation.
|
||||||
|
*/
|
||||||
|
public function clearCaches() : void{
|
||||||
|
$this->boundingBox = null;
|
||||||
|
$this->collisionBoxes = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Vector3 $pos1
|
* @param Vector3 $pos1
|
||||||
* @param Vector3 $pos2
|
* @param Vector3 $pos2
|
||||||
*
|
*
|
||||||
* @return MovingObjectPosition|null
|
* @return RayTraceResult|null
|
||||||
*/
|
*/
|
||||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){
|
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||||
$bb = $this->getBoundingBox();
|
$bbs = $this->getCollisionBoxes();
|
||||||
if($bb === null){
|
if(empty($bbs)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX);
|
/** @var RayTraceResult|null $currentHit */
|
||||||
$v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX);
|
$currentHit = null;
|
||||||
$v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY);
|
/** @var int|float $currentDistance */
|
||||||
$v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY);
|
$currentDistance = PHP_INT_MAX;
|
||||||
$v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ);
|
|
||||||
$v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ);
|
|
||||||
|
|
||||||
if($v1 !== null and !$bb->isVectorInYZ($v1)){
|
foreach($bbs as $bb){
|
||||||
$v1 = null;
|
$nextHit = $bb->calculateIntercept($pos1, $pos2);
|
||||||
|
if($nextHit === null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
|
||||||
|
if($nextDistance < $currentDistance){
|
||||||
|
$currentHit = $nextHit;
|
||||||
|
$currentDistance = $nextDistance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($v2 !== null and !$bb->isVectorInYZ($v2)){
|
return $currentHit;
|
||||||
$v2 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v3 !== null and !$bb->isVectorInXZ($v3)){
|
|
||||||
$v3 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v4 !== null and !$bb->isVectorInXZ($v4)){
|
|
||||||
$v4 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v5 !== null and !$bb->isVectorInXY($v5)){
|
|
||||||
$v5 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v6 !== null and !$bb->isVectorInXY($v6)){
|
|
||||||
$v6 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$vector = $v1;
|
|
||||||
|
|
||||||
if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($vector === null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$f = -1;
|
|
||||||
|
|
||||||
if($vector === $v1){
|
|
||||||
$f = 4;
|
|
||||||
}elseif($vector === $v2){
|
|
||||||
$f = 5;
|
|
||||||
}elseif($vector === $v3){
|
|
||||||
$f = 0;
|
|
||||||
}elseif($vector === $v4){
|
|
||||||
$f = 1;
|
|
||||||
}elseif($vector === $v5){
|
|
||||||
$f = 2;
|
|
||||||
}elseif($vector === $v6){
|
|
||||||
$f = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||||
|
@ -56,7 +56,7 @@ class BlockFactory{
|
|||||||
*
|
*
|
||||||
* @param bool $force
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public static function init(bool $force = false){
|
public static function init(bool $force = false) : void{
|
||||||
if(self::$list === null or $force){
|
if(self::$list === null or $force){
|
||||||
self::$list = new \SplFixedArray(256);
|
self::$list = new \SplFixedArray(256);
|
||||||
self::$fullList = new \SplFixedArray(4096);
|
self::$fullList = new \SplFixedArray(4096);
|
||||||
@ -133,7 +133,7 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Furnace());
|
self::registerBlock(new Furnace());
|
||||||
self::registerBlock(new BurningFurnace());
|
self::registerBlock(new BurningFurnace());
|
||||||
self::registerBlock(new SignPost());
|
self::registerBlock(new SignPost());
|
||||||
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door Block", Item::OAK_DOOR));
|
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
|
||||||
self::registerBlock(new Ladder());
|
self::registerBlock(new Ladder());
|
||||||
self::registerBlock(new Rail());
|
self::registerBlock(new Rail());
|
||||||
self::registerBlock(new CobblestoneStairs());
|
self::registerBlock(new CobblestoneStairs());
|
||||||
@ -153,8 +153,8 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Cactus());
|
self::registerBlock(new Cactus());
|
||||||
self::registerBlock(new Clay());
|
self::registerBlock(new Clay());
|
||||||
self::registerBlock(new Sugarcane());
|
self::registerBlock(new Sugarcane());
|
||||||
|
//TODO: JUKEBOX
|
||||||
self::registerBlock(new Fence());
|
self::registerBlock(new WoodenFence());
|
||||||
self::registerBlock(new Pumpkin());
|
self::registerBlock(new Pumpkin());
|
||||||
self::registerBlock(new Netherrack());
|
self::registerBlock(new Netherrack());
|
||||||
self::registerBlock(new SoulSand());
|
self::registerBlock(new SoulSand());
|
||||||
@ -168,8 +168,8 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Trapdoor());
|
self::registerBlock(new Trapdoor());
|
||||||
//TODO: MONSTER_EGG
|
//TODO: MONSTER_EGG
|
||||||
self::registerBlock(new StoneBricks());
|
self::registerBlock(new StoneBricks());
|
||||||
//TODO: BROWN_MUSHROOM_BLOCK
|
self::registerBlock(new BrownMushroomBlock());
|
||||||
//TODO: RED_MUSHROOM_BLOCK
|
self::registerBlock(new RedMushroomBlock());
|
||||||
self::registerBlock(new IronBars());
|
self::registerBlock(new IronBars());
|
||||||
self::registerBlock(new GlassPane());
|
self::registerBlock(new GlassPane());
|
||||||
self::registerBlock(new Melon());
|
self::registerBlock(new Melon());
|
||||||
@ -199,7 +199,7 @@ class BlockFactory{
|
|||||||
self::registerBlock(new CocoaBlock());
|
self::registerBlock(new CocoaBlock());
|
||||||
self::registerBlock(new SandstoneStairs());
|
self::registerBlock(new SandstoneStairs());
|
||||||
self::registerBlock(new EmeraldOre());
|
self::registerBlock(new EmeraldOre());
|
||||||
//TODO: ENDER_CHEST
|
self::registerBlock(new EnderChest());
|
||||||
self::registerBlock(new TripwireHook());
|
self::registerBlock(new TripwireHook());
|
||||||
self::registerBlock(new Tripwire());
|
self::registerBlock(new Tripwire());
|
||||||
self::registerBlock(new Emerald());
|
self::registerBlock(new Emerald());
|
||||||
@ -245,12 +245,13 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Coal());
|
self::registerBlock(new Coal());
|
||||||
self::registerBlock(new PackedIce());
|
self::registerBlock(new PackedIce());
|
||||||
self::registerBlock(new DoublePlant());
|
self::registerBlock(new DoublePlant());
|
||||||
|
self::registerBlock(new StandingBanner());
|
||||||
|
self::registerBlock(new WallBanner());
|
||||||
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
||||||
//TODO: RED_SANDSTONE
|
self::registerBlock(new RedSandstone());
|
||||||
//TODO: RED_SANDSTONE_STAIRS
|
self::registerBlock(new RedSandstoneStairs());
|
||||||
//TODO: DOUBLE_STONE_SLAB2
|
self::registerBlock(new DoubleStoneSlab2());
|
||||||
//TODO: STONE_SLAB2
|
self::registerBlock(new StoneSlab2());
|
||||||
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
|
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
|
||||||
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
|
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
|
||||||
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
||||||
@ -259,19 +260,20 @@ class BlockFactory{
|
|||||||
//TODO: REPEATING_COMMAND_BLOCK
|
//TODO: REPEATING_COMMAND_BLOCK
|
||||||
//TODO: CHAIN_COMMAND_BLOCK
|
//TODO: CHAIN_COMMAND_BLOCK
|
||||||
|
|
||||||
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door Block", Item::SPRUCE_DOOR));
|
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door Block", Item::BIRCH_DOOR));
|
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door", Item::BIRCH_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door Block", Item::JUNGLE_DOOR));
|
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door", Item::JUNGLE_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door Block", Item::ACACIA_DOOR));
|
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door", Item::ACACIA_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door Block", Item::DARK_OAK_DOOR));
|
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door", Item::DARK_OAK_DOOR));
|
||||||
self::registerBlock(new GrassPath());
|
self::registerBlock(new GrassPath());
|
||||||
self::registerBlock(new ItemFrame());
|
self::registerBlock(new ItemFrame());
|
||||||
//TODO: CHORUS_FLOWER
|
//TODO: CHORUS_FLOWER
|
||||||
//TODO: PURPUR_BLOCK
|
self::registerBlock(new Purpur());
|
||||||
|
|
||||||
//TODO: PURPUR_STAIRS
|
self::registerBlock(new PurpurStairs());
|
||||||
|
|
||||||
//TODO: END_BRICKS
|
//TODO: UNDYED_SHULKER_BOX
|
||||||
|
self::registerBlock(new EndStoneBricks());
|
||||||
//TODO: FROSTED_ICE
|
//TODO: FROSTED_ICE
|
||||||
self::registerBlock(new EndRod());
|
self::registerBlock(new EndRod());
|
||||||
//TODO: END_GATEWAY
|
//TODO: END_GATEWAY
|
||||||
@ -300,7 +302,7 @@ class BlockFactory{
|
|||||||
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
|
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
|
||||||
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
||||||
self::registerBlock(new Concrete());
|
self::registerBlock(new Concrete());
|
||||||
//TODO: CONCRETEPOWDER
|
self::registerBlock(new ConcretePowder());
|
||||||
|
|
||||||
//TODO: CHORUS_PLANT
|
//TODO: CHORUS_PLANT
|
||||||
self::registerBlock(new StainedGlass());
|
self::registerBlock(new StainedGlass());
|
||||||
@ -314,6 +316,7 @@ class BlockFactory{
|
|||||||
//TODO: INFO_UPDATE2
|
//TODO: INFO_UPDATE2
|
||||||
//TODO: MOVINGBLOCK
|
//TODO: MOVINGBLOCK
|
||||||
//TODO: OBSERVER
|
//TODO: OBSERVER
|
||||||
|
//TODO: STRUCTURE_BLOCK
|
||||||
|
|
||||||
//TODO: RESERVED6
|
//TODO: RESERVED6
|
||||||
|
|
||||||
@ -338,10 +341,10 @@ class BlockFactory{
|
|||||||
* @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
|
||||||
* $override parameter.
|
* $override parameter.
|
||||||
*/
|
*/
|
||||||
public static function registerBlock(Block $block, bool $override = false){
|
public static function registerBlock(Block $block, bool $override = false) : void{
|
||||||
$id = $block->getId();
|
$id = $block->getId();
|
||||||
|
|
||||||
if(self::$list[$id] !== null and !(self::$list[$id] instanceof UnknownBlock) and !$override){
|
if(!$override and self::isRegistered($id)){
|
||||||
throw new \RuntimeException("Trying to overwrite an already registered block");
|
throw new \RuntimeException("Trying to overwrite an already registered block");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,4 +406,15 @@ class BlockFactory{
|
|||||||
public static function getBlockStatesArray() : \SplFixedArray{
|
public static function getBlockStatesArray() : \SplFixedArray{
|
||||||
return self::$fullList;
|
return self::$fullList;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* 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{
|
||||||
|
$b = self::$list[$id];
|
||||||
|
return $b !== null and !($b instanceof UnknownBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,252 +25,255 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
interface BlockIds{
|
interface BlockIds{
|
||||||
|
|
||||||
const AIR = 0;
|
public const AIR = 0;
|
||||||
const STONE = 1;
|
public const STONE = 1;
|
||||||
const GRASS = 2;
|
public const GRASS = 2;
|
||||||
const DIRT = 3;
|
public const DIRT = 3;
|
||||||
const COBBLESTONE = 4;
|
public const COBBLESTONE = 4;
|
||||||
const PLANKS = 5, WOODEN_PLANKS = 5;
|
public const PLANKS = 5, WOODEN_PLANKS = 5;
|
||||||
const SAPLING = 6;
|
public const SAPLING = 6;
|
||||||
const BEDROCK = 7;
|
public const BEDROCK = 7;
|
||||||
const FLOWING_WATER = 8;
|
public const FLOWING_WATER = 8;
|
||||||
const STILL_WATER = 9, WATER = 9;
|
public const STILL_WATER = 9, WATER = 9;
|
||||||
const FLOWING_LAVA = 10;
|
public const FLOWING_LAVA = 10;
|
||||||
const LAVA = 11, STILL_LAVA = 11;
|
public const LAVA = 11, STILL_LAVA = 11;
|
||||||
const SAND = 12;
|
public const SAND = 12;
|
||||||
const GRAVEL = 13;
|
public const GRAVEL = 13;
|
||||||
const GOLD_ORE = 14;
|
public const GOLD_ORE = 14;
|
||||||
const IRON_ORE = 15;
|
public const IRON_ORE = 15;
|
||||||
const COAL_ORE = 16;
|
public const COAL_ORE = 16;
|
||||||
const LOG = 17, WOOD = 17;
|
public const LOG = 17, WOOD = 17;
|
||||||
const LEAVES = 18;
|
public const LEAVES = 18;
|
||||||
const SPONGE = 19;
|
public const SPONGE = 19;
|
||||||
const GLASS = 20;
|
public const GLASS = 20;
|
||||||
const LAPIS_ORE = 21;
|
public const LAPIS_ORE = 21;
|
||||||
const LAPIS_BLOCK = 22;
|
public const LAPIS_BLOCK = 22;
|
||||||
const DISPENSER = 23;
|
public const DISPENSER = 23;
|
||||||
const SANDSTONE = 24;
|
public const SANDSTONE = 24;
|
||||||
const NOTEBLOCK = 25, NOTE_BLOCK = 25;
|
public const NOTEBLOCK = 25, NOTE_BLOCK = 25;
|
||||||
const BED_BLOCK = 26;
|
public const BED_BLOCK = 26;
|
||||||
const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
|
public const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
|
||||||
const DETECTOR_RAIL = 28;
|
public const DETECTOR_RAIL = 28;
|
||||||
const STICKY_PISTON = 29;
|
public const STICKY_PISTON = 29;
|
||||||
const COBWEB = 30, WEB = 30;
|
public const COBWEB = 30, WEB = 30;
|
||||||
const TALLGRASS = 31, TALL_GRASS = 31;
|
public const TALLGRASS = 31, TALL_GRASS = 31;
|
||||||
const DEADBUSH = 32, DEAD_BUSH = 32;
|
public const DEADBUSH = 32, DEAD_BUSH = 32;
|
||||||
const PISTON = 33;
|
public const PISTON = 33;
|
||||||
const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
|
public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
|
||||||
const WOOL = 35;
|
public const WOOL = 35;
|
||||||
|
|
||||||
const DANDELION = 37, YELLOW_FLOWER = 37;
|
public const DANDELION = 37, YELLOW_FLOWER = 37;
|
||||||
const POPPY = 38, RED_FLOWER = 38;
|
public const POPPY = 38, RED_FLOWER = 38;
|
||||||
const BROWN_MUSHROOM = 39;
|
public const BROWN_MUSHROOM = 39;
|
||||||
const RED_MUSHROOM = 40;
|
public const RED_MUSHROOM = 40;
|
||||||
const GOLD_BLOCK = 41;
|
public const GOLD_BLOCK = 41;
|
||||||
const IRON_BLOCK = 42;
|
public const IRON_BLOCK = 42;
|
||||||
const DOUBLE_STONE_SLAB = 43;
|
public const DOUBLE_STONE_SLAB = 43;
|
||||||
const STONE_SLAB = 44;
|
public const STONE_SLAB = 44;
|
||||||
const BRICK_BLOCK = 45;
|
public const BRICK_BLOCK = 45;
|
||||||
const TNT = 46;
|
public const TNT = 46;
|
||||||
const BOOKSHELF = 47;
|
public const BOOKSHELF = 47;
|
||||||
const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
|
public const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
|
||||||
const OBSIDIAN = 49;
|
public const OBSIDIAN = 49;
|
||||||
const TORCH = 50;
|
public const TORCH = 50;
|
||||||
const FIRE = 51;
|
public const FIRE = 51;
|
||||||
const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
|
public const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
|
||||||
const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
|
public const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
|
||||||
const CHEST = 54;
|
public const CHEST = 54;
|
||||||
const REDSTONE_WIRE = 55;
|
public const REDSTONE_WIRE = 55;
|
||||||
const DIAMOND_ORE = 56;
|
public const DIAMOND_ORE = 56;
|
||||||
const DIAMOND_BLOCK = 57;
|
public const DIAMOND_BLOCK = 57;
|
||||||
const CRAFTING_TABLE = 58, WORKBENCH = 58;
|
public const CRAFTING_TABLE = 58, WORKBENCH = 58;
|
||||||
const WHEAT_BLOCK = 59;
|
public const WHEAT_BLOCK = 59;
|
||||||
const FARMLAND = 60;
|
public const FARMLAND = 60;
|
||||||
const FURNACE = 61;
|
public const FURNACE = 61;
|
||||||
const BURNING_FURNACE = 62, LIT_FURNACE = 62;
|
public const BURNING_FURNACE = 62, LIT_FURNACE = 62;
|
||||||
const SIGN_POST = 63, STANDING_SIGN = 63;
|
public const SIGN_POST = 63, STANDING_SIGN = 63;
|
||||||
const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
|
public const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
|
||||||
const LADDER = 65;
|
public const LADDER = 65;
|
||||||
const RAIL = 66;
|
public const RAIL = 66;
|
||||||
const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
|
public const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
|
||||||
const WALL_SIGN = 68;
|
public const WALL_SIGN = 68;
|
||||||
const LEVER = 69;
|
public const LEVER = 69;
|
||||||
const STONE_PRESSURE_PLATE = 70;
|
public const STONE_PRESSURE_PLATE = 70;
|
||||||
const IRON_DOOR_BLOCK = 71;
|
public const IRON_DOOR_BLOCK = 71;
|
||||||
const WOODEN_PRESSURE_PLATE = 72;
|
public const WOODEN_PRESSURE_PLATE = 72;
|
||||||
const REDSTONE_ORE = 73;
|
public const REDSTONE_ORE = 73;
|
||||||
const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
|
public const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
|
||||||
const UNLIT_REDSTONE_TORCH = 75;
|
public const UNLIT_REDSTONE_TORCH = 75;
|
||||||
const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
|
public const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
|
||||||
const STONE_BUTTON = 77;
|
public const STONE_BUTTON = 77;
|
||||||
const SNOW_LAYER = 78;
|
public const SNOW_LAYER = 78;
|
||||||
const ICE = 79;
|
public const ICE = 79;
|
||||||
const SNOW = 80, SNOW_BLOCK = 80;
|
public const SNOW = 80, SNOW_BLOCK = 80;
|
||||||
const CACTUS = 81;
|
public const CACTUS = 81;
|
||||||
const CLAY_BLOCK = 82;
|
public const CLAY_BLOCK = 82;
|
||||||
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
public const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
||||||
|
public const JUKEBOX = 84;
|
||||||
|
public const FENCE = 85;
|
||||||
|
public const PUMPKIN = 86;
|
||||||
|
public const NETHERRACK = 87;
|
||||||
|
public const SOUL_SAND = 88;
|
||||||
|
public const GLOWSTONE = 89;
|
||||||
|
public const PORTAL = 90;
|
||||||
|
public const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
|
||||||
|
public const CAKE_BLOCK = 92;
|
||||||
|
public const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
|
||||||
|
public const POWERED_REPEATER = 94;
|
||||||
|
public const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
|
||||||
|
public const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
|
||||||
|
public const MONSTER_EGG = 97;
|
||||||
|
public const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
|
||||||
|
public const BROWN_MUSHROOM_BLOCK = 99;
|
||||||
|
public const RED_MUSHROOM_BLOCK = 100;
|
||||||
|
public const IRON_BARS = 101;
|
||||||
|
public const GLASS_PANE = 102;
|
||||||
|
public const MELON_BLOCK = 103;
|
||||||
|
public const PUMPKIN_STEM = 104;
|
||||||
|
public const MELON_STEM = 105;
|
||||||
|
public const VINE = 106, VINES = 106;
|
||||||
|
public const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
|
||||||
|
public const BRICK_STAIRS = 108;
|
||||||
|
public const STONE_BRICK_STAIRS = 109;
|
||||||
|
public const MYCELIUM = 110;
|
||||||
|
public const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
|
||||||
|
public const NETHER_BRICK_BLOCK = 112;
|
||||||
|
public const NETHER_BRICK_FENCE = 113;
|
||||||
|
public const NETHER_BRICK_STAIRS = 114;
|
||||||
|
public const NETHER_WART_PLANT = 115;
|
||||||
|
public const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
|
||||||
|
public const BREWING_STAND_BLOCK = 117;
|
||||||
|
public const CAULDRON_BLOCK = 118;
|
||||||
|
public const END_PORTAL = 119;
|
||||||
|
public const END_PORTAL_FRAME = 120;
|
||||||
|
public const END_STONE = 121;
|
||||||
|
public const DRAGON_EGG = 122;
|
||||||
|
public const REDSTONE_LAMP = 123;
|
||||||
|
public const LIT_REDSTONE_LAMP = 124;
|
||||||
|
public const DROPPER = 125;
|
||||||
|
public const ACTIVATOR_RAIL = 126;
|
||||||
|
public const COCOA = 127, COCOA_BLOCK = 127;
|
||||||
|
public const SANDSTONE_STAIRS = 128;
|
||||||
|
public const EMERALD_ORE = 129;
|
||||||
|
public const ENDER_CHEST = 130;
|
||||||
|
public const TRIPWIRE_HOOK = 131;
|
||||||
|
public const TRIPWIRE = 132, TRIP_WIRE = 132;
|
||||||
|
public const EMERALD_BLOCK = 133;
|
||||||
|
public const SPRUCE_STAIRS = 134;
|
||||||
|
public const BIRCH_STAIRS = 135;
|
||||||
|
public const JUNGLE_STAIRS = 136;
|
||||||
|
public const COMMAND_BLOCK = 137;
|
||||||
|
public const BEACON = 138;
|
||||||
|
public const COBBLESTONE_WALL = 139, STONE_WALL = 139;
|
||||||
|
public const FLOWER_POT_BLOCK = 140;
|
||||||
|
public const CARROTS = 141, CARROT_BLOCK = 141;
|
||||||
|
public const POTATOES = 142, POTATO_BLOCK = 142;
|
||||||
|
public const WOODEN_BUTTON = 143;
|
||||||
|
public const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
|
||||||
|
public const ANVIL = 145;
|
||||||
|
public const TRAPPED_CHEST = 146;
|
||||||
|
public const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
|
||||||
|
public const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
|
||||||
|
public const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
|
||||||
|
public const POWERED_COMPARATOR = 150;
|
||||||
|
public const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
|
||||||
|
public const REDSTONE_BLOCK = 152;
|
||||||
|
public const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
|
||||||
|
public const HOPPER_BLOCK = 154;
|
||||||
|
public const QUARTZ_BLOCK = 155;
|
||||||
|
public const QUARTZ_STAIRS = 156;
|
||||||
|
public const DOUBLE_WOODEN_SLAB = 157;
|
||||||
|
public const WOODEN_SLAB = 158;
|
||||||
|
public const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
|
||||||
|
public const STAINED_GLASS_PANE = 160;
|
||||||
|
public const LEAVES2 = 161;
|
||||||
|
public const LOG2 = 162, WOOD2 = 162;
|
||||||
|
public const ACACIA_STAIRS = 163;
|
||||||
|
public const DARK_OAK_STAIRS = 164;
|
||||||
|
public const SLIME = 165, SLIME_BLOCK = 165;
|
||||||
|
|
||||||
const FENCE = 85;
|
public const IRON_TRAPDOOR = 167;
|
||||||
const PUMPKIN = 86;
|
public const PRISMARINE = 168;
|
||||||
const NETHERRACK = 87;
|
public const SEALANTERN = 169, SEA_LANTERN = 169;
|
||||||
const SOUL_SAND = 88;
|
public const HAY_BALE = 170, HAY_BLOCK = 170;
|
||||||
const GLOWSTONE = 89;
|
public const CARPET = 171;
|
||||||
const PORTAL = 90;
|
public const HARDENED_CLAY = 172;
|
||||||
const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
|
public const COAL_BLOCK = 173;
|
||||||
const CAKE_BLOCK = 92;
|
public const PACKED_ICE = 174;
|
||||||
const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
|
public const DOUBLE_PLANT = 175;
|
||||||
const POWERED_REPEATER = 94;
|
public const STANDING_BANNER = 176;
|
||||||
const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
|
public const WALL_BANNER = 177;
|
||||||
const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
|
public const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
||||||
const MONSTER_EGG = 97;
|
public const RED_SANDSTONE = 179;
|
||||||
const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
|
public const RED_SANDSTONE_STAIRS = 180;
|
||||||
const BROWN_MUSHROOM_BLOCK = 99;
|
public const DOUBLE_STONE_SLAB2 = 181;
|
||||||
const RED_MUSHROOM_BLOCK = 100;
|
public const STONE_SLAB2 = 182;
|
||||||
const IRON_BARS = 101;
|
public const SPRUCE_FENCE_GATE = 183;
|
||||||
const GLASS_PANE = 102;
|
public const BIRCH_FENCE_GATE = 184;
|
||||||
const MELON_BLOCK = 103;
|
public const JUNGLE_FENCE_GATE = 185;
|
||||||
const PUMPKIN_STEM = 104;
|
public const DARK_OAK_FENCE_GATE = 186;
|
||||||
const MELON_STEM = 105;
|
public const ACACIA_FENCE_GATE = 187;
|
||||||
const VINE = 106, VINES = 106;
|
public const REPEATING_COMMAND_BLOCK = 188;
|
||||||
const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
|
public const CHAIN_COMMAND_BLOCK = 189;
|
||||||
const BRICK_STAIRS = 108;
|
|
||||||
const STONE_BRICK_STAIRS = 109;
|
|
||||||
const MYCELIUM = 110;
|
|
||||||
const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
|
|
||||||
const NETHER_BRICK_BLOCK = 112;
|
|
||||||
const NETHER_BRICK_FENCE = 113;
|
|
||||||
const NETHER_BRICK_STAIRS = 114;
|
|
||||||
const NETHER_WART_PLANT = 115;
|
|
||||||
const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
|
|
||||||
const BREWING_STAND_BLOCK = 117;
|
|
||||||
const CAULDRON_BLOCK = 118;
|
|
||||||
const END_PORTAL = 119;
|
|
||||||
const END_PORTAL_FRAME = 120;
|
|
||||||
const END_STONE = 121;
|
|
||||||
const DRAGON_EGG = 122;
|
|
||||||
const REDSTONE_LAMP = 123;
|
|
||||||
const LIT_REDSTONE_LAMP = 124;
|
|
||||||
const DROPPER = 125;
|
|
||||||
const ACTIVATOR_RAIL = 126;
|
|
||||||
const COCOA = 127, COCOA_BLOCK = 127;
|
|
||||||
const SANDSTONE_STAIRS = 128;
|
|
||||||
const EMERALD_ORE = 129;
|
|
||||||
const ENDER_CHEST = 130;
|
|
||||||
const TRIPWIRE_HOOK = 131;
|
|
||||||
const TRIPWIRE = 132, TRIP_WIRE = 132;
|
|
||||||
const EMERALD_BLOCK = 133;
|
|
||||||
const SPRUCE_STAIRS = 134;
|
|
||||||
const BIRCH_STAIRS = 135;
|
|
||||||
const JUNGLE_STAIRS = 136;
|
|
||||||
const COMMAND_BLOCK = 137;
|
|
||||||
const BEACON = 138;
|
|
||||||
const COBBLESTONE_WALL = 139, STONE_WALL = 139;
|
|
||||||
const FLOWER_POT_BLOCK = 140;
|
|
||||||
const CARROTS = 141, CARROT_BLOCK = 141;
|
|
||||||
const POTATOES = 142, POTATO_BLOCK = 142;
|
|
||||||
const WOODEN_BUTTON = 143;
|
|
||||||
const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
|
|
||||||
const ANVIL = 145;
|
|
||||||
const TRAPPED_CHEST = 146;
|
|
||||||
const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
|
|
||||||
const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
|
|
||||||
const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
|
|
||||||
const POWERED_COMPARATOR = 150;
|
|
||||||
const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
|
|
||||||
const REDSTONE_BLOCK = 152;
|
|
||||||
const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
|
|
||||||
const HOPPER_BLOCK = 154;
|
|
||||||
const QUARTZ_BLOCK = 155;
|
|
||||||
const QUARTZ_STAIRS = 156;
|
|
||||||
const DOUBLE_WOODEN_SLAB = 157;
|
|
||||||
const WOODEN_SLAB = 158;
|
|
||||||
const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
|
|
||||||
const STAINED_GLASS_PANE = 160;
|
|
||||||
const LEAVES2 = 161;
|
|
||||||
const LOG2 = 162, WOOD2 = 162;
|
|
||||||
const ACACIA_STAIRS = 163;
|
|
||||||
const DARK_OAK_STAIRS = 164;
|
|
||||||
const SLIME = 165, SLIME_BLOCK = 165;
|
|
||||||
|
|
||||||
const IRON_TRAPDOOR = 167;
|
public const SPRUCE_DOOR_BLOCK = 193;
|
||||||
const PRISMARINE = 168;
|
public const BIRCH_DOOR_BLOCK = 194;
|
||||||
const SEALANTERN = 169, SEA_LANTERN = 169;
|
public const JUNGLE_DOOR_BLOCK = 195;
|
||||||
const HAY_BALE = 170, HAY_BLOCK = 170;
|
public const ACACIA_DOOR_BLOCK = 196;
|
||||||
const CARPET = 171;
|
public const DARK_OAK_DOOR_BLOCK = 197;
|
||||||
const HARDENED_CLAY = 172;
|
public const GRASS_PATH = 198;
|
||||||
const COAL_BLOCK = 173;
|
public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
|
||||||
const PACKED_ICE = 174;
|
public const CHORUS_FLOWER = 200;
|
||||||
const DOUBLE_PLANT = 175;
|
public const PURPUR_BLOCK = 201;
|
||||||
|
|
||||||
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
public const PURPUR_STAIRS = 203;
|
||||||
const RED_SANDSTONE = 179;
|
|
||||||
const RED_SANDSTONE_STAIRS = 180;
|
|
||||||
const DOUBLE_STONE_SLAB2 = 181;
|
|
||||||
const STONE_SLAB2 = 182;
|
|
||||||
const SPRUCE_FENCE_GATE = 183;
|
|
||||||
const BIRCH_FENCE_GATE = 184;
|
|
||||||
const JUNGLE_FENCE_GATE = 185;
|
|
||||||
const DARK_OAK_FENCE_GATE = 186;
|
|
||||||
const ACACIA_FENCE_GATE = 187;
|
|
||||||
const REPEATING_COMMAND_BLOCK = 188;
|
|
||||||
const CHAIN_COMMAND_BLOCK = 189;
|
|
||||||
|
|
||||||
const SPRUCE_DOOR_BLOCK = 193;
|
public const UNDYED_SHULKER_BOX = 205;
|
||||||
const BIRCH_DOOR_BLOCK = 194;
|
public const END_BRICKS = 206;
|
||||||
const JUNGLE_DOOR_BLOCK = 195;
|
public const FROSTED_ICE = 207;
|
||||||
const ACACIA_DOOR_BLOCK = 196;
|
public const END_ROD = 208;
|
||||||
const DARK_OAK_DOOR_BLOCK = 197;
|
public const END_GATEWAY = 209;
|
||||||
const GRASS_PATH = 198;
|
|
||||||
const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
|
|
||||||
const CHORUS_FLOWER = 200;
|
|
||||||
const PURPUR_BLOCK = 201;
|
|
||||||
|
|
||||||
const PURPUR_STAIRS = 203;
|
public const MAGMA = 213;
|
||||||
|
public const NETHER_WART_BLOCK = 214;
|
||||||
|
public const RED_NETHER_BRICK = 215;
|
||||||
|
public const BONE_BLOCK = 216;
|
||||||
|
|
||||||
const END_BRICKS = 206;
|
public const SHULKER_BOX = 218;
|
||||||
const FROSTED_ICE = 207;
|
public const PURPLE_GLAZED_TERRACOTTA = 219;
|
||||||
const END_ROD = 208;
|
public const WHITE_GLAZED_TERRACOTTA = 220;
|
||||||
const END_GATEWAY = 209;
|
public const ORANGE_GLAZED_TERRACOTTA = 221;
|
||||||
|
public const MAGENTA_GLAZED_TERRACOTTA = 222;
|
||||||
|
public const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
|
||||||
|
public const YELLOW_GLAZED_TERRACOTTA = 224;
|
||||||
|
public const LIME_GLAZED_TERRACOTTA = 225;
|
||||||
|
public const PINK_GLAZED_TERRACOTTA = 226;
|
||||||
|
public const GRAY_GLAZED_TERRACOTTA = 227;
|
||||||
|
public const SILVER_GLAZED_TERRACOTTA = 228;
|
||||||
|
public const CYAN_GLAZED_TERRACOTTA = 229;
|
||||||
|
|
||||||
const MAGMA = 213;
|
public const BLUE_GLAZED_TERRACOTTA = 231;
|
||||||
const NETHER_WART_BLOCK = 214;
|
public const BROWN_GLAZED_TERRACOTTA = 232;
|
||||||
const RED_NETHER_BRICK = 215;
|
public const GREEN_GLAZED_TERRACOTTA = 233;
|
||||||
const BONE_BLOCK = 216;
|
public const RED_GLAZED_TERRACOTTA = 234;
|
||||||
|
public const BLACK_GLAZED_TERRACOTTA = 235;
|
||||||
|
public const CONCRETE = 236;
|
||||||
|
public const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
|
||||||
|
|
||||||
const SHULKER_BOX = 218;
|
public const CHORUS_PLANT = 240;
|
||||||
const PURPLE_GLAZED_TERRACOTTA = 219;
|
public const STAINED_GLASS = 241;
|
||||||
const WHITE_GLAZED_TERRACOTTA = 220;
|
|
||||||
const ORANGE_GLAZED_TERRACOTTA = 221;
|
|
||||||
const MAGENTA_GLAZED_TERRACOTTA = 222;
|
|
||||||
const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
|
|
||||||
const YELLOW_GLAZED_TERRACOTTA = 224;
|
|
||||||
const LIME_GLAZED_TERRACOTTA = 225;
|
|
||||||
const PINK_GLAZED_TERRACOTTA = 226;
|
|
||||||
const GRAY_GLAZED_TERRACOTTA = 227;
|
|
||||||
const SILVER_GLAZED_TERRACOTTA = 228;
|
|
||||||
const CYAN_GLAZED_TERRACOTTA = 229;
|
|
||||||
|
|
||||||
const BLUE_GLAZED_TERRACOTTA = 231;
|
public const PODZOL = 243;
|
||||||
const BROWN_GLAZED_TERRACOTTA = 232;
|
public const BEETROOT_BLOCK = 244;
|
||||||
const GREEN_GLAZED_TERRACOTTA = 233;
|
public const STONECUTTER = 245;
|
||||||
const RED_GLAZED_TERRACOTTA = 234;
|
public const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
|
||||||
const BLACK_GLAZED_TERRACOTTA = 235;
|
public const NETHERREACTOR = 247, NETHER_REACTOR = 247;
|
||||||
const CONCRETE = 236;
|
public const INFO_UPDATE = 248;
|
||||||
const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
|
public const INFO_UPDATE2 = 249;
|
||||||
|
public const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
||||||
|
public const OBSERVER = 251;
|
||||||
|
public const STRUCTURE_BLOCK = 252;
|
||||||
|
|
||||||
const CHORUS_PLANT = 240;
|
public const RESERVED6 = 255;
|
||||||
const STAINED_GLASS = 241;
|
|
||||||
|
|
||||||
const PODZOL = 243;
|
|
||||||
const BEETROOT_BLOCK = 244;
|
|
||||||
const STONECUTTER = 245;
|
|
||||||
const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
|
|
||||||
const NETHERREACTOR = 247, NETHER_REACTOR = 247;
|
|
||||||
const INFO_UPDATE = 248;
|
|
||||||
const INFO_UPDATE2 = 249;
|
|
||||||
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
|
||||||
const OBSERVER = 251;
|
|
||||||
|
|
||||||
const RESERVED6 = 255;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,21 +21,19 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\inventory;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves all the information regarding default inventory sizes and types
|
* Types of tools that can be used to break blocks
|
||||||
|
* Blocks may allow multiple tool types by combining these bitflags
|
||||||
*/
|
*/
|
||||||
interface SlotType{
|
interface BlockToolType{
|
||||||
const RESULT = 0;
|
|
||||||
|
|
||||||
const CRAFTING = 1; //Not used in Minecraft: PE yet
|
public const TYPE_NONE = 0;
|
||||||
|
public const TYPE_SWORD = 1 << 0;
|
||||||
|
public const TYPE_SHOVEL = 1 << 1;
|
||||||
|
public const TYPE_PICKAXE = 1 << 2;
|
||||||
|
public const TYPE_AXE = 1 << 3;
|
||||||
|
public const TYPE_SHEARS = 1 << 4;
|
||||||
|
|
||||||
const ARMOR = 2;
|
}
|
||||||
|
|
||||||
const CONTAINER = 3;
|
|
||||||
|
|
||||||
const HOTBAR = 4;
|
|
||||||
|
|
||||||
const FUEL = 5;
|
|
||||||
}
|
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\block\utils\PillarRotationHelper;
|
use pocketmine\block\utils\PillarRotationHelper;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
@ -46,10 +46,14 @@ class BoneBlock extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
}
|
}
|
||||||
@ -57,13 +61,4 @@ class BoneBlock extends Solid{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0x03;
|
return 0x03;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item); // TODO: Change the autogenerated stub
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -25,7 +25,6 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Bookshelf extends Solid{
|
class Bookshelf extends Solid{
|
||||||
|
|
||||||
@ -44,10 +43,10 @@ class Bookshelf extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::BOOK, 0, 3)
|
ItemFactory::get(Item::BOOK, 0, 3)
|
||||||
];
|
];
|
||||||
@ -57,4 +56,4 @@ class Bookshelf extends Solid{
|
|||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class BrewingStand extends Transparent{
|
class BrewingStand extends Transparent{
|
||||||
|
|
||||||
@ -42,7 +42,11 @@ class BrewingStand extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
@ -50,4 +54,4 @@ class BrewingStand extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class BrickStairs extends Stair{
|
class BrickStairs extends Stair{
|
||||||
|
|
||||||
@ -42,11 +42,15 @@ class BrickStairs extends Stair{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Brick Stairs";
|
return "Brick Stairs";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Bricks extends Solid{
|
class Bricks extends Solid{
|
||||||
|
|
||||||
@ -43,18 +42,14 @@ class Bricks extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Bricks";
|
return "Bricks";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -34,4 +34,4 @@ class BrownMushroom extends RedMushroom{
|
|||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,23 +21,21 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
|
||||||
class WoodenSword extends Tool{
|
class BrownMushroomBlock extends RedMushroomBlock{
|
||||||
public function __construct(int $meta = 0){
|
|
||||||
parent::__construct(self::WOODEN_SWORD, $meta, "Wooden Sword");
|
protected $id = Block::BROWN_MUSHROOM_BLOCK;
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Brown Mushroom Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSword(){
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return Tool::TIER_WOODEN;
|
return [
|
||||||
}
|
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
|
||||||
|
];
|
||||||
public function getFuelTime() : int{
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAttackPoints() : int{
|
|
||||||
return 5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,12 +24,8 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\NBT;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Furnace as TileFurnace;
|
use pocketmine\tile\Furnace as TileFurnace;
|
||||||
@ -39,6 +35,8 @@ class BurningFurnace extends Solid{
|
|||||||
|
|
||||||
protected $id = self::BURNING_FURNACE;
|
protected $id = self::BURNING_FURNACE;
|
||||||
|
|
||||||
|
protected $itemId = self::FURNACE;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
@ -52,14 +50,18 @@ class BurningFurnace extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return 13;
|
return 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
$faces = [
|
$faces = [
|
||||||
0 => 4,
|
0 => 4,
|
||||||
1 => 2,
|
1 => 2,
|
||||||
@ -68,26 +70,8 @@ class BurningFurnace extends Solid{
|
|||||||
];
|
];
|
||||||
$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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::FURNACE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -96,21 +80,11 @@ class BurningFurnace extends Solid{
|
|||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$furnace = $this->getLevel()->getTile($this);
|
$furnace = $this->getLevel()->getTile($this);
|
||||||
if(!($furnace instanceof TileFurnace)){
|
if(!($furnace instanceof TileFurnace)){
|
||||||
$nbt = new CompoundTag("", [
|
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::FURNACE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
$furnace = Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
if($furnace->namedtag->hasTag("Lock", StringTag::class) and $furnace->namedtag->getString("Lock") !== $item->getCustomName()){
|
||||||
if($furnace->namedtag->Lock->getValue() !== $item->getCustomName()){
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$player->addWindow($furnace->getInventory());
|
$player->addWindow($furnace->getInventory());
|
||||||
@ -122,12 +96,4 @@ class BurningFurnace extends Solid{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
51
src/pocketmine/block/Button.php
Normal file
51
src/pocketmine/block/Button.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
abstract class Button extends Flowable{
|
||||||
|
|
||||||
|
public function __construct(int $meta = 0){
|
||||||
|
$this->meta = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVariantBitmask() : int{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
|
//TODO: check valid target block
|
||||||
|
$this->meta = $face;
|
||||||
|
|
||||||
|
return $this->level->setBlock($this, $this, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
|
//TODO
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -54,7 +54,7 @@ class Cactus extends Transparent{
|
|||||||
return "Cactus";
|
return "Cactus";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
@ -70,7 +70,7 @@ class Cactus extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ 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()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
@ -112,7 +112,7 @@ class Cactus extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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::SAND or $down->getId() === self::CACTUS){
|
if($down->getId() === self::SAND or $down->getId() === self::CACTUS){
|
||||||
$block0 = $this->getSide(Vector3::SIDE_NORTH);
|
$block0 = $this->getSide(Vector3::SIDE_NORTH);
|
||||||
@ -132,4 +132,4 @@ class Cactus extends Transparent{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\entity\Effect;
|
use pocketmine\entity\Effect;
|
||||||
use pocketmine\event\entity\EntityEatBlockEvent;
|
use pocketmine\entity\Living;
|
||||||
use pocketmine\item\FoodSource;
|
use pocketmine\item\FoodSource;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
@ -45,10 +45,10 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Cake Block";
|
return "Cake";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f = $this->getDamage() * 0.125; //1 slice width
|
$f = $this->getDamage() * 0.125; //1 slice width
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
@ -85,25 +85,18 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
//TODO: refactor this into generic food handling
|
if($player !== null){
|
||||||
if($player instanceof Player and $player->getFood() < $player->getMaxFood()){
|
$player->consumeObject($this);
|
||||||
$player->getServer()->getPluginManager()->callEvent($ev = new EntityEatBlockEvent($player, $this));
|
return true;
|
||||||
|
|
||||||
if(!$ev->isCancelled()){
|
|
||||||
$player->addFood($ev->getFoodRestore());
|
|
||||||
$player->addSaturation($ev->getSaturationRestore());
|
|
||||||
foreach($ev->getAdditionalEffects() as $effect){
|
|
||||||
$player->addEffect($effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getLevel()->setBlock($this, $ev->getResidue());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -117,6 +110,13 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
return 0.4;
|
return 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function requiresHunger() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Block
|
||||||
|
*/
|
||||||
public function getResidue(){
|
public function getResidue(){
|
||||||
$clone = clone $this;
|
$clone = clone $this;
|
||||||
$clone->meta++;
|
$clone->meta++;
|
||||||
@ -132,4 +132,8 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
public function getAdditionalEffects() : array{
|
public function getAdditionalEffects() : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onConsume(Living $consumer) : void{
|
||||||
|
$this->level->setBlock($this, $this->getResidue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class Carpet extends Flowable{
|
|||||||
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
@ -62,7 +62,7 @@ class Carpet extends Flowable{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
@ -85,4 +85,4 @@ class Carpet extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,13 @@ class Carrot extends Crops{
|
|||||||
return "Carrot Block";
|
return "Carrot Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
|
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get(Item::CARROT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,13 +24,8 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\NBT;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Chest as TileChest;
|
use pocketmine\tile\Chest as TileChest;
|
||||||
@ -53,21 +48,22 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
//these are slightly bigger than in PC
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.025,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 0.0625,
|
$this->z + 0.025,
|
||||||
$this->x + 0.9375,
|
$this->x + 0.975,
|
||||||
$this->y + 0.9475,
|
$this->y + 0.95,
|
||||||
$this->z + 0.9375
|
$this->z + 0.975
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
$faces = [
|
$faces = [
|
||||||
0 => 4,
|
0 => 4,
|
||||||
1 => 2,
|
1 => 2,
|
||||||
@ -95,26 +91,7 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::CHEST),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tile = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||||
$chest->pairWith($tile);
|
$chest->pairWith($tile);
|
||||||
@ -124,16 +101,6 @@ class Chest extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
|
||||||
$t = $this->getLevel()->getTile($this);
|
|
||||||
if($t instanceof TileChest){
|
|
||||||
$t->unpair();
|
|
||||||
}
|
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, 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){
|
||||||
|
|
||||||
@ -142,21 +109,13 @@ class Chest extends Transparent{
|
|||||||
if($t instanceof TileChest){
|
if($t instanceof TileChest){
|
||||||
$chest = $t;
|
$chest = $t;
|
||||||
}else{
|
}else{
|
||||||
$nbt = new CompoundTag("", [
|
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::CHEST),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
$chest = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
($chest->isPaired() and !$chest->getPair()->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
|
||||||
(isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag and $chest->namedtag->Lock->getValue() !== $item->getCustomName())
|
($chest->namedtag->hasTag("Lock", StringTag::class) and $chest->namedtag->getString("Lock") !== $item->getCustomName())
|
||||||
){
|
){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -174,4 +133,4 @@ class Chest extends Transparent{
|
|||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Clay extends Solid{
|
class Clay extends Solid{
|
||||||
|
|
||||||
@ -40,16 +39,16 @@ class Clay extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Clay Block";
|
return "Clay Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::CLAY_BALL, 0, 4)
|
ItemFactory::get(Item::CLAY_BALL, 0, 4)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Coal extends Solid{
|
class Coal extends Solid{
|
||||||
|
|
||||||
@ -39,22 +38,18 @@ class Coal extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Coal Block";
|
return "Coal Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
return 16000;
|
return 16000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class CoalOre extends Solid{
|
class CoalOre extends Solid{
|
||||||
|
|
||||||
@ -40,21 +40,21 @@ class CoalOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Coal Ore";
|
return "Coal Ore";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
return [
|
||||||
return [
|
ItemFactory::get(Item::COAL)
|
||||||
ItemFactory::get(Item::COAL, 0, 1)
|
];
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Cobblestone extends Solid{
|
class Cobblestone extends Solid{
|
||||||
|
|
||||||
@ -35,7 +34,11 @@ class Cobblestone extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
@ -45,12 +48,4 @@ class Cobblestone extends Solid{
|
|||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class CobblestoneStairs extends Stair{
|
class CobblestoneStairs extends Stair{
|
||||||
|
|
||||||
@ -38,11 +38,15 @@ class CobblestoneStairs extends Stair{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Cobblestone Stairs";
|
return "Cobblestone Stairs";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class CobblestoneWall extends Transparent{
|
class CobblestoneWall extends Transparent{
|
||||||
const NONE_MOSSY_WALL = 0;
|
public const NONE_MOSSY_WALL = 0;
|
||||||
const MOSSY_WALL = 1;
|
public const MOSSY_WALL = 1;
|
||||||
|
|
||||||
protected $id = self::COBBLESTONE_WALL;
|
protected $id = self::COBBLESTONE_WALL;
|
||||||
|
|
||||||
@ -37,12 +37,12 @@ class CobblestoneWall extends Transparent{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSolid() : bool{
|
public function getToolType() : int{
|
||||||
return false;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolHarvestLevel() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -57,38 +57,38 @@ class CobblestoneWall extends Transparent{
|
|||||||
return "Cobblestone Wall";
|
return "Cobblestone Wall";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
//walls don't have any special collision boxes like fences do
|
||||||
|
|
||||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||||
|
|
||||||
$n = $north ? 0 : 0.25;
|
$inset = 0.25;
|
||||||
$s = $south ? 1 : 0.75;
|
if(
|
||||||
$w = $west ? 0 : 0.25;
|
$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
|
||||||
$e = $east ? 1 : 0.75;
|
(
|
||||||
|
($north and $south and !$west and !$east) or
|
||||||
if($north and $south and !$west and !$east){
|
(!$north and !$south and $west and $east)
|
||||||
$w = 0.3125;
|
)
|
||||||
$e = 0.6875;
|
){
|
||||||
}elseif(!$north and !$south and $west and $east){
|
//If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner
|
||||||
$n = 0.3125;
|
$inset = 0.3125;
|
||||||
$s = 0.6875;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $w,
|
$this->x + ($west ? 0 : $inset),
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $n,
|
$this->z + ($north ? 0 : $inset),
|
||||||
$this->x + $e,
|
$this->x + 1 - ($east ? 0 : $inset),
|
||||||
$this->y + 1.5,
|
$this->y + 1.5,
|
||||||
$this->z + $s
|
$this->z + 1 - ($south ? 0 : $inset)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canConnect(Block $block){
|
public function canConnect(Block $block){
|
||||||
return ($block->getId() !== self::COBBLESTONE_WALL and $block->getId() !== self::FENCE_GATE) ? $block->isSolid() and !$block->isTransparent() : true;
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\ItemFactory;
|
||||||
|
|
||||||
class Cobweb extends Flowable{
|
class Cobweb extends Flowable{
|
||||||
|
|
||||||
@ -48,19 +48,24 @@ class Cobweb extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SWORD;
|
return BlockToolType::TYPE_SWORD | BlockToolType::TYPE_SHEARS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function getToolHarvestLevel() : int{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->resetFallDistance();
|
$entity->resetFallDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
//TODO: correct drops
|
return [
|
||||||
return [];
|
ItemFactory::get(Item::STRING)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function diffusesSkyLight() : bool{
|
public function diffusesSkyLight() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
class CocoaBlock extends Solid{
|
class CocoaBlock extends Transparent{
|
||||||
|
|
||||||
protected $id = self::COCOA_BLOCK;
|
protected $id = self::COCOA_BLOCK;
|
||||||
|
|
||||||
@ -35,5 +35,17 @@ class CocoaBlock extends Solid{
|
|||||||
return "Cocoa Block";
|
return "Cocoa Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_AXE;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\utils\ColorBlockMetaHelper;
|
use pocketmine\block\utils\ColorBlockMetaHelper;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Concrete extends Solid{
|
class Concrete extends Solid{
|
||||||
|
|
||||||
@ -44,15 +43,10 @@ class Concrete extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getToolHarvestLevel() : int{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
return TieredTool::TIER_WOODEN;
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
77
src/pocketmine/block/ConcretePowder.php
Normal file
77
src/pocketmine/block/ConcretePowder.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\block\utils\ColorBlockMetaHelper;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
|
||||||
|
class ConcretePowder extends Fallable{
|
||||||
|
|
||||||
|
protected $id = self::CONCRETE_POWDER;
|
||||||
|
|
||||||
|
public function __construct(int $meta = 0){
|
||||||
|
$this->meta = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Concrete Powder";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate(int $type){
|
||||||
|
if($type === Level::BLOCK_UPDATE_NORMAL and ($block = $this->checkAdjacentWater()) !== null){
|
||||||
|
$this->level->setBlock($this, $block);
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::onUpdate($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null|Block
|
||||||
|
*/
|
||||||
|
public function tickFalling() : ?Block{
|
||||||
|
return $this->checkAdjacentWater();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null|Block
|
||||||
|
*/
|
||||||
|
private function checkAdjacentWater() : ?Block{
|
||||||
|
for($i = 1; $i < 6; ++$i){ //Do not check underneath
|
||||||
|
if($this->getSide($i) instanceof Water){
|
||||||
|
return Block::get(Block::CONCRETE, $this->meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\inventory\BigCraftingGrid;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class CraftingTable extends Solid{
|
class CraftingTable extends Solid{
|
||||||
@ -44,12 +44,12 @@ class CraftingTable extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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->craftingType = 1;
|
$player->setCraftingGrid(new BigCraftingGrid($player));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -58,4 +58,4 @@ class CraftingTable extends Solid{
|
|||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ use pocketmine\Server;
|
|||||||
|
|
||||||
abstract class Crops extends Flowable{
|
abstract class Crops extends Flowable{
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
@ -95,4 +95,8 @@ abstract class Crops extends Flowable{
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ class Dandelion extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
@ -63,4 +63,4 @@ class Dandelion extends Flowable{
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,5 +43,9 @@ class DaylightSensor extends Transparent{
|
|||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_AXE;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
@ -38,7 +40,6 @@ class DeadBush extends Flowable{
|
|||||||
return "Dead Bush";
|
return "Dead Bush";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
||||||
@ -51,4 +52,21 @@ class DeadBush extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_SHEARS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDrops(Item $item) : array{
|
||||||
|
if(!$this->isCompatibleWithTool($item)){
|
||||||
|
return [
|
||||||
|
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getDrops($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Diamond extends Solid{
|
class Diamond extends Solid{
|
||||||
|
|
||||||
@ -43,14 +42,10 @@ class Diamond extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getToolHarvestLevel() : int{
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
return TieredTool::TIER_IRON;
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class DiamondOre extends Solid{
|
class DiamondOre extends Solid{
|
||||||
|
|
||||||
@ -44,16 +44,16 @@ class DiamondOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getToolHarvestLevel() : int{
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
return TieredTool::TIER_IRON;
|
||||||
return [
|
|
||||||
ItemFactory::get(Item::DIAMOND, 0, 1)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [
|
||||||
|
ItemFactory::get(Item::DIAMOND)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Dirt extends Solid{
|
class Dirt extends Solid{
|
||||||
@ -40,21 +39,28 @@ class Dirt extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
|
if($this->meta === 1){
|
||||||
|
return "Coarse Dirt";
|
||||||
|
}
|
||||||
return "Dirt";
|
return "Dirt";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($item->isHoe()){
|
if($item->isHoe()){
|
||||||
$item->useOn($this);
|
$item->useOn($this);
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND, 0), true);
|
if($this->meta === 1){
|
||||||
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
|
}else{
|
||||||
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ abstract class Door extends Transparent{
|
|||||||
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f = 0.1875;
|
$f = 0.1875;
|
||||||
$damage = $this->getFullDamage();
|
$damage = $this->getFullDamage();
|
||||||
@ -216,7 +216,7 @@ abstract class Door extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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_UP){
|
if($face === Vector3::SIDE_UP){
|
||||||
$blockUp = $this->getSide(Vector3::SIDE_UP);
|
$blockUp = $this->getSide(Vector3::SIDE_UP);
|
||||||
$blockDown = $this->getSide(Vector3::SIDE_DOWN);
|
$blockDown = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
@ -246,23 +246,6 @@ abstract class Door extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
|
||||||
if(($this->getDamage() & 0x08) === 0x08){
|
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
|
||||||
if($down->getId() === $this->getId()){
|
|
||||||
$this->getLevel()->setBlock($down, BlockFactory::get(Block::AIR), true);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$up = $this->getSide(Vector3::SIDE_UP);
|
|
||||||
if($up->getId() === $this->getId()){
|
|
||||||
$this->getLevel()->setBlock($up, BlockFactory::get(Block::AIR), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if(($this->getDamage() & 0x08) === 0x08){ //Top
|
if(($this->getDamage() & 0x08) === 0x08){ //Top
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
@ -286,4 +269,32 @@ abstract class Door extends Transparent{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
if(($this->meta & 0x08) === 0){ //bottom half only
|
||||||
|
return parent::getDropsForCompatibleTool($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAffectedBlocks() : array{
|
||||||
|
if(($this->getDamage() & 0x08) === 0x08){
|
||||||
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
|
if($down->getId() === $this->getId()){
|
||||||
|
return [$this, $down];
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$up = $this->getSide(Vector3::SIDE_UP);
|
||||||
|
if($up->getId() === $this->getId()){
|
||||||
|
return [$this, $up];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getAffectedBlocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,7 +30,7 @@ use pocketmine\math\Vector3;
|
|||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class DoublePlant extends Flowable{
|
class DoublePlant extends Flowable{
|
||||||
const BITFLAG_TOP = 0x08;
|
public const BITFLAG_TOP = 0x08;
|
||||||
|
|
||||||
protected $id = self::DOUBLE_PLANT;
|
protected $id = self::DOUBLE_PLANT;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ class DoublePlant extends Flowable{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return $this->meta === 2 or $this->meta === 3; //grass or fern
|
return $this->meta === 2 or $this->meta === 3; //grass or fern
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ class DoublePlant extends Flowable{
|
|||||||
4 => "Rose Bush",
|
4 => "Rose Bush",
|
||||||
5 => "Peony"
|
5 => "Peony"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x07] ?? "";
|
return $names[$this->getVariant()] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, false, false);
|
||||||
@ -79,7 +79,7 @@ class DoublePlant extends Flowable{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
$other->getId() === $this->getId() and
|
$other->getId() === $this->getId() and
|
||||||
($other->getDamage() & 0x07) === ($this->getDamage() & 0x07) and
|
$other->getVariant() === $this->getVariant() and
|
||||||
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
|
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -97,33 +97,39 @@ class DoublePlant extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
|
||||||
if(parent::onBreak($item, $player) and $this->isValidHalfPlant()){
|
|
||||||
$this->getLevel()->useBreakOn($this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Vector3::SIDE_DOWN : Vector3::SIDE_UP), $item, $player, $player !== null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0x07;
|
return 0x07;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return ($this->meta === 2 or $this->meta === 3) ? BlockToolType::TYPE_SHEARS : BlockToolType::TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return ($this->meta === 2 or $this->meta === 3) ? 1 : 0; //only grass or fern require shears
|
||||||
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
if($this->meta & self::BITFLAG_TOP){
|
if($this->meta & self::BITFLAG_TOP){
|
||||||
if(!$item->isShears() and ($this->meta === 2 or $this->meta === 3)){ //grass or fern
|
if($this->isCompatibleWithTool($item)){
|
||||||
if(mt_rand(0, 24) === 0){
|
return parent::getDrops($item);
|
||||||
return [
|
|
||||||
ItemFactory::get(Item::SEEDS, 0, 1)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getDrops($item);
|
if(mt_rand(0, 24) === 0){
|
||||||
|
return [
|
||||||
|
ItemFactory::get(Item::SEEDS)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getAffectedBlocks() : array{
|
||||||
|
if($this->isValidHalfPlant()){
|
||||||
|
return [$this, $this->getSide(($this->meta & self::BITFLAG_TOP) !== 0 ? Vector3::SIDE_DOWN : Vector3::SIDE_UP)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getAffectedBlocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
50
src/pocketmine/block/DoubleSlab.php
Normal file
50
src/pocketmine/block/DoubleSlab.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemFactory;
|
||||||
|
|
||||||
|
abstract class DoubleSlab extends Solid{
|
||||||
|
|
||||||
|
public function __construct(int $meta = 0){
|
||||||
|
$this->meta = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function getSlabId() : int;
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName() . " Slab";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [
|
||||||
|
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -23,16 +23,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class DoubleStoneSlab extends Solid{
|
class DoubleStoneSlab extends DoubleSlab{
|
||||||
|
|
||||||
protected $id = self::DOUBLE_STONE_SLAB;
|
protected $id = self::DOUBLE_STONE_SLAB;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function getSlabId() : int{
|
||||||
$this->meta = $meta;
|
return self::STONE_SLAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -40,31 +38,10 @@ class DoubleStoneSlab extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getToolHarvestLevel() : int{
|
||||||
static $names = [
|
return TieredTool::TIER_WOODEN;
|
||||||
0 => "Stone",
|
|
||||||
1 => "Sandstone",
|
|
||||||
2 => "Wooden",
|
|
||||||
3 => "Cobblestone",
|
|
||||||
4 => "Brick",
|
|
||||||
5 => "Stone Brick",
|
|
||||||
6 => "Quartz",
|
|
||||||
7 => "Nether Brick"
|
|
||||||
];
|
|
||||||
return "Double " . $names[$this->meta & 0x07] . " Slab";
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return [
|
|
||||||
ItemFactory::get(Item::STONE_SLAB, $this->getDamage() & 0x07, 2)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
34
src/pocketmine/block/DoubleStoneSlab2.php
Normal file
34
src/pocketmine/block/DoubleStoneSlab2.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
class DoubleStoneSlab2 extends DoubleStoneSlab{
|
||||||
|
|
||||||
|
protected $id = self::DOUBLE_STONE_SLAB2;
|
||||||
|
|
||||||
|
public function getSlabId() : int{
|
||||||
|
return self::STONE_SLAB2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,16 +23,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
class DoubleWoodenSlab extends DoubleSlab{
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class DoubleWoodenSlab extends Solid{
|
|
||||||
|
|
||||||
protected $id = self::DOUBLE_WOODEN_SLAB;
|
protected $id = self::DOUBLE_WOODEN_SLAB;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function getSlabId() : int{
|
||||||
$this->meta = $meta;
|
return self::WOODEN_SLAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -40,25 +36,6 @@ class DoubleWoodenSlab extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getName() : string{
|
|
||||||
static $names = [
|
|
||||||
0 => "Oak",
|
|
||||||
1 => "Spruce",
|
|
||||||
2 => "Birch",
|
|
||||||
3 => "Jungle",
|
|
||||||
4 => "Acacia",
|
|
||||||
5 => "Dark Oak"
|
|
||||||
];
|
|
||||||
return "Double " . ($names[$this->meta & 0x07] ?? "") . " Wooden Slab";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
return [
|
|
||||||
ItemFactory::get(Item::WOODEN_SLAB, $this->getDamage() & 0x07, 2)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Emerald extends Solid{
|
class Emerald extends Solid{
|
||||||
|
|
||||||
@ -39,18 +38,14 @@ class Emerald extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_IRON;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Emerald Block";
|
return "Emerald Block";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class EmeraldOre extends Solid{
|
class EmeraldOre extends Solid{
|
||||||
|
|
||||||
@ -40,20 +40,20 @@ class EmeraldOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_IRON;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
return [
|
||||||
return [
|
ItemFactory::get(Item::EMERALD)
|
||||||
ItemFactory::get(Item::EMERALD, 0, 1)
|
];
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,10 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\inventory\EnchantInventory;
|
use pocketmine\inventory\EnchantInventory;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\tile\EnchantTable as TileEnchantTable;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
class EnchantingTable extends Transparent{
|
class EnchantingTable extends Transparent{
|
||||||
@ -41,26 +39,10 @@ class EnchantingTable extends Transparent{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new StringTag("id", Tile::ENCHANT_TABLE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -78,7 +60,11 @@ class EnchantingTable extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
@ -90,12 +76,4 @@ class EnchantingTable extends Transparent{
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -54,7 +54,7 @@ class EndPortalFrame extends Solid{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
@ -65,4 +65,4 @@ class EndPortalFrame extends Solid{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class EndRod extends Flowable{
|
|||||||
return "End Rod";
|
return "End Rod";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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_UP or $face === Vector3::SIDE_DOWN){
|
if($face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
|
||||||
$this->meta = $face;
|
$this->meta = $face;
|
||||||
}else{
|
}else{
|
||||||
@ -61,7 +61,7 @@ class EndRod extends Flowable{
|
|||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
$m = $this->meta & ~0x01;
|
$m = $this->meta & ~0x01;
|
||||||
$width = 0.375;
|
$width = 0.375;
|
||||||
|
|
||||||
@ -101,4 +101,4 @@ class EndRod extends Flowable{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class EndStone extends Solid{
|
class EndStone extends Solid{
|
||||||
|
|
||||||
@ -38,10 +38,14 @@ class EndStone extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/pocketmine/block/EndStoneBricks.php
Normal file
51
src/pocketmine/block/EndStoneBricks.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
|
class EndStoneBricks extends Solid{
|
||||||
|
|
||||||
|
protected $id = self::END_BRICKS;
|
||||||
|
|
||||||
|
public function __construct(int $meta = 0){
|
||||||
|
$this->meta = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "End Stone Bricks";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
|
}
|
||||||
|
}
|
110
src/pocketmine/block/EnderChest.php
Normal file
110
src/pocketmine/block/EnderChest.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemFactory;
|
||||||
|
use pocketmine\item\TieredTool;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\Player;
|
||||||
|
use pocketmine\tile\EnderChest as TileEnderChest;
|
||||||
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
|
class EnderChest extends Chest{
|
||||||
|
|
||||||
|
protected $id = self::ENDER_CHEST;
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 22.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlastResistance() : float{
|
||||||
|
return 3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLightLevel() : int{
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Ender Chest";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
|
$faces = [
|
||||||
|
0 => 4,
|
||||||
|
1 => 2,
|
||||||
|
2 => 5,
|
||||||
|
3 => 3
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||||
|
|
||||||
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this, $face, $item, $player));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
|
if($player instanceof Player){
|
||||||
|
|
||||||
|
$t = $this->getLevel()->getTile($this);
|
||||||
|
$enderChest = null;
|
||||||
|
if($t instanceof TileEnderChest){
|
||||||
|
$enderChest = $t;
|
||||||
|
}else{
|
||||||
|
$enderChest = Tile::createTile(Tile::ENDER_CHEST, $this->getLevel(), TileEnderChest::createNBT($this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$this->getSide(Vector3::SIDE_UP)->isTransparent()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$player->getEnderChestInventory()->setHolderPosition($enderChest);
|
||||||
|
$player->addWindow($player->getEnderChestInventory());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [
|
||||||
|
ItemFactory::get(Item::OBSIDIAN, 0, 8)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFuelTime() : int{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,41 +26,32 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\DoubleTag;
|
|
||||||
use pocketmine\nbt\tag\FloatTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
|
|
||||||
abstract class Fallable extends Solid{
|
abstract class Fallable extends Solid{
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === self::AIR or ($down instanceof Liquid)){
|
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
|
||||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), new CompoundTag("", [
|
|
||||||
new ListTag("Pos", [
|
|
||||||
new DoubleTag("", $this->x + 0.5),
|
|
||||||
new DoubleTag("", $this->y),
|
|
||||||
new DoubleTag("", $this->z + 0.5)
|
|
||||||
]),
|
|
||||||
new ListTag("Motion", [
|
|
||||||
new DoubleTag("", 0),
|
|
||||||
new DoubleTag("", 0),
|
|
||||||
new DoubleTag("", 0)
|
|
||||||
]),
|
|
||||||
new ListTag("Rotation", [
|
|
||||||
new FloatTag("", 0),
|
|
||||||
new FloatTag("", 0)
|
|
||||||
]),
|
|
||||||
new IntTag("TileID", $this->getId()),
|
|
||||||
new ByteTag("Data", $this->getDamage())
|
|
||||||
]));
|
|
||||||
|
|
||||||
$fall->spawnToAll();
|
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
|
||||||
|
$nbt->setInt("TileID", $this->getId());
|
||||||
|
$nbt->setByte("Data", $this->getDamage());
|
||||||
|
|
||||||
|
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
|
||||||
|
|
||||||
|
if($fall !== null){
|
||||||
|
$fall->spawnToAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* @return null|Block
|
||||||
|
*/
|
||||||
|
public function tickFalling() : ?Block{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,9 +25,9 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class Farmland extends Transparent{
|
class Farmland extends Transparent{
|
||||||
|
|
||||||
@ -46,14 +46,14 @@ class Farmland extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ticksRandomly() : bool{
|
public function ticksRandomly() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -65,16 +65,55 @@ class Farmland extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_RANDOM){
|
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||||
//TODO: hydration
|
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
|
return $type;
|
||||||
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||||
|
if(!$this->canHydrate()){
|
||||||
|
if($this->meta > 0){
|
||||||
|
$this->meta--;
|
||||||
|
$this->level->setBlock($this, $this, false, false);
|
||||||
|
}else{
|
||||||
|
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}elseif($this->meta < 7){
|
||||||
|
$this->meta = 7;
|
||||||
|
$this->level->setBlock($this, $this, false, false);
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
protected function canHydrate() : bool{
|
||||||
|
//TODO: check rain
|
||||||
|
$start = $this->add(-4, 0, -4);
|
||||||
|
$end = $this->add(4, 1, 4);
|
||||||
|
for($y = $start->y; $y <= $end->y; ++$y){
|
||||||
|
for($z = $start->z; $z <= $end->z; ++$z){
|
||||||
|
for($x = $start->x; $x <= $end->x; ++$x){
|
||||||
|
$id = $this->level->getBlockIdAt($x, $y, $z);
|
||||||
|
if($id === Block::STILL_WATER or $id === Block::FLOWING_WATER){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::DIRT, 0, 1)
|
ItemFactory::get(Item::DIRT)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,73 +23,87 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class Fence extends Transparent{
|
abstract class Fence extends Transparent{
|
||||||
const FENCE_OAK = 0;
|
|
||||||
const FENCE_SPRUCE = 1;
|
|
||||||
const FENCE_BIRCH = 2;
|
|
||||||
const FENCE_JUNGLE = 3;
|
|
||||||
const FENCE_ACACIA = 4;
|
|
||||||
const FENCE_DARKOAK = 5;
|
|
||||||
|
|
||||||
protected $id = self::FENCE;
|
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getThickness() : float{
|
||||||
return 2;
|
return 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return Tool::TYPE_AXE;
|
$width = 0.5 - $this->getThickness() / 2;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function getName() : string{
|
|
||||||
static $names = [
|
|
||||||
self::FENCE_OAK => "Oak Fence",
|
|
||||||
self::FENCE_SPRUCE => "Spruce Fence",
|
|
||||||
self::FENCE_BIRCH => "Birch Fence",
|
|
||||||
self::FENCE_JUNGLE => "Jungle Fence",
|
|
||||||
self::FENCE_ACACIA => "Acacia Fence",
|
|
||||||
self::FENCE_DARKOAK => "Dark Oak Fence"
|
|
||||||
];
|
|
||||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
|
||||||
|
|
||||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
|
||||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
|
||||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
|
||||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
|
||||||
|
|
||||||
$n = $north ? 0 : 0.375;
|
|
||||||
$s = $south ? 1 : 0.625;
|
|
||||||
$w = $west ? 0 : 0.375;
|
|
||||||
$e = $east ? 1 : 0.625;
|
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $w,
|
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $n,
|
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||||
$this->x + $e,
|
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||||
$this->y + 1.5,
|
$this->y + 1.5,
|
||||||
$this->z + $s
|
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canConnect(Block $block){
|
protected function recalculateCollisionBoxes() : array{
|
||||||
return ($block instanceof Fence or $block instanceof FenceGate) ? true : $block->isSolid() and !$block->isTransparent();
|
$inset = 0.5 - $this->getThickness() / 2;
|
||||||
|
|
||||||
|
/** @var AxisAlignedBB[] $bbs */
|
||||||
|
$bbs = [];
|
||||||
|
|
||||||
|
$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||||
|
$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||||
|
|
||||||
|
if($connectWest or $connectEast){
|
||||||
|
//X axis (west/east)
|
||||||
|
$bbs[] = new AxisAlignedBB(
|
||||||
|
$this->x + ($connectWest ? 0 : $inset),
|
||||||
|
$this->y,
|
||||||
|
$this->z + $inset,
|
||||||
|
$this->x + 1 - ($connectEast ? 0 : $inset),
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||||
|
$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||||
|
|
||||||
|
if($connectNorth or $connectSouth){
|
||||||
|
//Z axis (north/south)
|
||||||
|
$bbs[] = new AxisAlignedBB(
|
||||||
|
$this->x + $inset,
|
||||||
|
$this->y,
|
||||||
|
$this->z + ($connectNorth ? 0 : $inset),
|
||||||
|
$this->x + 1 - $inset,
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - ($connectSouth ? 0 : $inset)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($bbs)){
|
||||||
|
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||||
|
return [
|
||||||
|
new AxisAlignedBB(
|
||||||
|
$this->x + $inset,
|
||||||
|
$this->y,
|
||||||
|
$this->z + $inset,
|
||||||
|
$this->x + 1 - $inset,
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
public function canConnect(Block $block){
|
||||||
return 300;
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\level\sound\DoorSound;
|
use pocketmine\level\sound\DoorSound;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
@ -37,11 +36,11 @@ class FenceGate extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
return BlockToolType::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
if(($this->getDamage() & 0x04) > 0){
|
if(($this->getDamage() & 0x04) > 0){
|
||||||
return null;
|
return null;
|
||||||
@ -69,7 +68,7 @@ class FenceGate extends Transparent{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\entity\Arrow;
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\projectile\Arrow;
|
||||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
@ -57,7 +57,7 @@ class Fire extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class Fire extends Flowable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ class Fire extends Flowable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,4 +114,4 @@ class Fire extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
abstract class Flowable extends Transparent{
|
abstract class Flowable extends Transparent{
|
||||||
|
|
||||||
public function canBeFlowedInto() : bool{
|
public function canBeFlowedInto() : bool{
|
||||||
@ -33,15 +35,11 @@ abstract class Flowable extends Transparent{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBlastResistance() : float{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isSolid() : bool{
|
public function isSolid() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,15 @@ use pocketmine\math\Vector3;
|
|||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Flower extends Flowable{
|
class Flower extends Flowable{
|
||||||
const TYPE_POPPY = 0;
|
public const TYPE_POPPY = 0;
|
||||||
const TYPE_BLUE_ORCHID = 1;
|
public const TYPE_BLUE_ORCHID = 1;
|
||||||
const TYPE_ALLIUM = 2;
|
public const TYPE_ALLIUM = 2;
|
||||||
const TYPE_AZURE_BLUET = 3;
|
public const TYPE_AZURE_BLUET = 3;
|
||||||
const TYPE_RED_TULIP = 4;
|
public const TYPE_RED_TULIP = 4;
|
||||||
const TYPE_ORANGE_TULIP = 5;
|
public const TYPE_ORANGE_TULIP = 5;
|
||||||
const TYPE_WHITE_TULIP = 6;
|
public const TYPE_WHITE_TULIP = 6;
|
||||||
const TYPE_PINK_TULIP = 7;
|
public const TYPE_PINK_TULIP = 7;
|
||||||
const TYPE_OXEYE_DAISY = 8;
|
public const TYPE_OXEYE_DAISY = 8;
|
||||||
|
|
||||||
protected $id = self::RED_FLOWER;
|
protected $id = self::RED_FLOWER;
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class Flower extends Flowable{
|
|||||||
return $names[$this->meta] ?? "Unknown";
|
return $names[$this->meta] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, 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->getLevel()->setBlock($blockReplace, $this, true);
|
||||||
@ -82,4 +82,4 @@ class Flower extends Flowable{
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,17 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ShortTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\FlowerPot as TileFlowerPot;
|
use pocketmine\tile\FlowerPot as TileFlowerPot;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
class FlowerPot extends Flowable{
|
class FlowerPot extends Flowable{
|
||||||
|
|
||||||
const STATE_EMPTY = 0;
|
public const STATE_EMPTY = 0;
|
||||||
const STATE_FULL = 1;
|
public const STATE_FULL = 1;
|
||||||
|
|
||||||
protected $id = self::FLOWER_POT_BLOCK;
|
protected $id = self::FLOWER_POT_BLOCK;
|
||||||
protected $itemId = Item::FLOWER_POT;
|
protected $itemId = Item::FLOWER_POT;
|
||||||
@ -49,10 +44,10 @@ class FlowerPot extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Flower Pot Block";
|
return "Flower Pot";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.3125,
|
$this->x + 0.3125,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -63,29 +58,13 @@ class FlowerPot extends Flowable{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new StringTag("id", Tile::FLOWER_POT),
|
|
||||||
new IntTag("x", $blockReplace->x),
|
|
||||||
new IntTag("y", $blockReplace->y),
|
|
||||||
new IntTag("z", $blockReplace->z),
|
|
||||||
new ShortTag("item", 0),
|
|
||||||
new IntTag("mData", 0)
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), $nbt);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,19 +91,17 @@ 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->getLevel()->setBlock($this, $this, true, false);
|
||||||
$pot->setItem($item);
|
$pot->setItem($item->pop());
|
||||||
|
|
||||||
if($player instanceof Player){
|
|
||||||
if($player->isSurvival()){
|
|
||||||
$item->setCount($item->getCount() - 1);
|
|
||||||
$player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : ItemFactory::get(Item::AIR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getVariantBitmask() : int{
|
||||||
$items = parent::getDrops($item);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
$items = parent::getDropsForCompatibleTool($item);
|
||||||
|
|
||||||
$tile = $this->getLevel()->getTile($this);
|
$tile = $this->getLevel()->getTile($this);
|
||||||
if($tile instanceof TileFlowerPot){
|
if($tile instanceof TileFlowerPot){
|
||||||
@ -137,4 +114,7 @@ class FlowerPot extends Flowable{
|
|||||||
return $items;
|
return $items;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public function isAffectedBySilkTouch() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,4 +35,4 @@ class Furnace extends BurningFurnace{
|
|||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class Glass extends Transparent{
|
|||||||
return 0.3;
|
return 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class GlassPane extends Thin{
|
|||||||
return 0.3;
|
return 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
@ -36,10 +36,14 @@ class GlazedTerracotta extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
if($player !== null){
|
if($player !== null){
|
||||||
$faces = [
|
$faces = [
|
||||||
0 => 4,
|
0 => 4,
|
||||||
@ -56,12 +60,4 @@ class GlazedTerracotta extends Solid{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,6 +24,8 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class GlowingObsidian extends Solid{
|
class GlowingObsidian extends Solid{
|
||||||
|
|
||||||
protected $id = self::GLOWING_OBSIDIAN;
|
protected $id = self::GLOWING_OBSIDIAN;
|
||||||
@ -47,4 +49,12 @@ class GlowingObsidian extends Solid{
|
|||||||
public function getBlastResistance() : float{
|
public function getBlastResistance() : float{
|
||||||
return 50;
|
return 50;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_DIAMOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,8 @@ class GlowingRedstoneOre extends RedstoneOre{
|
|||||||
|
|
||||||
protected $id = self::GLOWING_REDSTONE_ORE;
|
protected $id = self::GLOWING_REDSTONE_ORE;
|
||||||
|
|
||||||
|
protected $itemId = self::REDSTONE_ORE;
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Glowing Redstone Ore";
|
return "Glowing Redstone Ore";
|
||||||
}
|
}
|
||||||
@ -46,4 +48,4 @@ class GlowingRedstoneOre extends RedstoneOre{
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Glowstone extends Transparent{
|
class Glowstone extends Transparent{
|
||||||
|
|
||||||
@ -44,16 +43,16 @@ class Glowstone extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLightLevel() : int{
|
public function getLightLevel() : int{
|
||||||
return 15;
|
return 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::GLOWSTONE_DUST, 0, mt_rand(2, 4))
|
ItemFactory::get(Item::GLOWSTONE_DUST, 0, mt_rand(2, 4))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Gold extends Solid{
|
class Gold extends Solid{
|
||||||
|
|
||||||
@ -43,14 +42,10 @@ class Gold extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getToolHarvestLevel() : int{
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
return TieredTool::TIER_IRON;
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class GoldOre extends Solid{
|
class GoldOre extends Solid{
|
||||||
|
|
||||||
@ -43,14 +42,10 @@ class GoldOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getToolHarvestLevel() : int{
|
||||||
if($item->isPickaxe() >= Tool::TIER_IRON){
|
return TieredTool::TIER_IRON;
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\event\block\BlockSpreadEvent;
|
use pocketmine\event\block\BlockSpreadEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
@ -50,12 +49,12 @@ class Grass extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::DIRT, 0, 1)
|
ItemFactory::get(Item::DIRT)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,22 +75,22 @@ class Grass extends Solid{
|
|||||||
return Level::BLOCK_UPDATE_RANDOM;
|
return Level::BLOCK_UPDATE_RANDOM;
|
||||||
}elseif($lightAbove >= 9){
|
}elseif($lightAbove >= 9){
|
||||||
//try grass spread
|
//try grass spread
|
||||||
$vector = $this->asVector3();
|
|
||||||
for($i = 0; $i < 4; ++$i){
|
for($i = 0; $i < 4; ++$i){
|
||||||
$vector->x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$vector->y = mt_rand($this->y - 3, $this->y + 1);
|
$y = mt_rand($this->y - 3, $this->y + 1);
|
||||||
$vector->z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
if(
|
if(
|
||||||
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or
|
$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
|
||||||
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or
|
$this->level->getBlockDataAt($x, $y, $z) === 1 or
|
||||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3
|
$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
|
||||||
|
BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
|
||||||
){
|
){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this->level->getBlock($vector), $this, BlockFactory::get(Block::GRASS)));
|
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->level->setBlock($vector, $ev->getNewState(), false, false);
|
$this->level->setBlock($b, $ev->getNewState(), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,9 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class GrassPath extends Transparent{
|
class GrassPath extends Transparent{
|
||||||
|
|
||||||
@ -41,10 +42,10 @@ class GrassPath extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -59,9 +60,18 @@ class GrassPath extends Transparent{
|
|||||||
return 0.6;
|
return 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function onUpdate(int $type){
|
||||||
|
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||||
|
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::DIRT, 0, 1)
|
ItemFactory::get(Item::DIRT)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Gravel extends Fallable{
|
class Gravel extends Fallable{
|
||||||
|
|
||||||
@ -44,17 +43,17 @@ class Gravel extends Fallable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_SHOVEL;
|
return BlockToolType::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if(mt_rand(1, 10) === 1){
|
if(mt_rand(1, 10) === 1){
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::FLINT, 0, 1)
|
ItemFactory::get(Item::FLINT)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getDrops($item);
|
return parent::getDropsForCompatibleTool($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class HardenedClay extends Solid{
|
class HardenedClay extends Solid{
|
||||||
|
|
||||||
@ -38,10 +38,14 @@ class HardenedClay extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 1.25;
|
return 1.25;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\block\utils\PillarRotationHelper;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -43,17 +44,8 @@ class HayBale extends Solid{
|
|||||||
return 0.5;
|
return 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||||
$faces = [
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
0 => 0,
|
|
||||||
1 => 0,
|
|
||||||
2 => 0b1000,
|
|
||||||
3 => 0b1000,
|
|
||||||
4 => 0b0100,
|
|
||||||
5 => 0b0100
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->meta = ($this->meta & 0x03) | $faces[$face];
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -62,4 +54,4 @@ class HayBale extends Solid{
|
|||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0x03;
|
return 0x03;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\enchantment\Enchantment;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
@ -53,11 +53,14 @@ class Ice extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::WATER), true);
|
if(!$item->hasEnchantment(Enchantment::SILK_TOUCH)){
|
||||||
|
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::WATER), true);
|
||||||
|
}
|
||||||
|
return parent::onBreak($item, $player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ticksRandomly() : bool{
|
public function ticksRandomly() : bool{
|
||||||
@ -75,7 +78,7 @@ class Ice extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class Iron extends Solid{
|
class Iron extends Solid{
|
||||||
|
|
||||||
@ -39,18 +38,14 @@ class Iron extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_STONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_STONE){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,8 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\TieredTool;
|
||||||
use pocketmine\item\Tool;
|
|
||||||
|
|
||||||
class IronBars extends Thin{
|
class IronBars extends Thin{
|
||||||
|
|
||||||
@ -43,20 +42,15 @@ class IronBars extends Thin{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return BlockToolType::TYPE_PICKAXE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolHarvestLevel() : int{
|
||||||
|
return TieredTool::TIER_WOODEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getVariantBitmask() : int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
|
||||||
return parent::getDrops($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user