mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 19:02:59 +00:00
Compare commits
452 Commits
Alpha_1.4d
...
Alpha_1.4d
Author | SHA1 | Date | |
---|---|---|---|
6cb88afe1a | |||
a677bcb331 | |||
2f6007342c | |||
b6c0eb8c96 | |||
afa8496767 | |||
d7be2ce439 | |||
6dcb5da069 | |||
3cf1692c96 | |||
d04af590d1 | |||
d4c43215b1 | |||
a40918aabf | |||
20f9352714 | |||
a605e90dfc | |||
9fc250956f | |||
db2dfc47a6 | |||
408a537001 | |||
922bfb33ac | |||
8e47c93fbc | |||
c175485cd8 | |||
b6981cc31d | |||
1f9cd6a99b | |||
ded7ada7d7 | |||
1b50879823 | |||
1bd9cbd4d3 | |||
96122d3be7 | |||
71d602a4cf | |||
c81bbdaaa9 | |||
2752393c42 | |||
312e064b07 | |||
94f91967f3 | |||
fe900b417e | |||
4c30b6b8a1 | |||
c41ac7b0a2 | |||
b220bd2a45 | |||
04ee94dc91 | |||
ea8f10efa4 | |||
04ecbd1a76 | |||
ddfc9d9ce1 | |||
a4735eaf76 | |||
306f492fc0 | |||
5e5f8bf33d | |||
3bb2f12cde | |||
1041bb0e6a | |||
49e93cee80 | |||
8b6681c56d | |||
9e3d432b9e | |||
841a3d5ee6 | |||
a5294d5ec7 | |||
5373e6be07 | |||
075137bd3c | |||
68da4b5b39 | |||
e4557a2e8e | |||
964bf98ca6 | |||
747f7685e7 | |||
bb82e7be50 | |||
7506f01302 | |||
a98da3bab1 | |||
f0d6128282 | |||
161e7ae7ec | |||
6104c5b5a3 | |||
af82d616c1 | |||
a0d4bff385 | |||
79236c971c | |||
20e63ae543 | |||
add7879720 | |||
1a064d38b1 | |||
294e680d5d | |||
811970e58d | |||
941961f5ef | |||
1963d8fde0 | |||
e44ed4da3b | |||
a72488d41e | |||
3930f379cf | |||
66ba327e62 | |||
329ca62465 | |||
26e47ef694 | |||
61ea149ff0 | |||
b3c3f896a3 | |||
d139e5f342 | |||
3abf36ad07 | |||
0bc9a9bdab | |||
98340522d9 | |||
6d09754ea7 | |||
a3b1d318cc | |||
f866efb622 | |||
b1c4578726 | |||
f4181a6e36 | |||
38089af098 | |||
cd135b39ad | |||
dd3207cbd8 | |||
a7abd5ff9d | |||
a3e50f6337 | |||
441a98e60a | |||
4a90ac270f | |||
a906a2988b | |||
545f68382c | |||
8249cac592 | |||
7b7bbe9105 | |||
05679c7872 | |||
8eb80be691 | |||
f55b0d0b45 | |||
754e0dbb49 | |||
525c8db779 | |||
c7f578f297 | |||
19c030281f | |||
ca9fe1b89a | |||
9fd6a695f6 | |||
c07b0ff35b | |||
00be3f0dd3 | |||
6796fca2b6 | |||
5657cce3db | |||
05ac256cc3 | |||
49977c5410 | |||
ca40bb678c | |||
2068cc9cdf | |||
ea4617cedd | |||
1a5544f68c | |||
0128a7aeb2 | |||
fd954ce708 | |||
d63a82de0a | |||
92143d523c | |||
1818e64c8e | |||
7e1095e28d | |||
f1519e6d13 | |||
3b9a9bcd5d | |||
263bff01c8 | |||
987d647b76 | |||
522b75645c | |||
9eed0a579c | |||
064976d32b | |||
2abb577178 | |||
127855c220 | |||
93c7a3c170 | |||
31903a764a | |||
79bc1d6c85 | |||
cc7f12739d | |||
32dae93ef9 | |||
8fd6582e74 | |||
a5369b3570 | |||
abbd33210a | |||
6b6222c09c | |||
a8c997d88a | |||
6993718a83 | |||
86afecec89 | |||
29d1fd1fc8 | |||
af4eb2ab1e | |||
f7baf46a54 | |||
75c0d8324c | |||
da4334f06b | |||
413bd3c0df | |||
1a0428654b | |||
2803a38fd1 | |||
95a5ca7889 | |||
240f14c425 | |||
cb9b6ab1d1 | |||
8a87280566 | |||
4d97827d44 | |||
f8f1e0e9df | |||
bf596ebf05 | |||
90777014b6 | |||
4a78ffd2dd | |||
7c361a52d2 | |||
13fc0df92c | |||
d5012f6fcf | |||
4569a73f3d | |||
66acb5cdd7 | |||
8601405a88 | |||
ae06681b60 | |||
01ffb14e39 | |||
ce989876af | |||
f8d6ebabf3 | |||
094b600a0c | |||
82cfe6ea9c | |||
4fba6d7c86 | |||
f72d7284b9 | |||
8f0527832f | |||
f66944368d | |||
7ab3c57b00 | |||
673b867ee8 | |||
2424c8a76c | |||
92eb5cb0b8 | |||
fd46c71120 | |||
6a4259bf24 | |||
9a65279c6a | |||
09a01be709 | |||
57d1847c50 | |||
6e8e2a79dd | |||
d8f9def7f4 | |||
8cb9dd9a14 | |||
c4c374e3fa | |||
d57e37896d | |||
022a978ffb | |||
00b282d40c | |||
8a768cea33 | |||
289bc56b4b | |||
6f64af3066 | |||
72c09045d5 | |||
5e55c3a8f0 | |||
afaa2cf722 | |||
50cfeaa393 | |||
dda8b03349 | |||
56e848488a | |||
7e4f862634 | |||
577a7a1c3d | |||
78f8d0280d | |||
0680b98380 | |||
cbe0fe5e46 | |||
7eed92e8fb | |||
f772391866 | |||
8c4faa8622 | |||
b6f7ee20fc | |||
0fce83c671 | |||
8080643cc9 | |||
5bf2174cad | |||
34ae760def | |||
a5b85c549a | |||
b9f1812f61 | |||
350cee3d41 | |||
144a871c07 | |||
69492474e4 | |||
4299ebebcc | |||
119b429ab8 | |||
8f1eb41ca5 | |||
ca92d2a0d3 | |||
db82f76c11 | |||
3f5b129cf5 | |||
f6aac8728b | |||
809fc44813 | |||
64f1ff066d | |||
a5a3f4801a | |||
23d1532ff9 | |||
ecbbcc2e8e | |||
7abf52e615 | |||
9e01e2ef49 | |||
df81b365e5 | |||
db8ac0b9cb | |||
ee4f416d93 | |||
8feea721e3 | |||
8e7077ff4b | |||
4f4a6e7446 | |||
1fc066fc37 | |||
b565844062 | |||
be948f99cc | |||
5cb428e5cc | |||
d2f4a14d66 | |||
516bb37a50 | |||
580ade9092 | |||
8f7dfe0b71 | |||
5310ba3ae6 | |||
ef97efcd96 | |||
30c3718ea8 | |||
5437567e95 | |||
e3e97a4205 | |||
fec387d2ec | |||
481e2b08ee | |||
15de0eece7 | |||
2f8267aa1e | |||
f2b573c32f | |||
34946faf94 | |||
3b47513439 | |||
7d9a98ec6b | |||
92facc94b9 | |||
d3327f450c | |||
570cab9c66 | |||
582ba100b0 | |||
4c0daa462d | |||
2e6366868d | |||
245e9b4f18 | |||
68e73d4e3a | |||
684617d370 | |||
a879104a6f | |||
05f71691fc | |||
1c03c3afcf | |||
94e9485be9 | |||
9cb27e26ef | |||
7760559be1 | |||
163a37ee23 | |||
c73a3e53be | |||
8637b7f5a3 | |||
747fdab389 | |||
204915450f | |||
500a690cd0 | |||
d473ce13ee | |||
1adf53a81e | |||
ed942100ec | |||
8abe95309c | |||
5dc5aba42c | |||
bda6f03e15 | |||
69d132401e | |||
e3a9db5d8f | |||
b71a4701d9 | |||
9b85abd75e | |||
7b7b91ea0d | |||
18f6bad48d | |||
fbe548c611 | |||
4e793199fa | |||
43a97c407d | |||
07dcbdb9b0 | |||
60ca24fe0e | |||
6e8144d5d9 | |||
464afb949e | |||
823dc933b8 | |||
883f93cc8c | |||
b26ee09f76 | |||
1eec333501 | |||
5448a48f67 | |||
a10ad42a13 | |||
da23cf685d | |||
79e4b3e3a9 | |||
8472349caf | |||
96b61fbb92 | |||
6246ad19c4 | |||
9b69cc4288 | |||
114153ae97 | |||
ebb844fa52 | |||
bf89ea1cf6 | |||
4076fb4657 | |||
312f377483 | |||
0af3dfedd5 | |||
6f1f201c41 | |||
48f591e5ce | |||
7f85e37540 | |||
341717c89d | |||
afdf7bc2b9 | |||
24c76acf30 | |||
baf06dc363 | |||
645c00b2f7 | |||
0dd46c835c | |||
0dba14074a | |||
8b585fd9f7 | |||
9ede8177df | |||
13ec046f0d | |||
5c4e7b6ee0 | |||
6424934df6 | |||
b2ac959083 | |||
c67d4dae7b | |||
22ad75c5a0 | |||
b45ef8928c | |||
eccf7b08d2 | |||
94eb9e35e2 | |||
79bf1f12f2 | |||
10b33546ef | |||
c52dc58d6f | |||
62af784d37 | |||
aa010b7dea | |||
4a3163b4c8 | |||
c750a204e6 | |||
3313981d54 | |||
57f7d57c76 | |||
64bf293c69 | |||
7b09edf048 | |||
4346773e25 | |||
b0c314526d | |||
dd140ce018 | |||
08aa7808cf | |||
582c165479 | |||
5fb205493a | |||
e346d245e2 | |||
4fece32ca8 | |||
0b79d74a2f | |||
b83c6fbfa3 | |||
dda9c598f1 | |||
8769d2bcd1 | |||
3b7ece3363 | |||
b6025e3f2b | |||
35de331b74 | |||
de11cce154 | |||
d53ba52d32 | |||
9db2fe40eb | |||
57bb8f14fa | |||
761cd59514 | |||
4c2a1c8684 | |||
31bb6d1a68 | |||
cd65179aef | |||
9abd2c63f4 | |||
376e359577 | |||
571e2f8895 | |||
7106ea87e6 | |||
6b65b68ebc | |||
d4c75ce68a | |||
fae330d499 | |||
5e03e157ad | |||
b0c40dc1ab | |||
6840589f4e | |||
19e4aaa16a | |||
e0a7944faa | |||
eeda22d0ba | |||
769f1effb0 | |||
42c7322273 | |||
c8cf6b715e | |||
41f94f7385 | |||
602bdf27a5 | |||
539fa232f8 | |||
f8378c09ba | |||
69fb7ae525 | |||
ee8ad6f92a | |||
f888acbd7c | |||
215691f1c4 | |||
1252dd65a9 | |||
762c27affe | |||
706e1099a1 | |||
9cd66dc969 | |||
5b6b789ab3 | |||
85ff696ae5 | |||
25f8e8318b | |||
61d84c73d0 | |||
f5822c6de8 | |||
b0bd927545 | |||
fde61b7d21 | |||
886ad8442c | |||
7b5869bea8 | |||
3063863c65 | |||
0dfaa19380 | |||
7fea29e874 | |||
2ded2013bf | |||
aa27c28e65 | |||
05a81bebf4 | |||
ce91f2943a | |||
1d8562fb8c | |||
1dfb17b932 | |||
16384c2b20 | |||
48041b2f19 | |||
529bf743db | |||
48bc919a33 | |||
474091c013 | |||
666e5553c2 | |||
ae6f532b1d | |||
b231eba803 | |||
82d903733d | |||
8e2903da86 | |||
d720113ac9 | |||
5db45222c6 | |||
2975509d0f | |||
7e49d073fa | |||
ef3674a296 | |||
6cb7e36f8a | |||
b88f19bb74 | |||
8c3fcf0798 | |||
6b312a7826 | |||
9907e84eee | |||
01f299a7f1 | |||
91f20f6789 | |||
4c1edc3f7e | |||
5fd1e271c5 | |||
b3ae6eae04 | |||
3b56b536b6 | |||
9258281546 | |||
e7897be7cd | |||
5ff01de413 | |||
f191ada405 | |||
addd74d09e | |||
4e9d2d0a7f |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@ players/*
|
||||
worlds/*
|
||||
plugins/*
|
||||
bin/*
|
||||
timings/*
|
||||
*.log
|
||||
*.txt
|
||||
*.phar
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -9,3 +9,6 @@
|
||||
[submodule "src/spl"]
|
||||
path = src/spl
|
||||
url = https://github.com/PocketMine/PocketMine-SPL.git
|
||||
[submodule "tests/TesterPlugin"]
|
||||
path = tests/TesterPlugin
|
||||
url = https://github.com/PocketMine/TesterPlugin.git
|
||||
|
@ -9,8 +9,8 @@ branches:
|
||||
before_script:
|
||||
- mkdir plugins
|
||||
- wget -O plugins/DevTools.phar https://github.com/PocketMine/DevTools/releases/download/v1.9.0/DevTools_v1.9.0.phar
|
||||
- pecl install channel://pecl.php.net/pthreads-2.0.8
|
||||
- pecl install channel://pecl.php.net/weakref-0.2.4
|
||||
- pecl install channel://pecl.php.net/pthreads-2.0.10
|
||||
- pecl install channel://pecl.php.net/weakref-0.2.6
|
||||
- echo | pecl install channel://pecl.php.net/yaml-1.1.1
|
||||
|
||||
script:
|
||||
@ -18,4 +18,4 @@ script:
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
#webhooks: http://n.tkte.ch/h/214/wsNvmG43-ncxUVRrFPwSM-r0
|
||||
#webhooks: http://n.tkte.ch/h/214/wsNvmG43-ncxUVRrFPwSM-r0
|
||||
|
@ -72,6 +72,19 @@ class ExampleClass{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### RFC and Voting
|
||||
* These are big Pull Requests or contributions that change important behavior.
|
||||
* RFCs will be tagged with the *PR: RFC* label
|
||||
* A vote will be held once the RFC is ready. All users can vote commenting on the Pull Request
|
||||
* Comments MUST use "Yes" or "No" on the FIRST sentence to signify the vote, except when they don't want it to be counted.
|
||||
* If your comment is a voting comment, specify the reason of your vote or it won't be counted.
|
||||
* After voting has been closed, no further votes will be counted.
|
||||
* An RFC will be rejected if less than 50% + 1 (simple majority) has voted Yes.
|
||||
* If the RFC is approved, Team Members have the final word on its implementation or rejection.
|
||||
* RFCs with complex voting options will specify the vote percentage or other details.
|
||||
|
||||
|
||||
## Bug Tracking for Collaborators
|
||||
|
||||
### Labels
|
||||
@ -91,6 +104,7 @@ Category labels are prefixed by `C:`. Multiple category labels may be applied to
|
||||
Pull Requests are prefixed by `PR:`. Only one label may be applied for a Pull Request.
|
||||
- PR: Bug Fix - This label is applied when the Pull Request fixes a bug.
|
||||
- PR: Contribution - This label is applied when the Pull Request contributes code to PocketMine-MP such as a new feature or an improvement.
|
||||
- PR: RFC - Request for Comments
|
||||
|
||||
#### Status
|
||||
Status labels show the status of the issue. Multiple status labels may be applied.
|
||||
|
@ -137,7 +137,7 @@ class CrashDump{
|
||||
$error = $lastExceptionError;
|
||||
}else{
|
||||
$error = (array) error_get_last();
|
||||
$error["trace"] = getTrace(4);
|
||||
$error["trace"] = @getTrace(4);
|
||||
$errorConversion = [
|
||||
E_ERROR => "E_ERROR",
|
||||
E_WARNING => "E_WARNING",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -65,17 +65,15 @@ namespace {
|
||||
}
|
||||
|
||||
namespace pocketmine {
|
||||
use LogLevel;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\wizard\Installer;
|
||||
use raklib\RakLib;
|
||||
|
||||
const VERSION = "Alpha_1.4dev";
|
||||
const API_VERSION = "1.4.0";
|
||||
const API_VERSION = "1.9.0";
|
||||
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
|
||||
const MINECRAFT_VERSION = "v0.9.5 alpha";
|
||||
const MINECRAFT_VERSION = "v0.10.4 alpha";
|
||||
|
||||
/*
|
||||
* Startup code. Do not look at it, it may harm you.
|
||||
@ -111,36 +109,6 @@ namespace pocketmine {
|
||||
|
||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
||||
|
||||
if(ini_get("date.timezone") == ""){ //No Timezone set
|
||||
date_default_timezone_set("GMT");
|
||||
if(strpos(" " . strtoupper(php_uname("s")), " WIN") !== false){
|
||||
$time = time();
|
||||
$time -= $time % 60;
|
||||
//TODO: Parse different time & date formats by region. ¬¬ world
|
||||
//Example: USA
|
||||
@exec("time.exe /T", $hour);
|
||||
$i = array_map("intval", explode(":", trim($hour[0])));
|
||||
@exec("date.exe /T", $date);
|
||||
$j = array_map("intval", explode(substr($date[0], 2, 1), trim($date[0])));
|
||||
$offset = @round((mktime($i[0], $i[1], 0, $j[1], $j[0], $j[2]) - $time) / 60) * 60;
|
||||
}else{
|
||||
@exec("date +%s", $t);
|
||||
$offset = @round((intval(trim($t[0])) - time()) / 60) * 60;
|
||||
}
|
||||
|
||||
$daylight = (int) date("I");
|
||||
$d = timezone_name_from_abbr("", $offset, $daylight);
|
||||
@ini_set("date.timezone", $d);
|
||||
@date_default_timezone_set($d);
|
||||
}else{
|
||||
$d = @date_default_timezone_get();
|
||||
if(strpos($d, "/") === false){
|
||||
$d = timezone_name_from_abbr($d);
|
||||
@ini_set("date.timezone", $d);
|
||||
@date_default_timezone_set($d);
|
||||
}
|
||||
}
|
||||
|
||||
gc_enable();
|
||||
error_reporting(-1);
|
||||
ini_set("allow_url_fopen", 1);
|
||||
@ -153,13 +121,174 @@ namespace pocketmine {
|
||||
|
||||
$opts = getopt("", ["enable-ansi", "disable-ansi", "data:", "plugins:", "no-wizard", "enable-profiler"]);
|
||||
|
||||
define("pocketmine\\DATA", isset($opts["data"]) ? realpath($opts["data"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
|
||||
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? realpath($opts["plugins"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
||||
define("pocketmine\\DATA", isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
|
||||
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
||||
|
||||
define("pocketmine\\ANSI", ((strpos(strtoupper(php_uname("s")), "WIN") === false or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"])));
|
||||
define("pocketmine\\ANSI", (Utils::getOS() !== "win" or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"]));
|
||||
|
||||
|
||||
@mkdir(\pocketmine\DATA, 0777, true);
|
||||
|
||||
//Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
|
||||
date_default_timezone_set("UTC");
|
||||
$logger = new MainLogger(\pocketmine\DATA . "server.log", \pocketmine\ANSI);
|
||||
|
||||
if(!ini_get("date.timezone")){
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}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.
|
||||
*/
|
||||
$default_timezone = date_default_timezone_get();
|
||||
if(strpos($default_timezone, "/") === false){
|
||||
$default_timezone = timezone_name_from_abbr($default_timezone);
|
||||
ini_set("date.timezone", $default_timezone);
|
||||
date_default_timezone_set($default_timezone);
|
||||
}
|
||||
}
|
||||
|
||||
function detect_system_timezone(){
|
||||
switch(Utils::getOS()){
|
||||
case 'win':
|
||||
$regex = '/(UTC)(\+*\-*\d*\d*\:*\d*\d*)/';
|
||||
|
||||
/*
|
||||
* wmic timezone get Caption
|
||||
* Get the timezone offset
|
||||
*
|
||||
* Sample Output var_dump
|
||||
* array(3) {
|
||||
* [0] =>
|
||||
* string(7) "Caption"
|
||||
* [1] =>
|
||||
* string(20) "(UTC+09:30) Adelaide"
|
||||
* [2] =>
|
||||
* string(0) ""
|
||||
* }
|
||||
*/
|
||||
exec("wmic timezone get Caption", $output);
|
||||
|
||||
$string = trim(implode("\n", $output));
|
||||
|
||||
//Detect the Time Zone string
|
||||
preg_match($regex, $string, $matches);
|
||||
|
||||
if(!isset($matches[2])){
|
||||
return false;
|
||||
}
|
||||
|
||||
$offset = $matches[2];
|
||||
|
||||
if($offset == ""){
|
||||
return "UTC";
|
||||
}
|
||||
|
||||
return parse_offset($offset);
|
||||
break;
|
||||
case 'linux':
|
||||
// Ubuntu / Debian.
|
||||
if(file_exists('/etc/timezone')){
|
||||
$data = file_get_contents('/etc/timezone');
|
||||
if($data){
|
||||
return trim($data);
|
||||
}
|
||||
}
|
||||
|
||||
// RHEL / CentOS
|
||||
if(file_exists('/etc/sysconfig/clock')){
|
||||
$data = parse_ini_file('/etc/sysconfig/clock');
|
||||
if(!empty($data['ZONE'])){
|
||||
return trim($data['ZONE']);
|
||||
}
|
||||
}
|
||||
|
||||
//Portable method for incompatible linux distributions.
|
||||
|
||||
$offset = trim(exec('date +%:z'));
|
||||
|
||||
if($offset == "+00:00"){
|
||||
return "UTC";
|
||||
}
|
||||
|
||||
return parse_offset($offset);
|
||||
break;
|
||||
case 'mac':
|
||||
if(is_link('/etc/localtime')){
|
||||
$filename = readlink('/etc/localtime');
|
||||
if(strpos($filename, '/usr/share/zoneinfo/') === 0){
|
||||
$timezone = substr($filename, 20);
|
||||
return trim($timezone);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $offset In the format of +09:00, +02:00, -04:00 etc.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function parse_offset($offset){
|
||||
//Make signed offsets unsigned for date_parse
|
||||
if(strpos($offset, '-') !== false){
|
||||
$negative_offset = true;
|
||||
$offset = str_replace('-', '', $offset);
|
||||
}else{
|
||||
if(strpos($offset, '+') !== false){
|
||||
$negative_offset = false;
|
||||
$offset = str_replace('+', '', $offset);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$parsed = date_parse($offset);
|
||||
$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];
|
||||
|
||||
//After date_parse is done, put the sign back
|
||||
if($negative_offset == true){
|
||||
$offset = -abs($offset);
|
||||
}
|
||||
|
||||
//And then, look the offset up.
|
||||
//timezone_name_from_abbr is not used because it returns false on some(most) offsets because it's mapping function is weird.
|
||||
//That's been a bug in PHP since 2008!
|
||||
foreach(timezone_abbreviations_list() as $zones){
|
||||
foreach($zones as $timezone){
|
||||
if($timezone['offset'] == $offset){
|
||||
return $timezone['timezone_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset($opts["enable-profiler"])){
|
||||
if(function_exists("profiler_enable")){
|
||||
\profiler_enable();
|
||||
@ -215,54 +344,7 @@ namespace pocketmine {
|
||||
return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/");
|
||||
}
|
||||
|
||||
function error_handler($errno, $errstr, $errfile, $errline, $trace = null){
|
||||
global $lastError;
|
||||
if(error_reporting() === 0){ //@ error-control
|
||||
return false;
|
||||
}
|
||||
$errorConversion = [
|
||||
E_ERROR => "E_ERROR",
|
||||
E_WARNING => "E_WARNING",
|
||||
E_PARSE => "E_PARSE",
|
||||
E_NOTICE => "E_NOTICE",
|
||||
E_CORE_ERROR => "E_CORE_ERROR",
|
||||
E_CORE_WARNING => "E_CORE_WARNING",
|
||||
E_COMPILE_ERROR => "E_COMPILE_ERROR",
|
||||
E_COMPILE_WARNING => "E_COMPILE_WARNING",
|
||||
E_USER_ERROR => "E_USER_ERROR",
|
||||
E_USER_WARNING => "E_USER_WARNING",
|
||||
E_USER_NOTICE => "E_USER_NOTICE",
|
||||
E_STRICT => "E_STRICT",
|
||||
E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
|
||||
E_DEPRECATED => "E_DEPRECATED",
|
||||
E_USER_DEPRECATED => "E_USER_DEPRECATED",
|
||||
];
|
||||
$type = ($errno === E_ERROR or $errno === E_WARNING or $errno === E_USER_ERROR or $errno === E_USER_WARNING) ? LogLevel::ERROR : LogLevel::NOTICE;
|
||||
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno;
|
||||
if(($pos = strpos($errstr, "\n")) !== false){
|
||||
$errstr = substr($errstr, 0, $pos);
|
||||
}
|
||||
$logger = MainLogger::getLogger();
|
||||
$oldFile = $errfile;
|
||||
$errfile = cleanPath($errfile);
|
||||
$logger->log($type, "An $errno error happened: \"$errstr\" in \"$errfile\" at line $errline");
|
||||
|
||||
foreach(($trace = getTrace($trace === null ? 3 : 0, $trace)) as $i => $line){
|
||||
$logger->debug($line);
|
||||
}
|
||||
$lastError = [
|
||||
"type" => $type,
|
||||
"message" => $errstr,
|
||||
"fullFile" => $oldFile,
|
||||
"file" => $errfile,
|
||||
"line" => $errline,
|
||||
"trace" => $trace
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
set_error_handler("\\pocketmine\\error_handler", E_ALL);
|
||||
set_error_handler([\ExceptionHandler::class, "handler"], -1);
|
||||
|
||||
$errors = 0;
|
||||
|
||||
@ -285,8 +367,8 @@ namespace pocketmine {
|
||||
if(substr_count($pthreads_version, ".") < 2){
|
||||
$pthreads_version = "0.$pthreads_version";
|
||||
}
|
||||
if(version_compare($pthreads_version, "2.0.8") < 0){
|
||||
$logger->critical("pthreads >= 2.0.8 is required, while you have $pthreads_version.");
|
||||
if(version_compare($pthreads_version, "2.0.9") < 0){
|
||||
$logger->critical("pthreads >= 2.0.9 is required, while you have $pthreads_version.");
|
||||
++$errors;
|
||||
}
|
||||
|
||||
@ -364,14 +446,14 @@ namespace pocketmine {
|
||||
$logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
|
||||
if($thread instanceof Thread){
|
||||
$thread->kill();
|
||||
|
||||
if($thread->isRunning() or !$thread->join()){
|
||||
sleep(1);
|
||||
if($thread->isRunning()){
|
||||
$thread->detach();
|
||||
}
|
||||
}elseif($thread instanceof Worker){
|
||||
$thread->kill();
|
||||
sleep(1);
|
||||
if($thread->isRunning() or !$thread->join()){
|
||||
if($thread->isRunning()){
|
||||
$thread->detach();
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,15 @@ use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\ConsoleCommandSender;
|
||||
use pocketmine\command\PluginIdentifiableCommand;
|
||||
use pocketmine\command\SimpleCommandMap;
|
||||
use pocketmine\entity\Arrow;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\FallingSand;
|
||||
use pocketmine\entity\Human;
|
||||
use pocketmine\entity\Item as DroppedItem;
|
||||
use pocketmine\entity\PrimedTNT;
|
||||
use pocketmine\entity\Snowball;
|
||||
use pocketmine\entity\Villager;
|
||||
use pocketmine\entity\Zombie;
|
||||
use pocketmine\event\HandlerList;
|
||||
use pocketmine\event\level\LevelInitEvent;
|
||||
use pocketmine\event\level\LevelLoadEvent;
|
||||
@ -43,9 +51,11 @@ use pocketmine\inventory\InventoryType;
|
||||
use pocketmine\inventory\Recipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\format\anvil\Anvil;
|
||||
use pocketmine\level\format\leveldb\LevelDB;
|
||||
use pocketmine\level\format\LevelProviderManager;
|
||||
use pocketmine\level\format\mcregion\McRegion;
|
||||
use pocketmine\level\generator\Flat;
|
||||
use pocketmine\level\generator\GenerationInstanceManager;
|
||||
use pocketmine\level\generator\GenerationRequestManager;
|
||||
use pocketmine\level\generator\Generator;
|
||||
use pocketmine\level\generator\Normal;
|
||||
@ -78,13 +88,19 @@ use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\scheduler\CallbackTask;
|
||||
use pocketmine\scheduler\SendUsageTask;
|
||||
use pocketmine\scheduler\ServerScheduler;
|
||||
use pocketmine\tile\Chest;
|
||||
use pocketmine\tile\Furnace;
|
||||
use pocketmine\tile\Sign;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\updater\AutoUpdater;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\Cache;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\LevelException;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\ServerException;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\TextWrapper;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
|
||||
@ -113,6 +129,8 @@ class Server{
|
||||
/** @var bool */
|
||||
private $isRunning = true;
|
||||
|
||||
private $hasStopped = false;
|
||||
|
||||
/** @var PluginManager */
|
||||
private $pluginManager = null;
|
||||
|
||||
@ -132,14 +150,15 @@ class Server{
|
||||
*/
|
||||
private $tickCounter;
|
||||
private $nextTick = 0;
|
||||
private $tickAverage = [20,20,20,20,20];
|
||||
private $useAverage = [20,20,20,20,20];
|
||||
private $tickAverage = [20, 20, 20, 20, 20];
|
||||
private $useAverage = [20, 20, 20, 20, 20];
|
||||
|
||||
/** @var \AttachableThreadedLogger */
|
||||
private $logger;
|
||||
|
||||
/** @var CommandReader */
|
||||
private $console = null;
|
||||
private $consoleThreaded;
|
||||
|
||||
/** @var SimpleCommandMap */
|
||||
private $commandMap = null;
|
||||
@ -153,6 +172,9 @@ class Server{
|
||||
/** @var int */
|
||||
private $maxPlayers;
|
||||
|
||||
/** @var bool */
|
||||
private $autoSave;
|
||||
|
||||
/** @var RCON */
|
||||
private $rcon;
|
||||
|
||||
@ -278,21 +300,38 @@ class Server{
|
||||
* @return int
|
||||
*/
|
||||
public function getViewDistance(){
|
||||
return max(56, $this->getProperty("chunk-sending.max-chunks"));
|
||||
return max(56, $this->getProperty("chunk-sending.max-chunks", 96));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIp(){
|
||||
return $this->getConfigString("server-ip", "");
|
||||
return $this->getConfigString("server-ip", "0.0.0.0");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getServerName(){
|
||||
return $this->getConfigString("server-name", "Unknown server");
|
||||
return $this->getConfigString("motd", "Minecraft: PE Server");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getAutoSave(){
|
||||
return $this->autoSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setAutoSave($value){
|
||||
$this->autoSave = (bool) $value;
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->setAutoSave($this->autoSave);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -589,9 +628,16 @@ class Server{
|
||||
* @param string $payload
|
||||
*/
|
||||
public function handlePacket($address, $port, $payload){
|
||||
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
|
||||
$this->queryHandler->handle($address, $port, $payload);
|
||||
} //TODO: add raw packet events
|
||||
try{
|
||||
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
|
||||
$this->queryHandler->handle($address, $port, $payload);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
//TODO: add raw packet events
|
||||
}
|
||||
|
||||
/**
|
||||
@ -622,7 +668,7 @@ class Server{
|
||||
$result = $this->getPlayerExact($name);
|
||||
|
||||
if($result === null){
|
||||
$result = new OfflinePlayer($this, $name);
|
||||
return new OfflinePlayer($this, $name);
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -636,107 +682,112 @@ class Server{
|
||||
public function getOfflinePlayerData($name){
|
||||
$name = strtolower($name);
|
||||
$path = $this->getDataPath() . "players/";
|
||||
if(!file_exists($path . "$name.dat")){
|
||||
$spawn = $this->getDefaultLevel()->getSafeSpawn();
|
||||
$nbt = new Compound(false, [
|
||||
new Long("firstPlayed", floor(microtime(true) * 1000)),
|
||||
new Long("lastPlayed", floor(microtime(true) * 1000)),
|
||||
new Enum("Pos", [
|
||||
new Double(0, $spawn->x),
|
||||
new Double(1, $spawn->y),
|
||||
new Double(2, $spawn->z)
|
||||
]),
|
||||
new String("Level", $this->getDefaultLevel()->getName()),
|
||||
//new String("SpawnLevel", $this->getDefaultLevel()->getName()),
|
||||
//new Int("SpawnX", (int) $spawn->x),
|
||||
//new Int("SpawnY", (int) $spawn->y),
|
||||
//new Int("SpawnZ", (int) $spawn->z),
|
||||
//new Byte("SpawnForced", 1), //TODO
|
||||
new Enum("Inventory", []),
|
||||
new Compound("Achievements", []),
|
||||
new Int("playerGameType", $this->getGamemode()),
|
||||
new Enum("Motion", [
|
||||
new Double(0, 0.0),
|
||||
new Double(1, 0.0),
|
||||
new Double(2, 0.0)
|
||||
]),
|
||||
new Enum("Rotation", [
|
||||
new Float(0, 0.0),
|
||||
new Float(1, 0.0)
|
||||
]),
|
||||
new Float("FallDistance", 0.0),
|
||||
new Short("Fire", 0),
|
||||
new Short("Air", 0),
|
||||
new Byte("OnGround", 1),
|
||||
new Byte("Invulnerable", 0),
|
||||
new String("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);
|
||||
if(file_exists($path . "$name.dat")){
|
||||
try{
|
||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
|
||||
|
||||
if(file_exists($path . "$name.yml")){ //Importing old PocketMine-MP files
|
||||
$data = new Config($path . "$name.yml", Config::YAML, []);
|
||||
$nbt["playerGameType"] = (int) $data->get("gamemode");
|
||||
$nbt["Level"] = $data->get("position")["level"];
|
||||
$nbt["Pos"][0] = $data->get("position")["x"];
|
||||
$nbt["Pos"][1] = $data->get("position")["y"];
|
||||
$nbt["Pos"][2] = $data->get("position")["z"];
|
||||
$nbt["SpawnLevel"] = $data->get("spawn")["level"];
|
||||
$nbt["SpawnX"] = (int) $data->get("spawn")["x"];
|
||||
$nbt["SpawnY"] = (int) $data->get("spawn")["y"];
|
||||
$nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
|
||||
$this->logger->notice("Old Player data found for \"" . $name . "\", upgrading profile");
|
||||
foreach($data->get("inventory") as $slot => $item){
|
||||
if(count($item) === 3){
|
||||
$nbt->Inventory[$slot + 9] = new Compound(false, [
|
||||
new Short("id", $item[0]),
|
||||
new Short("Damage", $item[1]),
|
||||
new Byte("Count", $item[2]),
|
||||
new Byte("Slot", $slot + 9),
|
||||
new Byte("TrueSlot", $slot + 9)
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("hotbar") as $slot => $itemSlot){
|
||||
if(isset($nbt->Inventory[$itemSlot + 9])){
|
||||
$item = $nbt->Inventory[$itemSlot + 9];
|
||||
$nbt->Inventory[$slot] = new Compound(false, [
|
||||
new Short("id", $item["id"]),
|
||||
new Short("Damage", $item["Damage"]),
|
||||
new Byte("Count", $item["Count"]),
|
||||
new Byte("Slot", $slot),
|
||||
new Byte("TrueSlot", $item["TrueSlot"])
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("armor") as $slot => $item){
|
||||
if(count($item) === 2){
|
||||
$nbt->Inventory[$slot + 100] = new Compound(false, [
|
||||
new Short("id", $item[0]),
|
||||
new Short("Damage", $item[1]),
|
||||
new Byte("Count", 1),
|
||||
new Byte("Slot", $slot + 100)
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("achievements") as $achievement => $status){
|
||||
$nbt->Achievements[$achievement] = new Byte($achievement, $status == true ? 1 : 0);
|
||||
}
|
||||
unlink($path . "$name.yml");
|
||||
}else{
|
||||
$this->logger->notice("Player data not found for \"" . $name . "\", creating new profile");
|
||||
return $nbt->getData();
|
||||
}catch(\Exception $e){ //zlib decode error / corrupt data
|
||||
rename($path . "$name.dat", $path . "$name.dat.bak");
|
||||
$this->logger->warning("Corrupted data found for \"" . $name . "\", creating new profile");
|
||||
}
|
||||
$this->saveOfflinePlayerData($name, $nbt);
|
||||
|
||||
return $nbt;
|
||||
}else{
|
||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->readCompressed(file_get_contents($path . "$name.dat"));
|
||||
|
||||
return $nbt->getData();
|
||||
$this->logger->notice("Player data not found for \"" . $name . "\", creating new profile");
|
||||
}
|
||||
$spawn = $this->getDefaultLevel()->getSafeSpawn();
|
||||
$nbt = new Compound(false, [
|
||||
new Long("firstPlayed", floor(microtime(true) * 1000)),
|
||||
new Long("lastPlayed", floor(microtime(true) * 1000)),
|
||||
new Enum("Pos", [
|
||||
new Double(0, $spawn->x),
|
||||
new Double(1, $spawn->y),
|
||||
new Double(2, $spawn->z)
|
||||
]),
|
||||
new String("Level", $this->getDefaultLevel()->getName()),
|
||||
//new String("SpawnLevel", $this->getDefaultLevel()->getName()),
|
||||
//new Int("SpawnX", (int) $spawn->x),
|
||||
//new Int("SpawnY", (int) $spawn->y),
|
||||
//new Int("SpawnZ", (int) $spawn->z),
|
||||
//new Byte("SpawnForced", 1), //TODO
|
||||
new Enum("Inventory", []),
|
||||
new Compound("Achievements", []),
|
||||
new Int("playerGameType", $this->getGamemode()),
|
||||
new Enum("Motion", [
|
||||
new Double(0, 0.0),
|
||||
new Double(1, 0.0),
|
||||
new Double(2, 0.0)
|
||||
]),
|
||||
new Enum("Rotation", [
|
||||
new Float(0, 0.0),
|
||||
new Float(1, 0.0)
|
||||
]),
|
||||
new Float("FallDistance", 0.0),
|
||||
new Short("Fire", 0),
|
||||
new Short("Air", 0),
|
||||
new Byte("OnGround", 1),
|
||||
new Byte("Invulnerable", 0),
|
||||
new String("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);
|
||||
|
||||
if(file_exists($path . "$name.yml")){ //Importing old PocketMine-MP files
|
||||
$data = new Config($path . "$name.yml", Config::YAML, []);
|
||||
$nbt["playerGameType"] = (int) $data->get("gamemode");
|
||||
$nbt["Level"] = $data->get("position")["level"];
|
||||
$nbt["Pos"][0] = $data->get("position")["x"];
|
||||
$nbt["Pos"][1] = $data->get("position")["y"];
|
||||
$nbt["Pos"][2] = $data->get("position")["z"];
|
||||
$nbt["SpawnLevel"] = $data->get("spawn")["level"];
|
||||
$nbt["SpawnX"] = (int) $data->get("spawn")["x"];
|
||||
$nbt["SpawnY"] = (int) $data->get("spawn")["y"];
|
||||
$nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
|
||||
$this->logger->notice("Old Player data found for \"" . $name . "\", upgrading profile");
|
||||
foreach($data->get("inventory") as $slot => $item){
|
||||
if(count($item) === 3){
|
||||
$nbt->Inventory[$slot + 9] = new Compound(false, [
|
||||
new Short("id", $item[0]),
|
||||
new Short("Damage", $item[1]),
|
||||
new Byte("Count", $item[2]),
|
||||
new Byte("Slot", $slot + 9),
|
||||
new Byte("TrueSlot", $slot + 9)
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("hotbar") as $slot => $itemSlot){
|
||||
if(isset($nbt->Inventory[$itemSlot + 9])){
|
||||
$item = $nbt->Inventory[$itemSlot + 9];
|
||||
$nbt->Inventory[$slot] = new Compound(false, [
|
||||
new Short("id", $item["id"]),
|
||||
new Short("Damage", $item["Damage"]),
|
||||
new Byte("Count", $item["Count"]),
|
||||
new Byte("Slot", $slot),
|
||||
new Byte("TrueSlot", $item["TrueSlot"])
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("armor") as $slot => $item){
|
||||
if(count($item) === 2){
|
||||
$nbt->Inventory[$slot + 100] = new Compound(false, [
|
||||
new Short("id", $item[0]),
|
||||
new Short("Damage", $item[1]),
|
||||
new Byte("Count", 1),
|
||||
new Byte("Slot", $slot + 100)
|
||||
]);
|
||||
}
|
||||
}
|
||||
foreach($data->get("achievements") as $achievement => $status){
|
||||
$nbt->Achievements[$achievement] = new Byte($achievement, $status == true ? 1 : 0);
|
||||
}
|
||||
unlink($path . "$name.yml");
|
||||
}
|
||||
$this->saveOfflinePlayerData($name, $nbt);
|
||||
|
||||
return $nbt;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -893,8 +944,8 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
public function unloadLevel(Level $level, $forceUnload = false){
|
||||
if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getFolderName())){
|
||||
unset($this->levels[$level->getID()]);
|
||||
if($level->unload($forceUnload) === true){
|
||||
unset($this->levels[$level->getId()]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -909,11 +960,11 @@ class Server{
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws LevelException
|
||||
*/
|
||||
public function loadLevel($name){
|
||||
if(trim($name) === ""){
|
||||
throw new \Exception("Invalid empty level name");
|
||||
throw new LevelException("Invalid empty level name");
|
||||
}
|
||||
if($this->isLevelLoaded($name)){
|
||||
return true;
|
||||
@ -941,11 +992,15 @@ class Server{
|
||||
$level = new Level($this, $name, $path, $provider);
|
||||
}catch(\Exception $e){
|
||||
$this->logger->error("Could not load level \"" . $name . "\": " . $e->getMessage());
|
||||
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->levels[$level->getID()] = $level;
|
||||
$this->levels[$level->getId()] = $level;
|
||||
|
||||
$level->initLevel();
|
||||
|
||||
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
||||
|
||||
@ -1060,7 +1115,7 @@ class Server{
|
||||
return false;
|
||||
}
|
||||
|
||||
$seed = $seed === null ? Binary::readInt(Utils::getRandomBytes(4, false)) : (int) $seed;
|
||||
$seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed;
|
||||
|
||||
if($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)){
|
||||
$generator = new $generator($options);
|
||||
@ -1078,7 +1133,9 @@ class Server{
|
||||
$provider::generate($path, $name, $seed, $generator, $options);
|
||||
|
||||
$level = new Level($this, $name, $path, $provider);
|
||||
$this->levels[$level->getID()] = $level;
|
||||
$this->levels[$level->getId()] = $level;
|
||||
|
||||
$level->initLevel();
|
||||
|
||||
$this->getPluginManager()->callEvent(new LevelInitEvent($level));
|
||||
|
||||
@ -1090,14 +1147,14 @@ class Server{
|
||||
$radiusSquared = ($this->getViewDistance() + 1) / M_PI;
|
||||
$radius = ceil(sqrt($radiusSquared));
|
||||
|
||||
$centerX = $level->getSpawn()->getX() >> 4;
|
||||
$centerZ = $level->getSpawn()->getZ() >> 4;
|
||||
$centerX = $level->getSpawnLocation()->getX() >> 4;
|
||||
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
|
||||
|
||||
$order = [];
|
||||
|
||||
for($X = -$radius; $X <= $radius; ++$X){
|
||||
for($Z = -$radius; $Z <= $radius; ++$Z){
|
||||
$distance = ($X * $X) + ($Z * $Z);
|
||||
$distance = $X ** 2 + $Z ** 2;
|
||||
if($distance > $radiusSquared){
|
||||
continue;
|
||||
}
|
||||
@ -1170,24 +1227,9 @@ class Server{
|
||||
* @return mixed
|
||||
*/
|
||||
public function getProperty($variable, $defaultValue = null){
|
||||
$vars = explode(".", $variable);
|
||||
$base = array_shift($vars);
|
||||
if($this->config->exists($base)){
|
||||
$base = $this->config->get($base);
|
||||
}else{
|
||||
return $defaultValue;
|
||||
}
|
||||
$value = $this->config->getNested($variable);
|
||||
|
||||
while(count($vars) > 0){
|
||||
$baseKey = array_shift($vars);
|
||||
if(is_array($base) and isset($base[$baseKey])){
|
||||
$base = $base[$baseKey];
|
||||
}else{
|
||||
return $defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $base;
|
||||
return $value === null ? $defaultValue : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1352,7 +1394,7 @@ class Server{
|
||||
/**
|
||||
* @return Config
|
||||
*/
|
||||
public function getOPs(){
|
||||
public function getOps(){
|
||||
return $this->operators;
|
||||
}
|
||||
|
||||
@ -1390,7 +1432,7 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ClassLoader $autoloader
|
||||
* @param \ClassLoader $autoloader
|
||||
* @param \ThreadedLogger $logger
|
||||
* @param string $filePath
|
||||
* @param string $dataPath
|
||||
@ -1402,11 +1444,12 @@ class Server{
|
||||
$this->autoloader = $autoloader;
|
||||
$this->logger = $logger;
|
||||
$this->filePath = $filePath;
|
||||
$this->dataPath = $dataPath;
|
||||
$this->pluginPath = $pluginPath;
|
||||
@mkdir($this->dataPath . "worlds/", 0777, true);
|
||||
@mkdir($this->dataPath . "players/", 0777);
|
||||
@mkdir($this->pluginPath, 0777);
|
||||
@mkdir($dataPath . "worlds/", 0777);
|
||||
@mkdir($dataPath . "players/", 0777);
|
||||
@mkdir($pluginPath, 0777);
|
||||
|
||||
$this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
|
||||
$this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$this->entityMetadata = new EntityMetadataStore();
|
||||
$this->playerMetadata = new PlayerMetadataStore();
|
||||
@ -1424,7 +1467,8 @@ class Server{
|
||||
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
|
||||
$this->banByIP->load();
|
||||
|
||||
$this->console = new CommandReader();
|
||||
$this->consoleThreaded = new \Threaded();
|
||||
$this->console = new CommandReader($this->consoleThreaded);
|
||||
|
||||
$version = new VersionString($this->getPocketMineVersion());
|
||||
$this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
|
||||
@ -1462,7 +1506,7 @@ class Server{
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"enable-rcon" => false,
|
||||
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
|
||||
"rcon.password" => substr(base64_encode(@Utils::getRandomBytes(20, false)), 3, 10),
|
||||
"auto-save" => true,
|
||||
]);
|
||||
|
||||
@ -1475,6 +1519,7 @@ class Server{
|
||||
}
|
||||
|
||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
||||
|
||||
if(($memory = str_replace("B", "", strtoupper($this->getConfigString("memory-limit", "256M")))) !== false){
|
||||
$value = ["M" => 1, "G" => 1024];
|
||||
@ -1500,20 +1545,20 @@ class Server{
|
||||
$this->logger->info("Advanced cache enabled");
|
||||
}
|
||||
|
||||
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 7);
|
||||
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 8);
|
||||
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0){
|
||||
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
||||
}
|
||||
|
||||
$this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
|
||||
define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
|
||||
define("BOOTUP_RANDOM", @Utils::getRandomBytes(16));
|
||||
$this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8));
|
||||
|
||||
$this->addInterface($this->mainInterface = new RakLibInterface($this));
|
||||
|
||||
$this->logger->info("This server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(false) . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0);
|
||||
$this->logger->info($this->getName() . " is distributed under the LGPL License", true, true, 0);
|
||||
$this->logger->info("This server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . TextFormat::WHITE . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")");
|
||||
$this->logger->info($this->getName() . " is distributed under the LGPL License");
|
||||
|
||||
PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
|
||||
Timings::init();
|
||||
@ -1521,9 +1566,13 @@ class Server{
|
||||
$this->consoleSender = new ConsoleCommandSender();
|
||||
$this->commandMap = new SimpleCommandMap($this);
|
||||
|
||||
$this->registerEntities();
|
||||
$this->registerTiles();
|
||||
|
||||
InventoryType::init();
|
||||
Block::init();
|
||||
Item::init();
|
||||
TextWrapper::init();
|
||||
$this->craftingManager = new CraftingManager();
|
||||
|
||||
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
||||
@ -1533,7 +1582,6 @@ class Server{
|
||||
|
||||
set_exception_handler([$this, "exceptionHandler"]);
|
||||
register_shutdown_function([$this, "crashDump"]);
|
||||
register_shutdown_function([$this, "forceShutdown"]);
|
||||
|
||||
$this->pluginManager->loadPlugins($this->pluginPath);
|
||||
|
||||
@ -1541,24 +1589,25 @@ class Server{
|
||||
|
||||
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
||||
|
||||
$this->generationManager = new GenerationRequestManager($this);
|
||||
if($this->getProperty("chunk-generation.use-async", true)){
|
||||
$this->generationManager = new GenerationRequestManager($this);
|
||||
}else{
|
||||
$this->generationManager = new GenerationInstanceManager($this);
|
||||
}
|
||||
|
||||
LevelProviderManager::addProvider($this, Anvil::class);
|
||||
LevelProviderManager::addProvider($this, McRegion::class);
|
||||
if(extension_loaded("leveldb")){
|
||||
$this->logger->debug("Enabling LevelDB support");
|
||||
LevelProviderManager::addProvider($this, LevelDB::class);
|
||||
}
|
||||
|
||||
|
||||
Generator::addGenerator(Flat::class, "flat");
|
||||
Generator::addGenerator(Normal::class, "normal");
|
||||
Generator::addGenerator(Normal::class, "default");
|
||||
|
||||
//Temporal workaround, pthreads static property nullification test
|
||||
if(PluginManager::$pluginParentTimer === null){
|
||||
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
|
||||
kill(getmypid());
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($this->getProperty("worlds", []) as $name => $worldSetting){
|
||||
foreach((array) $this->getProperty("worlds", []) as $name => $worldSetting){
|
||||
if($this->loadLevel($name) === false){
|
||||
$seed = $this->getProperty("worlds.$name.seed", time());
|
||||
$options = explode(":", $this->getProperty("worlds.$name.generator", Generator::getGenerator("default")));
|
||||
@ -1601,7 +1650,7 @@ class Server{
|
||||
}
|
||||
|
||||
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([Cache::class, "cleanup"]), $this->getProperty("ticks-per.cache-cleanup", 900), $this->getProperty("ticks-per.cache-cleanup", 900));
|
||||
if($this->getConfigBoolean("auto-save", true) === true and $this->getProperty("ticks-per.autosave", 6000) > 0){
|
||||
if($this->getAutoSave() and $this->getProperty("ticks-per.autosave", 6000) > 0){
|
||||
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doAutoSave"]), $this->getProperty("ticks-per.autosave", 6000), $this->getProperty("ticks-per.autosave", 6000));
|
||||
}
|
||||
|
||||
@ -1615,12 +1664,18 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $message
|
||||
* @param Player[]|null $recipients
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function broadcastMessage($message){
|
||||
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
||||
public function broadcastMessage($message, $recipients = null){
|
||||
if(!is_array($recipients)){
|
||||
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
||||
}
|
||||
foreach($recipients as $recipient){
|
||||
$recipient->sendMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1654,8 +1709,13 @@ class Server{
|
||||
* @param DataPacket $packet
|
||||
*/
|
||||
public static function broadcastPacket(array $players, DataPacket $packet){
|
||||
$packet->encode();
|
||||
$packet->isEncoded = true;
|
||||
foreach($players as $player){
|
||||
$player->dataPacket(clone $packet);
|
||||
$player->dataPacket($packet);
|
||||
}
|
||||
if(isset($packet->__encapsulatedPacket)){
|
||||
unset($packet->__encapsulatedPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1719,7 +1779,7 @@ class Server{
|
||||
*/
|
||||
public function dispatchCommand(CommandSender $sender, $commandLine){
|
||||
if(!($sender instanceof CommandSender)){
|
||||
throw new \Exception("CommandSender is not valid");
|
||||
throw new ServerException("CommandSender is not valid");
|
||||
}
|
||||
|
||||
if($this->commandMap->dispatch($sender, $commandLine)){
|
||||
@ -1787,40 +1847,54 @@ class Server{
|
||||
}
|
||||
|
||||
public function forceShutdown(){
|
||||
$this->shutdown();
|
||||
if($this->rcon instanceof RCON){
|
||||
$this->rcon->stop();
|
||||
if($this->hasStopped){
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->getProperty("settings.upnp-forwarding", false) === true){
|
||||
$this->logger->info("[UPnP] Removing port forward...");
|
||||
UPnP::RemovePortForward($this->getPort());
|
||||
try{
|
||||
$this->hasStopped = true;
|
||||
|
||||
$this->shutdown();
|
||||
if($this->rcon instanceof RCON){
|
||||
$this->rcon->stop();
|
||||
}
|
||||
|
||||
if($this->getProperty("settings.upnp-forwarding", false) === true){
|
||||
$this->logger->info("[UPnP] Removing port forward...");
|
||||
UPnP::RemovePortForward($this->getPort());
|
||||
}
|
||||
|
||||
$this->pluginManager->disablePlugins();
|
||||
|
||||
foreach($this->players as $player){
|
||||
$player->close(TextFormat::YELLOW . $player->getName() . " has left the game", $this->getProperty("settings.shutdown-message", "Server closed"));
|
||||
}
|
||||
|
||||
foreach($this->getLevels() as $level){
|
||||
$this->unloadLevel($level, true);
|
||||
}
|
||||
|
||||
if($this->generationManager instanceof GenerationRequestManager){
|
||||
$this->generationManager->shutdown();
|
||||
}
|
||||
|
||||
HandlerList::unregisterAll();
|
||||
|
||||
$this->scheduler->cancelAllTasks();
|
||||
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
|
||||
|
||||
$this->properties->save();
|
||||
|
||||
$this->console->kill();
|
||||
|
||||
foreach($this->interfaces as $interface){
|
||||
$interface->shutdown();
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
$this->logger->emergency("Crashed while crashing, killing process");
|
||||
@kill(getmypid());
|
||||
}
|
||||
|
||||
$this->pluginManager->disablePlugins();
|
||||
|
||||
foreach($this->players as $player){
|
||||
$player->close(TextFormat::YELLOW . $player->getName() . " has left the game", $this->getProperty("settings.shutdown-message", "Server closed"));
|
||||
}
|
||||
|
||||
foreach($this->getLevels() as $level){
|
||||
$this->unloadLevel($level, true);
|
||||
}
|
||||
|
||||
if($this->generationManager instanceof GenerationRequestManager){
|
||||
$this->generationManager->shutdown();
|
||||
}
|
||||
|
||||
HandlerList::unregisterAll();
|
||||
$this->scheduler->cancelAllTasks();
|
||||
$this->scheduler->mainThreadHeartbeat(PHP_INT_MAX);
|
||||
|
||||
$this->properties->save();
|
||||
|
||||
$this->console->kill();
|
||||
foreach($this->interfaces as $interface){
|
||||
$interface->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1889,25 +1963,52 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
public function exceptionHandler(\Exception $e){
|
||||
public function exceptionHandler(\Exception $e, $trace = null){
|
||||
if($e === null){
|
||||
return;
|
||||
}
|
||||
|
||||
error_handler(E_ERROR, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace());
|
||||
global $lastError;
|
||||
|
||||
$errstr = $e->getMessage();
|
||||
$errfile = $e->getFile();
|
||||
$errno = $e->getCode();
|
||||
$errline = $e->getLine();
|
||||
|
||||
$type = ($errno === E_ERROR or $errno === E_USER_ERROR) ? \LogLevel::ERROR : (($errno === E_USER_WARNING or $errno === E_WARNING) ? \LogLevel::WARNING : \LogLevel::NOTICE);
|
||||
if(($pos = strpos($errstr, "\n")) !== false){
|
||||
$errstr = substr($errstr, 0, $pos);
|
||||
}
|
||||
|
||||
$errfile = cleanPath($errfile);
|
||||
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e, $trace);
|
||||
}
|
||||
|
||||
$lastError = [
|
||||
"type" => $type,
|
||||
"message" => $errstr,
|
||||
"fullFile" => $e->getFile(),
|
||||
"file" => $errfile,
|
||||
"line" => $errline,
|
||||
"trace" => @getTrace($trace === null ? 3 : 0, $trace)
|
||||
];
|
||||
|
||||
global $lastExceptionError, $lastError;
|
||||
$lastExceptionError = $lastError;
|
||||
$this->crashDump();
|
||||
$this->forceShutdown();
|
||||
kill(getmypid());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public function crashDump(){
|
||||
if($this->isRunning === false){
|
||||
return;
|
||||
}
|
||||
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
|
||||
$this->isRunning = false;
|
||||
$this->hasStopped = false;
|
||||
|
||||
ini_set("error_reporting", 0);
|
||||
ini_set("memory_limit", -1); //Fix error dump not dumped on memory problems
|
||||
$this->logger->emergency("An unrecoverable error has occurred and the server has crashed. Creating a crash dump");
|
||||
$dump = new CrashDump($this);
|
||||
|
||||
@ -1915,44 +2016,49 @@ class Server{
|
||||
|
||||
|
||||
if($this->getProperty("auto-report.enabled", true) !== false){
|
||||
$report = true;
|
||||
$plugin = $dump->getData()["plugin"];
|
||||
if(is_string($plugin)){
|
||||
$p = $this->pluginManager->getPlugin($plugin);
|
||||
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
|
||||
return;
|
||||
$report = false;
|
||||
}
|
||||
}elseif(\Phar::running(true) == ""){
|
||||
return;
|
||||
$report = false;
|
||||
}
|
||||
if($dump->getData()["type"] === "E_PARSE" or $dump->getData()["type"] === "E_COMPILE_ERROR"){
|
||||
return;
|
||||
if($dump->getData()["error"]["type"] === "E_PARSE" or $dump->getData()["error"]["type"] === "E_COMPILE_ERROR"){
|
||||
$report = false;
|
||||
}
|
||||
|
||||
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
|
||||
"report" => "yes",
|
||||
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
|
||||
"email" => "crash@pocketmine.net",
|
||||
"reportPaste" => base64_encode($dump->getEncodedData())
|
||||
]);
|
||||
if($report){
|
||||
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
|
||||
"report" => "yes",
|
||||
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
|
||||
"email" => "crash@pocketmine.net",
|
||||
"reportPaste" => base64_encode($dump->getEncodedData())
|
||||
]);
|
||||
|
||||
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
$this->logger->emergency("The crash dump has been automatically submitted to the Crash Archive. You can view it on $reportUrl or use the ID #$reportId.");
|
||||
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
$this->logger->emergency("The crash dump has been automatically submitted to the Crash Archive. You can view it on $reportUrl or use the ID #$reportId.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//$this->checkMemory();
|
||||
//$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n";
|
||||
|
||||
$this->forceShutdown();
|
||||
@kill(getmypid());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public function __debugInfo(){
|
||||
return get_class($this);
|
||||
return [];
|
||||
}
|
||||
|
||||
private function tickProcessor(){
|
||||
$lastLoop = 0;
|
||||
while($this->isRunning){
|
||||
$this->tick();
|
||||
usleep((int) max(1, ($this->nextTick - microtime(true)) * 1000000));
|
||||
@ -1967,24 +2073,33 @@ class Server{
|
||||
|
||||
//Do level ticks
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->doTick($currentTick);
|
||||
try{
|
||||
$level->doTick($currentTick);
|
||||
}catch(\Exception $e){
|
||||
$this->logger->critical("Could not tick level " . $level->getName() . ": " . $e->getMessage());
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function doAutoSave(){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->getOnlinePlayers() as $index => $player){
|
||||
if($player->isOnline()){
|
||||
$player->save();
|
||||
}elseif(!$player->isConnected()){
|
||||
unset($this->players[$index]);
|
||||
if($this->getAutoSave()){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->getOnlinePlayers() as $index => $player){
|
||||
if($player->isOnline()){
|
||||
$player->save();
|
||||
}elseif(!$player->isConnected()){
|
||||
unset($this->players[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->save(false);
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->save(false);
|
||||
}
|
||||
Timings::$worldSaveTimer->stopTiming();
|
||||
}
|
||||
Timings::$worldSaveTimer->stopTiming();
|
||||
}
|
||||
|
||||
public function doLevelGC(){
|
||||
@ -2029,7 +2144,7 @@ class Server{
|
||||
|
||||
private function titleTick(){
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and \pocketmine\ANSI === true){
|
||||
echo "\x1b]0;". $this->getName() . " " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U " . round($this->mainInterface->getUploadUsage() / 1024, 2) . " D " . round($this->mainInterface->getDownloadUsage() / 1024, 2) . " kB/s | TPS " . $this->getTicksPerSecond() . " | Load ". $this->getTickUsage() . "%\x07";
|
||||
echo "\x1b]0;" . $this->getName() . " " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U " . round($this->mainInterface->getUploadUsage() / 1024, 2) . " D " . round($this->mainInterface->getDownloadUsage() / 1024, 2) . " kB/s | TPS " . $this->getTicksPerSecond() . " | Load " . $this->getTickUsage() . "%\x07";
|
||||
}
|
||||
}
|
||||
|
||||
@ -2064,11 +2179,32 @@ class Server{
|
||||
if(($this->tickCounter & 0b1111) === 0){
|
||||
$this->titleTick();
|
||||
if(isset($this->queryHandler) and ($this->tickCounter & 0b111111111) === 0){
|
||||
$this->queryHandler->regenerateInfo();
|
||||
try{
|
||||
$this->queryHandler->regenerateInfo();
|
||||
}catch(\Exception $e){
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timings::$generationTimer->startTiming();
|
||||
try{
|
||||
$this->generationManager->process();
|
||||
}catch(\Exception $e){
|
||||
if($this->logger instanceof MainLogger){
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
}
|
||||
Timings::$generationTimer->stopTiming();
|
||||
|
||||
if(($this->tickCounter % 100) === 0){
|
||||
foreach($this->levels as $level){
|
||||
$level->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
$this->generationManager->handlePackets();
|
||||
|
||||
Timings::$serverTickTimer->stopTiming();
|
||||
|
||||
@ -2084,9 +2220,26 @@ class Server{
|
||||
$this->nextTick = $tickTime;
|
||||
}
|
||||
$this->nextTick += 0.05;
|
||||
$this->inTick = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function registerEntities(){
|
||||
Entity::registerEntity(Arrow::class);
|
||||
Entity::registerEntity(DroppedItem::class);
|
||||
Entity::registerEntity(FallingSand::class);
|
||||
Entity::registerEntity(PrimedTNT::class);
|
||||
Entity::registerEntity(Snowball::class);
|
||||
Entity::registerEntity(Villager::class);
|
||||
Entity::registerEntity(Zombie::class);
|
||||
|
||||
Entity::registerEntity(Human::class, true);
|
||||
}
|
||||
|
||||
private function registerTiles(){
|
||||
Tile::registerTile(Chest::class);
|
||||
Tile::registerTile(Furnace::class);
|
||||
Tile::registerTile(Sign::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,8 +24,15 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class AcaciaWoodStairs extends Stair{
|
||||
|
||||
protected $id = self::ACACIA_WOOD_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::ACACIA_WOOD_STAIRS, $meta, "Acacia Wood Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Acacia Wood Stairs";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -21,29 +21,45 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
|
||||
/**
|
||||
* Air block
|
||||
*/
|
||||
class Air extends Transparent{
|
||||
public $isActivable = false;
|
||||
public $breakable = false;
|
||||
public $isFlowable = true;
|
||||
public $isTransparent = true;
|
||||
public $isReplaceable = true;
|
||||
public $isPlaceable = false;
|
||||
public $hasPhysics = false;
|
||||
public $isSolid = false;
|
||||
public $isFullBlock = true;
|
||||
|
||||
protected $id = self::AIR;
|
||||
protected $meta = 0;
|
||||
protected $name = "Air";
|
||||
protected $hardness = 0;
|
||||
|
||||
public function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Air";
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeFlowedInto(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBeReplaced(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canBePlaced(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
@ -28,14 +28,26 @@ use pocketmine\network\protocol\ChatPacket;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Bed extends Transparent{
|
||||
public function __construct($type = 0){
|
||||
parent::__construct(self::BED_BLOCK, $type, "Bed Block");
|
||||
$this->isActivable = true;
|
||||
$this->isFullBlock = false;
|
||||
$this->hardness = 1;
|
||||
|
||||
protected $id = self::BED_BLOCK;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Bed Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -53,7 +65,7 @@ class Bed extends Transparent{
|
||||
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
||||
|
||||
if($player instanceof Player and !$isNight){
|
||||
$pk = new ChatPacket;
|
||||
$pk = new ChatPacket();
|
||||
$pk->message = "You can only sleep at night";
|
||||
$player->dataPacket($pk);
|
||||
|
||||
@ -67,17 +79,17 @@ class Bed extends Transparent{
|
||||
if(($this->meta & 0x08) === 0x08){ //This is the Top part of bed
|
||||
$b = $this;
|
||||
}else{ //Bottom Part of Bed
|
||||
if($blockNorth->getID() === $this->id and ($blockNorth->meta & 0x08) === 0x08){
|
||||
if($blockNorth->getId() === $this->id and ($blockNorth->meta & 0x08) === 0x08){
|
||||
$b = $blockNorth;
|
||||
}elseif($blockSouth->getID() === $this->id and ($blockSouth->meta & 0x08) === 0x08){
|
||||
}elseif($blockSouth->getId() === $this->id and ($blockSouth->meta & 0x08) === 0x08){
|
||||
$b = $blockSouth;
|
||||
}elseif($blockEast->getID() === $this->id and ($blockEast->meta & 0x08) === 0x08){
|
||||
}elseif($blockEast->getId() === $this->id and ($blockEast->meta & 0x08) === 0x08){
|
||||
$b = $blockEast;
|
||||
}elseif($blockWest->getID() === $this->id and ($blockWest->meta & 0x08) === 0x08){
|
||||
}elseif($blockWest->getId() === $this->id and ($blockWest->meta & 0x08) === 0x08){
|
||||
$b = $blockWest;
|
||||
}else{
|
||||
if($player instanceof Player){
|
||||
$pk = new ChatPacket;
|
||||
$pk = new ChatPacket();
|
||||
$pk->message = "This bed is incomplete";
|
||||
$player->dataPacket($pk);
|
||||
}
|
||||
@ -87,7 +99,7 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
if($player instanceof Player and $player->sleepOn($b) === false){
|
||||
$pk = new ChatPacket;
|
||||
$pk = new ChatPacket();
|
||||
$pk->message = "This bed is occupied";
|
||||
$player->dataPacket($pk);
|
||||
}
|
||||
@ -97,7 +109,7 @@ class Bed extends Transparent{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === false){
|
||||
if($down->isTransparent() === false){
|
||||
$faces = [
|
||||
0 => 3,
|
||||
1 => 4,
|
||||
@ -107,7 +119,7 @@ class Bed extends Transparent{
|
||||
$d = $player instanceof Player ? $player->getDirection() : 0;
|
||||
$next = $this->getSide($faces[(($d + 3) % 4)]);
|
||||
$downNext = $this->getSide(0);
|
||||
if($next->isReplaceable === true and $downNext->isTransparent === false){
|
||||
if($next->canBeReplaced() === true and $downNext->isTransparent() === false){
|
||||
$meta = (($d + 3) % 4) & 0x03;
|
||||
$this->getLevel()->setBlock($block, Block::get($this->id, $meta), true, true);
|
||||
$this->getLevel()->setBlock($next, Block::get($this->id, $meta | 0x08), true, true);
|
||||
@ -126,23 +138,23 @@ class Bed extends Transparent{
|
||||
$blockWest = $this->getSide(4);
|
||||
|
||||
if(($this->meta & 0x08) === 0x08){ //This is the Top part of bed
|
||||
if($blockNorth->getID() === $this->id and $blockNorth->meta !== 0x08){ //Checks if the block ID and meta are right
|
||||
if($blockNorth->getId() === $this->id and $blockNorth->meta !== 0x08){ //Checks if the block ID and meta are right
|
||||
$this->getLevel()->setBlock($blockNorth, new Air(), true, true);
|
||||
}elseif($blockSouth->getID() === $this->id and $blockSouth->meta !== 0x08){
|
||||
}elseif($blockSouth->getId() === $this->id and $blockSouth->meta !== 0x08){
|
||||
$this->getLevel()->setBlock($blockSouth, new Air(), true, true);
|
||||
}elseif($blockEast->getID() === $this->id and $blockEast->meta !== 0x08){
|
||||
}elseif($blockEast->getId() === $this->id and $blockEast->meta !== 0x08){
|
||||
$this->getLevel()->setBlock($blockEast, new Air(), true, true);
|
||||
}elseif($blockWest->getID() === $this->id and $blockWest->meta !== 0x08){
|
||||
}elseif($blockWest->getId() === $this->id and $blockWest->meta !== 0x08){
|
||||
$this->getLevel()->setBlock($blockWest, new Air(), true, true);
|
||||
}
|
||||
}else{ //Bottom Part of Bed
|
||||
if($blockNorth->getID() === $this->id and ($blockNorth->meta & 0x08) === 0x08){
|
||||
if($blockNorth->getId() === $this->id and ($blockNorth->meta & 0x08) === 0x08){
|
||||
$this->getLevel()->setBlock($blockNorth, new Air(), true, true);
|
||||
}elseif($blockSouth->getID() === $this->id and ($blockSouth->meta & 0x08) === 0x08){
|
||||
}elseif($blockSouth->getId() === $this->id and ($blockSouth->meta & 0x08) === 0x08){
|
||||
$this->getLevel()->setBlock($blockSouth, new Air(), true, true);
|
||||
}elseif($blockEast->getID() === $this->id and ($blockEast->meta & 0x08) === 0x08){
|
||||
}elseif($blockEast->getId() === $this->id and ($blockEast->meta & 0x08) === 0x08){
|
||||
$this->getLevel()->setBlock($blockEast, new Air(), true, true);
|
||||
}elseif($blockWest->getID() === $this->id and ($blockWest->meta & 0x08) === 0x08){
|
||||
}elseif($blockWest->getId() === $this->id and ($blockWest->meta & 0x08) === 0x08){
|
||||
$this->getLevel()->setBlock($blockWest, new Air(), true, true);
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Bedrock extends Solid{
|
||||
|
||||
protected $id = self::BEDROCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::BEDROCK, 0, "Bedrock");
|
||||
$this->breakable = false;
|
||||
$this->hardness = 18000000;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Bedrock";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 18000000;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
|
@ -22,65 +22,17 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Beetroot extends Flowable{
|
||||
class Beetroot extends Crops{
|
||||
|
||||
protected $id = self::BEETROOT_BLOCK;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::BEETROOT_BLOCK, $meta, "Beetroot Block");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 0;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$this->meta = 0x07;
|
||||
$this->getLevel()->setBlock($this, $this, true, true);
|
||||
$item->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get(Item::BEETROOT_SEEDS, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}else{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
public function getName(){
|
||||
return "Beetroot Block";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -24,8 +24,15 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class BirchWoodStairs extends Stair{
|
||||
|
||||
protected $id = self::BIRCH_WOOD_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::BIRCH_WOOD_STAIRS, $meta, "Birch Wood Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Birch Wood Stairs";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -39,7 +39,7 @@ use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
|
||||
|
||||
abstract class Block extends Position implements Metadatable{
|
||||
class Block extends Position implements Metadatable{
|
||||
const AIR = 0;
|
||||
const STONE = 1;
|
||||
const GRASS = 2;
|
||||
@ -144,6 +144,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
const SUGARCANE_BLOCK = 83;
|
||||
|
||||
const FENCE = 85;
|
||||
const FENCE_OAK = 85;
|
||||
const PUMPKIN = 86;
|
||||
const NETHERRACK = 87;
|
||||
const SOUL_SAND = 88;
|
||||
@ -167,7 +168,8 @@ abstract class Block extends Position implements Metadatable{
|
||||
const MELON_BLOCK = 103;
|
||||
const PUMPKIN_STEM = 104;
|
||||
const MELON_STEM = 105;
|
||||
|
||||
const VINE = 106;
|
||||
const VINES = 106;
|
||||
const FENCE_GATE = 107;
|
||||
const BRICK_STAIRS = 108;
|
||||
const STONE_BRICK_STAIRS = 109;
|
||||
@ -178,7 +180,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
|
||||
const NETHER_BRICKS_STAIRS = 114;
|
||||
|
||||
const END_PORTAL = 120;
|
||||
const END_PORTAL_FRAME = 120;
|
||||
const END_STONE = 121;
|
||||
|
||||
const SANDSTONE_STAIRS = 128;
|
||||
@ -227,6 +229,19 @@ abstract class Block extends Position implements Metadatable{
|
||||
const HARDENED_CLAY = 172;
|
||||
const COAL_BLOCK = 173;
|
||||
|
||||
const DOUBLE_PLANT = 175;
|
||||
|
||||
const FENCE_GATE_SPRUCE = 183;
|
||||
const FENCE_GATE_BIRCH = 184;
|
||||
const FENCE_GATE_JUNGLE = 185;
|
||||
const FENCE_GATE_DARK_OAK = 186;
|
||||
const FENCE_GATE_ACACIA = 187;
|
||||
const FENCE_SPRUCE = 188;
|
||||
const FENCE_BIRCH = 189;
|
||||
const FENCE_JUNGLE = 190;
|
||||
const FENCE_DARK_OAK = 191;
|
||||
const FENCE_ACACIA = 192;
|
||||
|
||||
const PODZOL = 243;
|
||||
const BEETROOT_BLOCK = 244;
|
||||
const STONECUTTER = 245;
|
||||
@ -345,7 +360,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
[Item::SNOW_LAYER, 0],
|
||||
[Item::GLASS, 0],
|
||||
[Item::GLOWSTONE_BLOCK, 0],
|
||||
//TODO: Vines
|
||||
[Item::VINES, 0],
|
||||
[Item::NETHER_REACTOR, 0],
|
||||
[Item::LADDER, 0],
|
||||
[Item::SPONGE, 0],
|
||||
@ -353,7 +368,16 @@ abstract class Block extends Position implements Metadatable{
|
||||
[Item::WOODEN_DOOR, 0],
|
||||
[Item::TRAPDOOR, 0],
|
||||
[Item::FENCE, 0],
|
||||
[Item::FENCE_SPRUCE, 0],
|
||||
[Item::FENCE_BIRCH, 0],
|
||||
[Item::FENCE_DARK_OAK, 0],
|
||||
[Item::FENCE_JUNGLE, 0],
|
||||
[Item::FENCE_GATE, 0],
|
||||
[Item::FENCE_GATE_BIRCH, 0],
|
||||
[Item::FENCE_GATE_SPRUCE, 0],
|
||||
[Item::FENCE_GATE_DARK_OAK, 0],
|
||||
[Item::FENCE_GATE_JUNGLE, 0],
|
||||
[Item::FENCE_GATE_ACACIA, 0],
|
||||
[Item::IRON_BARS, 0],
|
||||
[Item::BED, 0],
|
||||
[Item::BOOKSHELF, 0],
|
||||
@ -362,7 +386,6 @@ abstract class Block extends Position implements Metadatable{
|
||||
[Item::STONECUTTER, 0],
|
||||
[Item::CHEST, 0],
|
||||
[Item::FURNACE, 0],
|
||||
//TODO: End Portal
|
||||
[Item::END_PORTAL, 0],
|
||||
[Item::DANDELION, 0],
|
||||
[Item::POPPY, 0],
|
||||
@ -505,168 +528,247 @@ abstract class Block extends Position implements Metadatable{
|
||||
|
||||
];
|
||||
|
||||
/** @var Block[] */
|
||||
public static $list = [];
|
||||
/** @var \SplFixedArray */
|
||||
public static $list = null;
|
||||
/** @var \SplFixedArray */
|
||||
public static $fullList = null;
|
||||
|
||||
/** @var \SplFixedArray */
|
||||
public static $light = null;
|
||||
/** @var \SplFixedArray */
|
||||
public static $lightFilter = null;
|
||||
/** @var \SplFixedArray */
|
||||
public static $solid = null;
|
||||
/** @var \SplFixedArray */
|
||||
public static $hardness = null;
|
||||
/** @var \SplFixedArray */
|
||||
public static $transparent = null;
|
||||
|
||||
protected $id;
|
||||
protected $meta;
|
||||
protected $name = "Unknown";
|
||||
protected $breakTime = 0.20;
|
||||
protected $hardness = 10;
|
||||
public $isActivable = false;
|
||||
public $breakable = true;
|
||||
public $isFlowable = false;
|
||||
public $isSolid = true;
|
||||
public $isTransparent = false;
|
||||
public $isReplaceable = false;
|
||||
public $isPlaceable = true;
|
||||
public $hasPhysics = false;
|
||||
public $isLiquid = false;
|
||||
public $isFullBlock = true;
|
||||
public $x = 0;
|
||||
public $y = 0;
|
||||
public $z = 0;
|
||||
public $frictionFactor = 0.6;
|
||||
protected $meta = 0;
|
||||
|
||||
/** @var AxisAlignedBB */
|
||||
protected $boundingBox = null;
|
||||
|
||||
/**
|
||||
* Backwards-compatibility with old way to define block properties
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key){
|
||||
static $map = [
|
||||
"hardness" => "getHardness",
|
||||
"lightLevel" => "getLightLevel",
|
||||
"frictionFactor" => "getFrictionFactor",
|
||||
"name" => "getName",
|
||||
"isPlaceable" => "canBePlaced",
|
||||
"isReplaceable" => "canBeReplaced",
|
||||
"isTransparent" => "isTransparent",
|
||||
"isSolid" => "isSolid",
|
||||
"isFlowable" => "canBeFlowedInto",
|
||||
"isActivable" => "canBeActivated",
|
||||
"hasEntityCollision" => "hasEntityCollision"
|
||||
];
|
||||
return isset($map[$key]) ? $this->{$map[$key]}() : null;
|
||||
}
|
||||
|
||||
public static function init(){
|
||||
if(count(self::$list) === 0){
|
||||
self::$list = [
|
||||
self::AIR => Air::class,
|
||||
self::STONE => Stone::class,
|
||||
self::GRASS => Grass::class,
|
||||
self::DIRT => Dirt::class,
|
||||
self::COBBLESTONE => Cobblestone::class,
|
||||
self::PLANKS => Planks::class,
|
||||
self::SAPLING => Sapling::class,
|
||||
self::BEDROCK => Bedrock::class,
|
||||
self::WATER => Water::class,
|
||||
self::STILL_WATER => StillWater::class,
|
||||
self::LAVA => Lava::class,
|
||||
self::STILL_LAVA => StillLava::class,
|
||||
self::SAND => Sand::class,
|
||||
self::GRAVEL => Gravel::class,
|
||||
self::GOLD_ORE => GoldOre::class,
|
||||
self::IRON_ORE => IronOre::class,
|
||||
self::COAL_ORE => CoalOre::class,
|
||||
self::WOOD => Wood::class,
|
||||
self::LEAVES => Leaves::class,
|
||||
self::SPONGE => Sponge::class,
|
||||
self::GLASS => Glass::class,
|
||||
self::LAPIS_ORE => LapisOre::class,
|
||||
self::LAPIS_BLOCK => Lapis::class,
|
||||
self::SANDSTONE => Sandstone::class,
|
||||
self::BED_BLOCK => Bed::class,
|
||||
self::COBWEB => Cobweb::class,
|
||||
self::TALL_GRASS => TallGrass::class,
|
||||
self::DEAD_BUSH => DeadBush::class,
|
||||
self::WOOL => Wool::class,
|
||||
self::DANDELION => Dandelion::class,
|
||||
self::POPPY => CyanFlower::class,
|
||||
self::BROWN_MUSHROOM => BrownMushroom::class,
|
||||
self::RED_MUSHROOM => RedMushroom::class,
|
||||
self::GOLD_BLOCK => Gold::class,
|
||||
self::IRON_BLOCK => Iron::class,
|
||||
self::DOUBLE_SLAB => DoubleSlab::class,
|
||||
self::SLAB => Slab::class,
|
||||
self::BRICKS_BLOCK => Bricks::class,
|
||||
self::TNT => TNT::class,
|
||||
self::BOOKSHELF => Bookshelf::class,
|
||||
self::MOSS_STONE => MossStone::class,
|
||||
self::OBSIDIAN => Obsidian::class,
|
||||
self::TORCH => Torch::class,
|
||||
self::FIRE => Fire::class,
|
||||
self::MONSTER_SPAWNER => MonsterSpawner::class,
|
||||
self::WOOD_STAIRS => WoodStairs::class,
|
||||
self::CHEST => Chest::class,
|
||||
if(self::$list === null){
|
||||
self::$list = new \SplFixedArray(256);
|
||||
self::$fullList = new \SplFixedArray(4096);
|
||||
self::$light = new \SplFixedArray(256);
|
||||
self::$lightFilter = new \SplFixedArray(256);
|
||||
self::$solid = new \SplFixedArray(256);
|
||||
self::$hardness = new \SplFixedArray(256);
|
||||
self::$transparent = new \SplFixedArray(256);
|
||||
self::$list[self::AIR] = Air::class;
|
||||
self::$list[self::STONE] = Stone::class;
|
||||
self::$list[self::GRASS] = Grass::class;
|
||||
self::$list[self::DIRT] = Dirt::class;
|
||||
self::$list[self::COBBLESTONE] = Cobblestone::class;
|
||||
self::$list[self::PLANKS] = Planks::class;
|
||||
self::$list[self::SAPLING] = Sapling::class;
|
||||
self::$list[self::BEDROCK] = Bedrock::class;
|
||||
self::$list[self::WATER] = Water::class;
|
||||
self::$list[self::STILL_WATER] = StillWater::class;
|
||||
self::$list[self::LAVA] = Lava::class;
|
||||
self::$list[self::STILL_LAVA] = StillLava::class;
|
||||
self::$list[self::SAND] = Sand::class;
|
||||
self::$list[self::GRAVEL] = Gravel::class;
|
||||
self::$list[self::GOLD_ORE] = GoldOre::class;
|
||||
self::$list[self::IRON_ORE] = IronOre::class;
|
||||
self::$list[self::COAL_ORE] = CoalOre::class;
|
||||
self::$list[self::WOOD] = Wood::class;
|
||||
self::$list[self::LEAVES] = Leaves::class;
|
||||
self::$list[self::SPONGE] = Sponge::class;
|
||||
self::$list[self::GLASS] = Glass::class;
|
||||
self::$list[self::LAPIS_ORE] = LapisOre::class;
|
||||
self::$list[self::LAPIS_BLOCK] = Lapis::class;
|
||||
self::$list[self::SANDSTONE] = Sandstone::class;
|
||||
self::$list[self::BED_BLOCK] = Bed::class;
|
||||
self::$list[self::COBWEB] = Cobweb::class;
|
||||
self::$list[self::TALL_GRASS] = TallGrass::class;
|
||||
self::$list[self::DEAD_BUSH] = DeadBush::class;
|
||||
self::$list[self::WOOL] = Wool::class;
|
||||
self::$list[self::DANDELION] = Dandelion::class;
|
||||
self::$list[self::POPPY] = Poppy::class;
|
||||
self::$list[self::BROWN_MUSHROOM] = BrownMushroom::class;
|
||||
self::$list[self::RED_MUSHROOM] = RedMushroom::class;
|
||||
self::$list[self::GOLD_BLOCK] = Gold::class;
|
||||
self::$list[self::IRON_BLOCK] = Iron::class;
|
||||
self::$list[self::DOUBLE_SLAB] = DoubleSlab::class;
|
||||
self::$list[self::SLAB] = Slab::class;
|
||||
self::$list[self::BRICKS_BLOCK] = Bricks::class;
|
||||
self::$list[self::TNT] = TNT::class;
|
||||
self::$list[self::BOOKSHELF] = Bookshelf::class;
|
||||
self::$list[self::MOSS_STONE] = MossStone::class;
|
||||
self::$list[self::OBSIDIAN] = Obsidian::class;
|
||||
self::$list[self::TORCH] = Torch::class;
|
||||
self::$list[self::FIRE] = Fire::class;
|
||||
self::$list[self::MONSTER_SPAWNER] = MonsterSpawner::class;
|
||||
self::$list[self::WOOD_STAIRS] = WoodStairs::class;
|
||||
self::$list[self::CHEST] = Chest::class;
|
||||
|
||||
self::DIAMOND_ORE => DiamondOre::class,
|
||||
self::DIAMOND_BLOCK => Diamond::class,
|
||||
self::WORKBENCH => Workbench::class,
|
||||
self::WHEAT_BLOCK => Wheat::class,
|
||||
self::FARMLAND => Farmland::class,
|
||||
self::FURNACE => Furnace::class,
|
||||
self::BURNING_FURNACE => BurningFurnace::class,
|
||||
self::SIGN_POST => SignPost::class,
|
||||
self::WOOD_DOOR_BLOCK => WoodDoor::class,
|
||||
self::LADDER => Ladder::class,
|
||||
self::$list[self::DIAMOND_ORE] = DiamondOre::class;
|
||||
self::$list[self::DIAMOND_BLOCK] = Diamond::class;
|
||||
self::$list[self::WORKBENCH] = Workbench::class;
|
||||
self::$list[self::WHEAT_BLOCK] = Wheat::class;
|
||||
self::$list[self::FARMLAND] = Farmland::class;
|
||||
self::$list[self::FURNACE] = Furnace::class;
|
||||
self::$list[self::BURNING_FURNACE] = BurningFurnace::class;
|
||||
self::$list[self::SIGN_POST] = SignPost::class;
|
||||
self::$list[self::WOOD_DOOR_BLOCK] = WoodDoor::class;
|
||||
self::$list[self::LADDER] = Ladder::class;
|
||||
|
||||
self::COBBLESTONE_STAIRS => CobblestoneStairs::class,
|
||||
self::WALL_SIGN => WallSign::class,
|
||||
self::$list[self::COBBLESTONE_STAIRS] = CobblestoneStairs::class;
|
||||
self::$list[self::WALL_SIGN] = WallSign::class;
|
||||
|
||||
self::IRON_DOOR_BLOCK => IronDoor::class,
|
||||
self::REDSTONE_ORE => RedstoneOre::class,
|
||||
self::GLOWING_REDSTONE_ORE => GlowingRedstoneOre::class,
|
||||
self::$list[self::IRON_DOOR_BLOCK] = IronDoor::class;
|
||||
self::$list[self::REDSTONE_ORE] = RedstoneOre::class;
|
||||
self::$list[self::GLOWING_REDSTONE_ORE] = GlowingRedstoneOre::class;
|
||||
|
||||
self::SNOW_LAYER => SnowLayer::class,
|
||||
self::ICE => Ice::class,
|
||||
self::SNOW_BLOCK => Snow::class,
|
||||
self::CACTUS => Cactus::class,
|
||||
self::CLAY_BLOCK => Clay::class,
|
||||
self::SUGARCANE_BLOCK => Sugarcane::class,
|
||||
self::$list[self::SNOW_LAYER] = SnowLayer::class;
|
||||
self::$list[self::ICE] = Ice::class;
|
||||
self::$list[self::SNOW_BLOCK] = Snow::class;
|
||||
self::$list[self::CACTUS] = Cactus::class;
|
||||
self::$list[self::CLAY_BLOCK] = Clay::class;
|
||||
self::$list[self::SUGARCANE_BLOCK] = Sugarcane::class;
|
||||
|
||||
self::FENCE => Fence::class,
|
||||
self::PUMPKIN => Pumpkin::class,
|
||||
self::NETHERRACK => Netherrack::class,
|
||||
self::SOUL_SAND => SoulSand::class,
|
||||
self::GLOWSTONE_BLOCK => Glowstone::class,
|
||||
self::$list[self::FENCE] = Fence::class;
|
||||
self::$list[self::PUMPKIN] = Pumpkin::class;
|
||||
self::$list[self::NETHERRACK] = Netherrack::class;
|
||||
self::$list[self::SOUL_SAND] = SoulSand::class;
|
||||
self::$list[self::GLOWSTONE_BLOCK] = Glowstone::class;
|
||||
|
||||
self::LIT_PUMPKIN => LitPumpkin::class,
|
||||
self::CAKE_BLOCK => Cake::class,
|
||||
self::$list[self::LIT_PUMPKIN] = LitPumpkin::class;
|
||||
self::$list[self::CAKE_BLOCK] = Cake::class;
|
||||
|
||||
self::TRAPDOOR => Trapdoor::class,
|
||||
self::$list[self::TRAPDOOR] = Trapdoor::class;
|
||||
|
||||
self::STONE_BRICKS => StoneBricks::class,
|
||||
self::$list[self::STONE_BRICKS] = StoneBricks::class;
|
||||
|
||||
self::IRON_BARS => IronBars::class,
|
||||
self::GLASS_PANE => GlassPane::class,
|
||||
self::MELON_BLOCK => Melon::class,
|
||||
self::PUMPKIN_STEM => PumpkinStem::class,
|
||||
self::MELON_STEM => MelonStem::class,
|
||||
self::$list[self::IRON_BARS] = IronBars::class;
|
||||
self::$list[self::GLASS_PANE] = GlassPane::class;
|
||||
self::$list[self::MELON_BLOCK] = Melon::class;
|
||||
self::$list[self::PUMPKIN_STEM] = PumpkinStem::class;
|
||||
self::$list[self::MELON_STEM] = MelonStem::class;
|
||||
self::$list[self::VINE] = Vine::class;
|
||||
self::$list[self::FENCE_GATE] = FenceGate::class;
|
||||
self::$list[self::BRICK_STAIRS] = BrickStairs::class;
|
||||
self::$list[self::STONE_BRICK_STAIRS] = StoneBrickStairs::class;
|
||||
|
||||
self::FENCE_GATE => FenceGate::class,
|
||||
self::BRICK_STAIRS => BrickStairs::class,
|
||||
self::STONE_BRICK_STAIRS => StoneBrickStairs::class,
|
||||
self::$list[self::MYCELIUM] = Mycelium::class;
|
||||
self::$list[self::NETHER_BRICKS] = NetherBrick::class;
|
||||
|
||||
self::MYCELIUM => Mycelium::class,
|
||||
self::NETHER_BRICKS => NetherBrick::class,
|
||||
self::$list[self::NETHER_BRICKS_STAIRS] = NetherBrickStairs::class;
|
||||
|
||||
self::NETHER_BRICKS_STAIRS => NetherBrickStairs::class,
|
||||
self::$list[self::END_PORTAL_FRAME] = EndPortalFrame::class;
|
||||
self::$list[self::END_STONE] = EndStone::class;
|
||||
self::$list[self::SANDSTONE_STAIRS] = SandstoneStairs::class;
|
||||
self::$list[self::EMERALD_ORE] = EmeraldOre::class;
|
||||
|
||||
self::END_PORTAL => EndPortal::class,
|
||||
self::END_STONE => EndStone::class,
|
||||
self::SANDSTONE_STAIRS => SandstoneStairs::class,
|
||||
self::EMERALD_ORE => EmeraldOre::class,
|
||||
self::$list[self::EMERALD_BLOCK] = Emerald::class;
|
||||
self::$list[self::SPRUCE_WOOD_STAIRS] = SpruceWoodStairs::class;
|
||||
self::$list[self::BIRCH_WOOD_STAIRS] = BirchWoodStairs::class;
|
||||
self::$list[self::JUNGLE_WOOD_STAIRS] = JungleWoodStairs::class;
|
||||
self::$list[self::STONE_WALL] = StoneWall::class;
|
||||
|
||||
self::EMERALD_BLOCK => Emerald::class,
|
||||
self::SPRUCE_WOOD_STAIRS => SpruceWoodStairs::class,
|
||||
self::BIRCH_WOOD_STAIRS => BirchWoodStairs::class,
|
||||
self::JUNGLE_WOOD_STAIRS => JungleWoodStairs::class,
|
||||
self::STONE_WALL => StoneWall::class,
|
||||
self::$list[self::CARROT_BLOCK] = Carrot::class;
|
||||
self::$list[self::POTATO_BLOCK] = Potato::class;
|
||||
|
||||
self::CARROT_BLOCK => Carrot::class,
|
||||
self::POTATO_BLOCK => Potato::class,
|
||||
self::$list[self::QUARTZ_BLOCK] = Quartz::class;
|
||||
self::$list[self::QUARTZ_STAIRS] = QuartzStairs::class;
|
||||
self::$list[self::DOUBLE_WOOD_SLAB] = DoubleWoodSlab::class;
|
||||
self::$list[self::WOOD_SLAB] = WoodSlab::class;
|
||||
self::$list[self::STAINED_CLAY] = StainedClay::class;
|
||||
|
||||
self::QUARTZ_BLOCK => Quartz::class,
|
||||
self::QUARTZ_STAIRS => QuartzStairs::class,
|
||||
self::DOUBLE_WOOD_SLAB => DoubleWoodSlab::class,
|
||||
self::WOOD_SLAB => WoodSlab::class,
|
||||
self::STAINED_CLAY => StainedClay::class,
|
||||
self::$list[self::LEAVES2] = Leaves2::class;
|
||||
self::$list[self::WOOD2] = Wood2::class;
|
||||
self::$list[self::ACACIA_WOOD_STAIRS] = AcaciaWoodStairs::class;
|
||||
self::$list[self::DARK_OAK_WOOD_STAIRS] = DarkOakWoodStairs::class;
|
||||
|
||||
self::LEAVES2 => Leaves2::class,
|
||||
self::WOOD2 => Wood2::class,
|
||||
self::ACACIA_WOOD_STAIRS => AcaciaWoodStairs::class,
|
||||
self::DARK_OAK_WOOD_STAIRS => DarkOakWoodStairs::class,
|
||||
self::$list[self::HAY_BALE] = HayBale::class;
|
||||
self::$list[self::CARPET] = Carpet::class;
|
||||
self::$list[self::HARDENED_CLAY] = HardenedClay::class;
|
||||
self::$list[self::COAL_BLOCK] = Coal::class;
|
||||
|
||||
self::HAY_BALE => HayBale::class,
|
||||
self::CARPET => Carpet::class,
|
||||
self::HARDENED_CLAY => HardenedClay::class,
|
||||
self::COAL_BLOCK => Coal::class,
|
||||
self::$list[self::DOUBLE_PLANT] = DoublePlant::class;
|
||||
|
||||
self::PODZOL => Podzol::class,
|
||||
self::BEETROOT_BLOCK => Beetroot::class,
|
||||
self::STONECUTTER => Stonecutter::class,
|
||||
self::GLOWING_OBSIDIAN => GlowingObsidian::class,
|
||||
self::NETHER_REACTOR => NetherReactor::class,
|
||||
];
|
||||
self::$list[self::FENCE_GATE_SPRUCE] = FenceGateSpruce::class;
|
||||
self::$list[self::FENCE_GATE_BIRCH] = FenceGateBirch::class;
|
||||
self::$list[self::FENCE_GATE_JUNGLE] = FenceGateJungle::class;
|
||||
self::$list[self::FENCE_GATE_DARK_OAK] = FenceGateDarkOak::class;
|
||||
self::$list[self::FENCE_GATE_ACACIA] = FenceGateAcacia::class;
|
||||
self::$list[self::FENCE_SPRUCE] = FenceSpruce::class;
|
||||
self::$list[self::FENCE_BIRCH] = FenceBirch::class;
|
||||
self::$list[self::FENCE_DARK_OAK] = FenceDarkOak::class;
|
||||
self::$list[self::FENCE_JUNGLE] = FenceJungle::class;
|
||||
self::$list[self::FENCE_ACACIA] = FenceAcacia::class;
|
||||
|
||||
self::$list[self::PODZOL] = Podzol::class;
|
||||
self::$list[self::BEETROOT_BLOCK] = Beetroot::class;
|
||||
self::$list[self::STONECUTTER] = Stonecutter::class;
|
||||
self::$list[self::GLOWING_OBSIDIAN] = GlowingObsidian::class;
|
||||
self::$list[self::NETHER_REACTOR] = NetherReactor::class;
|
||||
|
||||
foreach(self::$list as $id => $class){
|
||||
if($class !== null){
|
||||
/** @var Block $block */
|
||||
$block = new $class();
|
||||
|
||||
for($data = 0; $data < 16; ++$data){
|
||||
self::$fullList[($id << 4) | $data] = new $class($data);
|
||||
}
|
||||
|
||||
self::$solid[$id] = $block->isSolid();
|
||||
self::$transparent[$id] = $block->isTransparent();
|
||||
self::$hardness[$id] = $block->getHardness();
|
||||
self::$light[$id] = $block->getLightLevel();
|
||||
|
||||
if($block->isSolid()){
|
||||
if($block->isTransparent()){
|
||||
if($block instanceof Liquid or $block instanceof Ice){
|
||||
self::$lightFilter[$id] = 2;
|
||||
}else{
|
||||
self::$lightFilter[$id] = 1;
|
||||
}
|
||||
}else{
|
||||
self::$lightFilter[$id] = 15;
|
||||
}
|
||||
}else{
|
||||
self::$lightFilter[$id] = 1;
|
||||
}
|
||||
}else{
|
||||
self::$lightFilter[$id] = 1;
|
||||
for($data = 0; $data < 16; ++$data){
|
||||
self::$fullList[($id << 4) | $data] = new Block($id, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,52 +780,189 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @return Block
|
||||
*/
|
||||
public static function get($id, $meta = 0, Position $pos = null){
|
||||
if(isset(self::$list[$id])){
|
||||
try{
|
||||
$block = self::$list[$id];
|
||||
$block = new $block($meta);
|
||||
}else{
|
||||
$block = new Generic($id, $meta);
|
||||
if($block !== null){
|
||||
$block = new $block($meta);
|
||||
}else{
|
||||
$block = new Block($id, $meta);
|
||||
}
|
||||
}catch(\RuntimeException $e){
|
||||
$block = new Block($id, $meta);
|
||||
}
|
||||
|
||||
if($pos instanceof Position){
|
||||
$block->position($pos);
|
||||
if($pos !== null){
|
||||
$block->x = $pos->x;
|
||||
$block->y = $pos->y;
|
||||
$block->z = $pos->z;
|
||||
$block->level = $pos->level;
|
||||
}
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
* @param string $name
|
||||
* @param int $id
|
||||
* @param int $meta
|
||||
*/
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
public function __construct($id, $meta = 0){
|
||||
$this->id = (int) $id;
|
||||
$this->meta = (int) $meta;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Block $block
|
||||
* @param Block $target
|
||||
* @param int $face
|
||||
* @param float $fx
|
||||
* @param float $fy
|
||||
* @param float $fz
|
||||
* @param Player $player = null
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
return $this->getLevel()->setBlock($this, $this, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the item can be broken with an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isBreakable(Item $item){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function onBreak(Item $item){
|
||||
return $this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a block update on the Block
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onUpdate($type){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Do actions when activated by Item. Returns if it has done anything
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Player $player
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
final public function getHardness(){
|
||||
return $this->hardness;
|
||||
public function getHardness(){
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getFrictionFactor(){
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getLightLevel(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBePlaced(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->canBeReplaced()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeReplaced(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransparent(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isFlowable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeFlowedInto(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isActivable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeActivated(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasEntityCollision(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
final public function getName(){
|
||||
return $this->name;
|
||||
public function getName(){
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
final public function getID(){
|
||||
final public function getId(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
@ -735,7 +974,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @param int $meta
|
||||
*/
|
||||
final public function setDamage($meta){
|
||||
$this->meta = $meta & 0x0F;
|
||||
$this->meta = $meta & 0x0f;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,7 +1014,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @return float
|
||||
*/
|
||||
public function getBreakTime(Item $item){
|
||||
return $this->breakTime;
|
||||
return 0.20;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -787,39 +1026,20 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @return Block
|
||||
*/
|
||||
public function getSide($side, $step = 1){
|
||||
$v = parent::getSide($side, $step);
|
||||
if($this->isValid()){
|
||||
return $this->getLevel()->getBlock($v);
|
||||
return $this->getLevel()->getBlock(Vector3::getSide($side, $step));
|
||||
}
|
||||
|
||||
return Block::get(Item::AIR, 0, $v);
|
||||
return Block::get(Item::AIR, 0, new Position($v->x, $v->y, $v->z, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
final public function __toString(){
|
||||
return "Block " . $this->name . " (" . $this->id . ":" . $this->meta . ")";
|
||||
public function __toString(){
|
||||
return "Block[" . $this->getName() . "] (" . $this->id . ":" . $this->meta . ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the item can be broken with an specific Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract function isBreakable(Item $item);
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract function onBreak(Item $item);
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
*
|
||||
@ -844,6 +1064,17 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @return AxisAlignedBB
|
||||
*/
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}else{
|
||||
return $this->boundingBox = $this->recalculateBoundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB
|
||||
*/
|
||||
protected function recalculateBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -936,41 +1167,6 @@ abstract class Block extends Position implements Metadatable{
|
||||
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Block $block
|
||||
* @param Block $target
|
||||
* @param int $face
|
||||
* @param float $fx
|
||||
* @param float $fy
|
||||
* @param float $fz
|
||||
* @param Player $player = null
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null);
|
||||
|
||||
/**
|
||||
* Do actions when activated by Item. Returns if it has done anything
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Player $player
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract function onActivate(Item $item, Player $player = null);
|
||||
|
||||
/**
|
||||
* Fires a block update on the Block
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract function onUpdate($type);
|
||||
|
||||
public function setMetadata($metadataKey, MetadataValue $metadataValue){
|
||||
if($this->getLevel() instanceof Level){
|
||||
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue);
|
||||
|
@ -23,9 +23,19 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class Bookshelf extends Solid{
|
||||
|
||||
protected $id = self::BOOKSHELF;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::BOOKSHELF, 0, "Bookshelf");
|
||||
$this->hardness = 7.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Bookshelf";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 7.5;
|
||||
}
|
||||
|
||||
}
|
@ -23,8 +23,15 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class BrickStairs extends Stair{
|
||||
|
||||
protected $id = self::BRICK_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::BRICK_STAIRS, $meta, "Brick Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Brick Stairs";
|
||||
}
|
||||
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Bricks extends Solid{
|
||||
|
||||
protected $id = self::BRICKS_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::BRICKS_BLOCK, 0, "Bricks");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Bricks";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -26,16 +26,25 @@ use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class BrownMushroom extends Flowable{
|
||||
public function __construct(){
|
||||
parent::__construct(self::BROWN_MUSHROOM, 0, "Brown Mushroom");
|
||||
$this->hardness = 0;
|
||||
|
||||
protected $id = self::BROWN_MUSHROOM;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Brown Mushroom";
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent() === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
@ -46,7 +55,7 @@ class BrownMushroom extends Flowable{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === false){
|
||||
if($down->isTransparent() === false){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
|
@ -32,10 +32,27 @@ use pocketmine\tile\Furnace;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
class BurningFurnace extends Solid{
|
||||
|
||||
protected $id = self::BURNING_FURNACE;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::BURNING_FURNACE, $meta, "Burning Furnace");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 17.5;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Burning Furnace";
|
||||
}
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 17.5;
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 13;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
@ -55,13 +72,13 @@ class BurningFurnace extends Solid{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item){
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -81,7 +98,7 @@ class BurningFurnace extends Solid{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$furnace = new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$furnace = Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
}
|
||||
|
||||
if(($player->getGamemode() & 0x01) === 0x01){
|
||||
@ -116,15 +133,6 @@ class BurningFurnace extends Solid{
|
||||
if($item->isPickaxe() >= 1){
|
||||
$drops[] = [Item::FURNACE, 0, 1];
|
||||
}
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
if($t instanceof Furnace){
|
||||
for($s = 0; $s < $t->getInventory()->getSize(); ++$s){
|
||||
$slot = $t->getInventory()->getItem($s);
|
||||
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
|
||||
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
|
@ -21,23 +21,39 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Cactus extends Transparent{
|
||||
|
||||
protected $id = self::CACTUS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CACTUS, $meta, "Cactus");
|
||||
$this->isFullBlock = false;
|
||||
$this->hardness = 2;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getHardness(){
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function hasEntityCollision(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Cactus";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
@ -49,40 +65,33 @@ class Cactus extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
|
||||
return;
|
||||
if($down->getId() !== self::SAND and $down->getId() !== self::CACTUS){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if(!$b->isFlowable){
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
|
||||
return;
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if($this->getSide(0)->getID() !== self::CACTUS){
|
||||
if($this->getSide(0)->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));
|
||||
if($b->getID() === self::AIR){
|
||||
$this->getLevel()->setBlock($b, new Cactus(), true);
|
||||
break;
|
||||
if($b->getId() === self::AIR){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Cactus()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
@ -91,8 +100,6 @@ class Cactus extends Transparent{
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,12 +108,12 @@ class Cactus extends Transparent{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::SAND or $down->getID() === self::CACTUS){
|
||||
if($down->getId() === self::SAND or $down->getId() === self::CACTUS){
|
||||
$block0 = $this->getSide(2);
|
||||
$block1 = $this->getSide(3);
|
||||
$block2 = $this->getSide(4);
|
||||
$block3 = $this->getSide(5);
|
||||
if($block0->isTransparent === true and $block1->isTransparent === true and $block2->isTransparent === true and $block3->isTransparent === true){
|
||||
if($block0->isTransparent() === true and $block1->isTransparent() === true and $block2->isTransparent() === true and $block3->isTransparent() === true){
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
|
||||
return true;
|
||||
|
@ -21,21 +21,35 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Cake extends Transparent{
|
||||
|
||||
protected $id = self::CAKE_BLOCK;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CAKE_BLOCK, 0, "Cake Block");
|
||||
$this->isFullBlock = false;
|
||||
$this->isActivable = true;
|
||||
$this->meta = $meta & 0x07;
|
||||
$this->hardness = 2.5;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2.5;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Cake Block";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
$f = (1 + $this->getDamage() * 2) / 16;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
@ -50,7 +64,7 @@ class Cake extends Transparent{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() !== self::AIR){
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
@ -61,7 +75,7 @@ class Cake extends Transparent{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
|
||||
if($this->getSide(0)->getId() === self::AIR){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
@ -78,7 +92,10 @@ class Cake extends Transparent{
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($player instanceof Player and $player->getHealth() < 20){
|
||||
++$this->meta;
|
||||
$player->heal(3, "cake");
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($player, 3, EntityRegainHealthEvent::CAUSE_EATING));
|
||||
if(!$ev->isCancelled()){
|
||||
$player->heal($ev->getAmount(), $ev);
|
||||
}
|
||||
if($this->meta >= 0x06){
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
}else{
|
||||
|
@ -27,9 +27,19 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Carpet extends Flowable{
|
||||
|
||||
protected $id = self::CARPET;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CARPET, $meta, "Carpet");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
0 => "White Carpet",
|
||||
1 => "Orange Carpet",
|
||||
2 => "Magenta Carpet",
|
||||
@ -47,13 +57,11 @@ class Carpet extends Flowable{
|
||||
14 => "Red Carpet",
|
||||
15 => "Black Carpet",
|
||||
];
|
||||
$this->name = $names[$this->meta];
|
||||
$this->hardness = 0;
|
||||
$this->isFullBlock = false;
|
||||
$this->isSolid = true;
|
||||
return $names[$this->meta & 0x0f];
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
@ -66,7 +74,7 @@ class Carpet extends Flowable{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() !== self::AIR){
|
||||
if($down->getId() !== self::AIR){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
@ -77,9 +85,8 @@ class Carpet extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === self::AIR){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
if($this->getSide(0)->getId() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -22,67 +22,17 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Carrot extends Flowable{
|
||||
class Carrot extends Crops{
|
||||
|
||||
protected $id = self::CARROT_BLOCK;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CARROT_BLOCK, $meta, "Carrot Block");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 0;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$this->meta = 0x07;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$item->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get(CARROT, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}else{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
public function getName(){
|
||||
return "Carrot Block";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -34,21 +34,31 @@ use pocketmine\tile\Tile;
|
||||
|
||||
class Chest extends Transparent{
|
||||
|
||||
const SLOTS = 27;
|
||||
protected $id = self::CHEST;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CHEST, $meta, "Chest");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 15;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Chest";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
$this->x + 0.9375,
|
||||
$this->y + 0.875,
|
||||
$this->y + 0.9475,
|
||||
$this->z + 0.9375
|
||||
);
|
||||
}
|
||||
@ -61,7 +71,7 @@ class Chest extends Transparent{
|
||||
3 => 3,
|
||||
];
|
||||
|
||||
$chest = false;
|
||||
$chest = null;
|
||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
@ -89,9 +99,9 @@ class Chest extends Transparent{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$tile = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
|
||||
if($chest instanceof TileChest){
|
||||
if($chest instanceof TileChest and $tile instanceof TileChest){
|
||||
$chest->pairWith($tile);
|
||||
$tile->pairWith($chest);
|
||||
}
|
||||
@ -104,7 +114,7 @@ class Chest extends Transparent{
|
||||
if($t instanceof TileChest){
|
||||
$t->unpair();
|
||||
}
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -112,7 +122,7 @@ class Chest extends Transparent{
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($player instanceof Player){
|
||||
$top = $this->getSide(1);
|
||||
if($top->isTransparent !== true){
|
||||
if($top->isTransparent() !== true){
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -129,11 +139,11 @@ class Chest extends Transparent{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$chest = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$chest = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
}
|
||||
|
||||
|
||||
if(($player->gamemode & 0x01) === 0x01){
|
||||
if($player->isCreative()){
|
||||
return true;
|
||||
}
|
||||
$player->addWindow($chest->getInventory());
|
||||
@ -143,19 +153,8 @@ class Chest extends Transparent{
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
$drops = [
|
||||
return [
|
||||
[$this->id, 0, 1],
|
||||
];
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
if($t instanceof TileChest){
|
||||
for($s = 0; $s < $t->getRealInventory()->getSize(); ++$s){
|
||||
$slot = $t->getRealInventory()->getItem($s);
|
||||
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
|
||||
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Clay extends Solid{
|
||||
|
||||
protected $id = self::CLAY_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::CLAY_BLOCK, 0, "Clay Block");
|
||||
$this->hardness = 3;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Clay Block";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Coal extends Solid{
|
||||
|
||||
protected $id = self::COAL_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::COAL_BLOCK, 0, "Coal Block");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Coal Block";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class CoalOre extends Solid{
|
||||
|
||||
protected $id = self::COAL_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::COAL_ORE, 0, "Coal Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Coal Ore";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Cobblestone extends Solid{
|
||||
|
||||
protected $id = self::COBBLESTONE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::COBBLESTONE, 0, "Cobblestone");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Cobblestone";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -23,8 +23,15 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class CobblestoneStairs extends Stair{
|
||||
|
||||
protected $id = self::COBBLESTONE_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::COBBLESTONE_STAIRS, $meta, "Cobblestone Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Cobblestone Stairs";
|
||||
}
|
||||
|
||||
}
|
@ -21,15 +21,27 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Cobweb extends Flowable{
|
||||
|
||||
protected $id = self::COBWEB;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::COBWEB, 0, "Cobweb");
|
||||
$this->isSolid = true;
|
||||
$this->isFullBlock = false;
|
||||
$this->hardness = 25;
|
||||
|
||||
}
|
||||
|
||||
public function hasEntityCollision(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Cobweb";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 25;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
@ -37,6 +49,7 @@ class Cobweb extends Flowable{
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
//TODO: correct drops
|
||||
return [];
|
||||
}
|
||||
}
|
96
src/pocketmine/block/Crops.php
Normal file
96
src/pocketmine/block/Crops.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
abstract class Crops extends Flowable{
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getId() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$block = clone $this;
|
||||
$block->meta += mt_rand(2, 5);
|
||||
if($block->meta > 7){
|
||||
$block->meta = 7;
|
||||
}
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
||||
}
|
||||
|
||||
$item->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent() === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
$block = clone $this;
|
||||
++$block->meta;
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
|
||||
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
|
||||
}else{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -26,19 +26,21 @@ use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Dandelion extends Flowable{
|
||||
|
||||
protected $id = self::DANDELION;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::DANDELION, 0, "Dandelion");
|
||||
$this->hardness = 0;
|
||||
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
public function getName(){
|
||||
return "Dandelion";
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === 2 or $down->getID() === 3 or $down->getID() === 60){
|
||||
if($down->getId() === 2 or $down->getId() === 3 or $down->getId() === 60){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
@ -49,10 +51,8 @@ class Dandelion extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent() === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -24,8 +24,15 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class DarkOakWoodStairs extends Stair{
|
||||
|
||||
protected $id = self::DARK_OAK_WOOD_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::DARK_OAK_WOOD_STAIRS, $meta, "Dark Oak Wood Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Dark Oak Wood Stairs";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -24,21 +24,22 @@ namespace pocketmine\block;
|
||||
use pocketmine\level\Level;
|
||||
|
||||
class DeadBush extends Flowable{
|
||||
public function __construct(){
|
||||
parent::__construct(self::DEAD_BUSH, 0, "Dead Bush");
|
||||
//$this->isReplaceable = true;
|
||||
$this->hardness = 0;
|
||||
|
||||
protected $id = self::DEAD_BUSH;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
public function getName(){
|
||||
return "Dead Bush";
|
||||
}
|
||||
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent() === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Diamond extends Solid{
|
||||
|
||||
protected $id = self::DIAMOND_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::DIAMOND_BLOCK, 0, "Diamond Block");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Diamond Block";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class DiamondOre extends Solid{
|
||||
|
||||
protected $id = self::DIAMOND_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::DIAMOND_ORE, 0, "Diamond Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Diamond Ore";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -26,16 +26,24 @@ use pocketmine\Player;
|
||||
|
||||
class Dirt extends Solid{
|
||||
|
||||
public $isActivable = true;
|
||||
protected $hardness = 2.5;
|
||||
protected $id = self::DIRT;
|
||||
protected $meta = 0;
|
||||
protected $name = "Dirt";
|
||||
|
||||
public function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2.5;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Dirt";
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->isHoe()){
|
||||
$item->useOn($this);
|
||||
|
@ -30,9 +30,13 @@ use pocketmine\Server;
|
||||
|
||||
|
||||
abstract class Door extends Transparent{
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
$this->isSolid = false;
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getFullDamage(){
|
||||
@ -52,7 +56,8 @@ abstract class Door extends Transparent{
|
||||
return $first & 0x07 | ($flag ? 8 : 0) | ($flag1 ? 0x10 : 0);
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
$f = 0.1875;
|
||||
$damage = $this->getFullDamage();
|
||||
|
||||
@ -72,7 +77,7 @@ abstract class Door extends Transparent{
|
||||
if($j === 0){
|
||||
if($flag){
|
||||
if(!$flag1){
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -81,7 +86,7 @@ abstract class Door extends Transparent{
|
||||
$this->z + $f
|
||||
);
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
@ -91,7 +96,7 @@ abstract class Door extends Transparent{
|
||||
);
|
||||
}
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -103,7 +108,7 @@ abstract class Door extends Transparent{
|
||||
}elseif($j === 1){
|
||||
if($flag){
|
||||
if(!$flag1){
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -112,7 +117,7 @@ abstract class Door extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -122,7 +127,7 @@ abstract class Door extends Transparent{
|
||||
);
|
||||
}
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -134,7 +139,7 @@ abstract class Door extends Transparent{
|
||||
}elseif($j === 2){
|
||||
if($flag){
|
||||
if(!$flag1){
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
@ -143,7 +148,7 @@ abstract class Door extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -153,7 +158,7 @@ abstract class Door extends Transparent{
|
||||
);
|
||||
}
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -165,7 +170,7 @@ abstract class Door extends Transparent{
|
||||
}elseif($j === 3){
|
||||
if($flag){
|
||||
if(!$flag1){
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -174,7 +179,7 @@ abstract class Door extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -184,7 +189,7 @@ abstract class Door extends Transparent{
|
||||
);
|
||||
}
|
||||
}else{
|
||||
$bb = new AxisAlignedBB(
|
||||
$bb->setBounds(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
@ -200,7 +205,7 @@ abstract class Door extends Transparent{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
|
||||
if($this->getSide(0)->getId() === self::AIR){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
if($this->getSide(1) instanceof Door){
|
||||
$this->getLevel()->setBlock($this->getSide(1), new Air(), false);
|
||||
@ -217,7 +222,7 @@ abstract class Door extends Transparent{
|
||||
if($face === 1){
|
||||
$blockUp = $this->getSide(1);
|
||||
$blockDown = $this->getSide(0);
|
||||
if($blockUp->isReplaceable === false or $blockDown->isTransparent === true){
|
||||
if($blockUp->canBeReplaced() === false or $blockDown->isTransparent() === true){
|
||||
return false;
|
||||
}
|
||||
$direction = $player instanceof Player ? $player->getDirection() : 0;
|
||||
@ -230,7 +235,7 @@ abstract class Door extends Transparent{
|
||||
$next = $this->getSide($face[(($direction + 2) % 4)]);
|
||||
$next2 = $this->getSide($face[$direction]);
|
||||
$metaUp = 0x08;
|
||||
if($next->getID() === $this->id or ($next2->isTransparent === false and $next->isTransparent === true)){ //Door hinge
|
||||
if($next->getId() === $this->id or ($next2->isTransparent() === false and $next->isTransparent() === true)){ //Door hinge
|
||||
$metaUp |= 0x01;
|
||||
}
|
||||
|
||||
@ -246,12 +251,12 @@ abstract class Door extends Transparent{
|
||||
public function onBreak(Item $item){
|
||||
if(($this->meta & 0x08) === 0x08){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === $this->id){
|
||||
if($down->getId() === $this->id){
|
||||
$this->getLevel()->setBlock($down, new Air(), true);
|
||||
}
|
||||
}else{
|
||||
$up = $this->getSide(1);
|
||||
if($up->getID() === $this->id){
|
||||
if($up->getId() === $this->id){
|
||||
$this->getLevel()->setBlock($up, new Air(), true);
|
||||
}
|
||||
}
|
||||
@ -263,14 +268,14 @@ abstract class Door extends Transparent{
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if(($this->meta & 0x08) === 0x08){ //Top
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === $this->id){
|
||||
if($down->getId() === $this->id){
|
||||
$meta = $down->getDamage() ^ 0x04;
|
||||
$this->getLevel()->setBlock($down, Block::get($this->id, $meta), true);
|
||||
$players = $this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4);
|
||||
if($player instanceof Player){
|
||||
unset($players[$player->getID()]);
|
||||
unset($players[$player->getId()]);
|
||||
}
|
||||
$pk = new LevelEventPacket;
|
||||
$pk = new LevelEventPacket();
|
||||
$pk->x = $this->x;
|
||||
$pk->y = $this->y;
|
||||
$pk->z = $this->z;
|
||||
@ -287,9 +292,9 @@ abstract class Door extends Transparent{
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$players = $this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4);
|
||||
if($player instanceof Player){
|
||||
unset($players[$player->getID()]);
|
||||
unset($players[$player->getId()]);
|
||||
}
|
||||
$pk = new LevelEventPacket;
|
||||
$pk = new LevelEventPacket();
|
||||
$pk->x = $this->x;
|
||||
$pk->y = $this->y;
|
||||
$pk->z = $this->z;
|
||||
|
70
src/pocketmine/block/DoublePlant.php
Normal file
70
src/pocketmine/block/DoublePlant.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
|
||||
class DoublePlant extends Flowable{
|
||||
|
||||
protected $id = self::DOUBLE_PLANT;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function canBeReplaced(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
0 => "Sunflower",
|
||||
1 => "Lilac",
|
||||
2 => "Double Tallgrass",
|
||||
3 => "Large Fern",
|
||||
4 => "Rose Bush",
|
||||
5 => "Peony"
|
||||
];
|
||||
return $names[$this->meta & 0x07];
|
||||
}
|
||||
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent() === true){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
//TODO
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class DoubleSlab extends Solid{
|
||||
|
||||
protected $id = self::DOUBLE_SLAB;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::DOUBLE_SLAB, $meta, "Double Slab");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
0 => "Stone",
|
||||
1 => "Sandstone",
|
||||
2 => "Wooden",
|
||||
@ -36,8 +46,7 @@ class DoubleSlab extends Solid{
|
||||
6 => "Quartz",
|
||||
7 => "",
|
||||
];
|
||||
$this->name = "Double " . $names[$this->meta & 0x07] . " Slab";
|
||||
$this->hardness = 30;
|
||||
return "Double " . $names[$this->meta & 0x07] . " Slab";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,18 +24,29 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class DoubleWoodSlab extends Solid{
|
||||
|
||||
protected $id = self::DOUBLE_WOOD_SLAB;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::DOUBLE_WOOD_SLAB, $meta, "Double Wooden Slab");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
0 => "Oak",
|
||||
1 => "Spruce",
|
||||
2 => "Birch",
|
||||
3 => "Jungle",
|
||||
4 => "Acacia",
|
||||
5 => "Dark Oak",
|
||||
6 => "",
|
||||
7 => ""
|
||||
];
|
||||
$this->name = "Double " . $names[$this->meta & 0x07] . " Wooden Slab";
|
||||
$this->hardness = 15;
|
||||
return "Double " . $names[$this->meta & 0x07] . " Wooden Slab";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Emerald extends Solid{
|
||||
|
||||
protected $id = self::EMERALD_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::EMERALD_BLOCK, 0, "Emerald Block");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Emerald Block";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class EmeraldOre extends Solid{
|
||||
|
||||
protected $id = self::EMERALD_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::EMERALD_ORE, 0, "Emerald Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Emerald Ore";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -21,15 +21,35 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
class EndPortal extends Solid{
|
||||
class EndPortalFrame extends Solid{
|
||||
|
||||
protected $id = self::END_PORTAL_FRAME;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::END_PORTAL, $meta, "End Portal");
|
||||
$this->hardness = 18000000;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getLightLevel(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "End Portal Frame";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 18000000;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class EndStone extends Solid{
|
||||
|
||||
protected $id = self::END_STONE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::END_STONE, 0, "End Stone");
|
||||
$this->hardness = 45;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "End Stone";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 45;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -21,19 +21,18 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\entity\FallingBlock;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\Double;
|
||||
use pocketmine\nbt\tag\Float;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\Double;
|
||||
use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\Float;
|
||||
use pocketmine\nbt\tag\Int;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Fallable extends Solid{
|
||||
|
||||
public $hasPhysics = true;
|
||||
abstract class Fallable extends Solid{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, true);
|
||||
@ -42,16 +41,15 @@ class Fallable extends Solid{
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::AIR or ($down instanceof Liquid)){
|
||||
$fall = new FallingBlock($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||
if($down->getId() === self::AIR or ($down instanceof Liquid)){
|
||||
$fall = Entity::createEntity("FallingSand", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||
"Pos" => new Enum("Pos", [
|
||||
new Double("", $this->x + 0.5),
|
||||
new Double("", $this->y + 0.5),
|
||||
new Double("", $this->y),
|
||||
new Double("", $this->z + 0.5)
|
||||
]),
|
||||
//TODO: add random motion with physics
|
||||
"Motion" => new Enum("Motion", [
|
||||
new Double("", 0),
|
||||
new Double("", 0),
|
||||
@ -61,13 +59,12 @@ class Fallable extends Solid{
|
||||
new Float("", 0),
|
||||
new Float("", 0)
|
||||
]),
|
||||
"Tile" => new Byte("Tile", $this->getID())
|
||||
"TileID" => new Int("TileID", $this->getId()),
|
||||
"Data" => new Byte("Data", $this->getDamage()),
|
||||
]));
|
||||
|
||||
$fall->spawnToAll();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,12 +25,22 @@ use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
class Farmland extends Solid{
|
||||
|
||||
protected $id = self::FARMLAND;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::FARMLAND, $meta, "Farmland");
|
||||
$this->hardness = 3;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getName(){
|
||||
return "Farmland";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
|
@ -21,24 +21,32 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class Fence extends Transparent{
|
||||
|
||||
protected $id = self::FENCE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::FENCE, 0, "Fence");
|
||||
$this->isFullBlock = false;
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Oak Fence";
|
||||
}
|
||||
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
$flag = $this->canConnect($this->getSide(2));
|
||||
$flag1 = $this->canConnect($this->getSide(3));
|
||||
$flag2 = $this->canConnect($this->getSide(4));
|
||||
$flag3 = $this->canConnect($this->getSide(5));
|
||||
|
||||
$f = $flag2 ? 0 : 0.375;
|
||||
$f = $flag2 ? 0 : 0.375;
|
||||
$f1 = $flag3 ? 1 : 0.625;
|
||||
$f2 = $flag ? 0 : 0.375;
|
||||
$f3 = $flag1 ? 1 : 0.625;
|
||||
@ -48,13 +56,13 @@ class Fence extends Transparent{
|
||||
$this->y,
|
||||
$this->z + $f2,
|
||||
$this->x + $f1,
|
||||
$this->y + 1, //TODO: check this, add extra bounding box
|
||||
$this->y + 1.5,
|
||||
$this->z + $f3
|
||||
);
|
||||
}
|
||||
|
||||
public function canConnect(Block $block){
|
||||
return ($block->getID() !== self::FENCE and $block->getID() !== self::FENCE_GATE) ? $block->isSolid : true;
|
||||
return (!($block instanceof Fence) and !($block instanceof FenceGate)) ? $block->isSolid() : true;
|
||||
}
|
||||
|
||||
}
|
31
src/pocketmine/block/FenceAcacia.php
Normal file
31
src/pocketmine/block/FenceAcacia.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class FenceAcacia extends Fence{
|
||||
|
||||
protected $id = self::FENCE_ACACIA;
|
||||
|
||||
public function getName(){
|
||||
return "Acacia Fence";
|
||||
}
|
||||
}
|
31
src/pocketmine/block/FenceBirch.php
Normal file
31
src/pocketmine/block/FenceBirch.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class FenceBirch extends Fence{
|
||||
|
||||
protected $id = self::FENCE_BIRCH;
|
||||
|
||||
public function getName(){
|
||||
return "Birch Fence";
|
||||
}
|
||||
}
|
31
src/pocketmine/block/FenceDarkOak.php
Normal file
31
src/pocketmine/block/FenceDarkOak.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class FenceDarkOak extends Fence{
|
||||
|
||||
protected $id = self::FENCE_DARK_OAK;
|
||||
|
||||
public function getName(){
|
||||
return "Dark Oak Fence";
|
||||
}
|
||||
}
|
@ -26,19 +26,28 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
|
||||
class FenceGate extends Transparent{
|
||||
|
||||
protected $id = self::FENCE_GATE;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::FENCE_GATE, $meta, "Fence Gate");
|
||||
$this->isActivable = true;
|
||||
if(($this->meta & 0x04) === 0x04){
|
||||
$this->isFullBlock = true;
|
||||
}else{
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
$this->hardness = 15;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Oak Fence Gate";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function getBoundingBox(){
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return null;
|
||||
}
|
||||
@ -50,7 +59,7 @@ class FenceGate extends Transparent{
|
||||
$this->y,
|
||||
$this->z + 0.375,
|
||||
$this->x + 1,
|
||||
$this->y + 1,
|
||||
$this->y + 1.5,
|
||||
$this->z + 0.625
|
||||
);
|
||||
}else{
|
||||
@ -59,7 +68,7 @@ class FenceGate extends Transparent{
|
||||
$this->y,
|
||||
$this->z,
|
||||
$this->x + 0.625,
|
||||
$this->y + 1,
|
||||
$this->y + 1.5,
|
||||
$this->z + 1
|
||||
);
|
||||
}
|
||||
@ -92,11 +101,6 @@ class FenceGate extends Transparent{
|
||||
3 => 2,
|
||||
];
|
||||
$this->meta = ($faces[$player instanceof Player ? $player->getDirection() : 0] & 0x03) | ((~$this->meta) & 0x04);
|
||||
if(($this->meta & 0x04) === 0x04){
|
||||
$this->isFullBlock = true;
|
||||
}else{
|
||||
$this->isFullBlock = false;
|
||||
}
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
|
||||
return true;
|
||||
|
@ -21,29 +21,12 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Generic extends Block{
|
||||
class FenceGateAcacia extends FenceGate{
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
return $this->getLevel()->setBlock($this, $this, true, true);
|
||||
}
|
||||
protected $id = self::FENCE_GATE_ACACIA;
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
return $this->breakable;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item){
|
||||
return $this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
return $this->isActivable;
|
||||
public function getName(){
|
||||
return "Acacia Fence Gate";
|
||||
}
|
||||
}
|
32
src/pocketmine/block/FenceGateBirch.php
Normal file
32
src/pocketmine/block/FenceGateBirch.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class FenceGateBirch extends FenceGate{
|
||||
|
||||
protected $id = self::FENCE_GATE_BIRCH;
|
||||
|
||||
public function getName(){
|
||||
return "Birch Fence Gate";
|
||||
}
|
||||
}
|
32
src/pocketmine/block/FenceGateDarkOak.php
Normal file
32
src/pocketmine/block/FenceGateDarkOak.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class FenceGateDarkOak extends FenceGate{
|
||||
|
||||
protected $id = self::FENCE_GATE_DARK_OAK;
|
||||
|
||||
public function getName(){
|
||||
return "Dark Oak Fence Gate";
|
||||
}
|
||||
}
|
32
src/pocketmine/block/FenceGateJungle.php
Normal file
32
src/pocketmine/block/FenceGateJungle.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class FenceGateJungle extends FenceGate{
|
||||
|
||||
protected $id = self::FENCE_GATE_JUNGLE;
|
||||
|
||||
public function getName(){
|
||||
return "Jungle Fence Gate";
|
||||
}
|
||||
}
|
32
src/pocketmine/block/FenceGateSpruce.php
Normal file
32
src/pocketmine/block/FenceGateSpruce.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class FenceGateSpruce extends FenceGate{
|
||||
|
||||
protected $id = self::FENCE_GATE_SPRUCE;
|
||||
|
||||
public function getName(){
|
||||
return "Spruce Fence Gate";
|
||||
}
|
||||
}
|
31
src/pocketmine/block/FenceJungle.php
Normal file
31
src/pocketmine/block/FenceJungle.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class FenceJungle extends Fence{
|
||||
|
||||
protected $id = self::FENCE_JUNGLE;
|
||||
|
||||
public function getName(){
|
||||
return "Jungle Fence";
|
||||
}
|
||||
}
|
31
src/pocketmine/block/FenceSpruce.php
Normal file
31
src/pocketmine/block/FenceSpruce.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
class FenceSpruce extends Fence{
|
||||
|
||||
protected $id = self::FENCE_SPRUCE;
|
||||
|
||||
public function getName(){
|
||||
return "Spruce Fence";
|
||||
}
|
||||
}
|
@ -21,31 +21,50 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Fire extends Flowable{
|
||||
|
||||
protected $id = self::FIRE;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::FIRE, $meta, "Fire");
|
||||
$this->isReplaceable = true;
|
||||
$this->breakable = false;
|
||||
$this->isFullBlock = true;
|
||||
$this->hardness = 0;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
public function hasEntityCollision(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Fire Block";
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->setOnFire(8);
|
||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
$entity->setOnFire($ev->getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +76,7 @@ class Fire extends Flowable{
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
for($s = 0; $s <= 5; ++$s){
|
||||
$side = $this->getSide($s);
|
||||
if($side->getID() !== self::AIR and !($side instanceof Liquid)){
|
||||
if($side->getId() !== self::AIR and !($side instanceof Liquid)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -65,7 +84,7 @@ class Fire extends Flowable{
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if($this->getSide(0)->getID() !== self::NETHERRACK){
|
||||
if($this->getSide(0)->getId() !== self::NETHERRACK){
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
|
@ -22,10 +22,21 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class Flowable extends Transparent{
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public $isFlowable = true;
|
||||
public $isFullBlock = false;
|
||||
public $isSolid = false;
|
||||
public function canBeFlowedInto(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -23,10 +23,10 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class Furnace extends BurningFurnace{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct($meta);
|
||||
$this->id = self::FURNACE;
|
||||
$this->name = "Furnace";
|
||||
$this->isActivable = true;
|
||||
|
||||
protected $id = self::FURNACE;
|
||||
|
||||
public function getName(){
|
||||
return "Furnace";
|
||||
}
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Glass extends Transparent{
|
||||
|
||||
protected $id = self::GLASS;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GLASS, 0, "Glass");
|
||||
$this->hardness = 1.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Glass";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -23,8 +23,19 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class GlassPane extends Thin{
|
||||
|
||||
protected $id = self::GLASS_PANE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GLASS_PANE, 0, "Glass Pane");
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Glass Pane";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
}
|
@ -23,8 +23,19 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class GlowingObsidian extends Solid{
|
||||
|
||||
protected $id = self::GLOWING_OBSIDIAN;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::GLOWING_OBSIDIAN, $meta, "Glowing Obsidian");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Glowing Obsidian";
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 12;
|
||||
}
|
||||
|
||||
}
|
@ -25,9 +25,23 @@ use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
|
||||
class GlowingRedstoneOre extends Solid{
|
||||
|
||||
protected $id = self::GLOWING_REDSTONE_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GLOWING_REDSTONE_ORE, 0, "Glowing Redstone Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Glowing Redstone Ore";
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 9;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
|
@ -24,9 +24,23 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Glowstone extends Transparent{
|
||||
|
||||
protected $id = self::GLOWSTONE_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GLOWSTONE_BLOCK, 0, "Glowstone");
|
||||
$this->hardness = 1.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Glowstone";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 1.5;
|
||||
}
|
||||
|
||||
public function getLightLevel(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Gold extends Solid{
|
||||
|
||||
protected $id = self::GOLD_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GOLD_BLOCK, 0, "Gold Block");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Gold Block";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class GoldOre extends Solid{
|
||||
|
||||
protected $id = self::GOLD_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GOLD_ORE, 0, "Gold Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Gold Ore";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -21,25 +21,35 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Random;
|
||||
|
||||
class Grass extends Solid{
|
||||
|
||||
public $isActivable = true;
|
||||
protected $hardness = 3;
|
||||
protected $id = self::GRASS;
|
||||
protected $meta = 0;
|
||||
protected $name = "Grass";
|
||||
|
||||
public function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Grass";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [
|
||||
[Item::DIRT, 0, 1],
|
||||
@ -52,18 +62,20 @@ class Grass 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()->getBlockIdAt($x, $y, $z);
|
||||
if($block === Block::DIRT){
|
||||
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
|
||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||
if($block->getId() === Block::DIRT){
|
||||
if($block->getSide(1) instanceof Transparent){
|
||||
$this->getLevel()->setBlock($block, new Grass());
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, new Grass()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($block, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){
|
||||
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
|
||||
$item->count--;
|
||||
TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2);
|
||||
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Gravel extends Fallable{
|
||||
|
||||
protected $id = self::GRAVEL;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::GRAVEL, 0, "Gravel");
|
||||
$this->hardness = 3;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Gravel";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class HardenedClay extends Solid{
|
||||
|
||||
protected $id = self::HARDENED_CLAY;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::HARDENED_CLAY, 0, "Hardened Clay");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Hardened Clay";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -25,9 +25,19 @@ use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
|
||||
class HayBale extends Solid{
|
||||
|
||||
protected $id = self::HAY_BALE;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::HAY_BALE, $meta, "Hay Bale");
|
||||
$this->hardness = 10;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Hay Bale";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 10;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Ice extends Transparent{
|
||||
|
||||
protected $id = self::ICE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::ICE, 0, "Ice");
|
||||
$this->hardness = 2.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Ice";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2.5;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Iron extends Solid{
|
||||
|
||||
protected $id = self::IRON_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::IRON_BLOCK, 0, "Iron Block");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Iron Block";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -23,8 +23,15 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class IronBars extends Thin{
|
||||
|
||||
protected $id = self::IRON_BARS;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::IRON_BARS, 0, "Iron Bars");
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Iron Bars";
|
||||
}
|
||||
|
||||
}
|
@ -24,10 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class IronDoor extends Door{
|
||||
|
||||
protected $id = self::IRON_DOOR_BLOCK;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::IRON_DOOR_BLOCK, $meta, "Iron Door Block");
|
||||
//$this->isActivable = true;
|
||||
$this->hardness = 25;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Iron Door Block";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 25;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class IronOre extends Solid{
|
||||
|
||||
protected $id = self::IRON_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::IRON_ORE, 0, "Iron Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Iron Ore";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,8 +24,15 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class JungleWoodStairs extends Stair{
|
||||
|
||||
protected $id = self::JUNGLE_WOOD_STAIRS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::JUNGLE_WOOD_STAIRS, $meta, "Jungle Wood Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Jungle Wood Stairs";
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -21,25 +21,43 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class Ladder extends Transparent{
|
||||
|
||||
protected $id = self::LADDER;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::LADDER, $meta, "Ladder");
|
||||
$this->isSolid = false;
|
||||
$this->isFullBlock = false;
|
||||
$this->hardness = 2;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Ladder";
|
||||
}
|
||||
|
||||
public function hasEntityCollision(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->fallDistance = 0;
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
protected function recalculateBoundingBox(){
|
||||
|
||||
$f = 0.125;
|
||||
|
||||
if($this->meta === 2){
|
||||
@ -85,7 +103,7 @@ class Ladder extends Transparent{
|
||||
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
if($target->isTransparent === false){
|
||||
if($target->isTransparent() === false){
|
||||
$faces = [
|
||||
2 => 2,
|
||||
3 => 3,
|
||||
@ -105,7 +123,7 @@ class Ladder extends Transparent{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
/*if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
|
||||
/*if($this->getSide(0)->getId() === self::AIR){ //Replace with common break method
|
||||
Server::getInstance()->api->entity->drop($this, Item::get(LADDER, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Lapis extends Solid{
|
||||
|
||||
protected $id = self::LAPIS_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::LAPIS_BLOCK, 0, "Lapis Block");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Lapis Block";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class LapisOre extends Solid{
|
||||
|
||||
protected $id = self::LAPIS_ORE;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::LAPIS_ORE, 0, "Lapis Ore");
|
||||
$this->hardness = 15;
|
||||
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Lapis Ore";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -21,150 +21,55 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
|
||||
class Lava extends Liquid{
|
||||
|
||||
protected $id = self::LAVA;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::LAVA, $meta, "Lava");
|
||||
$this->hardness = 0;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
public function getLightLevel(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Lava";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->setOnFire(15);
|
||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
$entity->fallDistance *= 0.5;
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 15);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
$entity->setOnFire($ev->getDuration());
|
||||
}
|
||||
|
||||
if($entity instanceof Player){
|
||||
$entity->onGround = true;
|
||||
}
|
||||
$entity->attack(4, EntityDamageEvent::CAUSE_LAVA);
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevel()->scheduleUpdate(clone $this, 40);
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getSourceCount(){
|
||||
$count = 0;
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
if($this->getSide($side) instanceof Lava){
|
||||
$b = $this->getSide($side);
|
||||
$level = $b->meta & 0x07;
|
||||
if($level == 0x00){
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function checkWater(){
|
||||
for($side = 1; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Water){
|
||||
$level = $this->meta & 0x07;
|
||||
if($level == 0x00){
|
||||
$this->getLevel()->setBlock($this, new Obsidian(), false, false, true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Cobblestone(), false, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFrom(){
|
||||
for($side = 0; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
$tlevel = $b->meta & 0x07;
|
||||
$level = $this->meta & 0x07;
|
||||
if(($tlevel + 2) == $level || ($side == 0x01 && $level == 0x01) || ($tlevel == 6 && $level == 7)){
|
||||
return $b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
return false;
|
||||
$newId = $this->id;
|
||||
$level = $this->meta & 0x07;
|
||||
if($type !== Level::BLOCK_UPDATE_NORMAL){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->checkWater()){
|
||||
return;
|
||||
}
|
||||
|
||||
$falling = $this->meta >> 3;
|
||||
$down = $this->getSide(0);
|
||||
|
||||
$from = $this->getFrom();
|
||||
if($from !== null || $level == 0x00){
|
||||
if($level !== 0x07){
|
||||
if($down instanceof Air || $down instanceof Lava){
|
||||
$this->getLevel()->setBlock($down, new Lava(0x01), false, false, true);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(new Position($down, 0, 0, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
|
||||
}elseif($b->isFlowable === true){
|
||||
$this->getLevel()->setBlock($b, new Lava(min($level + 2, 7)), false, false, true);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//Extend Remove for Left Lavas
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$sb = $this->getSide($side);
|
||||
if($sb instanceof Lava){
|
||||
$tlevel = $sb->meta & 0x07;
|
||||
if($tlevel != 0x00){
|
||||
for($s = 0; $s <= 5; $s++){
|
||||
$ssb = $sb->getSide($s);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->getLevel()->setBlock($sb, new Air(), false, false, true);
|
||||
}
|
||||
}
|
||||
$b = $this->getSide(0)->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
$tlevel = $b->meta & 0x07;
|
||||
if($tlevel != 0x00){
|
||||
for($s = 0; $s <= 5; $s++){
|
||||
$ssb = $sb->getSide($s);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->getLevel()->setBlock($b, new Air(), false, false, true);
|
||||
}
|
||||
}
|
||||
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\LeavesDecayEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Leaves extends Transparent{
|
||||
const OAK = 0;
|
||||
@ -33,16 +35,24 @@ class Leaves extends Transparent{
|
||||
const ACACIA = 0;
|
||||
const DARK_OAK = 1;
|
||||
|
||||
protected $id = self::LEAVES;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::LEAVES, $meta, "Leaves");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
self::OAK => "Oak Leaves",
|
||||
self::SPRUCE => "Spruce Leaves",
|
||||
self::BIRCH => "Birch Leaves",
|
||||
self::JUNGLE => "Jungle Leaves",
|
||||
];
|
||||
$this->name = $names[$this->meta & 0x03];
|
||||
$this->hardness = 1;
|
||||
return $names[$this->meta & 0x03];
|
||||
}
|
||||
|
||||
private function findLog(Block $pos, array $visited, $distance, &$check, $fromSide = null){
|
||||
@ -51,11 +61,11 @@ class Leaves extends Transparent{
|
||||
if(isset($visited[$index])){
|
||||
return false;
|
||||
}
|
||||
if($pos->getID() === self::WOOD){
|
||||
if($pos->getId() === self::WOOD){
|
||||
return true;
|
||||
}elseif($pos->getID() === self::LEAVES and $distance < 3){
|
||||
}elseif($pos->getId() === self::LEAVES and $distance < 3){
|
||||
$visited[$index] = true;
|
||||
$down = $pos->getSide(0)->getID();
|
||||
$down = $pos->getSide(0)->getId();
|
||||
if($down === Item::WOOD){
|
||||
return true;
|
||||
}
|
||||
@ -121,16 +131,13 @@ class Leaves extends Transparent{
|
||||
$this->meta &= 0x03;
|
||||
$visited = [];
|
||||
$check = 0;
|
||||
if($this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false, true);
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
|
||||
|
||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
|
||||
}
|
||||
if(($this->meta & 0x03) === self::OAK and mt_rand(1, 200) === 1){ //Apples
|
||||
$this->getLevel()->dropItem($this, Item::get(Item::APPLE, 0, 1));
|
||||
}
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -21,20 +21,26 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\LeavesDecayEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Leaves2 extends Leaves{
|
||||
|
||||
protected $id = self::LEAVES2;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
Transparent::__construct(self::LEAVES, $meta, "Leaves");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
self::ACACIA => "Acacia Leaves",
|
||||
self::DARK_OAK => "Dark Oak Leaves",
|
||||
];
|
||||
$this->name = $names[$this->meta & 0x03];
|
||||
$this->hardness = 1;
|
||||
return $names[$this->meta & 0x01];
|
||||
}
|
||||
|
||||
private function findLog(Block $pos, array $visited, $distance, &$check, $fromSide = null){
|
||||
@ -43,11 +49,11 @@ class Leaves2 extends Leaves{
|
||||
if(isset($visited[$index])){
|
||||
return false;
|
||||
}
|
||||
if($pos->getID() === self::WOOD2){
|
||||
if($pos->getId() === self::WOOD2){
|
||||
return true;
|
||||
}elseif($pos->getID() === self::LEAVES2 and $distance < 3){
|
||||
}elseif($pos->getId() === self::LEAVES2 and $distance < 3){
|
||||
$visited[$index] = true;
|
||||
$down = $pos->getSide(0)->getID();
|
||||
$down = $pos->getSide(0)->getId();
|
||||
if($down === Item::WOOD2){
|
||||
return true;
|
||||
}
|
||||
@ -113,13 +119,13 @@ class Leaves2 extends Leaves{
|
||||
$this->meta &= 0x03;
|
||||
$visited = [];
|
||||
$check = 0;
|
||||
if($this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false, true);
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
|
||||
|
||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
|
||||
}
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -22,12 +22,35 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class Liquid extends Transparent{
|
||||
public $isLiquid = true;
|
||||
public $breakable = false;
|
||||
public $isReplaceable = true;
|
||||
public $isSolid = false;
|
||||
public $isFullBlock = true;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
abstract class Liquid extends Transparent{
|
||||
|
||||
/** @var Vector3 */
|
||||
private $temporalVector = null;
|
||||
|
||||
public function hasEntityCollision(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isBreakable(Item $item){
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBeReplaced(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSolid(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public $adjacentSources = 0;
|
||||
public $isOptimalFlowDirection = [0, 0, 0, 0];
|
||||
public $flowCost = [0, 0, 0, 0];
|
||||
|
||||
public function getFluidHeightPercent(){
|
||||
$d = $this->meta;
|
||||
@ -37,4 +60,390 @@ class Liquid extends Transparent{
|
||||
|
||||
return ($d + 1) / 9;
|
||||
}
|
||||
|
||||
protected function getFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
}
|
||||
|
||||
if($pos->getId() !== $this->getId()){
|
||||
return -1;
|
||||
}else{
|
||||
return $pos->getDamage();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEffectiveFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
}
|
||||
|
||||
if($pos->getId() !== $this->getId()){
|
||||
return -1;
|
||||
}
|
||||
|
||||
$decay = $pos->getDamage();
|
||||
|
||||
if($decay >= 8){
|
||||
$decay = 0;
|
||||
}
|
||||
|
||||
return $decay;
|
||||
}
|
||||
|
||||
public function getFlowVector(){
|
||||
$vector = new Vector3(0, 0, 0);
|
||||
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
$decay = $this->getEffectiveFlowDecay($this);
|
||||
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
|
||||
$x = $this->x;
|
||||
$y = $this->y;
|
||||
$z = $this->z;
|
||||
|
||||
if($j === 0){
|
||||
--$x;
|
||||
}elseif($j === 1){
|
||||
++$x;
|
||||
}elseif($j === 2){
|
||||
--$z;
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$sideBlock = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||
|
||||
if($blockDecay < 0){
|
||||
if(!$sideBlock->canBeFlowedInto()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$blockDecay = $this->getEffectiveFlowDecay($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z)));
|
||||
|
||||
if($blockDecay >= 0){
|
||||
$realDecay = $blockDecay - ($decay - 8);
|
||||
$vector->x += ($sideBlock->x - $this->x) * $realDecay;
|
||||
$vector->y += ($sideBlock->y - $this->y) * $realDecay;
|
||||
$vector->z += ($sideBlock->z - $this->z) * $realDecay;
|
||||
}
|
||||
|
||||
continue;
|
||||
}else{
|
||||
$realDecay = $blockDecay - $decay;
|
||||
$vector->x += ($sideBlock->x - $this->x) * $realDecay;
|
||||
$vector->y += ($sideBlock->y - $this->y) * $realDecay;
|
||||
$vector->z += ($sideBlock->z - $this->z) * $realDecay;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->getDamage() >= 8){
|
||||
$falling = false;
|
||||
|
||||
if(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z - 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z + 1))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}elseif(!$this->getLevel()->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y + 1, $this->z))->canBeFlowedInto()){
|
||||
$falling = true;
|
||||
}
|
||||
|
||||
if($falling){
|
||||
$vector = $vector->normalize()->add(0, -6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $vector->normalize();
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
$flow = $this->getFlowVector();
|
||||
$vector->x += $flow->x;
|
||||
$vector->y += $flow->y;
|
||||
$vector->z += $flow->z;
|
||||
}
|
||||
|
||||
public function tickRate(){
|
||||
if($this instanceof Water){
|
||||
return 5;
|
||||
}elseif($this instanceof Lava){
|
||||
return 30;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$this->checkForHarden();
|
||||
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
}elseif($type === Level::BLOCK_UPDATE_SCHEDULED){
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
$decay = $this->getFlowDecay($this);
|
||||
$multiplier = $this instanceof Lava ? 2 : 1;
|
||||
|
||||
$flag = true;
|
||||
|
||||
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);
|
||||
|
||||
$k = $smallestFlowDecay + $multiplier;
|
||||
|
||||
if($k >= 8 or $smallestFlowDecay < 0){
|
||||
$k = -1;
|
||||
}
|
||||
|
||||
if(($topFlowDecay = $this->getFlowDecay($this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y + 1, $this->z))))) >= 0){
|
||||
if($topFlowDecay >= 8){
|
||||
$k = $topFlowDecay;
|
||||
}else{
|
||||
$k = $topFlowDecay | 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->adjacentSources >= 2 and $this instanceof Water){
|
||||
$bottomBlock = $this->level->getBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)));
|
||||
if($bottomBlock->isSolid()){
|
||||
$k = 0;
|
||||
}elseif($bottomBlock instanceof Water and $bottomBlock->getDamage() === 0){
|
||||
$k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if($this instanceof Lava and $decay < 8 and $k < 8 and $k > 1 and mt_rand(0, 4) !== 0){
|
||||
$k = $decay;
|
||||
$flag = false;
|
||||
}
|
||||
|
||||
if($k !== $decay){
|
||||
$decay = $k;
|
||||
if($decay < 0){
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, Block::get($this->id, $decay), true);
|
||||
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
}
|
||||
}elseif($flag){
|
||||
//$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
//$this->updateFlow();
|
||||
}
|
||||
}else{
|
||||
//$this->updateFlow();
|
||||
}
|
||||
|
||||
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
|
||||
|
||||
if($bottomBlock->canBeFlowedInto() or $bottomBlock instanceof Liquid){
|
||||
if($this instanceof Lava and $bottomBlock instanceof Water){
|
||||
$this->getLevel()->setBlock($bottomBlock, Block::get(Item::STONE), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if($decay >= 8){
|
||||
$this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay), true);
|
||||
$this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
|
||||
}else{
|
||||
$this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay + 8), true);
|
||||
$this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate());
|
||||
}
|
||||
}elseif($decay >= 0 and ($decay === 0 or !$bottomBlock->canBeFlowedInto())){
|
||||
$flags = $this->getOptimalFlowDirections();
|
||||
|
||||
$l = $decay + $multiplier;
|
||||
|
||||
if($decay >= 8){
|
||||
$l = 1;
|
||||
}
|
||||
|
||||
if($l >= 8){
|
||||
$this->checkForHarden();
|
||||
return;
|
||||
}
|
||||
|
||||
if($flags[0]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
|
||||
}
|
||||
|
||||
if($flags[1]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($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);
|
||||
}
|
||||
|
||||
if($flags[3]){
|
||||
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
|
||||
}
|
||||
}
|
||||
|
||||
$this->checkForHarden();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function flowIntoBlock(Block $block, $newFlowDecay){
|
||||
if($block->canBeFlowedInto()){
|
||||
if($block->getId() > 0){
|
||||
$this->getLevel()->useBreakOn($block);
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($block, Block::get($this->id, $newFlowDecay), true);
|
||||
$this->getLevel()->scheduleUpdate($block, $this->tickRate());
|
||||
}
|
||||
}
|
||||
|
||||
private function calculateFlowCost(Block $block, $accumulatedCost, $previousDirection){
|
||||
$cost = 1000;
|
||||
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
if(
|
||||
($j === 0 and $previousDirection === 1) or
|
||||
($j === 1 and $previousDirection === 0) or
|
||||
($j === 2 and $previousDirection === 3) or
|
||||
($j === 3 and $previousDirection === 2)
|
||||
){
|
||||
$x = $block->x;
|
||||
$y = $block->y;
|
||||
$z = $block->z;
|
||||
|
||||
if($j === 0){
|
||||
--$x;
|
||||
}elseif($j === 1){
|
||||
++$x;
|
||||
}elseif($j === 2){
|
||||
--$z;
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$blockSide = $this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y, $z));
|
||||
|
||||
if(!$blockSide->canBeFlowedInto() and !($blockSide instanceof Liquid)){
|
||||
continue;
|
||||
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
||||
continue;
|
||||
}elseif($this->getLevel()->getBlock($this->temporalVector->setComponents($x, $y - 1, $z))->canBeFlowedInto()){
|
||||
return $accumulatedCost;
|
||||
}
|
||||
|
||||
if($accumulatedCost >= 4){
|
||||
continue;
|
||||
}
|
||||
|
||||
$realCost = $this->calculateFlowCost($blockSide, $accumulatedCost + 1, $j);
|
||||
|
||||
if($realCost < $cost){
|
||||
$cost = $realCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cost;
|
||||
}
|
||||
|
||||
private function getOptimalFlowDirections(){
|
||||
if($this->temporalVector === null){
|
||||
$this->temporalVector = new Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
for($j = 0; $j < 4; ++$j){
|
||||
$this->flowCost[$j] = 1000;
|
||||
|
||||
$x = $this->x;
|
||||
$y = $this->y;
|
||||
$z = $this->z;
|
||||
|
||||
if($j === 0){
|
||||
--$x;
|
||||
}elseif($j === 1){
|
||||
++$x;
|
||||
}elseif($j === 2){
|
||||
--$z;
|
||||
}elseif($j === 3){
|
||||
++$z;
|
||||
}
|
||||
$block = $this->getLevel()->getBlock($this->temporalVector->setComponents($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()){
|
||||
$this->flowCost[$j] = 0;
|
||||
}else{
|
||||
$this->flowCost[$j] = $this->calculateFlowCost($block, 1, $j);
|
||||
}
|
||||
}
|
||||
|
||||
$minCost = $this->flowCost[0];
|
||||
|
||||
for($i = 1; $i < 4; ++$i){
|
||||
if($this->flowCost[$i] < $minCost){
|
||||
$minCost = $this->flowCost[$i];
|
||||
}
|
||||
}
|
||||
|
||||
for($i = 0; $i < 4; ++$i){
|
||||
$this->isOptimalFlowDirection[$i] = ($this->flowCost[$i] === $minCost);
|
||||
}
|
||||
|
||||
return $this->isOptimalFlowDirection;
|
||||
}
|
||||
|
||||
private function getSmallestFlowDecay(Vector3 $pos, $decay){
|
||||
$blockDecay = $this->getFlowDecay($pos);
|
||||
|
||||
if($blockDecay < 0){
|
||||
return $decay;
|
||||
}elseif($blockDecay === 0){
|
||||
++$this->adjacentSources;
|
||||
}elseif($blockDecay >= 8){
|
||||
$blockDecay = 0;
|
||||
}
|
||||
|
||||
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
|
||||
}
|
||||
|
||||
private function checkForHarden(){
|
||||
if($this instanceof Lava){
|
||||
$colliding = false;
|
||||
for($side = 0; $side <= 5 and !$colliding; ++$side){
|
||||
$colliding = $this->getSide($side) instanceof Water;
|
||||
}
|
||||
|
||||
if($colliding){
|
||||
if($this->getDamage() === 0){
|
||||
$this->getLevel()->setBlock($this, Block::get(Item::OBSIDIAN), true);
|
||||
}elseif($this->getDamage() <= 4){
|
||||
$this->getLevel()->setBlock($this, Block::get(Item::COBBLESTONE), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
}
|
@ -25,9 +25,23 @@ use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
|
||||
class LitPumpkin extends Solid{
|
||||
public function __construct(){
|
||||
parent::__construct(self::LIT_PUMPKIN, "Jack o'Lantern");
|
||||
$this->hardness = 5;
|
||||
|
||||
protected $id = self::LIT_PUMPKIN;
|
||||
|
||||
public function getLightLevel(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Jack o'Lantern";
|
||||
}
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Melon extends Transparent{
|
||||
|
||||
protected $id = self::MELON_BLOCK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::MELON_BLOCK, 0, "Melon Block");
|
||||
$this->hardness = 5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Melon Block";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 5;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -21,59 +21,54 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class MelonStem extends Crops{
|
||||
|
||||
protected $id = self::MELON_STEM;
|
||||
|
||||
public function getName(){
|
||||
return "Melon Stem";
|
||||
}
|
||||
|
||||
class MelonStem extends Flowable{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::MELON_STEM, $meta, "Melon Stem");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 0;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get(Item::MELON_SEEDS, 0, mt_rand(0, 2)));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
|
||||
if($this->getSide(0)->isTransparent() === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$block = clone $this;
|
||||
++$block->meta;
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
||||
}
|
||||
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b->getID() === self::MELON_BLOCK){
|
||||
if($b->getId() === self::MELON_BLOCK){
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}
|
||||
}
|
||||
$side = $this->getSide(mt_rand(2, 5));
|
||||
$d = $side->getSide(0);
|
||||
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
|
||||
$this->getLevel()->setBlock($side, new Melon(), true);
|
||||
if($side->getId() === self::AIR and ($d->getId() === self::FARMLAND or $d->getId() === self::GRASS or $d->getId() === self::DIRT)){
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($side, new Melon()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,20 +79,6 @@ class MelonStem extends Flowable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$this->meta = 0x07;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [
|
||||
[Item::MELON_SEEDS, 0, mt_rand(0, 2)],
|
||||
|
@ -24,29 +24,39 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class MonsterSpawner extends Solid{
|
||||
public function __construct(){
|
||||
parent::__construct(self::MONSTER_SPAWNER, 0, "Monster Spawner");
|
||||
$this->hardness = 25;
|
||||
|
||||
protected $id = self::MONSTER_SPAWNER;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.95;
|
||||
case 4:
|
||||
return 1.25;
|
||||
case 3:
|
||||
return 1.9;
|
||||
case 2:
|
||||
return 0.65;
|
||||
case 1:
|
||||
return 3.75;
|
||||
default:
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
public function getHardness(){
|
||||
return 25;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [];
|
||||
}
|
||||
public function getName(){
|
||||
return "Monster Spawner";
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
switch($item->isPickaxe()){
|
||||
case 5:
|
||||
return 0.95;
|
||||
case 4:
|
||||
return 1.25;
|
||||
case 3:
|
||||
return 1.9;
|
||||
case 2:
|
||||
return 0.65;
|
||||
case 1:
|
||||
return 3.75;
|
||||
default:
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [];
|
||||
}
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class MossStone extends Solid{
|
||||
|
||||
protected $id = self::MOSS_STONE;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::MOSS_STONE, $meta, "Moss Stone");
|
||||
$this->hardness = 30;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Moss Stone";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -21,14 +21,26 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Mycelium extends Solid{
|
||||
|
||||
protected $id = self::MYCELIUM;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::MYCELIUM, 0, "Mycelium");
|
||||
$this->hardness = 2.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Mycelium";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2.5;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
@ -43,11 +55,13 @@ 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()->getBlockIdAt($x, $y, $z);
|
||||
if($block === Block::DIRT){
|
||||
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
|
||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||
if($block->getId() === Block::DIRT){
|
||||
if($block->getSide(1) instanceof Transparent){
|
||||
$this->getLevel()->setBlock($block, new Mycelium());
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockSpreadEvent($block, $this, new Mycelium()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($block, $ev->getNewState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class NetherBrick extends Solid{
|
||||
|
||||
protected $id = self::NETHER_BRICKS;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::NETHER_BRICKS, 0, "Nether Bricks");
|
||||
$this->hardness = 30;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Nether Bricks";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -23,8 +23,15 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class NetherBrickStairs extends Stair{
|
||||
|
||||
protected $id = self::NETHER_BRICKS_STAIRS;
|
||||
|
||||
public function getName(){
|
||||
return "Nether Bricks Stairs";
|
||||
}
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::NETHER_BRICKS_STAIRS, $meta, "Nether Bricks Stairs");
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
}
|
@ -23,9 +23,19 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
class NetherReactor extends Solid{
|
||||
|
||||
protected $id = self::NETHER_REACTOR;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::NETHER_REACTOR, $meta, "Nether Reactor");
|
||||
$this->isActivable = true;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Nether Reactor";
|
||||
}
|
||||
|
||||
public function canBeActivated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Netherrack extends Solid{
|
||||
|
||||
protected $id = self::NETHERRACK;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::NETHERRACK, 0, "Netherrack");
|
||||
$this->hardness = 2;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Netherrack";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -24,9 +24,19 @@ namespace pocketmine\block;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Obsidian extends Solid{
|
||||
|
||||
protected $id = self::OBSIDIAN;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::OBSIDIAN, 0, "Obsidian");
|
||||
$this->hardness = 6000;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Obsidian";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 6000;
|
||||
}
|
||||
|
||||
public function getBreakTime(Item $item){
|
||||
|
@ -30,18 +30,28 @@ class Planks extends Solid{
|
||||
const ACACIA = 4;
|
||||
const DARK_OAK = 5;
|
||||
|
||||
protected $id = self::WOODEN_PLANKS;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::PLANKS, $meta, "Wood Planks");
|
||||
$names = [
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
static $names = [
|
||||
self::OAK => "Oak Wood Planks",
|
||||
self::SPRUCE => "Spruce Wood Planks",
|
||||
self::BIRCH => "Birch Wood Planks",
|
||||
self::JUNGLE => "Jungle Wood Planks",
|
||||
self::ACACIA => "Acacia Wood Planks",
|
||||
self::DARK_OAK => "Jungle Wood Planks",
|
||||
"",
|
||||
""
|
||||
];
|
||||
$this->name = $names[$this->meta & 0x07];
|
||||
$this->hardness = 15;
|
||||
return $names[$this->meta & 0x07];
|
||||
}
|
||||
|
||||
}
|
@ -22,8 +22,18 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
class Podzol extends Solid{
|
||||
|
||||
protected $id = self::PODZOL;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::PODZOL, 0, "Podzol");
|
||||
$this->hardness = 2.5;
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return "Podzol";
|
||||
}
|
||||
|
||||
public function getHardness(){
|
||||
return 2.5;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user