mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-12 12:25:09 +00:00
Compare commits
706 Commits
api/3.0.0-
...
1.7dev-516
Author | SHA1 | Date | |
---|---|---|---|
fbd04b0fe7 | |||
66562f24fb | |||
dc064dfa2e | |||
131a6a4d19 | |||
67a576722c | |||
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.
|
||||
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
||||
- 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:
|
||||
Expected result: What were you expecting to happen?
|
||||
Actual result: What actually happened?
|
||||
Any issues requesting updates to new versions of MCPE will be treated as spam.
|
||||
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
|
||||
-->
|
||||
|
||||
<!--- 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
|
||||
<!--- help us find the problem by adding steps to reproduce the issue -->
|
||||
1. ...
|
||||
@ -21,9 +22,9 @@ Actual result: What actually happened?
|
||||
### OS and versions
|
||||
<!--- 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.
|
||||
-->
|
||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -28,3 +28,12 @@ Desktop.ini
|
||||
# Sphinx-doc
|
||||
/docs/build/
|
||||
!/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"]
|
||||
path = src/pocketmine/lang/locale
|
||||
url = https://github.com/pmmp/PocketMine-Language.git
|
||||
|
17
.travis.yml
17
.travis.yml
@ -1,12 +1,21 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.2
|
||||
|
||||
before_script:
|
||||
- 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.0
|
||||
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
|
||||
- git clone https://github.com/krakjoe/pthreads.git
|
||||
- cd pthreads
|
||||
- git checkout 6c6b15138c923b69cfa46ee05fc2dd45da587287
|
||||
- phpize
|
||||
- ./configure
|
||||
- make
|
||||
- make install
|
||||
- cd ..
|
||||
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- composer install
|
||||
|
||||
script:
|
||||
- ./tests/travis.sh
|
||||
|
42
composer.json
Normal file
42
composer.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "pmmp/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",
|
||||
"pmmp/raklib": "dev-master#29ab14d5d8640a8ee359ce315b083a129e72db4a",
|
||||
"pmmp/pocketmine-spl": "^0.1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"": ["src"]
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/RakLib"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/pmmp/PocketMine-SPL"
|
||||
}
|
||||
]
|
||||
}
|
108
composer.lock
generated
Normal file
108
composer.lock
generated
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"_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": "169d2724a6847e704f3bb76030bebc87",
|
||||
"packages": [
|
||||
{
|
||||
"name": "pmmp/pocketmine-spl",
|
||||
"version": "0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/PocketMine-SPL.git",
|
||||
"reference": "c56936e6aaad925bb60002b29b1c70f497af4679"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/PocketMine-SPL/zipball/c56936e6aaad925bb60002b29b1c70f497af4679",
|
||||
"reference": "c56936e6aaad925bb60002b29b1c70f497af4679",
|
||||
"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": "2017-12-10T12:18:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pmmp/raklib",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "29ab14d5d8640a8ee359ce315b083a129e72db4a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/29ab14d5d8640a8ee359ce315b083a129e72db4a",
|
||||
"reference": "29ab14d5d8640a8ee359ce315b083a129e72db4a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-bcmath": "*",
|
||||
"ext-pthreads": ">=3.1.7dev",
|
||||
"ext-sockets": "*",
|
||||
"php": ">=7.2.0RC3",
|
||||
"pmmp/pocketmine-spl": "^0.1.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": "2017-12-10T12:24:38+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"php": 5,
|
||||
"ext-pthreads": 20,
|
||||
"pmmp/raklib": 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{
|
||||
if(isset(Achievement::$list[$achievementId])){
|
||||
$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);
|
||||
}else{
|
||||
$player->sendMessage($translation);
|
||||
|
@ -25,7 +25,9 @@ namespace pocketmine;
|
||||
|
||||
use pocketmine\event\server\LowMemoryEvent;
|
||||
use pocketmine\event\Timings;
|
||||
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
class MemoryManager{
|
||||
@ -63,16 +65,17 @@ class MemoryManager{
|
||||
private $garbageCollectionAsync;
|
||||
|
||||
/** @var int */
|
||||
private $chunkRadiusOverride;
|
||||
private $lowMemChunkRadiusOverride;
|
||||
/** @var bool */
|
||||
private $chunkCollect;
|
||||
/** @var bool */
|
||||
private $chunkTrigger;
|
||||
private $lowMemChunkGC;
|
||||
|
||||
/** @var bool */
|
||||
private $chunkCache;
|
||||
private $lowMemDisableChunkCache;
|
||||
/** @var bool */
|
||||
private $cacheTrigger;
|
||||
private $lowMemClearWorldCache;
|
||||
|
||||
/** @var bool */
|
||||
private $dumpWorkers = true;
|
||||
|
||||
public function __construct(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->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->chunkCollect = (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->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
||||
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
||||
|
||||
$this->chunkCache = (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->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", 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();
|
||||
}
|
||||
|
||||
@ -145,7 +148,7 @@ class MemoryManager{
|
||||
* @return 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
|
||||
*/
|
||||
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){
|
||||
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||
if($this->cacheTrigger){
|
||||
if($this->lowMemClearWorldCache){
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->clearCache(true);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->chunkTrigger and $this->chunkCollect){
|
||||
if($this->lowMemChunkGC){
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->doChunkGarbageCollection();
|
||||
}
|
||||
@ -261,6 +264,27 @@ class MemoryManager{
|
||||
* @param 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, $this->server->getLoader(), $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 \ClassLoader $loader
|
||||
* @param string $outputFolder
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
*/
|
||||
public static function dumpMemory($startingObject, \ClassLoader $loader, string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||
$hardLimit = ini_get('memory_limit');
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
@ -269,12 +293,8 @@ class MemoryManager{
|
||||
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+");
|
||||
|
||||
$staticProperties = [];
|
||||
|
||||
$data = [];
|
||||
|
||||
$objects = [];
|
||||
@ -283,8 +303,10 @@ class MemoryManager{
|
||||
|
||||
$instanceCounts = [];
|
||||
|
||||
$staticProperties = [];
|
||||
$staticCount = 0;
|
||||
foreach($this->server->getLoader()->getClasses() as $className){
|
||||
|
||||
foreach($loader->getClasses() as $className){
|
||||
$reflection = new \ReflectionClass($className);
|
||||
$staticProperties[$className] = [];
|
||||
foreach($reflection->getProperties() as $property){
|
||||
@ -297,7 +319,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$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){
|
||||
@ -305,9 +327,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($GLOBALS !== null){ //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{
|
||||
$continue = false;
|
||||
@ -349,25 +401,26 @@ class MemoryManager{
|
||||
if(!$property->isPublic()){
|
||||
$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");
|
||||
}
|
||||
|
||||
echo "[Dump] Wrote " . count($objects) . " objects\n";
|
||||
|
||||
}while($continue);
|
||||
|
||||
MainLogger::getLogger()->info("[Dump] Wrote " . count($objects) . " objects");
|
||||
|
||||
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 . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
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);
|
||||
gc_enable();
|
||||
@ -382,7 +435,7 @@ class MemoryManager{
|
||||
* @param int $maxNesting
|
||||
* @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){
|
||||
$data = "(error) NESTING LIMIT REACHED";
|
||||
return;
|
||||
@ -406,7 +459,7 @@ class MemoryManager{
|
||||
}
|
||||
$data = [];
|
||||
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)){
|
||||
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
|
@ -108,11 +108,11 @@ class OfflinePlayer implements IPlayer, Metadatable{
|
||||
}
|
||||
|
||||
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(){
|
||||
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{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@ namespace {
|
||||
}
|
||||
|
||||
namespace pocketmine {
|
||||
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\ServerKiller;
|
||||
@ -78,9 +79,12 @@ namespace pocketmine {
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
use raklib\RakLib;
|
||||
|
||||
const VERSION = "1.6.2dev";
|
||||
const API_VERSION = "3.0.0-ALPHA7";
|
||||
const CODENAME = "Unleashed";
|
||||
const NAME = "PocketMine-MP";
|
||||
const VERSION = "1.7dev";
|
||||
const API_VERSION = "3.0.0-ALPHA10";
|
||||
const CODENAME = "[REDACTED]";
|
||||
|
||||
const MIN_PHP_VERSION = "7.2.0RC3";
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
|
||||
echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
|
||||
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
|
||||
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
||||
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, or update to a newer PHP version." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -103,13 +107,15 @@ namespace pocketmine {
|
||||
|
||||
error_reporting(-1);
|
||||
|
||||
set_error_handler(function($severity, $message, $file, $line){
|
||||
function error_handler($severity, $message, $file, $line){
|
||||
if(error_reporting() & $severity){
|
||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||
}else{ //stfu operator
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set_error_handler('\pocketmine\error_handler');
|
||||
|
||||
if(!extension_loaded("phar")){
|
||||
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
||||
@ -120,42 +126,40 @@ namespace pocketmine {
|
||||
if(\Phar::running(true) !== ""){
|
||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
||||
}else{
|
||||
define('pocketmine\PATH', realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
$requiredSplVer = "0.0.1";
|
||||
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;
|
||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
|
||||
|
||||
function composer_error_die($message){
|
||||
echo "[CRITICAL] $message" . PHP_EOL;
|
||||
echo "[CRITICAL] Please install/update Composer dependencies or use provided builds." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!class_exists("ClassLoader", false)){
|
||||
if(!is_file(\pocketmine\PATH . "src/spl/ClassLoader.php")){
|
||||
echo "[CRITICAL] Unable to find the PocketMine-SPL library." . PHP_EOL;
|
||||
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
||||
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
}else{
|
||||
composer_error_die("Composer autoloader not found.");
|
||||
}
|
||||
|
||||
if(!class_exists(RakLib::class)){
|
||||
composer_error_die("Unable to find the RakLib library.");
|
||||
}
|
||||
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.");
|
||||
}
|
||||
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still for loading plugins.
|
||||
*/
|
||||
$autoloader = new \BaseClassLoader();
|
||||
$autoloader->addPath(\pocketmine\PATH . "src");
|
||||
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
|
||||
$autoloader->register(true);
|
||||
|
||||
if(!class_exists(RakLib::class)){
|
||||
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
|
||||
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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;
|
||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$autoloader->register(false);
|
||||
|
||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
||||
|
||||
@ -167,6 +171,8 @@ namespace pocketmine {
|
||||
ini_set("memory_limit", '-1');
|
||||
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"]);
|
||||
|
||||
define('pocketmine\DATA', isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
|
||||
@ -186,40 +192,51 @@ namespace pocketmine {
|
||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||
$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)){
|
||||
//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.
|
||||
ini_set("date.timezone", $timezone);
|
||||
}else{
|
||||
//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.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
$timezone = ini_get("date.timezone");
|
||||
if(strpos($timezone, "/") === false){
|
||||
$default_timezone = timezone_name_from_abbr($timezone);
|
||||
ini_set("date.timezone", $default_timezone);
|
||||
date_default_timezone_set($default_timezone);
|
||||
}else{
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
|
||||
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']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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(){
|
||||
switch(Utils::getOS()){
|
||||
@ -383,6 +400,12 @@ namespace pocketmine {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $start
|
||||
* @param array|null $trace
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getTrace($start = 0, $trace = null){
|
||||
if($trace === null){
|
||||
if(function_exists("xdebug_get_function_stack")){
|
||||
@ -408,7 +431,7 @@ namespace pocketmine {
|
||||
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
||||
}, $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;
|
||||
@ -424,13 +447,13 @@ namespace pocketmine {
|
||||
$errors = 0;
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -438,15 +461,15 @@ namespace pocketmine {
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "3.1.5") < 0){
|
||||
$logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
|
||||
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
|
||||
$logger->critical("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
|
||||
++$errors;
|
||||
}
|
||||
|
||||
if(extension_loaded("leveldb")){
|
||||
$leveldb_version = phpversion("leveldb");
|
||||
if(version_compare($leveldb_version, "0.2.0") < 0){
|
||||
$logger->critical("php-leveldb >= 0.2.0 is required, while you have $leveldb_version");
|
||||
if(version_compare($leveldb_version, "0.2.1") < 0){
|
||||
$logger->critical("php-leveldb >= 0.2.1 is required, while you have $leveldb_version");
|
||||
++$errors;
|
||||
}
|
||||
}
|
||||
@ -462,7 +485,7 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
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 = [
|
||||
@ -524,11 +547,11 @@ namespace pocketmine {
|
||||
|
||||
|
||||
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();
|
||||
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");
|
||||
|
||||
@ -536,19 +559,7 @@ namespace pocketmine {
|
||||
$killer->start();
|
||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||
|
||||
$erroredThreads = 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(ThreadManager::getInstance()->stopAll() > 0){
|
||||
if(\pocketmine\DEBUG > 1){
|
||||
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\Effect;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Skin;
|
||||
use pocketmine\event\HandlerList;
|
||||
use pocketmine\event\level\LevelInitEvent;
|
||||
use pocketmine\event\level\LevelLoadEvent;
|
||||
@ -45,9 +46,7 @@ use pocketmine\event\server\ServerCommandEvent;
|
||||
use pocketmine\event\TextContainer;
|
||||
use pocketmine\event\Timings;
|
||||
use pocketmine\event\TimingsHandler;
|
||||
use pocketmine\event\TranslationContainer;
|
||||
use pocketmine\inventory\CraftingManager;
|
||||
use pocketmine\inventory\InventoryType;
|
||||
use pocketmine\inventory\Recipe;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\ItemFactory;
|
||||
@ -83,6 +82,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\RakLibInterface;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\query\QueryHandler;
|
||||
@ -114,8 +114,8 @@ use pocketmine\utils\VersionString;
|
||||
* The class that manages everything
|
||||
*/
|
||||
class Server{
|
||||
const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
|
||||
const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
|
||||
public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin";
|
||||
public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user";
|
||||
|
||||
/** @var Server */
|
||||
private static $instance = null;
|
||||
@ -194,6 +194,9 @@ class Server{
|
||||
/** @var int */
|
||||
private $maxPlayers;
|
||||
|
||||
/** @var bool */
|
||||
private $onlineMode = true;
|
||||
|
||||
/** @var bool */
|
||||
private $autoSave;
|
||||
|
||||
@ -231,7 +234,6 @@ class Server{
|
||||
private $serverID;
|
||||
|
||||
private $autoloader;
|
||||
private $filePath;
|
||||
private $dataPath;
|
||||
private $pluginPath;
|
||||
|
||||
@ -273,7 +275,7 @@ class Server{
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string{
|
||||
return "PocketMine-MP";
|
||||
return \pocketmine\NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,7 +317,14 @@ class Server{
|
||||
* @return string
|
||||
*/
|
||||
public function getFilePath() : string{
|
||||
return $this->filePath;
|
||||
return \pocketmine\PATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResourcePath() : string{
|
||||
return \pocketmine\RESOURCE_PATH;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,6 +348,24 @@ class Server{
|
||||
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
|
||||
*/
|
||||
@ -406,7 +433,7 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
public function getGenerateStructures() : bool{
|
||||
return $this->getConfigBoolean("generate-structures", true);
|
||||
return $this->getConfigBool("generate-structures", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +447,7 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
public function getForceGamemode() : bool{
|
||||
return $this->getConfigBoolean("force-gamemode", false);
|
||||
return $this->getConfigBool("force-gamemode", false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -494,36 +521,17 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @deprecated Moved to {@link Level#getDifficultyFromString}
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
public static function getDifficultyFromString(string $str) : int{
|
||||
switch(strtolower(trim($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;
|
||||
return Level::getDifficultyFromString($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
|
||||
* @return int
|
||||
*/
|
||||
public function getDifficulty() : int{
|
||||
@ -534,7 +542,7 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
public function hasWhitelist() : bool{
|
||||
return $this->getConfigBoolean("white-list", false);
|
||||
return $this->getConfigBool("white-list", false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -548,14 +556,14 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
public function getAllowFlight() : bool{
|
||||
return $this->getConfigBoolean("allow-flight", false);
|
||||
return $this->getConfigBool("allow-flight", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isHardcore() : bool{
|
||||
return $this->getConfigBoolean("hardcore", false);
|
||||
return $this->getConfigBool("hardcore", false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -569,7 +577,7 @@ class Server{
|
||||
* @return string
|
||||
*/
|
||||
public function getMotd() : string{
|
||||
return $this->getConfigString("motd", "Minecraft: PE Server");
|
||||
return $this->getConfigString("motd", \pocketmine\NAME . " Server");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -754,32 +762,35 @@ class Server{
|
||||
}
|
||||
}
|
||||
$spawn = $this->getDefaultLevel()->getSafeSpawn();
|
||||
$currentTimeMillis = (int) (microtime(true) * 1000);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new LongTag("firstPlayed", (int) (microtime(true) * 1000)),
|
||||
new LongTag("lastPlayed", (int) (microtime(true) * 1000)),
|
||||
new LongTag("firstPlayed", $currentTimeMillis),
|
||||
new LongTag("lastPlayed", $currentTimeMillis),
|
||||
new ListTag("Pos", [
|
||||
new DoubleTag("", $spawn->x),
|
||||
new DoubleTag("", $spawn->y),
|
||||
new DoubleTag("", $spawn->z)
|
||||
]),
|
||||
], NBT::TAG_Double),
|
||||
new StringTag("Level", $this->getDefaultLevel()->getName()),
|
||||
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
|
||||
//new IntTag("SpawnX", (int) $spawn->x),
|
||||
//new IntTag("SpawnY", (int) $spawn->y),
|
||||
//new IntTag("SpawnZ", (int) $spawn->z),
|
||||
//new ByteTag("SpawnForced", 1), //TODO
|
||||
new ListTag("Inventory", []),
|
||||
new ListTag("Inventory", [], NBT::TAG_Compound),
|
||||
new ListTag("EnderChestInventory", [], NBT::TAG_Compound),
|
||||
new CompoundTag("Achievements", []),
|
||||
new IntTag("playerGameType", $this->getGamemode()),
|
||||
new ListTag("Motion", [
|
||||
new DoubleTag("", 0.0),
|
||||
new DoubleTag("", 0.0),
|
||||
new DoubleTag("", 0.0)
|
||||
]),
|
||||
], NBT::TAG_Double),
|
||||
new ListTag("Rotation", [
|
||||
new FloatTag("", 0.0),
|
||||
new FloatTag("", 0.0)
|
||||
]),
|
||||
], NBT::TAG_Float),
|
||||
new FloatTag("FallDistance", 0.0),
|
||||
new ShortTag("Fire", 0),
|
||||
new ShortTag("Air", 300),
|
||||
@ -787,10 +798,6 @@ class Server{
|
||||
new ByteTag("Invulnerable", 0),
|
||||
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;
|
||||
|
||||
@ -915,7 +922,7 @@ class Server{
|
||||
/**
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getDefaultLevel(){
|
||||
public function getDefaultLevel() : ?Level{
|
||||
return $this->levelDefault;
|
||||
}
|
||||
|
||||
@ -926,7 +933,7 @@ class Server{
|
||||
*
|
||||
* @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)){
|
||||
$this->levelDefault = $level;
|
||||
}
|
||||
@ -946,12 +953,8 @@ class Server{
|
||||
*
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getLevel(int $levelId){
|
||||
if(isset($this->levels[$levelId])){
|
||||
return $this->levels[$levelId];
|
||||
}
|
||||
|
||||
return null;
|
||||
public function getLevel(int $levelId) : ?Level{
|
||||
return $this->levels[$levelId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -961,7 +964,7 @@ class Server{
|
||||
*
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getLevelByName(string $name){
|
||||
public function getLevelByName(string $name) : ?Level{
|
||||
foreach($this->getLevels() as $level){
|
||||
if($level->getFolderName() === $name){
|
||||
return $level;
|
||||
@ -983,13 +986,16 @@ class Server{
|
||||
if($level === $this->getDefaultLevel() and !$forceUnload){
|
||||
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 +1090,7 @@ class Server{
|
||||
|
||||
$level->setTickRate($this->baseTickRate);
|
||||
}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);
|
||||
return false;
|
||||
}
|
||||
@ -1236,7 +1242,7 @@ class Server{
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getConfigBoolean(string $variable, bool $defaultValue = false) : bool{
|
||||
public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
|
||||
$v = getopt("", ["$variable::"]);
|
||||
if(isset($v[$variable])){
|
||||
$value = $v[$variable];
|
||||
@ -1258,6 +1264,18 @@ class Server{
|
||||
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 bool $value
|
||||
@ -1381,7 +1399,7 @@ class Server{
|
||||
if(is_array($value)){
|
||||
$commands = $value;
|
||||
}else{
|
||||
$commands[] = $value;
|
||||
$commands[] = (string) $value;
|
||||
}
|
||||
|
||||
$result[$key] = $commands;
|
||||
@ -1395,6 +1413,9 @@ class Server{
|
||||
* @return Server
|
||||
*/
|
||||
public static function getInstance() : Server{
|
||||
if(self::$instance === null){
|
||||
throw new \RuntimeException("Attempt to retrieve Server instance outside server thread");
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
@ -1407,19 +1428,16 @@ class Server{
|
||||
/**
|
||||
* @param \ClassLoader $autoloader
|
||||
* @param \ThreadedLogger $logger
|
||||
* @param string $filePath
|
||||
* @param string $dataPath
|
||||
* @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){
|
||||
self::$instance = $this;
|
||||
self::$sleeper = new \Threaded;
|
||||
$this->autoloader = $autoloader;
|
||||
$this->logger = $logger;
|
||||
|
||||
try{
|
||||
|
||||
$this->filePath = $filePath;
|
||||
if(!file_exists($dataPath . "worlds/")){
|
||||
mkdir($dataPath . "worlds/", 0777);
|
||||
}
|
||||
@ -1441,7 +1459,7 @@ class Server{
|
||||
|
||||
$this->logger->info("Loading 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()){
|
||||
$content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content);
|
||||
}
|
||||
@ -1463,7 +1481,7 @@ class Server{
|
||||
|
||||
$this->logger->info("Loading server properties...");
|
||||
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
||||
"motd" => "Minecraft: PE Server",
|
||||
"motd" => \pocketmine\NAME . " Server",
|
||||
"server-port" => 19132,
|
||||
"white-list" => false,
|
||||
"announce-player-achievements" => true,
|
||||
@ -1485,10 +1503,11 @@ class Server{
|
||||
"enable-rcon" => false,
|
||||
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
||||
"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->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
||||
|
||||
@ -1512,7 +1531,12 @@ class Server{
|
||||
}else{
|
||||
Network::$BATCH_THRESHOLD = -1;
|
||||
}
|
||||
|
||||
$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->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
||||
@ -1524,7 +1548,7 @@ class Server{
|
||||
|
||||
$this->scheduler = new ServerScheduler();
|
||||
|
||||
if($this->getConfigBoolean("enable-rcon", false) === true){
|
||||
if($this->getConfigBool("enable-rcon", false) === true){
|
||||
try{
|
||||
$this->rcon = new RCON(
|
||||
$this,
|
||||
@ -1556,10 +1580,20 @@ class Server{
|
||||
$this->banByIP->load();
|
||||
|
||||
$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->setConfigInt("difficulty", 3);
|
||||
$this->onlineMode = $this->getConfigBool("xbox-auth", true);
|
||||
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){
|
||||
@ -1579,12 +1613,13 @@ class Server{
|
||||
|
||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.info", [
|
||||
$this->getName(),
|
||||
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE,
|
||||
($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::RESET,
|
||||
$this->getCodename(),
|
||||
$this->getApiVersion()
|
||||
]));
|
||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
||||
|
||||
|
||||
Timings::init();
|
||||
|
||||
$this->consoleSender = new ConsoleCommandSender();
|
||||
@ -1592,7 +1627,6 @@ class Server{
|
||||
|
||||
Entity::init();
|
||||
Tile::init();
|
||||
InventoryType::init();
|
||||
BlockFactory::init();
|
||||
Enchantment::init();
|
||||
ItemFactory::init();
|
||||
@ -1626,35 +1660,37 @@ class Server{
|
||||
LevelProviderManager::addProvider(Anvil::class);
|
||||
LevelProviderManager::addProvider(McRegion::class);
|
||||
LevelProviderManager::addProvider(PMAnvil::class);
|
||||
LevelProviderManager::addProvider(LevelDB::class);
|
||||
if(extension_loaded("leveldb")){
|
||||
$this->logger->debug($this->getLanguage()->translateString("pocketmine.debug.enable"));
|
||||
LevelProviderManager::addProvider(LevelDB::class);
|
||||
}
|
||||
|
||||
|
||||
Generator::addGenerator(Flat::class, "flat");
|
||||
Generator::addGenerator(Normal::class, "normal");
|
||||
Generator::addGenerator(Normal::class, "default");
|
||||
Generator::addGenerator(Nether::class, "hell");
|
||||
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){
|
||||
$seed = $this->getProperty("worlds.$name.seed", time());
|
||||
$seed = $options["seed"] ?? time();
|
||||
if(is_string($seed) and !is_numeric($seed)){
|
||||
$seed = Utils::javaStringHash($seed);
|
||||
}elseif(!is_int($seed)){
|
||||
$seed = (int) $seed;
|
||||
}
|
||||
|
||||
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
|
||||
$generator = Generator::getGenerator(array_shift($options));
|
||||
if(count($options) > 0){
|
||||
$options = [
|
||||
"preset" => implode(":", $options)
|
||||
];
|
||||
if(isset($options["generator"])){
|
||||
$generatorOptions = explode(":", $options["generator"]);
|
||||
$generator = Generator::getGenerator(array_shift($generatorOptions));
|
||||
if(count($options) > 0){
|
||||
$options["preset"] = implode(":", $generatorOptions);
|
||||
}
|
||||
}else{
|
||||
$options = [];
|
||||
$generator = Generator::getGenerator("default");
|
||||
}
|
||||
|
||||
$this->generateLevel($name, $seed, $generator, $options);
|
||||
@ -1681,8 +1717,9 @@ class Server{
|
||||
$this->setDefaultLevel($this->getLevelByName($default));
|
||||
}
|
||||
|
||||
|
||||
$this->properties->save(true);
|
||||
if($this->properties->hasChanged()){
|
||||
$this->properties->save(true);
|
||||
}
|
||||
|
||||
if(!($this->getDefaultLevel() instanceof Level)){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translateString("pocketmine.level.defaultError"));
|
||||
@ -1886,17 +1923,9 @@ class Server{
|
||||
$pk->encode();
|
||||
}
|
||||
|
||||
if($immediate){
|
||||
foreach($identifiers as $i){
|
||||
if(isset($this->players[$i])){
|
||||
$this->players[$i]->directDataPacket($pk);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
foreach($identifiers as $i){
|
||||
if(isset($this->players[$i])){
|
||||
$this->players[$i]->dataPacket($pk);
|
||||
}
|
||||
foreach($identifiers as $i){
|
||||
if(isset($this->players[$i])){
|
||||
$this->players[$i]->sendDataPacket($pk, false, $immediate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1955,7 +1984,7 @@ class Server{
|
||||
}
|
||||
|
||||
|
||||
$sender->sendMessage(new TranslationContainer(TextFormat::GOLD . "%commands.generic.notFound"));
|
||||
$sender->sendMessage($this->getLanguage()->translateString(TextFormat::RED . "%commands.generic.notFound"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1975,8 +2004,8 @@ class Server{
|
||||
$this->properties->reload();
|
||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||
|
||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
||||
$this->setConfigInt("difficulty", 3);
|
||||
if($this->getConfigBool("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
$this->banByIP->load();
|
||||
@ -2048,8 +2077,10 @@ class Server{
|
||||
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Saving properties");
|
||||
$this->properties->save();
|
||||
if($this->properties->hasChanged()){
|
||||
$this->getLogger()->debug("Saving properties");
|
||||
$this->properties->save();
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Closing console");
|
||||
$this->console->shutdown();
|
||||
@ -2083,7 +2114,7 @@ class Server{
|
||||
* Starts the PocketMine-MP server and starts processing ticks and packets
|
||||
*/
|
||||
public function start(){
|
||||
if($this->getConfigBoolean("enable-query", true) === true){
|
||||
if($this->getConfigBool("enable-query", true) === true){
|
||||
$this->queryHandler = new QueryHandler();
|
||||
}
|
||||
|
||||
@ -2125,6 +2156,10 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable $e
|
||||
* @param array|null $trace
|
||||
*/
|
||||
public function exceptionHandler(\Throwable $e, $trace = null){
|
||||
if($e === null){
|
||||
return;
|
||||
@ -2271,7 +2306,7 @@ class Server{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -2280,32 +2315,44 @@ class Server{
|
||||
if(isset($this->playerList[$player->getRawUniqueId()])){
|
||||
unset($this->playerList[$player->getRawUniqueId()]);
|
||||
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$player->getUniqueId()];
|
||||
$this->broadcastPacket($this->playerList, $pk);
|
||||
$this->removePlayerListData($player->getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UUID $uuid
|
||||
* @param Player[]|null $players
|
||||
*/
|
||||
public function removePlayerListData(UUID $uuid, array $players = null){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$uuid];
|
||||
$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
|
||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Player $p
|
||||
*/
|
||||
public function sendFullPlayerListData(Player $p){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||
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);
|
||||
@ -2315,7 +2362,7 @@ class Server{
|
||||
foreach($this->players as $p){
|
||||
if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
|
||||
$p->close("", "Login timeout");
|
||||
}elseif($this->alwaysTickPlayers and $p->joined){
|
||||
}elseif($this->alwaysTickPlayers and $p->spawned){
|
||||
$p->onUpdate($currentTick);
|
||||
}
|
||||
}
|
||||
@ -2350,7 +2397,11 @@ class Server{
|
||||
}
|
||||
}
|
||||
}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);
|
||||
}
|
||||
}
|
||||
@ -2360,7 +2411,7 @@ class Server{
|
||||
if($this->getAutoSave()){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->players as $index => $player){
|
||||
if($player->joined){
|
||||
if($player->spawned){
|
||||
$player->save(true);
|
||||
}elseif(!$player->isConnected()){
|
||||
$this->removePlayer($player);
|
||||
@ -2375,7 +2426,7 @@ class Server{
|
||||
}
|
||||
|
||||
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->uniquePlayers = [];
|
||||
@ -2426,8 +2477,6 @@ class Server{
|
||||
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
||||
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
||||
|
||||
$this->network->resetStatistics();
|
||||
|
||||
Timings::$titleTickTimer->stopTiming();
|
||||
}
|
||||
|
||||
@ -2488,25 +2537,26 @@ class Server{
|
||||
$player->checkNetwork();
|
||||
}
|
||||
|
||||
if(($this->tickCounter & 0b1111) === 0){
|
||||
if(($this->tickCounter % 20) === 0){
|
||||
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
||||
$this->titleTick();
|
||||
}
|
||||
$this->currentTPS = 20;
|
||||
$this->currentUse = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
$this->network->updateName();
|
||||
$this->network->resetStatistics();
|
||||
}
|
||||
|
||||
$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){
|
||||
|
@ -51,16 +51,17 @@ abstract class Thread extends \Thread{
|
||||
* (unless you are using a custom autoloader).
|
||||
*/
|
||||
public function registerClassLoader(){
|
||||
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||
if(!interface_exists("ClassLoader", false)){
|
||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
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);
|
||||
|
||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\utils\MainLogger;
|
||||
|
||||
class ThreadManager extends \Volatile{
|
||||
|
||||
/** @var ThreadManager */
|
||||
@ -68,4 +70,23 @@ class ThreadManager extends \Volatile{
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -52,16 +52,17 @@ abstract class Worker extends \Worker{
|
||||
* (unless you are using a custom autoloader).
|
||||
*/
|
||||
public function registerClassLoader(){
|
||||
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||
if(!interface_exists("ClassLoader", false)){
|
||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
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);
|
||||
|
||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
|
||||
/**
|
||||
@ -32,7 +33,6 @@ use pocketmine\item\Item;
|
||||
class Air extends Transparent{
|
||||
|
||||
protected $id = self::AIR;
|
||||
protected $meta = 0;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
@ -54,7 +54,7 @@ class Air extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -66,10 +66,14 @@ class Air extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return -1;
|
||||
}
|
||||
|
@ -27,25 +27,26 @@ use pocketmine\inventory\AnvilInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Anvil extends Fallable{
|
||||
|
||||
const TYPE_NORMAL = 0;
|
||||
const TYPE_SLIGHTLY_DAMAGED = 4;
|
||||
const TYPE_VERY_DAMAGED = 8;
|
||||
public const TYPE_NORMAL = 0;
|
||||
public const TYPE_SLIGHTLY_DAMAGED = 4;
|
||||
public const TYPE_VERY_DAMAGED = 8;
|
||||
|
||||
protected $id = self::ANVIL;
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isTransparent() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 5;
|
||||
}
|
||||
@ -67,6 +68,30 @@ class Anvil extends Fallable{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
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{
|
||||
if($player instanceof Player){
|
||||
$player->addWindow(new AnvilInventory($this));
|
||||
@ -75,7 +100,7 @@ class Anvil extends Fallable{
|
||||
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;
|
||||
$this->meta = ($this->meta & 0x0c) | $direction;
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
@ -29,18 +29,14 @@ use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
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\tile\Bed as TileBed;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\utils\TextFormat;
|
||||
|
||||
class Bed extends Transparent{
|
||||
const BITFLAG_OCCUPIED = 0x04;
|
||||
const BITFLAG_HEAD = 0x08;
|
||||
public const BITFLAG_OCCUPIED = 0x04;
|
||||
public const BITFLAG_HEAD = 0x08;
|
||||
|
||||
protected $id = self::BED_BLOCK;
|
||||
|
||||
@ -58,7 +54,7 @@ class Bed extends Transparent{
|
||||
return "Bed Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -129,7 +125,7 @@ class Bed extends Transparent{
|
||||
/**
|
||||
* @return Bed|null
|
||||
*/
|
||||
public function getOtherHalf(){
|
||||
public function getOtherHalf() : ?Bed{
|
||||
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
||||
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
||||
return $other;
|
||||
@ -146,7 +142,7 @@ class Bed extends Transparent{
|
||||
|
||||
return true;
|
||||
}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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
if(!$down->isTransparent()){
|
||||
$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($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::BED),
|
||||
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);
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -209,7 +193,7 @@ class Bed extends Transparent{
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
$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
|
||||
$this->getLevel()->useBreakOn($other, $item, null, $player !== null); //make sure tiles get removed
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -50,4 +50,8 @@ class Beetroot extends Crops{
|
||||
ItemFactory::get(Item::BEETROOT_SEEDS, 0, 1)
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::BEETROOT_SEEDS);
|
||||
}
|
||||
}
|
@ -61,21 +61,25 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
protected $id;
|
||||
/** @var int */
|
||||
protected $meta = 0;
|
||||
/** @var string */
|
||||
/** @var string|null */
|
||||
protected $fallbackName;
|
||||
/** @var int|null */
|
||||
protected $itemId;
|
||||
|
||||
/** @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 $meta Meta value of the block type
|
||||
* @param string $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 $id The block type's ID, 0-255
|
||||
* @param int $meta Meta value of the block type
|
||||
* @param string|null $name English name of the block type (TODO: implement translations)
|
||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||
*/
|
||||
public function __construct(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->meta = $meta;
|
||||
$this->fallbackName = $name;
|
||||
@ -86,7 +90,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @return 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
|
||||
*/
|
||||
final public function setDamage(int $meta){
|
||||
final public function setDamage(int $meta) : void{
|
||||
if($meta < 0 or $meta > 0xf){
|
||||
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
||||
}
|
||||
@ -136,6 +140,34 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
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.
|
||||
*
|
||||
@ -143,12 +175,12 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @param Block $blockReplace
|
||||
* @param Block $blockClicked
|
||||
* @param int $face
|
||||
* @param Vector3 $facePos
|
||||
* @param Vector3 $clickVector
|
||||
* @param Player|null $player
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
@ -163,6 +195,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeBrokenWith(Item $item) : bool{
|
||||
return $this->getHardness() !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
@ -175,6 +211,63 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
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() * 1.5;
|
||||
if($this->canBeBrokenWith($item)){
|
||||
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 /= 1.5;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
@ -266,32 +359,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
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
|
||||
*/
|
||||
@ -328,7 +395,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 +404,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*
|
||||
* @param Position $v
|
||||
*/
|
||||
final public function position(Position $v){
|
||||
final public function position(Position $v) : void{
|
||||
$this->x = (int) $v->x;
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
@ -354,58 +421,16 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*/
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getDamage() & $this->getVariantBitmask(), 1)
|
||||
ItemFactory::get($this->getItemId(), $this->getVariant(), 1)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seconds that this block takes to be broken using an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return float
|
||||
* Returns the item that players will equip when middle-clicking on this block.
|
||||
* @return Item
|
||||
*/
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$base = $this->getHardness() * 1.5;
|
||||
if($this->canBeBrokenWith($item)){
|
||||
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;
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get($this->getItemId(), $this->getVariant());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -417,7 +442,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 $step
|
||||
@ -432,6 +457,35 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -447,22 +501,50 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @return 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function getBoundingBox(){
|
||||
public function getBoundingBox() : ?AxisAlignedBB{
|
||||
if($this->boundingBox === null){
|
||||
$this->boundingBox = $this->recalculateBoundingBox();
|
||||
}
|
||||
@ -472,7 +554,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
/**
|
||||
* @return AxisAlignedBB|null
|
||||
*/
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -483,92 +565,52 @@ 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 $pos2
|
||||
*
|
||||
* @return MovingObjectPosition|null
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){
|
||||
$bb = $this->getBoundingBox();
|
||||
if($bb === null){
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(empty($bbs)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX);
|
||||
$v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX);
|
||||
$v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY);
|
||||
$v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY);
|
||||
$v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ);
|
||||
$v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ);
|
||||
/** @var MovingObjectPosition|null $currentHit */
|
||||
$currentHit = null;
|
||||
/** @var int|float $currentDistance */
|
||||
$currentDistance = PHP_INT_MAX;
|
||||
|
||||
if($v1 !== null and !$bb->isVectorInYZ($v1)){
|
||||
$v1 = null;
|
||||
foreach($bbs as $bb){
|
||||
$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)){
|
||||
$v2 = null;
|
||||
if($currentHit !== null){
|
||||
$currentHit->blockX = $this->x;
|
||||
$currentHit->blockY = $this->y;
|
||||
$currentHit->blockZ = $this->z;
|
||||
}
|
||||
|
||||
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));
|
||||
return $currentHit;
|
||||
}
|
||||
|
||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||
|
@ -56,7 +56,7 @@ class BlockFactory{
|
||||
*
|
||||
* @param bool $force
|
||||
*/
|
||||
public static function init(bool $force = false){
|
||||
public static function init(bool $force = false) : void{
|
||||
if(self::$list === null or $force){
|
||||
self::$list = new \SplFixedArray(256);
|
||||
self::$fullList = new \SplFixedArray(4096);
|
||||
@ -133,7 +133,7 @@ class BlockFactory{
|
||||
self::registerBlock(new Furnace());
|
||||
self::registerBlock(new BurningFurnace());
|
||||
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 Rail());
|
||||
self::registerBlock(new CobblestoneStairs());
|
||||
@ -153,8 +153,8 @@ class BlockFactory{
|
||||
self::registerBlock(new Cactus());
|
||||
self::registerBlock(new Clay());
|
||||
self::registerBlock(new Sugarcane());
|
||||
|
||||
self::registerBlock(new Fence());
|
||||
//TODO: JUKEBOX
|
||||
self::registerBlock(new WoodenFence());
|
||||
self::registerBlock(new Pumpkin());
|
||||
self::registerBlock(new Netherrack());
|
||||
self::registerBlock(new SoulSand());
|
||||
@ -168,8 +168,8 @@ class BlockFactory{
|
||||
self::registerBlock(new Trapdoor());
|
||||
//TODO: MONSTER_EGG
|
||||
self::registerBlock(new StoneBricks());
|
||||
//TODO: BROWN_MUSHROOM_BLOCK
|
||||
//TODO: RED_MUSHROOM_BLOCK
|
||||
self::registerBlock(new BrownMushroomBlock());
|
||||
self::registerBlock(new RedMushroomBlock());
|
||||
self::registerBlock(new IronBars());
|
||||
self::registerBlock(new GlassPane());
|
||||
self::registerBlock(new Melon());
|
||||
@ -199,7 +199,7 @@ class BlockFactory{
|
||||
self::registerBlock(new CocoaBlock());
|
||||
self::registerBlock(new SandstoneStairs());
|
||||
self::registerBlock(new EmeraldOre());
|
||||
//TODO: ENDER_CHEST
|
||||
self::registerBlock(new EnderChest());
|
||||
self::registerBlock(new TripwireHook());
|
||||
self::registerBlock(new Tripwire());
|
||||
self::registerBlock(new Emerald());
|
||||
@ -245,12 +245,13 @@ class BlockFactory{
|
||||
self::registerBlock(new Coal());
|
||||
self::registerBlock(new PackedIce());
|
||||
self::registerBlock(new DoublePlant());
|
||||
|
||||
self::registerBlock(new StandingBanner());
|
||||
self::registerBlock(new WallBanner());
|
||||
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
||||
//TODO: RED_SANDSTONE
|
||||
//TODO: RED_SANDSTONE_STAIRS
|
||||
//TODO: DOUBLE_STONE_SLAB2
|
||||
//TODO: STONE_SLAB2
|
||||
self::registerBlock(new RedSandstone());
|
||||
self::registerBlock(new RedSandstoneStairs());
|
||||
self::registerBlock(new DoubleStoneSlab2());
|
||||
self::registerBlock(new StoneSlab2());
|
||||
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::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
||||
@ -259,19 +260,20 @@ class BlockFactory{
|
||||
//TODO: REPEATING_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::BIRCH_DOOR_BLOCK, 0, "Birch Door Block", Item::BIRCH_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door Block", Item::JUNGLE_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door Block", 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::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_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", Item::JUNGLE_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", Item::DARK_OAK_DOOR));
|
||||
self::registerBlock(new GrassPath());
|
||||
self::registerBlock(new ItemFrame());
|
||||
//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
|
||||
self::registerBlock(new EndRod());
|
||||
//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::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
||||
self::registerBlock(new Concrete());
|
||||
//TODO: CONCRETEPOWDER
|
||||
self::registerBlock(new ConcretePowder());
|
||||
|
||||
//TODO: CHORUS_PLANT
|
||||
self::registerBlock(new StainedGlass());
|
||||
@ -314,6 +316,7 @@ class BlockFactory{
|
||||
//TODO: INFO_UPDATE2
|
||||
//TODO: MOVINGBLOCK
|
||||
//TODO: OBSERVER
|
||||
//TODO: STRUCTURE_BLOCK
|
||||
|
||||
//TODO: RESERVED6
|
||||
|
||||
@ -338,10 +341,10 @@ class BlockFactory{
|
||||
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
||||
* $override parameter.
|
||||
*/
|
||||
public static function registerBlock(Block $block, bool $override = false){
|
||||
public static function registerBlock(Block $block, bool $override = false) : void{
|
||||
$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");
|
||||
}
|
||||
|
||||
@ -403,4 +406,15 @@ class BlockFactory{
|
||||
public static function getBlockStatesArray() : \SplFixedArray{
|
||||
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{
|
||||
|
||||
const AIR = 0;
|
||||
const STONE = 1;
|
||||
const GRASS = 2;
|
||||
const DIRT = 3;
|
||||
const COBBLESTONE = 4;
|
||||
const PLANKS = 5, WOODEN_PLANKS = 5;
|
||||
const SAPLING = 6;
|
||||
const BEDROCK = 7;
|
||||
const FLOWING_WATER = 8;
|
||||
const STILL_WATER = 9, WATER = 9;
|
||||
const FLOWING_LAVA = 10;
|
||||
const LAVA = 11, STILL_LAVA = 11;
|
||||
const SAND = 12;
|
||||
const GRAVEL = 13;
|
||||
const GOLD_ORE = 14;
|
||||
const IRON_ORE = 15;
|
||||
const COAL_ORE = 16;
|
||||
const LOG = 17, WOOD = 17;
|
||||
const LEAVES = 18;
|
||||
const SPONGE = 19;
|
||||
const GLASS = 20;
|
||||
const LAPIS_ORE = 21;
|
||||
const LAPIS_BLOCK = 22;
|
||||
const DISPENSER = 23;
|
||||
const SANDSTONE = 24;
|
||||
const NOTEBLOCK = 25, NOTE_BLOCK = 25;
|
||||
const BED_BLOCK = 26;
|
||||
const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
|
||||
const DETECTOR_RAIL = 28;
|
||||
const STICKY_PISTON = 29;
|
||||
const COBWEB = 30, WEB = 30;
|
||||
const TALLGRASS = 31, TALL_GRASS = 31;
|
||||
const DEADBUSH = 32, DEAD_BUSH = 32;
|
||||
const PISTON = 33;
|
||||
const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
|
||||
const WOOL = 35;
|
||||
public const AIR = 0;
|
||||
public const STONE = 1;
|
||||
public const GRASS = 2;
|
||||
public const DIRT = 3;
|
||||
public const COBBLESTONE = 4;
|
||||
public const PLANKS = 5, WOODEN_PLANKS = 5;
|
||||
public const SAPLING = 6;
|
||||
public const BEDROCK = 7;
|
||||
public const FLOWING_WATER = 8;
|
||||
public const STILL_WATER = 9, WATER = 9;
|
||||
public const FLOWING_LAVA = 10;
|
||||
public const LAVA = 11, STILL_LAVA = 11;
|
||||
public const SAND = 12;
|
||||
public const GRAVEL = 13;
|
||||
public const GOLD_ORE = 14;
|
||||
public const IRON_ORE = 15;
|
||||
public const COAL_ORE = 16;
|
||||
public const LOG = 17, WOOD = 17;
|
||||
public const LEAVES = 18;
|
||||
public const SPONGE = 19;
|
||||
public const GLASS = 20;
|
||||
public const LAPIS_ORE = 21;
|
||||
public const LAPIS_BLOCK = 22;
|
||||
public const DISPENSER = 23;
|
||||
public const SANDSTONE = 24;
|
||||
public const NOTEBLOCK = 25, NOTE_BLOCK = 25;
|
||||
public const BED_BLOCK = 26;
|
||||
public const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
|
||||
public const DETECTOR_RAIL = 28;
|
||||
public const STICKY_PISTON = 29;
|
||||
public const COBWEB = 30, WEB = 30;
|
||||
public const TALLGRASS = 31, TALL_GRASS = 31;
|
||||
public const DEADBUSH = 32, DEAD_BUSH = 32;
|
||||
public const PISTON = 33;
|
||||
public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
|
||||
public const WOOL = 35;
|
||||
|
||||
const DANDELION = 37, YELLOW_FLOWER = 37;
|
||||
const POPPY = 38, RED_FLOWER = 38;
|
||||
const BROWN_MUSHROOM = 39;
|
||||
const RED_MUSHROOM = 40;
|
||||
const GOLD_BLOCK = 41;
|
||||
const IRON_BLOCK = 42;
|
||||
const DOUBLE_STONE_SLAB = 43;
|
||||
const STONE_SLAB = 44;
|
||||
const BRICK_BLOCK = 45;
|
||||
const TNT = 46;
|
||||
const BOOKSHELF = 47;
|
||||
const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
|
||||
const OBSIDIAN = 49;
|
||||
const TORCH = 50;
|
||||
const FIRE = 51;
|
||||
const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
|
||||
const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
|
||||
const CHEST = 54;
|
||||
const REDSTONE_WIRE = 55;
|
||||
const DIAMOND_ORE = 56;
|
||||
const DIAMOND_BLOCK = 57;
|
||||
const CRAFTING_TABLE = 58, WORKBENCH = 58;
|
||||
const WHEAT_BLOCK = 59;
|
||||
const FARMLAND = 60;
|
||||
const FURNACE = 61;
|
||||
const BURNING_FURNACE = 62, LIT_FURNACE = 62;
|
||||
const SIGN_POST = 63, STANDING_SIGN = 63;
|
||||
const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
|
||||
const LADDER = 65;
|
||||
const RAIL = 66;
|
||||
const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
|
||||
const WALL_SIGN = 68;
|
||||
const LEVER = 69;
|
||||
const STONE_PRESSURE_PLATE = 70;
|
||||
const IRON_DOOR_BLOCK = 71;
|
||||
const WOODEN_PRESSURE_PLATE = 72;
|
||||
const REDSTONE_ORE = 73;
|
||||
const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
|
||||
const UNLIT_REDSTONE_TORCH = 75;
|
||||
const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
|
||||
const STONE_BUTTON = 77;
|
||||
const SNOW_LAYER = 78;
|
||||
const ICE = 79;
|
||||
const SNOW = 80, SNOW_BLOCK = 80;
|
||||
const CACTUS = 81;
|
||||
const CLAY_BLOCK = 82;
|
||||
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
||||
public const DANDELION = 37, YELLOW_FLOWER = 37;
|
||||
public const POPPY = 38, RED_FLOWER = 38;
|
||||
public const BROWN_MUSHROOM = 39;
|
||||
public const RED_MUSHROOM = 40;
|
||||
public const GOLD_BLOCK = 41;
|
||||
public const IRON_BLOCK = 42;
|
||||
public const DOUBLE_STONE_SLAB = 43;
|
||||
public const STONE_SLAB = 44;
|
||||
public const BRICK_BLOCK = 45;
|
||||
public const TNT = 46;
|
||||
public const BOOKSHELF = 47;
|
||||
public const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
|
||||
public const OBSIDIAN = 49;
|
||||
public const TORCH = 50;
|
||||
public const FIRE = 51;
|
||||
public const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
|
||||
public const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
|
||||
public const CHEST = 54;
|
||||
public const REDSTONE_WIRE = 55;
|
||||
public const DIAMOND_ORE = 56;
|
||||
public const DIAMOND_BLOCK = 57;
|
||||
public const CRAFTING_TABLE = 58, WORKBENCH = 58;
|
||||
public const WHEAT_BLOCK = 59;
|
||||
public const FARMLAND = 60;
|
||||
public const FURNACE = 61;
|
||||
public const BURNING_FURNACE = 62, LIT_FURNACE = 62;
|
||||
public const SIGN_POST = 63, STANDING_SIGN = 63;
|
||||
public const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
|
||||
public const LADDER = 65;
|
||||
public const RAIL = 66;
|
||||
public const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
|
||||
public const WALL_SIGN = 68;
|
||||
public const LEVER = 69;
|
||||
public const STONE_PRESSURE_PLATE = 70;
|
||||
public const IRON_DOOR_BLOCK = 71;
|
||||
public const WOODEN_PRESSURE_PLATE = 72;
|
||||
public const REDSTONE_ORE = 73;
|
||||
public const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
|
||||
public const UNLIT_REDSTONE_TORCH = 75;
|
||||
public const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
|
||||
public const STONE_BUTTON = 77;
|
||||
public const SNOW_LAYER = 78;
|
||||
public const ICE = 79;
|
||||
public const SNOW = 80, SNOW_BLOCK = 80;
|
||||
public const CACTUS = 81;
|
||||
public const CLAY_BLOCK = 82;
|
||||
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;
|
||||
const PUMPKIN = 86;
|
||||
const NETHERRACK = 87;
|
||||
const SOUL_SAND = 88;
|
||||
const GLOWSTONE = 89;
|
||||
const PORTAL = 90;
|
||||
const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
|
||||
const CAKE_BLOCK = 92;
|
||||
const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
|
||||
const POWERED_REPEATER = 94;
|
||||
const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
|
||||
const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
|
||||
const MONSTER_EGG = 97;
|
||||
const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
|
||||
const BROWN_MUSHROOM_BLOCK = 99;
|
||||
const RED_MUSHROOM_BLOCK = 100;
|
||||
const IRON_BARS = 101;
|
||||
const GLASS_PANE = 102;
|
||||
const MELON_BLOCK = 103;
|
||||
const PUMPKIN_STEM = 104;
|
||||
const MELON_STEM = 105;
|
||||
const VINE = 106, VINES = 106;
|
||||
const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
|
||||
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;
|
||||
public const IRON_TRAPDOOR = 167;
|
||||
public const PRISMARINE = 168;
|
||||
public const SEALANTERN = 169, SEA_LANTERN = 169;
|
||||
public const HAY_BALE = 170, HAY_BLOCK = 170;
|
||||
public const CARPET = 171;
|
||||
public const HARDENED_CLAY = 172;
|
||||
public const COAL_BLOCK = 173;
|
||||
public const PACKED_ICE = 174;
|
||||
public const DOUBLE_PLANT = 175;
|
||||
public const STANDING_BANNER = 176;
|
||||
public const WALL_BANNER = 177;
|
||||
public const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
||||
public const RED_SANDSTONE = 179;
|
||||
public const RED_SANDSTONE_STAIRS = 180;
|
||||
public const DOUBLE_STONE_SLAB2 = 181;
|
||||
public const STONE_SLAB2 = 182;
|
||||
public const SPRUCE_FENCE_GATE = 183;
|
||||
public const BIRCH_FENCE_GATE = 184;
|
||||
public const JUNGLE_FENCE_GATE = 185;
|
||||
public const DARK_OAK_FENCE_GATE = 186;
|
||||
public const ACACIA_FENCE_GATE = 187;
|
||||
public const REPEATING_COMMAND_BLOCK = 188;
|
||||
public const CHAIN_COMMAND_BLOCK = 189;
|
||||
|
||||
const IRON_TRAPDOOR = 167;
|
||||
const PRISMARINE = 168;
|
||||
const SEALANTERN = 169, SEA_LANTERN = 169;
|
||||
const HAY_BALE = 170, HAY_BLOCK = 170;
|
||||
const CARPET = 171;
|
||||
const HARDENED_CLAY = 172;
|
||||
const COAL_BLOCK = 173;
|
||||
const PACKED_ICE = 174;
|
||||
const DOUBLE_PLANT = 175;
|
||||
public const SPRUCE_DOOR_BLOCK = 193;
|
||||
public const BIRCH_DOOR_BLOCK = 194;
|
||||
public const JUNGLE_DOOR_BLOCK = 195;
|
||||
public const ACACIA_DOOR_BLOCK = 196;
|
||||
public const DARK_OAK_DOOR_BLOCK = 197;
|
||||
public const GRASS_PATH = 198;
|
||||
public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
|
||||
public const CHORUS_FLOWER = 200;
|
||||
public const PURPUR_BLOCK = 201;
|
||||
|
||||
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
||||
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;
|
||||
public const PURPUR_STAIRS = 203;
|
||||
|
||||
const SPRUCE_DOOR_BLOCK = 193;
|
||||
const BIRCH_DOOR_BLOCK = 194;
|
||||
const JUNGLE_DOOR_BLOCK = 195;
|
||||
const ACACIA_DOOR_BLOCK = 196;
|
||||
const DARK_OAK_DOOR_BLOCK = 197;
|
||||
const GRASS_PATH = 198;
|
||||
const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
|
||||
const CHORUS_FLOWER = 200;
|
||||
const PURPUR_BLOCK = 201;
|
||||
public const UNDYED_SHULKER_BOX = 205;
|
||||
public const END_BRICKS = 206;
|
||||
public const FROSTED_ICE = 207;
|
||||
public const END_ROD = 208;
|
||||
public const END_GATEWAY = 209;
|
||||
|
||||
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;
|
||||
const FROSTED_ICE = 207;
|
||||
const END_ROD = 208;
|
||||
const END_GATEWAY = 209;
|
||||
public const SHULKER_BOX = 218;
|
||||
public const PURPLE_GLAZED_TERRACOTTA = 219;
|
||||
public const WHITE_GLAZED_TERRACOTTA = 220;
|
||||
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;
|
||||
const NETHER_WART_BLOCK = 214;
|
||||
const RED_NETHER_BRICK = 215;
|
||||
const BONE_BLOCK = 216;
|
||||
public const BLUE_GLAZED_TERRACOTTA = 231;
|
||||
public const BROWN_GLAZED_TERRACOTTA = 232;
|
||||
public const GREEN_GLAZED_TERRACOTTA = 233;
|
||||
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;
|
||||
const PURPLE_GLAZED_TERRACOTTA = 219;
|
||||
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;
|
||||
public const CHORUS_PLANT = 240;
|
||||
public const STAINED_GLASS = 241;
|
||||
|
||||
const BLUE_GLAZED_TERRACOTTA = 231;
|
||||
const BROWN_GLAZED_TERRACOTTA = 232;
|
||||
const GREEN_GLAZED_TERRACOTTA = 233;
|
||||
const RED_GLAZED_TERRACOTTA = 234;
|
||||
const BLACK_GLAZED_TERRACOTTA = 235;
|
||||
const CONCRETE = 236;
|
||||
const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
|
||||
public const PODZOL = 243;
|
||||
public const BEETROOT_BLOCK = 244;
|
||||
public const STONECUTTER = 245;
|
||||
public const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
|
||||
public const NETHERREACTOR = 247, NETHER_REACTOR = 247;
|
||||
public const INFO_UPDATE = 248;
|
||||
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;
|
||||
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;
|
||||
public const RESERVED6 = 255;
|
||||
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ class BoneBlock extends Solid{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
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 = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
@ -60,7 +60,7 @@ class BoneBlock extends Solid{
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item); // TODO: Change the autogenerated stub
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -21,18 +21,21 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class IronDoor extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::IRON_DOOR_BLOCK);
|
||||
parent::__construct(self::IRON_DOOR, $meta, "Iron Door");
|
||||
class BrownMushroomBlock extends RedMushroomBlock{
|
||||
|
||||
protected $id = Block::BROWN_MUSHROOM_BLOCK;
|
||||
|
||||
public function getName() : string{
|
||||
return "Brown Mushroom Block";
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
}
|
@ -26,10 +26,6 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
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\Player;
|
||||
use pocketmine\tile\Furnace as TileFurnace;
|
||||
@ -59,7 +55,7 @@ class BurningFurnace extends Solid{
|
||||
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 = [
|
||||
0 => 4,
|
||||
1 => 2,
|
||||
@ -68,26 +64,8 @@ class BurningFurnace extends Solid{
|
||||
];
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
$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()){
|
||||
$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);
|
||||
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -96,21 +74,11 @@ class BurningFurnace extends Solid{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->getLevel()->getTile($this);
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
$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);
|
||||
$furnace = Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||
}
|
||||
|
||||
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
||||
if($furnace->namedtag->Lock->getValue() !== $item->getCustomName()){
|
||||
return true;
|
||||
}
|
||||
if($furnace->namedtag->hasTag("Lock", StringTag::class) and $furnace->namedtag->getString("Lock") !== $item->getCustomName()){
|
||||
return true;
|
||||
}
|
||||
|
||||
$player->addWindow($furnace->getInventory());
|
||||
|
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";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
@ -70,7 +70,7 @@ class Cactus extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
$entity->attack($ev);
|
||||
}
|
||||
@ -92,7 +92,7 @@ class Cactus extends Transparent{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||
if($this->meta === 0x0f){
|
||||
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){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
||||
if(!$ev->isCancelled()){
|
||||
@ -112,7 +112,7 @@ class Cactus extends Transparent{
|
||||
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);
|
||||
if($down->getId() === self::SAND or $down->getId() === self::CACTUS){
|
||||
$block0 = $this->getSide(Vector3::SIDE_NORTH);
|
||||
|
@ -48,7 +48,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
return "Cake Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$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);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
@ -50,7 +50,7 @@ class Carpet extends Flowable{
|
||||
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$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);
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
@ -43,4 +43,8 @@ class Carrot extends Crops{
|
||||
ItemFactory::get(Item::CARROT, 0, $this->meta >= 0x07 ? mt_rand(1, 4) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::CARROT);
|
||||
}
|
||||
}
|
@ -27,10 +27,6 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
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\Player;
|
||||
use pocketmine\tile\Chest as TileChest;
|
||||
@ -56,18 +52,19 @@ class Chest extends Transparent{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
//these are slightly bigger than in PC
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->x + 0.025,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
$this->x + 0.9375,
|
||||
$this->y + 0.9475,
|
||||
$this->z + 0.9375
|
||||
$this->z + 0.025,
|
||||
$this->x + 0.975,
|
||||
$this->y + 0.95,
|
||||
$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 = [
|
||||
0 => 4,
|
||||
1 => 2,
|
||||
@ -95,26 +92,7 @@ class Chest extends Transparent{
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
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);
|
||||
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
||||
|
||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||
$chest->pairWith($tile);
|
||||
@ -142,21 +120,13 @@ class Chest extends Transparent{
|
||||
if($t instanceof TileChest){
|
||||
$chest = $t;
|
||||
}else{
|
||||
$nbt = new CompoundTag("", [
|
||||
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);
|
||||
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
||||
}
|
||||
|
||||
if(
|
||||
!$this->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;
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class CobblestoneWall extends Transparent{
|
||||
const NONE_MOSSY_WALL = 0;
|
||||
const MOSSY_WALL = 1;
|
||||
public const NONE_MOSSY_WALL = 0;
|
||||
public const MOSSY_WALL = 1;
|
||||
|
||||
protected $id = self::COBBLESTONE_WALL;
|
||||
|
||||
@ -37,10 +37,6 @@ class CobblestoneWall extends Transparent{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
@ -57,38 +53,38 @@ class CobblestoneWall extends Transparent{
|
||||
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));
|
||||
$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.25;
|
||||
$s = $south ? 1 : 0.75;
|
||||
$w = $west ? 0 : 0.25;
|
||||
$e = $east ? 1 : 0.75;
|
||||
|
||||
if($north and $south and !$west and !$east){
|
||||
$w = 0.3125;
|
||||
$e = 0.6875;
|
||||
}elseif(!$north and !$south and $west and $east){
|
||||
$n = 0.3125;
|
||||
$s = 0.6875;
|
||||
$inset = 0.25;
|
||||
if(
|
||||
$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
|
||||
(
|
||||
($north and $south and !$west and !$east) or
|
||||
(!$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
|
||||
$inset = 0.3125;
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $w,
|
||||
$this->x + ($west ? 0 : $inset),
|
||||
$this->y,
|
||||
$this->z + $n,
|
||||
$this->x + $e,
|
||||
$this->z + ($north ? 0 : $inset),
|
||||
$this->x + 1 - ($east ? 0 : $inset),
|
||||
$this->y + 1.5,
|
||||
$this->z + $s
|
||||
$this->z + 1 - ($south ? 0 : $inset)
|
||||
);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class Cobweb extends Flowable{
|
||||
return Tool::TYPE_SWORD;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class CocoaBlock extends Solid{
|
||||
class CocoaBlock extends Transparent{
|
||||
|
||||
protected $id = self::COCOA_BLOCK;
|
||||
|
||||
|
78
src/pocketmine/block/ConcretePowder.php
Normal file
78
src/pocketmine/block/ConcretePowder.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?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\item\Tool;
|
||||
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 Tool::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,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\inventory\BigCraftingGrid;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\Player;
|
||||
@ -49,7 +50,7 @@ class CraftingTable extends Solid{
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->craftingType = 1;
|
||||
$player->setCraftingGrid(new BigCraftingGrid($player));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -32,7 +32,7 @@ use pocketmine\Server;
|
||||
|
||||
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){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
|
@ -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);
|
||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
@ -38,7 +41,6 @@ class DeadBush extends Flowable{
|
||||
return "Dead Bush";
|
||||
}
|
||||
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
||||
@ -51,4 +53,17 @@ class DeadBush extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_SHEARS;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isShears()){
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [
|
||||
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
}
|
@ -44,13 +44,20 @@ class Dirt extends Solid{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
if($this->meta === 1){
|
||||
return "Coarse Dirt";
|
||||
}
|
||||
return "Dirt";
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->isHoe()){
|
||||
$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;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ abstract class Door extends Transparent{
|
||||
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$f = 0.1875;
|
||||
$damage = $this->getFullDamage();
|
||||
@ -216,7 +216,7 @@ abstract class Door extends Transparent{
|
||||
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){
|
||||
$blockUp = $this->getSide(Vector3::SIDE_UP);
|
||||
$blockDown = $this->getSide(Vector3::SIDE_DOWN);
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class DoublePlant extends Flowable{
|
||||
const BITFLAG_TOP = 0x08;
|
||||
public const BITFLAG_TOP = 0x08;
|
||||
|
||||
protected $id = self::DOUBLE_PLANT;
|
||||
|
||||
@ -38,7 +38,7 @@ class DoublePlant extends Flowable{
|
||||
$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
|
||||
}
|
||||
|
||||
@ -51,10 +51,10 @@ class DoublePlant extends Flowable{
|
||||
4 => "Rose Bush",
|
||||
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();
|
||||
if(($id === Block::GRASS or $id === Block::DIRT) and $blockReplace->getSide(Vector3::SIDE_UP)->canBeReplaced()){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, false, false);
|
||||
@ -79,7 +79,7 @@ class DoublePlant extends Flowable{
|
||||
|
||||
return (
|
||||
$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)
|
||||
);
|
||||
}
|
||||
|
47
src/pocketmine/block/DoubleSlab.php
Normal file
47
src/pocketmine/block/DoubleSlab.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?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 getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -24,15 +24,14 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class DoubleStoneSlab extends Solid{
|
||||
class DoubleStoneSlab extends DoubleSlab{
|
||||
|
||||
protected $id = self::DOUBLE_STONE_SLAB;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
public function getSlabId() : int{
|
||||
return self::STONE_SLAB;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
@ -43,25 +42,9 @@ class DoubleStoneSlab extends Solid{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
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 parent::getDrops($item);
|
||||
}
|
||||
|
||||
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,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class DoubleWoodenSlab extends Solid{
|
||||
class DoubleWoodenSlab extends DoubleSlab{
|
||||
|
||||
protected $id = self::DOUBLE_WOODEN_SLAB;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
public function getSlabId() : int{
|
||||
return self::WOODEN_SLAB;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
@ -42,23 +40,4 @@ class DoubleWoodenSlab extends Solid{
|
||||
public function getToolType() : int{
|
||||
return Tool::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)
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -27,10 +27,8 @@ use pocketmine\inventory\EnchantInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\EnchantTable as TileEnchantTable;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class EnchantingTable extends Transparent{
|
||||
@ -41,26 +39,10 @@ class EnchantingTable extends Transparent{
|
||||
$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);
|
||||
$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()){
|
||||
$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);
|
||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class EndPortalFrame extends Solid{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
|
@ -40,7 +40,7 @@ class EndRod extends Flowable{
|
||||
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){
|
||||
$this->meta = $face;
|
||||
}else{
|
||||
@ -61,7 +61,7 @@ class EndRod extends Flowable{
|
||||
return 14;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$m = $this->meta & ~0x01;
|
||||
$width = 0.375;
|
||||
|
||||
|
57
src/pocketmine/block/EndStoneBricks.php
Normal file
57
src/pocketmine/block/EndStoneBricks.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?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\Tool;
|
||||
|
||||
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 Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
112
src/pocketmine/block/EnderChest.php
Normal file
112
src/pocketmine/block/EnderChest.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?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\Tool;
|
||||
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 Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
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 onBreak(Item $item, Player $player = null) : bool{
|
||||
return Block::onBreak($item, $player);
|
||||
}
|
||||
|
||||
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 getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return [ItemFactory::get(Item::OBSIDIAN, 0, 8)];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -26,41 +26,32 @@ namespace pocketmine\block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
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{
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::AIR or ($down instanceof Liquid)){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, 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())
|
||||
]));
|
||||
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class Farmland extends Transparent{
|
||||
|
||||
@ -53,7 +54,7 @@ class Farmland extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -65,8 +66,43 @@ class Farmland extends Transparent{
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
//TODO: hydration
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||
$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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -23,73 +23,87 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
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;
|
||||
abstract class Fence extends Transparent{
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
public function getThickness() : float{
|
||||
return 0.25;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$width = 0.5 - $this->getThickness() / 2;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $w,
|
||||
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||
$this->y,
|
||||
$this->z + $n,
|
||||
$this->x + $e,
|
||||
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||
$this->y + 1.5,
|
||||
$this->z + $s
|
||||
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
|
||||
);
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block instanceof Fence or $block instanceof FenceGate) ? true : $block->isSolid() and !$block->isTransparent();
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$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{
|
||||
return 300;
|
||||
public function canConnect(Block $block){
|
||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class FenceGate extends Transparent{
|
||||
}
|
||||
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return null;
|
||||
@ -69,7 +69,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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Arrow;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Arrow;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
@ -57,7 +57,7 @@ class Fire extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class Fire extends Flowable{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev);
|
||||
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
@ -33,15 +35,11 @@ abstract class Flowable extends Transparent{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
}
|
@ -29,15 +29,15 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Flower extends Flowable{
|
||||
const TYPE_POPPY = 0;
|
||||
const TYPE_BLUE_ORCHID = 1;
|
||||
const TYPE_ALLIUM = 2;
|
||||
const TYPE_AZURE_BLUET = 3;
|
||||
const TYPE_RED_TULIP = 4;
|
||||
const TYPE_ORANGE_TULIP = 5;
|
||||
const TYPE_WHITE_TULIP = 6;
|
||||
const TYPE_PINK_TULIP = 7;
|
||||
const TYPE_OXEYE_DAISY = 8;
|
||||
public const TYPE_POPPY = 0;
|
||||
public const TYPE_BLUE_ORCHID = 1;
|
||||
public const TYPE_ALLIUM = 2;
|
||||
public const TYPE_AZURE_BLUET = 3;
|
||||
public const TYPE_RED_TULIP = 4;
|
||||
public const TYPE_ORANGE_TULIP = 5;
|
||||
public const TYPE_WHITE_TULIP = 6;
|
||||
public const TYPE_PINK_TULIP = 7;
|
||||
public const TYPE_OXEYE_DAISY = 8;
|
||||
|
||||
protected $id = self::RED_FLOWER;
|
||||
|
||||
@ -60,7 +60,7 @@ class Flower extends Flowable{
|
||||
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);
|
||||
if($down->getId() === Block::GRASS or $down->getId() === Block::DIRT or $down->getId() === Block::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
|
@ -24,22 +24,17 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
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\tile\FlowerPot as TileFlowerPot;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class FlowerPot extends Flowable{
|
||||
|
||||
const STATE_EMPTY = 0;
|
||||
const STATE_FULL = 1;
|
||||
public const STATE_EMPTY = 0;
|
||||
public const STATE_FULL = 1;
|
||||
|
||||
protected $id = self::FLOWER_POT_BLOCK;
|
||||
protected $itemId = Item::FLOWER_POT;
|
||||
@ -49,10 +44,10 @@ class FlowerPot extends Flowable{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Flower Pot Block";
|
||||
return "Flower Pot";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.3125,
|
||||
$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()){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
$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);
|
||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -112,14 +91,8 @@ 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->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;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class GlazedTerracotta extends Solid{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
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($player !== null){
|
||||
$faces = [
|
||||
0 => 4,
|
||||
|
@ -76,22 +76,22 @@ class Grass extends Solid{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}elseif($lightAbove >= 9){
|
||||
//try grass spread
|
||||
$vector = $this->asVector3();
|
||||
for($i = 0; $i < 4; ++$i){
|
||||
$vector->x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$vector->y = mt_rand($this->y - 3, $this->y + 1);
|
||||
$vector->z = mt_rand($this->z - 1, $this->z + 1);
|
||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$y = mt_rand($this->y - 3, $this->y + 1);
|
||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||
if(
|
||||
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or
|
||||
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or
|
||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3
|
||||
$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
|
||||
$this->level->getBlockDataAt($x, $y, $z) === 1 or
|
||||
$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
|
||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
|
||||
){
|
||||
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()){
|
||||
$this->level->setBlock($vector, $ev->getNewState(), false, false);
|
||||
$this->level->setBlock($b, $ev->getNewState(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,9 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class GrassPath extends Transparent{
|
||||
|
||||
@ -44,7 +46,7 @@ class GrassPath extends Transparent{
|
||||
return Tool::TYPE_SHOVEL;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -59,6 +61,15 @@ class GrassPath extends Transparent{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
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 getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get(Item::DIRT, 0, 1)
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
@ -43,17 +44,8 @@ class HayBale extends Solid{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
$faces = [
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
2 => 0b1000,
|
||||
3 => 0b1000,
|
||||
4 => 0b0100,
|
||||
5 => 0b0100
|
||||
];
|
||||
|
||||
$this->meta = ($this->meta & 0x03) | $faces[$face];
|
||||
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->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
|
@ -37,7 +37,7 @@ class IronDoor extends Door{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Iron Door Block";
|
||||
return "Iron Door";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -24,12 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\{
|
||||
ByteTag, CompoundTag, FloatTag, IntTag, StringTag
|
||||
};
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\tile\Tile;
|
||||
@ -50,52 +46,25 @@ class ItemFrame extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$tile = $this->level->getTile($this);
|
||||
if(!($tile instanceof TileItemFrame)){
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::ITEM_FRAME),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z),
|
||||
new FloatTag("ItemDropChance", 1.0),
|
||||
new ByteTag("ItemRotation", 0)
|
||||
]);
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
|
||||
}
|
||||
|
||||
if($tile->hasItem()){
|
||||
$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
|
||||
}else{
|
||||
if($item->getCount() > 0){
|
||||
$frameItem = clone $item;
|
||||
$frameItem->setCount(1);
|
||||
$item->setCount($item->getCount() - 1);
|
||||
$tile->setItem($frameItem);
|
||||
if($player instanceof Player and $player->isSurvival()){
|
||||
$player->getInventory()->setItemInHand($item->getCount() <= 0 ? ItemFactory::get(Item::AIR) : $item);
|
||||
}
|
||||
}
|
||||
}elseif(!$item->isNull()){
|
||||
$tile->setItem($item->pop());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
$tile = $this->level->getTile($this);
|
||||
if($tile instanceof TileItemFrame){
|
||||
//TODO: add events
|
||||
if(lcg_value() <= $tile->getItemDropChance() and $tile->getItem()->getId() !== Item::AIR){
|
||||
$this->level->dropItem($tile->getBlock(), $tile->getItem());
|
||||
}
|
||||
}
|
||||
return parent::onBreak($item, $player);
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$sides = [
|
||||
0 => 4,
|
||||
1 => 5,
|
||||
2 => 2,
|
||||
3 => 3
|
||||
0 => Vector3::SIDE_WEST,
|
||||
1 => Vector3::SIDE_EAST,
|
||||
2 => Vector3::SIDE_NORTH,
|
||||
3 => Vector3::SIDE_SOUTH
|
||||
];
|
||||
if(!$this->getSide($sides[$this->meta])->isSolid()){
|
||||
$this->level->useBreakOn($this);
|
||||
@ -105,8 +74,8 @@ class ItemFrame extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
if($face === Vector3::SIDE_DOWN or $face === Vector3::SIDE_UP){
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if($face === Vector3::SIDE_DOWN or $face === Vector3::SIDE_UP or !$blockClicked->isSolid()){
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -120,22 +89,7 @@ class ItemFrame extends Flowable{
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::ITEM_FRAME),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z),
|
||||
new FloatTag("ItemDropChance", 1.0),
|
||||
new ByteTag("ItemRotation", 0)
|
||||
]);
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
|
||||
@ -144,4 +98,18 @@ class ItemFrame extends Flowable{
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$drops = parent::getDrops($item);
|
||||
|
||||
$tile = $this->level->getTile($this);
|
||||
if($tile instanceof TileItemFrame){
|
||||
$tileItem = $tile->getItem();
|
||||
if(lcg_value() <= $tile->getItemDropChance() and !$tileItem->isNull()){
|
||||
$drops[] = $tileItem;
|
||||
}
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
}
|
@ -59,58 +59,39 @@ class Ladder extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$f = 0.1875;
|
||||
|
||||
$minX = $minZ = 0;
|
||||
$maxX = $maxZ = 1;
|
||||
|
||||
if($this->meta === 2){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$minZ = 1 - $f;
|
||||
}elseif($this->meta === 3){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + $f
|
||||
);
|
||||
$maxZ = $f;
|
||||
}elseif($this->meta === 4){
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$minX = 1 - $f;
|
||||
}elseif($this->meta === 5){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + $f,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$maxX = $f;
|
||||
}
|
||||
|
||||
return null;
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $minX,
|
||||
$this->y,
|
||||
$this->z + $minZ,
|
||||
$this->x + $maxX,
|
||||
$this->y + 1,
|
||||
$this->z + $maxZ
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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($blockClicked->isTransparent() === false){
|
||||
$faces = [
|
||||
2 => 2,
|
||||
@ -131,13 +112,7 @@ class Ladder extends Transparent{
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$sides = [
|
||||
2 => 3,
|
||||
3 => 2,
|
||||
4 => 5,
|
||||
5 => 4
|
||||
];
|
||||
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
|
||||
if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
|
||||
$this->level->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -48,7 +48,42 @@ class Lava extends Liquid{
|
||||
return "Lava";
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function tickRate() : int{
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getFlowDecayPerBlock() : int{
|
||||
return 2; //TODO: this is 1 in the nether
|
||||
}
|
||||
|
||||
protected function checkForHarden(){
|
||||
$colliding = null;
|
||||
for($side = 1; $side <= 5; ++$side){ //don't check downwards side
|
||||
$blockSide = $this->getSide($side);
|
||||
if($blockSide instanceof Water){
|
||||
$colliding = $blockSide;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($colliding !== null){
|
||||
if($this->getDamage() === 0){
|
||||
$this->liquidCollide($colliding, BlockFactory::get(Block::OBSIDIAN));
|
||||
}elseif($this->getDamage() <= 4){
|
||||
$this->liquidCollide($colliding, BlockFactory::get(Block::COBBLESTONE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
|
||||
if($block instanceof Water){
|
||||
$block->liquidCollide($this, BlockFactory::get(Block::STONE));
|
||||
}else{
|
||||
parent::flowIntoBlock($block, $newFlowDecay);
|
||||
}
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->fallDistance *= 0.5;
|
||||
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
@ -63,7 +98,7 @@ class Lava extends Liquid{
|
||||
$entity->resetFallDistance();
|
||||
}
|
||||
|
||||
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{
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
|
||||
|
@ -32,12 +32,12 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Leaves extends Transparent{
|
||||
const OAK = 0;
|
||||
const SPRUCE = 1;
|
||||
const BIRCH = 2;
|
||||
const JUNGLE = 3;
|
||||
const ACACIA = 0;
|
||||
const DARK_OAK = 1;
|
||||
public const OAK = 0;
|
||||
public const SPRUCE = 1;
|
||||
public const BIRCH = 2;
|
||||
public const JUNGLE = 3;
|
||||
public const ACACIA = 0;
|
||||
public const DARK_OAK = 1;
|
||||
|
||||
protected $id = self::LEAVES;
|
||||
protected $woodType = self::WOOD;
|
||||
@ -61,7 +61,7 @@ class Leaves extends Transparent{
|
||||
self::BIRCH => "Birch Leaves",
|
||||
self::JUNGLE => "Jungle Leaves"
|
||||
];
|
||||
return $names[$this->meta & 0x03];
|
||||
return $names[$this->getVariant()];
|
||||
}
|
||||
|
||||
public function diffusesSkyLight() : bool{
|
||||
@ -164,27 +164,36 @@ class Leaves extends Transparent{
|
||||
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{
|
||||
$this->meta |= 0x04;
|
||||
return $this->getLevel()->setBlock($this, $this, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x03;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$drops = [];
|
||||
|
||||
$variantMeta = $this->getDamage() & 0x03;
|
||||
|
||||
if($item->isShears()){
|
||||
$drops[] = ItemFactory::get($this->getItemId(), $variantMeta, 1);
|
||||
}else{
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$drops[] = ItemFactory::get(Item::SAPLING, $variantMeta, 1);
|
||||
}
|
||||
if($variantMeta === self::OAK and mt_rand(1, 200) === 1){ //Apples
|
||||
$drops[] = ItemFactory::get(Item::APPLE, 0, 1);
|
||||
}
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
$drops = [];
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$drops[] = $this->getSaplingItem();
|
||||
}
|
||||
if($this->canDropApples() and mt_rand(1, 200) === 1){ //Apples
|
||||
$drops[] = ItemFactory::get(Item::APPLE, 0, 1);
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
|
||||
public function getSaplingItem() : Item{
|
||||
return ItemFactory::get(Item::SAPLING, $this->getVariant());
|
||||
}
|
||||
|
||||
public function canDropApples() : bool{
|
||||
return $this->meta === self::OAK;
|
||||
}
|
||||
}
|
@ -36,22 +36,14 @@ class Leaves2 extends Leaves{
|
||||
self::ACACIA => "Acacia Leaves",
|
||||
self::DARK_OAK => "Dark Oak Leaves"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$variantMeta = $this->getDamage() & 0x03;
|
||||
public function getSaplingItem() : Item{
|
||||
return ItemFactory::get(Item::SAPLING, $this->getVariant() + 4);
|
||||
}
|
||||
|
||||
if($item->isShears()){
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $variantMeta, 1)
|
||||
];
|
||||
}elseif(mt_rand(1, 20) === 1){ //Saplings
|
||||
return [
|
||||
ItemFactory::get(Item::SAPLING, $variantMeta + 4, 1)
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
public function canDropApples() : bool{
|
||||
return $this->meta === self::DARK_OAK;
|
||||
}
|
||||
}
|
@ -26,12 +26,23 @@ namespace pocketmine\block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
|
||||
abstract class Liquid extends Transparent{
|
||||
|
||||
/** @var Vector3 */
|
||||
private $temporalVector = null;
|
||||
public $adjacentSources = 0;
|
||||
|
||||
/** @var Vector3|null */
|
||||
protected $flowVector = null;
|
||||
|
||||
/** @var int[] */
|
||||
private $flowCostVisited = [];
|
||||
|
||||
private const CAN_FLOW_DOWN = 1;
|
||||
private const CAN_FLOW = 0;
|
||||
private const BLOCKED = -1;
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
@ -41,7 +52,11 @@ abstract class Liquid extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -49,9 +64,17 @@ abstract class Liquid extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public $adjacentSources = 0;
|
||||
public $isOptimalFlowDirection = [0, 0, 0, 0];
|
||||
public $flowCost = [0, 0, 0, 0];
|
||||
public function getHardness() : float{
|
||||
return 100;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getFluidHeightPercent(){
|
||||
$d = $this->meta;
|
||||
@ -62,28 +85,20 @@ abstract class Liquid extends Transparent{
|
||||
return ($d + 1) / 9;
|
||||
}
|
||||
|
||||
protected function getFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
protected function getFlowDecay(Block $block) : int{
|
||||
if($block->getId() !== $this->getId()){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if($pos->getId() !== $this->getId()){
|
||||
return -1;
|
||||
}else{
|
||||
return $pos->getDamage();
|
||||
}
|
||||
return $block->getDamage();
|
||||
}
|
||||
|
||||
protected function getEffectiveFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
}
|
||||
|
||||
if($pos->getId() !== $this->getId()){
|
||||
protected function getEffectiveFlowDecay(Block $block) : int{
|
||||
if($block->getId() !== $this->getId()){
|
||||
return -1;
|
||||
}
|
||||
|
||||
$decay = $pos->getDamage();
|
||||
$decay = $block->getDamage();
|
||||
|
||||
if($decay >= 8){
|
||||
$decay = 0;
|
||||
@ -92,13 +107,18 @@ abstract class Liquid extends Transparent{
|
||||
return $decay;
|
||||
}
|
||||
|
||||
public function getFlowVector(){
|
||||
$vector = new Vector3(0, 0, 0);
|
||||
public function clearCaches() : void{
|
||||
parent::clearCaches();
|
||||
$this->flowVector = null;
|
||||
}
|
||||
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
public function getFlowVector() : Vector3{
|
||||
if($this->flowVector !== null){
|
||||
return $this->flowVector;
|
||||
}
|
||||
|
||||
$vector = new Vector3(0, 0, 0);
|
||||
|
||||
$decay = $this->getEffectiveFlowDecay($this);
|
||||
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
@ -116,7 +136,7 @@ abstract class Liquid extends Transparent{
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
$sideBlock = $this->level->getBlockAt($x, $y, $z);
|
||||
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||
|
||||
if($blockDecay < 0){
|
||||
@ -124,7 +144,7 @@ abstract class Liquid extends Transparent{
|
||||
continue;
|
||||
}
|
||||
|
||||
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
|
||||
$blockDecay = $this->getEffectiveFlowDecay($this->level->getBlockAt($x, $y - 1, $z));
|
||||
|
||||
if($blockDecay >= 0){
|
||||
$realDecay = $blockDecay - ($decay - 8);
|
||||
@ -143,235 +163,211 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
if($this->getDamage() >= 8){
|
||||
$falling = false;
|
||||
|
||||
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}
|
||||
|
||||
if($falling){
|
||||
if(
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z - 1)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y, $this->z + 1)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x - 1, $this->y, $this->z)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x + 1, $this->y, $this->z)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y + 1, $this->z - 1)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x, $this->y + 1, $this->z + 1)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x - 1, $this->y + 1, $this->z)) or
|
||||
!$this->canFlowInto($this->level->getBlockAt($this->x + 1, $this->y + 1, $this->z))
|
||||
){
|
||||
$vector = $vector->normalize()->add(0, -6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $vector->normalize();
|
||||
return $this->flowVector = $vector->normalize();
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||
$flow = $this->getFlowVector();
|
||||
$vector->x += $flow->x;
|
||||
$vector->y += $flow->y;
|
||||
$vector->z += $flow->z;
|
||||
}
|
||||
|
||||
public function tickRate(){
|
||||
if($this instanceof Water){
|
||||
return 5;
|
||||
}elseif($this instanceof Lava){
|
||||
return 30;
|
||||
}
|
||||
abstract public function tickRate() : int;
|
||||
|
||||
return 0;
|
||||
/**
|
||||
* Returns how many liquid levels are lost per block flowed horizontally. Affects how far the liquid can flow.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFlowDecayPerBlock() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$this->checkForHarden();
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
$this->level->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
|
||||
return $type;
|
||||
}elseif($type === Level::BLOCK_UPDATE_SCHEDULED){
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
$decay = $this->getFlowDecay($this);
|
||||
$multiplier = $this instanceof Lava ? 2 : 1;
|
||||
|
||||
$flag = true;
|
||||
$multiplier = $this->getFlowDecayPerBlock();
|
||||
|
||||
if($decay > 0){
|
||||
$smallestFlowDecay = -100;
|
||||
$this->adjacentSources = 0;
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);
|
||||
|
||||
$k = $smallestFlowDecay + $multiplier;
|
||||
$newDecay = $smallestFlowDecay + $multiplier;
|
||||
|
||||
if($k >= 8 or $smallestFlowDecay < 0){
|
||||
$k = -1;
|
||||
if($newDecay >= 8 or $smallestFlowDecay < 0){
|
||||
$newDecay = -1;
|
||||
}
|
||||
|
||||
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z)))) >= 0){
|
||||
if($topFlowDecay >= 8){
|
||||
$k = $topFlowDecay;
|
||||
}else{
|
||||
$k = $topFlowDecay | 0x08;
|
||||
}
|
||||
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
|
||||
$newDecay = $topFlowDecay | 0x08;
|
||||
}
|
||||
|
||||
if($this->adjacentSources >= 2 and $this instanceof Water){
|
||||
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
|
||||
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
|
||||
if($bottomBlock->isSolid()){
|
||||
$k = 0;
|
||||
$newDecay = 0;
|
||||
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
|
||||
$k = 0;
|
||||
$newDecay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if($this instanceof Lava and $decay < 8 and $k < 8 and $k > 1 and mt_rand(0, 4) !== 0){
|
||||
$k = $decay;
|
||||
$flag = false;
|
||||
}
|
||||
|
||||
if($k !== $decay){
|
||||
$decay = $k;
|
||||
if($newDecay !== $decay){
|
||||
$decay = $newDecay;
|
||||
if($decay < 0){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get($this->id, $decay), true, true);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
$this->level->setBlock($this, BlockFactory::get($this->id, $decay), true, true);
|
||||
$this->level->scheduleDelayedBlockUpdate($this, $this->tickRate());
|
||||
}
|
||||
}elseif($flag){
|
||||
//$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
//$this->updateFlow();
|
||||
}
|
||||
}else{
|
||||
//$this->updateFlow();
|
||||
}
|
||||
|
||||
if($decay >= 0){
|
||||
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
|
||||
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
|
||||
|
||||
if($this instanceof Lava and $bottomBlock instanceof Water){
|
||||
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
|
||||
|
||||
}elseif($bottomBlock->canBeFlowedInto() or ($bottomBlock instanceof Liquid and ($bottomBlock->getDamage() & 0x07) !== 0)){
|
||||
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get($this->id, $decay | 0x08), true, false);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($bottomBlock, $this->tickRate());
|
||||
|
||||
}elseif($decay === 0 or !$bottomBlock->canBeFlowedInto()){
|
||||
$flags = $this->getOptimalFlowDirections();
|
||||
|
||||
$l = $decay + $multiplier;
|
||||
$this->flowIntoBlock($bottomBlock, $decay | 0x08);
|
||||
|
||||
if($decay === 0 or !$bottomBlock->canBeFlowedInto()){
|
||||
if($decay >= 8){
|
||||
$l = 1;
|
||||
$adjacentDecay = 1;
|
||||
}else{
|
||||
$adjacentDecay = $decay + $multiplier;
|
||||
}
|
||||
|
||||
if($l >= 8){
|
||||
$this->checkForHarden();
|
||||
if($adjacentDecay < 8){
|
||||
$flags = $this->getOptimalFlowDirections();
|
||||
|
||||
return;
|
||||
}
|
||||
if($flags[0]){
|
||||
$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $adjacentDecay);
|
||||
}
|
||||
|
||||
if($flags[0]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
|
||||
}
|
||||
if($flags[1]){
|
||||
$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $adjacentDecay);
|
||||
}
|
||||
|
||||
if($flags[1]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
|
||||
}
|
||||
if($flags[2]){
|
||||
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $adjacentDecay);
|
||||
}
|
||||
|
||||
if($flags[2]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
|
||||
}
|
||||
|
||||
if($flags[3]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
|
||||
if($flags[3]){
|
||||
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $adjacentDecay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->checkForHarden();
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function flowIntoBlock(Block $block, $newFlowDecay){
|
||||
if($block->canBeFlowedInto()){
|
||||
protected function flowIntoBlock(Block $block, int $newFlowDecay) : void{
|
||||
if($this->canFlowInto($block) and !($block instanceof Liquid)){
|
||||
if($block->getId() > 0){
|
||||
$this->getLevel()->useBreakOn($block);
|
||||
$this->level->useBreakOn($block);
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($block, BlockFactory::get($this->getId(), $newFlowDecay), true, false);
|
||||
$this->getLevel()->scheduleDelayedBlockUpdate($block, $this->tickRate());
|
||||
$this->level->setBlock($block, BlockFactory::get($this->getId(), $newFlowDecay), true, true);
|
||||
$this->level->scheduleDelayedBlockUpdate($block, $this->tickRate());
|
||||
}
|
||||
}
|
||||
|
||||
private function calculateFlowCost(Block $block, $accumulatedCost, $previousDirection){
|
||||
private function calculateFlowCost(int $blockX, int $blockY, int $blockZ, int $accumulatedCost, int $maxCost, int $originOpposite, int $lastOpposite) : int{
|
||||
$cost = 1000;
|
||||
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
if(
|
||||
($j === 0 and $previousDirection === 1) or
|
||||
($j === 1 and $previousDirection === 0) or
|
||||
($j === 2 and $previousDirection === 3) or
|
||||
($j === 3 and $previousDirection === 2)
|
||||
){
|
||||
$x = $block->x;
|
||||
$y = $block->y;
|
||||
$z = $block->z;
|
||||
if($j === $originOpposite or $j === $lastOpposite){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($j === 0){
|
||||
--$x;
|
||||
}elseif($j === 1){
|
||||
++$x;
|
||||
}elseif($j === 2){
|
||||
--$z;
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
$x = $blockX;
|
||||
$y = $blockY;
|
||||
$z = $blockZ;
|
||||
|
||||
if($j === 0){
|
||||
--$x;
|
||||
}elseif($j === 1){
|
||||
++$x;
|
||||
}elseif($j === 2){
|
||||
--$z;
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
|
||||
if(!isset($this->flowCostVisited[$hash = Level::blockHash($x, $y, $z)])){
|
||||
$blockSide = $this->level->getBlockAt($x, $y, $z);
|
||||
if(!$this->canFlowInto($blockSide)){
|
||||
$this->flowCostVisited[$hash] = self::BLOCKED;
|
||||
}elseif($this->level->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
|
||||
$this->flowCostVisited[$hash] = self::CAN_FLOW_DOWN;
|
||||
}else{
|
||||
$this->flowCostVisited[$hash] = self::CAN_FLOW;
|
||||
}
|
||||
$blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
}
|
||||
|
||||
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
|
||||
continue;
|
||||
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
||||
continue;
|
||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
||||
return $accumulatedCost;
|
||||
}
|
||||
$status = $this->flowCostVisited[$hash];
|
||||
|
||||
if($accumulatedCost >= 4){
|
||||
continue;
|
||||
}
|
||||
if($status === self::BLOCKED){
|
||||
continue;
|
||||
}elseif($status === self::CAN_FLOW_DOWN){
|
||||
return $accumulatedCost;
|
||||
}
|
||||
|
||||
$realCost = $this->calculateFlowCost($blockSide, $accumulatedCost + 1, $j);
|
||||
if($accumulatedCost >= $maxCost){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($realCost < $cost){
|
||||
$cost = $realCost;
|
||||
}
|
||||
$realCost = $this->calculateFlowCost($x, $y, $z, $accumulatedCost + 1, $maxCost, $originOpposite, $j ^ 0x01);
|
||||
|
||||
if($realCost < $cost){
|
||||
$cost = $realCost;
|
||||
}
|
||||
}
|
||||
|
||||
return $cost;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getOptimalFlowDirections(){
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool[]
|
||||
*/
|
||||
private function getOptimalFlowDirections() : array{
|
||||
$flowCost = array_fill(0, 4, 1000);
|
||||
$maxCost = 4 / $this->getFlowDecayPerBlock();
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
$this->flowCost[$j] = 1000;
|
||||
|
||||
$x = $this->x;
|
||||
$y = $this->y;
|
||||
$z = $this->z;
|
||||
@ -385,36 +381,36 @@ abstract class Liquid extends Transparent{
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
$block = $this->level->getBlockAt($x, $y, $z);
|
||||
|
||||
if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
|
||||
if(!$this->canFlowInto($block)){
|
||||
$this->flowCostVisited[Level::blockHash($x, $y, $z)] = self::BLOCKED;
|
||||
continue;
|
||||
}elseif($block instanceof Liquid and $block->getDamage() === 0){
|
||||
continue;
|
||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
||||
$this->flowCost[$j] = 0;
|
||||
}else{
|
||||
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
|
||||
}elseif($this->level->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
|
||||
$this->flowCostVisited[Level::blockHash($x, $y, $z)] = self::CAN_FLOW_DOWN;
|
||||
$flowCost[$j] = $maxCost = 0;
|
||||
}elseif($maxCost > 0){
|
||||
$this->flowCostVisited[Level::blockHash($x, $y, $z)] = self::CAN_FLOW;
|
||||
$flowCost[$j] = $this->calculateFlowCost($x, $y, $z, 1, $maxCost, $j ^ 0x01, $j ^ 0x01);
|
||||
$maxCost = min($maxCost, $flowCost[$j]);
|
||||
}
|
||||
}
|
||||
|
||||
$minCost = $this->flowCost[0];
|
||||
$this->flowCostVisited = [];
|
||||
|
||||
for($i = 1; $i < 4; ++$i){
|
||||
if($this->flowCost[$i] < $minCost){
|
||||
$minCost = $this->flowCost[$i];
|
||||
}
|
||||
}
|
||||
$minCost = min($flowCost);
|
||||
|
||||
$isOptimalFlowDirection = [];
|
||||
|
||||
for($i = 0; $i < 4; ++$i){
|
||||
$this->isOptimalFlowDirection[$i] = ($this->flowCost[$i] === $minCost);
|
||||
$isOptimalFlowDirection[$i] = ($flowCost[$i] === $minCost);
|
||||
}
|
||||
|
||||
return $this->isOptimalFlowDirection;
|
||||
return $isOptimalFlowDirection;
|
||||
}
|
||||
|
||||
private function getSmallestFlowDecay(Vector3 $pos, $decay){
|
||||
$blockDecay = $this->getFlowDecay($pos);
|
||||
private function getSmallestFlowDecay(Block $block, int $decay) : int{
|
||||
$blockDecay = $this->getFlowDecay($block);
|
||||
|
||||
if($blockDecay < 0){
|
||||
return $decay;
|
||||
@ -427,28 +423,19 @@ abstract class Liquid extends Transparent{
|
||||
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
|
||||
}
|
||||
|
||||
private function checkForHarden(){
|
||||
if($this instanceof Lava){
|
||||
$colliding = false;
|
||||
for($side = 0; $side <= 5 and !$colliding; ++$side){
|
||||
$colliding = $this->getSide($side) instanceof Water;
|
||||
}
|
||||
protected function checkForHarden(){
|
||||
|
||||
if($colliding){
|
||||
if($this->getDamage() === 0){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::OBSIDIAN), true, true);
|
||||
}elseif($this->getDamage() <= 4){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::COBBLESTONE), true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
return null;
|
||||
protected function liquidCollide(Block $cause, Block $result) : bool{
|
||||
//TODO: add events
|
||||
|
||||
$this->level->setBlock($this, $result, true, true);
|
||||
$this->level->broadcastLevelSoundEvent($this->add(0.5, 0.5, 0.5), LevelSoundEventPacket::SOUND_FIZZ, (int) ((2.6 + (lcg_value() - lcg_value()) * 0.8) * 1000));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [];
|
||||
protected function canFlowInto(Block $block) : bool{
|
||||
return $block->canBeFlowedInto() and !($block instanceof Liquid and $block->meta === 0); //TODO: I think this should only be liquids of the same type
|
||||
}
|
||||
}
|
@ -57,7 +57,7 @@ class Magma extends Solid{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
if(!$entity->isSneaking()){
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev);
|
||||
|
@ -88,4 +88,8 @@ class MelonStem extends Crops{
|
||||
ItemFactory::get(Item::MELON_SEEDS, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::MELON_SEEDS);
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class MonsterSpawner extends Solid{
|
||||
class MonsterSpawner extends Transparent{
|
||||
|
||||
protected $id = self::MONSTER_SPAWNER;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Mycelium extends Solid{
|
||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||
if($block->getId() === Block::DIRT){
|
||||
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)));
|
||||
|
@ -26,14 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class NetherBrickFence extends Transparent{
|
||||
class NetherBrickFence extends Fence{
|
||||
|
||||
protected $id = self::NETHER_BRICK_FENCE;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
}
|
||||
@ -46,10 +42,6 @@ class NetherBrickFence extends Transparent{
|
||||
return "Nether Brick Fence";
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block instanceof NetherBrickFence) or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item);
|
||||
@ -57,6 +49,4 @@ class NetherBrickFence extends Transparent{
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
//TODO: fix bounding boxes
|
||||
}
|
||||
|
@ -40,11 +40,15 @@ class NetherWartPlant extends Flowable{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Nether Wart";
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
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{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === Block::SOUL_SAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, false, true);
|
||||
|
@ -26,12 +26,12 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class Planks extends Solid{
|
||||
const OAK = 0;
|
||||
const SPRUCE = 1;
|
||||
const BIRCH = 2;
|
||||
const JUNGLE = 3;
|
||||
const ACACIA = 4;
|
||||
const DARK_OAK = 5;
|
||||
public const OAK = 0;
|
||||
public const SPRUCE = 1;
|
||||
public const BIRCH = 2;
|
||||
public const JUNGLE = 3;
|
||||
public const ACACIA = 4;
|
||||
public const DARK_OAK = 5;
|
||||
|
||||
protected $id = self::WOODEN_PLANKS;
|
||||
|
||||
@ -56,7 +56,7 @@ class Planks extends Solid{
|
||||
self::ACACIA => "Acacia Wood Planks",
|
||||
self::DARK_OAK => "Dark Oak Wood Planks"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -43,4 +43,8 @@ class Potato extends Crops{
|
||||
ItemFactory::get(Item::POTATO, 0, $this->getDamage() >= 0x07 ? mt_rand(1, 4) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::POTATO);
|
||||
}
|
||||
}
|
@ -28,9 +28,9 @@ use pocketmine\item\Tool;
|
||||
|
||||
class Prismarine extends Solid{
|
||||
|
||||
const NORMAL = 0;
|
||||
const DARK = 1;
|
||||
const BRICKS = 2;
|
||||
public const NORMAL = 0;
|
||||
public const DARK = 1;
|
||||
public const BRICKS = 2;
|
||||
|
||||
protected $id = self::PRISMARINE;
|
||||
|
||||
@ -48,7 +48,7 @@ class Prismarine extends Solid{
|
||||
self::DARK => "Dark Prismarine",
|
||||
self::BRICKS => "Prismarine Bricks"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -48,7 +48,7 @@ class Pumpkin extends Solid{
|
||||
return "Pumpkin";
|
||||
}
|
||||
|
||||
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($player instanceof Player){
|
||||
$this->meta = ((int) $player->getDirection() + 1) % 4;
|
||||
}
|
||||
|
@ -88,4 +88,8 @@ class PumpkinStem extends Crops{
|
||||
ItemFactory::get(Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
|
||||
public function getPickedItem() : Item{
|
||||
return ItemFactory::get(Item::PUMPKIN_SEEDS);
|
||||
}
|
||||
}
|
@ -21,34 +21,27 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
class Purpur extends Quartz{
|
||||
|
||||
interface Transaction{
|
||||
protected $id = self::PURPUR_BLOCK;
|
||||
|
||||
/**
|
||||
* @return Inventory
|
||||
*/
|
||||
public function getInventory() : Inventory;
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::NORMAL => "Purpur Block",
|
||||
self::CHISELED => "Chiseled Purpur", //wtf?
|
||||
self::PILLAR => "Purpur Pillar"
|
||||
];
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSlot() : int;
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getSourceItem() : Item;
|
||||
public function getHardness() : float{
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getTargetItem() : Item;
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getCreationTime() : float;
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
}
|
@ -21,18 +21,31 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class PurpurStairs extends Stair{
|
||||
|
||||
protected $id = self::PURPUR_STAIRS;
|
||||
|
||||
class WoodenDoor extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::WOODEN_DOOR_BLOCK);
|
||||
parent::__construct(self::WOODEN_DOOR, $meta, "Wooden Door");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
public function getName() : string{
|
||||
return "Purpur Stairs";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
}
|
@ -31,9 +31,9 @@ use pocketmine\Player;
|
||||
|
||||
class Quartz extends Solid{
|
||||
|
||||
const QUARTZ_NORMAL = 0;
|
||||
const QUARTZ_CHISELED = 1;
|
||||
const QUARTZ_PILLAR = 2;
|
||||
public const NORMAL = 0;
|
||||
public const CHISELED = 1;
|
||||
public const PILLAR = 2;
|
||||
|
||||
protected $id = self::QUARTZ_BLOCK;
|
||||
|
||||
@ -47,15 +47,15 @@ class Quartz extends Solid{
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::QUARTZ_NORMAL => "Quartz Block",
|
||||
self::QUARTZ_CHISELED => "Chiseled Quartz Block",
|
||||
self::QUARTZ_PILLAR => "Quartz Pillar"
|
||||
self::NORMAL => "Quartz Block",
|
||||
self::CHISELED => "Chiseled Quartz Block",
|
||||
self::PILLAR => "Quartz Pillar"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
if($this->meta !== self::QUARTZ_NORMAL){
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if($this->meta !== self::NORMAL){
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
}
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
@ -30,16 +30,16 @@ use pocketmine\Player;
|
||||
|
||||
class Rail extends Flowable{
|
||||
|
||||
const STRAIGHT_NORTH_SOUTH = 0;
|
||||
const STRAIGHT_EAST_WEST = 1;
|
||||
const ASCENDING_EAST = 2;
|
||||
const ASCENDING_WEST = 3;
|
||||
const ASCENDING_NORTH = 4;
|
||||
const ASCENDING_SOUTH = 5;
|
||||
const CURVE_SOUTHEAST = 6;
|
||||
const CURVE_SOUTHWEST = 7;
|
||||
const CURVE_NORTHWEST = 8;
|
||||
const CURVE_NORTHEAST = 9;
|
||||
public const STRAIGHT_NORTH_SOUTH = 0;
|
||||
public const STRAIGHT_EAST_WEST = 1;
|
||||
public const ASCENDING_EAST = 2;
|
||||
public const ASCENDING_WEST = 3;
|
||||
public const ASCENDING_NORTH = 4;
|
||||
public const ASCENDING_SOUTH = 5;
|
||||
public const CURVE_SOUTHEAST = 6;
|
||||
public const CURVE_SOUTHWEST = 7;
|
||||
public const CURVE_NORTHWEST = 8;
|
||||
public const CURVE_NORTHEAST = 9;
|
||||
|
||||
protected $id = self::RAIL;
|
||||
|
||||
@ -55,7 +55,7 @@ class Rail extends Flowable{
|
||||
return 0.7;
|
||||
}
|
||||
|
||||
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)->isTransparent()){
|
||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class RedMushroom extends Flowable{
|
||||
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);
|
||||
if($down->isTransparent() === false){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
55
src/pocketmine/block/RedMushroomBlock.php
Normal file
55
src/pocketmine/block/RedMushroomBlock.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class RedMushroomBlock extends Solid{
|
||||
|
||||
protected $id = Block::RED_MUSHROOM_BLOCK;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Red Mushroom Block";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0.2;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
Item::get(Item::RED_MUSHROOM, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -21,14 +21,17 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
class RedSandstone extends Sandstone{
|
||||
protected $id = self::RED_SANDSTONE;
|
||||
|
||||
class ItemFrame extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::ITEM_FRAME_BLOCK);
|
||||
parent::__construct(self::ITEM_FRAME, $meta, "Item Frame");
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::NORMAL => "Red Sandstone",
|
||||
self::CHISELED => "Chiseled Red Sandstone",
|
||||
self::SMOOTH => "Smooth Red Sandstone"
|
||||
];
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
}
|
34
src/pocketmine/block/RedSandstoneStairs.php
Normal file
34
src/pocketmine/block/RedSandstoneStairs.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 RedSandstoneStairs extends SandstoneStairs{
|
||||
|
||||
protected $id = self::RED_SANDSTONE_STAIRS;
|
||||
|
||||
public function getName() : string{
|
||||
return "Red " . parent::getName();
|
||||
}
|
||||
|
||||
}
|
@ -46,7 +46,7 @@ class RedstoneOre extends Solid{
|
||||
return 3;
|
||||
}
|
||||
|
||||
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, false);
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,9 @@ use pocketmine\item\Tool;
|
||||
|
||||
class Sandstone extends Solid{
|
||||
|
||||
const NORMAL = 0;
|
||||
const CHISELED = 1;
|
||||
const SMOOTH = 2;
|
||||
public const NORMAL = 0;
|
||||
public const CHISELED = 1;
|
||||
public const SMOOTH = 2;
|
||||
|
||||
protected $id = self::SANDSTONE;
|
||||
|
||||
@ -48,7 +48,7 @@ class Sandstone extends Solid{
|
||||
self::CHISELED => "Chiseled Sandstone",
|
||||
self::SMOOTH => "Smooth Sandstone"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\generator\object\Tree;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -32,12 +31,12 @@ use pocketmine\Player;
|
||||
use pocketmine\utils\Random;
|
||||
|
||||
class Sapling extends Flowable{
|
||||
const OAK = 0;
|
||||
const SPRUCE = 1;
|
||||
const BIRCH = 2;
|
||||
const JUNGLE = 3;
|
||||
const ACACIA = 4;
|
||||
const DARK_OAK = 5;
|
||||
public const OAK = 0;
|
||||
public const SPRUCE = 1;
|
||||
public const BIRCH = 2;
|
||||
public const JUNGLE = 3;
|
||||
public const ACACIA = 4;
|
||||
public const DARK_OAK = 5;
|
||||
|
||||
protected $id = self::SAPLING;
|
||||
|
||||
@ -54,14 +53,14 @@ class Sapling extends Flowable{
|
||||
4 => "Acacia Sapling",
|
||||
5 => "Dark Oak Sapling"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
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{
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::GRASS or $down->getId() === self::DIRT or $down->getId() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
@ -75,7 +74,7 @@ class Sapling extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
//TODO: change log type
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
|
||||
$item->count--;
|
||||
|
||||
@ -95,7 +94,7 @@ class Sapling extends Flowable{
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){ //Growth
|
||||
if(mt_rand(1, 7) === 1){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
@ -110,10 +109,8 @@ class Sapling extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x07, 1)
|
||||
];
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x07;
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -26,11 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Sign as TileSign;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class SignPost extends Transparent{
|
||||
@ -55,43 +54,23 @@ class SignPost extends Transparent{
|
||||
return "Sign Post";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
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_DOWN){
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::SIGN),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z),
|
||||
new StringTag("Text1", ""),
|
||||
new StringTag("Text2", ""),
|
||||
new StringTag("Text3", ""),
|
||||
new StringTag("Text4", "")
|
||||
]);
|
||||
|
||||
if($player !== null){
|
||||
$nbt->Creator = new StringTag("Creator", $player->getRawUniqueId());
|
||||
}
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if($face === Vector3::SIDE_UP){
|
||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
}else{
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, new WallSign($this->meta), true);
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::SIGN, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -27,13 +27,8 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
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\tile\Skull as SkullTile;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\tile\Skull as TileSkull;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class Skull extends Flowable{
|
||||
@ -49,10 +44,10 @@ class Skull extends Flowable{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Mob Head Block";
|
||||
return "Mob Head";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
//TODO: different bounds depending on attached face (meta)
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.25,
|
||||
@ -64,36 +59,21 @@ class Skull extends Flowable{
|
||||
);
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
if($face !== Vector3::SIDE_DOWN){
|
||||
$this->meta = $face;
|
||||
if($face === Vector3::SIDE_UP){
|
||||
$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
|
||||
}else{
|
||||
$rot = $face;
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::SKULL),
|
||||
new ByteTag("SkullType", $item->getDamage()),
|
||||
new ByteTag("Rot", $rot),
|
||||
new IntTag("x", (int) $this->x),
|
||||
new IntTag("y", (int) $this->y),
|
||||
new IntTag("z", (int) $this->z)
|
||||
]);
|
||||
if($item->hasCustomName()){
|
||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
||||
}
|
||||
/** @var Spawnable $tile */
|
||||
Tile::createTile("Skull", $this->getLevel(), $nbt);
|
||||
return true;
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if($face === Vector3::SIDE_DOWN){
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$tile = $this->level->getTile($this);
|
||||
if($tile instanceof SkullTile){
|
||||
if($tile instanceof TileSkull){
|
||||
return [
|
||||
ItemFactory::get(Item::SKULL, $tile->getType(), 1)
|
||||
];
|
||||
|
129
src/pocketmine/block/Slab.php
Normal file
129
src/pocketmine/block/Slab.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?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\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
abstract class Slab extends Transparent{
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
abstract public function getDoubleSlabId() : int;
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
if(parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock)){
|
||||
return true;
|
||||
}
|
||||
|
||||
if($blockReplace->getId() === $this->getId() and $blockReplace->getVariant() === $this->getVariant()){
|
||||
if(($blockReplace->getDamage() & 0x08) !== 0){ //Trying to combine with top slab
|
||||
return $clickVector->y <= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_UP);
|
||||
}else{
|
||||
return $clickVector->y >= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
$this->meta &= 0x07;
|
||||
if($face === Vector3::SIDE_DOWN){
|
||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0x08 and $blockClicked->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
}elseif($face === Vector3::SIDE_UP){
|
||||
if($blockClicked->getId() === $this->id and ($blockClicked->getDamage() & 0x08) === 0 and $blockClicked->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockClicked, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}elseif($blockReplace->getId() === $this->id and $blockReplace->getVariant() === $this->getVariant()){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
}else{ //TODO: collision
|
||||
if($blockReplace->getId() === $this->id){
|
||||
if($blockReplace->getVariant() === $this->meta){
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->getDoubleSlabId(), $this->getVariant()), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}else{
|
||||
if($clickVector->y > 0.5){
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($blockReplace->getId() === $this->id and $blockClicked->getVariant() !== $this->getVariant()){
|
||||
return false;
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x07;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
if(($this->meta & 0x08) > 0){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 0.5,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ class SnowLayer extends Flowable{
|
||||
return "Snow Layer";
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class SnowLayer extends Flowable{
|
||||
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{
|
||||
if($blockReplace->getSide(Vector3::SIDE_DOWN)->isSolid()){
|
||||
//TODO: fix placement
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
|
@ -46,7 +46,7 @@ class SoulSand extends Solid{
|
||||
return Tool::TYPE_SHOVEL;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
|
@ -31,106 +31,59 @@ use pocketmine\Player;
|
||||
|
||||
abstract class Stair extends Transparent{
|
||||
|
||||
/*
|
||||
public function collidesWithBB(AxisAlignedBB $bb, &$list = []){
|
||||
$damage = $this->getDamage();
|
||||
$j = $damage & 0x03;
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//TODO: handle corners
|
||||
|
||||
$f = 0;
|
||||
$f1 = 0.5;
|
||||
$f2 = 0.5;
|
||||
$f3 = 1;
|
||||
$minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
|
||||
$maxYSlab = $minYSlab + 0.5;
|
||||
|
||||
if(($damage & 0x04) > 0){
|
||||
$f = 0.5;
|
||||
$f1 = 1;
|
||||
$f2 = 0;
|
||||
$f3 = 0.5;
|
||||
$bbs = [
|
||||
new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + $minYSlab,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $maxYSlab,
|
||||
$this->z + 1
|
||||
)
|
||||
];
|
||||
|
||||
$minY = ($this->meta & 0x04) === 0 ? 0.5 : 0;
|
||||
$maxY = $minY + 0.5;
|
||||
|
||||
$rotationMeta = $this->meta & 0x03;
|
||||
|
||||
$minX = $minZ = 0;
|
||||
$maxX = $maxZ = 1;
|
||||
|
||||
switch($rotationMeta){
|
||||
case 0:
|
||||
$minX = 0.5;
|
||||
break;
|
||||
case 1:
|
||||
$maxX = 0.5;
|
||||
break;
|
||||
case 2:
|
||||
$minZ = 0.5;
|
||||
break;
|
||||
case 3:
|
||||
$maxZ = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f1,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
$bbs[] = new AxisAlignedBB(
|
||||
$this->x + $minX,
|
||||
$this->y + $minY,
|
||||
$this->z + $minZ,
|
||||
$this->x + $maxX,
|
||||
$this->y + $maxY,
|
||||
$this->z + $maxZ
|
||||
);
|
||||
|
||||
if($j === 0){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x + 0.5,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 1){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 0.5,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 2){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z + 0.5,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 3){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 0.5
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 0.5,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
return $bbs;
|
||||
}
|
||||
|
||||
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 = [
|
||||
0 => 0,
|
||||
1 => 2,
|
||||
@ -138,7 +91,7 @@ abstract class Stair extends Transparent{
|
||||
3 => 3
|
||||
];
|
||||
$this->meta = $faces[$player->getDirection()] & 0x03;
|
||||
if(($facePos->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
||||
if(($clickVector->y > 0.5 and $face !== Vector3::SIDE_UP) or $face === Vector3::SIDE_DOWN){
|
||||
$this->meta |= 0x04; //Upside-down stairs
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
109
src/pocketmine/block/StandingBanner.php
Normal file
109
src/pocketmine/block/StandingBanner.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?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\ItemFactory;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Banner as TileBanner;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class StandingBanner extends Transparent{
|
||||
|
||||
protected $id = self::STANDING_BANNER;
|
||||
|
||||
protected $itemId = Item::BANNER;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Standing Banner";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, Player $player = null) : bool{
|
||||
if($face !== Vector3::SIDE_DOWN){
|
||||
if($face === Vector3::SIDE_UP and $player !== null){
|
||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
}else{
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_BANNER, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::BANNER, $this->getLevel(), TileBanner::createNBT($this, $face, $item, $player));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$tile = $this->level->getTile($this);
|
||||
|
||||
$drop = ItemFactory::get(Item::BANNER, ($tile instanceof TileBanner ? $tile->getBaseColor() : 0));
|
||||
if($tile instanceof TileBanner and ($patterns = $tile->namedtag->getListTag(TileBanner::TAG_PATTERNS)) !== null and $patterns->getCount() > 0){
|
||||
$drop->setNamedTagEntry($patterns);
|
||||
}
|
||||
|
||||
return [$drop];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user