mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-14 13:25:11 +00:00
Compare commits
479 Commits
api/3.0.0-
...
1.7dev-318
Author | SHA1 | Date | |
---|---|---|---|
716c1f29b4 | |||
0df3b00de4 | |||
13e5718463 | |||
270e0c076c | |||
3765511317 | |||
8daa8deae9 | |||
e055ce9526 | |||
3ed8855894 | |||
f25255e46c | |||
7db8345424 | |||
bc7ba3b3c1 | |||
1dd2203ee5 | |||
554096953b | |||
55a1731da3 | |||
ba3fe20227 | |||
7b04049bb7 | |||
30211bee82 | |||
e318dc12a5 | |||
967ce99b03 | |||
9bdda54aec | |||
18e4e5364f | |||
98cfd0b398 | |||
a245615531 | |||
0a19a2611a | |||
50be26958a | |||
67c6fca0ed | |||
d99e9513b0 | |||
5a353012de | |||
087badcb48 | |||
d9769360fe | |||
9fb93985d6 | |||
2b22d5d8cc | |||
2db13bd114 | |||
11cc20972f | |||
4821e7386d | |||
584810780a | |||
55de75b914 | |||
2a1a17aa7a | |||
90165cf99d | |||
a4ca3f1d1c | |||
f783789e5a | |||
43be64baed | |||
5c92c8a9d3 | |||
d2dc49cd9c | |||
f148c366f9 | |||
91d84aaff4 | |||
6b78ba8c25 | |||
b9de2e8b4b | |||
15764543b4 | |||
2c34648c3d | |||
3e3157cbe1 | |||
07abd61f73 | |||
a456b7cfca | |||
ece37d1e19 | |||
cccaade00c | |||
7f0a961526 | |||
68ac4f538f | |||
f14b7cbf78 | |||
f4ff5d81ea | |||
28a840d161 | |||
292e462ea0 | |||
c8379efbce | |||
1b5746fd97 | |||
4a0ac01697 | |||
9bcb41fb21 | |||
20b86bdea8 | |||
0b1a9ba062 | |||
45b003ac2e | |||
769a50faa5 | |||
af85659c63 | |||
95fa1824c8 | |||
251d5d7946 | |||
3b5eb45ff5 | |||
fd847f02ad | |||
18d3a97466 | |||
04668d534d | |||
092cc2750f | |||
68809d992b | |||
1641183674 | |||
72531209bf | |||
8c6ab3e634 | |||
97e2d64592 | |||
a547e2cca8 | |||
cdebb62c35 | |||
2e73fd7f8c | |||
51906daad0 | |||
ce67bc620a | |||
bcefc3a54b | |||
f5378ab604 | |||
dab7cfde1c | |||
6e1318b522 | |||
cd8006e242 | |||
f5abed95ec | |||
489b9fc29b | |||
b524b841c5 | |||
41f292d995 | |||
fd8a562e02 | |||
cc553a157d | |||
a6d1cc27ec | |||
d8c90be5b8 | |||
060426ff12 | |||
eeea4fa06a | |||
401e33dd85 | |||
2893aac3ac | |||
c5c74c1898 | |||
423bea4b57 | |||
e3567faa94 | |||
4b5040dcc7 | |||
21c79b0645 | |||
7b5df10b6a | |||
c4fe9ad32d | |||
60b62a4890 | |||
061a9444cc | |||
3eb73ab468 | |||
15d6fd86e2 | |||
0c092a7ceb | |||
b9501ef415 | |||
5afe4fdb5b | |||
cc7ed7a28f | |||
7e9b89e48a | |||
63fccd4682 | |||
35e7aca88f | |||
9413f155ce | |||
6569fdbe04 | |||
d8b1757ebc | |||
8f0ee84277 | |||
b7a9e10d49 | |||
be2d134994 | |||
7b1bfc0520 | |||
59d9d6a7df | |||
8d095dff6c | |||
4981931c4a | |||
5dafabbec2 | |||
2a5d954c67 | |||
287f08cbd1 | |||
76469e1d5f | |||
c4c83e23ca | |||
eccc7bf7b3 | |||
78ca2f2e58 | |||
cef9c4621c | |||
151681bd80 | |||
327907988b | |||
97dbf61236 | |||
2be8b576ef | |||
6dbdefafdd | |||
9598b8cee4 | |||
246c6daef6 | |||
2601e35990 | |||
bdfd9c95dd | |||
cd44551d64 | |||
cebb4b35f6 | |||
7267f1a520 | |||
66a3354b31 | |||
ac7384a2b4 | |||
748beaaaa7 | |||
58788b4bc7 | |||
ae76ac82c8 | |||
e4000f8f03 | |||
ebcce43131 | |||
119913da30 | |||
1a88f59b23 | |||
fdfe70b9f2 | |||
3bda1473e7 | |||
29cd071108 | |||
1810088acf | |||
51e4a62e7b | |||
aa91183504 | |||
ae5aa31e7b | |||
7239dbbb1a | |||
3738ab1f8a | |||
8fafef2f7f | |||
5b9515b20f | |||
69e29236aa | |||
e8453b7872 | |||
00bf190e54 | |||
81dee2f9fc | |||
f6875705a1 | |||
d294d5a91b | |||
a7e9aa4bc1 | |||
628ff9449e | |||
7f5fe137d1 | |||
18448cbcb8 | |||
b0104099fe | |||
68195c64ce | |||
27aa51bac4 | |||
eac1d76e8b | |||
a8c6e14d02 | |||
bf68a6a9fc | |||
4dfd171af0 | |||
fc9c264e77 | |||
04ba41c58c | |||
736cc927ff | |||
4be7885ee4 | |||
7dc5dc3a9f | |||
f7ee78233b | |||
88807e8b22 | |||
5a6812357b | |||
ca401ec3f5 | |||
9bbebaa071 | |||
76117e7fa0 | |||
088a44ea3a | |||
b54f256fea | |||
c09d782503 | |||
b3b3ee7c56 | |||
ab5bbaa7bd | |||
afa37bd2aa | |||
49ac2555ce | |||
edd0189d59 | |||
b76b9d53fe | |||
42dd9d6abd | |||
9cd7f39c03 | |||
f6e30d4225 | |||
27798c69ee | |||
a33be643c4 | |||
a06ff3d96b | |||
e6cecabf3f | |||
c273a46537 | |||
c448f4a3b5 | |||
86b76bfcab | |||
7ba193dc2e | |||
f565791e41 | |||
bc0434913e | |||
9bc8d8db79 | |||
d0bf0ff083 | |||
7dc1fc54b1 | |||
bae42dc0d9 | |||
ab809f8a2b | |||
2162675b64 | |||
8f63117dac | |||
1c9b4f3e21 | |||
48d2d7e422 | |||
52bd042bde | |||
4b63a22f8c | |||
c47f1f572c | |||
7a77bb0402 | |||
90cb018de2 | |||
992c4ce6a0 | |||
78af87a572 | |||
c79a5509f6 | |||
827ee5d4f9 | |||
f5b0cbb337 | |||
18777a9041 | |||
13d50aff62 | |||
5b191327bc | |||
8811188e71 | |||
38fad4b963 | |||
e64076ec81 | |||
ccbdb77618 | |||
91c6086ae1 | |||
85ec7d9732 | |||
10f597cd64 | |||
6e5759b1d1 | |||
03d3e595d6 | |||
8ca59d12e9 | |||
89e4defa29 | |||
f5534a9ab0 | |||
28bce8d48c | |||
3c02a6a8ed | |||
6b0ac8adb8 | |||
38ec5da260 | |||
240cc3043a | |||
043ae487de | |||
f12701e582 | |||
6e961ae897 | |||
e1d10f595a | |||
178dd1b981 | |||
826ec90856 | |||
0523f26613 | |||
5190d9c1e2 | |||
c8fd0eaf8b | |||
53ef9b653a | |||
030cc4afb0 | |||
9bd7f771d3 | |||
10f6a0eef0 | |||
d0a96f35da | |||
65e908a403 | |||
d7091f4460 | |||
c6670b2e74 | |||
194278d986 | |||
0e2e9aab2e | |||
1b5fed983b | |||
5aba87b250 | |||
f01ce8e994 | |||
d89b8cf12e | |||
6aa9b081e9 | |||
dbed80386a | |||
cefad0444c | |||
ee052f91d4 | |||
ef6250967f | |||
61cfdac6a1 | |||
fd7fb10223 | |||
6897cb4774 | |||
8e7ad532f1 | |||
9e8366725a | |||
b14ecc18c4 | |||
55720d9f0a | |||
0262465a26 | |||
7996a7b08c | |||
4a1fc1bdf7 | |||
85b2b2ae2e | |||
38e11aae5e | |||
f0755d1659 | |||
fd33a65e3b | |||
7baadf9dad | |||
ca23864e4c | |||
8728547a11 | |||
90fb3c5e12 | |||
1fb6d12a6b | |||
1323d89139 | |||
136ab1dba1 | |||
8cae20e818 | |||
ff2b3bfa2a | |||
361b262d3a | |||
1fd7f441b4 | |||
3f56d6ddc8 | |||
1e4cbb0dd9 | |||
a99eee9def | |||
bdee746e46 | |||
642c7733cd | |||
c8199e14ad | |||
0f37bc35ba | |||
8dc3d019f6 | |||
bd64172750 | |||
0e51820dfb | |||
30d2318bb7 | |||
63634d7e7d | |||
d941bf8e74 | |||
8c9d9626ab | |||
6b34c47c96 | |||
77241e14ce | |||
15b08c1417 | |||
4d1daecd91 | |||
53e5db5142 | |||
ad72fe6232 | |||
8b33f711d0 | |||
319735db3a | |||
c283d87494 | |||
be27e03126 | |||
c1c290cd39 | |||
5267c571e9 | |||
0fac3b9a9d | |||
23a38400e2 | |||
297172d111 | |||
825d4f9702 | |||
1d31958ce6 | |||
130a60f2b2 | |||
07268e4b37 | |||
441efc4ae2 | |||
88bd7713c5 | |||
aaa3b6e59a | |||
25adac8859 | |||
8d0b881762 | |||
16cb75ef38 | |||
3b9689674d | |||
7f5d8cc900 | |||
8761256246 | |||
8c363cb571 | |||
10b765e17a | |||
0eb866bf25 | |||
c46caa38e1 | |||
17d949f476 | |||
c569f55933 | |||
01d8d216ca | |||
f1ccee505b | |||
a61adb5991 | |||
cae1a3bb4b | |||
6681bd250a | |||
38293913ee | |||
8493ce8a35 | |||
9b7868238c | |||
953c1ef4ec | |||
021a9a4820 | |||
5b7565664c | |||
ebdfbe6bb9 | |||
85ff236461 | |||
d7422d9283 | |||
fcb3c4820e | |||
c72ef605b9 | |||
e274f1b7f8 | |||
69514c5763 | |||
12c154badf | |||
c9ee206fe6 | |||
6877ac35eb | |||
78d49f8e66 | |||
de6ebc5791 | |||
2cff5a500c | |||
f077ba4748 | |||
dcf34b7188 | |||
ca84532640 | |||
75e32b11b7 | |||
9f44b2ed75 | |||
1c02c747ca | |||
a6c0f1512c | |||
604d8ecf9a | |||
5d75d3d5b6 | |||
8b13b520e0 | |||
00e4fff259 | |||
a06c934f4d | |||
5335ed9394 | |||
16aeb0ac85 | |||
8caabd3267 | |||
ddfe828445 | |||
67ad2d25b9 | |||
190f4dd6ab | |||
6d6283b7f3 | |||
a3d21de559 | |||
ece0692229 | |||
b5d2402c9b | |||
c7fd3eb725 | |||
5433a3f964 | |||
2c3d7c49f9 | |||
76acb1da7b | |||
17518195d1 | |||
2443a57234 | |||
95752ef542 | |||
da4c9cf404 | |||
770616d4ab | |||
445a67954d | |||
4250e99e3a | |||
121777375e | |||
93e149e91c | |||
1f70a7830e | |||
159b2e3d5e | |||
e0307411da | |||
e5e76d4c93 | |||
2688228a6f | |||
e15eefc58f | |||
8853452feb | |||
09c53552c1 | |||
1f6d325328 | |||
f35ca147bb | |||
b6fb2bca13 | |||
4f1302adf2 | |||
643e10037c | |||
eda2473e78 | |||
4b65fef957 | |||
fbe2567e58 | |||
5fc50aeda5 | |||
9be1b929a5 | |||
6480f7a989 | |||
1576a79644 | |||
02cbf800d0 | |||
5a4fbc6f5a | |||
83fcec3e94 | |||
5d436a06ec | |||
8958b3c51c | |||
c1ff7bbef4 | |||
74ee94b385 | |||
5208ad885c | |||
51be88c698 | |||
0dc8362536 | |||
9bae4d8ef6 | |||
bb4808c23e | |||
3025f76cd0 | |||
1e539c4e3b | |||
590003d7c1 | |||
72d40860f3 | |||
d3d1e32309 | |||
36d47a33f3 | |||
260179197b | |||
75644b5df2 | |||
3ad1b1ba7f | |||
b4c2305c7f | |||
1d0f0a2999 | |||
8ca37b3813 | |||
2ba601b6e9 | |||
7958fffa07 | |||
98e0a2ecba | |||
899e318a88 | |||
989505c42c | |||
d9da9accbc | |||
711d62b5eb | |||
49506659e0 | |||
7886918140 | |||
8a151dc373 | |||
58a12fdfa3 | |||
50dffeb6a1 | |||
63d2b341b9 | |||
77cd8e7799 |
19
.github/ISSUE_TEMPLATE.md
vendored
19
.github/ISSUE_TEMPLATE.md
vendored
@ -3,16 +3,17 @@
|
|||||||
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
|
THIS ISSUE TRACKER IS FOR BUG REPORTING, NOT FOR HELP & SUPPORT. If you need help, use the links below.
|
||||||
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
||||||
- https://forums.pmmp.io - PMMP Forums
|
- https://forums.pmmp.io - PMMP Forums
|
||||||
-->
|
|
||||||
<!--- Any issues requesting updates to new versions of MCPE will be treated as spam. We do not need issues to tell us that there is a new version available. -->
|
|
||||||
<!---
|
|
||||||
Write a short description about the issue
|
|
||||||
|
|
||||||
If you are reporting a regression or unexpected behaviour, please include the below information:
|
Any issues requesting updates to new versions of MCPE will be treated as spam.
|
||||||
Expected result: What were you expecting to happen?
|
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
|
||||||
Actual result: What actually happened?
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!--- Write a short description about the issue -->
|
||||||
|
|
||||||
|
<!--- If you are reporting a regression or unexpected behaviour, please include the below information: -->
|
||||||
|
- Expected result: What were you expecting to happen?
|
||||||
|
- Actual result: What actually happened?
|
||||||
|
|
||||||
### Steps to reproduce the issue
|
### Steps to reproduce the issue
|
||||||
<!--- help us find the problem by adding steps to reproduce the issue -->
|
<!--- help us find the problem by adding steps to reproduce the issue -->
|
||||||
1. ...
|
1. ...
|
||||||
@ -21,9 +22,9 @@ Actual result: What actually happened?
|
|||||||
### OS and versions
|
### OS and versions
|
||||||
<!--- use the 'version' command in PocketMine-MP
|
<!--- use the 'version' command in PocketMine-MP
|
||||||
|
|
||||||
NOTE: LATEST is not a valid version. PocketMine version should include Jenkins build number and/or git commit hash.
|
NOTE: LATEST is not a valid version. PocketMine-MP version should include Jenkins build number and/or git commit hash.
|
||||||
|
|
||||||
NO support whatsoever will be provided for forks or spoons of PocketMine. Issues relating to non-official distributions will be closed as spam. Please send such issues to whoever is responsible for the fork or spoon you are using.
|
NO support whatsoever will be provided for third-party modified variants of PocketMine-MP. Issues relating to third-party modifications will be closed as spam.
|
||||||
|
|
||||||
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
||||||
-->
|
-->
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -28,3 +28,9 @@ Desktop.ini
|
|||||||
# Sphinx-doc
|
# Sphinx-doc
|
||||||
/docs/build/
|
/docs/build/
|
||||||
!/docs/requirements.txt
|
!/docs/requirements.txt
|
||||||
|
|
||||||
|
# Composer
|
||||||
|
vendor/*
|
||||||
|
|
||||||
|
# Travis files
|
||||||
|
test_data/*
|
||||||
|
17
.travis.yml
17
.travis.yml
@ -1,12 +1,21 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 7.0
|
- 7.2
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- pecl install channel://pecl.php.net/pthreads-3.1.6
|
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||||
- pecl install channel://pecl.php.net/weakref-0.3.3
|
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
|
||||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.0
|
- git clone https://github.com/krakjoe/pthreads.git
|
||||||
|
- cd pthreads
|
||||||
|
- git checkout 6c6b15138c923b69cfa46ee05fc2dd45da587287
|
||||||
|
- phpize
|
||||||
|
- ./configure
|
||||||
|
- make
|
||||||
|
- make install
|
||||||
|
- cd ..
|
||||||
|
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||||
|
- composer install
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./tests/travis.sh
|
- ./tests/travis.sh
|
||||||
|
33
composer.json
Normal file
33
composer.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"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",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"src/spl/stubs"
|
||||||
|
],
|
||||||
|
"psr-0": {
|
||||||
|
"": ["src", "src/spl"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
composer.lock
generated
Normal file
36
composer.lock
generated
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"_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": "d4fecad9dce5314493052c870c8cf059",
|
||||||
|
"packages": [],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {
|
||||||
|
"ext-pthreads": 20
|
||||||
|
},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {
|
||||||
|
"php": ">=7.2",
|
||||||
|
"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": []
|
||||||
|
}
|
@ -25,7 +25,9 @@ namespace pocketmine;
|
|||||||
|
|
||||||
use pocketmine\event\server\LowMemoryEvent;
|
use pocketmine\event\server\LowMemoryEvent;
|
||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
|
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||||
use pocketmine\scheduler\GarbageCollectionTask;
|
use pocketmine\scheduler\GarbageCollectionTask;
|
||||||
|
use pocketmine\utils\MainLogger;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
|
|
||||||
class MemoryManager{
|
class MemoryManager{
|
||||||
@ -63,16 +65,19 @@ class MemoryManager{
|
|||||||
private $garbageCollectionAsync;
|
private $garbageCollectionAsync;
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $chunkRadiusOverride;
|
private $lowMemChunkRadiusOverride;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $chunkCollect;
|
private $lowMemChunkGC;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $chunkTrigger;
|
private $lowMemReduceChunkRadius;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $chunkCache;
|
private $lowMemDisableChunkCache;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $cacheTrigger;
|
private $lowMemClearWorldCache;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $dumpWorkers = true;
|
||||||
|
|
||||||
public function __construct(Server $server){
|
public function __construct(Server $server){
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
@ -124,13 +129,13 @@ class MemoryManager{
|
|||||||
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
|
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
|
||||||
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
|
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
|
||||||
|
|
||||||
$this->chunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
||||||
$this->chunkCollect = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
||||||
$this->chunkTrigger = (bool) $this->server->getProperty("memory.max-chunks.low-memory-trigger", true);
|
|
||||||
|
|
||||||
$this->chunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
||||||
$this->cacheTrigger = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
||||||
|
|
||||||
|
$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
|
||||||
gc_enable();
|
gc_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +150,7 @@ class MemoryManager{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function canUseChunkCache() : bool{
|
public function canUseChunkCache() : bool{
|
||||||
return !($this->lowMemory and $this->chunkTrigger);
|
return !$this->lowMemory or !$this->lowMemDisableChunkCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,7 +161,7 @@ class MemoryManager{
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getViewDistance(int $distance) : int{
|
public function getViewDistance(int $distance) : int{
|
||||||
return $this->lowMemory ? (int) min($this->chunkRadiusOverride, $distance) : $distance;
|
return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? (int) min($this->lowMemChunkRadiusOverride, $distance) : $distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,13 +175,13 @@ class MemoryManager{
|
|||||||
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
|
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0){
|
||||||
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
||||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||||
if($this->cacheTrigger){
|
if($this->lowMemClearWorldCache){
|
||||||
foreach($this->server->getLevels() as $level){
|
foreach($this->server->getLevels() as $level){
|
||||||
$level->clearCache(true);
|
$level->clearCache(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->chunkTrigger and $this->chunkCollect){
|
if($this->lowMemChunkGC){
|
||||||
foreach($this->server->getLevels() as $level){
|
foreach($this->server->getLevels() as $level){
|
||||||
$level->doChunkGarbageCollection();
|
$level->doChunkGarbageCollection();
|
||||||
}
|
}
|
||||||
@ -261,6 +266,27 @@ class MemoryManager{
|
|||||||
* @param int $maxStringSize
|
* @param int $maxStringSize
|
||||||
*/
|
*/
|
||||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||||
|
MainLogger::getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||||
|
self::dumpMemory($this->server, $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');
|
$hardLimit = ini_get('memory_limit');
|
||||||
ini_set('memory_limit', '-1');
|
ini_set('memory_limit', '-1');
|
||||||
gc_disable();
|
gc_disable();
|
||||||
@ -269,12 +295,8 @@ class MemoryManager{
|
|||||||
mkdir($outputFolder, 0777, true);
|
mkdir($outputFolder, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
|
||||||
|
|
||||||
$obData = fopen($outputFolder . "/objects.js", "wb+");
|
$obData = fopen($outputFolder . "/objects.js", "wb+");
|
||||||
|
|
||||||
$staticProperties = [];
|
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
$objects = [];
|
$objects = [];
|
||||||
@ -283,8 +305,10 @@ class MemoryManager{
|
|||||||
|
|
||||||
$instanceCounts = [];
|
$instanceCounts = [];
|
||||||
|
|
||||||
|
$staticProperties = [];
|
||||||
$staticCount = 0;
|
$staticCount = 0;
|
||||||
foreach($this->server->getLoader()->getClasses() as $className){
|
|
||||||
|
foreach($loader->getClasses() as $className){
|
||||||
$reflection = new \ReflectionClass($className);
|
$reflection = new \ReflectionClass($className);
|
||||||
$staticProperties[$className] = [];
|
$staticProperties[$className] = [];
|
||||||
foreach($reflection->getProperties() as $property){
|
foreach($reflection->getProperties() as $property){
|
||||||
@ -297,7 +321,7 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$staticCount++;
|
$staticCount++;
|
||||||
$this->continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($staticProperties[$className]) === 0){
|
if(count($staticProperties[$className]) === 0){
|
||||||
@ -305,9 +329,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{
|
do{
|
||||||
$continue = false;
|
$continue = false;
|
||||||
@ -349,25 +403,26 @@ class MemoryManager{
|
|||||||
if(!$property->isPublic()){
|
if(!$property->isPublic()){
|
||||||
$property->setAccessible(true);
|
$property->setAccessible(true);
|
||||||
}
|
}
|
||||||
$this->continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
self::continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "[Dump] Wrote " . count($objects) . " objects\n";
|
|
||||||
}while($continue);
|
}while($continue);
|
||||||
|
|
||||||
|
MainLogger::getLogger()->info("[Dump] Wrote " . count($objects) . " objects");
|
||||||
|
|
||||||
fclose($obData);
|
fclose($obData);
|
||||||
|
|
||||||
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
|
||||||
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
arsort($instanceCounts, SORT_NUMERIC);
|
arsort($instanceCounts, SORT_NUMERIC);
|
||||||
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
echo "[Dump] Finished!\n";
|
MainLogger::getLogger()->info("[Dump] Finished!");
|
||||||
|
|
||||||
ini_set('memory_limit', $hardLimit);
|
ini_set('memory_limit', $hardLimit);
|
||||||
gc_enable();
|
gc_enable();
|
||||||
@ -382,7 +437,7 @@ class MemoryManager{
|
|||||||
* @param int $maxNesting
|
* @param int $maxNesting
|
||||||
* @param int $maxStringSize
|
* @param int $maxStringSize
|
||||||
*/
|
*/
|
||||||
private function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||||
if($maxNesting <= 0){
|
if($maxNesting <= 0){
|
||||||
$data = "(error) NESTING LIMIT REACHED";
|
$data = "(error) NESTING LIMIT REACHED";
|
||||||
return;
|
return;
|
||||||
@ -406,7 +461,7 @@ class MemoryManager{
|
|||||||
}
|
}
|
||||||
$data = [];
|
$data = [];
|
||||||
foreach($from as $key => $value){
|
foreach($from as $key => $value){
|
||||||
$this->continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||||
}
|
}
|
||||||
}elseif(is_string($from)){
|
}elseif(is_string($from)){
|
||||||
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);
|
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace pocketmine {
|
namespace pocketmine {
|
||||||
|
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\MainLogger;
|
use pocketmine\utils\MainLogger;
|
||||||
use pocketmine\utils\ServerKiller;
|
use pocketmine\utils\ServerKiller;
|
||||||
@ -78,9 +79,12 @@ namespace pocketmine {
|
|||||||
use pocketmine\wizard\SetupWizard;
|
use pocketmine\wizard\SetupWizard;
|
||||||
use raklib\RakLib;
|
use raklib\RakLib;
|
||||||
|
|
||||||
const VERSION = "1.6.2dev";
|
const NAME = "PocketMine-MP";
|
||||||
const API_VERSION = "3.0.0-ALPHA7";
|
const VERSION = "1.7dev";
|
||||||
const CODENAME = "Unleashed";
|
const API_VERSION = "3.0.0-ALPHA9";
|
||||||
|
const CODENAME = "[REDACTED]";
|
||||||
|
|
||||||
|
const MIN_PHP_VERSION = "7.2.0RC3";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Startup code. Do not look at it, it may harm you.
|
* Startup code. Do not look at it, it may harm you.
|
||||||
@ -89,9 +93,9 @@ namespace pocketmine {
|
|||||||
* Enjoy it as much as I did writing it. I don't want to do it again.
|
* Enjoy it as much as I did writing it. I don't want to do it again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
|
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
||||||
echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
|
echo "[CRITICAL] " . \pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "." . PHP_EOL;
|
||||||
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
|
echo "[CRITICAL] Please use the installer provided on the homepage, or update to a newer PHP version." . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,13 +107,15 @@ namespace pocketmine {
|
|||||||
|
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
|
|
||||||
set_error_handler(function($severity, $message, $file, $line){
|
function error_handler($severity, $message, $file, $line){
|
||||||
if(error_reporting() & $severity){
|
if(error_reporting() & $severity){
|
||||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||||
}else{ //stfu operator
|
}else{ //stfu operator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
set_error_handler('\pocketmine\error_handler');
|
||||||
|
|
||||||
if(!extension_loaded("phar")){
|
if(!extension_loaded("phar")){
|
||||||
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
||||||
@ -120,30 +126,40 @@ namespace pocketmine {
|
|||||||
if(\Phar::running(true) !== ""){
|
if(\Phar::running(true) !== ""){
|
||||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
define('pocketmine\PATH', \Phar::running(true) . "/");
|
||||||
}else{
|
}else{
|
||||||
define('pocketmine\PATH', realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requiredSplVer = "0.0.1";
|
$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){
|
if(!is_file(\pocketmine\PATH . "src/spl/version.php")){
|
||||||
|
echo "[CRITICAL] Cannot find PocketMine-SPL or incompatible version." . PHP_EOL;
|
||||||
|
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}elseif(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] Incompatible PocketMine-SPL submodule version ($requiredSplVer is required)." . PHP_EOL;
|
||||||
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
echo "[CRITICAL] Please update your submodules or use provided builds." . PHP_EOL;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(is_file(\pocketmine\PATH . "vendor/autoload.php")){
|
||||||
|
require_once(\pocketmine\PATH . "vendor/autoload.php");
|
||||||
|
}else{
|
||||||
|
echo "[CRITICAL] Composer autoloader not found" . PHP_EOL;
|
||||||
|
echo "[CRITICAL] Please initialize composer dependencies before running." . PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if(!class_exists("ClassLoader", false)){
|
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/ClassLoader.php");
|
||||||
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We now use the Composer autoloader, but this autoloader is still used by RakLib and for loading plugins.
|
||||||
|
*/
|
||||||
$autoloader = new \BaseClassLoader();
|
$autoloader = new \BaseClassLoader();
|
||||||
$autoloader->addPath(\pocketmine\PATH . "src");
|
$autoloader->addPath(\pocketmine\PATH . "src");
|
||||||
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
|
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
|
||||||
$autoloader->register(true);
|
$autoloader->register(false);
|
||||||
|
|
||||||
if(!class_exists(RakLib::class)){
|
if(!class_exists(RakLib::class)){
|
||||||
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
|
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
|
||||||
@ -186,40 +202,51 @@ namespace pocketmine {
|
|||||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||||
$logger->registerStatic();
|
$logger->registerStatic();
|
||||||
|
|
||||||
if(!ini_get("date.timezone")){
|
do{
|
||||||
|
$timezone = ini_get("date.timezone");
|
||||||
|
if($timezone !== ""){
|
||||||
|
/*
|
||||||
|
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
||||||
|
* an incorrect timezone abbreviation in php.ini apparently.
|
||||||
|
*/
|
||||||
|
if(strpos($timezone, "/") === false){
|
||||||
|
$default_timezone = timezone_name_from_abbr($timezone);
|
||||||
|
if($default_timezone !== false){
|
||||||
|
ini_set("date.timezone", $default_timezone);
|
||||||
|
date_default_timezone_set($default_timezone);
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
//Bad php.ini value, try another method to detect timezone
|
||||||
|
$logger->warning("Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
||||||
//Success! Timezone has already been set and validated in the if statement.
|
//Success! Timezone has already been set and validated in the if statement.
|
||||||
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
|
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
|
||||||
ini_set("date.timezone", $timezone);
|
ini_set("date.timezone", $timezone);
|
||||||
}else{
|
break;
|
||||||
//If system timezone detection fails or timezone is an invalid value.
|
|
||||||
if($response = Utils::getURL("http://ip-api.com/json")
|
|
||||||
and $ip_geolocation_data = json_decode($response, true)
|
|
||||||
and $ip_geolocation_data['status'] !== 'fail'
|
|
||||||
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
|
||||||
){
|
|
||||||
//Again, for redundancy.
|
|
||||||
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
|
||||||
}else{
|
|
||||||
ini_set("date.timezone", "UTC");
|
|
||||||
date_default_timezone_set("UTC");
|
|
||||||
$logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
/*
|
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
|
||||||
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
and $ip_geolocation_data = json_decode($response, true)
|
||||||
* an incorrect timezone abbreviation in php.ini apparently.
|
and $ip_geolocation_data['status'] !== 'fail'
|
||||||
*/
|
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
||||||
$timezone = ini_get("date.timezone");
|
){
|
||||||
if(strpos($timezone, "/") === false){
|
//Again, for redundancy.
|
||||||
$default_timezone = timezone_name_from_abbr($timezone);
|
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
||||||
ini_set("date.timezone", $default_timezone);
|
break;
|
||||||
date_default_timezone_set($default_timezone);
|
|
||||||
}else{
|
|
||||||
date_default_timezone_set($timezone);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ini_set("date.timezone", "UTC");
|
||||||
|
date_default_timezone_set("UTC");
|
||||||
|
$logger->warning("Timezone could not be automatically determined or was set to an invalid value. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
||||||
|
}while(false);
|
||||||
|
|
||||||
|
|
||||||
function detect_system_timezone(){
|
function detect_system_timezone(){
|
||||||
switch(Utils::getOS()){
|
switch(Utils::getOS()){
|
||||||
@ -408,7 +435,7 @@ namespace pocketmine {
|
|||||||
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
||||||
}, $args));
|
}, $args));
|
||||||
}
|
}
|
||||||
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . ($trace[$i]["line"] ?? "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $messages;
|
return $messages;
|
||||||
@ -424,13 +451,13 @@ namespace pocketmine {
|
|||||||
$errors = 0;
|
$errors = 0;
|
||||||
|
|
||||||
if(PHP_INT_SIZE < 8){
|
if(PHP_INT_SIZE < 8){
|
||||||
$logger->critical("Running PocketMine-MP with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
|
$logger->critical("Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
|
||||||
$exitCode = 1;
|
$exitCode = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(php_sapi_name() !== "cli"){
|
if(php_sapi_name() !== "cli"){
|
||||||
$logger->critical("You must run PocketMine-MP using the CLI.");
|
$logger->critical("You must run " . \pocketmine\NAME . " using the CLI.");
|
||||||
++$errors;
|
++$errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,8 +465,8 @@ namespace pocketmine {
|
|||||||
if(substr_count($pthreads_version, ".") < 2){
|
if(substr_count($pthreads_version, ".") < 2){
|
||||||
$pthreads_version = "0.$pthreads_version";
|
$pthreads_version = "0.$pthreads_version";
|
||||||
}
|
}
|
||||||
if(version_compare($pthreads_version, "3.1.5") < 0){
|
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
|
||||||
$logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
|
$logger->critical("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
|
||||||
++$errors;
|
++$errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,7 +489,7 @@ namespace pocketmine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(extension_loaded("xdebug")){
|
if(extension_loaded("xdebug")){
|
||||||
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running PocketMine with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$extensions = [
|
$extensions = [
|
||||||
@ -524,7 +551,7 @@ namespace pocketmine {
|
|||||||
|
|
||||||
|
|
||||||
if(\Phar::running(true) === ""){
|
if(\Phar::running(true) === ""){
|
||||||
$logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
|
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::init();
|
ThreadManager::init();
|
||||||
@ -536,19 +563,7 @@ namespace pocketmine {
|
|||||||
$killer->start();
|
$killer->start();
|
||||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||||
|
|
||||||
$erroredThreads = 0;
|
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||||
foreach(ThreadManager::getInstance()->getAll() as $id => $thread){
|
|
||||||
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
|
||||||
try{
|
|
||||||
$thread->quit();
|
|
||||||
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
|
||||||
}catch(\ThreadException $e){
|
|
||||||
++$erroredThreads;
|
|
||||||
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($erroredThreads > 0){
|
|
||||||
if(\pocketmine\DEBUG > 1){
|
if(\pocketmine\DEBUG > 1){
|
||||||
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ use pocketmine\command\SimpleCommandMap;
|
|||||||
use pocketmine\entity\Attribute;
|
use pocketmine\entity\Attribute;
|
||||||
use pocketmine\entity\Effect;
|
use pocketmine\entity\Effect;
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\event\HandlerList;
|
use pocketmine\event\HandlerList;
|
||||||
use pocketmine\event\level\LevelInitEvent;
|
use pocketmine\event\level\LevelInitEvent;
|
||||||
use pocketmine\event\level\LevelLoadEvent;
|
use pocketmine\event\level\LevelLoadEvent;
|
||||||
@ -47,7 +48,6 @@ use pocketmine\event\Timings;
|
|||||||
use pocketmine\event\TimingsHandler;
|
use pocketmine\event\TimingsHandler;
|
||||||
use pocketmine\event\TranslationContainer;
|
use pocketmine\event\TranslationContainer;
|
||||||
use pocketmine\inventory\CraftingManager;
|
use pocketmine\inventory\CraftingManager;
|
||||||
use pocketmine\inventory\InventoryType;
|
|
||||||
use pocketmine\inventory\Recipe;
|
use pocketmine\inventory\Recipe;
|
||||||
use pocketmine\item\enchantment\Enchantment;
|
use pocketmine\item\enchantment\Enchantment;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
@ -83,6 +83,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
|||||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||||
use pocketmine\network\mcpe\RakLibInterface;
|
use pocketmine\network\mcpe\RakLibInterface;
|
||||||
use pocketmine\network\Network;
|
use pocketmine\network\Network;
|
||||||
use pocketmine\network\query\QueryHandler;
|
use pocketmine\network\query\QueryHandler;
|
||||||
@ -194,6 +195,9 @@ class Server{
|
|||||||
/** @var int */
|
/** @var int */
|
||||||
private $maxPlayers;
|
private $maxPlayers;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $onlineMode = true;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $autoSave;
|
private $autoSave;
|
||||||
|
|
||||||
@ -273,7 +277,7 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "PocketMine-MP";
|
return \pocketmine\NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,6 +343,24 @@ class Server{
|
|||||||
return $this->maxPlayers;
|
return $this->maxPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||||
|
* are not logged into Xbox Live will be disconnected.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getOnlineMode() : bool{
|
||||||
|
return $this->onlineMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias of {@link #getOnlineMode()}.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function requiresAuthentication() : bool{
|
||||||
|
return $this->getOnlineMode();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -494,36 +516,17 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $str
|
* @deprecated Moved to {@link Level#getDifficultyFromString}
|
||||||
*
|
*
|
||||||
|
* @param string $str
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getDifficultyFromString(string $str) : int{
|
public static function getDifficultyFromString(string $str) : int{
|
||||||
switch(strtolower(trim($str))){
|
return Level::getDifficultyFromString($str);
|
||||||
case "0":
|
|
||||||
case "peaceful":
|
|
||||||
case "p":
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case "1":
|
|
||||||
case "easy":
|
|
||||||
case "e":
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case "2":
|
|
||||||
case "normal":
|
|
||||||
case "n":
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case "3":
|
|
||||||
case "hard":
|
|
||||||
case "h":
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDifficulty() : int{
|
public function getDifficulty() : int{
|
||||||
@ -569,7 +572,7 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getMotd() : string{
|
public function getMotd() : string{
|
||||||
return $this->getConfigString("motd", "Minecraft: PE Server");
|
return $this->getConfigString("motd", \pocketmine\NAME . " Server");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -761,25 +764,25 @@ class Server{
|
|||||||
new DoubleTag("", $spawn->x),
|
new DoubleTag("", $spawn->x),
|
||||||
new DoubleTag("", $spawn->y),
|
new DoubleTag("", $spawn->y),
|
||||||
new DoubleTag("", $spawn->z)
|
new DoubleTag("", $spawn->z)
|
||||||
]),
|
], NBT::TAG_Double),
|
||||||
new StringTag("Level", $this->getDefaultLevel()->getName()),
|
new StringTag("Level", $this->getDefaultLevel()->getName()),
|
||||||
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
|
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
|
||||||
//new IntTag("SpawnX", (int) $spawn->x),
|
//new IntTag("SpawnX", (int) $spawn->x),
|
||||||
//new IntTag("SpawnY", (int) $spawn->y),
|
//new IntTag("SpawnY", (int) $spawn->y),
|
||||||
//new IntTag("SpawnZ", (int) $spawn->z),
|
//new IntTag("SpawnZ", (int) $spawn->z),
|
||||||
//new ByteTag("SpawnForced", 1), //TODO
|
//new ByteTag("SpawnForced", 1), //TODO
|
||||||
new ListTag("Inventory", []),
|
new ListTag("Inventory", [], NBT::TAG_Compound),
|
||||||
new CompoundTag("Achievements", []),
|
new CompoundTag("Achievements", []),
|
||||||
new IntTag("playerGameType", $this->getGamemode()),
|
new IntTag("playerGameType", $this->getGamemode()),
|
||||||
new ListTag("Motion", [
|
new ListTag("Motion", [
|
||||||
new DoubleTag("", 0.0),
|
new DoubleTag("", 0.0),
|
||||||
new DoubleTag("", 0.0),
|
new DoubleTag("", 0.0),
|
||||||
new DoubleTag("", 0.0)
|
new DoubleTag("", 0.0)
|
||||||
]),
|
], NBT::TAG_Double),
|
||||||
new ListTag("Rotation", [
|
new ListTag("Rotation", [
|
||||||
new FloatTag("", 0.0),
|
new FloatTag("", 0.0),
|
||||||
new FloatTag("", 0.0)
|
new FloatTag("", 0.0)
|
||||||
]),
|
], NBT::TAG_Float),
|
||||||
new FloatTag("FallDistance", 0.0),
|
new FloatTag("FallDistance", 0.0),
|
||||||
new ShortTag("Fire", 0),
|
new ShortTag("Fire", 0),
|
||||||
new ShortTag("Air", 300),
|
new ShortTag("Air", 300),
|
||||||
@ -787,10 +790,6 @@ class Server{
|
|||||||
new ByteTag("Invulnerable", 0),
|
new ByteTag("Invulnerable", 0),
|
||||||
new StringTag("NameTag", $name)
|
new StringTag("NameTag", $name)
|
||||||
]);
|
]);
|
||||||
$nbt->Pos->setTagType(NBT::TAG_Double);
|
|
||||||
$nbt->Inventory->setTagType(NBT::TAG_Compound);
|
|
||||||
$nbt->Motion->setTagType(NBT::TAG_Double);
|
|
||||||
$nbt->Rotation->setTagType(NBT::TAG_Float);
|
|
||||||
|
|
||||||
return $nbt;
|
return $nbt;
|
||||||
|
|
||||||
@ -915,7 +914,7 @@ class Server{
|
|||||||
/**
|
/**
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getDefaultLevel(){
|
public function getDefaultLevel() : ?Level{
|
||||||
return $this->levelDefault;
|
return $this->levelDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,7 +925,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @param Level|null $level
|
* @param Level|null $level
|
||||||
*/
|
*/
|
||||||
public function setDefaultLevel($level){
|
public function setDefaultLevel(?Level $level) : void{
|
||||||
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
|
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
|
||||||
$this->levelDefault = $level;
|
$this->levelDefault = $level;
|
||||||
}
|
}
|
||||||
@ -946,12 +945,8 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getLevel(int $levelId){
|
public function getLevel(int $levelId) : ?Level{
|
||||||
if(isset($this->levels[$levelId])){
|
return $this->levels[$levelId] ?? null;
|
||||||
return $this->levels[$levelId];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -961,7 +956,7 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return Level|null
|
* @return Level|null
|
||||||
*/
|
*/
|
||||||
public function getLevelByName(string $name){
|
public function getLevelByName(string $name) : ?Level{
|
||||||
foreach($this->getLevels() as $level){
|
foreach($this->getLevels() as $level){
|
||||||
if($level->getFolderName() === $name){
|
if($level->getFolderName() === $name){
|
||||||
return $level;
|
return $level;
|
||||||
@ -983,13 +978,16 @@ class Server{
|
|||||||
if($level === $this->getDefaultLevel() and !$forceUnload){
|
if($level === $this->getDefaultLevel() and !$forceUnload){
|
||||||
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
|
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
|
||||||
}
|
}
|
||||||
if($level->unload($forceUnload) === true){
|
|
||||||
unset($this->levels[$level->getId()]);
|
|
||||||
|
|
||||||
return true;
|
return $level->unload($forceUnload);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* @internal
|
||||||
|
* @param Level $level
|
||||||
|
*/
|
||||||
|
public function removeLevel(Level $level) : void{
|
||||||
|
unset($this->levels[$level->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1463,7 +1461,7 @@ class Server{
|
|||||||
|
|
||||||
$this->logger->info("Loading server properties...");
|
$this->logger->info("Loading server properties...");
|
||||||
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
||||||
"motd" => "Minecraft: PE Server",
|
"motd" => \pocketmine\NAME . " Server",
|
||||||
"server-port" => 19132,
|
"server-port" => 19132,
|
||||||
"white-list" => false,
|
"white-list" => false,
|
||||||
"announce-player-achievements" => true,
|
"announce-player-achievements" => true,
|
||||||
@ -1485,10 +1483,11 @@ class Server{
|
|||||||
"enable-rcon" => false,
|
"enable-rcon" => false,
|
||||||
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
||||||
"auto-save" => true,
|
"auto-save" => true,
|
||||||
"view-distance" => 8
|
"view-distance" => 8,
|
||||||
|
"xbox-auth" => true
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->forceLanguage = $this->getProperty("settings.force-language", false);
|
$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
|
||||||
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
|
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
|
||||||
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
||||||
|
|
||||||
@ -1512,7 +1511,12 @@ class Server{
|
|||||||
}else{
|
}else{
|
||||||
Network::$BATCH_THRESHOLD = -1;
|
Network::$BATCH_THRESHOLD = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
|
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
|
||||||
|
if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
|
||||||
|
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
|
||||||
|
$this->networkCompressionLevel = 7;
|
||||||
|
}
|
||||||
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
|
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
|
||||||
|
|
||||||
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
||||||
@ -1558,8 +1562,18 @@ class Server{
|
|||||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||||
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
||||||
|
|
||||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
$this->onlineMode = $this->getConfigBoolean("xbox-auth", true);
|
||||||
$this->setConfigInt("difficulty", 3);
|
if($this->onlineMode){
|
||||||
|
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth", ["enabled", "will"]));
|
||||||
|
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty", ["disable", "false"]));
|
||||||
|
}else{
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth", ["disabled", "will not"]));
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
|
||||||
|
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty", ["enable", "true"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||||
|
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(\pocketmine\DEBUG >= 0){
|
if(\pocketmine\DEBUG >= 0){
|
||||||
@ -1585,6 +1599,7 @@ class Server{
|
|||||||
]));
|
]));
|
||||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
||||||
|
|
||||||
|
|
||||||
Timings::init();
|
Timings::init();
|
||||||
|
|
||||||
$this->consoleSender = new ConsoleCommandSender();
|
$this->consoleSender = new ConsoleCommandSender();
|
||||||
@ -1592,7 +1607,6 @@ class Server{
|
|||||||
|
|
||||||
Entity::init();
|
Entity::init();
|
||||||
Tile::init();
|
Tile::init();
|
||||||
InventoryType::init();
|
|
||||||
BlockFactory::init();
|
BlockFactory::init();
|
||||||
Enchantment::init();
|
Enchantment::init();
|
||||||
ItemFactory::init();
|
ItemFactory::init();
|
||||||
@ -1638,23 +1652,23 @@ class Server{
|
|||||||
Generator::addGenerator(Nether::class, "hell");
|
Generator::addGenerator(Nether::class, "hell");
|
||||||
Generator::addGenerator(Nether::class, "nether");
|
Generator::addGenerator(Nether::class, "nether");
|
||||||
|
|
||||||
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
|
foreach((array) $this->getProperty("worlds", []) as $name => $options){
|
||||||
if($this->loadLevel($name) === false){
|
if($this->loadLevel($name) === false){
|
||||||
$seed = $this->getProperty("worlds.$name.seed", time());
|
$seed = $options["seed"] ?? time();
|
||||||
if(is_string($seed) and !is_numeric($seed)){
|
if(is_string($seed) and !is_numeric($seed)){
|
||||||
$seed = Utils::javaStringHash($seed);
|
$seed = Utils::javaStringHash($seed);
|
||||||
}elseif(!is_int($seed)){
|
}elseif(!is_int($seed)){
|
||||||
$seed = (int) $seed;
|
$seed = (int) $seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
|
if(isset($options["generator"])){
|
||||||
$generator = Generator::getGenerator(array_shift($options));
|
$generatorOptions = explode(":", $options["generator"]);
|
||||||
if(count($options) > 0){
|
$generator = Generator::getGenerator(array_shift($generatorOptions));
|
||||||
$options = [
|
if(count($options) > 0){
|
||||||
"preset" => implode(":", $options)
|
$options["preset"] = implode(":", $generatorOptions);
|
||||||
];
|
}
|
||||||
}else{
|
}else{
|
||||||
$options = [];
|
$generator = Generator::getGenerator("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->generateLevel($name, $seed, $generator, $options);
|
$this->generateLevel($name, $seed, $generator, $options);
|
||||||
@ -1975,8 +1989,8 @@ class Server{
|
|||||||
$this->properties->reload();
|
$this->properties->reload();
|
||||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||||
|
|
||||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||||
$this->setConfigInt("difficulty", 3);
|
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->banByIP->load();
|
$this->banByIP->load();
|
||||||
@ -2271,7 +2285,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function addOnlinePlayer(Player $player){
|
public function addOnlinePlayer(Player $player){
|
||||||
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
|
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
|
|
||||||
$this->playerList[$player->getRawUniqueId()] = $player;
|
$this->playerList[$player->getRawUniqueId()] = $player;
|
||||||
}
|
}
|
||||||
@ -2280,32 +2294,44 @@ class Server{
|
|||||||
if(isset($this->playerList[$player->getRawUniqueId()])){
|
if(isset($this->playerList[$player->getRawUniqueId()])){
|
||||||
unset($this->playerList[$player->getRawUniqueId()]);
|
unset($this->playerList[$player->getRawUniqueId()]);
|
||||||
|
|
||||||
$pk = new PlayerListPacket();
|
$this->removePlayerListData($player->getUniqueId());
|
||||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
|
||||||
$pk->entries[] = [$player->getUniqueId()];
|
|
||||||
$this->broadcastPacket($this->playerList, $pk);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePlayerListData(UUID $uuid, $entityId, $name, $skinId, $skinData, array $players = null){
|
/**
|
||||||
|
* @param UUID $uuid
|
||||||
|
* @param int $entityId
|
||||||
|
* @param string $name
|
||||||
|
* @param Skin $skin
|
||||||
|
* @param Player[]|null $players
|
||||||
|
*/
|
||||||
|
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
$pk->entries[] = [$uuid, $entityId, $name, $skinId, $skinData];
|
|
||||||
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
|
||||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UUID $uuid
|
||||||
|
* @param Player[]|null $players
|
||||||
|
*/
|
||||||
public function removePlayerListData(UUID $uuid, array $players = null){
|
public function removePlayerListData(UUID $uuid, array $players = null){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||||
$pk->entries[] = [$uuid];
|
$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
|
||||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player $p
|
||||||
|
*/
|
||||||
public function sendFullPlayerListData(Player $p){
|
public function sendFullPlayerListData(Player $p){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
foreach($this->playerList as $player){
|
foreach($this->playerList as $player){
|
||||||
$pk->entries[] = [$player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData()];
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
}
|
}
|
||||||
|
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk);
|
||||||
@ -2375,7 +2401,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
|
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
|
||||||
if($this->getProperty("anonymous-statistics.enabled", true)){
|
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
|
||||||
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
||||||
}
|
}
|
||||||
$this->uniquePlayers = [];
|
$this->uniquePlayers = [];
|
||||||
@ -2426,8 +2452,6 @@ class Server{
|
|||||||
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
||||||
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
||||||
|
|
||||||
$this->network->resetStatistics();
|
|
||||||
|
|
||||||
Timings::$titleTickTimer->stopTiming();
|
Timings::$titleTickTimer->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2488,25 +2512,26 @@ class Server{
|
|||||||
$player->checkNetwork();
|
$player->checkNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($this->tickCounter & 0b1111) === 0){
|
if(($this->tickCounter % 20) === 0){
|
||||||
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
||||||
$this->titleTick();
|
$this->titleTick();
|
||||||
}
|
}
|
||||||
$this->currentTPS = 20;
|
$this->currentTPS = 20;
|
||||||
$this->currentUse = 0;
|
$this->currentUse = 0;
|
||||||
|
|
||||||
if(($this->tickCounter & 0b111111111) === 0){
|
$this->network->updateName();
|
||||||
try{
|
$this->network->resetStatistics();
|
||||||
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
}
|
||||||
if($this->queryHandler !== null){
|
|
||||||
$this->queryHandler->regenerateInfo();
|
|
||||||
}
|
|
||||||
}catch(\Throwable $e){
|
|
||||||
$this->logger->logException($e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getNetwork()->updateName();
|
if(($this->tickCounter & 0b111111111) === 0){
|
||||||
|
try{
|
||||||
|
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
||||||
|
if($this->queryHandler !== null){
|
||||||
|
$this->queryHandler->regenerateInfo();
|
||||||
|
}
|
||||||
|
}catch(\Throwable $e){
|
||||||
|
$this->logger->logException($e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
|
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
|
||||||
|
@ -51,16 +51,17 @@ abstract class Thread extends \Thread{
|
|||||||
* (unless you are using a custom autoloader).
|
* (unless you are using a custom autoloader).
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
|
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||||
if(!interface_exists("ClassLoader", false)){
|
if(!interface_exists("ClassLoader", false)){
|
||||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||||
}
|
}
|
||||||
if($this->classLoader !== null){
|
if($this->classLoader !== null){
|
||||||
$this->classLoader->register(true);
|
$this->classLoader->register(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine;
|
namespace pocketmine;
|
||||||
|
|
||||||
|
use pocketmine\utils\MainLogger;
|
||||||
|
|
||||||
class ThreadManager extends \Volatile{
|
class ThreadManager extends \Volatile{
|
||||||
|
|
||||||
/** @var ThreadManager */
|
/** @var ThreadManager */
|
||||||
@ -68,4 +70,23 @@ class ThreadManager extends \Volatile{
|
|||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function stopAll() : int{
|
||||||
|
$logger = MainLogger::getLogger();
|
||||||
|
|
||||||
|
$erroredThreads = 0;
|
||||||
|
|
||||||
|
foreach($this->getAll() as $thread){
|
||||||
|
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
||||||
|
try{
|
||||||
|
$thread->quit();
|
||||||
|
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
||||||
|
}catch(\ThreadException $e){
|
||||||
|
++$erroredThreads;
|
||||||
|
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $erroredThreads;
|
||||||
|
}
|
||||||
}
|
}
|
@ -52,16 +52,17 @@ abstract class Worker extends \Worker{
|
|||||||
* (unless you are using a custom autoloader).
|
* (unless you are using a custom autoloader).
|
||||||
*/
|
*/
|
||||||
public function registerClassLoader(){
|
public function registerClassLoader(){
|
||||||
|
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||||
if(!interface_exists("ClassLoader", false)){
|
if(!interface_exists("ClassLoader", false)){
|
||||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||||
}
|
}
|
||||||
if($this->classLoader !== null){
|
if($this->classLoader !== null){
|
||||||
$this->classLoader->register(true);
|
$this->classLoader->register(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||||
ThreadManager::getInstance()->add($this);
|
ThreadManager::getInstance()->add($this);
|
||||||
|
|
||||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,7 +55,7 @@ class Air extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,10 +67,14 @@ class Air extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
public function getBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCollisionBoxes() : array{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ use pocketmine\inventory\AnvilInventory;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
@ -38,14 +39,14 @@ class Anvil extends Fallable{
|
|||||||
|
|
||||||
protected $id = self::ANVIL;
|
protected $id = self::ANVIL;
|
||||||
|
|
||||||
public function isSolid() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isTransparent() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
@ -67,6 +68,30 @@ class Anvil extends Fallable{
|
|||||||
return Tool::TYPE_PICKAXE;
|
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{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$player->addWindow(new AnvilInventory($this));
|
$player->addWindow(new AnvilInventory($this));
|
||||||
|
@ -29,10 +29,6 @@ use pocketmine\item\ItemFactory;
|
|||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Bed as TileBed;
|
use pocketmine\tile\Bed as TileBed;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
@ -58,7 +54,7 @@ class Bed extends Transparent{
|
|||||||
return "Bed Block";
|
return "Bed Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -129,7 +125,7 @@ class Bed extends Transparent{
|
|||||||
/**
|
/**
|
||||||
* @return Bed|null
|
* @return Bed|null
|
||||||
*/
|
*/
|
||||||
public function getOtherHalf(){
|
public function getOtherHalf() : ?Bed{
|
||||||
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
||||||
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
||||||
return $other;
|
return $other;
|
||||||
@ -184,20 +180,8 @@ class Bed extends Transparent{
|
|||||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||||
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||||
|
|
||||||
$nbt = new CompoundTag("", [
|
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
||||||
new StringTag("id", Tile::BED),
|
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
||||||
new ByteTag("color", $item->getDamage() & 0x0f),
|
|
||||||
new IntTag("x", $blockReplace->x),
|
|
||||||
new IntTag("y", $blockReplace->y),
|
|
||||||
new IntTag("z", $blockReplace->z)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nbt2 = clone $nbt;
|
|
||||||
$nbt2["x"] = $next->x;
|
|
||||||
$nbt2["z"] = $next->z;
|
|
||||||
|
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt);
|
|
||||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt2);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -209,7 +193,7 @@ class Bed extends Transparent{
|
|||||||
public function onBreak(Item $item, Player $player = null) : bool{
|
public function onBreak(Item $item, Player $player = null) : bool{
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||||
if(($other = $this->getOtherHalf()) !== null){
|
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;
|
return true;
|
||||||
|
@ -61,7 +61,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
protected $id;
|
protected $id;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
protected $meta = 0;
|
protected $meta = 0;
|
||||||
/** @var string */
|
/** @var string|null */
|
||||||
protected $fallbackName;
|
protected $fallbackName;
|
||||||
/** @var int|null */
|
/** @var int|null */
|
||||||
protected $itemId;
|
protected $itemId;
|
||||||
@ -69,13 +69,17 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/** @var AxisAlignedBB */
|
/** @var AxisAlignedBB */
|
||||||
public $boundingBox = null;
|
public $boundingBox = null;
|
||||||
|
|
||||||
|
|
||||||
|
/** @var AxisAlignedBB[]|null */
|
||||||
|
protected $collisionBoxes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $id The block type's ID, 0-255
|
* @param int $id The block type's ID, 0-255
|
||||||
* @param int $meta Meta value of the block type
|
* @param int $meta Meta value of the block type
|
||||||
* @param string $name English name of the block type (TODO: implement translations)
|
* @param string|null $name English name of the block type (TODO: implement translations)
|
||||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||||
*/
|
*/
|
||||||
public function __construct(int $id, int $meta = 0, string $name = "Unknown", int $itemId = null){
|
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
$this->fallbackName = $name;
|
$this->fallbackName = $name;
|
||||||
@ -86,7 +90,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return $this->fallbackName;
|
return $this->fallbackName ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,7 +120,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* @param int $meta
|
* @param int $meta
|
||||||
*/
|
*/
|
||||||
final public function setDamage(int $meta){
|
final public function setDamage(int $meta) : void{
|
||||||
if($meta < 0 or $meta > 0xf){
|
if($meta < 0 or $meta > 0xf){
|
||||||
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
||||||
}
|
}
|
||||||
@ -136,6 +140,34 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the block meta, stripped of non-variant flags.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getVariant() : int{
|
||||||
|
return $this->meta & $this->getVariantBitmask();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AKA: Block->isPlaceable
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function canBePlaced() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function canBeReplaced() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||||
|
return $blockReplace->canBeReplaced();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||||
*
|
*
|
||||||
@ -163,6 +195,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canBeBrokenWith(Item $item) : bool{
|
||||||
|
return $this->getHardness() !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the actions needed so the block is broken with the Item
|
* Do the actions needed so the block is broken with the Item
|
||||||
*
|
*
|
||||||
@ -175,6 +211,63 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the seconds that this block takes to be broken using an specific Item
|
||||||
|
*
|
||||||
|
* @param Item $item
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public function getBreakTime(Item $item) : float{
|
||||||
|
$base = $this->getHardness() * 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether random block updates will be done on this block.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function ticksRandomly() : bool{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires a block update on the Block
|
* Fires a block update on the Block
|
||||||
*
|
*
|
||||||
@ -266,32 +359,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether random block updates will be done on this block.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function ticksRandomly() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AKA: Block->isPlaceable
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canBePlaced() : bool{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Block|null $with
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -328,7 +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
|
* @param Position $v
|
||||||
*/
|
*/
|
||||||
final public function position(Position $v){
|
final public function position(Position $v) : void{
|
||||||
$this->x = (int) $v->x;
|
$this->x = (int) $v->x;
|
||||||
$this->y = (int) $v->y;
|
$this->y = (int) $v->y;
|
||||||
$this->z = (int) $v->z;
|
$this->z = (int) $v->z;
|
||||||
@ -354,60 +421,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
*/
|
*/
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
return [
|
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
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the time in ticks which the block will fuel a furnace for.
|
* Returns the time in ticks which the block will fuel a furnace for.
|
||||||
* @return int
|
* @return int
|
||||||
@ -432,6 +449,35 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
return BlockFactory::get(Block::AIR, 0, Position::fromObject(Vector3::getSide($side, $step)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getHorizontalSides() : array{
|
||||||
|
return [
|
||||||
|
$this->getSide(Vector3::SIDE_NORTH),
|
||||||
|
$this->getSide(Vector3::SIDE_SOUTH),
|
||||||
|
$this->getSide(Vector3::SIDE_WEST),
|
||||||
|
$this->getSide(Vector3::SIDE_EAST)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the six blocks around this block.
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getAllSides() : array{
|
||||||
|
return array_merge(
|
||||||
|
[
|
||||||
|
$this->getSide(Vector3::SIDE_DOWN),
|
||||||
|
$this->getSide(Vector3::SIDE_UP)
|
||||||
|
],
|
||||||
|
$this->getHorizontalSides()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -447,22 +493,50 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||||
$bb2 = $this->getBoundingBox();
|
$bbs = $this->getCollisionBoxes();
|
||||||
|
|
||||||
return $bb2 !== null and $bb->intersectsWith($bb2);
|
foreach($bbs as $bb2){
|
||||||
|
if($bb->intersectsWith($bb2)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Entity $entity
|
* @param Entity $entity
|
||||||
*/
|
*/
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AxisAlignedBB[]
|
||||||
|
*/
|
||||||
|
public function getCollisionBoxes() : array{
|
||||||
|
if($this->collisionBoxes === null){
|
||||||
|
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->collisionBoxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AxisAlignedBB[]
|
||||||
|
*/
|
||||||
|
protected function recalculateCollisionBoxes() : array{
|
||||||
|
if($bb = $this->recalculateBoundingBox()){
|
||||||
|
return [$bb];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return AxisAlignedBB|null
|
* @return AxisAlignedBB|null
|
||||||
*/
|
*/
|
||||||
public function getBoundingBox(){
|
public function getBoundingBox() : ?AxisAlignedBB{
|
||||||
if($this->boundingBox === null){
|
if($this->boundingBox === null){
|
||||||
$this->boundingBox = $this->recalculateBoundingBox();
|
$this->boundingBox = $this->recalculateBoundingBox();
|
||||||
}
|
}
|
||||||
@ -472,7 +546,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
/**
|
/**
|
||||||
* @return AxisAlignedBB|null
|
* @return AxisAlignedBB|null
|
||||||
*/
|
*/
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -483,92 +557,52 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears any cached precomputed bounding boxes. This is called on block neighbour update and when the block is set
|
||||||
|
* into the world to remove any outdated precomputed AABBs and force recalculation.
|
||||||
|
*/
|
||||||
|
public function clearBoundingBoxes() : void{
|
||||||
|
$this->boundingBox = null;
|
||||||
|
$this->collisionBoxes = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Vector3 $pos1
|
* @param Vector3 $pos1
|
||||||
* @param Vector3 $pos2
|
* @param Vector3 $pos2
|
||||||
*
|
*
|
||||||
* @return MovingObjectPosition|null
|
* @return MovingObjectPosition|null
|
||||||
*/
|
*/
|
||||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){
|
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
|
||||||
$bb = $this->getBoundingBox();
|
$bbs = $this->getCollisionBoxes();
|
||||||
if($bb === null){
|
if(empty($bbs)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX);
|
/** @var MovingObjectPosition|null $currentHit */
|
||||||
$v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX);
|
$currentHit = null;
|
||||||
$v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY);
|
/** @var int|float $currentDistance */
|
||||||
$v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY);
|
$currentDistance = PHP_INT_MAX;
|
||||||
$v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ);
|
|
||||||
$v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ);
|
|
||||||
|
|
||||||
if($v1 !== null and !$bb->isVectorInYZ($v1)){
|
foreach($bbs as $bb){
|
||||||
$v1 = null;
|
$nextHit = $bb->calculateIntercept($pos1, $pos2);
|
||||||
|
if($nextHit === null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
|
||||||
|
if($nextDistance < $currentDistance){
|
||||||
|
$currentHit = $nextHit;
|
||||||
|
$currentDistance = $nextDistance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($v2 !== null and !$bb->isVectorInYZ($v2)){
|
if($currentHit !== null){
|
||||||
$v2 = null;
|
$currentHit->blockX = $this->x;
|
||||||
|
$currentHit->blockY = $this->y;
|
||||||
|
$currentHit->blockZ = $this->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($v3 !== null and !$bb->isVectorInXZ($v3)){
|
return $currentHit;
|
||||||
$v3 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v4 !== null and !$bb->isVectorInXZ($v4)){
|
|
||||||
$v4 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v5 !== null and !$bb->isVectorInXY($v5)){
|
|
||||||
$v5 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v6 !== null and !$bb->isVectorInXY($v6)){
|
|
||||||
$v6 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$vector = $v1;
|
|
||||||
|
|
||||||
if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){
|
|
||||||
$vector = $v6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($vector === null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$f = -1;
|
|
||||||
|
|
||||||
if($vector === $v1){
|
|
||||||
$f = 4;
|
|
||||||
}elseif($vector === $v2){
|
|
||||||
$f = 5;
|
|
||||||
}elseif($vector === $v3){
|
|
||||||
$f = 0;
|
|
||||||
}elseif($vector === $v4){
|
|
||||||
$f = 1;
|
|
||||||
}elseif($vector === $v5){
|
|
||||||
$f = 2;
|
|
||||||
}elseif($vector === $v6){
|
|
||||||
$f = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||||
|
@ -56,7 +56,7 @@ class BlockFactory{
|
|||||||
*
|
*
|
||||||
* @param bool $force
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public static function init(bool $force = false){
|
public static function init(bool $force = false) : void{
|
||||||
if(self::$list === null or $force){
|
if(self::$list === null or $force){
|
||||||
self::$list = new \SplFixedArray(256);
|
self::$list = new \SplFixedArray(256);
|
||||||
self::$fullList = new \SplFixedArray(4096);
|
self::$fullList = new \SplFixedArray(4096);
|
||||||
@ -133,7 +133,7 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Furnace());
|
self::registerBlock(new Furnace());
|
||||||
self::registerBlock(new BurningFurnace());
|
self::registerBlock(new BurningFurnace());
|
||||||
self::registerBlock(new SignPost());
|
self::registerBlock(new SignPost());
|
||||||
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door Block", Item::OAK_DOOR));
|
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
|
||||||
self::registerBlock(new Ladder());
|
self::registerBlock(new Ladder());
|
||||||
self::registerBlock(new Rail());
|
self::registerBlock(new Rail());
|
||||||
self::registerBlock(new CobblestoneStairs());
|
self::registerBlock(new CobblestoneStairs());
|
||||||
@ -153,8 +153,8 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Cactus());
|
self::registerBlock(new Cactus());
|
||||||
self::registerBlock(new Clay());
|
self::registerBlock(new Clay());
|
||||||
self::registerBlock(new Sugarcane());
|
self::registerBlock(new Sugarcane());
|
||||||
|
//TODO: JUKEBOX
|
||||||
self::registerBlock(new Fence());
|
self::registerBlock(new WoodenFence());
|
||||||
self::registerBlock(new Pumpkin());
|
self::registerBlock(new Pumpkin());
|
||||||
self::registerBlock(new Netherrack());
|
self::registerBlock(new Netherrack());
|
||||||
self::registerBlock(new SoulSand());
|
self::registerBlock(new SoulSand());
|
||||||
@ -168,8 +168,8 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Trapdoor());
|
self::registerBlock(new Trapdoor());
|
||||||
//TODO: MONSTER_EGG
|
//TODO: MONSTER_EGG
|
||||||
self::registerBlock(new StoneBricks());
|
self::registerBlock(new StoneBricks());
|
||||||
//TODO: BROWN_MUSHROOM_BLOCK
|
self::registerBlock(new BrownMushroomBlock());
|
||||||
//TODO: RED_MUSHROOM_BLOCK
|
self::registerBlock(new RedMushroomBlock());
|
||||||
self::registerBlock(new IronBars());
|
self::registerBlock(new IronBars());
|
||||||
self::registerBlock(new GlassPane());
|
self::registerBlock(new GlassPane());
|
||||||
self::registerBlock(new Melon());
|
self::registerBlock(new Melon());
|
||||||
@ -245,12 +245,13 @@ class BlockFactory{
|
|||||||
self::registerBlock(new Coal());
|
self::registerBlock(new Coal());
|
||||||
self::registerBlock(new PackedIce());
|
self::registerBlock(new PackedIce());
|
||||||
self::registerBlock(new DoublePlant());
|
self::registerBlock(new DoublePlant());
|
||||||
|
//TODO: STANDING_BANNER
|
||||||
|
//TODO: WALL_BANNER
|
||||||
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
||||||
//TODO: RED_SANDSTONE
|
self::registerBlock(new RedSandstone());
|
||||||
//TODO: RED_SANDSTONE_STAIRS
|
self::registerBlock(new RedSandstoneStairs());
|
||||||
//TODO: DOUBLE_STONE_SLAB2
|
self::registerBlock(new DoubleStoneSlab2());
|
||||||
//TODO: STONE_SLAB2
|
self::registerBlock(new StoneSlab2());
|
||||||
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
|
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
|
||||||
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
|
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
|
||||||
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
||||||
@ -259,19 +260,20 @@ class BlockFactory{
|
|||||||
//TODO: REPEATING_COMMAND_BLOCK
|
//TODO: REPEATING_COMMAND_BLOCK
|
||||||
//TODO: CHAIN_COMMAND_BLOCK
|
//TODO: CHAIN_COMMAND_BLOCK
|
||||||
|
|
||||||
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door Block", Item::SPRUCE_DOOR));
|
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door Block", Item::BIRCH_DOOR));
|
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door", Item::BIRCH_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door Block", Item::JUNGLE_DOOR));
|
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door", Item::JUNGLE_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door Block", Item::ACACIA_DOOR));
|
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door", Item::ACACIA_DOOR));
|
||||||
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door Block", Item::DARK_OAK_DOOR));
|
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door", Item::DARK_OAK_DOOR));
|
||||||
self::registerBlock(new GrassPath());
|
self::registerBlock(new GrassPath());
|
||||||
self::registerBlock(new ItemFrame());
|
self::registerBlock(new ItemFrame());
|
||||||
//TODO: CHORUS_FLOWER
|
//TODO: CHORUS_FLOWER
|
||||||
//TODO: PURPUR_BLOCK
|
self::registerBlock(new Purpur());
|
||||||
|
|
||||||
//TODO: PURPUR_STAIRS
|
self::registerBlock(new PurpurStairs());
|
||||||
|
|
||||||
//TODO: END_BRICKS
|
//TODO: UNDYED_SHULKER_BOX
|
||||||
|
self::registerBlock(new EndStoneBricks());
|
||||||
//TODO: FROSTED_ICE
|
//TODO: FROSTED_ICE
|
||||||
self::registerBlock(new EndRod());
|
self::registerBlock(new EndRod());
|
||||||
//TODO: END_GATEWAY
|
//TODO: END_GATEWAY
|
||||||
@ -300,7 +302,7 @@ class BlockFactory{
|
|||||||
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
|
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
|
||||||
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
||||||
self::registerBlock(new Concrete());
|
self::registerBlock(new Concrete());
|
||||||
//TODO: CONCRETEPOWDER
|
self::registerBlock(new ConcretePowder());
|
||||||
|
|
||||||
//TODO: CHORUS_PLANT
|
//TODO: CHORUS_PLANT
|
||||||
self::registerBlock(new StainedGlass());
|
self::registerBlock(new StainedGlass());
|
||||||
@ -314,6 +316,7 @@ class BlockFactory{
|
|||||||
//TODO: INFO_UPDATE2
|
//TODO: INFO_UPDATE2
|
||||||
//TODO: MOVINGBLOCK
|
//TODO: MOVINGBLOCK
|
||||||
//TODO: OBSERVER
|
//TODO: OBSERVER
|
||||||
|
//TODO: STRUCTURE_BLOCK
|
||||||
|
|
||||||
//TODO: RESERVED6
|
//TODO: RESERVED6
|
||||||
|
|
||||||
@ -338,10 +341,10 @@ class BlockFactory{
|
|||||||
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
||||||
* $override parameter.
|
* $override parameter.
|
||||||
*/
|
*/
|
||||||
public static function registerBlock(Block $block, bool $override = false){
|
public static function registerBlock(Block $block, bool $override = false) : void{
|
||||||
$id = $block->getId();
|
$id = $block->getId();
|
||||||
|
|
||||||
if(self::$list[$id] !== null and !(self::$list[$id] instanceof UnknownBlock) and !$override){
|
if(!$override and self::isRegistered($id)){
|
||||||
throw new \RuntimeException("Trying to overwrite an already registered block");
|
throw new \RuntimeException("Trying to overwrite an already registered block");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,4 +406,15 @@ class BlockFactory{
|
|||||||
public static function getBlockStatesArray() : \SplFixedArray{
|
public static function getBlockStatesArray() : \SplFixedArray{
|
||||||
return self::$fullList;
|
return self::$fullList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a specified block ID is already registered in the block factory.
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isRegistered(int $id) : bool{
|
||||||
|
$b = self::$list[$id];
|
||||||
|
return $b !== null and !($b instanceof UnknownBlock);
|
||||||
|
}
|
||||||
}
|
}
|
@ -109,7 +109,7 @@ interface BlockIds{
|
|||||||
const CACTUS = 81;
|
const CACTUS = 81;
|
||||||
const CLAY_BLOCK = 82;
|
const CLAY_BLOCK = 82;
|
||||||
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
||||||
|
const JUKEBOX = 84;
|
||||||
const FENCE = 85;
|
const FENCE = 85;
|
||||||
const PUMPKIN = 86;
|
const PUMPKIN = 86;
|
||||||
const NETHERRACK = 87;
|
const NETHERRACK = 87;
|
||||||
@ -201,7 +201,8 @@ interface BlockIds{
|
|||||||
const COAL_BLOCK = 173;
|
const COAL_BLOCK = 173;
|
||||||
const PACKED_ICE = 174;
|
const PACKED_ICE = 174;
|
||||||
const DOUBLE_PLANT = 175;
|
const DOUBLE_PLANT = 175;
|
||||||
|
const STANDING_BANNER = 176;
|
||||||
|
const WALL_BANNER = 177;
|
||||||
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
||||||
const RED_SANDSTONE = 179;
|
const RED_SANDSTONE = 179;
|
||||||
const RED_SANDSTONE_STAIRS = 180;
|
const RED_SANDSTONE_STAIRS = 180;
|
||||||
@ -227,6 +228,7 @@ interface BlockIds{
|
|||||||
|
|
||||||
const PURPUR_STAIRS = 203;
|
const PURPUR_STAIRS = 203;
|
||||||
|
|
||||||
|
const UNDYED_SHULKER_BOX = 205;
|
||||||
const END_BRICKS = 206;
|
const END_BRICKS = 206;
|
||||||
const FROSTED_ICE = 207;
|
const FROSTED_ICE = 207;
|
||||||
const END_ROD = 208;
|
const END_ROD = 208;
|
||||||
@ -270,6 +272,7 @@ interface BlockIds{
|
|||||||
const INFO_UPDATE2 = 249;
|
const INFO_UPDATE2 = 249;
|
||||||
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
||||||
const OBSERVER = 251;
|
const OBSERVER = 251;
|
||||||
|
const STRUCTURE_BLOCK = 252;
|
||||||
|
|
||||||
const RESERVED6 = 255;
|
const RESERVED6 = 255;
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class BoneBlock extends Solid{
|
|||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||||
return parent::getDrops($item); // TODO: Change the autogenerated stub
|
return parent::getDrops($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
@ -21,18 +21,21 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\block\BlockFactory;
|
|
||||||
|
|
||||||
class IronDoor extends Item{
|
class BrownMushroomBlock extends RedMushroomBlock{
|
||||||
public function __construct(int $meta = 0){
|
|
||||||
$this->block = BlockFactory::get(Block::IRON_DOOR_BLOCK);
|
protected $id = Block::BROWN_MUSHROOM_BLOCK;
|
||||||
parent::__construct(self::IRON_DOOR, $meta, "Iron Door");
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Brown Mushroom Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMaxStackSize() : int{
|
public function getDrops(Item $item) : array{
|
||||||
return 1;
|
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\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\NBT;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Furnace as TileFurnace;
|
use pocketmine\tile\Furnace as TileFurnace;
|
||||||
@ -68,26 +64,8 @@ class BurningFurnace extends Solid{
|
|||||||
];
|
];
|
||||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::FURNACE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -96,15 +74,7 @@ class BurningFurnace extends Solid{
|
|||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$furnace = $this->getLevel()->getTile($this);
|
$furnace = $this->getLevel()->getTile($this);
|
||||||
if(!($furnace instanceof TileFurnace)){
|
if(!($furnace instanceof TileFurnace)){
|
||||||
$nbt = new CompoundTag("", [
|
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::FURNACE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
$furnace = Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
||||||
|
@ -21,14 +21,31 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\block\BlockFactory;
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
abstract class Button extends Flowable{
|
||||||
|
|
||||||
class Skull extends Item{
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->block = BlockFactory::get(Block::SKULL_BLOCK);
|
$this->meta = $meta;
|
||||||
parent::__construct(self::SKULL, $meta, "Mob Head");
|
}
|
||||||
|
|
||||||
|
public function getVariantBitmask() : int{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||||
|
//TODO: check valid target block
|
||||||
|
$this->meta = $face;
|
||||||
|
|
||||||
|
return $this->level->setBlock($this, $this, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
|
//TODO
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -54,7 +54,7 @@ class Cactus extends Transparent{
|
|||||||
return "Cactus";
|
return "Cactus";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
@ -70,7 +70,7 @@ class Cactus extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ class Cactus extends Transparent{
|
|||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||||
if($this->meta === 0x0f){
|
if($this->meta === 0x0f){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
|
@ -48,7 +48,7 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
return "Cake Block";
|
return "Cake Block";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f = $this->getDamage() * 0.125; //1 slice width
|
$f = $this->getDamage() * 0.125; //1 slice width
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class Carpet extends Flowable{
|
|||||||
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -27,10 +27,6 @@ use pocketmine\item\Item;
|
|||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\NBT;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Chest as TileChest;
|
use pocketmine\tile\Chest as TileChest;
|
||||||
@ -56,7 +52,7 @@ class Chest extends Transparent{
|
|||||||
return Tool::TYPE_AXE;
|
return Tool::TYPE_AXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -95,26 +91,7 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::CHEST),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tile = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||||
$chest->pairWith($tile);
|
$chest->pairWith($tile);
|
||||||
@ -142,15 +119,7 @@ class Chest extends Transparent{
|
|||||||
if($t instanceof TileChest){
|
if($t instanceof TileChest){
|
||||||
$chest = $t;
|
$chest = $t;
|
||||||
}else{
|
}else{
|
||||||
$nbt = new CompoundTag("", [
|
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
||||||
new ListTag("Items", []),
|
|
||||||
new StringTag("id", Tile::CHEST),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
|
||||||
$chest = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
|
@ -37,10 +37,6 @@ class CobblestoneWall extends Transparent{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSolid() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_PICKAXE;
|
return Tool::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
@ -57,38 +53,38 @@ class CobblestoneWall extends Transparent{
|
|||||||
return "Cobblestone Wall";
|
return "Cobblestone Wall";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
//walls don't have any special collision boxes like fences do
|
||||||
|
|
||||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||||
|
|
||||||
$n = $north ? 0 : 0.25;
|
$inset = 0.25;
|
||||||
$s = $south ? 1 : 0.75;
|
if(
|
||||||
$w = $west ? 0 : 0.25;
|
$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
|
||||||
$e = $east ? 1 : 0.75;
|
(
|
||||||
|
($north and $south and !$west and !$east) or
|
||||||
if($north and $south and !$west and !$east){
|
(!$north and !$south and $west and $east)
|
||||||
$w = 0.3125;
|
)
|
||||||
$e = 0.6875;
|
){
|
||||||
}elseif(!$north and !$south and $west and $east){
|
//If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner
|
||||||
$n = 0.3125;
|
$inset = 0.3125;
|
||||||
$s = 0.6875;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $w,
|
$this->x + ($west ? 0 : $inset),
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $n,
|
$this->z + ($north ? 0 : $inset),
|
||||||
$this->x + $e,
|
$this->x + 1 - ($east ? 0 : $inset),
|
||||||
$this->y + 1.5,
|
$this->y + 1.5,
|
||||||
$this->z + $s
|
$this->z + 1 - ($south ? 0 : $inset)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canConnect(Block $block){
|
public function canConnect(Block $block){
|
||||||
return ($block->getId() !== self::COBBLESTONE_WALL and $block->getId() !== self::FENCE_GATE) ? $block->isSolid() and !$block->isTransparent() : true;
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class Cobweb extends Flowable{
|
|||||||
return Tool::TYPE_SWORD;
|
return Tool::TYPE_SWORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->resetFallDistance();
|
$entity->resetFallDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
class CocoaBlock extends Solid{
|
class CocoaBlock extends Transparent{
|
||||||
|
|
||||||
protected $id = self::COCOA_BLOCK;
|
protected $id = self::COCOA_BLOCK;
|
||||||
|
|
||||||
|
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;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\inventory\BigCraftingGrid;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -49,6 +50,7 @@ class CraftingTable extends Solid{
|
|||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
|
$player->setCraftingGrid(new BigCraftingGrid($player));
|
||||||
$player->craftingType = 1;
|
$player->craftingType = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemFactory;
|
||||||
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
@ -38,7 +41,6 @@ class DeadBush extends Flowable{
|
|||||||
return "Dead Bush";
|
return "Dead Bush";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
||||||
@ -51,4 +53,17 @@ class DeadBush extends Flowable{
|
|||||||
return false;
|
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{
|
public function getName() : string{
|
||||||
|
if($this->meta === 1){
|
||||||
|
return "Coarse Dirt";
|
||||||
|
}
|
||||||
return "Dirt";
|
return "Dirt";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($item->isHoe()){
|
if($item->isHoe()){
|
||||||
$item->useOn($this);
|
$item->useOn($this);
|
||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND, 0), true);
|
if($this->meta === 1){
|
||||||
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
|
}else{
|
||||||
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ abstract class Door extends Transparent{
|
|||||||
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f = 0.1875;
|
$f = 0.1875;
|
||||||
$damage = $this->getFullDamage();
|
$damage = $this->getFullDamage();
|
||||||
|
@ -38,7 +38,7 @@ class DoublePlant extends Flowable{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return $this->meta === 2 or $this->meta === 3; //grass or fern
|
return $this->meta === 2 or $this->meta === 3; //grass or fern
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class DoublePlant extends Flowable{
|
|||||||
4 => "Rose Bush",
|
4 => "Rose Bush",
|
||||||
5 => "Peony"
|
5 => "Peony"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x07] ?? "";
|
return $names[$this->getVariant()] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||||
@ -79,7 +79,7 @@ class DoublePlant extends Flowable{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
$other->getId() === $this->getId() and
|
$other->getId() === $this->getId() and
|
||||||
($other->getDamage() & 0x07) === ($this->getDamage() & 0x07) and
|
$other->getVariant() === $this->getVariant() and
|
||||||
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
|
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,14 +21,27 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\block\BlockFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
|
|
||||||
|
abstract class DoubleSlab extends Solid{
|
||||||
|
|
||||||
class ItemFrame extends Item{
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->block = BlockFactory::get(Block::ITEM_FRAME_BLOCK);
|
$this->meta = $meta;
|
||||||
parent::__construct(self::ITEM_FRAME, $meta, "Item Frame");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class DoubleStoneSlab extends Solid{
|
class DoubleStoneSlab extends DoubleSlab{
|
||||||
|
|
||||||
protected $id = self::DOUBLE_STONE_SLAB;
|
protected $id = self::DOUBLE_STONE_SLAB;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function getSlabId() : int{
|
||||||
$this->meta = $meta;
|
return self::STONE_SLAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -43,25 +42,9 @@ class DoubleStoneSlab extends Solid{
|
|||||||
return Tool::TYPE_PICKAXE;
|
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{
|
public function getDrops(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||||
return [
|
return parent::getDrops($item);
|
||||||
ItemFactory::get(Item::STONE_SLAB, $this->getDamage() & 0x07, 2)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
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;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class DoubleWoodenSlab extends Solid{
|
class DoubleWoodenSlab extends DoubleSlab{
|
||||||
|
|
||||||
protected $id = self::DOUBLE_WOODEN_SLAB;
|
protected $id = self::DOUBLE_WOODEN_SLAB;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function getSlabId() : int{
|
||||||
$this->meta = $meta;
|
return self::WOODEN_SLAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
@ -42,23 +40,4 @@ class DoubleWoodenSlab extends Solid{
|
|||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
return Tool::TYPE_AXE;
|
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\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\tile\EnchantTable as TileEnchantTable;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
class EnchantingTable extends Transparent{
|
class EnchantingTable extends Transparent{
|
||||||
@ -43,24 +41,8 @@ class EnchantingTable 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 $facePos, Player $player = null) : bool{
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new StringTag("id", Tile::ENCHANT_TABLE),
|
|
||||||
new IntTag("x", $this->x),
|
|
||||||
new IntTag("y", $this->y),
|
|
||||||
new IntTag("z", $this->z)
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($item->hasCustomName()){
|
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), $nbt);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class EndPortalFrame extends Solid{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -61,7 +61,7 @@ class EndRod extends Flowable{
|
|||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
$m = $this->meta & ~0x01;
|
$m = $this->meta & ~0x01;
|
||||||
$width = 0.375;
|
$width = 0.375;
|
||||||
|
|
||||||
|
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 [];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,41 +26,32 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\DoubleTag;
|
|
||||||
use pocketmine\nbt\tag\FloatTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
|
|
||||||
abstract class Fallable extends Solid{
|
abstract class Fallable extends Solid{
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
if($down->getId() === self::AIR or ($down instanceof Liquid)){
|
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
|
||||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), new CompoundTag("", [
|
|
||||||
new ListTag("Pos", [
|
|
||||||
new DoubleTag("", $this->x + 0.5),
|
|
||||||
new DoubleTag("", $this->y),
|
|
||||||
new DoubleTag("", $this->z + 0.5)
|
|
||||||
]),
|
|
||||||
new ListTag("Motion", [
|
|
||||||
new DoubleTag("", 0),
|
|
||||||
new DoubleTag("", 0),
|
|
||||||
new DoubleTag("", 0)
|
|
||||||
]),
|
|
||||||
new ListTag("Rotation", [
|
|
||||||
new FloatTag("", 0),
|
|
||||||
new FloatTag("", 0)
|
|
||||||
]),
|
|
||||||
new IntTag("TileID", $this->getId()),
|
|
||||||
new ByteTag("Data", $this->getDamage())
|
|
||||||
]));
|
|
||||||
|
|
||||||
$fall->spawnToAll();
|
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
|
||||||
|
$nbt->setInt("TileID", $this->getId());
|
||||||
|
$nbt->setByte("Data", $this->getDamage());
|
||||||
|
|
||||||
|
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
|
||||||
|
|
||||||
|
if($fall !== null){
|
||||||
|
$fall->spawnToAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null|Block
|
||||||
|
*/
|
||||||
|
public function tickFalling() : ?Block{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
@ -28,6 +28,7 @@ use pocketmine\item\ItemFactory;
|
|||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class Farmland extends Transparent{
|
class Farmland extends Transparent{
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ class Farmland extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -65,8 +66,43 @@ class Farmland extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_RANDOM){
|
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||||
//TODO: hydration
|
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||||
|
return $type;
|
||||||
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||||
|
if(!$this->canHydrate()){
|
||||||
|
if($this->meta > 0){
|
||||||
|
$this->meta--;
|
||||||
|
$this->level->setBlock($this, $this, false, false);
|
||||||
|
}else{
|
||||||
|
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}elseif($this->meta < 7){
|
||||||
|
$this->meta = 7;
|
||||||
|
$this->level->setBlock($this, $this, false, false);
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return false;
|
||||||
|
@ -23,73 +23,87 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Tool;
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class Fence extends Transparent{
|
abstract class Fence extends Transparent{
|
||||||
const FENCE_OAK = 0;
|
|
||||||
const FENCE_SPRUCE = 1;
|
|
||||||
const FENCE_BIRCH = 2;
|
|
||||||
const FENCE_JUNGLE = 3;
|
|
||||||
const FENCE_ACACIA = 4;
|
|
||||||
const FENCE_DARKOAK = 5;
|
|
||||||
|
|
||||||
protected $id = self::FENCE;
|
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getThickness() : float{
|
||||||
return 2;
|
return 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return Tool::TYPE_AXE;
|
$width = 0.5 - $this->getThickness() / 2;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function getName() : string{
|
|
||||||
static $names = [
|
|
||||||
self::FENCE_OAK => "Oak Fence",
|
|
||||||
self::FENCE_SPRUCE => "Spruce Fence",
|
|
||||||
self::FENCE_BIRCH => "Birch Fence",
|
|
||||||
self::FENCE_JUNGLE => "Jungle Fence",
|
|
||||||
self::FENCE_ACACIA => "Acacia Fence",
|
|
||||||
self::FENCE_DARKOAK => "Dark Oak Fence"
|
|
||||||
];
|
|
||||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
|
||||||
|
|
||||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
|
||||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
|
||||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
|
||||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
|
||||||
|
|
||||||
$n = $north ? 0 : 0.375;
|
|
||||||
$s = $south ? 1 : 0.625;
|
|
||||||
$w = $west ? 0 : 0.375;
|
|
||||||
$e = $east ? 1 : 0.625;
|
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $w,
|
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $n,
|
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||||
$this->x + $e,
|
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||||
$this->y + 1.5,
|
$this->y + 1.5,
|
||||||
$this->z + $s
|
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canConnect(Block $block){
|
protected function recalculateCollisionBoxes() : array{
|
||||||
return ($block instanceof Fence or $block instanceof FenceGate) ? true : $block->isSolid() and !$block->isTransparent();
|
$inset = 0.5 - $this->getThickness() / 2;
|
||||||
|
|
||||||
|
/** @var AxisAlignedBB[] $bbs */
|
||||||
|
$bbs = [];
|
||||||
|
|
||||||
|
$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||||
|
$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||||
|
|
||||||
|
if($connectWest or $connectEast){
|
||||||
|
//X axis (west/east)
|
||||||
|
$bbs[] = new AxisAlignedBB(
|
||||||
|
$this->x + ($connectWest ? 0 : $inset),
|
||||||
|
$this->y,
|
||||||
|
$this->z + $inset,
|
||||||
|
$this->x + 1 - ($connectEast ? 0 : $inset),
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||||
|
$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||||
|
|
||||||
|
if($connectNorth or $connectSouth){
|
||||||
|
//Z axis (north/south)
|
||||||
|
$bbs[] = new AxisAlignedBB(
|
||||||
|
$this->x + $inset,
|
||||||
|
$this->y,
|
||||||
|
$this->z + ($connectNorth ? 0 : $inset),
|
||||||
|
$this->x + 1 - $inset,
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - ($connectSouth ? 0 : $inset)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($bbs)){
|
||||||
|
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||||
|
return [
|
||||||
|
new AxisAlignedBB(
|
||||||
|
$this->x + $inset,
|
||||||
|
$this->y,
|
||||||
|
$this->z + $inset,
|
||||||
|
$this->x + 1 - $inset,
|
||||||
|
$this->y + 1.5,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
public function canConnect(Block $block){
|
||||||
return 300;
|
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class FenceGate extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
if(($this->getDamage() & 0x04) > 0){
|
if(($this->getDamage() & 0x04) > 0){
|
||||||
return null;
|
return null;
|
||||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\entity\Arrow;
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\projectile\Arrow;
|
||||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
@ -57,7 +57,7 @@ class Fire extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class Fire extends Flowable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
abstract class Flowable extends Transparent{
|
abstract class Flowable extends Transparent{
|
||||||
|
|
||||||
public function canBeFlowedInto() : bool{
|
public function canBeFlowedInto() : bool{
|
||||||
@ -33,15 +35,11 @@ abstract class Flowable extends Transparent{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBlastResistance() : float{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isSolid() : bool{
|
public function isSolid() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,14 +24,9 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\ShortTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\FlowerPot as TileFlowerPot;
|
use pocketmine\tile\FlowerPot as TileFlowerPot;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
@ -49,10 +44,10 @@ class FlowerPot extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Flower Pot Block";
|
return "Flower Pot";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.3125,
|
$this->x + 0.3125,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -69,23 +64,7 @@ class FlowerPot extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||||
$nbt = new CompoundTag("", [
|
|
||||||
new StringTag("id", Tile::FLOWER_POT),
|
|
||||||
new IntTag("x", $blockReplace->x),
|
|
||||||
new IntTag("y", $blockReplace->y),
|
|
||||||
new IntTag("z", $blockReplace->z),
|
|
||||||
new ShortTag("item", 0),
|
|
||||||
new IntTag("mData", 0)
|
|
||||||
]);
|
|
||||||
|
|
||||||
if($item->hasCustomBlockData()){
|
|
||||||
foreach($item->getCustomBlockData() as $key => $v){
|
|
||||||
$nbt->{$key} = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), $nbt);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,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->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
|
||||||
$this->getLevel()->setBlock($this, $this, true, false);
|
$this->getLevel()->setBlock($this, $this, true, false);
|
||||||
$pot->setItem($item);
|
$pot->setItem($item->pop());
|
||||||
|
|
||||||
if($player instanceof Player){
|
|
||||||
if($player->isSurvival()){
|
|
||||||
$item->setCount($item->getCount() - 1);
|
|
||||||
$player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : ItemFactory::get(Item::AIR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,22 +76,22 @@ class Grass extends Solid{
|
|||||||
return Level::BLOCK_UPDATE_RANDOM;
|
return Level::BLOCK_UPDATE_RANDOM;
|
||||||
}elseif($lightAbove >= 9){
|
}elseif($lightAbove >= 9){
|
||||||
//try grass spread
|
//try grass spread
|
||||||
$vector = $this->asVector3();
|
|
||||||
for($i = 0; $i < 4; ++$i){
|
for($i = 0; $i < 4; ++$i){
|
||||||
$vector->x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$vector->y = mt_rand($this->y - 3, $this->y + 1);
|
$y = mt_rand($this->y - 3, $this->y + 1);
|
||||||
$vector->z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
if(
|
if(
|
||||||
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or
|
$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
|
||||||
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or
|
$this->level->getBlockDataAt($x, $y, $z) === 1 or
|
||||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3
|
$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
|
||||||
|
BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
|
||||||
){
|
){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this->level->getBlock($vector), $this, BlockFactory::get(Block::GRASS)));
|
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$this->level->setBlock($vector, $ev->getNewState(), false, false);
|
$this->level->setBlock($b, $ev->getNewState(), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,9 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class GrassPath extends Transparent{
|
class GrassPath extends Transparent{
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ class GrassPath extends Transparent{
|
|||||||
return Tool::TYPE_SHOVEL;
|
return Tool::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -59,6 +61,15 @@ class GrassPath extends Transparent{
|
|||||||
return 0.6;
|
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{
|
public function getDrops(Item $item) : array{
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::DIRT, 0, 1)
|
ItemFactory::get(Item::DIRT, 0, 1)
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\block\utils\PillarRotationHelper;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -44,16 +45,7 @@ class HayBale extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 $facePos, Player $player = null) : bool{
|
||||||
$faces = [
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
0 => 0,
|
|
||||||
1 => 0,
|
|
||||||
2 => 0b1000,
|
|
||||||
3 => 0b1000,
|
|
||||||
4 => 0b0100,
|
|
||||||
5 => 0b0100
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->meta = ($this->meta & 0x03) | $faces[$face];
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -37,7 +37,7 @@ class IronDoor extends Door{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Iron Door Block";
|
return "Iron Door";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
|
@ -24,12 +24,8 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\{
|
|
||||||
ByteTag, CompoundTag, FloatTag, IntTag, StringTag
|
|
||||||
};
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\ItemFrame as TileItemFrame;
|
use pocketmine\tile\ItemFrame as TileItemFrame;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
@ -50,29 +46,13 @@ class ItemFrame extends Flowable{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
$tile = $this->level->getTile($this);
|
$tile = $this->level->getTile($this);
|
||||||
if(!($tile instanceof TileItemFrame)){
|
if(!($tile instanceof TileItemFrame)){
|
||||||
$nbt = new CompoundTag("", [
|
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($tile->hasItem()){
|
if($tile->hasItem()){
|
||||||
$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
|
$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
|
||||||
}else{
|
}elseif(!$item->isNull()){
|
||||||
if($item->getCount() > 0){
|
$tile->setItem($item->pop());
|
||||||
$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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -92,10 +72,10 @@ class ItemFrame extends Flowable{
|
|||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$sides = [
|
$sides = [
|
||||||
0 => 4,
|
0 => Vector3::SIDE_WEST,
|
||||||
1 => 5,
|
1 => Vector3::SIDE_EAST,
|
||||||
2 => 2,
|
2 => Vector3::SIDE_NORTH,
|
||||||
3 => 3
|
3 => Vector3::SIDE_SOUTH
|
||||||
];
|
];
|
||||||
if(!$this->getSide($sides[$this->meta])->isSolid()){
|
if(!$this->getSide($sides[$this->meta])->isSolid()){
|
||||||
$this->level->useBreakOn($this);
|
$this->level->useBreakOn($this);
|
||||||
@ -120,22 +100,7 @@ class ItemFrame extends Flowable{
|
|||||||
$this->meta = $faces[$face];
|
$this->meta = $faces[$face];
|
||||||
$this->level->setBlock($blockReplace, $this, true, true);
|
$this->level->setBlock($blockReplace, $this, true, true);
|
||||||
|
|
||||||
$nbt = new CompoundTag("", [
|
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||||
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);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -59,54 +59,35 @@ class Ladder extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->resetFallDistance();
|
$entity->resetFallDistance();
|
||||||
$entity->onGround = true;
|
$entity->onGround = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f = 0.1875;
|
$f = 0.1875;
|
||||||
|
|
||||||
|
$minX = $minZ = 0;
|
||||||
|
$maxX = $maxZ = 1;
|
||||||
|
|
||||||
if($this->meta === 2){
|
if($this->meta === 2){
|
||||||
return new AxisAlignedBB(
|
$minZ = 1 - $f;
|
||||||
$this->x,
|
|
||||||
$this->y,
|
|
||||||
$this->z + 1 - $f,
|
|
||||||
$this->x + 1,
|
|
||||||
$this->y + 1,
|
|
||||||
$this->z + 1
|
|
||||||
);
|
|
||||||
}elseif($this->meta === 3){
|
}elseif($this->meta === 3){
|
||||||
return new AxisAlignedBB(
|
$maxZ = $f;
|
||||||
$this->x,
|
|
||||||
$this->y,
|
|
||||||
$this->z,
|
|
||||||
$this->x + 1,
|
|
||||||
$this->y + 1,
|
|
||||||
$this->z + $f
|
|
||||||
);
|
|
||||||
}elseif($this->meta === 4){
|
}elseif($this->meta === 4){
|
||||||
return new AxisAlignedBB(
|
$minX = 1 - $f;
|
||||||
$this->x + 1 - $f,
|
|
||||||
$this->y,
|
|
||||||
$this->z,
|
|
||||||
$this->x + 1,
|
|
||||||
$this->y + 1,
|
|
||||||
$this->z + 1
|
|
||||||
);
|
|
||||||
}elseif($this->meta === 5){
|
}elseif($this->meta === 5){
|
||||||
return new AxisAlignedBB(
|
$maxX = $f;
|
||||||
$this->x,
|
|
||||||
$this->y,
|
|
||||||
$this->z,
|
|
||||||
$this->x + $f,
|
|
||||||
$this->y + 1,
|
|
||||||
$this->z + 1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return new AxisAlignedBB(
|
||||||
|
$this->x + $minX,
|
||||||
|
$this->y,
|
||||||
|
$this->z + $minZ,
|
||||||
|
$this->x + $maxX,
|
||||||
|
$this->y + 1,
|
||||||
|
$this->z + $maxZ
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -131,13 +112,7 @@ class Ladder extends Transparent{
|
|||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$sides = [
|
if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
|
||||||
2 => 3,
|
|
||||||
3 => 2,
|
|
||||||
4 => 5,
|
|
||||||
5 => 4
|
|
||||||
];
|
|
||||||
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
|
|
||||||
$this->level->useBreakOn($this);
|
$this->level->useBreakOn($this);
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class Lava extends Liquid{
|
|||||||
return "Lava";
|
return "Lava";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->fallDistance *= 0.5;
|
$entity->fallDistance *= 0.5;
|
||||||
|
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||||
|
@ -61,7 +61,7 @@ class Leaves extends Transparent{
|
|||||||
self::BIRCH => "Birch Leaves",
|
self::BIRCH => "Birch Leaves",
|
||||||
self::JUNGLE => "Jungle Leaves"
|
self::JUNGLE => "Jungle Leaves"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03];
|
return $names[$this->getVariant()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function diffusesSkyLight() : bool{
|
public function diffusesSkyLight() : bool{
|
||||||
@ -169,10 +169,14 @@ class Leaves extends Transparent{
|
|||||||
return $this->getLevel()->setBlock($this, $this, true);
|
return $this->getLevel()->setBlock($this, $this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getVariantBitmask() : int{
|
||||||
|
return 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
$drops = [];
|
$drops = [];
|
||||||
|
|
||||||
$variantMeta = $this->getDamage() & 0x03;
|
$variantMeta = $this->getVariant();
|
||||||
|
|
||||||
if($item->isShears()){
|
if($item->isShears()){
|
||||||
$drops[] = ItemFactory::get($this->getItemId(), $variantMeta, 1);
|
$drops[] = ItemFactory::get($this->getItemId(), $variantMeta, 1);
|
||||||
|
@ -36,11 +36,11 @@ class Leaves2 extends Leaves{
|
|||||||
self::ACACIA => "Acacia Leaves",
|
self::ACACIA => "Acacia Leaves",
|
||||||
self::DARK_OAK => "Dark Oak Leaves"
|
self::DARK_OAK => "Dark Oak Leaves"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
$variantMeta = $this->getDamage() & 0x03;
|
$variantMeta = $this->getVariant();
|
||||||
|
|
||||||
if($item->isShears()){
|
if($item->isShears()){
|
||||||
return [
|
return [
|
||||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
abstract class Liquid extends Transparent{
|
abstract class Liquid extends Transparent{
|
||||||
@ -41,7 +42,7 @@ abstract class Liquid extends Transparent{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ abstract class Liquid extends Transparent{
|
|||||||
}elseif($j === 3){
|
}elseif($j === 3){
|
||||||
++$z;
|
++$z;
|
||||||
}
|
}
|
||||||
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
$sideBlock = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||||
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||||
|
|
||||||
if($blockDecay < 0){
|
if($blockDecay < 0){
|
||||||
@ -124,7 +125,7 @@ abstract class Liquid extends Transparent{
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
|
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlockAt($x, $y - 1, $z));
|
||||||
|
|
||||||
if($blockDecay >= 0){
|
if($blockDecay >= 0){
|
||||||
$realDecay = $blockDecay - ($decay - 8);
|
$realDecay = $blockDecay - ($decay - 8);
|
||||||
@ -145,21 +146,21 @@ abstract class Liquid extends Transparent{
|
|||||||
if($this->getDamage() >= 8){
|
if($this->getDamage() >= 8){
|
||||||
$falling = false;
|
$falling = false;
|
||||||
|
|
||||||
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
|
if(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z - 1)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z + 1)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y, $this->z)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y, $this->z)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z - 1)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z + 1)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y + 1, $this->z)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y + 1, $this->z)->canBeFlowedInto()){
|
||||||
$falling = true;
|
$falling = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ abstract class Liquid extends Transparent{
|
|||||||
return $vector->normalize();
|
return $vector->normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||||
$flow = $this->getFlowVector();
|
$flow = $this->getFlowVector();
|
||||||
$vector->x += $flow->x;
|
$vector->x += $flow->x;
|
||||||
$vector->y += $flow->y;
|
$vector->y += $flow->y;
|
||||||
@ -205,10 +206,10 @@ abstract class Liquid extends Transparent{
|
|||||||
if($decay > 0){
|
if($decay > 0){
|
||||||
$smallestFlowDecay = -100;
|
$smallestFlowDecay = -100;
|
||||||
$this->adjacentSources = 0;
|
$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->getBlockAt($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->getBlockAt($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->getBlockAt($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 + 1, $this->y, $this->z), $smallestFlowDecay);
|
||||||
|
|
||||||
$k = $smallestFlowDecay + $multiplier;
|
$k = $smallestFlowDecay + $multiplier;
|
||||||
|
|
||||||
@ -216,7 +217,7 @@ abstract class Liquid extends Transparent{
|
|||||||
$k = -1;
|
$k = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z)))) >= 0){
|
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlockAt($this->x, $this->y + 1, $this->z))) >= 0){
|
||||||
if($topFlowDecay >= 8){
|
if($topFlowDecay >= 8){
|
||||||
$k = $topFlowDecay;
|
$k = $topFlowDecay;
|
||||||
}else{
|
}else{
|
||||||
@ -225,7 +226,7 @@ abstract class Liquid extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($this->adjacentSources >= 2 and $this instanceof Water){
|
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()){
|
if($bottomBlock->isSolid()){
|
||||||
$k = 0;
|
$k = 0;
|
||||||
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
|
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
|
||||||
@ -255,7 +256,7 @@ abstract class Liquid extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($decay >= 0){
|
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){
|
if($this instanceof Lava and $bottomBlock instanceof Water){
|
||||||
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
|
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
|
||||||
@ -280,19 +281,19 @@ abstract class Liquid extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($flags[0]){
|
if($flags[0]){
|
||||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
|
$this->flowIntoBlock($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $l);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($flags[1]){
|
if($flags[1]){
|
||||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
|
$this->flowIntoBlock($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $l);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($flags[2]){
|
if($flags[2]){
|
||||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
|
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $l);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($flags[3]){
|
if($flags[3]){
|
||||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
|
$this->flowIntoBlock($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,13 +336,13 @@ abstract class Liquid extends Transparent{
|
|||||||
}elseif($j === 3){
|
}elseif($j === 3){
|
||||||
++$z;
|
++$z;
|
||||||
}
|
}
|
||||||
$blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
$blockSide = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||||
|
|
||||||
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
|
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
|
||||||
continue;
|
continue;
|
||||||
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
||||||
continue;
|
continue;
|
||||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
}elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
|
||||||
return $accumulatedCost;
|
return $accumulatedCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,13 +386,13 @@ abstract class Liquid extends Transparent{
|
|||||||
}elseif($j === 3){
|
}elseif($j === 3){
|
||||||
++$z;
|
++$z;
|
||||||
}
|
}
|
||||||
$block = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||||
|
|
||||||
if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
|
if(!$block->canBeFlowedInto() and !($block instanceof Liquid)){
|
||||||
continue;
|
continue;
|
||||||
}elseif($block instanceof Liquid and $block->getDamage() === 0){
|
}elseif($block instanceof Liquid and $block->getDamage() === 0){
|
||||||
continue;
|
continue;
|
||||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
}elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
|
||||||
$this->flowCost[$j] = 0;
|
$this->flowCost[$j] = 0;
|
||||||
}else{
|
}else{
|
||||||
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
|
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
|
||||||
@ -444,7 +445,7 @@ abstract class Liquid extends Transparent{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class Magma extends Solid{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
if(!$entity->isSneaking()){
|
if(!$entity->isSneaking()){
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
|
@ -26,7 +26,7 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class MonsterSpawner extends Solid{
|
class MonsterSpawner extends Transparent{
|
||||||
|
|
||||||
protected $id = self::MONSTER_SPAWNER;
|
protected $id = self::MONSTER_SPAWNER;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class Mycelium extends Solid{
|
|||||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||||
if($block->getId() === Block::DIRT){
|
if($block->getId() === Block::DIRT){
|
||||||
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)));
|
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\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class NetherBrickFence extends Transparent{
|
class NetherBrickFence extends Fence{
|
||||||
|
|
||||||
protected $id = self::NETHER_BRICK_FENCE;
|
protected $id = self::NETHER_BRICK_FENCE;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
|
||||||
$this->meta = $meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@ -46,10 +42,6 @@ class NetherBrickFence extends Transparent{
|
|||||||
return "Nether Brick Fence";
|
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{
|
public function getDrops(Item $item) : array{
|
||||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||||
return parent::getDrops($item);
|
return parent::getDrops($item);
|
||||||
@ -57,6 +49,4 @@ class NetherBrickFence extends Transparent{
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: fix bounding boxes
|
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,10 @@ class NetherWartPlant extends Flowable{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Nether Wart";
|
||||||
|
}
|
||||||
|
|
||||||
public function ticksRandomly() : bool{
|
public function ticksRandomly() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class Planks extends Solid{
|
|||||||
self::ACACIA => "Acacia Wood Planks",
|
self::ACACIA => "Acacia Wood Planks",
|
||||||
self::DARK_OAK => "Dark Oak Wood Planks"
|
self::DARK_OAK => "Dark Oak Wood Planks"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
|
@ -48,7 +48,7 @@ class Prismarine extends Solid{
|
|||||||
self::DARK => "Dark Prismarine",
|
self::DARK => "Dark Prismarine",
|
||||||
self::BRICKS => "Prismarine Bricks"
|
self::BRICKS => "Prismarine Bricks"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
|
@ -21,34 +21,27 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
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;
|
||||||
|
|
||||||
/**
|
public function getName() : string{
|
||||||
* @return Inventory
|
static $names = [
|
||||||
*/
|
self::NORMAL => "Purpur Block",
|
||||||
public function getInventory() : Inventory;
|
self::CHISELED => "Chiseled Purpur", //wtf?
|
||||||
|
self::PILLAR => "Purpur Pillar"
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
* @return int
|
}
|
||||||
*/
|
|
||||||
public function getSlot() : int;
|
|
||||||
|
|
||||||
/**
|
public function getHardness() : float{
|
||||||
* @return Item
|
return 1.5;
|
||||||
*/
|
}
|
||||||
public function getSourceItem() : Item;
|
|
||||||
|
|
||||||
/**
|
public function getBlastResistance() : float{
|
||||||
* @return Item
|
return 30;
|
||||||
*/
|
}
|
||||||
public function getTargetItem() : Item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getCreationTime() : float;
|
|
||||||
}
|
}
|
@ -21,18 +21,31 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\block\BlockFactory;
|
|
||||||
|
class PurpurStairs extends Stair{
|
||||||
|
|
||||||
|
protected $id = self::PURPUR_STAIRS;
|
||||||
|
|
||||||
class WoodenDoor extends Item{
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->block = BlockFactory::get(Block::WOODEN_DOOR_BLOCK);
|
$this->meta = $meta;
|
||||||
parent::__construct(self::WOODEN_DOOR, $meta, "Wooden Door");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMaxStackSize() : int{
|
public function getName() : string{
|
||||||
return 1;
|
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{
|
class Quartz extends Solid{
|
||||||
|
|
||||||
const QUARTZ_NORMAL = 0;
|
const NORMAL = 0;
|
||||||
const QUARTZ_CHISELED = 1;
|
const CHISELED = 1;
|
||||||
const QUARTZ_PILLAR = 2;
|
const PILLAR = 2;
|
||||||
|
|
||||||
protected $id = self::QUARTZ_BLOCK;
|
protected $id = self::QUARTZ_BLOCK;
|
||||||
|
|
||||||
@ -47,15 +47,15 @@ class Quartz extends Solid{
|
|||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
static $names = [
|
static $names = [
|
||||||
self::QUARTZ_NORMAL => "Quartz Block",
|
self::NORMAL => "Quartz Block",
|
||||||
self::QUARTZ_CHISELED => "Chiseled Quartz Block",
|
self::CHISELED => "Chiseled Quartz Block",
|
||||||
self::QUARTZ_PILLAR => "Quartz Pillar"
|
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{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||||
if($this->meta !== self::QUARTZ_NORMAL){
|
if($this->meta !== self::NORMAL){
|
||||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||||
}
|
}
|
||||||
return $this->getLevel()->setBlock($blockReplace, $this, true, true);
|
return $this->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);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace pocketmine\item;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
class RedSandstone extends Sandstone{
|
||||||
use pocketmine\block\BlockFactory;
|
protected $id = self::RED_SANDSTONE;
|
||||||
|
|
||||||
class FlowerPot extends Item{
|
public function getName() : string{
|
||||||
public function __construct(int $meta = 0){
|
static $names = [
|
||||||
$this->block = BlockFactory::get(Block::FLOWER_POT_BLOCK);
|
self::NORMAL => "Red Sandstone",
|
||||||
parent::__construct(self::FLOWER_POT, $meta, "Flower Pot");
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -48,7 +48,7 @@ class Sandstone extends Solid{
|
|||||||
self::CHISELED => "Chiseled Sandstone",
|
self::CHISELED => "Chiseled Sandstone",
|
||||||
self::SMOOTH => "Smooth Sandstone"
|
self::SMOOTH => "Smooth Sandstone"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\level\generator\object\Tree;
|
use pocketmine\level\generator\object\Tree;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
@ -54,7 +53,7 @@ class Sapling extends Flowable{
|
|||||||
4 => "Acacia Sapling",
|
4 => "Acacia Sapling",
|
||||||
5 => "Dark Oak Sapling"
|
5 => "Dark Oak Sapling"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ticksRandomly() : bool{
|
public function ticksRandomly() : bool{
|
||||||
@ -75,7 +74,7 @@ class Sapling extends Flowable{
|
|||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||||
//TODO: change log type
|
//TODO: change log type
|
||||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||||
|
|
||||||
$item->count--;
|
$item->count--;
|
||||||
|
|
||||||
@ -95,7 +94,7 @@ class Sapling extends Flowable{
|
|||||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){ //Growth
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){ //Growth
|
||||||
if(mt_rand(1, 7) === 1){
|
if(mt_rand(1, 7) === 1){
|
||||||
if(($this->meta & 0x08) === 0x08){
|
if(($this->meta & 0x08) === 0x08){
|
||||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||||
}else{
|
}else{
|
||||||
$this->meta |= 0x08;
|
$this->meta |= 0x08;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
$this->getLevel()->setBlock($this, $this, true);
|
||||||
@ -110,10 +109,8 @@ class Sapling extends Flowable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getVariantBitmask() : int{
|
||||||
return [
|
return 0x07;
|
||||||
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x07, 1)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
public function getFuelTime() : int{
|
||||||
|
@ -26,11 +26,10 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\tile\Sign as TileSign;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
class SignPost extends Transparent{
|
class SignPost extends Transparent{
|
||||||
@ -55,43 +54,23 @@ class SignPost extends Transparent{
|
|||||||
return "Sign Post";
|
return "Sign Post";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return null;
|
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 $facePos, Player $player = null) : bool{
|
||||||
if($face !== Vector3::SIDE_DOWN){
|
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){
|
if($face === Vector3::SIDE_UP){
|
||||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||||
}else{
|
}else{
|
||||||
$this->meta = $face;
|
$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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -27,13 +27,8 @@ use pocketmine\item\Item;
|
|||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\IntTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\tile\Skull as SkullTile;
|
use pocketmine\tile\Skull as TileSkull;
|
||||||
use pocketmine\tile\Spawnable;
|
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
|
|
||||||
class Skull extends Flowable{
|
class Skull extends Flowable{
|
||||||
@ -49,10 +44,10 @@ class Skull extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() : string{
|
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)
|
//TODO: different bounds depending on attached face (meta)
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.25,
|
$this->x + 0.25,
|
||||||
@ -65,35 +60,20 @@ class Skull 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 $facePos, Player $player = null) : bool{
|
||||||
if($face !== Vector3::SIDE_DOWN){
|
if($face === Vector3::SIDE_DOWN){
|
||||||
$this->meta = $face;
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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{
|
public function getDrops(Item $item) : array{
|
||||||
$tile = $this->level->getTile($this);
|
$tile = $this->level->getTile($this);
|
||||||
if($tile instanceof SkullTile){
|
if($tile instanceof TileSkull){
|
||||||
return [
|
return [
|
||||||
ItemFactory::get(Item::SKULL, $tile->getType(), 1)
|
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 $facePos, 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($facePos->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";
|
return "Snow Layer";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class SoulSand extends Solid{
|
|||||||
return Tool::TYPE_SHOVEL;
|
return Tool::TYPE_SHOVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -31,103 +31,56 @@ use pocketmine\Player;
|
|||||||
|
|
||||||
abstract class Stair extends Transparent{
|
abstract class Stair extends Transparent{
|
||||||
|
|
||||||
/*
|
protected function recalculateCollisionBoxes() : array{
|
||||||
public function collidesWithBB(AxisAlignedBB $bb, &$list = []){
|
//TODO: handle corners
|
||||||
$damage = $this->getDamage();
|
|
||||||
$j = $damage & 0x03;
|
|
||||||
|
|
||||||
$f = 0;
|
$minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
|
||||||
$f1 = 0.5;
|
$maxYSlab = $minYSlab + 0.5;
|
||||||
$f2 = 0.5;
|
|
||||||
$f3 = 1;
|
|
||||||
|
|
||||||
if(($damage & 0x04) > 0){
|
$bbs = [
|
||||||
$f = 0.5;
|
new AxisAlignedBB(
|
||||||
$f1 = 1;
|
$this->x,
|
||||||
$f2 = 0;
|
$this->y + $minYSlab,
|
||||||
$f3 = 0.5;
|
$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(
|
$bbs[] = new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x + $minX,
|
||||||
$this->y + $f,
|
$this->y + $minY,
|
||||||
$this->z,
|
$this->z + $minZ,
|
||||||
$this->x + 1,
|
$this->x + $maxX,
|
||||||
$this->y + $f1,
|
$this->y + $maxY,
|
||||||
$this->z + 1
|
$this->z + $maxZ
|
||||||
))){
|
);
|
||||||
$list[] = $bb2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($j === 0){
|
return $bbs;
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 $facePos, Player $player = null) : bool{
|
||||||
|
@ -60,7 +60,7 @@ class Stone extends Solid{
|
|||||||
self::ANDESITE => "Andesite",
|
self::ANDESITE => "Andesite",
|
||||||
self::POLISHED_ANDESITE => "Polished Andesite"
|
self::POLISHED_ANDESITE => "Polished Andesite"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
|
@ -53,7 +53,7 @@ class StoneBricks extends Solid{
|
|||||||
self::CRACKED => "Cracked Stone Bricks",
|
self::CRACKED => "Cracked Stone Bricks",
|
||||||
self::CHISELED => "Chiseled Stone Bricks"
|
self::CHISELED => "Chiseled Stone Bricks"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03];
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item) : array{
|
public function getDrops(Item $item) : array{
|
||||||
|
@ -23,14 +23,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
class StoneButton extends Flowable{
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
|
class StoneButton extends Button{
|
||||||
|
|
||||||
protected $id = self::STONE_BUTTON;
|
protected $id = self::STONE_BUTTON;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
|
||||||
$this->meta = $meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Stone Button";
|
return "Stone Button";
|
||||||
}
|
}
|
||||||
@ -39,7 +37,7 @@ class StoneButton extends Flowable{
|
|||||||
return 0.5;
|
return 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getVariantBitmask() : int{
|
public function getToolType() : int{
|
||||||
return 0;
|
return Tool::TYPE_PICKAXE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace pocketmine\block;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Tool;
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class StoneSlab extends WoodenSlab{
|
class StoneSlab extends Slab{
|
||||||
const STONE = 0;
|
const STONE = 0;
|
||||||
const SANDSTONE = 1;
|
const SANDSTONE = 1;
|
||||||
const WOODEN = 2;
|
const WOODEN = 2;
|
||||||
@ -38,7 +38,9 @@ class StoneSlab extends WoodenSlab{
|
|||||||
|
|
||||||
protected $id = self::STONE_SLAB;
|
protected $id = self::STONE_SLAB;
|
||||||
|
|
||||||
protected $doubleId = self::DOUBLE_STONE_SLAB;
|
public function getDoubleSlabId() : int{
|
||||||
|
return self::DOUBLE_STONE_SLAB;
|
||||||
|
}
|
||||||
|
|
||||||
public function getHardness() : float{
|
public function getHardness() : float{
|
||||||
return 2;
|
return 2;
|
||||||
@ -55,7 +57,7 @@ class StoneSlab extends WoodenSlab{
|
|||||||
self::QUARTZ => "Quartz",
|
self::QUARTZ => "Quartz",
|
||||||
self::NETHER_BRICK => "Nether Brick"
|
self::NETHER_BRICK => "Nether Brick"
|
||||||
];
|
];
|
||||||
return (($this->meta & 0x08) > 0 ? "Upper " : "") . $names[$this->meta & 0x07] . " Slab";
|
return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getToolType() : int{
|
public function getToolType() : int{
|
||||||
@ -69,8 +71,4 @@ class StoneSlab extends WoodenSlab{
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFuelTime() : int{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
44
src/pocketmine/block/StoneSlab2.php
Normal file
44
src/pocketmine/block/StoneSlab2.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?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 StoneSlab2 extends StoneSlab{
|
||||||
|
const TYPE_RED_SANDSTONE = 0;
|
||||||
|
const TYPE_PURPUR = 1;
|
||||||
|
|
||||||
|
protected $id = self::STONE_SLAB2;
|
||||||
|
|
||||||
|
public function getDoubleSlabId() : int{
|
||||||
|
return self::DOUBLE_STONE_SLAB2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
static $names = [
|
||||||
|
self::TYPE_RED_SANDSTONE => "Red Sandstone",
|
||||||
|
self::TYPE_PURPUR => "Purpur"
|
||||||
|
];
|
||||||
|
|
||||||
|
return (($this->meta & 0x08) > 0 ? "Upper " : "") . ($names[$this->getVariant()] ?? "") . " Slab";
|
||||||
|
}
|
||||||
|
}
|
@ -52,7 +52,7 @@ class Sugarcane extends Flowable{
|
|||||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)));
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
@ -85,7 +85,7 @@ class Sugarcane extends Flowable{
|
|||||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||||
if($this->meta === 0x0F){
|
if($this->meta === 0x0F){
|
||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||||
if($b->getId() === self::AIR){
|
if($b->getId() === self::AIR){
|
||||||
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||||
break;
|
break;
|
||||||
|
@ -25,11 +25,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\nbt\tag\ByteTag;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
|
||||||
use pocketmine\nbt\tag\DoubleTag;
|
|
||||||
use pocketmine\nbt\tag\FloatTag;
|
|
||||||
use pocketmine\nbt\tag\ListTag;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\Random;
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
@ -63,24 +59,13 @@ class TNT extends Solid{
|
|||||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||||
|
|
||||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||||
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), new CompoundTag("", [
|
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
||||||
new ListTag("Pos", [
|
$nbt->setByte("Fuse", $fuse);
|
||||||
new DoubleTag("", $this->x + 0.5),
|
|
||||||
new DoubleTag("", $this->y),
|
|
||||||
new DoubleTag("", $this->z + 0.5)
|
|
||||||
]),
|
|
||||||
new ListTag("Motion", [
|
|
||||||
new DoubleTag("", -sin($mot) * 0.02),
|
|
||||||
new DoubleTag("", 0.2),
|
|
||||||
new DoubleTag("", -cos($mot) * 0.02)
|
|
||||||
]),
|
|
||||||
new ListTag("Rotation", [
|
|
||||||
new FloatTag("", 0),
|
|
||||||
new FloatTag("", 0)
|
|
||||||
]),
|
|
||||||
new ByteTag("Fuse", $fuse)
|
|
||||||
]));
|
|
||||||
|
|
||||||
$tnt->spawnToAll();
|
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), $nbt);
|
||||||
|
|
||||||
|
if($tnt !== null){
|
||||||
|
$tnt->spawnToAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -37,7 +37,7 @@ class TallGrass extends Flowable{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canBeReplaced(Block $with = null) : bool{
|
public function canBeReplaced() : bool{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class TallGrass extends Flowable{
|
|||||||
1 => "Tall Grass",
|
1 => "Tall Grass",
|
||||||
2 => "Fern"
|
2 => "Fern"
|
||||||
];
|
];
|
||||||
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{
|
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||||
|
@ -28,57 +28,83 @@ use pocketmine\math\Vector3;
|
|||||||
|
|
||||||
abstract class Thin extends Transparent{
|
abstract class Thin extends Transparent{
|
||||||
|
|
||||||
public function isSolid() : bool{
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return false;
|
$width = 0.5 - 0.125 / 2;
|
||||||
}
|
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
|
||||||
|
|
||||||
$f = 0.4375;
|
|
||||||
$f1 = 0.5625;
|
|
||||||
$f2 = 0.4375;
|
|
||||||
$f3 = 0.5625;
|
|
||||||
|
|
||||||
$flag = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
|
||||||
$flag1 = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
|
||||||
$flag2 = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
|
||||||
$flag3 = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
|
||||||
|
|
||||||
if((!$flag2 or !$flag3) and ($flag2 or $flag3 or $flag or $flag1)){
|
|
||||||
if($flag2 and !$flag3){
|
|
||||||
$f = 0;
|
|
||||||
}elseif(!$flag2 and $flag3){
|
|
||||||
$f1 = 1;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$f = 0;
|
|
||||||
$f1 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((!$flag or !$flag1) and ($flag2 or $flag3 or $flag or $flag1)){
|
|
||||||
if($flag and !$flag1){
|
|
||||||
$f2 = 0;
|
|
||||||
}elseif(!$flag and $flag1){
|
|
||||||
$f3 = 1;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
$f2 = 0;
|
|
||||||
$f3 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $f,
|
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $f2,
|
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||||
$this->x + $f1,
|
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||||
$this->y + 1,
|
$this->y + 1,
|
||||||
$this->z + $f3
|
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function recalculateCollisionBoxes() : array{
|
||||||
|
$inset = 0.5 - 0.125 / 2;
|
||||||
|
|
||||||
public function canConnect(Block $block){
|
/** @var AxisAlignedBB[] $bbs */
|
||||||
return $block->isSolid() or $block->getId() === $this->getId() or $block->getId() === self::GLASS_PANE or $block->getId() === self::GLASS;
|
$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,
|
||||||
|
$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,
|
||||||
|
$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,
|
||||||
|
$this->z + 1 - $inset
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canConnect(Block $block) : bool{
|
||||||
|
if($block instanceof Thin){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: currently there's no proper way to tell if a block is a full-block, so we check the bounding box size
|
||||||
|
$bbs = $block->getCollisionBoxes();
|
||||||
|
if(count($bbs) === 1){
|
||||||
|
return $bbs[0]->getAverageEdgeLength() >= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -50,15 +50,15 @@ class Torch extends Flowable{
|
|||||||
$below = $this->getSide(Vector3::SIDE_DOWN);
|
$below = $this->getSide(Vector3::SIDE_DOWN);
|
||||||
$side = $this->getDamage();
|
$side = $this->getDamage();
|
||||||
$faces = [
|
$faces = [
|
||||||
0 => 0,
|
0 => Vector3::SIDE_DOWN,
|
||||||
1 => 4,
|
1 => Vector3::SIDE_WEST,
|
||||||
2 => 5,
|
2 => Vector3::SIDE_EAST,
|
||||||
3 => 2,
|
3 => Vector3::SIDE_NORTH,
|
||||||
4 => 3,
|
4 => Vector3::SIDE_SOUTH,
|
||||||
5 => 0
|
5 => Vector3::SIDE_DOWN
|
||||||
];
|
];
|
||||||
|
|
||||||
if($this->getSide($faces[$side])->isTransparent() === true and !($side === 0 and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
|
if($this->getSide($faces[$side])->isTransparent() === true and !($side === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevel()->useBreakOn($this);
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
|
@ -53,7 +53,7 @@ class Trapdoor extends Transparent{
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$damage = $this->getDamage();
|
$damage = $this->getDamage();
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ use pocketmine\math\AxisAlignedBB;
|
|||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Vine extends Transparent{
|
class Vine extends Flowable{
|
||||||
const FLAG_SOUTH = 0x01;
|
const FLAG_SOUTH = 0x01;
|
||||||
const FLAG_WEST = 0x02;
|
const FLAG_WEST = 0x02;
|
||||||
const FLAG_NORTH = 0x04;
|
const FLAG_NORTH = 0x04;
|
||||||
@ -43,10 +43,6 @@ class Vine extends Transparent{
|
|||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSolid() : bool{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Vines";
|
return "Vines";
|
||||||
}
|
}
|
||||||
@ -71,106 +67,126 @@ class Vine extends Transparent{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function canBeReplaced() : bool{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->resetFallDistance();
|
$entity->resetFallDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
|
|
||||||
$f1 = 1;
|
$minX = 1;
|
||||||
$f2 = 1;
|
$minY = 1;
|
||||||
$f3 = 1;
|
$minZ = 1;
|
||||||
$f4 = 0;
|
$maxX = 0;
|
||||||
$f5 = 0;
|
$maxY = 0;
|
||||||
$f6 = 0;
|
$maxZ = 0;
|
||||||
|
|
||||||
$flag = $this->meta > 0;
|
$flag = $this->meta > 0;
|
||||||
|
|
||||||
if(($this->meta & self::FLAG_WEST) > 0){
|
if(($this->meta & self::FLAG_WEST) > 0){
|
||||||
$f4 = max($f4, 0.0625);
|
$maxX = max($maxX, 0.0625);
|
||||||
$f1 = 0;
|
$minX = 0;
|
||||||
$f2 = 0;
|
$minY = 0;
|
||||||
$f5 = 1;
|
$maxY = 1;
|
||||||
$f3 = 0;
|
$minZ = 0;
|
||||||
$f6 = 1;
|
$maxZ = 1;
|
||||||
$flag = true;
|
$flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($this->meta & self::FLAG_EAST) > 0){
|
if(($this->meta & self::FLAG_EAST) > 0){
|
||||||
$f1 = min($f1, 0.9375);
|
$minX = min($minX, 0.9375);
|
||||||
$f4 = 1;
|
$maxX = 1;
|
||||||
$f2 = 0;
|
$minY = 0;
|
||||||
$f5 = 1;
|
$maxY = 1;
|
||||||
$f3 = 0;
|
$minZ = 0;
|
||||||
$f6 = 1;
|
$maxZ = 1;
|
||||||
$flag = true;
|
$flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($this->meta & self::FLAG_SOUTH) > 0){
|
if(($this->meta & self::FLAG_SOUTH) > 0){
|
||||||
$f3 = min($f3, 0.9375);
|
$minZ = min($minZ, 0.9375);
|
||||||
$f6 = 1;
|
$maxZ = 1;
|
||||||
$f1 = 0;
|
$minX = 0;
|
||||||
$f4 = 1;
|
$maxX = 1;
|
||||||
$f2 = 0;
|
$minY = 0;
|
||||||
$f5 = 1;
|
$maxY = 1;
|
||||||
$flag = true;
|
$flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Missing NORTH check
|
||||||
|
|
||||||
if(!$flag and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
if(!$flag and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||||
$f2 = min($f2, 0.9375);
|
$minY = min($minY, 0.9375);
|
||||||
$f5 = 1;
|
$maxY = 1;
|
||||||
$f1 = 0;
|
$minX = 0;
|
||||||
$f4 = 1;
|
$maxX = 1;
|
||||||
$f3 = 0;
|
$minZ = 0;
|
||||||
$f6 = 1;
|
$maxZ = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + $f1,
|
$this->x + $minX,
|
||||||
$this->y + $f2,
|
$this->y + $minY,
|
||||||
$this->z + $f3,
|
$this->z + $minZ,
|
||||||
$this->x + $f4,
|
$this->x + $maxX,
|
||||||
$this->y + $f5,
|
$this->y + $maxY,
|
||||||
$this->z + $f6
|
$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 $facePos, Player $player = null) : bool{
|
||||||
//TODO: multiple sides
|
if(!$blockClicked->isSolid() or $face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
|
||||||
if($blockClicked->isSolid()){
|
return false;
|
||||||
$faces = [
|
|
||||||
2 => self::FLAG_SOUTH,
|
|
||||||
3 => self::FLAG_NORTH,
|
|
||||||
4 => self::FLAG_EAST,
|
|
||||||
5 => self::FLAG_WEST
|
|
||||||
];
|
|
||||||
if(isset($faces[$face])){
|
|
||||||
$this->meta = $faces[$face];
|
|
||||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
$faces = [
|
||||||
|
Vector3::SIDE_NORTH => self::FLAG_SOUTH,
|
||||||
|
Vector3::SIDE_SOUTH => self::FLAG_NORTH,
|
||||||
|
Vector3::SIDE_WEST => self::FLAG_EAST,
|
||||||
|
Vector3::SIDE_EAST => self::FLAG_WEST
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->meta = $faces[$face] ?? 0;
|
||||||
|
if($blockReplace->getId() === $this->getId()){
|
||||||
|
$this->meta |= $blockReplace->meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$sides = [
|
$sides = [
|
||||||
1 => 3,
|
self::FLAG_SOUTH => Vector3::SIDE_SOUTH,
|
||||||
2 => 4,
|
self::FLAG_WEST => Vector3::SIDE_WEST,
|
||||||
4 => 2,
|
self::FLAG_NORTH => Vector3::SIDE_NORTH,
|
||||||
8 => 5
|
self::FLAG_EAST => Vector3::SIDE_EAST
|
||||||
];
|
];
|
||||||
|
|
||||||
if(!isset($sides[$this->meta])){
|
$meta = $this->meta;
|
||||||
return false; //TODO: remove this once placing on multiple sides is supported (these are bitflags, not actual meta values
|
|
||||||
|
foreach($sides as $flag => $side){
|
||||||
|
if(($meta & $flag) === 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$this->getSide($side)->isSolid()){
|
||||||
|
$meta &= ~$flag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
|
if($meta !== $this->meta){
|
||||||
$this->level->useBreakOn($this);
|
if($meta === 0){
|
||||||
|
$this->level->useBreakOn($this);
|
||||||
|
}else{
|
||||||
|
$this->meta = $meta;
|
||||||
|
$this->level->setBlock($this, $this);
|
||||||
|
}
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||||
|
@ -34,19 +34,11 @@ class WallSign extends SignPost{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(int $type){
|
public function onUpdate(int $type){
|
||||||
$faces = [
|
|
||||||
2 => 3,
|
|
||||||
3 => 2,
|
|
||||||
4 => 5,
|
|
||||||
5 => 4
|
|
||||||
];
|
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if(isset($faces[$this->meta])){
|
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
|
||||||
if($this->getSide($faces[$this->meta])->getId() === self::AIR){
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->useBreakOn($this);
|
|
||||||
}
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
|
||||||
}
|
}
|
||||||
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ class Water extends Liquid{
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity) : void{
|
||||||
$entity->resetFallDistance();
|
$entity->resetFallDistance();
|
||||||
if($entity->fireTicks > 0){
|
if($entity->fireTicks > 0){
|
||||||
$entity->extinguish();
|
$entity->extinguish();
|
||||||
|
@ -45,7 +45,7 @@ class WaterLily extends Flowable{
|
|||||||
return 0.6;
|
return 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function recalculateBoundingBox(){
|
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
$this->y,
|
$this->y,
|
||||||
|
@ -52,7 +52,7 @@ class Wood extends Solid{
|
|||||||
self::BIRCH => "Birch Wood",
|
self::BIRCH => "Birch Wood",
|
||||||
self::JUNGLE => "Jungle Wood"
|
self::JUNGLE => "Jungle Wood"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03];
|
return $names[$this->getVariant()] ?? "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 $facePos, Player $player = null) : bool{
|
||||||
|
@ -36,6 +36,6 @@ class Wood2 extends Wood{
|
|||||||
0 => "Acacia Wood",
|
0 => "Acacia Wood",
|
||||||
1 => "Dark Oak Wood"
|
1 => "Dark Oak Wood"
|
||||||
];
|
];
|
||||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
return $names[$this->getVariant()] ?? "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,21 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
class WoodenButton extends StoneButton{
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
|
class WoodenButton extends Button{
|
||||||
|
|
||||||
protected $id = self::WOODEN_BUTTON;
|
protected $id = self::WOODEN_BUTTON;
|
||||||
|
|
||||||
public function getName() : string{
|
public function getName() : string{
|
||||||
return "Wooden Button";
|
return "Wooden Button";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToolType() : int{
|
||||||
|
return Tool::TYPE_AXE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
61
src/pocketmine/block/WoodenFence.php
Normal file
61
src/pocketmine/block/WoodenFence.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?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\Tool;
|
||||||
|
|
||||||
|
class WoodenFence extends Fence{
|
||||||
|
const FENCE_OAK = 0;
|
||||||
|
const FENCE_SPRUCE = 1;
|
||||||
|
const FENCE_BIRCH = 2;
|
||||||
|
const FENCE_JUNGLE = 3;
|
||||||
|
const FENCE_ACACIA = 4;
|
||||||
|
const FENCE_DARKOAK = 5;
|
||||||
|
|
||||||
|
protected $id = self::FENCE;
|
||||||
|
|
||||||
|
public function getHardness() : float{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->getVariant()] ?? "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFuelTime() : int{
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user