mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 11:16:57 +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.
|
||||
- http://pmmp.readthedocs.io/en/rtfd/ - Documentation
|
||||
- https://forums.pmmp.io - PMMP Forums
|
||||
-->
|
||||
<!--- Any issues requesting updates to new versions of MCPE will be treated as spam. We do not need issues to tell us that there is a new version available. -->
|
||||
<!---
|
||||
Write a short description about the issue
|
||||
|
||||
If you are reporting a regression or unexpected behaviour, please include the below information:
|
||||
Expected result: What were you expecting to happen?
|
||||
Actual result: What actually happened?
|
||||
Any issues requesting updates to new versions of MCPE will be treated as spam.
|
||||
Please do not create issues for missing/un-implemented gameplay features - they will be closed.
|
||||
-->
|
||||
|
||||
<!--- Write a short description about the issue -->
|
||||
|
||||
<!--- If you are reporting a regression or unexpected behaviour, please include the below information: -->
|
||||
- Expected result: What were you expecting to happen?
|
||||
- Actual result: What actually happened?
|
||||
|
||||
### Steps to reproduce the issue
|
||||
<!--- help us find the problem by adding steps to reproduce the issue -->
|
||||
1. ...
|
||||
@ -21,9 +22,9 @@ Actual result: What actually happened?
|
||||
### OS and versions
|
||||
<!--- use the 'version' command in PocketMine-MP
|
||||
|
||||
NOTE: LATEST is not a valid version. PocketMine version should include Jenkins build number and/or git commit hash.
|
||||
NOTE: LATEST is not a valid version. PocketMine-MP version should include Jenkins build number and/or git commit hash.
|
||||
|
||||
NO support whatsoever will be provided for forks or spoons of PocketMine. Issues relating to non-official distributions will be closed as spam. Please send such issues to whoever is responsible for the fork or spoon you are using.
|
||||
NO support whatsoever will be provided for third-party modified variants of PocketMine-MP. Issues relating to third-party modifications will be closed as spam.
|
||||
|
||||
Note that 32-bit platforms are no longer supported by PocketMine-MP and issues concerning 32-bit platforms will be closed.
|
||||
-->
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -28,3 +28,9 @@ Desktop.ini
|
||||
# Sphinx-doc
|
||||
/docs/build/
|
||||
!/docs/requirements.txt
|
||||
|
||||
# Composer
|
||||
vendor/*
|
||||
|
||||
# Travis files
|
||||
test_data/*
|
||||
|
17
.travis.yml
17
.travis.yml
@ -1,12 +1,21 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.2
|
||||
|
||||
before_script:
|
||||
- pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||
- pecl install channel://pecl.php.net/weakref-0.3.3
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.0
|
||||
# - pecl install channel://pecl.php.net/pthreads-3.1.6
|
||||
- echo | pecl install channel://pecl.php.net/yaml-2.0.2
|
||||
- git clone https://github.com/krakjoe/pthreads.git
|
||||
- cd pthreads
|
||||
- git checkout 6c6b15138c923b69cfa46ee05fc2dd45da587287
|
||||
- phpize
|
||||
- ./configure
|
||||
- make
|
||||
- make install
|
||||
- cd ..
|
||||
- echo "extension=pthreads.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
- composer install
|
||||
|
||||
script:
|
||||
- ./tests/travis.sh
|
||||
|
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\Timings;
|
||||
use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
class MemoryManager{
|
||||
@ -63,16 +65,19 @@ class MemoryManager{
|
||||
private $garbageCollectionAsync;
|
||||
|
||||
/** @var int */
|
||||
private $chunkRadiusOverride;
|
||||
private $lowMemChunkRadiusOverride;
|
||||
/** @var bool */
|
||||
private $chunkCollect;
|
||||
private $lowMemChunkGC;
|
||||
/** @var bool */
|
||||
private $chunkTrigger;
|
||||
private $lowMemReduceChunkRadius;
|
||||
|
||||
/** @var bool */
|
||||
private $chunkCache;
|
||||
private $lowMemDisableChunkCache;
|
||||
/** @var bool */
|
||||
private $cacheTrigger;
|
||||
private $lowMemClearWorldCache;
|
||||
|
||||
/** @var bool */
|
||||
private $dumpWorkers = true;
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->server = $server;
|
||||
@ -124,13 +129,13 @@ class MemoryManager{
|
||||
$this->garbageCollectionTrigger = (bool) $this->server->getProperty("memory.garbage-collection.low-memory-trigger", true);
|
||||
$this->garbageCollectionAsync = (bool) $this->server->getProperty("memory.garbage-collection.collect-async-worker", true);
|
||||
|
||||
$this->chunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
||||
$this->chunkCollect = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
||||
$this->chunkTrigger = (bool) $this->server->getProperty("memory.max-chunks.low-memory-trigger", true);
|
||||
$this->lowMemChunkRadiusOverride = (int) $this->server->getProperty("memory.max-chunks.chunk-radius", 4);
|
||||
$this->lowMemChunkGC = (bool) $this->server->getProperty("memory.max-chunks.trigger-chunk-collect", true);
|
||||
|
||||
$this->chunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
||||
$this->cacheTrigger = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
||||
$this->lowMemDisableChunkCache = (bool) $this->server->getProperty("memory.world-caches.disable-chunk-cache", true);
|
||||
$this->lowMemClearWorldCache = (bool) $this->server->getProperty("memory.world-caches.low-memory-trigger", true);
|
||||
|
||||
$this->dumpWorkers = (bool) $this->server->getProperty("memory.memory-dump.dump-async-worker", true);
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
@ -145,7 +150,7 @@ class MemoryManager{
|
||||
* @return 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
|
||||
*/
|
||||
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){
|
||||
$this->server->getLogger()->debug(sprintf("[Memory Manager] %sLow memory triggered, limit %gMB, using %gMB",
|
||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||
if($this->cacheTrigger){
|
||||
if($this->lowMemClearWorldCache){
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->clearCache(true);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->chunkTrigger and $this->chunkCollect){
|
||||
if($this->lowMemChunkGC){
|
||||
foreach($this->server->getLevels() as $level){
|
||||
$level->doChunkGarbageCollection();
|
||||
}
|
||||
@ -261,6 +266,27 @@ class MemoryManager{
|
||||
* @param int $maxStringSize
|
||||
*/
|
||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||
MainLogger::getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||
self::dumpMemory($this->server, $this->server->getLoader(), $outputFolder, $maxNesting, $maxStringSize);
|
||||
|
||||
if($this->dumpWorkers){
|
||||
$scheduler = $this->server->getScheduler();
|
||||
for($i = 0, $size = $scheduler->getAsyncTaskPoolSize(); $i < $size; ++$i){
|
||||
$scheduler->scheduleAsyncTaskToWorker(new DumpWorkerMemoryTask($outputFolder, $maxNesting, $maxStringSize), $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
*
|
||||
* @param mixed $startingObject
|
||||
* @param \ClassLoader $loader
|
||||
* @param string $outputFolder
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
*/
|
||||
public static function dumpMemory($startingObject, \ClassLoader $loader, string $outputFolder, int $maxNesting, int $maxStringSize){
|
||||
$hardLimit = ini_get('memory_limit');
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
@ -269,12 +295,8 @@ class MemoryManager{
|
||||
mkdir($outputFolder, 0777, true);
|
||||
}
|
||||
|
||||
$this->server->getLogger()->notice("[Dump] After the memory dump is done, the server might crash");
|
||||
|
||||
$obData = fopen($outputFolder . "/objects.js", "wb+");
|
||||
|
||||
$staticProperties = [];
|
||||
|
||||
$data = [];
|
||||
|
||||
$objects = [];
|
||||
@ -283,8 +305,10 @@ class MemoryManager{
|
||||
|
||||
$instanceCounts = [];
|
||||
|
||||
$staticProperties = [];
|
||||
$staticCount = 0;
|
||||
foreach($this->server->getLoader()->getClasses() as $className){
|
||||
|
||||
foreach($loader->getClasses() as $className){
|
||||
$reflection = new \ReflectionClass($className);
|
||||
$staticProperties[$className] = [];
|
||||
foreach($reflection->getProperties() as $property){
|
||||
@ -297,7 +321,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$staticCount++;
|
||||
$this->continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
self::continueDump($property->getValue(), $staticProperties[$className][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
if(count($staticProperties[$className]) === 0){
|
||||
@ -305,9 +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{
|
||||
$continue = false;
|
||||
@ -349,25 +403,26 @@ class MemoryManager{
|
||||
if(!$property->isPublic()){
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
$this->continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
self::continueDump($property->getValue($object), $info["properties"][$property->getName()], $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
fwrite($obData, "$hash@$className: " . json_encode($info, JSON_UNESCAPED_SLASHES) . "\n");
|
||||
}
|
||||
|
||||
echo "[Dump] Wrote " . count($objects) . " objects\n";
|
||||
|
||||
}while($continue);
|
||||
|
||||
MainLogger::getLogger()->info("[Dump] Wrote " . count($objects) . " objects");
|
||||
|
||||
fclose($obData);
|
||||
|
||||
file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents($outputFolder . "/serverEntry.js", json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents($outputFolder . "/referenceCounts.js", json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
file_put_contents($outputFolder . "/instanceCounts.js", json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
echo "[Dump] Finished!\n";
|
||||
MainLogger::getLogger()->info("[Dump] Finished!");
|
||||
|
||||
ini_set('memory_limit', $hardLimit);
|
||||
gc_enable();
|
||||
@ -382,7 +437,7 @@ class MemoryManager{
|
||||
* @param int $maxNesting
|
||||
* @param int $maxStringSize
|
||||
*/
|
||||
private function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||
private static function continueDump($from, &$data, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
|
||||
if($maxNesting <= 0){
|
||||
$data = "(error) NESTING LIMIT REACHED";
|
||||
return;
|
||||
@ -406,7 +461,7 @@ class MemoryManager{
|
||||
}
|
||||
$data = [];
|
||||
foreach($from as $key => $value){
|
||||
$this->continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}elseif(is_string($from)){
|
||||
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,6 +70,7 @@ namespace {
|
||||
}
|
||||
|
||||
namespace pocketmine {
|
||||
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\ServerKiller;
|
||||
@ -78,9 +79,12 @@ namespace pocketmine {
|
||||
use pocketmine\wizard\SetupWizard;
|
||||
use raklib\RakLib;
|
||||
|
||||
const VERSION = "1.6.2dev";
|
||||
const API_VERSION = "3.0.0-ALPHA7";
|
||||
const CODENAME = "Unleashed";
|
||||
const NAME = "PocketMine-MP";
|
||||
const VERSION = "1.7dev";
|
||||
const API_VERSION = "3.0.0-ALPHA9";
|
||||
const CODENAME = "[REDACTED]";
|
||||
|
||||
const MIN_PHP_VERSION = "7.2.0RC3";
|
||||
|
||||
/*
|
||||
* Startup code. Do not look at it, it may harm you.
|
||||
@ -89,9 +93,9 @@ namespace pocketmine {
|
||||
* Enjoy it as much as I did writing it. I don't want to do it again.
|
||||
*/
|
||||
|
||||
if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
|
||||
echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
|
||||
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
|
||||
if(version_compare(MIN_PHP_VERSION, PHP_VERSION) > 0){
|
||||
echo "[CRITICAL] " . \pocketmine\NAME . " requires PHP >= " . MIN_PHP_VERSION . ", but you have PHP " . PHP_VERSION . "." . PHP_EOL;
|
||||
echo "[CRITICAL] Please use the installer provided on the homepage, or update to a newer PHP version." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -103,13 +107,15 @@ namespace pocketmine {
|
||||
|
||||
error_reporting(-1);
|
||||
|
||||
set_error_handler(function($severity, $message, $file, $line){
|
||||
function error_handler($severity, $message, $file, $line){
|
||||
if(error_reporting() & $severity){
|
||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||
}else{ //stfu operator
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set_error_handler('\pocketmine\error_handler');
|
||||
|
||||
if(!extension_loaded("phar")){
|
||||
echo "[CRITICAL] Unable to find the Phar extension." . PHP_EOL;
|
||||
@ -120,30 +126,40 @@ namespace pocketmine {
|
||||
if(\Phar::running(true) !== ""){
|
||||
define('pocketmine\PATH', \Phar::running(true) . "/");
|
||||
}else{
|
||||
define('pocketmine\PATH', realpath(getcwd()) . DIRECTORY_SEPARATOR);
|
||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
$requiredSplVer = "0.0.1";
|
||||
if(!is_file(\pocketmine\PATH . "src/spl/version.php") or version_compare($requiredSplVer, require(\pocketmine\PATH . "src/spl/version.php")) > 0){
|
||||
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] Please update your submodules or use provided builds." . PHP_EOL;
|
||||
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(!is_file(\pocketmine\PATH . "src/spl/ClassLoader.php")){
|
||||
echo "[CRITICAL] Unable to find the PocketMine-SPL library." . PHP_EOL;
|
||||
echo "[CRITICAL] Please use provided builds or clone the repository recursively." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
require_once(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require_once(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
|
||||
/*
|
||||
* We now use the Composer autoloader, but this autoloader is still used by RakLib and for loading plugins.
|
||||
*/
|
||||
$autoloader = new \BaseClassLoader();
|
||||
$autoloader->addPath(\pocketmine\PATH . "src");
|
||||
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "spl");
|
||||
$autoloader->register(true);
|
||||
$autoloader->register(false);
|
||||
|
||||
if(!class_exists(RakLib::class)){
|
||||
echo "[CRITICAL] Unable to find the RakLib library." . PHP_EOL;
|
||||
@ -186,40 +202,51 @@ namespace pocketmine {
|
||||
$logger = new MainLogger(\pocketmine\DATA . "server.log");
|
||||
$logger->registerStatic();
|
||||
|
||||
if(!ini_get("date.timezone")){
|
||||
do{
|
||||
$timezone = ini_get("date.timezone");
|
||||
if($timezone !== ""){
|
||||
/*
|
||||
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
||||
* an incorrect timezone abbreviation in php.ini apparently.
|
||||
*/
|
||||
if(strpos($timezone, "/") === false){
|
||||
$default_timezone = timezone_name_from_abbr($timezone);
|
||||
if($default_timezone !== false){
|
||||
ini_set("date.timezone", $default_timezone);
|
||||
date_default_timezone_set($default_timezone);
|
||||
break;
|
||||
}else{
|
||||
//Bad php.ini value, try another method to detect timezone
|
||||
$logger->warning("Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection");
|
||||
}
|
||||
}else{
|
||||
date_default_timezone_set($timezone);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
||||
//Success! Timezone has already been set and validated in the if statement.
|
||||
//This here is just for redundancy just in case some program wants to read timezone data from the ini.
|
||||
ini_set("date.timezone", $timezone);
|
||||
}else{
|
||||
//If system timezone detection fails or timezone is an invalid value.
|
||||
if($response = Utils::getURL("http://ip-api.com/json")
|
||||
and $ip_geolocation_data = json_decode($response, true)
|
||||
and $ip_geolocation_data['status'] !== 'fail'
|
||||
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
||||
){
|
||||
//Again, for redundancy.
|
||||
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
||||
}else{
|
||||
ini_set("date.timezone", "UTC");
|
||||
date_default_timezone_set("UTC");
|
||||
$logger->warning("Timezone could not be automatically determined. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
/*
|
||||
* This is here so that people don't come to us complaining and fill up the issue tracker when they put
|
||||
* an incorrect timezone abbreviation in php.ini apparently.
|
||||
*/
|
||||
$timezone = ini_get("date.timezone");
|
||||
if(strpos($timezone, "/") === false){
|
||||
$default_timezone = timezone_name_from_abbr($timezone);
|
||||
ini_set("date.timezone", $default_timezone);
|
||||
date_default_timezone_set($default_timezone);
|
||||
}else{
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
if($response = Utils::getURL("http://ip-api.com/json") //If system timezone detection fails or timezone is an invalid value.
|
||||
and $ip_geolocation_data = json_decode($response, true)
|
||||
and $ip_geolocation_data['status'] !== 'fail'
|
||||
and date_default_timezone_set($ip_geolocation_data['timezone'])
|
||||
){
|
||||
//Again, for redundancy.
|
||||
ini_set("date.timezone", $ip_geolocation_data['timezone']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ini_set("date.timezone", "UTC");
|
||||
date_default_timezone_set("UTC");
|
||||
$logger->warning("Timezone could not be automatically determined or was set to an invalid value. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file.");
|
||||
}while(false);
|
||||
|
||||
|
||||
function detect_system_timezone(){
|
||||
switch(Utils::getOS()){
|
||||
@ -408,7 +435,7 @@ namespace pocketmine {
|
||||
return (is_object($value) ? get_class($value) . " object" : gettype($value) . " " . (is_array($value) ? "Array()" : Utils::printable(@strval($value))));
|
||||
}, $args));
|
||||
}
|
||||
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . ($trace[$i]["line"] ?? "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
||||
$messages[] = "#$j " . (isset($trace[$i]["file"]) ? cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
|
||||
}
|
||||
|
||||
return $messages;
|
||||
@ -424,13 +451,13 @@ namespace pocketmine {
|
||||
$errors = 0;
|
||||
|
||||
if(PHP_INT_SIZE < 8){
|
||||
$logger->critical("Running PocketMine-MP with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
|
||||
$logger->critical("Running " . \pocketmine\NAME . " with 32-bit systems/PHP is no longer supported. Please upgrade to a 64-bit system or use a 64-bit PHP binary.");
|
||||
$exitCode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(php_sapi_name() !== "cli"){
|
||||
$logger->critical("You must run PocketMine-MP using the CLI.");
|
||||
$logger->critical("You must run " . \pocketmine\NAME . " using the CLI.");
|
||||
++$errors;
|
||||
}
|
||||
|
||||
@ -438,8 +465,8 @@ namespace pocketmine {
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "3.1.5") < 0){
|
||||
$logger->critical("pthreads >= 3.1.5 is required, while you have $pthreads_version.");
|
||||
if(version_compare($pthreads_version, "3.1.7-dev") < 0){
|
||||
$logger->critical("pthreads >= 3.1.7-dev is required, while you have $pthreads_version.");
|
||||
++$errors;
|
||||
}
|
||||
|
||||
@ -462,7 +489,7 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
if(extension_loaded("xdebug")){
|
||||
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running PocketMine with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
||||
$logger->warning(PHP_EOL . PHP_EOL . PHP_EOL . "\tYou are running " . \pocketmine\NAME . " with xdebug enabled. This has a major impact on performance." . PHP_EOL . PHP_EOL);
|
||||
}
|
||||
|
||||
$extensions = [
|
||||
@ -524,7 +551,7 @@ namespace pocketmine {
|
||||
|
||||
|
||||
if(\Phar::running(true) === ""){
|
||||
$logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
|
||||
$logger->warning("Non-packaged " . \pocketmine\NAME . " installation detected. Consider using a phar in production for better performance.");
|
||||
}
|
||||
|
||||
ThreadManager::init();
|
||||
@ -536,19 +563,7 @@ namespace pocketmine {
|
||||
$killer->start();
|
||||
usleep(10000); //Fixes ServerKiller not being able to start on single-core machines
|
||||
|
||||
$erroredThreads = 0;
|
||||
foreach(ThreadManager::getInstance()->getAll() as $id => $thread){
|
||||
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
||||
try{
|
||||
$thread->quit();
|
||||
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
||||
}catch(\ThreadException $e){
|
||||
++$erroredThreads;
|
||||
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if($erroredThreads > 0){
|
||||
if(ThreadManager::getInstance()->stopAll() > 0){
|
||||
if(\pocketmine\DEBUG > 1){
|
||||
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\command\SimpleCommandMap;
|
||||
use pocketmine\entity\Attribute;
|
||||
use pocketmine\entity\Effect;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Skin;
|
||||
use pocketmine\event\HandlerList;
|
||||
use pocketmine\event\level\LevelInitEvent;
|
||||
use pocketmine\event\level\LevelLoadEvent;
|
||||
@ -47,7 +48,6 @@ use pocketmine\event\Timings;
|
||||
use pocketmine\event\TimingsHandler;
|
||||
use pocketmine\event\TranslationContainer;
|
||||
use pocketmine\inventory\CraftingManager;
|
||||
use pocketmine\inventory\InventoryType;
|
||||
use pocketmine\inventory\Recipe;
|
||||
use pocketmine\item\enchantment\Enchantment;
|
||||
use pocketmine\item\ItemFactory;
|
||||
@ -83,6 +83,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||
use pocketmine\network\mcpe\protocol\DataPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\RakLibInterface;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\query\QueryHandler;
|
||||
@ -194,6 +195,9 @@ class Server{
|
||||
/** @var int */
|
||||
private $maxPlayers;
|
||||
|
||||
/** @var bool */
|
||||
private $onlineMode = true;
|
||||
|
||||
/** @var bool */
|
||||
private $autoSave;
|
||||
|
||||
@ -273,7 +277,7 @@ class Server{
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string{
|
||||
return "PocketMine-MP";
|
||||
return \pocketmine\NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,6 +343,24 @@ class Server{
|
||||
return $this->maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||
* are not logged into Xbox Live will be disconnected.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getOnlineMode() : bool{
|
||||
return $this->onlineMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of {@link #getOnlineMode()}.
|
||||
* @return bool
|
||||
*/
|
||||
public function requiresAuthentication() : bool{
|
||||
return $this->getOnlineMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
@ -494,36 +516,17 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @deprecated Moved to {@link Level#getDifficultyFromString}
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
public static function getDifficultyFromString(string $str) : int{
|
||||
switch(strtolower(trim($str))){
|
||||
case "0":
|
||||
case "peaceful":
|
||||
case "p":
|
||||
return 0;
|
||||
|
||||
case "1":
|
||||
case "easy":
|
||||
case "e":
|
||||
return 1;
|
||||
|
||||
case "2":
|
||||
case "normal":
|
||||
case "n":
|
||||
return 2;
|
||||
|
||||
case "3":
|
||||
case "hard":
|
||||
case "h":
|
||||
return 3;
|
||||
}
|
||||
return -1;
|
||||
return Level::getDifficultyFromString($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Server global difficulty. Note that this may be overridden in individual Levels.
|
||||
* @return int
|
||||
*/
|
||||
public function getDifficulty() : int{
|
||||
@ -569,7 +572,7 @@ class Server{
|
||||
* @return 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->y),
|
||||
new DoubleTag("", $spawn->z)
|
||||
]),
|
||||
], NBT::TAG_Double),
|
||||
new StringTag("Level", $this->getDefaultLevel()->getName()),
|
||||
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getName()),
|
||||
//new IntTag("SpawnX", (int) $spawn->x),
|
||||
//new IntTag("SpawnY", (int) $spawn->y),
|
||||
//new IntTag("SpawnZ", (int) $spawn->z),
|
||||
//new ByteTag("SpawnForced", 1), //TODO
|
||||
new ListTag("Inventory", []),
|
||||
new ListTag("Inventory", [], NBT::TAG_Compound),
|
||||
new CompoundTag("Achievements", []),
|
||||
new IntTag("playerGameType", $this->getGamemode()),
|
||||
new ListTag("Motion", [
|
||||
new DoubleTag("", 0.0),
|
||||
new DoubleTag("", 0.0),
|
||||
new DoubleTag("", 0.0)
|
||||
]),
|
||||
], NBT::TAG_Double),
|
||||
new ListTag("Rotation", [
|
||||
new FloatTag("", 0.0),
|
||||
new FloatTag("", 0.0)
|
||||
]),
|
||||
], NBT::TAG_Float),
|
||||
new FloatTag("FallDistance", 0.0),
|
||||
new ShortTag("Fire", 0),
|
||||
new ShortTag("Air", 300),
|
||||
@ -787,10 +790,6 @@ class Server{
|
||||
new ByteTag("Invulnerable", 0),
|
||||
new StringTag("NameTag", $name)
|
||||
]);
|
||||
$nbt->Pos->setTagType(NBT::TAG_Double);
|
||||
$nbt->Inventory->setTagType(NBT::TAG_Compound);
|
||||
$nbt->Motion->setTagType(NBT::TAG_Double);
|
||||
$nbt->Rotation->setTagType(NBT::TAG_Float);
|
||||
|
||||
return $nbt;
|
||||
|
||||
@ -915,7 +914,7 @@ class Server{
|
||||
/**
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getDefaultLevel(){
|
||||
public function getDefaultLevel() : ?Level{
|
||||
return $this->levelDefault;
|
||||
}
|
||||
|
||||
@ -926,7 +925,7 @@ class Server{
|
||||
*
|
||||
* @param Level|null $level
|
||||
*/
|
||||
public function setDefaultLevel($level){
|
||||
public function setDefaultLevel(?Level $level) : void{
|
||||
if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){
|
||||
$this->levelDefault = $level;
|
||||
}
|
||||
@ -946,12 +945,8 @@ class Server{
|
||||
*
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getLevel(int $levelId){
|
||||
if(isset($this->levels[$levelId])){
|
||||
return $this->levels[$levelId];
|
||||
}
|
||||
|
||||
return null;
|
||||
public function getLevel(int $levelId) : ?Level{
|
||||
return $this->levels[$levelId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -961,7 +956,7 @@ class Server{
|
||||
*
|
||||
* @return Level|null
|
||||
*/
|
||||
public function getLevelByName(string $name){
|
||||
public function getLevelByName(string $name) : ?Level{
|
||||
foreach($this->getLevels() as $level){
|
||||
if($level->getFolderName() === $name){
|
||||
return $level;
|
||||
@ -983,13 +978,16 @@ class Server{
|
||||
if($level === $this->getDefaultLevel() and !$forceUnload){
|
||||
throw new \InvalidStateException("The default level cannot be unloaded while running, please switch levels.");
|
||||
}
|
||||
if($level->unload($forceUnload) === true){
|
||||
unset($this->levels[$level->getId()]);
|
||||
|
||||
return true;
|
||||
}
|
||||
return $level->unload($forceUnload);
|
||||
}
|
||||
|
||||
return false;
|
||||
/**
|
||||
* @internal
|
||||
* @param Level $level
|
||||
*/
|
||||
public function removeLevel(Level $level) : void{
|
||||
unset($this->levels[$level->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1463,7 +1461,7 @@ class Server{
|
||||
|
||||
$this->logger->info("Loading server properties...");
|
||||
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, [
|
||||
"motd" => "Minecraft: PE Server",
|
||||
"motd" => \pocketmine\NAME . " Server",
|
||||
"server-port" => 19132,
|
||||
"white-list" => false,
|
||||
"announce-player-achievements" => true,
|
||||
@ -1485,10 +1483,11 @@ class Server{
|
||||
"enable-rcon" => false,
|
||||
"rcon.password" => substr(base64_encode(random_bytes(20)), 3, 10),
|
||||
"auto-save" => true,
|
||||
"view-distance" => 8
|
||||
"view-distance" => 8,
|
||||
"xbox-auth" => true
|
||||
]);
|
||||
|
||||
$this->forceLanguage = $this->getProperty("settings.force-language", false);
|
||||
$this->forceLanguage = (bool) $this->getProperty("settings.force-language", false);
|
||||
$this->baseLang = new BaseLang($this->getProperty("settings.language", BaseLang::FALLBACK_LANGUAGE));
|
||||
$this->logger->info($this->getLanguage()->translateString("language.selected", [$this->getLanguage()->getName(), $this->getLanguage()->getLang()]));
|
||||
|
||||
@ -1512,7 +1511,12 @@ class Server{
|
||||
}else{
|
||||
Network::$BATCH_THRESHOLD = -1;
|
||||
}
|
||||
|
||||
$this->networkCompressionLevel = $this->getProperty("network.compression-level", 7);
|
||||
if($this->networkCompressionLevel < 1 or $this->networkCompressionLevel > 9){
|
||||
$this->logger->warning("Invalid network compression level $this->networkCompressionLevel set, setting to default 7");
|
||||
$this->networkCompressionLevel = 7;
|
||||
}
|
||||
$this->networkCompressionAsync = $this->getProperty("network.async-compression", true);
|
||||
|
||||
$this->autoTickRate = (bool) $this->getProperty("level-settings.auto-tick-rate", true);
|
||||
@ -1558,8 +1562,18 @@ class Server{
|
||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
||||
|
||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
||||
$this->setConfigInt("difficulty", 3);
|
||||
$this->onlineMode = $this->getConfigBoolean("xbox-auth", true);
|
||||
if($this->onlineMode){
|
||||
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.auth", ["enabled", "will"]));
|
||||
$this->logger->notice($this->getLanguage()->translateString("pocketmine.server.authProperty", ["disable", "false"]));
|
||||
}else{
|
||||
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.auth", ["disabled", "will not"]));
|
||||
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authWarning"));
|
||||
$this->logger->warning($this->getLanguage()->translateString("pocketmine.server.authProperty", ["enable", "true"]));
|
||||
}
|
||||
|
||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
if(\pocketmine\DEBUG >= 0){
|
||||
@ -1585,6 +1599,7 @@ class Server{
|
||||
]));
|
||||
$this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()]));
|
||||
|
||||
|
||||
Timings::init();
|
||||
|
||||
$this->consoleSender = new ConsoleCommandSender();
|
||||
@ -1592,7 +1607,6 @@ class Server{
|
||||
|
||||
Entity::init();
|
||||
Tile::init();
|
||||
InventoryType::init();
|
||||
BlockFactory::init();
|
||||
Enchantment::init();
|
||||
ItemFactory::init();
|
||||
@ -1638,23 +1652,23 @@ class Server{
|
||||
Generator::addGenerator(Nether::class, "hell");
|
||||
Generator::addGenerator(Nether::class, "nether");
|
||||
|
||||
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
|
||||
foreach((array) $this->getProperty("worlds", []) as $name => $options){
|
||||
if($this->loadLevel($name) === false){
|
||||
$seed = $this->getProperty("worlds.$name.seed", time());
|
||||
$seed = $options["seed"] ?? time();
|
||||
if(is_string($seed) and !is_numeric($seed)){
|
||||
$seed = Utils::javaStringHash($seed);
|
||||
}elseif(!is_int($seed)){
|
||||
$seed = (int) $seed;
|
||||
}
|
||||
|
||||
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
|
||||
$generator = Generator::getGenerator(array_shift($options));
|
||||
if(count($options) > 0){
|
||||
$options = [
|
||||
"preset" => implode(":", $options)
|
||||
];
|
||||
if(isset($options["generator"])){
|
||||
$generatorOptions = explode(":", $options["generator"]);
|
||||
$generator = Generator::getGenerator(array_shift($generatorOptions));
|
||||
if(count($options) > 0){
|
||||
$options["preset"] = implode(":", $generatorOptions);
|
||||
}
|
||||
}else{
|
||||
$options = [];
|
||||
$generator = Generator::getGenerator("default");
|
||||
}
|
||||
|
||||
$this->generateLevel($name, $seed, $generator, $options);
|
||||
@ -1975,8 +1989,8 @@ class Server{
|
||||
$this->properties->reload();
|
||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||
|
||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < 3){
|
||||
$this->setConfigInt("difficulty", 3);
|
||||
if($this->getConfigBoolean("hardcore", false) === true and $this->getDifficulty() < Level::DIFFICULTY_HARD){
|
||||
$this->setConfigInt("difficulty", Level::DIFFICULTY_HARD);
|
||||
}
|
||||
|
||||
$this->banByIP->load();
|
||||
@ -2271,7 +2285,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function addOnlinePlayer(Player $player){
|
||||
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
|
||||
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||
|
||||
$this->playerList[$player->getRawUniqueId()] = $player;
|
||||
}
|
||||
@ -2280,32 +2294,44 @@ class Server{
|
||||
if(isset($this->playerList[$player->getRawUniqueId()])){
|
||||
unset($this->playerList[$player->getRawUniqueId()]);
|
||||
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$player->getUniqueId()];
|
||||
$this->broadcastPacket($this->playerList, $pk);
|
||||
$this->removePlayerListData($player->getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePlayerListData(UUID $uuid, $entityId, $name, $skinId, $skinData, array $players = null){
|
||||
/**
|
||||
* @param UUID $uuid
|
||||
* @param int $entityId
|
||||
* @param string $name
|
||||
* @param Skin $skin
|
||||
* @param Player[]|null $players
|
||||
*/
|
||||
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||
$pk->entries[] = [$uuid, $entityId, $name, $skinId, $skinData];
|
||||
|
||||
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
|
||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UUID $uuid
|
||||
* @param Player[]|null $players
|
||||
*/
|
||||
public function removePlayerListData(UUID $uuid, array $players = null){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$uuid];
|
||||
$pk->entries[] = PlayerListEntry::createRemovalEntry($uuid);
|
||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Player $p
|
||||
*/
|
||||
public function sendFullPlayerListData(Player $p){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||
foreach($this->playerList as $player){
|
||||
$pk->entries[] = [$player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData()];
|
||||
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||
}
|
||||
|
||||
$p->dataPacket($pk);
|
||||
@ -2375,7 +2401,7 @@ class Server{
|
||||
}
|
||||
|
||||
public function sendUsage($type = SendUsageTask::TYPE_STATUS){
|
||||
if($this->getProperty("anonymous-statistics.enabled", true)){
|
||||
if((bool) $this->getProperty("anonymous-statistics.enabled", true)){
|
||||
$this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers));
|
||||
}
|
||||
$this->uniquePlayers = [];
|
||||
@ -2426,8 +2452,6 @@ class Server{
|
||||
" kB/s | TPS " . $this->getTicksPerSecondAverage() .
|
||||
" | Load " . $this->getTickUsageAverage() . "%\x07";
|
||||
|
||||
$this->network->resetStatistics();
|
||||
|
||||
Timings::$titleTickTimer->stopTiming();
|
||||
}
|
||||
|
||||
@ -2488,25 +2512,26 @@ class Server{
|
||||
$player->checkNetwork();
|
||||
}
|
||||
|
||||
if(($this->tickCounter & 0b1111) === 0){
|
||||
if(($this->tickCounter % 20) === 0){
|
||||
if($this->doTitleTick and Terminal::hasFormattingCodes()){
|
||||
$this->titleTick();
|
||||
}
|
||||
$this->currentTPS = 20;
|
||||
$this->currentUse = 0;
|
||||
|
||||
if(($this->tickCounter & 0b111111111) === 0){
|
||||
try{
|
||||
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
||||
if($this->queryHandler !== null){
|
||||
$this->queryHandler->regenerateInfo();
|
||||
}
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
$this->network->updateName();
|
||||
$this->network->resetStatistics();
|
||||
}
|
||||
|
||||
$this->getNetwork()->updateName();
|
||||
if(($this->tickCounter & 0b111111111) === 0){
|
||||
try{
|
||||
$this->getPluginManager()->callEvent($this->queryRegenerateTask = new QueryRegenerateEvent($this, 5));
|
||||
if($this->queryHandler !== null){
|
||||
$this->queryHandler->regenerateInfo();
|
||||
}
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){
|
||||
|
@ -51,16 +51,17 @@ abstract class Thread extends \Thread{
|
||||
* (unless you are using a custom autoloader).
|
||||
*/
|
||||
public function registerClassLoader(){
|
||||
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||
if(!interface_exists("ClassLoader", false)){
|
||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
if($this->classLoader !== null){
|
||||
$this->classLoader->register(true);
|
||||
$this->classLoader->register(false);
|
||||
}
|
||||
}
|
||||
|
||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||
ThreadManager::getInstance()->add($this);
|
||||
|
||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\utils\MainLogger;
|
||||
|
||||
class ThreadManager extends \Volatile{
|
||||
|
||||
/** @var ThreadManager */
|
||||
@ -68,4 +70,23 @@ class ThreadManager extends \Volatile{
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function stopAll() : int{
|
||||
$logger = MainLogger::getLogger();
|
||||
|
||||
$erroredThreads = 0;
|
||||
|
||||
foreach($this->getAll() as $thread){
|
||||
$logger->debug("Stopping " . $thread->getThreadName() . " thread");
|
||||
try{
|
||||
$thread->quit();
|
||||
$logger->debug($thread->getThreadName() . " thread stopped successfully.");
|
||||
}catch(\ThreadException $e){
|
||||
++$erroredThreads;
|
||||
$logger->debug("Could not stop " . $thread->getThreadName() . " thread: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $erroredThreads;
|
||||
}
|
||||
}
|
@ -52,16 +52,17 @@ abstract class Worker extends \Worker{
|
||||
* (unless you are using a custom autoloader).
|
||||
*/
|
||||
public function registerClassLoader(){
|
||||
require(\pocketmine\PATH . "vendor/autoload.php");
|
||||
if(!interface_exists("ClassLoader", false)){
|
||||
require(\pocketmine\PATH . "src/spl/ClassLoader.php");
|
||||
require(\pocketmine\PATH . "src/spl/BaseClassLoader.php");
|
||||
}
|
||||
if($this->classLoader !== null){
|
||||
$this->classLoader->register(true);
|
||||
$this->classLoader->register(false);
|
||||
}
|
||||
}
|
||||
|
||||
public function start(int $options = PTHREADS_INHERIT_ALL){
|
||||
public function start(?int $options = \PTHREADS_INHERIT_ALL){
|
||||
ThreadManager::getInstance()->add($this);
|
||||
|
||||
if(!$this->isRunning() and !$this->isJoined() and !$this->isTerminated()){
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
|
||||
/**
|
||||
@ -54,7 +55,7 @@ class Air extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -66,10 +67,14 @@ class Air extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return -1;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\inventory\AnvilInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
@ -38,14 +39,14 @@ class Anvil extends Fallable{
|
||||
|
||||
protected $id = self::ANVIL;
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isTransparent() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 5;
|
||||
}
|
||||
@ -67,6 +68,30 @@ class Anvil extends Fallable{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$inset = 0.125;
|
||||
|
||||
if($this->meta & 0x01){ //east/west
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + $inset,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1 - $inset
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $inset,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1 - $inset,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->addWindow(new AnvilInventory($this));
|
||||
|
@ -29,10 +29,6 @@ use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Bed as TileBed;
|
||||
use pocketmine\tile\Tile;
|
||||
@ -58,7 +54,7 @@ class Bed extends Transparent{
|
||||
return "Bed Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -129,7 +125,7 @@ class Bed extends Transparent{
|
||||
/**
|
||||
* @return Bed|null
|
||||
*/
|
||||
public function getOtherHalf(){
|
||||
public function getOtherHalf() : ?Bed{
|
||||
$other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart()));
|
||||
if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){
|
||||
return $other;
|
||||
@ -184,20 +180,8 @@ class Bed extends Transparent{
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get($this->id, $meta), true, true);
|
||||
$this->getLevel()->setBlock($next, BlockFactory::get($this->id, $meta | self::BITFLAG_HEAD), true, true);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::BED),
|
||||
new ByteTag("color", $item->getDamage() & 0x0f),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z)
|
||||
]);
|
||||
|
||||
$nbt2 = clone $nbt;
|
||||
$nbt2["x"] = $next->x;
|
||||
$nbt2["z"] = $next->z;
|
||||
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), $nbt2);
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($this, $face, $item, $player));
|
||||
Tile::createTile(Tile::BED, $this->getLevel(), TileBed::createNBT($next, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -209,7 +193,7 @@ class Bed extends Transparent{
|
||||
public function onBreak(Item $item, Player $player = null) : bool{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
if(($other = $this->getOtherHalf()) !== null){
|
||||
$this->getLevel()->useBreakOn($other, $item, $player, $player !== null); //make sure tiles get removed
|
||||
$this->getLevel()->useBreakOn($other, $item, null, $player !== null); //make sure tiles get removed
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -61,7 +61,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
protected $id;
|
||||
/** @var int */
|
||||
protected $meta = 0;
|
||||
/** @var string */
|
||||
/** @var string|null */
|
||||
protected $fallbackName;
|
||||
/** @var int|null */
|
||||
protected $itemId;
|
||||
@ -69,13 +69,17 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
/** @var AxisAlignedBB */
|
||||
public $boundingBox = null;
|
||||
|
||||
|
||||
/** @var AxisAlignedBB[]|null */
|
||||
protected $collisionBoxes = null;
|
||||
|
||||
/**
|
||||
* @param int $id The block type's ID, 0-255
|
||||
* @param int $meta Meta value of the block type
|
||||
* @param string $name English name of the block type (TODO: implement translations)
|
||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||
* @param int $id The block type's ID, 0-255
|
||||
* @param int $meta Meta value of the block type
|
||||
* @param string|null $name English name of the block type (TODO: implement translations)
|
||||
* @param int $itemId The item ID of the block type, used for block picking and dropping items.
|
||||
*/
|
||||
public function __construct(int $id, int $meta = 0, string $name = "Unknown", int $itemId = null){
|
||||
public function __construct(int $id, int $meta = 0, string $name = null, int $itemId = null){
|
||||
$this->id = $id;
|
||||
$this->meta = $meta;
|
||||
$this->fallbackName = $name;
|
||||
@ -86,7 +90,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @return string
|
||||
*/
|
||||
public function getName() : string{
|
||||
return $this->fallbackName;
|
||||
return $this->fallbackName ?? "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,7 +120,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
/**
|
||||
* @param int $meta
|
||||
*/
|
||||
final public function setDamage(int $meta){
|
||||
final public function setDamage(int $meta) : void{
|
||||
if($meta < 0 or $meta > 0xf){
|
||||
throw new \InvalidArgumentException("Block damage values must be 0-15, not $meta");
|
||||
}
|
||||
@ -136,6 +140,34 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block meta, stripped of non-variant flags.
|
||||
* @return int
|
||||
*/
|
||||
public function getVariant() : int{
|
||||
return $this->meta & $this->getVariantBitmask();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
* @return bool
|
||||
*/
|
||||
public function canBePlaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeReplaced() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return $blockReplace->canBeReplaced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
@ -163,6 +195,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeBrokenWith(Item $item) : bool{
|
||||
return $this->getHardness() !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
@ -175,6 +211,63 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the seconds that this block takes to be broken using an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$base = $this->getHardness() * 1.5;
|
||||
if($this->canBeBrokenWith($item)){
|
||||
if($this->getToolType() === Tool::TYPE_SHEARS and $item->isShears()){
|
||||
$base /= 15;
|
||||
}elseif(
|
||||
($this->getToolType() === Tool::TYPE_PICKAXE and ($tier = $item->isPickaxe()) !== false) or
|
||||
($this->getToolType() === Tool::TYPE_AXE and ($tier = $item->isAxe()) !== false) or
|
||||
($this->getToolType() === Tool::TYPE_SHOVEL and ($tier = $item->isShovel()) !== false)
|
||||
){
|
||||
switch($tier){
|
||||
case Tool::TIER_WOODEN:
|
||||
$base /= 2;
|
||||
break;
|
||||
case Tool::TIER_STONE:
|
||||
$base /= 4;
|
||||
break;
|
||||
case Tool::TIER_IRON:
|
||||
$base /= 6;
|
||||
break;
|
||||
case Tool::TIER_DIAMOND:
|
||||
$base /= 8;
|
||||
break;
|
||||
case Tool::TIER_GOLD:
|
||||
$base /= 12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$base *= 3.33;
|
||||
}
|
||||
|
||||
if($item->isSword()){
|
||||
$base *= 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
|
||||
*
|
||||
@ -266,32 +359,6 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether random block updates will be done on this block.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ticksRandomly() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
* @return bool
|
||||
*/
|
||||
public function canBePlaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Block|null $with
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@ -328,7 +395,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
}
|
||||
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||
|
||||
}
|
||||
|
||||
@ -337,7 +404,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*
|
||||
* @param Position $v
|
||||
*/
|
||||
final public function position(Position $v){
|
||||
final public function position(Position $v) : void{
|
||||
$this->x = (int) $v->x;
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
@ -354,60 +421,10 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
*/
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getDamage() & $this->getVariantBitmask(), 1)
|
||||
ItemFactory::get($this->getItemId(), $this->getVariant(), 1)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seconds that this block takes to be broken using an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
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.
|
||||
* @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)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
|
||||
*
|
||||
* @return Block[]
|
||||
*/
|
||||
public function getHorizontalSides() : array{
|
||||
return [
|
||||
$this->getSide(Vector3::SIDE_NORTH),
|
||||
$this->getSide(Vector3::SIDE_SOUTH),
|
||||
$this->getSide(Vector3::SIDE_WEST),
|
||||
$this->getSide(Vector3::SIDE_EAST)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the six blocks around this block.
|
||||
*
|
||||
* @return Block[]
|
||||
*/
|
||||
public function getAllSides() : array{
|
||||
return array_merge(
|
||||
[
|
||||
$this->getSide(Vector3::SIDE_DOWN),
|
||||
$this->getSide(Vector3::SIDE_UP)
|
||||
],
|
||||
$this->getHorizontalSides()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -447,22 +493,50 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
* @return bool
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||
$bb2 = $this->getBoundingBox();
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
|
||||
return $bb2 !== null and $bb->intersectsWith($bb2);
|
||||
foreach($bbs as $bb2){
|
||||
if($bb->intersectsWith($bb2)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
public function getCollisionBoxes() : array{
|
||||
if($this->collisionBoxes === null){
|
||||
$this->collisionBoxes = $this->recalculateCollisionBoxes();
|
||||
}
|
||||
|
||||
return $this->collisionBoxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
if($bb = $this->recalculateBoundingBox()){
|
||||
return [$bb];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB|null
|
||||
*/
|
||||
public function getBoundingBox(){
|
||||
public function getBoundingBox() : ?AxisAlignedBB{
|
||||
if($this->boundingBox === null){
|
||||
$this->boundingBox = $this->recalculateBoundingBox();
|
||||
}
|
||||
@ -472,7 +546,7 @@ class Block extends Position implements BlockIds, Metadatable{
|
||||
/**
|
||||
* @return AxisAlignedBB|null
|
||||
*/
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -483,92 +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 $pos2
|
||||
*
|
||||
* @return MovingObjectPosition|null
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2){
|
||||
$bb = $this->getBoundingBox();
|
||||
if($bb === null){
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?MovingObjectPosition{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(empty($bbs)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$v1 = $pos1->getIntermediateWithXValue($pos2, $bb->minX);
|
||||
$v2 = $pos1->getIntermediateWithXValue($pos2, $bb->maxX);
|
||||
$v3 = $pos1->getIntermediateWithYValue($pos2, $bb->minY);
|
||||
$v4 = $pos1->getIntermediateWithYValue($pos2, $bb->maxY);
|
||||
$v5 = $pos1->getIntermediateWithZValue($pos2, $bb->minZ);
|
||||
$v6 = $pos1->getIntermediateWithZValue($pos2, $bb->maxZ);
|
||||
/** @var MovingObjectPosition|null $currentHit */
|
||||
$currentHit = null;
|
||||
/** @var int|float $currentDistance */
|
||||
$currentDistance = PHP_INT_MAX;
|
||||
|
||||
if($v1 !== null and !$bb->isVectorInYZ($v1)){
|
||||
$v1 = null;
|
||||
foreach($bbs as $bb){
|
||||
$nextHit = $bb->calculateIntercept($pos1, $pos2);
|
||||
if($nextHit === null){
|
||||
continue;
|
||||
}
|
||||
|
||||
$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
|
||||
if($nextDistance < $currentDistance){
|
||||
$currentHit = $nextHit;
|
||||
$currentDistance = $nextDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if($v2 !== null and !$bb->isVectorInYZ($v2)){
|
||||
$v2 = null;
|
||||
if($currentHit !== null){
|
||||
$currentHit->blockX = $this->x;
|
||||
$currentHit->blockY = $this->y;
|
||||
$currentHit->blockZ = $this->z;
|
||||
}
|
||||
|
||||
if($v3 !== null and !$bb->isVectorInXZ($v3)){
|
||||
$v3 = null;
|
||||
}
|
||||
|
||||
if($v4 !== null and !$bb->isVectorInXZ($v4)){
|
||||
$v4 = null;
|
||||
}
|
||||
|
||||
if($v5 !== null and !$bb->isVectorInXY($v5)){
|
||||
$v5 = null;
|
||||
}
|
||||
|
||||
if($v6 !== null and !$bb->isVectorInXY($v6)){
|
||||
$v6 = null;
|
||||
}
|
||||
|
||||
$vector = $v1;
|
||||
|
||||
if($v2 !== null and ($vector === null or $pos1->distanceSquared($v2) < $pos1->distanceSquared($vector))){
|
||||
$vector = $v2;
|
||||
}
|
||||
|
||||
if($v3 !== null and ($vector === null or $pos1->distanceSquared($v3) < $pos1->distanceSquared($vector))){
|
||||
$vector = $v3;
|
||||
}
|
||||
|
||||
if($v4 !== null and ($vector === null or $pos1->distanceSquared($v4) < $pos1->distanceSquared($vector))){
|
||||
$vector = $v4;
|
||||
}
|
||||
|
||||
if($v5 !== null and ($vector === null or $pos1->distanceSquared($v5) < $pos1->distanceSquared($vector))){
|
||||
$vector = $v5;
|
||||
}
|
||||
|
||||
if($v6 !== null and ($vector === null or $pos1->distanceSquared($v6) < $pos1->distanceSquared($vector))){
|
||||
$vector = $v6;
|
||||
}
|
||||
|
||||
if($vector === null){
|
||||
return null;
|
||||
}
|
||||
|
||||
$f = -1;
|
||||
|
||||
if($vector === $v1){
|
||||
$f = 4;
|
||||
}elseif($vector === $v2){
|
||||
$f = 5;
|
||||
}elseif($vector === $v3){
|
||||
$f = 0;
|
||||
}elseif($vector === $v4){
|
||||
$f = 1;
|
||||
}elseif($vector === $v5){
|
||||
$f = 2;
|
||||
}elseif($vector === $v6){
|
||||
$f = 3;
|
||||
}
|
||||
|
||||
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
|
||||
return $currentHit;
|
||||
}
|
||||
|
||||
public function setMetadata(string $metadataKey, MetadataValue $newMetadataValue){
|
||||
|
@ -56,7 +56,7 @@ class BlockFactory{
|
||||
*
|
||||
* @param bool $force
|
||||
*/
|
||||
public static function init(bool $force = false){
|
||||
public static function init(bool $force = false) : void{
|
||||
if(self::$list === null or $force){
|
||||
self::$list = new \SplFixedArray(256);
|
||||
self::$fullList = new \SplFixedArray(4096);
|
||||
@ -133,7 +133,7 @@ class BlockFactory{
|
||||
self::registerBlock(new Furnace());
|
||||
self::registerBlock(new BurningFurnace());
|
||||
self::registerBlock(new SignPost());
|
||||
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door Block", Item::OAK_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::OAK_DOOR_BLOCK, 0, "Oak Door", Item::OAK_DOOR));
|
||||
self::registerBlock(new Ladder());
|
||||
self::registerBlock(new Rail());
|
||||
self::registerBlock(new CobblestoneStairs());
|
||||
@ -153,8 +153,8 @@ class BlockFactory{
|
||||
self::registerBlock(new Cactus());
|
||||
self::registerBlock(new Clay());
|
||||
self::registerBlock(new Sugarcane());
|
||||
|
||||
self::registerBlock(new Fence());
|
||||
//TODO: JUKEBOX
|
||||
self::registerBlock(new WoodenFence());
|
||||
self::registerBlock(new Pumpkin());
|
||||
self::registerBlock(new Netherrack());
|
||||
self::registerBlock(new SoulSand());
|
||||
@ -168,8 +168,8 @@ class BlockFactory{
|
||||
self::registerBlock(new Trapdoor());
|
||||
//TODO: MONSTER_EGG
|
||||
self::registerBlock(new StoneBricks());
|
||||
//TODO: BROWN_MUSHROOM_BLOCK
|
||||
//TODO: RED_MUSHROOM_BLOCK
|
||||
self::registerBlock(new BrownMushroomBlock());
|
||||
self::registerBlock(new RedMushroomBlock());
|
||||
self::registerBlock(new IronBars());
|
||||
self::registerBlock(new GlassPane());
|
||||
self::registerBlock(new Melon());
|
||||
@ -245,12 +245,13 @@ class BlockFactory{
|
||||
self::registerBlock(new Coal());
|
||||
self::registerBlock(new PackedIce());
|
||||
self::registerBlock(new DoublePlant());
|
||||
|
||||
//TODO: STANDING_BANNER
|
||||
//TODO: WALL_BANNER
|
||||
//TODO: DAYLIGHT_DETECTOR_INVERTED
|
||||
//TODO: RED_SANDSTONE
|
||||
//TODO: RED_SANDSTONE_STAIRS
|
||||
//TODO: DOUBLE_STONE_SLAB2
|
||||
//TODO: STONE_SLAB2
|
||||
self::registerBlock(new RedSandstone());
|
||||
self::registerBlock(new RedSandstoneStairs());
|
||||
self::registerBlock(new DoubleStoneSlab2());
|
||||
self::registerBlock(new StoneSlab2());
|
||||
self::registerBlock(new FenceGate(Block::SPRUCE_FENCE_GATE, 0, "Spruce Fence Gate"));
|
||||
self::registerBlock(new FenceGate(Block::BIRCH_FENCE_GATE, 0, "Birch Fence Gate"));
|
||||
self::registerBlock(new FenceGate(Block::JUNGLE_FENCE_GATE, 0, "Jungle Fence Gate"));
|
||||
@ -259,19 +260,20 @@ class BlockFactory{
|
||||
//TODO: REPEATING_COMMAND_BLOCK
|
||||
//TODO: CHAIN_COMMAND_BLOCK
|
||||
|
||||
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door Block", Item::SPRUCE_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door Block", Item::BIRCH_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door Block", Item::JUNGLE_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door Block", Item::ACACIA_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door Block", Item::DARK_OAK_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::SPRUCE_DOOR_BLOCK, 0, "Spruce Door", Item::SPRUCE_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::BIRCH_DOOR_BLOCK, 0, "Birch Door", Item::BIRCH_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::JUNGLE_DOOR_BLOCK, 0, "Jungle Door", Item::JUNGLE_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::ACACIA_DOOR_BLOCK, 0, "Acacia Door", Item::ACACIA_DOOR));
|
||||
self::registerBlock(new WoodenDoor(Block::DARK_OAK_DOOR_BLOCK, 0, "Dark Oak Door", Item::DARK_OAK_DOOR));
|
||||
self::registerBlock(new GrassPath());
|
||||
self::registerBlock(new ItemFrame());
|
||||
//TODO: CHORUS_FLOWER
|
||||
//TODO: PURPUR_BLOCK
|
||||
self::registerBlock(new Purpur());
|
||||
|
||||
//TODO: PURPUR_STAIRS
|
||||
self::registerBlock(new PurpurStairs());
|
||||
|
||||
//TODO: END_BRICKS
|
||||
//TODO: UNDYED_SHULKER_BOX
|
||||
self::registerBlock(new EndStoneBricks());
|
||||
//TODO: FROSTED_ICE
|
||||
self::registerBlock(new EndRod());
|
||||
//TODO: END_GATEWAY
|
||||
@ -300,7 +302,7 @@ class BlockFactory{
|
||||
self::registerBlock(new GlazedTerracotta(Block::RED_GLAZED_TERRACOTTA, 0, "Red Glazed Terracotta"));
|
||||
self::registerBlock(new GlazedTerracotta(Block::BLACK_GLAZED_TERRACOTTA, 0, "Black Glazed Terracotta"));
|
||||
self::registerBlock(new Concrete());
|
||||
//TODO: CONCRETEPOWDER
|
||||
self::registerBlock(new ConcretePowder());
|
||||
|
||||
//TODO: CHORUS_PLANT
|
||||
self::registerBlock(new StainedGlass());
|
||||
@ -314,6 +316,7 @@ class BlockFactory{
|
||||
//TODO: INFO_UPDATE2
|
||||
//TODO: MOVINGBLOCK
|
||||
//TODO: OBSERVER
|
||||
//TODO: STRUCTURE_BLOCK
|
||||
|
||||
//TODO: RESERVED6
|
||||
|
||||
@ -338,10 +341,10 @@ class BlockFactory{
|
||||
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
|
||||
* $override parameter.
|
||||
*/
|
||||
public static function registerBlock(Block $block, bool $override = false){
|
||||
public static function registerBlock(Block $block, bool $override = false) : void{
|
||||
$id = $block->getId();
|
||||
|
||||
if(self::$list[$id] !== null and !(self::$list[$id] instanceof UnknownBlock) and !$override){
|
||||
if(!$override and self::isRegistered($id)){
|
||||
throw new \RuntimeException("Trying to overwrite an already registered block");
|
||||
}
|
||||
|
||||
@ -403,4 +406,15 @@ class BlockFactory{
|
||||
public static function getBlockStatesArray() : \SplFixedArray{
|
||||
return self::$fullList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a specified block ID is already registered in the block factory.
|
||||
*
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public static function isRegistered(int $id) : bool{
|
||||
$b = self::$list[$id];
|
||||
return $b !== null and !($b instanceof UnknownBlock);
|
||||
}
|
||||
}
|
@ -109,7 +109,7 @@ interface BlockIds{
|
||||
const CACTUS = 81;
|
||||
const CLAY_BLOCK = 82;
|
||||
const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
|
||||
|
||||
const JUKEBOX = 84;
|
||||
const FENCE = 85;
|
||||
const PUMPKIN = 86;
|
||||
const NETHERRACK = 87;
|
||||
@ -201,7 +201,8 @@ interface BlockIds{
|
||||
const COAL_BLOCK = 173;
|
||||
const PACKED_ICE = 174;
|
||||
const DOUBLE_PLANT = 175;
|
||||
|
||||
const STANDING_BANNER = 176;
|
||||
const WALL_BANNER = 177;
|
||||
const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
|
||||
const RED_SANDSTONE = 179;
|
||||
const RED_SANDSTONE_STAIRS = 180;
|
||||
@ -227,6 +228,7 @@ interface BlockIds{
|
||||
|
||||
const PURPUR_STAIRS = 203;
|
||||
|
||||
const UNDYED_SHULKER_BOX = 205;
|
||||
const END_BRICKS = 206;
|
||||
const FROSTED_ICE = 207;
|
||||
const END_ROD = 208;
|
||||
@ -270,6 +272,7 @@ interface BlockIds{
|
||||
const INFO_UPDATE2 = 249;
|
||||
const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
|
||||
const OBSERVER = 251;
|
||||
const STRUCTURE_BLOCK = 252;
|
||||
|
||||
const RESERVED6 = 255;
|
||||
|
||||
|
@ -60,7 +60,7 @@ class BoneBlock extends Solid{
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item); // TODO: Change the autogenerated stub
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
@ -21,18 +21,21 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class IronDoor extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::IRON_DOOR_BLOCK);
|
||||
parent::__construct(self::IRON_DOOR, $meta, "Iron Door");
|
||||
class BrownMushroomBlock extends RedMushroomBlock{
|
||||
|
||||
protected $id = Block::BROWN_MUSHROOM_BLOCK;
|
||||
|
||||
public function getName() : string{
|
||||
return "Brown Mushroom Block";
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
Item::get(Item::BROWN_MUSHROOM, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
}
|
@ -26,10 +26,6 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Furnace as TileFurnace;
|
||||
@ -68,26 +64,8 @@ class BurningFurnace extends Solid{
|
||||
];
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Items", []),
|
||||
new StringTag("id", Tile::FURNACE),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
|
||||
if($item->hasCustomName()){
|
||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
||||
}
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -96,15 +74,7 @@ class BurningFurnace extends Solid{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->getLevel()->getTile($this);
|
||||
if(!($furnace instanceof TileFurnace)){
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Items", []),
|
||||
new StringTag("id", Tile::FURNACE),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$furnace = Tile::createTile("Furnace", $this->getLevel(), $nbt);
|
||||
$furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this));
|
||||
}
|
||||
|
||||
if(isset($furnace->namedtag->Lock) and $furnace->namedtag->Lock instanceof StringTag){
|
||||
|
@ -21,14 +21,31 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
abstract class Button extends Flowable{
|
||||
|
||||
class Skull extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::SKULL_BLOCK);
|
||||
parent::__construct(self::SKULL, $meta, "Mob Head");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
@ -70,7 +70,7 @@ class Cactus extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
$entity->attack($ev);
|
||||
}
|
||||
@ -92,7 +92,7 @@ class Cactus extends Transparent{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::CACTUS){
|
||||
if($this->meta === 0x0f){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::CACTUS)));
|
||||
if(!$ev->isCancelled()){
|
||||
|
@ -48,7 +48,7 @@ class Cake extends Transparent implements FoodSource{
|
||||
return "Cake Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$f = $this->getDamage() * 0.125; //1 slice width
|
||||
|
||||
|
@ -50,7 +50,7 @@ class Carpet extends Flowable{
|
||||
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Carpet";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
|
@ -27,10 +27,6 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Chest as TileChest;
|
||||
@ -56,7 +52,7 @@ class Chest extends Transparent{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
@ -95,26 +91,7 @@ class Chest extends Transparent{
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Items", []),
|
||||
new StringTag("id", Tile::CHEST),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
|
||||
if($item->hasCustomName()){
|
||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
||||
}
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$tile = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
||||
$tile = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this, $face, $item, $player));
|
||||
|
||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||
$chest->pairWith($tile);
|
||||
@ -142,15 +119,7 @@ class Chest extends Transparent{
|
||||
if($t instanceof TileChest){
|
||||
$chest = $t;
|
||||
}else{
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Items", []),
|
||||
new StringTag("id", Tile::CHEST),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$chest = Tile::createTile("Chest", $this->getLevel(), $nbt);
|
||||
$chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this));
|
||||
}
|
||||
|
||||
if(
|
||||
|
@ -37,10 +37,6 @@ class CobblestoneWall extends Transparent{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
@ -57,38 +53,38 @@ class CobblestoneWall extends Transparent{
|
||||
return "Cobblestone Wall";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
//walls don't have any special collision boxes like fences do
|
||||
|
||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||
|
||||
$n = $north ? 0 : 0.25;
|
||||
$s = $south ? 1 : 0.75;
|
||||
$w = $west ? 0 : 0.25;
|
||||
$e = $east ? 1 : 0.75;
|
||||
|
||||
if($north and $south and !$west and !$east){
|
||||
$w = 0.3125;
|
||||
$e = 0.6875;
|
||||
}elseif(!$north and !$south and $west and $east){
|
||||
$n = 0.3125;
|
||||
$s = 0.6875;
|
||||
$inset = 0.25;
|
||||
if(
|
||||
$this->getSide(Vector3::SIDE_UP)->getId() === Block::AIR and //if there is a block on top, it stays as a post
|
||||
(
|
||||
($north and $south and !$west and !$east) or
|
||||
(!$north and !$south and $west and $east)
|
||||
)
|
||||
){
|
||||
//If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner
|
||||
$inset = 0.3125;
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $w,
|
||||
$this->x + ($west ? 0 : $inset),
|
||||
$this->y,
|
||||
$this->z + $n,
|
||||
$this->x + $e,
|
||||
$this->z + ($north ? 0 : $inset),
|
||||
$this->x + 1 - ($east ? 0 : $inset),
|
||||
$this->y + 1.5,
|
||||
$this->z + $s
|
||||
$this->z + 1 - ($south ? 0 : $inset)
|
||||
);
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block->getId() !== self::COBBLESTONE_WALL and $block->getId() !== self::FENCE_GATE) ? $block->isSolid() and !$block->isTransparent() : true;
|
||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class Cobweb extends Flowable{
|
||||
return Tool::TYPE_SWORD;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class CocoaBlock extends Solid{
|
||||
class CocoaBlock extends Transparent{
|
||||
|
||||
protected $id = self::COCOA_BLOCK;
|
||||
|
||||
|
78
src/pocketmine/block/ConcretePowder.php
Normal file
78
src/pocketmine/block/ConcretePowder.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\ColorBlockMetaHelper;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
|
||||
class ConcretePowder extends Fallable{
|
||||
|
||||
protected $id = self::CONCRETE_POWDER;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return ColorBlockMetaHelper::getColorFromMeta($this->meta) . " Concrete Powder";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_SHOVEL;
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL and ($block = $this->checkAdjacentWater()) !== null){
|
||||
$this->level->setBlock($this, $block);
|
||||
return $type;
|
||||
}
|
||||
|
||||
return parent::onUpdate($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|Block
|
||||
*/
|
||||
public function tickFalling() : ?Block{
|
||||
return $this->checkAdjacentWater();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|Block
|
||||
*/
|
||||
private function checkAdjacentWater() : ?Block{
|
||||
for($i = 1; $i < 6; ++$i){ //Do not check underneath
|
||||
if($this->getSide($i) instanceof Water){
|
||||
return Block::get(Block::CONCRETE, $this->meta);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\inventory\BigCraftingGrid;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\Player;
|
||||
@ -49,6 +50,7 @@ class CraftingTable extends Solid{
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($player instanceof Player){
|
||||
$player->setCraftingGrid(new BigCraftingGrid($player));
|
||||
$player->craftingType = 1;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
@ -38,7 +41,6 @@ class DeadBush extends Flowable{
|
||||
return "Dead Bush";
|
||||
}
|
||||
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->isTransparent() === true){
|
||||
@ -51,4 +53,17 @@ class DeadBush extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_SHEARS;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isShears()){
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [
|
||||
ItemFactory::get(Item::STICK, 0, mt_rand(0, 2))
|
||||
];
|
||||
}
|
||||
}
|
@ -44,13 +44,20 @@ class Dirt extends Solid{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
if($this->meta === 1){
|
||||
return "Coarse Dirt";
|
||||
}
|
||||
return "Dirt";
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->isHoe()){
|
||||
$item->useOn($this);
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND, 0), true);
|
||||
if($this->meta === 1){
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::FARMLAND), true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ abstract class Door extends Transparent{
|
||||
return $down & 0x07 | ($isUp ? 8 : 0) | ($isRight ? 0x10 : 0);
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$f = 0.1875;
|
||||
$damage = $this->getFullDamage();
|
||||
|
@ -38,7 +38,7 @@ class DoublePlant extends Flowable{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return $this->meta === 2 or $this->meta === 3; //grass or fern
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ class DoublePlant extends Flowable{
|
||||
4 => "Rose Bush",
|
||||
5 => "Peony"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "";
|
||||
return $names[$this->getVariant()] ?? "";
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
@ -79,7 +79,7 @@ class DoublePlant extends Flowable{
|
||||
|
||||
return (
|
||||
$other->getId() === $this->getId() and
|
||||
($other->getDamage() & 0x07) === ($this->getDamage() & 0x07) and
|
||||
$other->getVariant() === $this->getVariant() and
|
||||
($other->getDamage() & self::BITFLAG_TOP) !== ($this->getDamage() & self::BITFLAG_TOP)
|
||||
);
|
||||
}
|
||||
|
@ -21,14 +21,27 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
|
||||
abstract class DoubleSlab extends Solid{
|
||||
|
||||
class ItemFrame extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::ITEM_FRAME_BLOCK);
|
||||
parent::__construct(self::ITEM_FRAME, $meta, "Item Frame");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
abstract public function getSlabId() : int;
|
||||
|
||||
public function getName() : string{
|
||||
return "Double " . BlockFactory::get($this->getSlabId(), $this->getVariant())->getName() . " Slab";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getSlabId(), $this->getVariant(), 2)
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -24,15 +24,14 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class DoubleStoneSlab extends Solid{
|
||||
class DoubleStoneSlab extends DoubleSlab{
|
||||
|
||||
protected $id = self::DOUBLE_STONE_SLAB;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
public function getSlabId() : int{
|
||||
return self::STONE_SLAB;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
@ -43,25 +42,9 @@ class DoubleStoneSlab extends Solid{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
0 => "Stone",
|
||||
1 => "Sandstone",
|
||||
2 => "Wooden",
|
||||
3 => "Cobblestone",
|
||||
4 => "Brick",
|
||||
5 => "Stone Brick",
|
||||
6 => "Quartz",
|
||||
7 => "Nether Brick"
|
||||
];
|
||||
return "Double " . $names[$this->meta & 0x07] . " Slab";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return [
|
||||
ItemFactory::get(Item::STONE_SLAB, $this->getDamage() & 0x07, 2)
|
||||
];
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
34
src/pocketmine/block/DoubleStoneSlab2.php
Normal file
34
src/pocketmine/block/DoubleStoneSlab2.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class DoubleStoneSlab2 extends DoubleStoneSlab{
|
||||
|
||||
protected $id = self::DOUBLE_STONE_SLAB2;
|
||||
|
||||
public function getSlabId() : int{
|
||||
return self::STONE_SLAB2;
|
||||
}
|
||||
|
||||
}
|
@ -23,16 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class DoubleWoodenSlab extends Solid{
|
||||
class DoubleWoodenSlab extends DoubleSlab{
|
||||
|
||||
protected $id = self::DOUBLE_WOODEN_SLAB;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
public function getSlabId() : int{
|
||||
return self::WOODEN_SLAB;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
@ -42,23 +40,4 @@ class DoubleWoodenSlab extends Solid{
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
0 => "Oak",
|
||||
1 => "Spruce",
|
||||
2 => "Birch",
|
||||
3 => "Jungle",
|
||||
4 => "Acacia",
|
||||
5 => "Dark Oak"
|
||||
];
|
||||
return "Double " . ($names[$this->meta & 0x07] ?? "") . " Wooden Slab";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get(Item::WOODEN_SLAB, $this->getDamage() & 0x07, 2)
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -27,10 +27,8 @@ use pocketmine\inventory\EnchantInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\EnchantTable as TileEnchantTable;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class EnchantingTable extends Transparent{
|
||||
@ -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{
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::ENCHANT_TABLE),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z)
|
||||
]);
|
||||
|
||||
if($item->hasCustomName()){
|
||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
||||
}
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel(), TileEnchantTable::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class EndPortalFrame extends Solid{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
|
@ -61,7 +61,7 @@ class EndRod extends Flowable{
|
||||
return 14;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$m = $this->meta & ~0x01;
|
||||
$width = 0.375;
|
||||
|
||||
|
57
src/pocketmine/block/EndStoneBricks.php
Normal file
57
src/pocketmine/block/EndStoneBricks.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class EndStoneBricks extends Solid{
|
||||
|
||||
protected $id = self::END_BRICKS;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "End Stone Bricks";
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 0.8;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
@ -26,41 +26,32 @@ namespace pocketmine\block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
|
||||
abstract class Fallable extends Solid{
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(Vector3::SIDE_DOWN);
|
||||
if($down->getId() === self::AIR or ($down instanceof Liquid)){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true, true);
|
||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), new CompoundTag("", [
|
||||
new ListTag("Pos", [
|
||||
new DoubleTag("", $this->x + 0.5),
|
||||
new DoubleTag("", $this->y),
|
||||
new DoubleTag("", $this->z + 0.5)
|
||||
]),
|
||||
new ListTag("Motion", [
|
||||
new DoubleTag("", 0),
|
||||
new DoubleTag("", 0),
|
||||
new DoubleTag("", 0)
|
||||
]),
|
||||
new ListTag("Rotation", [
|
||||
new FloatTag("", 0),
|
||||
new FloatTag("", 0)
|
||||
]),
|
||||
new IntTag("TileID", $this->getId()),
|
||||
new ByteTag("Data", $this->getDamage())
|
||||
]));
|
||||
if($down->getId() === self::AIR or $down instanceof Liquid or $down instanceof Fire){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
|
||||
$fall->spawnToAll();
|
||||
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5));
|
||||
$nbt->setInt("TileID", $this->getId());
|
||||
$nbt->setByte("Data", $this->getDamage());
|
||||
|
||||
$fall = Entity::createEntity("FallingSand", $this->getLevel(), $nbt);
|
||||
|
||||
if($fall !== null){
|
||||
$fall->spawnToAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|Block
|
||||
*/
|
||||
public function tickFalling() : ?Block{
|
||||
return null;
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class Farmland extends Transparent{
|
||||
|
||||
@ -53,7 +54,7 @@ class Farmland extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -65,8 +66,43 @@ class Farmland extends Transparent{
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
//TODO: hydration
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||
return $type;
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(!$this->canHydrate()){
|
||||
if($this->meta > 0){
|
||||
$this->meta--;
|
||||
$this->level->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), false, true);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}elseif($this->meta < 7){
|
||||
$this->meta = 7;
|
||||
$this->level->setBlock($this, $this, false, false);
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function canHydrate() : bool{
|
||||
//TODO: check rain
|
||||
$start = $this->add(-4, 0, -4);
|
||||
$end = $this->add(4, 1, 4);
|
||||
for($y = $start->y; $y <= $end->y; ++$y){
|
||||
for($z = $start->z; $z <= $end->z; ++$z){
|
||||
for($x = $start->x; $x <= $end->x; ++$x){
|
||||
$id = $this->level->getBlockIdAt($x, $y, $z);
|
||||
if($id === Block::STILL_WATER or $id === Block::FLOWING_WATER){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -23,73 +23,87 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class Fence extends Transparent{
|
||||
const FENCE_OAK = 0;
|
||||
const FENCE_SPRUCE = 1;
|
||||
const FENCE_BIRCH = 2;
|
||||
const FENCE_JUNGLE = 3;
|
||||
const FENCE_ACACIA = 4;
|
||||
const FENCE_DARKOAK = 5;
|
||||
|
||||
protected $id = self::FENCE;
|
||||
abstract class Fence extends Transparent{
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
public function getThickness() : float{
|
||||
return 0.25;
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_AXE;
|
||||
}
|
||||
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::FENCE_OAK => "Oak Fence",
|
||||
self::FENCE_SPRUCE => "Spruce Fence",
|
||||
self::FENCE_BIRCH => "Birch Fence",
|
||||
self::FENCE_JUNGLE => "Jungle Fence",
|
||||
self::FENCE_ACACIA => "Acacia Fence",
|
||||
self::FENCE_DARKOAK => "Dark Oak Fence"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
$north = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||
$south = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||
$west = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||
$east = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||
|
||||
$n = $north ? 0 : 0.375;
|
||||
$s = $south ? 1 : 0.625;
|
||||
$w = $west ? 0 : 0.375;
|
||||
$e = $east ? 1 : 0.625;
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$width = 0.5 - $this->getThickness() / 2;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $w,
|
||||
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||
$this->y,
|
||||
$this->z + $n,
|
||||
$this->x + $e,
|
||||
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||
$this->y + 1.5,
|
||||
$this->z + $s
|
||||
$this->z + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_SOUTH)) ? 0 : $width)
|
||||
);
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block instanceof Fence or $block instanceof FenceGate) ? true : $block->isSolid() and !$block->isTransparent();
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$inset = 0.5 - $this->getThickness() / 2;
|
||||
|
||||
/** @var AxisAlignedBB[] $bbs */
|
||||
$bbs = [];
|
||||
|
||||
$connectWest = $this->canConnect($this->getSide(Vector3::SIDE_WEST));
|
||||
$connectEast = $this->canConnect($this->getSide(Vector3::SIDE_EAST));
|
||||
|
||||
if($connectWest or $connectEast){
|
||||
//X axis (west/east)
|
||||
$bbs[] = new AxisAlignedBB(
|
||||
$this->x + ($connectWest ? 0 : $inset),
|
||||
$this->y,
|
||||
$this->z + $inset,
|
||||
$this->x + 1 - ($connectEast ? 0 : $inset),
|
||||
$this->y + 1.5,
|
||||
$this->z + 1 - $inset
|
||||
);
|
||||
}
|
||||
|
||||
$connectNorth = $this->canConnect($this->getSide(Vector3::SIDE_NORTH));
|
||||
$connectSouth = $this->canConnect($this->getSide(Vector3::SIDE_SOUTH));
|
||||
|
||||
if($connectNorth or $connectSouth){
|
||||
//Z axis (north/south)
|
||||
$bbs[] = new AxisAlignedBB(
|
||||
$this->x + $inset,
|
||||
$this->y,
|
||||
$this->z + ($connectNorth ? 0 : $inset),
|
||||
$this->x + 1 - $inset,
|
||||
$this->y + 1.5,
|
||||
$this->z + 1 - ($connectSouth ? 0 : $inset)
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($bbs)){
|
||||
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
|
||||
return [
|
||||
new AxisAlignedBB(
|
||||
$this->x + $inset,
|
||||
$this->y,
|
||||
$this->z + $inset,
|
||||
$this->x + 1 - $inset,
|
||||
$this->y + 1.5,
|
||||
$this->z + 1 - $inset
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
return $bbs;
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
return 300;
|
||||
public function canConnect(Block $block){
|
||||
return $block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class FenceGate extends Transparent{
|
||||
}
|
||||
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return null;
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Arrow;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Arrow;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
@ -57,7 +57,7 @@ class Fire extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class Fire extends Flowable{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev);
|
||||
|
||||
|
@ -23,6 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
@ -33,15 +35,11 @@ abstract class Flowable extends Transparent{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
}
|
@ -24,14 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\FlowerPot as TileFlowerPot;
|
||||
use pocketmine\tile\Tile;
|
||||
@ -49,10 +44,10 @@ class FlowerPot extends Flowable{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Flower Pot Block";
|
||||
return "Flower Pot";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.3125,
|
||||
$this->y,
|
||||
@ -69,23 +64,7 @@ class FlowerPot extends Flowable{
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::FLOWER_POT),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z),
|
||||
new ShortTag("item", 0),
|
||||
new IntTag("mData", 0)
|
||||
]);
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::FLOWER_POT, $this->getLevel(), TileFlowerPot::createNBT($this, $face, $item, $player));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -112,14 +91,8 @@ class FlowerPot extends Flowable{
|
||||
|
||||
$this->setDamage(self::STATE_FULL); //specific damage value is unnecessary, it just needs to be non-zero to show an item.
|
||||
$this->getLevel()->setBlock($this, $this, true, false);
|
||||
$pot->setItem($item);
|
||||
$pot->setItem($item->pop());
|
||||
|
||||
if($player instanceof Player){
|
||||
if($player->isSurvival()){
|
||||
$item->setCount($item->getCount() - 1);
|
||||
$player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : ItemFactory::get(Item::AIR));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -76,22 +76,22 @@ class Grass extends Solid{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}elseif($lightAbove >= 9){
|
||||
//try grass spread
|
||||
$vector = $this->asVector3();
|
||||
for($i = 0; $i < 4; ++$i){
|
||||
$vector->x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$vector->y = mt_rand($this->y - 3, $this->y + 1);
|
||||
$vector->z = mt_rand($this->z - 1, $this->z + 1);
|
||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$y = mt_rand($this->y - 3, $this->y + 1);
|
||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||
if(
|
||||
$this->level->getBlockIdAt($vector->x, $vector->y, $vector->z) !== Block::DIRT or
|
||||
$this->level->getFullLightAt($vector->x, $vector->y + 1, $vector->z) < 4 or
|
||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($vector->x, $vector->y + 1, $vector->z)] >= 3
|
||||
$this->level->getBlockIdAt($x, $y, $z) !== Block::DIRT or
|
||||
$this->level->getBlockDataAt($x, $y, $z) === 1 or
|
||||
$this->level->getFullLightAt($x, $y + 1, $z) < 4 or
|
||||
BlockFactory::$lightFilter[$this->level->getBlockIdAt($x, $y + 1, $z)] >= 3
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($this->level->getBlock($vector), $this, BlockFactory::get(Block::GRASS)));
|
||||
$this->level->getServer()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($b = $this->level->getBlockAt($x, $y, $z), $this, BlockFactory::get(Block::GRASS)));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->level->setBlock($vector, $ev->getNewState(), false, false);
|
||||
$this->level->setBlock($b, $ev->getNewState(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,9 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class GrassPath extends Transparent{
|
||||
|
||||
@ -44,7 +46,7 @@ class GrassPath extends Transparent{
|
||||
return Tool::TYPE_SHOVEL;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -59,6 +61,15 @@ class GrassPath extends Transparent{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||
$this->level->setBlock($this, BlockFactory::get(Block::DIRT), true);
|
||||
return $type;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get(Item::DIRT, 0, 1)
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\PillarRotationHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
@ -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{
|
||||
$faces = [
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
2 => 0b1000,
|
||||
3 => 0b1000,
|
||||
4 => 0b0100,
|
||||
5 => 0b0100
|
||||
];
|
||||
|
||||
$this->meta = ($this->meta & 0x03) | $faces[$face];
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
return true;
|
||||
|
@ -37,7 +37,7 @@ class IronDoor extends Door{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Iron Door Block";
|
||||
return "Iron Door";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -24,12 +24,8 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\{
|
||||
ByteTag, CompoundTag, FloatTag, IntTag, StringTag
|
||||
};
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\tile\Tile;
|
||||
@ -50,29 +46,13 @@ class ItemFrame extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
$tile = $this->level->getTile($this);
|
||||
if(!($tile instanceof TileItemFrame)){
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::ITEM_FRAME),
|
||||
new IntTag("x", $this->x),
|
||||
new IntTag("y", $this->y),
|
||||
new IntTag("z", $this->z),
|
||||
new FloatTag("ItemDropChance", 1.0),
|
||||
new ByteTag("ItemRotation", 0)
|
||||
]);
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
|
||||
$tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this));
|
||||
}
|
||||
|
||||
if($tile->hasItem()){
|
||||
$tile->setItemRotation(($tile->getItemRotation() + 1) % 8);
|
||||
}else{
|
||||
if($item->getCount() > 0){
|
||||
$frameItem = clone $item;
|
||||
$frameItem->setCount(1);
|
||||
$item->setCount($item->getCount() - 1);
|
||||
$tile->setItem($frameItem);
|
||||
if($player instanceof Player and $player->isSurvival()){
|
||||
$player->getInventory()->setItemInHand($item->getCount() <= 0 ? ItemFactory::get(Item::AIR) : $item);
|
||||
}
|
||||
}
|
||||
}elseif(!$item->isNull()){
|
||||
$tile->setItem($item->pop());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -92,10 +72,10 @@ class ItemFrame extends Flowable{
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$sides = [
|
||||
0 => 4,
|
||||
1 => 5,
|
||||
2 => 2,
|
||||
3 => 3
|
||||
0 => Vector3::SIDE_WEST,
|
||||
1 => Vector3::SIDE_EAST,
|
||||
2 => Vector3::SIDE_NORTH,
|
||||
3 => Vector3::SIDE_SOUTH
|
||||
];
|
||||
if(!$this->getSide($sides[$this->meta])->isSolid()){
|
||||
$this->level->useBreakOn($this);
|
||||
@ -120,22 +100,7 @@ class ItemFrame extends Flowable{
|
||||
$this->meta = $faces[$face];
|
||||
$this->level->setBlock($blockReplace, $this, true, true);
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::ITEM_FRAME),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z),
|
||||
new FloatTag("ItemDropChance", 1.0),
|
||||
new ByteTag("ItemRotation", 0)
|
||||
]);
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -59,54 +59,35 @@ class Ladder extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$f = 0.1875;
|
||||
|
||||
$minX = $minZ = 0;
|
||||
$maxX = $maxZ = 1;
|
||||
|
||||
if($this->meta === 2){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$minZ = 1 - $f;
|
||||
}elseif($this->meta === 3){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + $f
|
||||
);
|
||||
$maxZ = $f;
|
||||
}elseif($this->meta === 4){
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$minX = 1 - $f;
|
||||
}elseif($this->meta === 5){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + $f,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
$maxX = $f;
|
||||
}
|
||||
|
||||
return null;
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $minX,
|
||||
$this->y,
|
||||
$this->z + $minZ,
|
||||
$this->x + $maxX,
|
||||
$this->y + 1,
|
||||
$this->z + $maxZ
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -131,13 +112,7 @@ class Ladder extends Transparent{
|
||||
|
||||
public function onUpdate(int $type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$sides = [
|
||||
2 => 3,
|
||||
3 => 2,
|
||||
4 => 5,
|
||||
5 => 4
|
||||
];
|
||||
if(!$this->getSide($sides[$this->meta])->isSolid()){ //Replace with common break method
|
||||
if(!$this->getSide($this->meta ^ 0x01)->isSolid()){ //Replace with common break method
|
||||
$this->level->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class Lava extends Liquid{
|
||||
return "Lava";
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->fallDistance *= 0.5;
|
||||
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
|
@ -61,7 +61,7 @@ class Leaves extends Transparent{
|
||||
self::BIRCH => "Birch Leaves",
|
||||
self::JUNGLE => "Jungle Leaves"
|
||||
];
|
||||
return $names[$this->meta & 0x03];
|
||||
return $names[$this->getVariant()];
|
||||
}
|
||||
|
||||
public function diffusesSkyLight() : bool{
|
||||
@ -169,10 +169,14 @@ class Leaves extends Transparent{
|
||||
return $this->getLevel()->setBlock($this, $this, true);
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x03;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$drops = [];
|
||||
|
||||
$variantMeta = $this->getDamage() & 0x03;
|
||||
$variantMeta = $this->getVariant();
|
||||
|
||||
if($item->isShears()){
|
||||
$drops[] = ItemFactory::get($this->getItemId(), $variantMeta, 1);
|
||||
|
@ -36,11 +36,11 @@ class Leaves2 extends Leaves{
|
||||
self::ACACIA => "Acacia Leaves",
|
||||
self::DARK_OAK => "Dark Oak Leaves"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$variantMeta = $this->getDamage() & 0x03;
|
||||
$variantMeta = $this->getVariant();
|
||||
|
||||
if($item->isShears()){
|
||||
return [
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
abstract class Liquid extends Transparent{
|
||||
@ -41,7 +42,7 @@ abstract class Liquid extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ abstract class Liquid extends Transparent{
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
$sideBlock = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||
|
||||
if($blockDecay < 0){
|
||||
@ -124,7 +125,7 @@ abstract class Liquid extends Transparent{
|
||||
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){
|
||||
$realDecay = $blockDecay - ($decay - 8);
|
||||
@ -145,21 +146,21 @@ abstract class Liquid extends Transparent{
|
||||
if($this->getDamage() >= 8){
|
||||
$falling = false;
|
||||
|
||||
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
|
||||
if(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z - 1)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y, $this->z + 1)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y, $this->z)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y, $this->z)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z - 1)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x, $this->y + 1, $this->z + 1)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x - 1, $this->y + 1, $this->z)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
}elseif(!$this->getLevel()->getBlockAt($this->x + 1, $this->y + 1, $this->z)->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}
|
||||
|
||||
@ -171,7 +172,7 @@ abstract class Liquid extends Transparent{
|
||||
return $vector->normalize();
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector) : void{
|
||||
$flow = $this->getFlowVector();
|
||||
$vector->x += $flow->x;
|
||||
$vector->y += $flow->y;
|
||||
@ -205,10 +206,10 @@ abstract class Liquid extends Transparent{
|
||||
if($decay > 0){
|
||||
$smallestFlowDecay = -100;
|
||||
$this->adjacentSources = 0;
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z - 1), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x, $this->y, $this->z + 1), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x - 1, $this->y, $this->z), $smallestFlowDecay);
|
||||
$smallestFlowDecay = $this->getSmallestFlowDecay($this->level->getBlockAt($this->x + 1, $this->y, $this->z), $smallestFlowDecay);
|
||||
|
||||
$k = $smallestFlowDecay + $multiplier;
|
||||
|
||||
@ -216,7 +217,7 @@ abstract class Liquid extends Transparent{
|
||||
$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){
|
||||
$k = $topFlowDecay;
|
||||
}else{
|
||||
@ -225,7 +226,7 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
if($this->adjacentSources >= 2 and $this instanceof Water){
|
||||
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
|
||||
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
|
||||
if($bottomBlock->isSolid()){
|
||||
$k = 0;
|
||||
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
|
||||
@ -255,7 +256,7 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
if($decay >= 0){
|
||||
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
|
||||
$bottomBlock = $this->level->getBlockAt($this->x, $this->y - 1, $this->z);
|
||||
|
||||
if($this instanceof Lava and $bottomBlock instanceof Water){
|
||||
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
|
||||
@ -280,19 +281,19 @@ abstract class Liquid extends Transparent{
|
||||
}
|
||||
|
||||
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]){
|
||||
$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]){
|
||||
$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]){
|
||||
$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){
|
||||
++$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)){
|
||||
continue;
|
||||
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
||||
continue;
|
||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
||||
}elseif($this->getLevel()->getBlockAt($x, $y - 1, $z)->canBeFlowedInto()){
|
||||
return $accumulatedCost;
|
||||
}
|
||||
|
||||
@ -385,13 +386,13 @@ abstract class Liquid extends Transparent{
|
||||
}elseif($j === 3){
|
||||
++$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)){
|
||||
continue;
|
||||
}elseif($block instanceof Liquid and $block->getDamage() === 0){
|
||||
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;
|
||||
}else{
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ class Magma extends Solid{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
if(!$entity->isSneaking()){
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev);
|
||||
|
@ -26,7 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class MonsterSpawner extends Solid{
|
||||
class MonsterSpawner extends Transparent{
|
||||
|
||||
protected $id = self::MONSTER_SPAWNER;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Mycelium extends Solid{
|
||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||
$block = $this->getLevel()->getBlockAt($x, $y, $z);
|
||||
if($block->getId() === Block::DIRT){
|
||||
if($block->getSide(Vector3::SIDE_UP) instanceof Transparent){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, BlockFactory::get(Block::MYCELIUM)));
|
||||
|
@ -26,14 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class NetherBrickFence extends Transparent{
|
||||
class NetherBrickFence extends Fence{
|
||||
|
||||
protected $id = self::NETHER_BRICK_FENCE;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
}
|
||||
@ -46,10 +42,6 @@ class NetherBrickFence extends Transparent{
|
||||
return "Nether Brick Fence";
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block instanceof NetherBrickFence) or ($block->isSolid() and !$block->isTransparent());
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||
return parent::getDrops($item);
|
||||
@ -57,6 +49,4 @@ class NetherBrickFence extends Transparent{
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
//TODO: fix bounding boxes
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ class NetherWartPlant extends Flowable{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Nether Wart";
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
return true;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class Planks extends Solid{
|
||||
self::ACACIA => "Acacia Wood Planks",
|
||||
self::DARK_OAK => "Dark Oak Wood Planks"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -48,7 +48,7 @@ class Prismarine extends Solid{
|
||||
self::DARK => "Dark Prismarine",
|
||||
self::BRICKS => "Prismarine Bricks"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -21,34 +21,27 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
class Purpur extends Quartz{
|
||||
|
||||
interface Transaction{
|
||||
protected $id = self::PURPUR_BLOCK;
|
||||
|
||||
/**
|
||||
* @return Inventory
|
||||
*/
|
||||
public function getInventory() : Inventory;
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::NORMAL => "Purpur Block",
|
||||
self::CHISELED => "Chiseled Purpur", //wtf?
|
||||
self::PILLAR => "Purpur Pillar"
|
||||
];
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSlot() : int;
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getSourceItem() : Item;
|
||||
public function getHardness() : float{
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getTargetItem() : Item;
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getCreationTime() : float;
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
}
|
@ -21,18 +21,31 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class PurpurStairs extends Stair{
|
||||
|
||||
protected $id = self::PURPUR_STAIRS;
|
||||
|
||||
class WoodenDoor extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::WOODEN_DOOR_BLOCK);
|
||||
parent::__construct(self::WOODEN_DOOR, $meta, "Wooden Door");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
public function getName() : string{
|
||||
return "Purpur Stairs";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
public function getBlastResistance() : float{
|
||||
return 30;
|
||||
}
|
||||
}
|
@ -31,9 +31,9 @@ use pocketmine\Player;
|
||||
|
||||
class Quartz extends Solid{
|
||||
|
||||
const QUARTZ_NORMAL = 0;
|
||||
const QUARTZ_CHISELED = 1;
|
||||
const QUARTZ_PILLAR = 2;
|
||||
const NORMAL = 0;
|
||||
const CHISELED = 1;
|
||||
const PILLAR = 2;
|
||||
|
||||
protected $id = self::QUARTZ_BLOCK;
|
||||
|
||||
@ -47,15 +47,15 @@ class Quartz extends Solid{
|
||||
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::QUARTZ_NORMAL => "Quartz Block",
|
||||
self::QUARTZ_CHISELED => "Chiseled Quartz Block",
|
||||
self::QUARTZ_PILLAR => "Quartz Pillar"
|
||||
self::NORMAL => "Quartz Block",
|
||||
self::CHISELED => "Chiseled Quartz Block",
|
||||
self::PILLAR => "Quartz Pillar"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
if($this->meta !== self::QUARTZ_NORMAL){
|
||||
if($this->meta !== self::NORMAL){
|
||||
$this->meta = PillarRotationHelper::getMetaFromFace($this->meta, $face);
|
||||
}
|
||||
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);
|
||||
|
||||
namespace pocketmine\item;
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
class RedSandstone extends Sandstone{
|
||||
protected $id = self::RED_SANDSTONE;
|
||||
|
||||
class FlowerPot extends Item{
|
||||
public function __construct(int $meta = 0){
|
||||
$this->block = BlockFactory::get(Block::FLOWER_POT_BLOCK);
|
||||
parent::__construct(self::FLOWER_POT, $meta, "Flower Pot");
|
||||
public function getName() : string{
|
||||
static $names = [
|
||||
self::NORMAL => "Red Sandstone",
|
||||
self::CHISELED => "Chiseled Red Sandstone",
|
||||
self::SMOOTH => "Smooth Red Sandstone"
|
||||
];
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
}
|
34
src/pocketmine/block/RedSandstoneStairs.php
Normal file
34
src/pocketmine/block/RedSandstoneStairs.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class RedSandstoneStairs extends SandstoneStairs{
|
||||
|
||||
protected $id = self::RED_SANDSTONE_STAIRS;
|
||||
|
||||
public function getName() : string{
|
||||
return "Red " . parent::getName();
|
||||
}
|
||||
|
||||
}
|
@ -48,7 +48,7 @@ class Sandstone extends Solid{
|
||||
self::CHISELED => "Chiseled Sandstone",
|
||||
self::SMOOTH => "Smooth Sandstone"
|
||||
];
|
||||
return $names[$this->meta & 0x03] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getToolType() : int{
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\level\generator\object\Tree;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -54,7 +53,7 @@ class Sapling extends Flowable{
|
||||
4 => "Acacia Sapling",
|
||||
5 => "Dark Oak Sapling"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function ticksRandomly() : bool{
|
||||
@ -75,7 +74,7 @@ class Sapling extends Flowable{
|
||||
public function onActivate(Item $item, Player $player = null) : bool{
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
//TODO: change log type
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
|
||||
$item->count--;
|
||||
|
||||
@ -95,7 +94,7 @@ class Sapling extends Flowable{
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){ //Growth
|
||||
if(mt_rand(1, 7) === 1){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->meta & 0x07);
|
||||
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
|
||||
}else{
|
||||
$this->meta |= 0x08;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
@ -110,10 +109,8 @@ class Sapling extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
return [
|
||||
ItemFactory::get($this->getItemId(), $this->getDamage() & 0x07, 1)
|
||||
];
|
||||
public function getVariantBitmask() : int{
|
||||
return 0x07;
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
|
@ -26,11 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Sign as TileSign;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class SignPost extends Transparent{
|
||||
@ -55,43 +54,23 @@ class SignPost extends Transparent{
|
||||
return "Sign Post";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
if($face !== Vector3::SIDE_DOWN){
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::SIGN),
|
||||
new IntTag("x", $blockReplace->x),
|
||||
new IntTag("y", $blockReplace->y),
|
||||
new IntTag("z", $blockReplace->z),
|
||||
new StringTag("Text1", ""),
|
||||
new StringTag("Text2", ""),
|
||||
new StringTag("Text3", ""),
|
||||
new StringTag("Text4", "")
|
||||
]);
|
||||
|
||||
if($player !== null){
|
||||
$nbt->Creator = new StringTag("Creator", $player->getRawUniqueId());
|
||||
}
|
||||
|
||||
if($item->hasCustomBlockData()){
|
||||
foreach($item->getCustomBlockData() as $key => $v){
|
||||
$nbt->{$key} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if($face === Vector3::SIDE_UP){
|
||||
$this->meta = floor((($player->yaw + 180) * 16 / 360) + 0.5) & 0x0f;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
}else{
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, new WallSign($this->meta), true);
|
||||
$this->getLevel()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
|
||||
}
|
||||
|
||||
Tile::createTile(Tile::SIGN, $this->getLevel(), $nbt);
|
||||
Tile::createTile(Tile::SIGN, $this->getLevel(), TileSign::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -27,13 +27,8 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Skull as SkullTile;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\tile\Skull as TileSkull;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class Skull extends Flowable{
|
||||
@ -49,10 +44,10 @@ class Skull extends Flowable{
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Mob Head Block";
|
||||
return "Mob Head";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
//TODO: different bounds depending on attached face (meta)
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.25,
|
||||
@ -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{
|
||||
if($face !== Vector3::SIDE_DOWN){
|
||||
$this->meta = $face;
|
||||
if($face === Vector3::SIDE_UP){
|
||||
$rot = floor(($player->yaw * 16 / 360) + 0.5) & 0x0F;
|
||||
}else{
|
||||
$rot = $face;
|
||||
}
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
$nbt = new CompoundTag("", [
|
||||
new StringTag("id", Tile::SKULL),
|
||||
new ByteTag("SkullType", $item->getDamage()),
|
||||
new ByteTag("Rot", $rot),
|
||||
new IntTag("x", (int) $this->x),
|
||||
new IntTag("y", (int) $this->y),
|
||||
new IntTag("z", (int) $this->z)
|
||||
]);
|
||||
if($item->hasCustomName()){
|
||||
$nbt->CustomName = new StringTag("CustomName", $item->getCustomName());
|
||||
}
|
||||
/** @var Spawnable $tile */
|
||||
Tile::createTile("Skull", $this->getLevel(), $nbt);
|
||||
return true;
|
||||
if($face === Vector3::SIDE_DOWN){
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
$this->meta = $face;
|
||||
$this->getLevel()->setBlock($blockReplace, $this, true);
|
||||
Tile::createTile(Tile::SKULL, $this->getLevel(), TileSkull::createNBT($this, $face, $item, $player));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
$tile = $this->level->getTile($this);
|
||||
if($tile instanceof SkullTile){
|
||||
if($tile instanceof TileSkull){
|
||||
return [
|
||||
ItemFactory::get(Item::SKULL, $tile->getType(), 1)
|
||||
];
|
||||
|
129
src/pocketmine/block/Slab.php
Normal file
129
src/pocketmine/block/Slab.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
abstract class Slab extends Transparent{
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
abstract public function getDoubleSlabId() : int;
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
if(parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock)){
|
||||
return true;
|
||||
}
|
||||
|
||||
if($blockReplace->getId() === $this->getId() and $blockReplace->getVariant() === $this->getVariant()){
|
||||
if(($blockReplace->getDamage() & 0x08) !== 0){ //Trying to combine with top slab
|
||||
return $clickVector->y <= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_UP);
|
||||
}else{
|
||||
return $clickVector->y >= 0.5 or (!$isClickedBlock and $face === Vector3::SIDE_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $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";
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ class SoulSand extends Solid{
|
||||
return Tool::TYPE_SHOVEL;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
|
@ -31,103 +31,56 @@ use pocketmine\Player;
|
||||
|
||||
abstract class Stair extends Transparent{
|
||||
|
||||
/*
|
||||
public function collidesWithBB(AxisAlignedBB $bb, &$list = []){
|
||||
$damage = $this->getDamage();
|
||||
$j = $damage & 0x03;
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//TODO: handle corners
|
||||
|
||||
$f = 0;
|
||||
$f1 = 0.5;
|
||||
$f2 = 0.5;
|
||||
$f3 = 1;
|
||||
$minYSlab = ($this->meta & 0x04) === 0 ? 0 : 0.5;
|
||||
$maxYSlab = $minYSlab + 0.5;
|
||||
|
||||
if(($damage & 0x04) > 0){
|
||||
$f = 0.5;
|
||||
$f1 = 1;
|
||||
$f2 = 0;
|
||||
$f3 = 0.5;
|
||||
$bbs = [
|
||||
new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + $minYSlab,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $maxYSlab,
|
||||
$this->z + 1
|
||||
)
|
||||
];
|
||||
|
||||
$minY = ($this->meta & 0x04) === 0 ? 0.5 : 0;
|
||||
$maxY = $minY + 0.5;
|
||||
|
||||
$rotationMeta = $this->meta & 0x03;
|
||||
|
||||
$minX = $minZ = 0;
|
||||
$maxX = $maxZ = 1;
|
||||
|
||||
switch($rotationMeta){
|
||||
case 0:
|
||||
$minX = 0.5;
|
||||
break;
|
||||
case 1:
|
||||
$maxX = 0.5;
|
||||
break;
|
||||
case 2:
|
||||
$minZ = 0.5;
|
||||
break;
|
||||
case 3:
|
||||
$maxZ = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f1,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
$bbs[] = new AxisAlignedBB(
|
||||
$this->x + $minX,
|
||||
$this->y + $minY,
|
||||
$this->z + $minZ,
|
||||
$this->x + $maxX,
|
||||
$this->y + $maxY,
|
||||
$this->z + $maxZ
|
||||
);
|
||||
|
||||
if($j === 0){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x + 0.5,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 1){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 0.5,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 2){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z + 0.5,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 1
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}elseif($j === 3){
|
||||
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||
$this->x,
|
||||
$this->y + $f2,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + $f3,
|
||||
$this->z + 0.5
|
||||
))){
|
||||
$list[] = $bb2;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 1,
|
||||
$this->y + 0.5,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
return $bbs;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
|
@ -60,7 +60,7 @@ class Stone extends Solid{
|
||||
self::ANDESITE => "Andesite",
|
||||
self::POLISHED_ANDESITE => "Polished Andesite"
|
||||
];
|
||||
return $names[$this->meta & 0x07] ?? "Unknown";
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
|
@ -53,7 +53,7 @@ class StoneBricks extends Solid{
|
||||
self::CRACKED => "Cracked Stone Bricks",
|
||||
self::CHISELED => "Chiseled Stone Bricks"
|
||||
];
|
||||
return $names[$this->meta & 0x03];
|
||||
return $names[$this->getVariant()] ?? "Unknown";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
|
@ -23,14 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class StoneButton extends Flowable{
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class StoneButton extends Button{
|
||||
|
||||
protected $id = self::STONE_BUTTON;
|
||||
|
||||
public function __construct(int $meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Stone Button";
|
||||
}
|
||||
@ -39,7 +37,7 @@ class StoneButton extends Flowable{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public function getVariantBitmask() : int{
|
||||
return 0;
|
||||
public function getToolType() : int{
|
||||
return Tool::TYPE_PICKAXE;
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class StoneSlab extends WoodenSlab{
|
||||
class StoneSlab extends Slab{
|
||||
const STONE = 0;
|
||||
const SANDSTONE = 1;
|
||||
const WOODEN = 2;
|
||||
@ -38,7 +38,9 @@ class StoneSlab extends WoodenSlab{
|
||||
|
||||
protected $id = self::STONE_SLAB;
|
||||
|
||||
protected $doubleId = self::DOUBLE_STONE_SLAB;
|
||||
public function getDoubleSlabId() : int{
|
||||
return self::DOUBLE_STONE_SLAB;
|
||||
}
|
||||
|
||||
public function getHardness() : float{
|
||||
return 2;
|
||||
@ -55,7 +57,7 @@ class StoneSlab extends WoodenSlab{
|
||||
self::QUARTZ => "Quartz",
|
||||
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{
|
||||
@ -69,8 +71,4 @@ class StoneSlab extends WoodenSlab{
|
||||
|
||||
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($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, BlockFactory::get(Block::SUGARCANE_BLOCK)));
|
||||
if(!$ev->isCancelled()){
|
||||
@ -85,7 +85,7 @@ class Sugarcane extends Flowable{
|
||||
if($this->getSide(Vector3::SIDE_DOWN)->getId() !== self::SUGARCANE_BLOCK){
|
||||
if($this->meta === 0x0F){
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
$b = $this->getLevel()->getBlockAt($this->x, $this->y + $y, $this->z);
|
||||
if($b->getId() === self::AIR){
|
||||
$this->getLevel()->setBlock($b, BlockFactory::get(Block::SUGARCANE_BLOCK), true);
|
||||
break;
|
||||
|
@ -25,11 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Random;
|
||||
|
||||
@ -63,24 +59,13 @@ class TNT extends Solid{
|
||||
$this->getLevel()->setBlock($this, BlockFactory::get(Block::AIR), true);
|
||||
|
||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||
$tnt = Entity::createEntity("PrimedTNT", $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("", -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)
|
||||
]));
|
||||
$nbt = Entity::createBaseNBT($this->add(0.5, 0, 0.5), new Vector3(-sin($mot) * 0.02, 0.2, -cos($mot) * 0.02));
|
||||
$nbt->setByte("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;
|
||||
}
|
||||
|
||||
public function canBeReplaced(Block $with = null) : bool{
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ class TallGrass extends Flowable{
|
||||
1 => "Tall Grass",
|
||||
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{
|
||||
|
@ -28,57 +28,83 @@ use pocketmine\math\Vector3;
|
||||
|
||||
abstract class Thin extends Transparent{
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
$width = 0.5 - 0.125 / 2;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $f,
|
||||
$this->x + ($this->canConnect($this->getSide(Vector3::SIDE_WEST)) ? 0 : $width),
|
||||
$this->y,
|
||||
$this->z + $f2,
|
||||
$this->x + $f1,
|
||||
$this->z + ($this->canConnect($this->getSide(Vector3::SIDE_NORTH)) ? 0 : $width),
|
||||
$this->x + 1 - ($this->canConnect($this->getSide(Vector3::SIDE_EAST)) ? 0 : $width),
|
||||
$this->y + 1,
|
||||
$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){
|
||||
return $block->isSolid() or $block->getId() === $this->getId() or $block->getId() === self::GLASS_PANE or $block->getId() === self::GLASS;
|
||||
/** @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,
|
||||
$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);
|
||||
$side = $this->getDamage();
|
||||
$faces = [
|
||||
0 => 0,
|
||||
1 => 4,
|
||||
2 => 5,
|
||||
3 => 2,
|
||||
4 => 3,
|
||||
5 => 0
|
||||
0 => Vector3::SIDE_DOWN,
|
||||
1 => Vector3::SIDE_WEST,
|
||||
2 => Vector3::SIDE_EAST,
|
||||
3 => Vector3::SIDE_NORTH,
|
||||
4 => Vector3::SIDE_SOUTH,
|
||||
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);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
|
@ -53,7 +53,7 @@ class Trapdoor extends Transparent{
|
||||
return 3;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$damage = $this->getDamage();
|
||||
|
||||
|
@ -31,7 +31,7 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Vine extends Transparent{
|
||||
class Vine extends Flowable{
|
||||
const FLAG_SOUTH = 0x01;
|
||||
const FLAG_WEST = 0x02;
|
||||
const FLAG_NORTH = 0x04;
|
||||
@ -43,10 +43,6 @@ class Vine extends Transparent{
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return "Vines";
|
||||
}
|
||||
@ -71,106 +67,126 @@ class Vine extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
|
||||
$f1 = 1;
|
||||
$f2 = 1;
|
||||
$f3 = 1;
|
||||
$f4 = 0;
|
||||
$f5 = 0;
|
||||
$f6 = 0;
|
||||
$minX = 1;
|
||||
$minY = 1;
|
||||
$minZ = 1;
|
||||
$maxX = 0;
|
||||
$maxY = 0;
|
||||
$maxZ = 0;
|
||||
|
||||
$flag = $this->meta > 0;
|
||||
|
||||
if(($this->meta & self::FLAG_WEST) > 0){
|
||||
$f4 = max($f4, 0.0625);
|
||||
$f1 = 0;
|
||||
$f2 = 0;
|
||||
$f5 = 1;
|
||||
$f3 = 0;
|
||||
$f6 = 1;
|
||||
$maxX = max($maxX, 0.0625);
|
||||
$minX = 0;
|
||||
$minY = 0;
|
||||
$maxY = 1;
|
||||
$minZ = 0;
|
||||
$maxZ = 1;
|
||||
$flag = true;
|
||||
}
|
||||
|
||||
if(($this->meta & self::FLAG_EAST) > 0){
|
||||
$f1 = min($f1, 0.9375);
|
||||
$f4 = 1;
|
||||
$f2 = 0;
|
||||
$f5 = 1;
|
||||
$f3 = 0;
|
||||
$f6 = 1;
|
||||
$minX = min($minX, 0.9375);
|
||||
$maxX = 1;
|
||||
$minY = 0;
|
||||
$maxY = 1;
|
||||
$minZ = 0;
|
||||
$maxZ = 1;
|
||||
$flag = true;
|
||||
}
|
||||
|
||||
if(($this->meta & self::FLAG_SOUTH) > 0){
|
||||
$f3 = min($f3, 0.9375);
|
||||
$f6 = 1;
|
||||
$f1 = 0;
|
||||
$f4 = 1;
|
||||
$f2 = 0;
|
||||
$f5 = 1;
|
||||
$minZ = min($minZ, 0.9375);
|
||||
$maxZ = 1;
|
||||
$minX = 0;
|
||||
$maxX = 1;
|
||||
$minY = 0;
|
||||
$maxY = 1;
|
||||
$flag = true;
|
||||
}
|
||||
|
||||
//TODO: Missing NORTH check
|
||||
|
||||
if(!$flag and $this->getSide(Vector3::SIDE_UP)->isSolid()){
|
||||
$f2 = min($f2, 0.9375);
|
||||
$f5 = 1;
|
||||
$f1 = 0;
|
||||
$f4 = 1;
|
||||
$f3 = 0;
|
||||
$f6 = 1;
|
||||
$minY = min($minY, 0.9375);
|
||||
$maxY = 1;
|
||||
$minX = 0;
|
||||
$maxX = 1;
|
||||
$minZ = 0;
|
||||
$maxZ = 1;
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + $f1,
|
||||
$this->y + $f2,
|
||||
$this->z + $f3,
|
||||
$this->x + $f4,
|
||||
$this->y + $f5,
|
||||
$this->z + $f6
|
||||
$this->x + $minX,
|
||||
$this->y + $minY,
|
||||
$this->z + $minZ,
|
||||
$this->x + $maxX,
|
||||
$this->y + $maxY,
|
||||
$this->z + $maxZ
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $facePos, Player $player = null) : bool{
|
||||
//TODO: multiple sides
|
||||
if($blockClicked->isSolid()){
|
||||
$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;
|
||||
}
|
||||
if(!$blockClicked->isSolid() or $face === Vector3::SIDE_UP or $face === Vector3::SIDE_DOWN){
|
||||
return false;
|
||||
}
|
||||
|
||||
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){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$sides = [
|
||||
1 => 3,
|
||||
2 => 4,
|
||||
4 => 2,
|
||||
8 => 5
|
||||
self::FLAG_SOUTH => Vector3::SIDE_SOUTH,
|
||||
self::FLAG_WEST => Vector3::SIDE_WEST,
|
||||
self::FLAG_NORTH => Vector3::SIDE_NORTH,
|
||||
self::FLAG_EAST => Vector3::SIDE_EAST
|
||||
];
|
||||
|
||||
if(!isset($sides[$this->meta])){
|
||||
return false; //TODO: remove this once placing on multiple sides is supported (these are bitflags, not actual meta values
|
||||
$meta = $this->meta;
|
||||
|
||||
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
|
||||
$this->level->useBreakOn($this);
|
||||
if($meta !== $this->meta){
|
||||
if($meta === 0){
|
||||
$this->level->useBreakOn($this);
|
||||
}else{
|
||||
$this->meta = $meta;
|
||||
$this->level->setBlock($this, $this);
|
||||
}
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
|
@ -34,19 +34,11 @@ class WallSign extends SignPost{
|
||||
}
|
||||
|
||||
public function onUpdate(int $type){
|
||||
$faces = [
|
||||
2 => 3,
|
||||
3 => 2,
|
||||
4 => 5,
|
||||
5 => 4
|
||||
];
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if(isset($faces[$this->meta])){
|
||||
if($this->getSide($faces[$this->meta])->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
if($this->getSide($this->meta ^ 0x01)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class Water extends Liquid{
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
public function onEntityCollide(Entity $entity) : void{
|
||||
$entity->resetFallDistance();
|
||||
if($entity->fireTicks > 0){
|
||||
$entity->extinguish();
|
||||
|
@ -45,7 +45,7 @@ class WaterLily extends Flowable{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
protected function recalculateBoundingBox() : ?AxisAlignedBB{
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
|
@ -52,7 +52,7 @@ class Wood extends Solid{
|
||||
self::BIRCH => "Birch 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{
|
||||
|
@ -36,6 +36,6 @@ class Wood2 extends Wood{
|
||||
0 => "Acacia 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;
|
||||
|
||||
class WoodenButton extends StoneButton{
|
||||
use pocketmine\item\Tool;
|
||||
|
||||
class WoodenButton extends Button{
|
||||
|
||||
protected $id = self::WOODEN_BUTTON;
|
||||
|
||||
public function getName() : string{
|
||||
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