mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-14 05:15:11 +00:00
Compare commits
315 Commits
Alpha_1.4d
...
Alpha_1.4d
Author | SHA1 | Date | |
---|---|---|---|
7e1095e28d | |||
f1519e6d13 | |||
3b9a9bcd5d | |||
263bff01c8 | |||
987d647b76 | |||
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 | |||
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 | |||
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 | |||
be948f99cc | |||
516bb37a50 | |||
580ade9092 | |||
8f7dfe0b71 | |||
5310ba3ae6 | |||
ef97efcd96 | |||
30c3718ea8 | |||
e3e97a4205 | |||
fec387d2ec | |||
481e2b08ee | |||
15de0eece7 | |||
2f8267aa1e | |||
f2b573c32f | |||
34946faf94 | |||
3b47513439 | |||
2e6366868d | |||
245e9b4f18 | |||
68e73d4e3a | |||
684617d370 | |||
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 |
@ -9,7 +9,7 @@ branches:
|
|||||||
before_script:
|
before_script:
|
||||||
- mkdir plugins
|
- mkdir plugins
|
||||||
- wget -O plugins/DevTools.phar https://github.com/PocketMine/DevTools/releases/download/v1.9.0/DevTools_v1.9.0.phar
|
- 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/pthreads-2.0.10
|
||||||
- pecl install channel://pecl.php.net/weakref-0.2.4
|
- pecl install channel://pecl.php.net/weakref-0.2.4
|
||||||
- echo | pecl install channel://pecl.php.net/yaml-1.1.1
|
- echo | pecl install channel://pecl.php.net/yaml-1.1.1
|
||||||
|
|
||||||
|
@ -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
|
## Bug Tracking for Collaborators
|
||||||
|
|
||||||
### Labels
|
### 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.
|
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: 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: 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
|
||||||
Status labels show the status of the issue. Multiple status labels may be applied.
|
Status labels show the status of the issue. Multiple status labels may be applied.
|
||||||
|
@ -137,7 +137,7 @@ class CrashDump{
|
|||||||
$error = $lastExceptionError;
|
$error = $lastExceptionError;
|
||||||
}else{
|
}else{
|
||||||
$error = (array) error_get_last();
|
$error = (array) error_get_last();
|
||||||
$error["trace"] = getTrace(4);
|
$error["trace"] = @getTrace(4);
|
||||||
$errorConversion = [
|
$errorConversion = [
|
||||||
E_ERROR => "E_ERROR",
|
E_ERROR => "E_ERROR",
|
||||||
E_WARNING => "E_WARNING",
|
E_WARNING => "E_WARNING",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -65,15 +65,13 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace pocketmine {
|
namespace pocketmine {
|
||||||
use LogLevel;
|
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\MainLogger;
|
use pocketmine\utils\MainLogger;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
use pocketmine\wizard\Installer;
|
use pocketmine\wizard\Installer;
|
||||||
use raklib\RakLib;
|
|
||||||
|
|
||||||
const VERSION = "Alpha_1.4dev";
|
const VERSION = "Alpha_1.4dev";
|
||||||
const API_VERSION = "1.4.0";
|
const API_VERSION = "1.7.0";
|
||||||
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
|
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
|
||||||
const MINECRAFT_VERSION = "v0.9.5 alpha";
|
const MINECRAFT_VERSION = "v0.9.5 alpha";
|
||||||
|
|
||||||
@ -111,36 +109,6 @@ namespace pocketmine {
|
|||||||
|
|
||||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
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();
|
gc_enable();
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
ini_set("allow_url_fopen", 1);
|
ini_set("allow_url_fopen", 1);
|
||||||
@ -153,13 +121,159 @@ namespace pocketmine {
|
|||||||
|
|
||||||
$opts = getopt("", ["enable-ansi", "disable-ansi", "data:", "plugins:", "no-wizard", "enable-profiler"]);
|
$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\\DATA", isset($opts["data"]) ? $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\\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);
|
$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 stupid 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 stupid idiots 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 = '/(?:Time Zone:\s*\()(UTC)(\+*\-*\d*\d*\:*\d*\d*)(?:\))/';
|
||||||
|
|
||||||
|
exec("systeminfo", $output);
|
||||||
|
|
||||||
|
$string = trim(implode("\n", $output));
|
||||||
|
|
||||||
|
//Detect the Time Zone string in systeminfo
|
||||||
|
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(isset($opts["enable-profiler"])){
|
||||||
if(function_exists("profiler_enable")){
|
if(function_exists("profiler_enable")){
|
||||||
\profiler_enable();
|
\profiler_enable();
|
||||||
@ -215,54 +329,7 @@ namespace pocketmine {
|
|||||||
return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/");
|
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){
|
set_error_handler([\ExceptionHandler::class, "handler"], -1);
|
||||||
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);
|
|
||||||
|
|
||||||
$errors = 0;
|
$errors = 0;
|
||||||
|
|
||||||
@ -364,14 +431,14 @@ namespace pocketmine {
|
|||||||
$logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
|
$logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
|
||||||
if($thread instanceof Thread){
|
if($thread instanceof Thread){
|
||||||
$thread->kill();
|
$thread->kill();
|
||||||
|
sleep(1);
|
||||||
if($thread->isRunning() or !$thread->join()){
|
if($thread->isRunning()){
|
||||||
$thread->detach();
|
$thread->detach();
|
||||||
}
|
}
|
||||||
}elseif($thread instanceof Worker){
|
}elseif($thread instanceof Worker){
|
||||||
$thread->kill();
|
$thread->kill();
|
||||||
sleep(1);
|
sleep(1);
|
||||||
if($thread->isRunning() or !$thread->join()){
|
if($thread->isRunning()){
|
||||||
$thread->detach();
|
$thread->detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,15 @@ use pocketmine\command\CommandSender;
|
|||||||
use pocketmine\command\ConsoleCommandSender;
|
use pocketmine\command\ConsoleCommandSender;
|
||||||
use pocketmine\command\PluginIdentifiableCommand;
|
use pocketmine\command\PluginIdentifiableCommand;
|
||||||
use pocketmine\command\SimpleCommandMap;
|
use pocketmine\command\SimpleCommandMap;
|
||||||
|
use pocketmine\entity\Arrow;
|
||||||
use pocketmine\entity\Entity;
|
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\HandlerList;
|
||||||
use pocketmine\event\level\LevelInitEvent;
|
use pocketmine\event\level\LevelInitEvent;
|
||||||
use pocketmine\event\level\LevelLoadEvent;
|
use pocketmine\event\level\LevelLoadEvent;
|
||||||
@ -46,6 +54,7 @@ use pocketmine\level\format\anvil\Anvil;
|
|||||||
use pocketmine\level\format\LevelProviderManager;
|
use pocketmine\level\format\LevelProviderManager;
|
||||||
use pocketmine\level\format\mcregion\McRegion;
|
use pocketmine\level\format\mcregion\McRegion;
|
||||||
use pocketmine\level\generator\Flat;
|
use pocketmine\level\generator\Flat;
|
||||||
|
use pocketmine\level\generator\GenerationInstanceManager;
|
||||||
use pocketmine\level\generator\GenerationRequestManager;
|
use pocketmine\level\generator\GenerationRequestManager;
|
||||||
use pocketmine\level\generator\Generator;
|
use pocketmine\level\generator\Generator;
|
||||||
use pocketmine\level\generator\Normal;
|
use pocketmine\level\generator\Normal;
|
||||||
@ -78,13 +87,19 @@ use pocketmine\plugin\PluginManager;
|
|||||||
use pocketmine\scheduler\CallbackTask;
|
use pocketmine\scheduler\CallbackTask;
|
||||||
use pocketmine\scheduler\SendUsageTask;
|
use pocketmine\scheduler\SendUsageTask;
|
||||||
use pocketmine\scheduler\ServerScheduler;
|
use pocketmine\scheduler\ServerScheduler;
|
||||||
|
use pocketmine\tile\Chest;
|
||||||
|
use pocketmine\tile\Furnace;
|
||||||
|
use pocketmine\tile\Sign;
|
||||||
use pocketmine\tile\Tile;
|
use pocketmine\tile\Tile;
|
||||||
use pocketmine\updater\AutoUpdater;
|
use pocketmine\updater\AutoUpdater;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
use pocketmine\utils\Cache;
|
use pocketmine\utils\Cache;
|
||||||
use pocketmine\utils\Config;
|
use pocketmine\utils\Config;
|
||||||
|
use pocketmine\utils\LevelException;
|
||||||
use pocketmine\utils\MainLogger;
|
use pocketmine\utils\MainLogger;
|
||||||
|
use pocketmine\utils\ServerException;
|
||||||
use pocketmine\utils\TextFormat;
|
use pocketmine\utils\TextFormat;
|
||||||
|
use pocketmine\utils\TextWrapper;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
use pocketmine\utils\VersionString;
|
use pocketmine\utils\VersionString;
|
||||||
|
|
||||||
@ -113,6 +128,8 @@ class Server{
|
|||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $isRunning = true;
|
private $isRunning = true;
|
||||||
|
|
||||||
|
private $hasStopped = false;
|
||||||
|
|
||||||
/** @var PluginManager */
|
/** @var PluginManager */
|
||||||
private $pluginManager = null;
|
private $pluginManager = null;
|
||||||
|
|
||||||
@ -140,6 +157,7 @@ class Server{
|
|||||||
|
|
||||||
/** @var CommandReader */
|
/** @var CommandReader */
|
||||||
private $console = null;
|
private $console = null;
|
||||||
|
private $consoleThreaded;
|
||||||
|
|
||||||
/** @var SimpleCommandMap */
|
/** @var SimpleCommandMap */
|
||||||
private $commandMap = null;
|
private $commandMap = null;
|
||||||
@ -153,6 +171,9 @@ class Server{
|
|||||||
/** @var int */
|
/** @var int */
|
||||||
private $maxPlayers;
|
private $maxPlayers;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $autoSave;
|
||||||
|
|
||||||
/** @var RCON */
|
/** @var RCON */
|
||||||
private $rcon;
|
private $rcon;
|
||||||
|
|
||||||
@ -285,14 +306,31 @@ class Server{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getIp(){
|
public function getIp(){
|
||||||
return $this->getConfigString("server-ip", "");
|
return $this->getConfigString("server-ip", "0.0.0.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getServerName(){
|
public function getServerName(){
|
||||||
return $this->getConfigString("server-name", "Unknown server");
|
return $this->getConfigString("motd", "Unknown 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 +627,16 @@ class Server{
|
|||||||
* @param string $payload
|
* @param string $payload
|
||||||
*/
|
*/
|
||||||
public function handlePacket($address, $port, $payload){
|
public function handlePacket($address, $port, $payload){
|
||||||
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
|
try{
|
||||||
$this->queryHandler->handle($address, $port, $payload);
|
if(strlen($payload) > 2 and substr($payload, 0, 2) === "\xfe\xfd" and $this->queryHandler instanceof QueryHandler){
|
||||||
} //TODO: add raw packet events
|
$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 +667,7 @@ class Server{
|
|||||||
$result = $this->getPlayerExact($name);
|
$result = $this->getPlayerExact($name);
|
||||||
|
|
||||||
if($result === null){
|
if($result === null){
|
||||||
$result = new OfflinePlayer($this, $name);
|
return new OfflinePlayer($this, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -893,7 +938,7 @@ class Server{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function unloadLevel(Level $level, $forceUnload = false){
|
public function unloadLevel(Level $level, $forceUnload = false){
|
||||||
if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getFolderName())){
|
if($level->unload($forceUnload) === true){
|
||||||
unset($this->levels[$level->getID()]);
|
unset($this->levels[$level->getID()]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -909,11 +954,11 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws LevelException
|
||||||
*/
|
*/
|
||||||
public function loadLevel($name){
|
public function loadLevel($name){
|
||||||
if(trim($name) === ""){
|
if(trim($name) === ""){
|
||||||
throw new \Exception("Invalid empty level name");
|
throw new LevelException("Invalid empty level name");
|
||||||
}
|
}
|
||||||
if($this->isLevelLoaded($name)){
|
if($this->isLevelLoaded($name)){
|
||||||
return true;
|
return true;
|
||||||
@ -947,6 +992,8 @@ class Server{
|
|||||||
|
|
||||||
$this->levels[$level->getID()] = $level;
|
$this->levels[$level->getID()] = $level;
|
||||||
|
|
||||||
|
$level->initLevel();
|
||||||
|
|
||||||
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
||||||
|
|
||||||
/*foreach($entities->getAll() as $entity){
|
/*foreach($entities->getAll() as $entity){
|
||||||
@ -1060,7 +1107,7 @@ class Server{
|
|||||||
return false;
|
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)){
|
if($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)){
|
||||||
$generator = new $generator($options);
|
$generator = new $generator($options);
|
||||||
@ -1080,6 +1127,8 @@ class Server{
|
|||||||
$level = new Level($this, $name, $path, $provider);
|
$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));
|
$this->getPluginManager()->callEvent(new LevelInitEvent($level));
|
||||||
|
|
||||||
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
||||||
@ -1090,14 +1139,14 @@ class Server{
|
|||||||
$radiusSquared = ($this->getViewDistance() + 1) / M_PI;
|
$radiusSquared = ($this->getViewDistance() + 1) / M_PI;
|
||||||
$radius = ceil(sqrt($radiusSquared));
|
$radius = ceil(sqrt($radiusSquared));
|
||||||
|
|
||||||
$centerX = $level->getSpawn()->getX() >> 4;
|
$centerX = $level->getSpawnLocation()->getX() >> 4;
|
||||||
$centerZ = $level->getSpawn()->getZ() >> 4;
|
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
|
||||||
|
|
||||||
$order = [];
|
$order = [];
|
||||||
|
|
||||||
for($X = -$radius; $X <= $radius; ++$X){
|
for($X = -$radius; $X <= $radius; ++$X){
|
||||||
for($Z = -$radius; $Z <= $radius; ++$Z){
|
for($Z = -$radius; $Z <= $radius; ++$Z){
|
||||||
$distance = ($X * $X) + ($Z * $Z);
|
$distance = $X ** 2 + $Z ** 2;
|
||||||
if($distance > $radiusSquared){
|
if($distance > $radiusSquared){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1402,11 +1451,12 @@ class Server{
|
|||||||
$this->autoloader = $autoloader;
|
$this->autoloader = $autoloader;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->filePath = $filePath;
|
$this->filePath = $filePath;
|
||||||
$this->dataPath = $dataPath;
|
@mkdir($dataPath . "worlds/", 0777);
|
||||||
$this->pluginPath = $pluginPath;
|
@mkdir($dataPath . "players/", 0777);
|
||||||
@mkdir($this->dataPath . "worlds/", 0777, true);
|
@mkdir($pluginPath, 0777);
|
||||||
@mkdir($this->dataPath . "players/", 0777);
|
|
||||||
@mkdir($this->pluginPath, 0777);
|
$this->dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
|
||||||
|
$this->pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
$this->entityMetadata = new EntityMetadataStore();
|
$this->entityMetadata = new EntityMetadataStore();
|
||||||
$this->playerMetadata = new PlayerMetadataStore();
|
$this->playerMetadata = new PlayerMetadataStore();
|
||||||
@ -1424,7 +1474,8 @@ class Server{
|
|||||||
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
|
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
|
||||||
$this->banByIP->load();
|
$this->banByIP->load();
|
||||||
|
|
||||||
$this->console = new CommandReader();
|
$this->consoleThreaded = new \Threaded();
|
||||||
|
$this->console = new CommandReader($this->consoleThreaded);
|
||||||
|
|
||||||
$version = new VersionString($this->getPocketMineVersion());
|
$version = new VersionString($this->getPocketMineVersion());
|
||||||
$this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
|
$this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
|
||||||
@ -1462,7 +1513,7 @@ class Server{
|
|||||||
"level-type" => "DEFAULT",
|
"level-type" => "DEFAULT",
|
||||||
"enable-query" => true,
|
"enable-query" => true,
|
||||||
"enable-rcon" => false,
|
"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,
|
"auto-save" => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -1475,6 +1526,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
$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){
|
if(($memory = str_replace("B", "", strtoupper($this->getConfigString("memory-limit", "256M")))) !== false){
|
||||||
$value = ["M" => 1, "G" => 1024];
|
$value = ["M" => 1, "G" => 1024];
|
||||||
@ -1500,19 +1552,19 @@ class Server{
|
|||||||
$this->logger->info("Advanced cache enabled");
|
$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){
|
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0){
|
||||||
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
|
$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->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8));
|
||||||
|
|
||||||
$this->addInterface($this->mainInterface = new RakLibInterface($this));
|
$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 server is running " . $this->getName() . " version " . ($version->isDev() ? TextFormat::YELLOW : "") . $version->get(true) . 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->getName() . " is distributed under the LGPL License", true, true, 0);
|
||||||
|
|
||||||
PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
|
PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
|
||||||
@ -1521,9 +1573,13 @@ class Server{
|
|||||||
$this->consoleSender = new ConsoleCommandSender();
|
$this->consoleSender = new ConsoleCommandSender();
|
||||||
$this->commandMap = new SimpleCommandMap($this);
|
$this->commandMap = new SimpleCommandMap($this);
|
||||||
|
|
||||||
|
$this->registerEntities();
|
||||||
|
$this->registerTiles();
|
||||||
|
|
||||||
InventoryType::init();
|
InventoryType::init();
|
||||||
Block::init();
|
Block::init();
|
||||||
Item::init();
|
Item::init();
|
||||||
|
TextWrapper::init();
|
||||||
$this->craftingManager = new CraftingManager();
|
$this->craftingManager = new CraftingManager();
|
||||||
|
|
||||||
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
||||||
@ -1533,7 +1589,6 @@ class Server{
|
|||||||
|
|
||||||
set_exception_handler([$this, "exceptionHandler"]);
|
set_exception_handler([$this, "exceptionHandler"]);
|
||||||
register_shutdown_function([$this, "crashDump"]);
|
register_shutdown_function([$this, "crashDump"]);
|
||||||
register_shutdown_function([$this, "forceShutdown"]);
|
|
||||||
|
|
||||||
$this->pluginManager->loadPlugins($this->pluginPath);
|
$this->pluginManager->loadPlugins($this->pluginPath);
|
||||||
|
|
||||||
@ -1541,7 +1596,11 @@ class Server{
|
|||||||
|
|
||||||
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
$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, Anvil::class);
|
||||||
LevelProviderManager::addProvider($this, McRegion::class);
|
LevelProviderManager::addProvider($this, McRegion::class);
|
||||||
@ -1552,7 +1611,7 @@ class Server{
|
|||||||
Generator::addGenerator(Normal::class, "default");
|
Generator::addGenerator(Normal::class, "default");
|
||||||
|
|
||||||
//Temporal workaround, pthreads static property nullification test
|
//Temporal workaround, pthreads static property nullification test
|
||||||
if(PluginManager::$pluginParentTimer === null){
|
if(PluginManager::$pluginParentTimer === null or Timings::$serverTickTimer === null){
|
||||||
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
|
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
|
||||||
kill(getmypid());
|
kill(getmypid());
|
||||||
return;
|
return;
|
||||||
@ -1601,7 +1660,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));
|
$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));
|
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doAutoSave"]), $this->getProperty("ticks-per.autosave", 6000), $this->getProperty("ticks-per.autosave", 6000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1616,11 +1675,17 @@ class Server{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $message
|
* @param $message
|
||||||
|
* @param Player[]|null $recipients
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function broadcastMessage($message){
|
public function broadcastMessage($message, $recipients = null){
|
||||||
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
if(!is_array($recipients)){
|
||||||
|
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
||||||
|
}
|
||||||
|
foreach($recipients as $recipient){
|
||||||
|
$recipient->sendMessage($message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1654,8 +1719,13 @@ class Server{
|
|||||||
* @param DataPacket $packet
|
* @param DataPacket $packet
|
||||||
*/
|
*/
|
||||||
public static function broadcastPacket(array $players, DataPacket $packet){
|
public static function broadcastPacket(array $players, DataPacket $packet){
|
||||||
|
$packet->encode();
|
||||||
|
$packet->isEncoded = true;
|
||||||
foreach($players as $player){
|
foreach($players as $player){
|
||||||
$player->dataPacket(clone $packet);
|
$player->dataPacket($packet);
|
||||||
|
}
|
||||||
|
if(isset($packet->__encapsulatedPacket)){
|
||||||
|
unset($packet->__encapsulatedPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1719,7 +1789,7 @@ class Server{
|
|||||||
*/
|
*/
|
||||||
public function dispatchCommand(CommandSender $sender, $commandLine){
|
public function dispatchCommand(CommandSender $sender, $commandLine){
|
||||||
if(!($sender instanceof CommandSender)){
|
if(!($sender instanceof CommandSender)){
|
||||||
throw new \Exception("CommandSender is not valid");
|
throw new ServerException("CommandSender is not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->commandMap->dispatch($sender, $commandLine)){
|
if($this->commandMap->dispatch($sender, $commandLine)){
|
||||||
@ -1787,40 +1857,54 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function forceShutdown(){
|
public function forceShutdown(){
|
||||||
$this->shutdown();
|
if($this->hasStopped){
|
||||||
if($this->rcon instanceof RCON){
|
return;
|
||||||
$this->rcon->stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->getProperty("settings.upnp-forwarding", false) === true){
|
try{
|
||||||
$this->logger->info("[UPnP] Removing port forward...");
|
$this->hasStopped = true;
|
||||||
UPnP::RemovePortForward($this->getPort());
|
|
||||||
|
$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 +1973,52 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exceptionHandler(\Exception $e){
|
public function exceptionHandler(\Exception $e, $trace = null){
|
||||||
if($e === null){
|
if($e === null){
|
||||||
return;
|
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;
|
global $lastExceptionError, $lastError;
|
||||||
$lastExceptionError = $lastError;
|
$lastExceptionError = $lastError;
|
||||||
$this->crashDump();
|
$this->crashDump();
|
||||||
$this->forceShutdown();
|
|
||||||
kill(getmypid());
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function crashDump(){
|
public function crashDump(){
|
||||||
if($this->isRunning === false){
|
if($this->isRunning === false){
|
||||||
return;
|
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");
|
$this->logger->emergency("An unrecoverable error has occurred and the server has crashed. Creating a crash dump");
|
||||||
$dump = new CrashDump($this);
|
$dump = new CrashDump($this);
|
||||||
|
|
||||||
@ -1915,44 +2026,49 @@ class Server{
|
|||||||
|
|
||||||
|
|
||||||
if($this->getProperty("auto-report.enabled", true) !== false){
|
if($this->getProperty("auto-report.enabled", true) !== false){
|
||||||
|
$report = true;
|
||||||
$plugin = $dump->getData()["plugin"];
|
$plugin = $dump->getData()["plugin"];
|
||||||
if(is_string($plugin)){
|
if(is_string($plugin)){
|
||||||
$p = $this->pluginManager->getPlugin($plugin);
|
$p = $this->pluginManager->getPlugin($plugin);
|
||||||
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
|
if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){
|
||||||
return;
|
$report = false;
|
||||||
}
|
}
|
||||||
}elseif(\Phar::running(true) == ""){
|
}elseif(\Phar::running(true) == ""){
|
||||||
return;
|
$report = false;
|
||||||
}
|
}
|
||||||
if($dump->getData()["type"] === "E_PARSE" or $dump->getData()["type"] === "E_COMPILE_ERROR"){
|
if($dump->getData()["error"]["type"] === "E_PARSE" or $dump->getData()["error"]["type"] === "E_COMPILE_ERROR"){
|
||||||
return;
|
$report = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
|
if($report){
|
||||||
"report" => "yes",
|
$reply = Utils::postURL("http://" . $this->getProperty("auto-report.host", "crash.pocketmine.net") . "/submit/api", [
|
||||||
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
|
"report" => "yes",
|
||||||
"email" => "crash@pocketmine.net",
|
"name" => $this->getName() . " " . $this->getPocketMineVersion(),
|
||||||
"reportPaste" => base64_encode($dump->getEncodedData())
|
"email" => "crash@pocketmine.net",
|
||||||
]);
|
"reportPaste" => base64_encode($dump->getEncodedData())
|
||||||
|
]);
|
||||||
|
|
||||||
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
|
if(($data = json_decode($reply)) !== false and isset($data->crashId)){
|
||||||
$reportId = $data->crashId;
|
$reportId = $data->crashId;
|
||||||
$reportUrl = $data->crashUrl;
|
$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->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();
|
//$this->checkMemory();
|
||||||
//$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n";
|
//$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(){
|
public function __debugInfo(){
|
||||||
return get_class($this);
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function tickProcessor(){
|
private function tickProcessor(){
|
||||||
$lastLoop = 0;
|
|
||||||
while($this->isRunning){
|
while($this->isRunning){
|
||||||
$this->tick();
|
$this->tick();
|
||||||
usleep((int) max(1, ($this->nextTick - microtime(true)) * 1000000));
|
usleep((int) max(1, ($this->nextTick - microtime(true)) * 1000000));
|
||||||
@ -1972,19 +2088,21 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function doAutoSave(){
|
public function doAutoSave(){
|
||||||
Timings::$worldSaveTimer->startTiming();
|
if($this->getAutoSave()){
|
||||||
foreach($this->getOnlinePlayers() as $index => $player){
|
Timings::$worldSaveTimer->startTiming();
|
||||||
if($player->isOnline()){
|
foreach($this->getOnlinePlayers() as $index => $player){
|
||||||
$player->save();
|
if($player->isOnline()){
|
||||||
}elseif(!$player->isConnected()){
|
$player->save();
|
||||||
unset($this->players[$index]);
|
}elseif(!$player->isConnected()){
|
||||||
|
unset($this->players[$index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->getLevels() as $level){
|
foreach($this->getLevels() as $level){
|
||||||
$level->save(false);
|
$level->save(false);
|
||||||
|
}
|
||||||
|
Timings::$worldSaveTimer->stopTiming();
|
||||||
}
|
}
|
||||||
Timings::$worldSaveTimer->stopTiming();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doLevelGC(){
|
public function doLevelGC(){
|
||||||
@ -2064,11 +2182,24 @@ class Server{
|
|||||||
if(($this->tickCounter & 0b1111) === 0){
|
if(($this->tickCounter & 0b1111) === 0){
|
||||||
$this->titleTick();
|
$this->titleTick();
|
||||||
if(isset($this->queryHandler) and ($this->tickCounter & 0b111111111) === 0){
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->generationManager->process();
|
||||||
|
|
||||||
|
if(($this->tickCounter % 100) === 0){
|
||||||
|
foreach($this->levels as $level){
|
||||||
|
$level->clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->generationManager->handlePackets();
|
|
||||||
|
|
||||||
Timings::$serverTickTimer->stopTiming();
|
Timings::$serverTickTimer->stopTiming();
|
||||||
|
|
||||||
@ -2084,9 +2215,26 @@ class Server{
|
|||||||
$this->nextTick = $tickTime;
|
$this->nextTick = $tickTime;
|
||||||
}
|
}
|
||||||
$this->nextTick += 0.05;
|
$this->nextTick += 0.05;
|
||||||
$this->inTick = false;
|
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class Bed extends Transparent{
|
|||||||
$this->hardness = 1;
|
$this->hardness = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -53,7 +53,7 @@ class Bed extends Transparent{
|
|||||||
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
$isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE);
|
||||||
|
|
||||||
if($player instanceof Player and !$isNight){
|
if($player instanceof Player and !$isNight){
|
||||||
$pk = new ChatPacket;
|
$pk = new ChatPacket();
|
||||||
$pk->message = "You can only sleep at night";
|
$pk->message = "You can only sleep at night";
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class Bed extends Transparent{
|
|||||||
$b = $blockWest;
|
$b = $blockWest;
|
||||||
}else{
|
}else{
|
||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
$pk = new ChatPacket;
|
$pk = new ChatPacket();
|
||||||
$pk->message = "This bed is incomplete";
|
$pk->message = "This bed is incomplete";
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ class Bed extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($player instanceof Player and $player->sleepOn($b) === false){
|
if($player instanceof Player and $player->sleepOn($b) === false){
|
||||||
$pk = new ChatPacket;
|
$pk = new ChatPacket();
|
||||||
$pk->message = "This bed is occupied";
|
$pk->message = "This bed is occupied";
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
}
|
}
|
||||||
|
@ -22,65 +22,10 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
|
||||||
use pocketmine\Player;
|
|
||||||
|
|
||||||
class Beetroot extends Flowable{
|
class Beetroot extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::BEETROOT_BLOCK, $meta, "Beetroot Block");
|
parent::__construct(self::BEETROOT_BLOCK, $meta, "Beetroot Block");
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
|
@ -39,7 +39,7 @@ use pocketmine\Player;
|
|||||||
use pocketmine\plugin\Plugin;
|
use pocketmine\plugin\Plugin;
|
||||||
|
|
||||||
|
|
||||||
abstract class Block extends Position implements Metadatable{
|
class Block extends Position implements Metadatable{
|
||||||
const AIR = 0;
|
const AIR = 0;
|
||||||
const STONE = 1;
|
const STONE = 1;
|
||||||
const GRASS = 2;
|
const GRASS = 2;
|
||||||
@ -167,7 +167,8 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
const MELON_BLOCK = 103;
|
const MELON_BLOCK = 103;
|
||||||
const PUMPKIN_STEM = 104;
|
const PUMPKIN_STEM = 104;
|
||||||
const MELON_STEM = 105;
|
const MELON_STEM = 105;
|
||||||
|
const VINE = 106;
|
||||||
|
const VINES = 106;
|
||||||
const FENCE_GATE = 107;
|
const FENCE_GATE = 107;
|
||||||
const BRICK_STAIRS = 108;
|
const BRICK_STAIRS = 108;
|
||||||
const STONE_BRICK_STAIRS = 109;
|
const STONE_BRICK_STAIRS = 109;
|
||||||
@ -345,7 +346,7 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
[Item::SNOW_LAYER, 0],
|
[Item::SNOW_LAYER, 0],
|
||||||
[Item::GLASS, 0],
|
[Item::GLASS, 0],
|
||||||
[Item::GLOWSTONE_BLOCK, 0],
|
[Item::GLOWSTONE_BLOCK, 0],
|
||||||
//TODO: Vines
|
[Item::VINES, 0],
|
||||||
[Item::NETHER_REACTOR, 0],
|
[Item::NETHER_REACTOR, 0],
|
||||||
[Item::LADDER, 0],
|
[Item::LADDER, 0],
|
||||||
[Item::SPONGE, 0],
|
[Item::SPONGE, 0],
|
||||||
@ -362,7 +363,6 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
[Item::STONECUTTER, 0],
|
[Item::STONECUTTER, 0],
|
||||||
[Item::CHEST, 0],
|
[Item::CHEST, 0],
|
||||||
[Item::FURNACE, 0],
|
[Item::FURNACE, 0],
|
||||||
//TODO: End Portal
|
|
||||||
[Item::END_PORTAL, 0],
|
[Item::END_PORTAL, 0],
|
||||||
[Item::DANDELION, 0],
|
[Item::DANDELION, 0],
|
||||||
[Item::POPPY, 0],
|
[Item::POPPY, 0],
|
||||||
@ -505,13 +505,14 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var Block[] */
|
/** @var \SplFixedArray */
|
||||||
public static $list = [];
|
public static $list = null;
|
||||||
protected $id;
|
protected $id;
|
||||||
protected $meta;
|
protected $meta;
|
||||||
protected $name = "Unknown";
|
protected $name = "Unknown";
|
||||||
protected $breakTime = 0.20;
|
protected $breakTime = 0.20;
|
||||||
protected $hardness = 10;
|
protected $hardness = 10;
|
||||||
|
public $hasEntityCollision = false;
|
||||||
public $isActivable = false;
|
public $isActivable = false;
|
||||||
public $breakable = true;
|
public $breakable = true;
|
||||||
public $isFlowable = false;
|
public $isFlowable = false;
|
||||||
@ -527,146 +528,149 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
public $z = 0;
|
public $z = 0;
|
||||||
public $frictionFactor = 0.6;
|
public $frictionFactor = 0.6;
|
||||||
|
|
||||||
|
/** @var AxisAlignedBB */
|
||||||
|
protected $boundingBox = null;
|
||||||
|
|
||||||
public static function init(){
|
public static function init(){
|
||||||
if(count(self::$list) === 0){
|
if(self::$list === null){
|
||||||
self::$list = [
|
self::$list = new \SplFixedArray(256);
|
||||||
self::AIR => Air::class,
|
self::$list[self::AIR] = Air::class;;
|
||||||
self::STONE => Stone::class,
|
self::$list[self::STONE] = Stone::class;;
|
||||||
self::GRASS => Grass::class,
|
self::$list[self::GRASS] = Grass::class;;
|
||||||
self::DIRT => Dirt::class,
|
self::$list[self::DIRT] = Dirt::class;;
|
||||||
self::COBBLESTONE => Cobblestone::class,
|
self::$list[self::COBBLESTONE] = Cobblestone::class;;
|
||||||
self::PLANKS => Planks::class,
|
self::$list[self::PLANKS] = Planks::class;;
|
||||||
self::SAPLING => Sapling::class,
|
self::$list[self::SAPLING] = Sapling::class;;
|
||||||
self::BEDROCK => Bedrock::class,
|
self::$list[self::BEDROCK] = Bedrock::class;;
|
||||||
self::WATER => Water::class,
|
self::$list[self::WATER] = Water::class;;
|
||||||
self::STILL_WATER => StillWater::class,
|
self::$list[self::STILL_WATER] = StillWater::class;;
|
||||||
self::LAVA => Lava::class,
|
self::$list[self::LAVA] = Lava::class;;
|
||||||
self::STILL_LAVA => StillLava::class,
|
self::$list[self::STILL_LAVA] = StillLava::class;;
|
||||||
self::SAND => Sand::class,
|
self::$list[self::SAND] = Sand::class;;
|
||||||
self::GRAVEL => Gravel::class,
|
self::$list[self::GRAVEL] = Gravel::class;;
|
||||||
self::GOLD_ORE => GoldOre::class,
|
self::$list[self::GOLD_ORE] = GoldOre::class;;
|
||||||
self::IRON_ORE => IronOre::class,
|
self::$list[self::IRON_ORE] = IronOre::class;;
|
||||||
self::COAL_ORE => CoalOre::class,
|
self::$list[self::COAL_ORE] = CoalOre::class;;
|
||||||
self::WOOD => Wood::class,
|
self::$list[self::WOOD] = Wood::class;;
|
||||||
self::LEAVES => Leaves::class,
|
self::$list[self::LEAVES] = Leaves::class;;
|
||||||
self::SPONGE => Sponge::class,
|
self::$list[self::SPONGE] = Sponge::class;;
|
||||||
self::GLASS => Glass::class,
|
self::$list[self::GLASS] = Glass::class;;
|
||||||
self::LAPIS_ORE => LapisOre::class,
|
self::$list[self::LAPIS_ORE] = LapisOre::class;;
|
||||||
self::LAPIS_BLOCK => Lapis::class,
|
self::$list[self::LAPIS_BLOCK] = Lapis::class;;
|
||||||
self::SANDSTONE => Sandstone::class,
|
self::$list[self::SANDSTONE] = Sandstone::class;;
|
||||||
self::BED_BLOCK => Bed::class,
|
self::$list[self::BED_BLOCK] = Bed::class;;
|
||||||
self::COBWEB => Cobweb::class,
|
self::$list[self::COBWEB] = Cobweb::class;;
|
||||||
self::TALL_GRASS => TallGrass::class,
|
self::$list[self::TALL_GRASS] = TallGrass::class;;
|
||||||
self::DEAD_BUSH => DeadBush::class,
|
self::$list[self::DEAD_BUSH] = DeadBush::class;;
|
||||||
self::WOOL => Wool::class,
|
self::$list[self::WOOL] = Wool::class;;
|
||||||
self::DANDELION => Dandelion::class,
|
self::$list[self::DANDELION] = Dandelion::class;;
|
||||||
self::POPPY => CyanFlower::class,
|
self::$list[self::POPPY] = CyanFlower::class;;
|
||||||
self::BROWN_MUSHROOM => BrownMushroom::class,
|
self::$list[self::BROWN_MUSHROOM] = BrownMushroom::class;;
|
||||||
self::RED_MUSHROOM => RedMushroom::class,
|
self::$list[self::RED_MUSHROOM] = RedMushroom::class;;
|
||||||
self::GOLD_BLOCK => Gold::class,
|
self::$list[self::GOLD_BLOCK] = Gold::class;;
|
||||||
self::IRON_BLOCK => Iron::class,
|
self::$list[self::IRON_BLOCK] = Iron::class;;
|
||||||
self::DOUBLE_SLAB => DoubleSlab::class,
|
self::$list[self::DOUBLE_SLAB] = DoubleSlab::class;;
|
||||||
self::SLAB => Slab::class,
|
self::$list[self::SLAB] = Slab::class;;
|
||||||
self::BRICKS_BLOCK => Bricks::class,
|
self::$list[self::BRICKS_BLOCK] = Bricks::class;;
|
||||||
self::TNT => TNT::class,
|
self::$list[self::TNT] = TNT::class;;
|
||||||
self::BOOKSHELF => Bookshelf::class,
|
self::$list[self::BOOKSHELF] = Bookshelf::class;;
|
||||||
self::MOSS_STONE => MossStone::class,
|
self::$list[self::MOSS_STONE] = MossStone::class;;
|
||||||
self::OBSIDIAN => Obsidian::class,
|
self::$list[self::OBSIDIAN] = Obsidian::class;;
|
||||||
self::TORCH => Torch::class,
|
self::$list[self::TORCH] = Torch::class;;
|
||||||
self::FIRE => Fire::class,
|
self::$list[self::FIRE] = Fire::class;;
|
||||||
self::MONSTER_SPAWNER => MonsterSpawner::class,
|
self::$list[self::MONSTER_SPAWNER] = MonsterSpawner::class;;
|
||||||
self::WOOD_STAIRS => WoodStairs::class,
|
self::$list[self::WOOD_STAIRS] = WoodStairs::class;;
|
||||||
self::CHEST => Chest::class,
|
self::$list[self::CHEST] = Chest::class;;
|
||||||
|
|
||||||
self::DIAMOND_ORE => DiamondOre::class,
|
self::$list[self::DIAMOND_ORE] = DiamondOre::class;;
|
||||||
self::DIAMOND_BLOCK => Diamond::class,
|
self::$list[self::DIAMOND_BLOCK] = Diamond::class;;
|
||||||
self::WORKBENCH => Workbench::class,
|
self::$list[self::WORKBENCH] = Workbench::class;;
|
||||||
self::WHEAT_BLOCK => Wheat::class,
|
self::$list[self::WHEAT_BLOCK] = Wheat::class;;
|
||||||
self::FARMLAND => Farmland::class,
|
self::$list[self::FARMLAND] = Farmland::class;;
|
||||||
self::FURNACE => Furnace::class,
|
self::$list[self::FURNACE] = Furnace::class;;
|
||||||
self::BURNING_FURNACE => BurningFurnace::class,
|
self::$list[self::BURNING_FURNACE] = BurningFurnace::class;;
|
||||||
self::SIGN_POST => SignPost::class,
|
self::$list[self::SIGN_POST] = SignPost::class;;
|
||||||
self::WOOD_DOOR_BLOCK => WoodDoor::class,
|
self::$list[self::WOOD_DOOR_BLOCK] = WoodDoor::class;;
|
||||||
self::LADDER => Ladder::class,
|
self::$list[self::LADDER] = Ladder::class;;
|
||||||
|
|
||||||
self::COBBLESTONE_STAIRS => CobblestoneStairs::class,
|
self::$list[self::COBBLESTONE_STAIRS] = CobblestoneStairs::class;;
|
||||||
self::WALL_SIGN => WallSign::class,
|
self::$list[self::WALL_SIGN] = WallSign::class;;
|
||||||
|
|
||||||
self::IRON_DOOR_BLOCK => IronDoor::class,
|
self::$list[self::IRON_DOOR_BLOCK] = IronDoor::class;;
|
||||||
self::REDSTONE_ORE => RedstoneOre::class,
|
self::$list[self::REDSTONE_ORE] = RedstoneOre::class;;
|
||||||
self::GLOWING_REDSTONE_ORE => GlowingRedstoneOre::class,
|
self::$list[self::GLOWING_REDSTONE_ORE] = GlowingRedstoneOre::class;;
|
||||||
|
|
||||||
self::SNOW_LAYER => SnowLayer::class,
|
self::$list[self::SNOW_LAYER] = SnowLayer::class;;
|
||||||
self::ICE => Ice::class,
|
self::$list[self::ICE] = Ice::class;;
|
||||||
self::SNOW_BLOCK => Snow::class,
|
self::$list[self::SNOW_BLOCK] = Snow::class;;
|
||||||
self::CACTUS => Cactus::class,
|
self::$list[self::CACTUS] = Cactus::class;;
|
||||||
self::CLAY_BLOCK => Clay::class,
|
self::$list[self::CLAY_BLOCK] = Clay::class;;
|
||||||
self::SUGARCANE_BLOCK => Sugarcane::class,
|
self::$list[self::SUGARCANE_BLOCK] = Sugarcane::class;;
|
||||||
|
|
||||||
self::FENCE => Fence::class,
|
self::$list[self::FENCE] = Fence::class;;
|
||||||
self::PUMPKIN => Pumpkin::class,
|
self::$list[self::PUMPKIN] = Pumpkin::class;;
|
||||||
self::NETHERRACK => Netherrack::class,
|
self::$list[self::NETHERRACK] = Netherrack::class;;
|
||||||
self::SOUL_SAND => SoulSand::class,
|
self::$list[self::SOUL_SAND] = SoulSand::class;;
|
||||||
self::GLOWSTONE_BLOCK => Glowstone::class,
|
self::$list[self::GLOWSTONE_BLOCK] = Glowstone::class;;
|
||||||
|
|
||||||
self::LIT_PUMPKIN => LitPumpkin::class,
|
self::$list[self::LIT_PUMPKIN] = LitPumpkin::class;;
|
||||||
self::CAKE_BLOCK => Cake::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::$list[self::IRON_BARS] = IronBars::class;;
|
||||||
self::GLASS_PANE => GlassPane::class,
|
self::$list[self::GLASS_PANE] = GlassPane::class;;
|
||||||
self::MELON_BLOCK => Melon::class,
|
self::$list[self::MELON_BLOCK] = Melon::class;;
|
||||||
self::PUMPKIN_STEM => PumpkinStem::class,
|
self::$list[self::PUMPKIN_STEM] = PumpkinStem::class;;
|
||||||
self::MELON_STEM => MelonStem::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::$list[self::MYCELIUM] = Mycelium::class;;
|
||||||
self::BRICK_STAIRS => BrickStairs::class,
|
self::$list[self::NETHER_BRICKS] = NetherBrick::class;;
|
||||||
self::STONE_BRICK_STAIRS => StoneBrickStairs::class,
|
|
||||||
|
|
||||||
self::MYCELIUM => Mycelium::class,
|
self::$list[self::NETHER_BRICKS_STAIRS] = NetherBrickStairs::class;;
|
||||||
self::NETHER_BRICKS => NetherBrick::class,
|
|
||||||
|
|
||||||
self::NETHER_BRICKS_STAIRS => NetherBrickStairs::class,
|
self::$list[self::END_PORTAL] = EndPortal::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::$list[self::EMERALD_BLOCK] = Emerald::class;;
|
||||||
self::END_STONE => EndStone::class,
|
self::$list[self::SPRUCE_WOOD_STAIRS] = SpruceWoodStairs::class;;
|
||||||
self::SANDSTONE_STAIRS => SandstoneStairs::class,
|
self::$list[self::BIRCH_WOOD_STAIRS] = BirchWoodStairs::class;;
|
||||||
self::EMERALD_ORE => EmeraldOre::class,
|
self::$list[self::JUNGLE_WOOD_STAIRS] = JungleWoodStairs::class;;
|
||||||
|
self::$list[self::STONE_WALL] = StoneWall::class;;
|
||||||
|
|
||||||
self::EMERALD_BLOCK => Emerald::class,
|
self::$list[self::CARROT_BLOCK] = Carrot::class;;
|
||||||
self::SPRUCE_WOOD_STAIRS => SpruceWoodStairs::class,
|
self::$list[self::POTATO_BLOCK] = Potato::class;;
|
||||||
self::BIRCH_WOOD_STAIRS => BirchWoodStairs::class,
|
|
||||||
self::JUNGLE_WOOD_STAIRS => JungleWoodStairs::class,
|
|
||||||
self::STONE_WALL => StoneWall::class,
|
|
||||||
|
|
||||||
self::CARROT_BLOCK => Carrot::class,
|
self::$list[self::QUARTZ_BLOCK] = Quartz::class;;
|
||||||
self::POTATO_BLOCK => Potato::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::$list[self::LEAVES2] = Leaves2::class;;
|
||||||
self::QUARTZ_STAIRS => QuartzStairs::class,
|
self::$list[self::WOOD2] = Wood2::class;;
|
||||||
self::DOUBLE_WOOD_SLAB => DoubleWoodSlab::class,
|
self::$list[self::ACACIA_WOOD_STAIRS] = AcaciaWoodStairs::class;;
|
||||||
self::WOOD_SLAB => WoodSlab::class,
|
self::$list[self::DARK_OAK_WOOD_STAIRS] = DarkOakWoodStairs::class;;
|
||||||
self::STAINED_CLAY => StainedClay::class,
|
|
||||||
|
|
||||||
self::LEAVES2 => Leaves2::class,
|
self::$list[self::HAY_BALE] = HayBale::class;;
|
||||||
self::WOOD2 => Wood2::class,
|
self::$list[self::CARPET] = Carpet::class;;
|
||||||
self::ACACIA_WOOD_STAIRS => AcaciaWoodStairs::class,
|
self::$list[self::HARDENED_CLAY] = HardenedClay::class;;
|
||||||
self::DARK_OAK_WOOD_STAIRS => DarkOakWoodStairs::class,
|
self::$list[self::COAL_BLOCK] = Coal::class;;
|
||||||
|
|
||||||
self::HAY_BALE => HayBale::class,
|
self::$list[self::PODZOL] = Podzol::class;;
|
||||||
self::CARPET => Carpet::class,
|
self::$list[self::BEETROOT_BLOCK] = Beetroot::class;;
|
||||||
self::HARDENED_CLAY => HardenedClay::class,
|
self::$list[self::STONECUTTER] = Stonecutter::class;;
|
||||||
self::COAL_BLOCK => Coal::class,
|
self::$list[self::GLOWING_OBSIDIAN] = GlowingObsidian::class;;
|
||||||
|
self::$list[self::NETHER_REACTOR] = NetherReactor::class;;
|
||||||
|
|
||||||
self::PODZOL => Podzol::class,
|
|
||||||
self::BEETROOT_BLOCK => Beetroot::class,
|
|
||||||
self::STONECUTTER => Stonecutter::class,
|
|
||||||
self::GLOWING_OBSIDIAN => GlowingObsidian::class,
|
|
||||||
self::NETHER_REACTOR => NetherReactor::class,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,15 +682,22 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
* @return Block
|
* @return Block
|
||||||
*/
|
*/
|
||||||
public static function get($id, $meta = 0, Position $pos = null){
|
public static function get($id, $meta = 0, Position $pos = null){
|
||||||
if(isset(self::$list[$id])){
|
try{
|
||||||
$block = self::$list[$id];
|
$block = self::$list[$id];
|
||||||
$block = new $block($meta);
|
if($block !== null){
|
||||||
}else{
|
$block = new $block($meta);
|
||||||
$block = new Generic($id, $meta);
|
}else{
|
||||||
|
$block = new Block($id, $meta);
|
||||||
|
}
|
||||||
|
}catch(\RuntimeException $e){
|
||||||
|
$block = new Block($id, $meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($pos instanceof Position){
|
if($pos !== null){
|
||||||
$block->position($pos);
|
$block->x = $pos->x;
|
||||||
|
$block->y = $pos->y;
|
||||||
|
$block->z = $pos->z;
|
||||||
|
$block->level = $pos->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $block;
|
return $block;
|
||||||
@ -703,6 +714,69 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
$this->name = $name;
|
$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 $this->breakable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 $this->isActivable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -720,10 +794,14 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
final public function getID(){
|
final public function getId(){
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -802,24 +880,6 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
return "Block " . $this->name . " (" . $this->id . ":" . $this->meta . ")";
|
return "Block " . $this->name . " (" . $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
|
* Checks for collision against an AxisAlignedBB
|
||||||
*
|
*
|
||||||
@ -844,6 +904,17 @@ abstract class Block extends Position implements Metadatable{
|
|||||||
* @return AxisAlignedBB
|
* @return AxisAlignedBB
|
||||||
*/
|
*/
|
||||||
public function getBoundingBox(){
|
public function getBoundingBox(){
|
||||||
|
if($this->boundingBox !== null){
|
||||||
|
return $this->boundingBox;
|
||||||
|
}else{
|
||||||
|
return $this->boundingBox = $this->recalculateBoundingBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AxisAlignedBB
|
||||||
|
*/
|
||||||
|
protected function recalculateBoundingBox(){
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -936,41 +1007,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));
|
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){
|
public function setMetadata($metadataKey, MetadataValue $metadataValue){
|
||||||
if($this->getLevel() instanceof Level){
|
if($this->getLevel() instanceof Level){
|
||||||
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue);
|
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue);
|
||||||
|
@ -33,9 +33,8 @@ class BrownMushroom extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,13 @@ class BurningFurnace extends Solid{
|
|||||||
new Int("z", $this->z)
|
new Int("z", $this->z)
|
||||||
]);
|
]);
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
$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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onBreak(Item $item){
|
public function onBreak(Item $item){
|
||||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ class BurningFurnace extends Solid{
|
|||||||
new Int("z", $this->z)
|
new Int("z", $this->z)
|
||||||
]);
|
]);
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
$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){
|
if(($player->getGamemode() & 0x01) === 0x01){
|
||||||
@ -116,15 +116,6 @@ class BurningFurnace extends Solid{
|
|||||||
if($item->isPickaxe() >= 1){
|
if($item->isPickaxe() >= 1){
|
||||||
$drops[] = [Item::FURNACE, 0, 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;
|
return $drops;
|
||||||
}
|
}
|
||||||
|
@ -21,23 +21,29 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
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\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3 as Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\entity\Entity;
|
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Cactus extends Transparent{
|
class Cactus extends Transparent{
|
||||||
|
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::CACTUS, $meta, "Cactus");
|
parent::__construct(self::CACTUS, $meta, "Cactus");
|
||||||
$this->isFullBlock = false;
|
$this->isFullBlock = false;
|
||||||
$this->hardness = 2;
|
$this->hardness = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -49,29 +55,20 @@ class Cactus extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity){
|
||||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
$entity->attack($ev->getFinalDamage(), $ev);
|
||||||
if(!$ev->isCancelled()){
|
|
||||||
$entity->attack($ev->getFinalDamage(), $ev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$down = $this->getSide(0);
|
$down = $this->getSide(0);
|
||||||
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){ //Replace with common break method
|
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){
|
||||||
$this->getLevel()->setBlock($this, new Air(), false);
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}else{
|
}else{
|
||||||
for($side = 2; $side <= 5; ++$side){
|
for($side = 2; $side <= 5; ++$side){
|
||||||
$b = $this->getSide($side);
|
$b = $this->getSide($side);
|
||||||
if(!$b->isFlowable){
|
if(!$b->isFlowable){
|
||||||
$this->getLevel()->setBlock($this, new Air(), false);
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,8 +78,10 @@ class Cactus extends Transparent{
|
|||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||||
if($b->getID() === self::AIR){
|
if($b->getID() === self::AIR){
|
||||||
$this->getLevel()->setBlock($b, new Cactus(), true);
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Cactus()));
|
||||||
break;
|
if(!$ev->isCancelled()){
|
||||||
|
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->meta = 0;
|
$this->meta = 0;
|
||||||
@ -91,8 +90,6 @@ class Cactus extends Transparent{
|
|||||||
++$this->meta;
|
++$this->meta;
|
||||||
$this->getLevel()->setBlock($this, $this);
|
$this->getLevel()->setBlock($this, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,10 +21,12 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Cake extends Transparent{
|
class Cake extends Transparent{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
@ -35,7 +37,8 @@ class Cake extends Transparent{
|
|||||||
$this->hardness = 2.5;
|
$this->hardness = 2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$f = (1 + $this->getDamage() * 2) / 16;
|
$f = (1 + $this->getDamage() * 2) / 16;
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
@ -78,7 +81,10 @@ class Cake extends Transparent{
|
|||||||
public function onActivate(Item $item, Player $player = null){
|
public function onActivate(Item $item, Player $player = null){
|
||||||
if($player instanceof Player and $player->getHealth() < 20){
|
if($player instanceof Player and $player->getHealth() < 20){
|
||||||
++$this->meta;
|
++$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){
|
if($this->meta >= 0x06){
|
||||||
$this->getLevel()->setBlock($this, new Air(), true);
|
$this->getLevel()->setBlock($this, new Air(), true);
|
||||||
}else{
|
}else{
|
||||||
|
@ -53,7 +53,8 @@ class Carpet extends Flowable{
|
|||||||
$this->isSolid = true;
|
$this->isSolid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
@ -77,9 +78,8 @@ class Carpet extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->getID() === self::AIR){ //TODO: Replace with common break method
|
if($this->getSide(0)->getID() === self::AIR){
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta, 1));
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->setBlock($this, new Air(), true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -22,67 +22,10 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
|
||||||
use pocketmine\Player;
|
|
||||||
|
|
||||||
class Carrot extends Flowable{
|
class Carrot extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::CARROT_BLOCK, $meta, "Carrot Block");
|
parent::__construct(self::CARROT_BLOCK, $meta, "Carrot Block");
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
|
@ -42,13 +42,14 @@ class Chest extends Transparent{
|
|||||||
$this->hardness = 15;
|
$this->hardness = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x + 0.0625,
|
$this->x + 0.0625,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 0.0625,
|
$this->z + 0.0625,
|
||||||
$this->x + 0.9375,
|
$this->x + 0.9375,
|
||||||
$this->y + 0.875,
|
$this->y + 0.9475,
|
||||||
$this->z + 0.9375
|
$this->z + 0.9375
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -61,7 +62,7 @@ class Chest extends Transparent{
|
|||||||
3 => 3,
|
3 => 3,
|
||||||
];
|
];
|
||||||
|
|
||||||
$chest = false;
|
$chest = null;
|
||||||
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
$this->meta = $faces[$player instanceof Player ? $player->getDirection() : 0];
|
||||||
|
|
||||||
for($side = 2; $side <= 5; ++$side){
|
for($side = 2; $side <= 5; ++$side){
|
||||||
@ -89,9 +90,9 @@ class Chest extends Transparent{
|
|||||||
new Int("z", $this->z)
|
new Int("z", $this->z)
|
||||||
]);
|
]);
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
$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);
|
$chest->pairWith($tile);
|
||||||
$tile->pairWith($chest);
|
$tile->pairWith($chest);
|
||||||
}
|
}
|
||||||
@ -104,7 +105,7 @@ class Chest extends Transparent{
|
|||||||
if($t instanceof TileChest){
|
if($t instanceof TileChest){
|
||||||
$t->unpair();
|
$t->unpair();
|
||||||
}
|
}
|
||||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -129,11 +130,11 @@ class Chest extends Transparent{
|
|||||||
new Int("z", $this->z)
|
new Int("z", $this->z)
|
||||||
]);
|
]);
|
||||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
$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;
|
return true;
|
||||||
}
|
}
|
||||||
$player->addWindow($chest->getInventory());
|
$player->addWindow($chest->getInventory());
|
||||||
@ -143,19 +144,8 @@ class Chest extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
$drops = [
|
return [
|
||||||
[$this->id, 0, 1],
|
[$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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,10 +21,13 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
|
||||||
class Cobweb extends Flowable{
|
class Cobweb extends Flowable{
|
||||||
|
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
parent::__construct(self::COBWEB, 0, "Cobweb");
|
parent::__construct(self::COBWEB, 0, "Cobweb");
|
||||||
$this->isSolid = true;
|
$this->isSolid = true;
|
||||||
|
100
src/pocketmine/block/Crops.php
Normal file
100
src/pocketmine/block/Crops.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?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 $isActivable = true;
|
||||||
|
public $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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -49,9 +49,8 @@ class CyanFlower extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id, 0, 1));
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,8 @@ class Dandelion extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ abstract class Door extends Transparent{
|
|||||||
return $first & 0x07 | ($flag ? 8 : 0) | ($flag1 ? 0x10 : 0);
|
return $first & 0x07 | ($flag ? 8 : 0) | ($flag1 ? 0x10 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$f = 0.1875;
|
$f = 0.1875;
|
||||||
$damage = $this->getFullDamage();
|
$damage = $this->getFullDamage();
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ abstract class Door extends Transparent{
|
|||||||
if($j === 0){
|
if($j === 0){
|
||||||
if($flag){
|
if($flag){
|
||||||
if(!$flag1){
|
if(!$flag1){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -81,7 +82,7 @@ abstract class Door extends Transparent{
|
|||||||
$this->z + $f
|
$this->z + $f
|
||||||
);
|
);
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 1 - $f,
|
$this->z + 1 - $f,
|
||||||
@ -91,7 +92,7 @@ abstract class Door extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -103,7 +104,7 @@ abstract class Door extends Transparent{
|
|||||||
}elseif($j === 1){
|
}elseif($j === 1){
|
||||||
if($flag){
|
if($flag){
|
||||||
if(!$flag1){
|
if(!$flag1){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x + 1 - $f,
|
$this->x + 1 - $f,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -112,7 +113,7 @@ abstract class Door extends Transparent{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -122,7 +123,7 @@ abstract class Door extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -134,7 +135,7 @@ abstract class Door extends Transparent{
|
|||||||
}elseif($j === 2){
|
}elseif($j === 2){
|
||||||
if($flag){
|
if($flag){
|
||||||
if(!$flag1){
|
if(!$flag1){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 1 - $f,
|
$this->z + 1 - $f,
|
||||||
@ -143,7 +144,7 @@ abstract class Door extends Transparent{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -153,7 +154,7 @@ abstract class Door extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x + 1 - $f,
|
$this->x + 1 - $f,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -165,7 +166,7 @@ abstract class Door extends Transparent{
|
|||||||
}elseif($j === 3){
|
}elseif($j === 3){
|
||||||
if($flag){
|
if($flag){
|
||||||
if(!$flag1){
|
if(!$flag1){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -174,7 +175,7 @@ abstract class Door extends Transparent{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x + 1 - $f,
|
$this->x + 1 - $f,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -184,7 +185,7 @@ abstract class Door extends Transparent{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 1 - $f,
|
$this->z + 1 - $f,
|
||||||
@ -270,7 +271,7 @@ abstract class Door extends Transparent{
|
|||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
unset($players[$player->getID()]);
|
unset($players[$player->getID()]);
|
||||||
}
|
}
|
||||||
$pk = new LevelEventPacket;
|
$pk = new LevelEventPacket();
|
||||||
$pk->x = $this->x;
|
$pk->x = $this->x;
|
||||||
$pk->y = $this->y;
|
$pk->y = $this->y;
|
||||||
$pk->z = $this->z;
|
$pk->z = $this->z;
|
||||||
@ -289,7 +290,7 @@ abstract class Door extends Transparent{
|
|||||||
if($player instanceof Player){
|
if($player instanceof Player){
|
||||||
unset($players[$player->getID()]);
|
unset($players[$player->getID()]);
|
||||||
}
|
}
|
||||||
$pk = new LevelEventPacket;
|
$pk = new LevelEventPacket();
|
||||||
$pk->x = $this->x;
|
$pk->x = $this->x;
|
||||||
$pk->y = $this->y;
|
$pk->y = $this->y;
|
||||||
$pk->z = $this->z;
|
$pk->z = $this->z;
|
||||||
|
@ -29,7 +29,8 @@ class EndPortal extends Solid{
|
|||||||
$this->hardness = 18000000;
|
$this->hardness = 18000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
|
@ -21,17 +21,18 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\Player;
|
|
||||||
use pocketmine\level\Level;
|
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\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{
|
abstract class Fallable extends Solid{
|
||||||
|
|
||||||
public $hasPhysics = true;
|
public $hasPhysics = true;
|
||||||
|
|
||||||
@ -45,13 +46,12 @@ class Fallable extends Solid{
|
|||||||
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
|
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$down = $this->getSide(0);
|
$down = $this->getSide(0);
|
||||||
if($down->getID() === self::AIR or ($down instanceof Liquid)){
|
if($down->getID() === self::AIR or ($down instanceof Liquid)){
|
||||||
$fall = new FallingBlock($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), new Compound("", [
|
$fall = Entity::createEntity("FallingSand", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||||
"Pos" => new Enum("Pos", [
|
"Pos" => new Enum("Pos", [
|
||||||
new Double("", $this->x + 0.5),
|
new Double("", $this->x + 0.5),
|
||||||
new Double("", $this->y + 0.5),
|
new Double("", $this->y),
|
||||||
new Double("", $this->z + 0.5)
|
new Double("", $this->z + 0.5)
|
||||||
]),
|
]),
|
||||||
//TODO: add random motion with physics
|
|
||||||
"Motion" => new Enum("Motion", [
|
"Motion" => new Enum("Motion", [
|
||||||
new Double("", 0),
|
new Double("", 0),
|
||||||
new Double("", 0),
|
new Double("", 0),
|
||||||
@ -61,13 +61,12 @@ class Fallable extends Solid{
|
|||||||
new Float("", 0),
|
new Float("", 0),
|
||||||
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();
|
$fall->spawnToAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,7 +30,8 @@ class Farmland extends Solid{
|
|||||||
$this->hardness = 3;
|
$this->hardness = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
|
@ -23,7 +23,6 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
|
||||||
|
|
||||||
class Fence extends Transparent{
|
class Fence extends Transparent{
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
@ -32,7 +31,8 @@ class Fence extends Transparent{
|
|||||||
$this->hardness = 15;
|
$this->hardness = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$flag = $this->canConnect($this->getSide(2));
|
$flag = $this->canConnect($this->getSide(2));
|
||||||
$flag1 = $this->canConnect($this->getSide(3));
|
$flag1 = $this->canConnect($this->getSide(3));
|
||||||
$flag2 = $this->canConnect($this->getSide(4));
|
$flag2 = $this->canConnect($this->getSide(4));
|
||||||
@ -48,7 +48,7 @@ class Fence extends Transparent{
|
|||||||
$this->y,
|
$this->y,
|
||||||
$this->z + $f2,
|
$this->z + $f2,
|
||||||
$this->x + $f1,
|
$this->x + $f1,
|
||||||
$this->y + 1, //TODO: check this, add extra bounding box
|
$this->y + 1,
|
||||||
$this->z + $f3
|
$this->z + $f3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,8 @@ class FenceGate extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
if(($this->getDamage() & 0x04) > 0){
|
if(($this->getDamage() & 0x04) > 0){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,18 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\entity\Entity;
|
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\event\entity\EntityDamageEvent;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Fire extends Flowable{
|
class Fire extends Flowable{
|
||||||
|
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::FIRE, $meta, "Fire");
|
parent::__construct(self::FIRE, $meta, "Fire");
|
||||||
$this->isReplaceable = true;
|
$this->isReplaceable = true;
|
||||||
@ -41,11 +46,13 @@ class Fire extends Flowable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity){
|
||||||
$entity->setOnFire(8);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
$entity->attack($ev->getFinalDamage(), $ev);
|
||||||
|
|
||||||
|
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$entity->attack($ev->getFinalDamage(), $ev);
|
$entity->setOnFire($ev->getDuration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class Flowable extends Transparent{
|
abstract class Flowable extends Transparent{
|
||||||
|
|
||||||
public $isFlowable = true;
|
public $isFlowable = true;
|
||||||
public $isFullBlock = false;
|
public $isFullBlock = false;
|
||||||
|
@ -21,11 +21,13 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\BlockSpreadEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\level\Position;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\Server;
|
||||||
use pocketmine\utils\Random;
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
class Grass extends Solid{
|
class Grass extends Solid{
|
||||||
@ -52,11 +54,13 @@ class Grass extends Solid{
|
|||||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
$block = $this->getLevel()->getBlockIdAt($x, $y, $z);
|
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||||
if($block === Block::DIRT){
|
if($block->getID() === Block::DIRT){
|
||||||
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
|
|
||||||
if($block->getSide(1) instanceof Transparent){
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,16 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\entity\Entity;
|
|
||||||
|
|
||||||
class Ladder extends Transparent{
|
class Ladder extends Transparent{
|
||||||
|
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::LADDER, $meta, "Ladder");
|
parent::__construct(self::LADDER, $meta, "Ladder");
|
||||||
$this->isSolid = false;
|
$this->isSolid = false;
|
||||||
@ -37,9 +40,11 @@ class Ladder extends Transparent{
|
|||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity){
|
||||||
$entity->fallDistance = 0;
|
$entity->fallDistance = 0;
|
||||||
|
$entity->onGround = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$f = 0.125;
|
$f = 0.125;
|
||||||
|
|
||||||
if($this->meta === 2){
|
if($this->meta === 2){
|
||||||
|
@ -21,150 +21,42 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||||
use pocketmine\level\Position;
|
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||||
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
|
use pocketmine\item\Item;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
|
||||||
|
|
||||||
class Lava extends Liquid{
|
class Lava extends Liquid{
|
||||||
|
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::LAVA, $meta, "Lava");
|
parent::__construct(self::LAVA, $meta, "Lava");
|
||||||
$this->hardness = 0;
|
$this->hardness = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity){
|
||||||
$entity->setOnFire(15);
|
$entity->fallDistance *= 0.5;
|
||||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
$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);
|
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||||
if(!$ev->isCancelled()){
|
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){
|
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||||
$ret = $this->getLevel()->setBlock($this, $this, true);
|
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||||
$this->getLevel()->scheduleUpdate(clone $this, 40);
|
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||||
|
|
||||||
return $ret;
|
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;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\LeavesDecayEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Leaves extends Transparent{
|
class Leaves extends Transparent{
|
||||||
const OAK = 0;
|
const OAK = 0;
|
||||||
@ -121,16 +123,13 @@ class Leaves extends Transparent{
|
|||||||
$this->meta &= 0x03;
|
$this->meta &= 0x03;
|
||||||
$visited = [];
|
$visited = [];
|
||||||
$check = 0;
|
$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{
|
}else{
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
$this->getLevel()->useBreakOn($this);
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\LeavesDecayEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Leaves2 extends Leaves{
|
class Leaves2 extends Leaves{
|
||||||
|
|
||||||
@ -113,13 +115,13 @@ class Leaves2 extends Leaves{
|
|||||||
$this->meta &= 0x03;
|
$this->meta &= 0x03;
|
||||||
$visited = [];
|
$visited = [];
|
||||||
$check = 0;
|
$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{
|
}else{
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
$this->getLevel()->useBreakOn($this);
|
||||||
if(mt_rand(1, 20) === 1){ //Saplings
|
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,24 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class Liquid extends Transparent{
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
|
abstract class Liquid extends Transparent{
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
public $isLiquid = true;
|
public $isLiquid = true;
|
||||||
public $breakable = false;
|
public $breakable = false;
|
||||||
public $isReplaceable = true;
|
public $isReplaceable = true;
|
||||||
public $isSolid = false;
|
public $isSolid = false;
|
||||||
public $isFullBlock = true;
|
public $isFullBlock = true;
|
||||||
|
|
||||||
|
public $adjacentSources = 0;
|
||||||
|
public $isOptimalFlowDirection = [0, 0, 0, 0];
|
||||||
|
public $flowCost = [0, 0, 0, 0];
|
||||||
|
|
||||||
public function getFluidHeightPercent(){
|
public function getFluidHeightPercent(){
|
||||||
$d = $this->meta;
|
$d = $this->meta;
|
||||||
if($d >= 8){
|
if($d >= 8){
|
||||||
@ -37,4 +48,374 @@ class Liquid extends Transparent{
|
|||||||
|
|
||||||
return ($d + 1) / 9;
|
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);
|
||||||
|
|
||||||
|
$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(new Vector3($x, $y, $z));
|
||||||
|
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
|
||||||
|
|
||||||
|
if($blockDecay < 0){
|
||||||
|
if(!$sideBlock->isFlowable){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$blockDecay = $this->getEffectiveFlowDecay($sideBlock->getSide(0));
|
||||||
|
|
||||||
|
if($blockDecay >= 0){
|
||||||
|
$realDecay = $blockDecay - ($decay - 8);
|
||||||
|
$vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}else{
|
||||||
|
$realDecay = $blockDecay - $decay;
|
||||||
|
$vector = $vector->add(($sideBlock->x - $this->x) * $realDecay, ($sideBlock->y - $this->y) * $realDecay, ($sideBlock->z - $this->z) * $realDecay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->getDamage() >= 8){
|
||||||
|
$falling = false;
|
||||||
|
|
||||||
|
if(!$this->getLevel()->getBlock($this->add(0, 0, -1))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(0, 0, 1))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(-1, 0, 0))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(1, 0, 0))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(0, 1, -1))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(0, 1, 1))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(-1, 1, 0))->isFlowable){
|
||||||
|
$falling = true;
|
||||||
|
}elseif(!$this->getLevel()->getBlock($this->add(1, 1, 0))->isFlowable){
|
||||||
|
$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){
|
||||||
|
$decay = $this->getFlowDecay($this);
|
||||||
|
$multiplier = $this instanceof Lava ? 2 : 1;
|
||||||
|
|
||||||
|
$flag = true;
|
||||||
|
|
||||||
|
if($decay > 0){
|
||||||
|
$smallestFlowDecay = -100;
|
||||||
|
$this->adjacentSources = 0;
|
||||||
|
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(4), $smallestFlowDecay);
|
||||||
|
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(5), $smallestFlowDecay);
|
||||||
|
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(2), $smallestFlowDecay);
|
||||||
|
$smallestFlowDecay = $this->getSmallestFlowDecay($this->getSide(3), $smallestFlowDecay);
|
||||||
|
|
||||||
|
$k = $smallestFlowDecay + $multiplier;
|
||||||
|
|
||||||
|
if($k >= 8 or $smallestFlowDecay < 0){
|
||||||
|
$k = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($topFlowDecay = $this->getFlowDecay($this->getSide(1))) >= 0){
|
||||||
|
if($topFlowDecay >= 8){
|
||||||
|
$k = $topFlowDecay;
|
||||||
|
}else{
|
||||||
|
$k = $topFlowDecay | 0x08;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->adjacentSources >= 2 and $this instanceof Water){
|
||||||
|
$bottomBlock = $this->getSide(0);
|
||||||
|
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, Block::get(Item::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->getSide(0);
|
||||||
|
|
||||||
|
if($bottomBlock->isFlowable 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->isFlowable)){
|
||||||
|
$flags = $this->getOptimalFlowDirections();
|
||||||
|
|
||||||
|
$l = $decay + $multiplier;
|
||||||
|
|
||||||
|
if($decay >= 8){
|
||||||
|
$l = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($l >= 8){
|
||||||
|
$this->checkForHarden();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($flags[0]){
|
||||||
|
$this->flowIntoBlock($this->getSide(4), $l);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($flags[1]){
|
||||||
|
$this->flowIntoBlock($this->getSide(5), $l);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($flags[2]){
|
||||||
|
$this->flowIntoBlock($this->getSide(2), $l);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($flags[3]){
|
||||||
|
$this->flowIntoBlock($this->getSide(3), $l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkForHarden();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function flowIntoBlock(Block $block, $newFlowDecay){
|
||||||
|
if($block->isFlowable){
|
||||||
|
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(new Vector3($x, $y, $z));
|
||||||
|
|
||||||
|
if(!$blockSide->isFlowable and !($blockSide instanceof Liquid)){
|
||||||
|
continue;
|
||||||
|
}elseif($blockSide instanceof Liquid and $blockSide->getDamage() === 0){
|
||||||
|
continue;
|
||||||
|
}elseif($blockSide->getSide(0)->isFlowable){
|
||||||
|
return $accumulatedCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($accumulatedCost >= 4){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$realCost = $this->calculateFlowCost($blockSide, $accumulatedCost + 1, $j);
|
||||||
|
|
||||||
|
if($realCost < $cost){
|
||||||
|
$cost = $realCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOptimalFlowDirections(){
|
||||||
|
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(new Vector3($x, $y, $z));
|
||||||
|
|
||||||
|
if(!$block->isFlowable and !($block instanceof Liquid)){
|
||||||
|
continue;
|
||||||
|
}elseif($block instanceof Liquid and $block->getDamage() === 0){
|
||||||
|
continue;
|
||||||
|
}elseif($block->getSide(0)->isFlowable){
|
||||||
|
$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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,46 +21,31 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\BlockGrowEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Player;
|
use pocketmine\Server;
|
||||||
|
|
||||||
class MelonStem extends Flowable{
|
class MelonStem extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::MELON_STEM, $meta, "Melon Stem");
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
$this->getLevel()->dropItem($this, Item::get(Item::MELON_SEEDS, 0, mt_rand(0, 2)));
|
$this->getLevel()->useBreakOn($this);
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||||
if(mt_rand(0, 2) == 1){
|
if(mt_rand(0, 2) == 1){
|
||||||
if($this->meta < 0x07){
|
if($this->meta < 0x07){
|
||||||
++$this->meta;
|
$block = clone $this;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
++$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;
|
return Level::BLOCK_UPDATE_RANDOM;
|
||||||
}else{
|
}else{
|
||||||
@ -73,7 +58,10 @@ class MelonStem extends Flowable{
|
|||||||
$side = $this->getSide(mt_rand(2, 5));
|
$side = $this->getSide(mt_rand(2, 5));
|
||||||
$d = $side->getSide(0);
|
$d = $side->getSide(0);
|
||||||
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
|
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);
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($side, new Melon()));
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,20 +72,6 @@ class MelonStem extends Flowable{
|
|||||||
return false;
|
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){
|
public function getDrops(Item $item){
|
||||||
return [
|
return [
|
||||||
[Item::MELON_SEEDS, 0, mt_rand(0, 2)],
|
[Item::MELON_SEEDS, 0, mt_rand(0, 2)],
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\BlockSpreadEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\level\Position;
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Mycelium extends Solid{
|
class Mycelium extends Solid{
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
@ -43,11 +45,13 @@ class Mycelium extends Solid{
|
|||||||
$x = mt_rand($this->x - 1, $this->x + 1);
|
$x = mt_rand($this->x - 1, $this->x + 1);
|
||||||
$y = mt_rand($this->y - 2, $this->y + 2);
|
$y = mt_rand($this->y - 2, $this->y + 2);
|
||||||
$z = mt_rand($this->z - 1, $this->z + 1);
|
$z = mt_rand($this->z - 1, $this->z + 1);
|
||||||
$block = $this->getLevel()->getBlockIdAt($x, $y, $z);
|
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||||
if($block === Block::DIRT){
|
if($block->getID() === Block::DIRT){
|
||||||
$block = Block::get($block, $this->getLevel()->getBlockDataAt($x, $y, $z), new Position($x, $y, $z, $this->getLevel()));
|
|
||||||
if($block->getSide(1) instanceof Transparent){
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,68 +22,10 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
|
||||||
use pocketmine\Player;
|
|
||||||
|
|
||||||
class Potato extends Flowable{
|
class Potato extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::POTATO_BLOCK, $meta, "Potato Block");
|
parent::__construct(self::POTATO_BLOCK, $meta, "Potato Block");
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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::POTATO, 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 getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
|
@ -21,47 +21,31 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\BlockGrowEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\Player;
|
use pocketmine\Server;
|
||||||
|
|
||||||
class PumpkinStem extends Flowable{
|
class PumpkinStem extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::PUMPKIN_STEM, $meta, "Pumpkin Stem");
|
parent::__construct(self::PUMPKIN_STEM, $meta, "Pumpkin 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get(PUMPKIN_SEEDS, 0, mt_rand(0, 2)));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||||
if(mt_rand(0, 2) == 1){
|
if(mt_rand(0, 2) == 1){
|
||||||
if($this->meta < 0x07){
|
if($this->meta < 0x07){
|
||||||
++$this->meta;
|
$block = clone $this;
|
||||||
$this->getLevel()->setBlock($this, $this, true);
|
++$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;
|
return Level::BLOCK_UPDATE_RANDOM;
|
||||||
}else{
|
}else{
|
||||||
@ -74,7 +58,10 @@ class PumpkinStem extends Flowable{
|
|||||||
$side = $this->getSide(mt_rand(2, 5));
|
$side = $this->getSide(mt_rand(2, 5));
|
||||||
$d = $side->getSide(0);
|
$d = $side->getSide(0);
|
||||||
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
|
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 Pumpkin(), true);
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($side, new Pumpkin()));
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$this->getLevel()->setBlock($side, $ev->getNewState(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,20 +72,6 @@ class PumpkinStem extends Flowable{
|
|||||||
return false;
|
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){
|
public function getDrops(Item $item){
|
||||||
return [
|
return [
|
||||||
[Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2)],
|
[Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2)],
|
||||||
|
@ -38,10 +38,8 @@ class RedMushroom extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), false);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,8 @@ class Sapling extends Flowable{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
if($this->getSide(0)->isTransparent === true){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,8 @@ class SignPost extends Transparent{
|
|||||||
|
|
||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
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){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get(SIGN, 0, 1));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,8 @@ class Slab extends Transparent{
|
|||||||
$this->hardness = 30;
|
$this->hardness = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
if(($this->meta & 0x08) > 0){
|
if(($this->meta & 0x08) > 0){
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
|
||||||
class Solid extends Generic{
|
abstract class Solid extends Block{
|
||||||
|
|
||||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||||
parent::__construct($id, $meta, $name);
|
parent::__construct($id, $meta, $name);
|
||||||
|
@ -30,7 +30,8 @@ class SoulSand extends Solid{
|
|||||||
$this->hardness = 2.5;
|
$this->hardness = 2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
|
@ -25,7 +25,7 @@ use pocketmine\item\Item;
|
|||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Stair extends Transparent{
|
abstract class Stair extends Transparent{
|
||||||
|
|
||||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||||
parent::__construct($id, $meta, $name);
|
parent::__construct($id, $meta, $name);
|
||||||
@ -54,7 +54,7 @@ class Stair extends Transparent{
|
|||||||
$f3 = 0.5;
|
$f3 = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
|
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y + $f,
|
$this->y + $f,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -66,7 +66,7 @@ class Stair extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($j === 0){
|
if($j === 0){
|
||||||
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
|
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||||
$this->x + 0.5,
|
$this->x + 0.5,
|
||||||
$this->y + $f2,
|
$this->y + $f2,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -77,7 +77,7 @@ class Stair extends Transparent{
|
|||||||
$list[] = $bb2;
|
$list[] = $bb2;
|
||||||
}
|
}
|
||||||
}elseif($j === 1){
|
}elseif($j === 1){
|
||||||
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
|
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y + $f2,
|
$this->y + $f2,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -88,7 +88,7 @@ class Stair extends Transparent{
|
|||||||
$list[] = $bb2;
|
$list[] = $bb2;
|
||||||
}
|
}
|
||||||
}elseif($j === 2){
|
}elseif($j === 2){
|
||||||
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
|
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y + $f2,
|
$this->y + $f2,
|
||||||
$this->z + 0.5,
|
$this->z + 0.5,
|
||||||
@ -99,7 +99,7 @@ class Stair extends Transparent{
|
|||||||
$list[] = $bb2;
|
$list[] = $bb2;
|
||||||
}
|
}
|
||||||
}elseif($j === 3){
|
}elseif($j === 3){
|
||||||
if($bb->intersectsWith($bb2 = new AxisAlignedBB(
|
if($bb->intersectsWith($bb2 = AxisAlignedBB::getBoundingBoxFromPool(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y + $f2,
|
$this->y + $f2,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -113,7 +113,8 @@ class Stair extends Transparent{
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
if(($this->getDamage() & 0x04) > 0){
|
if(($this->getDamage() & 0x04) > 0){
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -21,28 +21,10 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
class StillLava extends Lava{
|
||||||
use pocketmine\Server;
|
|
||||||
use pocketmine\entity\Entity;
|
|
||||||
|
|
||||||
class StillLava extends Liquid{
|
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::STILL_LAVA, $meta, "Still Lava");
|
parent::__construct(self::STILL_LAVA, $meta, "Still Lava");
|
||||||
$this->hardness = 500;
|
$this->hardness = 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
|
||||||
$entity->setOnFire(15);
|
|
||||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
|
||||||
if(!$ev->isCancelled()){
|
|
||||||
$entity->attack($ev->getFinalDamage(), $ev);
|
|
||||||
}
|
|
||||||
$entity->attack(4, EntityDamageEvent::CAUSE_LAVA);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -22,6 +22,7 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\Tool;
|
||||||
|
|
||||||
class Stone extends Solid{
|
class Stone extends Solid{
|
||||||
const NORMAL = 0;
|
const NORMAL = 0;
|
||||||
@ -45,6 +46,7 @@ class Stone extends Solid{
|
|||||||
self::POLISHED_DIORITE => "Polished Diorite",
|
self::POLISHED_DIORITE => "Polished Diorite",
|
||||||
self::ANDESITE => "Andesite",
|
self::ANDESITE => "Andesite",
|
||||||
self::POLISHED_ANDESITE => "Polished Andesite",
|
self::POLISHED_ANDESITE => "Polished Andesite",
|
||||||
|
7 => "Unknown Stone",
|
||||||
];
|
];
|
||||||
$this->name = $names[$this->meta & 0x07];
|
$this->name = $names[$this->meta & 0x07];
|
||||||
}
|
}
|
||||||
@ -67,7 +69,7 @@ class Stone extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
if($item->isPickaxe() >= 1){
|
if($item->isPickaxe() >= Tool::TIER_WOODEN){
|
||||||
return [
|
return [
|
||||||
[Item::COBBLESTONE, 0, 1],
|
[Item::COBBLESTONE, 0, 1],
|
||||||
];
|
];
|
||||||
|
@ -36,7 +36,8 @@ class StoneWall extends Transparent{
|
|||||||
$this->hardness = 30;
|
$this->hardness = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$flag = $this->canConnect($this->getSide(2));
|
$flag = $this->canConnect($this->getSide(2));
|
||||||
$flag1 = $this->canConnect($this->getSide(3));
|
$flag1 = $this->canConnect($this->getSide(3));
|
||||||
$flag2 = $this->canConnect($this->getSide(4));
|
$flag2 = $this->canConnect($this->getSide(4));
|
||||||
|
@ -21,10 +21,12 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\event\block\BlockGrowEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\math\Vector3 as Vector3;
|
use pocketmine\math\Vector3 as Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
class Sugarcane extends Flowable{
|
class Sugarcane extends Flowable{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
@ -49,7 +51,10 @@ class Sugarcane extends Flowable{
|
|||||||
for($y = 1; $y < 3; ++$y){
|
for($y = 1; $y < 3; ++$y){
|
||||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||||
if($b->getID() === self::AIR){
|
if($b->getID() === self::AIR){
|
||||||
$this->getLevel()->setBlock($b, new Sugarcane(), true);
|
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Sugarcane()));
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,10 +74,8 @@ class Sugarcane extends Flowable{
|
|||||||
public function onUpdate($type){
|
public function onUpdate($type){
|
||||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
$down = $this->getSide(0);
|
$down = $this->getSide(0);
|
||||||
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){ //Replace with common break method
|
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get(SUGARCANE));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,15 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\entity\Entity;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
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\Player;
|
use pocketmine\Player;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
class TNT extends Solid{
|
class TNT extends Solid{
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
@ -33,20 +40,29 @@ class TNT extends Solid{
|
|||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null){
|
public function onActivate(Item $item, Player $player = null){
|
||||||
if($item->getID() === Item::FLINT_STEEL){
|
if($item->getID() === Item::FLINT_STEEL){
|
||||||
if(($player->gamemode & 0x01) === 0){
|
$item->useOn($this);
|
||||||
$item->useOn($this);
|
$this->getLevel()->setBlock($this, new Air(), true);
|
||||||
}
|
|
||||||
$data = [
|
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||||
"x" => $this->x + 0.5,
|
$tnt = Entity::createEntity("PrimedTNT", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||||
"y" => $this->y + 0.5,
|
"Pos" => new Enum("Pos", [
|
||||||
"z" => $this->z + 0.5,
|
new Double("", $this->x + 0.5),
|
||||||
"power" => 4,
|
new Double("", $this->y),
|
||||||
"fuse" => 20 * 4, //4 seconds
|
new Double("", $this->z + 0.5)
|
||||||
];
|
]),
|
||||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
"Motion" => new Enum("Motion", [
|
||||||
//TODO
|
new Double("", -sin($mot) * 0.02),
|
||||||
//$e = Server::getInstance()->api->entity->add($this->level, ENTITY_OBJECT, OBJECT_PRIMEDTNT, $data);
|
new Double("", 0.2),
|
||||||
//$e->spawnToAll();
|
new Double("", -cos($mot) * 0.02)
|
||||||
|
]),
|
||||||
|
"Rotation" => new Enum("Rotation", [
|
||||||
|
new Float("", 0),
|
||||||
|
new Float("", 0)
|
||||||
|
]),
|
||||||
|
"Fuse" => new Byte("Fuse", 80)
|
||||||
|
]));
|
||||||
|
|
||||||
|
$tnt->spawnToAll();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,13 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
|
||||||
class Thin extends Transparent{
|
abstract class Thin extends Transparent{
|
||||||
|
|
||||||
public $isFullBlock = false;
|
public $isFullBlock = false;
|
||||||
public $isSolid = false;
|
public $isSolid = false;
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$f = 0.4375;
|
$f = 0.4375;
|
||||||
$f1 = 0.5625;
|
$f1 = 0.5625;
|
||||||
$f2 = 0.4375;
|
$f2 = 0.4375;
|
||||||
|
@ -49,10 +49,8 @@ class Torch extends Flowable{
|
|||||||
0 => 0,
|
0 => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){ //Replace with common break method
|
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){
|
||||||
//TODO
|
$this->getLevel()->useBreakOn($this);
|
||||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id, 0, 1));
|
|
||||||
$this->getLevel()->setBlock($this, new Air(), true);
|
|
||||||
|
|
||||||
return Level::BLOCK_UPDATE_NORMAL;
|
return Level::BLOCK_UPDATE_NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace pocketmine\block;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Transparent extends Generic{
|
abstract class Transparent extends Block{
|
||||||
public $isActivable = false;
|
public $isActivable = false;
|
||||||
public $breakable = true;
|
public $breakable = true;
|
||||||
public $isFlowable = false;
|
public $isFlowable = false;
|
||||||
|
@ -37,13 +37,12 @@ class Trapdoor extends Transparent{
|
|||||||
$this->hardness = 15;
|
$this->hardness = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
$damage = $this->getDamage();
|
$damage = $this->getDamage();
|
||||||
|
|
||||||
$f = 0.1875;
|
$f = 0.1875;
|
||||||
|
|
||||||
$bb = null;
|
|
||||||
|
|
||||||
if(($damage & 0x08) > 0){
|
if(($damage & 0x08) > 0){
|
||||||
$bb = new AxisAlignedBB(
|
$bb = new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
@ -66,7 +65,7 @@ class Trapdoor extends Transparent{
|
|||||||
|
|
||||||
if(($damage & 0x04) > 0){
|
if(($damage & 0x04) > 0){
|
||||||
if(($damage & 0x03) === 0){
|
if(($damage & 0x03) === 0){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z + 1 - $f,
|
$this->z + 1 - $f,
|
||||||
@ -75,7 +74,7 @@ class Trapdoor extends Transparent{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}elseif(($damage & 0x03) === 1){
|
}elseif(($damage & 0x03) === 1){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -84,7 +83,7 @@ class Trapdoor extends Transparent{
|
|||||||
$this->z + $f
|
$this->z + $f
|
||||||
);
|
);
|
||||||
}if(($damage & 0x03) === 2){
|
}if(($damage & 0x03) === 2){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x + 1 - $f,
|
$this->x + 1 - $f,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
@ -93,7 +92,7 @@ class Trapdoor extends Transparent{
|
|||||||
$this->z + 1
|
$this->z + 1
|
||||||
);
|
);
|
||||||
}if(($damage & 0x03) === 3){
|
}if(($damage & 0x03) === 3){
|
||||||
$bb = new AxisAlignedBB(
|
$bb->setBounds(
|
||||||
$this->x,
|
$this->x,
|
||||||
$this->y,
|
$this->y,
|
||||||
$this->z,
|
$this->z,
|
||||||
|
172
src/pocketmine/block/Vine.php
Normal file
172
src/pocketmine/block/Vine.php
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<?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\entity\Entity;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\Tool;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
class Vine extends Transparent{
|
||||||
|
|
||||||
|
public $hasEntityCollision = true;
|
||||||
|
|
||||||
|
public function __construct($meta = 0){
|
||||||
|
parent::__construct(self::VINE, $meta, "Vines");
|
||||||
|
$this->isSolid = false;
|
||||||
|
$this->isFullBlock = false;
|
||||||
|
$this->hardness = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityCollide(Entity $entity){
|
||||||
|
$entity->fallDistance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
|
$f1 = 1;
|
||||||
|
$f2 = 1;
|
||||||
|
$f3 = 1;
|
||||||
|
$f4 = 0;
|
||||||
|
$f5 = 0;
|
||||||
|
$f6 = 0;
|
||||||
|
|
||||||
|
$flag = $this->meta > 0;
|
||||||
|
|
||||||
|
if(($this->meta & 0x02) > 0){
|
||||||
|
$f4 = max($f4, 0.0625);
|
||||||
|
$f1 = 0;
|
||||||
|
$f2 = 0;
|
||||||
|
$f5 = 1;
|
||||||
|
$f3 = 0;
|
||||||
|
$f6 = 1;
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($this->meta & 0x08) > 0){
|
||||||
|
$f1 = min($f1, 0.9375);
|
||||||
|
$f4 = 1;
|
||||||
|
$f2 = 0;
|
||||||
|
$f5 = 1;
|
||||||
|
$f3 = 0;
|
||||||
|
$f6 = 1;
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($this->meta & 0x01) > 0){
|
||||||
|
$f3 = min($f3, 0.9375);
|
||||||
|
$f6 = 1;
|
||||||
|
$f1 = 0;
|
||||||
|
$f4 = 1;
|
||||||
|
$f2 = 0;
|
||||||
|
$f5 = 1;
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$flag and $this->getSide(1)->isSolid){
|
||||||
|
$f2 = min($f2, 0.9375);
|
||||||
|
$f5 = 1;
|
||||||
|
$f1 = 0;
|
||||||
|
$f4 = 1;
|
||||||
|
$f3 = 0;
|
||||||
|
$f6 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AxisAlignedBB(
|
||||||
|
$this->x + $f1,
|
||||||
|
$this->y + $f2,
|
||||||
|
$this->z + $f3,
|
||||||
|
$this->x + $f4,
|
||||||
|
$this->y + $f5,
|
||||||
|
$this->z + $f6
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||||
|
if($target->isSolid){
|
||||||
|
$faces = [
|
||||||
|
0 => 0,
|
||||||
|
1 => 0,
|
||||||
|
2 => 1,
|
||||||
|
3 => 4,
|
||||||
|
4 => 8,
|
||||||
|
5 => 2,
|
||||||
|
];
|
||||||
|
if(isset($faces[$face])){
|
||||||
|
$this->meta = $faces[$face];
|
||||||
|
$this->getLevel()->setBlock($block, $this, true, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBreakTime(Item $item){
|
||||||
|
if($item->isShears()){
|
||||||
|
return 0.02;
|
||||||
|
}elseif($item->isSword()){
|
||||||
|
return 0.2;
|
||||||
|
}elseif($item->isAxe()){
|
||||||
|
switch($item->isAxe()){
|
||||||
|
case Tool::TIER_WOODEN:
|
||||||
|
return 0.15;
|
||||||
|
case Tool::TIER_STONE:
|
||||||
|
return 0.075;
|
||||||
|
case Tool::TIER_IRON:
|
||||||
|
return 0.05;
|
||||||
|
case Tool::TIER_DIAMOND:
|
||||||
|
return 0.0375;
|
||||||
|
case Tool::TIER_GOLD:
|
||||||
|
return 0.025;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate($type){
|
||||||
|
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||||
|
/*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;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDrops(Item $item){
|
||||||
|
if($item->isShears()){
|
||||||
|
return [
|
||||||
|
[$this->id, 0, 1],
|
||||||
|
];
|
||||||
|
}else{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,150 +21,31 @@
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\level\Level;
|
|
||||||
use pocketmine\level\Position;
|
|
||||||
use pocketmine\Player;
|
|
||||||
use pocketmine\Server;
|
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Water extends Liquid{
|
class Water extends Liquid{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::WATER, $meta, "Water");
|
parent::__construct(self::WATER, $meta, "Water");
|
||||||
$this->hardness = 500;
|
$this->hardness = 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityCollide(Entity $entity){
|
public function onEntityCollide(Entity $entity){
|
||||||
$entity->fallDistance = 0;
|
$entity->fallDistance = 0;
|
||||||
$entity->extinguish();
|
if($entity->fireTicks > 0){
|
||||||
|
$entity->extinguish();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($entity instanceof Player){
|
||||||
|
$entity->onGround = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||||
$ret = $this->getLevel()->setBlock($this, $this, true);
|
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||||
$this->getLevel()->scheduleUpdate(clone $this, 10);
|
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSourceCount(){
|
|
||||||
$count = 0;
|
|
||||||
for($side = 2; $side <= 5; ++$side){
|
|
||||||
if($this->getSide($side) instanceof Water){
|
|
||||||
$b = $this->getSide($side);
|
|
||||||
$level = $b->meta & 0x07;
|
|
||||||
if($level == 0x00){
|
|
||||||
$count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkLava(){
|
|
||||||
for($side = 0; $side <= 5; ++$side){
|
|
||||||
if($side == 1){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$b = $this->getSide($side);
|
|
||||||
if($b instanceof Lava){
|
|
||||||
$level = $b->meta & 0x07;
|
|
||||||
if($level == 0x00){
|
|
||||||
$this->getLevel()->setBlock($b, new Obsidian(), false, false, true);
|
|
||||||
}else{
|
|
||||||
$this->getLevel()->setBlock($b, new Cobblestone(), false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFrom(){
|
|
||||||
for($side = 0; $side <= 5; ++$side){
|
|
||||||
$b = $this->getSide($side);
|
|
||||||
if($b instanceof Water){
|
|
||||||
$tlevel = $b->meta & 0x07;
|
|
||||||
$level = $this->meta & 0x07;
|
|
||||||
if(($tlevel + 1) == $level || ($side == 0x01 && $level == 0x01)){
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->checkLava();
|
|
||||||
|
|
||||||
$falling = $this->meta >> 3;
|
|
||||||
$down = $this->getSide(0);
|
|
||||||
|
|
||||||
$from = $this->getFrom();
|
|
||||||
//Has Source or Its Source
|
|
||||||
if($from !== null || $level == 0x00){
|
|
||||||
if($level !== 0x07){
|
|
||||||
if($down instanceof Air || $down instanceof Water){
|
|
||||||
$this->getLevel()->setBlock($down, new Water(0x01), false, false, true);
|
|
||||||
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($down, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
|
|
||||||
}else{
|
|
||||||
for($side = 2; $side <= 5; ++$side){
|
|
||||||
$b = $this->getSide($side);
|
|
||||||
if($b instanceof Water){
|
|
||||||
if($this->getSourceCount() >= 2 && $level != 0x00){
|
|
||||||
$this->getLevel()->setBlock($this, new Water(0), false, false, true);
|
|
||||||
}
|
|
||||||
}elseif($b->isFlowable === true){
|
|
||||||
$this->getLevel()->setBlock($b, new Water($level + 1), false, false, true);
|
|
||||||
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//Extend Remove for Left Waters
|
|
||||||
for($side = 2; $side <= 5; ++$side){
|
|
||||||
$sb = $this->getSide($side);
|
|
||||||
if($sb instanceof Water){
|
|
||||||
$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), 10, Level::BLOCK_UPDATE_NORMAL);
|
|
||||||
}
|
|
||||||
$this->getLevel()->setBlock($sb, new Air(), false, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$b = $this->getSide(0)->getSide($side);
|
|
||||||
if($b instanceof Water){
|
|
||||||
$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), 10, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,65 +22,10 @@
|
|||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\level\Level;
|
|
||||||
use pocketmine\Player;
|
|
||||||
|
|
||||||
class Wheat extends Flowable{
|
class Wheat extends Crops{
|
||||||
public function __construct($meta = 0){
|
public function __construct($meta = 0){
|
||||||
parent::__construct(self::WHEAT_BLOCK, $meta, "Wheat Block");
|
parent::__construct(self::WHEAT_BLOCK, $meta, "Wheat Block");
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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(WHEAT_SEEDS, 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 false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDrops(Item $item){
|
public function getDrops(Item $item){
|
||||||
|
@ -45,7 +45,8 @@ class WoodSlab extends Transparent{
|
|||||||
$this->hardness = 15;
|
$this->hardness = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBoundingBox(){
|
protected function recalculateBoundingBox(){
|
||||||
|
|
||||||
if(($this->meta & 0x08) > 0){
|
if(($this->meta & 0x08) > 0){
|
||||||
return new AxisAlignedBB(
|
return new AxisAlignedBB(
|
||||||
$this->x,
|
$this->x,
|
||||||
|
@ -31,13 +31,15 @@ class CommandReader extends Thread{
|
|||||||
private $readline;
|
private $readline;
|
||||||
|
|
||||||
/** @var \Threaded */
|
/** @var \Threaded */
|
||||||
private $buffer;
|
protected $buffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param \Threaded $threaded
|
||||||
* @param string $stream
|
* @param string $stream
|
||||||
*/
|
*/
|
||||||
public function __construct($stream = "php://stdin"){
|
public function __construct(\Threaded $threaded, $stream = "php://stdin"){
|
||||||
$this->stream = $stream;
|
$this->stream = $stream;
|
||||||
|
$this->buffer = $threaded;
|
||||||
$this->start();
|
$this->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +72,6 @@ class CommandReader extends Thread{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function run(){
|
public function run(){
|
||||||
$this->buffer = new \Threaded;
|
|
||||||
$opts = getopt("", ["disable-readline"]);
|
$opts = getopt("", ["disable-readline"]);
|
||||||
if(extension_loaded("readline") and $this->stream === "php://stdin" and !isset($opts["disable-readline"])){
|
if(extension_loaded("readline") and $this->stream === "php://stdin" and !isset($opts["disable-readline"])){
|
||||||
$this->readline = true;
|
$this->readline = true;
|
||||||
|
@ -178,7 +178,11 @@ class SimpleCommandMap implements CommandMap{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$target->timings->startTiming();
|
$target->timings->startTiming();
|
||||||
$target->execute($sender, $sentCommandLabel, $args);
|
try{
|
||||||
|
$target->execute($sender, $sentCommandLabel, $args);
|
||||||
|
}catch(\Exception $e){
|
||||||
|
$this->server->getLogger()->critical("Unhandled exception executing command '". $commandLine ,"' in ". $target);
|
||||||
|
}
|
||||||
$target->timings->stopTiming();
|
$target->timings->stopTiming();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -24,7 +24,6 @@ namespace pocketmine\command\defaults;
|
|||||||
use pocketmine\command\CommandSender;
|
use pocketmine\command\CommandSender;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\Server;
|
|
||||||
use pocketmine\utils\TextFormat;
|
use pocketmine\utils\TextFormat;
|
||||||
|
|
||||||
class KillCommand extends VanillaCommand{
|
class KillCommand extends VanillaCommand{
|
||||||
@ -45,9 +44,7 @@ class KillCommand extends VanillaCommand{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($sender instanceof Player){
|
if($sender instanceof Player){
|
||||||
//TODO: EntityDamageEvent
|
$sender->getServer()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||||
|
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
|
||||||
|
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
return true;
|
return true;
|
||||||
|
@ -41,9 +41,7 @@ class SaveOffCommand extends VanillaCommand{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($sender->getServer()->getLevels() as $level){
|
$sender->getServer()->setAutoSave(false);
|
||||||
$level->setAutoSave(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::broadcastCommandMessage($sender, "Disabled level saving");
|
Command::broadcastCommandMessage($sender, "Disabled level saving");
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ class SaveOnCommand extends VanillaCommand{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($sender->getServer()->getLevels() as $level){
|
$sender->getServer()->setAutoSave(true);
|
||||||
$level->setAutoSave(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::broadcastCommandMessage($sender, "Enabled level saving");
|
Command::broadcastCommandMessage($sender, "Enabled level saving");
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class SetWorldSpawnCommand extends VanillaCommand{
|
|||||||
if(count($args) === 0){
|
if(count($args) === 0){
|
||||||
if($sender instanceof Player){
|
if($sender instanceof Player){
|
||||||
$level = $sender->getLevel();
|
$level = $sender->getLevel();
|
||||||
$pos = $sender->round();
|
$pos = (new Vector3($sender->x, $sender->y, $sender->z))->round();
|
||||||
}else{
|
}else{
|
||||||
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");
|
$sender->sendMessage(TextFormat::RED . "You can only perform this command as a player");
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class SpawnpointCommand extends VanillaCommand{
|
|||||||
|
|
||||||
if(count($args) === 4){
|
if(count($args) === 4){
|
||||||
if($level !== null){
|
if($level !== null){
|
||||||
$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawn();
|
$pos = $sender instanceof Player ? $sender->getPosition() : $level->getSpawnLocation();
|
||||||
$x = (int) $this->getRelativeDouble($pos->x, $sender, $args[1]);
|
$x = (int) $this->getRelativeDouble($pos->x, $sender, $args[1]);
|
||||||
$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, 128);
|
$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, 128);
|
||||||
$z = $this->getRelativeDouble($pos->z, $sender, $args[3]);
|
$z = $this->getRelativeDouble($pos->z, $sender, $args[3]);
|
||||||
|
@ -23,7 +23,6 @@ namespace pocketmine\command\defaults;
|
|||||||
|
|
||||||
use pocketmine\command\Command;
|
use pocketmine\command\Command;
|
||||||
use pocketmine\command\CommandSender;
|
use pocketmine\command\CommandSender;
|
||||||
use pocketmine\level\Position;
|
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\TextFormat;
|
use pocketmine\utils\TextFormat;
|
||||||
@ -88,8 +87,7 @@ class TeleportCommand extends VanillaCommand{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(count($args) < 3){
|
if(count($args) < 3){
|
||||||
$pos = new Position($target->x, $target->y, $target->z, $target->getLevel());
|
$origin->teleport($target);
|
||||||
$origin->teleport($pos);
|
|
||||||
Command::broadcastCommandMessage($sender, "Teleported " . $origin->getDisplayName() . " to " . $target->getDisplayName());
|
Command::broadcastCommandMessage($sender, "Teleported " . $origin->getDisplayName() . " to " . $target->getDisplayName());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -32,12 +32,47 @@ class TimeCommand extends VanillaCommand{
|
|||||||
parent::__construct(
|
parent::__construct(
|
||||||
$name,
|
$name,
|
||||||
"Changes the time on each world",
|
"Changes the time on each world",
|
||||||
"/time set <value>\n/time add <value>"
|
"/time set <value>\n/time add <value>\n/time start|stop"
|
||||||
);
|
);
|
||||||
$this->setPermission("pocketmine.command.time.add;pocketmine.command.time.set");
|
$this->setPermission("pocketmine.command.time.add;pocketmine.command.time.set;pocketmine.command.time.start;pocketmine.command.time.stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(CommandSender $sender, $currentAlias, array $args){
|
public function execute(CommandSender $sender, $currentAlias, array $args){
|
||||||
|
if(count($args) < 1){
|
||||||
|
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($args[0] === "start"){
|
||||||
|
if(!$sender->hasPermission("pocketmine.command.time.start")){
|
||||||
|
$sender->sendMessage(TextFormat::RED . "You don't have permission to restart the time");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach($sender->getServer()->getLevels() as $level){
|
||||||
|
$level->checkTime();
|
||||||
|
$level->startTime();
|
||||||
|
$level->checkTime();
|
||||||
|
}
|
||||||
|
Command::broadcastCommandMessage($sender, "Restarted the time");
|
||||||
|
return true;
|
||||||
|
}elseif($args[0] === "stop"){
|
||||||
|
if(!$sender->hasPermission("pocketmine.command.time.stop")){
|
||||||
|
$sender->sendMessage(TextFormat::RED . "You don't have permission to stop the time");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach($sender->getServer()->getLevels() as $level){
|
||||||
|
$level->checkTime();
|
||||||
|
$level->stopTime();
|
||||||
|
$level->checkTime();
|
||||||
|
}
|
||||||
|
Command::broadcastCommandMessage($sender, "Stopped the time");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(count($args) < 2){
|
if(count($args) < 2){
|
||||||
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
|
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
|
||||||
|
|
||||||
@ -78,6 +113,7 @@ class TimeCommand extends VanillaCommand{
|
|||||||
$level->setTime($level->getTime() + $value);
|
$level->setTime($level->getTime() + $value);
|
||||||
$level->checkTime();
|
$level->checkTime();
|
||||||
}
|
}
|
||||||
|
Command::broadcastCommandMessage($sender, "Added " . $value ." to time");
|
||||||
}else{
|
}else{
|
||||||
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
|
$sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage);
|
||||||
}
|
}
|
||||||
|
@ -93,40 +93,39 @@ class TimingsCommand extends VanillaCommand{
|
|||||||
if($paste){
|
if($paste){
|
||||||
fseek($fileTimings, 0);
|
fseek($fileTimings, 0);
|
||||||
$data = [
|
$data = [
|
||||||
"public" => false,
|
"syntax" => "text",
|
||||||
"description" => $sender->getServer()->getName() . " Timings",
|
"poster" => $sender->getServer()->getName(),
|
||||||
"files" => [
|
"content" => stream_get_contents($fileTimings)
|
||||||
"timings.txt" => [
|
|
||||||
"content" => stream_get_contents($fileTimings)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$ch = curl_init("https://api.github.com/gists");
|
$ch = curl_init("http://paste.ubuntu.com/");
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||||
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
|
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
|
||||||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
|
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_SLASHES));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
curl_setopt($ch, CURLOPT_AUTOREFERER, false);
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json", "User-Agent: " . $this->getName() . " " . $sender->getServer()->getPocketMineVersion()]);
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: " . $this->getName() . " " . $sender->getServer()->getPocketMineVersion()]);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
$ret = curl_exec($ch);
|
$data = curl_exec($ch);
|
||||||
$data = json_decode($ret);
|
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
if($data === false or $data === null or !isset($data->html_url)){
|
if(preg_match('#^Location: http://paste\\.ubuntu\\.com/([0-9]{1,})/#m', $data, $matches) == 0){
|
||||||
$sender->sendMessage("An error happened while pasting the report");
|
$sender->sendMessage("An error happened while pasting the report");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$timings = $data->html_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($fileTimings);
|
|
||||||
$sender->sendMessage("Timings written to " . $timings);
|
$sender->sendMessage("Timings uploaded to http://paste.ubuntu.com/".$matches[1]."/");
|
||||||
$sender->sendMessage("Paste contents of file into form at http://aikar.co/timings.php to read results.");
|
$sender->sendMessage("You can read the results at http://timings.aikar.co/?url=".$matches[1]);
|
||||||
|
fclose($fileTimings);
|
||||||
|
}else{
|
||||||
|
fclose($fileTimings);
|
||||||
|
$sender->sendMessage("Timings written to " . $timings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -21,15 +21,8 @@
|
|||||||
|
|
||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
|
||||||
use pocketmine\level\format\FullChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\MovingObjectPosition;
|
|
||||||
use pocketmine\math\Vector3;
|
|
||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
use pocketmine\nbt\tag\Short;
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
use pocketmine\network\protocol\AddEntityPacket;
|
use pocketmine\network\protocol\AddEntityPacket;
|
||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -41,149 +34,33 @@ class Arrow extends Projectile{
|
|||||||
public $length = 0.5;
|
public $length = 0.5;
|
||||||
public $height = 0.5;
|
public $height = 0.5;
|
||||||
|
|
||||||
/** @var Entity */
|
|
||||||
public $shootingEntity = null;
|
|
||||||
|
|
||||||
protected $gravity = 0.05;
|
protected $gravity = 0.05;
|
||||||
protected $drag = 0.01;
|
protected $drag = 0.01;
|
||||||
|
|
||||||
private $damage = 6;
|
protected $damage = 6;
|
||||||
|
|
||||||
public function __construct(FullChunk $chunk, Compound $nbt, Entity $shootingEntity = null){
|
public function __construct(FullChunk $chunk, Compound $nbt, Entity $shootingEntity = null){
|
||||||
$this->shootingEntity = $shootingEntity;
|
$this->shootingEntity = $shootingEntity;
|
||||||
parent::__construct($chunk, $nbt);
|
parent::__construct($chunk, $nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function initEntity(){
|
public function onUpdate($currentTick){
|
||||||
$this->namedtag->id = new String("id", "Arrow");
|
if($this->closed){
|
||||||
$this->setMaxHealth(1);
|
|
||||||
$this->setHealth(1);
|
|
||||||
if(isset($this->namedtag->Age)){
|
|
||||||
$this->age = $this->namedtag["Age"];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onUpdate(){
|
|
||||||
$this->entityBaseTick();
|
|
||||||
|
|
||||||
if($this->closed !== false){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$movingObjectPosition = null;
|
$this->timings->startTiming();
|
||||||
|
|
||||||
$this->motionY -= $this->gravity;
|
$hasUpdate = parent::onUpdate($currentTick);
|
||||||
|
|
||||||
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
|
||||||
|
|
||||||
$moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
|
|
||||||
|
|
||||||
$list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
|
|
||||||
|
|
||||||
$nearDistance = PHP_INT_MAX;
|
|
||||||
$nearEntity = null;
|
|
||||||
|
|
||||||
foreach($list as $entity){
|
|
||||||
if(/*!$entity->canCollideWith($this) or */($entity === $this->shootingEntity and $this->ticksLived < 5)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
|
|
||||||
$ob = $axisalignedbb->calculateIntercept($this, $moveVector);
|
|
||||||
|
|
||||||
if($ob === null){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$distance = $this->distance($ob->hitVector);
|
|
||||||
|
|
||||||
if($distance < $nearDistance){
|
|
||||||
$nearDistance = $distance;
|
|
||||||
$nearEntity = $entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($nearEntity !== null){
|
|
||||||
$movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($movingObjectPosition !== null){
|
|
||||||
if($movingObjectPosition->entityHit !== null){
|
|
||||||
$motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2);
|
|
||||||
$damage = ceil($motion * $this->damage);
|
|
||||||
|
|
||||||
|
|
||||||
$ev = new EntityDamageByEntityEvent($this->shootingEntity === null ? $this : $this->shootingEntity, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent($ev);
|
|
||||||
|
|
||||||
if(!$ev->isCancelled()){
|
|
||||||
$movingObjectPosition->entityHit->attack($damage, $ev);
|
|
||||||
if($this->fireTicks > 0){
|
|
||||||
$movingObjectPosition->entityHit->setOnFire(5);
|
|
||||||
}
|
|
||||||
$this->kill();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
|
||||||
|
|
||||||
$friction = 1 - $this->drag;
|
|
||||||
|
|
||||||
if($this->onGround){
|
|
||||||
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->motionX *= $friction;
|
|
||||||
$this->motionY *= 1 - $this->drag;
|
|
||||||
$this->motionZ *= $friction;
|
|
||||||
|
|
||||||
if($this->onGround){
|
|
||||||
$this->motionX = 0;
|
|
||||||
$this->motionY = 0;
|
|
||||||
$this->motionZ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0){
|
|
||||||
$f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2));
|
|
||||||
$this->yaw = (atan2($this->motionX, $this->motionZ) * 180 / M_PI);
|
|
||||||
$this->pitch = (atan2($this->motionY, $f) * 180 / M_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->age > 1200){
|
if($this->age > 1200){
|
||||||
$this->kill();
|
$this->kill();
|
||||||
|
$hasUpdate = true;
|
||||||
}
|
}
|
||||||
$this->updateMovement();
|
|
||||||
|
|
||||||
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
$this->timings->stopTiming();
|
||||||
}
|
|
||||||
|
|
||||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
return $hasUpdate;
|
||||||
$this->setLastDamageCause($source);
|
|
||||||
$this->setHealth($this->getHealth() - $damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function heal($amount){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveNBT(){
|
|
||||||
$this->namedtag->Age = new Short("Age", $this->age);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getData(){
|
|
||||||
$flags = 0;
|
|
||||||
$flags |= $this->fireTicks > 0 ? 1 : 0;
|
|
||||||
|
|
||||||
return [
|
|
||||||
0 => ["type" => 0, "value" => $flags]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function canCollideWith(Entity $entity){
|
|
||||||
return $entity instanceof Living and !$this->onGround;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function spawnTo(Player $player){
|
public function spawnTo(Player $player){
|
||||||
|
@ -22,11 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Chicken extends Animal{
|
class Chicken extends Animal{
|
||||||
|
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Chicken");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Cow extends Animal{
|
class Cow extends Animal{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Cow");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Creeper extends Monster implements Explosive{
|
class Creeper extends Monster implements Explosive{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Creeper");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Egg extends Projectile{
|
class Egg extends Projectile{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Egg");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -23,10 +23,7 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
|
|
||||||
use pocketmine\inventory\InventoryHolder;
|
use pocketmine\inventory\InventoryHolder;
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Enderman extends Monster implements InventoryHolder{
|
class Enderman extends Monster implements InventoryHolder{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Enderman");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -24,23 +24,23 @@
|
|||||||
*/
|
*/
|
||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
|
||||||
use pocketmine\block\Water;
|
use pocketmine\block\Water;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
use pocketmine\event\entity\EntityDespawnEvent;
|
use pocketmine\event\entity\EntityDespawnEvent;
|
||||||
use pocketmine\event\entity\EntityLevelChangeEvent;
|
use pocketmine\event\entity\EntityLevelChangeEvent;
|
||||||
use pocketmine\event\entity\EntityMotionEvent;
|
use pocketmine\event\entity\EntityMotionEvent;
|
||||||
use pocketmine\event\entity\EntityMoveEvent;
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
use pocketmine\event\entity\EntitySpawnEvent;
|
use pocketmine\event\entity\EntitySpawnEvent;
|
||||||
use pocketmine\event\entity\EntityTeleportEvent;
|
use pocketmine\event\entity\EntityTeleportEvent;
|
||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
use pocketmine\level\format\Chunk;
|
use pocketmine\level\format\Chunk;
|
||||||
use pocketmine\level\format\FullChunk;
|
use pocketmine\level\format\FullChunk;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\level\Location;
|
||||||
use pocketmine\level\Position;
|
use pocketmine\level\Position;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Math;
|
use pocketmine\math\Math;
|
||||||
use pocketmine\math\Vector3 as Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\metadata\Metadatable;
|
use pocketmine\metadata\Metadatable;
|
||||||
use pocketmine\metadata\MetadataValue;
|
use pocketmine\metadata\MetadataValue;
|
||||||
use pocketmine\nbt\tag\Byte;
|
use pocketmine\nbt\tag\Byte;
|
||||||
@ -49,8 +49,9 @@ use pocketmine\nbt\tag\Double;
|
|||||||
use pocketmine\nbt\tag\Enum;
|
use pocketmine\nbt\tag\Enum;
|
||||||
use pocketmine\nbt\tag\Float;
|
use pocketmine\nbt\tag\Float;
|
||||||
use pocketmine\nbt\tag\Short;
|
use pocketmine\nbt\tag\Short;
|
||||||
use pocketmine\network\protocol\MoveEntityPacket;
|
use pocketmine\nbt\tag\String;
|
||||||
use pocketmine\Network;
|
use pocketmine\Network;
|
||||||
|
use pocketmine\network\protocol\MoveEntityPacket;
|
||||||
use pocketmine\network\protocol\MovePlayerPacket;
|
use pocketmine\network\protocol\MovePlayerPacket;
|
||||||
use pocketmine\network\protocol\RemoveEntityPacket;
|
use pocketmine\network\protocol\RemoveEntityPacket;
|
||||||
use pocketmine\network\protocol\SetEntityDataPacket;
|
use pocketmine\network\protocol\SetEntityDataPacket;
|
||||||
@ -59,12 +60,17 @@ use pocketmine\network\protocol\SetTimePacket;
|
|||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\plugin\Plugin;
|
use pocketmine\plugin\Plugin;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
use pocketmine\utils\ChunkException;
|
||||||
|
|
||||||
|
abstract class Entity extends Location implements Metadatable{
|
||||||
|
|
||||||
abstract class Entity extends Position implements Metadatable{
|
|
||||||
|
|
||||||
const NETWORK_ID = -1;
|
const NETWORK_ID = -1;
|
||||||
|
|
||||||
public static $entityCount = 1;
|
public static $entityCount = 1;
|
||||||
|
/** @var Entity[] */
|
||||||
|
private static $knownEntities = [];
|
||||||
|
private static $shortNames = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Player[]
|
* @var Player[]
|
||||||
@ -97,8 +103,6 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
public $lastMotionY;
|
public $lastMotionY;
|
||||||
public $lastMotionZ;
|
public $lastMotionZ;
|
||||||
|
|
||||||
public $yaw;
|
|
||||||
public $pitch;
|
|
||||||
public $lastYaw;
|
public $lastYaw;
|
||||||
public $lastPitch;
|
public $lastPitch;
|
||||||
|
|
||||||
@ -124,7 +128,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
protected $ySize = 0;
|
protected $ySize = 0;
|
||||||
protected $stepHeight = 0;
|
protected $stepHeight = 0;
|
||||||
public $keepMovement = true;
|
public $keepMovement = false;
|
||||||
|
|
||||||
public $fallDistance;
|
public $fallDistance;
|
||||||
public $ticksLived;
|
public $ticksLived;
|
||||||
@ -133,17 +137,19 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
public $fireTicks;
|
public $fireTicks;
|
||||||
public $airTicks;
|
public $airTicks;
|
||||||
public $namedtag;
|
public $namedtag;
|
||||||
protected $isStatic = false;
|
public $canCollide = true;
|
||||||
protected $isColliding = false;
|
|
||||||
|
protected $isStatic = false;
|
||||||
|
|
||||||
|
public $isCollided = false;
|
||||||
|
public $isCollidedHorizontally = false;
|
||||||
|
public $isCollidedVertically = false;
|
||||||
|
|
||||||
protected $inWater;
|
|
||||||
public $noDamageTicks;
|
public $noDamageTicks;
|
||||||
private $justCreated;
|
private $justCreated;
|
||||||
protected $fireProof;
|
protected $fireProof;
|
||||||
private $invulnerable;
|
private $invulnerable;
|
||||||
|
|
||||||
protected $spawnTime;
|
|
||||||
|
|
||||||
protected $gravity;
|
protected $gravity;
|
||||||
protected $drag;
|
protected $drag;
|
||||||
|
|
||||||
@ -152,14 +158,19 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
public $closed = false;
|
public $closed = false;
|
||||||
|
|
||||||
|
/** @var \pocketmine\event\TimingsHandler */
|
||||||
|
protected $timings;
|
||||||
|
|
||||||
|
|
||||||
public function __construct(FullChunk $chunk, Compound $nbt){
|
public function __construct(FullChunk $chunk, Compound $nbt){
|
||||||
if($chunk === null or $chunk->getProvider() === null){
|
if($chunk === null or $chunk->getProvider() === null){
|
||||||
throw new \Exception("Invalid garbage Chunk given to Entity");
|
throw new ChunkException("Invalid garbage Chunk given to Entity");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->timings = Timings::getEntityTimings($this);
|
||||||
|
|
||||||
if($this->eyeHeight === null){
|
if($this->eyeHeight === null){
|
||||||
$this->eyeHeight = $this->height;
|
$this->eyeHeight = $this->height / 2 + 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->id = Entity::$entityCount++;
|
$this->id = Entity::$entityCount++;
|
||||||
@ -198,7 +209,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->airTicks = $this->namedtag["Air"];
|
$this->airTicks = $this->namedtag["Air"];
|
||||||
|
|
||||||
if(!isset($this->namedtag->OnGround)){
|
if(!isset($this->namedtag->OnGround)){
|
||||||
$this->namedtag->OnGround = new Byte("OnGround", 1);
|
$this->namedtag->OnGround = new Byte("OnGround", 0);
|
||||||
}
|
}
|
||||||
$this->onGround = $this->namedtag["OnGround"] > 0 ? true : false;
|
$this->onGround = $this->namedtag["OnGround"] > 0 ? true : false;
|
||||||
|
|
||||||
@ -208,16 +219,63 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false;
|
$this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false;
|
||||||
|
|
||||||
$this->chunk->addEntity($this);
|
$this->chunk->addEntity($this);
|
||||||
$this->getLevel()->addEntity($this);
|
$this->level->addEntity($this);
|
||||||
$this->initEntity();
|
$this->initEntity();
|
||||||
$this->lastUpdate = $this->spawnTime = microtime(true);
|
$this->lastUpdate = $this->server->getTick();
|
||||||
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
|
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
|
||||||
|
|
||||||
$this->scheduleUpdate();
|
$this->scheduleUpdate();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|string $type
|
||||||
|
* @param FullChunk $chunk
|
||||||
|
* @param Compound $nbt
|
||||||
|
* @param $args
|
||||||
|
*
|
||||||
|
* @return Entity
|
||||||
|
*/
|
||||||
|
public static function createEntity($type, FullChunk $chunk, Compound $nbt, ...$args){
|
||||||
|
if(isset(self::$knownEntities[$type])){
|
||||||
|
$class = self::$knownEntities[$type];
|
||||||
|
return new $class($chunk, $nbt, ...$args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function registerEntity($className, $force = false){
|
||||||
|
$class = new \ReflectionClass($className);
|
||||||
|
if(is_a($className, Entity::class, true) and !$class->isAbstract()){
|
||||||
|
if($className::NETWORK_ID !== -1){
|
||||||
|
self::$knownEntities[$className::NETWORK_ID] = $className;
|
||||||
|
}elseif(!$force){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$knownEntities[$class->getShortName()] = $className;
|
||||||
|
self::$shortNames[$className] = $class->getShortName();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the short save name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSaveId(){
|
||||||
|
return self::$shortNames[static::class];
|
||||||
|
}
|
||||||
|
|
||||||
public function saveNBT(){
|
public function saveNBT(){
|
||||||
|
if(!($this instanceof Player)){
|
||||||
|
$this->namedtag->id = new String("id", $this->getSaveId());
|
||||||
|
}
|
||||||
|
|
||||||
$this->namedtag->Pos = new Enum("Pos", [
|
$this->namedtag->Pos = new Enum("Pos", [
|
||||||
new Double(0, $this->x),
|
new Double(0, $this->x),
|
||||||
new Double(1, $this->y),
|
new Double(1, $this->y),
|
||||||
@ -271,13 +329,15 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$pk = new SetEntityDataPacket();
|
$pk = new SetEntityDataPacket();
|
||||||
$pk->eid = $this->id;
|
$pk->eid = $this->id;
|
||||||
$pk->metadata = $this->getData();
|
$pk->metadata = $this->getData();
|
||||||
|
$pk->encode();
|
||||||
|
$pk->isEncoded = true;
|
||||||
foreach($player as $p){
|
foreach($player as $p){
|
||||||
if($p === $this){
|
if($p === $this){
|
||||||
/** @var Player $p */
|
/** @var Player $p */
|
||||||
$pk = new SetEntityDataPacket();
|
$pk2 = new SetEntityDataPacket();
|
||||||
$pk->eid = 0;
|
$pk2->eid = 0;
|
||||||
$pk->metadata = $this->getData();
|
$pk2->metadata = $this->getData();
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk2);
|
||||||
}else{
|
}else{
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk);
|
||||||
}
|
}
|
||||||
@ -289,7 +349,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
*/
|
*/
|
||||||
public function despawnFrom(Player $player){
|
public function despawnFrom(Player $player){
|
||||||
if(isset($this->hasSpawned[$player->getID()])){
|
if(isset($this->hasSpawned[$player->getID()])){
|
||||||
$pk = new RemoveEntityPacket;
|
$pk = new RemoveEntityPacket();
|
||||||
$pk->eid = $this->id;
|
$pk->eid = $this->id;
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
unset($this->hasSpawned[$player->getID()]);
|
unset($this->hasSpawned[$player->getID()]);
|
||||||
@ -300,11 +360,15 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
* @param float $damage
|
* @param float $damage
|
||||||
* @param int|EntityDamageEvent $source
|
* @param int|EntityDamageEvent $source
|
||||||
*
|
*
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
abstract function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC);
|
abstract function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC);
|
||||||
|
|
||||||
abstract function heal($amount);
|
/**
|
||||||
|
* @param float $amount
|
||||||
|
* @param int|EntityRegainHealthEvent $source
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
@ -339,7 +403,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
* @param int|EntityDamageEvent $type
|
* @param int|EntityDamageEvent $type
|
||||||
*/
|
*/
|
||||||
public function setLastDamageCause($type){
|
public function setLastDamageCause($type){
|
||||||
$this->lastDamageCause = $type;
|
$this->lastDamageCause = $type instanceof EntityDamageEvent ? clone $type : $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,17 +441,19 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$diffY = $y - $j;
|
$diffY = $y - $j;
|
||||||
$diffZ = $z - $k;
|
$diffZ = $z - $k;
|
||||||
|
|
||||||
$list = $this->getLevel()->getCollisionBlocks($this->boundingBox);
|
$list = $this->level->getCollisionBlocks($this->boundingBox);
|
||||||
|
|
||||||
if(count($list) === 0 and !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k))){
|
$v = new Vector3($i, $j, $k);
|
||||||
|
|
||||||
|
if(count($list) === 0 and !$this->level->isFullBlock($v->setComponents($i, $j, $k))){
|
||||||
return false;
|
return false;
|
||||||
}else{
|
}else{
|
||||||
$flag = !$this->getLevel()->isFullBlock(new Vector3($i - 1, $j, $k));
|
$flag = !$this->level->isFullBlock($v->setComponents($i - 1, $j, $k));
|
||||||
$flag1 = !$this->getLevel()->isFullBlock(new Vector3($i + 1, $j, $k));
|
$flag1 = !$this->level->isFullBlock($v->setComponents($i + 1, $j, $k));
|
||||||
//$flag2 = !$this->getLevel()->isFullBlock(new Vector3($i, $j - 1, $k));
|
//$flag2 = !$this->level->isFullBlock($v->setComponents($i, $j - 1, $k));
|
||||||
$flag3 = !$this->getLevel()->isFullBlock(new Vector3($i, $j + 1, $k));
|
$flag3 = !$this->level->isFullBlock($v->setComponents($i, $j + 1, $k));
|
||||||
$flag4 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k - 1));
|
$flag4 = !$this->level->isFullBlock($v->setComponents($i, $j, $k - 1));
|
||||||
$flag5 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k + 1));
|
$flag5 = !$this->level->isFullBlock($v->setComponents($i, $j, $k + 1));
|
||||||
|
|
||||||
$direction = 3; //UP!
|
$direction = 3; //UP!
|
||||||
$limit = 9999;
|
$limit = 9999;
|
||||||
@ -453,72 +519,60 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entityBaseTick(){
|
public function entityBaseTick($tickDiff = 1){
|
||||||
|
|
||||||
|
Timings::$tickEntityTimer->startTiming();
|
||||||
//TODO: check vehicles
|
//TODO: check vehicles
|
||||||
|
|
||||||
$this->justCreated = false;
|
$this->justCreated = false;
|
||||||
|
$isPlayer = $this instanceof Player;
|
||||||
|
|
||||||
if($this->dead === true and !($this instanceof Player)){
|
if($this->dead === true){
|
||||||
$this->close();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}elseif($this->dead === true){
|
|
||||||
$this->despawnFromAll();
|
$this->despawnFromAll();
|
||||||
|
if(!$isPlayer){
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
Timings::$tickEntityTimer->stopTiming();
|
||||||
|
return $isPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasUpdate = false;
|
$hasUpdate = false;
|
||||||
$this->updateMovement();
|
|
||||||
|
|
||||||
$this->checkBlockCollision();
|
$this->checkBlockCollision();
|
||||||
|
|
||||||
if($this->handleWaterMovement()){
|
|
||||||
$this->fallDistance = 0;
|
|
||||||
$this->inWater = true;
|
|
||||||
$this->extinguish();
|
|
||||||
}else{
|
|
||||||
$this->inWater = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->y < 0 and $this->dead !== true){
|
if($this->y < 0 and $this->dead !== true){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10));
|
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10);
|
||||||
if(!$ev->isCancelled()){
|
$this->attack($ev->getFinalDamage(), $ev);
|
||||||
$this->attack($ev->getFinalDamage(), $ev);
|
$hasUpdate = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->fireTicks > 0){
|
if($this->fireTicks > 0){
|
||||||
if($this->fireProof){
|
if($this->fireProof){
|
||||||
$this->fireTicks -= 4;
|
$this->fireTicks -= 4 * $tickDiff;
|
||||||
if($this->fireTicks < 0){
|
if($this->fireTicks < 0){
|
||||||
$this->fireTicks = 0;
|
$this->fireTicks = 0;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(($this->fireTicks % 20) === 0){
|
if(($this->fireTicks % 20) === 0 or $tickDiff > 20){
|
||||||
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
|
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
|
||||||
$this->server->getPluginManager()->callEvent($ev);
|
$this->attack($ev->getFinalDamage(), $ev);
|
||||||
if(!$ev->isCancelled()){
|
|
||||||
$this->attack($ev->getFinalDamage(), $ev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
--$this->fireTicks;
|
$this->fireTicks -= $tickDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->fireTicks <= 0){
|
if($this->fireTicks <= 0){
|
||||||
$this->extinguish();
|
$this->extinguish();
|
||||||
|
}else{
|
||||||
|
$hasUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->handleLavaMovement()){
|
$this->age += $tickDiff;
|
||||||
//$this->attack(4, EntityDamageEvent::CAUSE_LAVA);
|
$this->ticksLived += $tickDiff;
|
||||||
//$this->setOnFire(15);
|
|
||||||
$hasUpdate = true;
|
|
||||||
$this->fallDistance *= 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
++$this->age;
|
Timings::$tickEntityTimer->stopTiming();
|
||||||
++$this->ticksLived;
|
|
||||||
|
return $hasUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateMovement(){
|
public function updateMovement(){
|
||||||
@ -531,10 +585,10 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->lastPitch = $this->pitch;
|
$this->lastPitch = $this->pitch;
|
||||||
|
|
||||||
if($this instanceof Human){
|
if($this instanceof Human){
|
||||||
$pk = new MovePlayerPacket;
|
$pk = new MovePlayerPacket();
|
||||||
$pk->eid = $this->id;
|
$pk->eid = $this->id;
|
||||||
$pk->x = $this->x;
|
$pk->x = $this->x;
|
||||||
$pk->y = $this->y; //teleport from head
|
$pk->y = $this->y;
|
||||||
$pk->z = $this->z;
|
$pk->z = $this->z;
|
||||||
$pk->yaw = $this->yaw;
|
$pk->yaw = $this->yaw;
|
||||||
$pk->pitch = $this->pitch;
|
$pk->pitch = $this->pitch;
|
||||||
@ -543,13 +597,11 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
//TODO: add to move list
|
//TODO: add to move list
|
||||||
$pk = new MoveEntityPacket();
|
$pk = new MoveEntityPacket();
|
||||||
$pk->entities = [
|
$pk->entities = [
|
||||||
[$this->id, $this->x, $this->y, $this->z, $this->yaw, $this->pitch]
|
[$this->id, $this->x, $this->y + $this->getEyeHeight(), $this->z, $this->yaw, $this->pitch]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->hasSpawned as $player){
|
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||||
$player->directDataPacket($pk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){
|
if(($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){
|
||||||
@ -557,10 +609,11 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->lastMotionY = $this->motionY;
|
$this->lastMotionY = $this->motionY;
|
||||||
$this->lastMotionZ = $this->motionZ;
|
$this->lastMotionZ = $this->motionZ;
|
||||||
|
|
||||||
$pk = new SetEntityMotionPacket;
|
$pk = new SetEntityMotionPacket();
|
||||||
$pk->entities = [
|
$pk->entities = [
|
||||||
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
];
|
];
|
||||||
|
|
||||||
Server::broadcastPacket($this->hasSpawned, $pk);
|
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||||
|
|
||||||
if($this instanceof Player){
|
if($this instanceof Player){
|
||||||
@ -586,15 +639,24 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
return new Vector3($x, $y, $z);
|
return new Vector3($x, $y, $z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(){
|
public function onUpdate($currentTick){
|
||||||
if($this->closed !== false){
|
if($this->closed){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasUpdate = $this->entityBaseTick();
|
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||||
|
$this->lastUpdate = $currentTick;
|
||||||
|
|
||||||
|
$this->timings->startTiming();
|
||||||
|
|
||||||
|
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
$this->updateMovement();
|
||||||
|
|
||||||
|
$this->timings->stopTiming();
|
||||||
|
|
||||||
//if($this->isStatic())
|
//if($this->isStatic())
|
||||||
return true;
|
return $hasUpdate;
|
||||||
//return !($this instanceof Player);
|
//return !($this instanceof Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,18 +728,11 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
public function fall($fallDistance){
|
public function fall($fallDistance){
|
||||||
$damage = floor($fallDistance - 3);
|
$damage = floor($fallDistance - 3);
|
||||||
if($damage > 0){
|
if($damage > 0){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage));
|
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage);
|
||||||
if($ev->isCancelled()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->attack($ev->getFinalDamage(), $ev);
|
$this->attack($ev->getFinalDamage(), $ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleWaterMovement(){ //TODO
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleLavaMovement(){ //TODO
|
public function handleLavaMovement(){ //TODO
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -696,34 +751,32 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
protected function switchLevel(Level $targetLevel){
|
protected function switchLevel(Level $targetLevel){
|
||||||
if($this->isValid()){
|
if($this->isValid()){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->getLevel(), $targetLevel));
|
$this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel));
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getLevel()->removeEntity($this);
|
$this->level->removeEntity($this);
|
||||||
$this->chunk->removeEntity($this);
|
if($this->chunk !== null){
|
||||||
|
$this->chunk->removeEntity($this);
|
||||||
|
}
|
||||||
$this->despawnFromAll();
|
$this->despawnFromAll();
|
||||||
if($this instanceof Player){
|
if($this instanceof Player){
|
||||||
foreach($this->usedChunks as $index => $d){
|
foreach($this->usedChunks as $index => $d){
|
||||||
$X = null;
|
$X = null;
|
||||||
$Z = null;
|
$Z = null;
|
||||||
Level::getXZ($index, $X, $Z);
|
Level::getXZ($index, $X, $Z);
|
||||||
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
$this->unloadChunk($X, $Z);
|
||||||
$entity->despawnFrom($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
$this->getLevel()->freeAllChunks($this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->setLevel($targetLevel, $this instanceof Player ? true : false); //Hard reference
|
$this->setLevel($targetLevel);
|
||||||
$this->getLevel()->addEntity($this);
|
$this->level->addEntity($this);
|
||||||
if($this instanceof Player){
|
if($this instanceof Player){
|
||||||
$this->usedChunks = [];
|
$this->usedChunks = [];
|
||||||
$pk = new SetTimePacket();
|
$pk = new SetTimePacket();
|
||||||
$pk->time = $this->getLevel()->getTime();
|
$pk->time = $this->level->getTime();
|
||||||
$pk->started = $this->getLevel()->stopTime == false;
|
$pk->started = $this->level->stopTime == false;
|
||||||
$this->dataPacket($pk);
|
$this->dataPacket($pk);
|
||||||
}
|
}
|
||||||
$this->chunk = null;
|
$this->chunk = null;
|
||||||
@ -732,14 +785,18 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getPosition(){
|
public function getPosition(){
|
||||||
return new Position($this->x, $this->y, $this->z, $this->getLevel());
|
return new Position($this->x, $this->y, $this->z, $this->level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocation(){
|
||||||
|
return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->level);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isInsideOfWater(){
|
public function isInsideOfWater(){
|
||||||
$block = $this->getLevel()->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
|
$block = $this->level->getBlock(new Vector3(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
|
||||||
|
|
||||||
if($block instanceof Water){
|
if($block instanceof Water){
|
||||||
$f = ($pos->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
|
$f = ($block->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
|
||||||
return $y < $f;
|
return $y < $f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,38 +804,27 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function isInsideOfSolid(){
|
public function isInsideOfSolid(){
|
||||||
for($i = 0; $i < 8; ++$i){
|
$block = $this->level->getBlock(new Vector3(Math::floorFloat($this->x), Math::floorFloat($y = ($this->y + $this->getEyeHeight())), Math::floorFloat($this->z)));
|
||||||
$x = (($i % 2) - 0.5) * $this->width * 0.8;
|
|
||||||
$y = ((($i >> 1) % 2) - 0.5) * 0.1;
|
|
||||||
$z = ((($i >> 2) % 2) - 0.5) * $this->width * 0.8;
|
|
||||||
$block = $this->getLevel()->getBlock((new Vector3($this->x + $x, $this->y + $this->getEyeHeight() + $y, $this->z + $z))->floor());
|
|
||||||
|
|
||||||
$bb = $block->getBoundingBox();
|
$bb = $block->getBoundingBox();
|
||||||
|
|
||||||
if($bb !== null and $block->isSolid and $bb->intersectsWith($this->getBoundingBox())){
|
if($bb !== null and $block->isSolid and !$block->isTransparent and $bb->intersectsWith($this->getBoundingBox())){
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function collision(){
|
|
||||||
$this->isColliding = true;
|
|
||||||
$this->fallDistance = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function move($dx, $dy, $dz){
|
public function move($dx, $dy, $dz){
|
||||||
|
|
||||||
if($dx == 0 and $dz == 0 and $dy == 0){
|
if($dx == 0 and $dz == 0 and $dy == 0){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if($this->inBlock){ //TODO: noclip
|
if($this->keepMovement){
|
||||||
// $this->boundingBox->offset($dx, $dy, $dz);
|
$this->boundingBox->offset($dx, $dy, $dz);
|
||||||
// $this->x = ($this->boundingBox->minX + $this->boundingBox->maxX) / 2;
|
$this->setPosition(new Vector3(($this->boundingBox->minX + $this->boundingBox->maxX) / 2, $this->boundingBox->minY - $this->ySize, ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2));
|
||||||
// $this->y = $this->boundingBox->minY/* + $this->height*/;
|
$this->onGround = $this instanceof Player ? true : false;
|
||||||
// $this->z = ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2;
|
}else{
|
||||||
//}else{
|
|
||||||
|
|
||||||
Timings::$entityMoveTimer->startTiming();
|
Timings::$entityMoveTimer->startTiming();
|
||||||
|
|
||||||
@ -805,7 +851,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
/*$sneakFlag = $this->onGround and $this instanceof Player;
|
/*$sneakFlag = $this->onGround and $this instanceof Player;
|
||||||
|
|
||||||
if($sneakFlag){
|
if($sneakFlag){
|
||||||
for($mov = 0.05; $dx != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
|
for($mov = 0.05; $dx != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, -1, 0))) === 0; $movX = $dx){
|
||||||
if($dx < $mov and $dx >= -$mov){
|
if($dx < $mov and $dx >= -$mov){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
}elseif($dx > 0){
|
}elseif($dx > 0){
|
||||||
@ -815,7 +861,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; $dz != 0.0 and count($this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
|
for(; $dz != 0.0 and count($this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox(0, -1, $dz))) === 0; $movZ = $dz){
|
||||||
if($dz < $mov and $dz >= -$mov){
|
if($dz < $mov and $dz >= -$mov){
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
}elseif($dz > 0){
|
}elseif($dz > 0){
|
||||||
@ -828,7 +874,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
//TODO: big messy loop
|
//TODO: big messy loop
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz));
|
$list = $this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($dx, $dy, $dz));
|
||||||
|
|
||||||
|
|
||||||
foreach($list as $bb){
|
foreach($list as $bb){
|
||||||
@ -837,7 +883,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
$this->boundingBox->offset(0, $dy, 0);
|
$this->boundingBox->offset(0, $dy, 0);
|
||||||
|
|
||||||
if(!$this->keepMovement and $movY != $dy){
|
if($movY != $dy){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -851,7 +897,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
$this->boundingBox->offset($dx, 0, 0);
|
$this->boundingBox->offset($dx, 0, 0);
|
||||||
|
|
||||||
if(!$this->keepMovement and $movX != $dx){
|
if($movX != $dx){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -863,7 +909,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
$this->boundingBox->offset(0, 0, $dz);
|
$this->boundingBox->offset(0, 0, $dz);
|
||||||
|
|
||||||
if(!$this->keepMovement and $movZ != $dz){
|
if($movZ != $dz){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -882,14 +928,14 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
$this->boundingBox->setBB($axisalignedbb);
|
$this->boundingBox->setBB($axisalignedbb);
|
||||||
|
|
||||||
$list = $this->getLevel()->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ));
|
$list = $this->level->getCollisionCubes($this, $this->boundingBox->getOffsetBoundingBox($movX, $dy, $movZ), false);
|
||||||
|
|
||||||
foreach($list as $bb){
|
foreach($list as $bb){
|
||||||
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
|
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->boundingBox->offset(0, $dy, 0);
|
$this->boundingBox->offset(0, $dy, 0);
|
||||||
if(!$this->keepMovement and $movY != $dy){
|
if($movY != $dy){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -900,7 +946,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->boundingBox->offset($dx, 0, 0);
|
$this->boundingBox->offset($dx, 0, 0);
|
||||||
if(!$this->keepMovement and $movX != $dx){
|
if($movX != $dx){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -911,13 +957,13 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->boundingBox->offset(0, 0, $dz);
|
$this->boundingBox->offset(0, 0, $dz);
|
||||||
if(!$this->keepMovement and $movZ != $dz){
|
if($movZ != $dz){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->keepMovement and $movY != $dy){
|
if($movY != $dy){
|
||||||
$dx = 0;
|
$dx = 0;
|
||||||
$dy = 0;
|
$dy = 0;
|
||||||
$dz = 0;
|
$dz = 0;
|
||||||
@ -940,7 +986,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
|
|
||||||
$pos = new Vector3(
|
$pos = new Vector3(
|
||||||
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
|
($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
|
||||||
$this->boundingBox->minY - $this->ySize/* + $this->height*/,
|
$this->boundingBox->minY - $this->ySize,
|
||||||
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
|
($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -952,16 +998,20 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}else{
|
}else{
|
||||||
|
|
||||||
if($this instanceof Player){
|
if($this instanceof Player){
|
||||||
if(($this->onGround and $movY != 0) or (!$this->onGround and $movY <= 0)){
|
if(!$this->onGround or $movY != 0){
|
||||||
if(count($this->getLevel()->getCollisionBlocks($this->boundingBox->getOffsetBoundingBox(0, $movY - 0.1, 0))) > 0){
|
$bb = clone $this->boundingBox;
|
||||||
$isColliding = true;
|
$bb->maxY = $bb->minY + 1;
|
||||||
|
if(count($this->level->getCollisionBlocks($bb->expand(0.01, 0.01, 0.01))) > 0){
|
||||||
|
$this->onGround = true;
|
||||||
}else{
|
}else{
|
||||||
$isColliding = false;
|
$this->onGround = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->onGround = ($movY <= 0 and $isColliding);
|
|
||||||
}
|
}
|
||||||
|
$this->isCollided = $this->onGround;
|
||||||
}else{
|
}else{
|
||||||
|
$this->isCollidedVertically = $movY != $dy;
|
||||||
|
$this->isCollidedHorizontally = ($movX != $dx or $movZ != $dz);
|
||||||
|
$this->isCollided = ($this->isCollidedHorizontally or $this->isCollidedVertically);
|
||||||
$this->onGround = ($movY != $dy and $movY < 0);
|
$this->onGround = ($movY != $dy and $movY < 0);
|
||||||
}
|
}
|
||||||
$this->updateFallState($dy, $this->onGround);
|
$this->updateFallState($dy, $this->onGround);
|
||||||
@ -984,31 +1034,45 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
Timings::$entityMoveTimer->stopTiming();
|
Timings::$entityMoveTimer->stopTiming();
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function checkBlockCollision(){
|
protected function checkBlockCollision(){
|
||||||
$minX = Math::floorFloat($this->boundingBox->minX - 0.001);
|
$minX = Math::floorFloat($this->boundingBox->minX + 0.001);
|
||||||
$minY = Math::floorFloat($this->boundingBox->minY - 0.001);
|
$minY = Math::floorFloat($this->boundingBox->minY + 0.001);
|
||||||
$minZ = Math::floorFloat($this->boundingBox->minZ - 0.001);
|
$minZ = Math::floorFloat($this->boundingBox->minZ + 0.001);
|
||||||
$maxX = Math::floorFloat($this->boundingBox->maxX + 0.001);
|
$maxX = Math::floorFloat($this->boundingBox->maxX - 0.001);
|
||||||
$maxY = Math::floorFloat($this->boundingBox->maxY + 0.001);
|
$maxY = Math::floorFloat($this->boundingBox->maxY - 0.001);
|
||||||
$maxZ = Math::floorFloat($this->boundingBox->maxZ + 0.001);
|
$maxZ = Math::floorFloat($this->boundingBox->maxZ - 0.001);
|
||||||
|
|
||||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
$vector = new Vector3(0, 0, 0);
|
||||||
for($x = $minX; $x <= $maxX; ++$x){
|
$v = new Vector3(0, 0, 0);
|
||||||
for($y = $minY; $y <= $maxY; ++$y){
|
|
||||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
for($v->z = $minZ; $v->z <= $maxZ; ++$v->z){
|
||||||
if($block !== null and $block->getID() > 0){
|
for($v->x = $minX; $v->x <= $maxX; ++$v->x){
|
||||||
|
for($v->y = $minY; $v->y <= $maxY; ++$v->y){
|
||||||
|
$block = $this->level->getBlock($v);
|
||||||
|
if($block !== null and $block->hasEntityCollision){
|
||||||
$block->onEntityCollide($this);
|
$block->onEntityCollide($this);
|
||||||
|
if(!($this instanceof Player)){
|
||||||
|
$block->addVelocityToEntity($this, $vector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!($this instanceof Player) and $vector->length() > 0){
|
||||||
|
$vector = $vector->normalize();
|
||||||
|
$d = 0.014;
|
||||||
|
$this->motionX += $vector->x * $d;
|
||||||
|
$this->motionY += $vector->y * $d;
|
||||||
|
$this->motionZ += $vector->z * $d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch, $force = false){
|
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){
|
||||||
if($this->setPosition($pos, $force) === true){
|
if($this->setPosition($pos) === true){
|
||||||
$this->setRotation($yaw, $pitch);
|
$this->setRotation($yaw, $pitch);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1023,18 +1087,13 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->scheduleUpdate();
|
$this->scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPosition(Vector3 $pos, $force = false){
|
public function setPosition(Vector3 $pos){
|
||||||
if($pos instanceof Position and $pos->getLevel() instanceof Level and $pos->getLevel() !== $this->getLevel()){
|
if($this->closed){
|
||||||
if($this->switchLevel($pos->getLevel()) === false){
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->justCreated and $force !== true){
|
if($pos instanceof Position and $pos->level instanceof Level and $pos->level !== $this->level){
|
||||||
$ev = new EntityMoveEvent($this, $pos);
|
if($this->switchLevel($pos->getLevel()) === false){
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent($ev);
|
|
||||||
if($ev->isCancelled()){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1051,11 +1110,11 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
if($this->chunk instanceof FullChunk){
|
if($this->chunk instanceof FullChunk){
|
||||||
$this->chunk->removeEntity($this);
|
$this->chunk->removeEntity($this);
|
||||||
}
|
}
|
||||||
$this->getLevel()->loadChunk($this->x >> 4, $this->z >> 4);
|
$this->level->loadChunk($this->x >> 4, $this->z >> 4);
|
||||||
$this->chunk = $this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4);
|
$this->chunk = $this->level->getChunk($this->x >> 4, $this->z >> 4);
|
||||||
|
|
||||||
if(!$this->justCreated){
|
if(!$this->justCreated){
|
||||||
$newChunk = $this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4);
|
$newChunk = $this->level->getUsingChunk($this->x >> 4, $this->z >> 4);
|
||||||
foreach($this->hasSpawned as $player){
|
foreach($this->hasSpawned as $player){
|
||||||
if(!isset($newChunk[$player->getID()])){
|
if(!isset($newChunk[$player->getID()])){
|
||||||
$this->despawnFrom($player);
|
$this->despawnFrom($player);
|
||||||
@ -1085,12 +1144,14 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->motionX = $motion->x;
|
$this->motionX = $motion->x;
|
||||||
$this->motionY = $motion->y;
|
$this->motionY = $motion->y;
|
||||||
$this->motionZ = $motion->z;
|
$this->motionZ = $motion->z;
|
||||||
|
|
||||||
if(!$this->justCreated){
|
if(!$this->justCreated){
|
||||||
if($this instanceof Player){
|
if($this instanceof Player){
|
||||||
$pk = new SetEntityMotionPacket;
|
$pk = new SetEntityMotionPacket();
|
||||||
$pk->entities = [
|
$pk->entities = [
|
||||||
[0, $this->motionX, $this->motionY, $this->motionZ]
|
[0, $this->motionX, $this->motionY, $this->motionZ]
|
||||||
];
|
];
|
||||||
@ -1115,9 +1176,20 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->scheduleUpdate();
|
$this->scheduleUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Vector3|Position|Location $pos
|
||||||
|
* @param float $yaw
|
||||||
|
* @param float $pitch
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){
|
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){
|
||||||
$from = Position::fromObject($this, $this->getLevel());
|
if($pos instanceof Location){
|
||||||
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->getLevel());
|
$yaw = $pos->yaw;
|
||||||
|
$pitch = $pos->pitch;
|
||||||
|
}
|
||||||
|
$from = Position::fromObject($this, $this->level);
|
||||||
|
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->level);
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityTeleportEvent($this, $from, $to));
|
$this->server->getPluginManager()->callEvent($ev = new EntityTeleportEvent($this, $from, $to));
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
return false;
|
return false;
|
||||||
@ -1136,12 +1208,12 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getID(){
|
public function getId(){
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function spawnToAll(){
|
public function spawnToAll(){
|
||||||
foreach($this->getLevel()->getUsingChunk($this->x >> 4, $this->z >> 4) as $player){
|
foreach($this->level->getUsingChunk($this->x >> 4, $this->z >> 4) as $player){
|
||||||
if(isset($player->id) and $player->spawned === true){
|
if(isset($player->id) and $player->spawned === true){
|
||||||
$this->spawnTo($player);
|
$this->spawnTo($player);
|
||||||
}
|
}
|
||||||
@ -1155,17 +1227,18 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function close(){
|
public function close(){
|
||||||
if($this->closed === false){
|
if(!$this->closed){
|
||||||
$this->server->getPluginManager()->callEvent(new EntityDespawnEvent($this));
|
$this->server->getPluginManager()->callEvent(new EntityDespawnEvent($this));
|
||||||
$this->closed = true;
|
$this->closed = true;
|
||||||
unset($this->level->updateEntities[$this->id]);
|
unset($this->level->updateEntities[$this->id]);
|
||||||
if($this->chunk instanceof FullChunk){
|
if($this->chunk instanceof FullChunk){
|
||||||
$this->chunk->removeEntity($this);
|
$this->chunk->removeEntity($this);
|
||||||
}
|
}
|
||||||
if(($level = $this->getLevel()) instanceof Level){
|
if($this->level instanceof Level){
|
||||||
$level->removeEntity($this);
|
$this->level->removeEntity($this);
|
||||||
}
|
}
|
||||||
$this->despawnFromAll();
|
$this->despawnFromAll();
|
||||||
|
$this->level = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,4 +24,5 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
interface Explosive{
|
interface Explosive{
|
||||||
|
|
||||||
|
public function explode();
|
||||||
}
|
}
|
@ -1,143 +0,0 @@
|
|||||||
<?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\entity;
|
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
use pocketmine\nbt\tag\Byte;
|
|
||||||
use pocketmine\block\Block;
|
|
||||||
use pocketmine\item\Item;
|
|
||||||
use pocketmine\network\protocol\AddEntityPacket;
|
|
||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
|
||||||
use pocketmine\Player;
|
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
|
||||||
|
|
||||||
class FallingBlock extends Entity{
|
|
||||||
|
|
||||||
const NETWORK_ID = 66;
|
|
||||||
|
|
||||||
public $width = 0.98;
|
|
||||||
public $length = 0.98;
|
|
||||||
public $height = 0.98;
|
|
||||||
|
|
||||||
protected $gravity = 0.04;
|
|
||||||
protected $drag = 0.02;
|
|
||||||
protected $blockId = 0;
|
|
||||||
|
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "FallingSand");
|
|
||||||
if(isset($this->namedtag->Tile)){
|
|
||||||
$this->blockId = $this->namedtag["Tile"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->blockId === 0){
|
|
||||||
$this->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function canCollideWith(Entity $entity){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getData(){
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onUpdate(){
|
|
||||||
$this->entityBaseTick();
|
|
||||||
|
|
||||||
if($this->closed !== false){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->ticksLived === 1){
|
|
||||||
$block = $this->level->getBlock($this->floor());
|
|
||||||
if($block->getID() != $this->blockId){
|
|
||||||
$this->kill();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$this->level->setBlock($this->floor(), Block::get(0, true));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->motionY -= $this->gravity;
|
|
||||||
|
|
||||||
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
|
||||||
|
|
||||||
$friction = 1 - $this->drag;
|
|
||||||
|
|
||||||
$this->motionX *= $friction;
|
|
||||||
$this->motionY *= 1 - $this->drag;
|
|
||||||
$this->motionZ *= $friction;
|
|
||||||
|
|
||||||
$pos = $this->floor();
|
|
||||||
|
|
||||||
if($this->onGround){
|
|
||||||
$this->kill();
|
|
||||||
$block = $this->level->getBlock($pos);
|
|
||||||
if(!$block->isFullBlock){
|
|
||||||
$this->getLevel()->dropItem($this, Item::get($this->getBlock(), 0, 1));
|
|
||||||
}else{
|
|
||||||
$this->getLevel()->setBlock($pos, Block::get($this->getBlock(), 0), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->updateMovement();
|
|
||||||
|
|
||||||
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBlock(){
|
|
||||||
return $this->blockId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveNBT(){
|
|
||||||
$this->namedtag->Tile = new Byte("Tile", $this->blockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function heal($amount){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function spawnTo(Player $player){
|
|
||||||
$pk = new AddEntityPacket;
|
|
||||||
$pk->type = FallingBlock::NETWORK_ID;
|
|
||||||
$pk->eid = $this->getID();
|
|
||||||
$pk->x = $this->x;
|
|
||||||
$pk->y = $this->y;
|
|
||||||
$pk->z = $this->z;
|
|
||||||
$pk->did = -$this->getBlock();
|
|
||||||
$player->dataPacket($pk);
|
|
||||||
|
|
||||||
$pk = new SetEntityMotionPacket;
|
|
||||||
$pk->entities = [
|
|
||||||
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
|
||||||
];
|
|
||||||
$player->dataPacket($pk);
|
|
||||||
|
|
||||||
parent::spawnTo($player);
|
|
||||||
}
|
|
||||||
}
|
|
170
src/pocketmine/entity/FallingSand.php
Normal file
170
src/pocketmine/entity/FallingSand.php
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?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\entity;
|
||||||
|
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\event\entity\EntityBlockChangeEvent;
|
||||||
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
|
use pocketmine\item\Item as ItemItem;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\nbt\tag\Byte;
|
||||||
|
use pocketmine\nbt\tag\Int;
|
||||||
|
use pocketmine\network\protocol\AddEntityPacket;
|
||||||
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
class FallingSand extends Entity{
|
||||||
|
const NETWORK_ID = 66;
|
||||||
|
|
||||||
|
public $width = 0.98;
|
||||||
|
public $length = 0.98;
|
||||||
|
public $height = 0.98;
|
||||||
|
|
||||||
|
protected $gravity = 0.04;
|
||||||
|
protected $drag = 0.02;
|
||||||
|
protected $blockId = 0;
|
||||||
|
protected $damage;
|
||||||
|
|
||||||
|
public $canCollide = false;
|
||||||
|
|
||||||
|
protected function initEntity(){
|
||||||
|
if(isset($this->namedtag->TileID)){
|
||||||
|
$this->blockId = $this->namedtag["TileID"];
|
||||||
|
}elseif(isset($this->namedtag->Tile)){
|
||||||
|
$this->blockId = $this->namedtag["Tile"];
|
||||||
|
$this->namedtag["TileID"] = new Int("TileID", $this->blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->namedtag->Data)){
|
||||||
|
$this->damage = $this->namedtag["Data"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->blockId === 0){
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canCollideWith(Entity $entity){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData(){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate($currentTick){
|
||||||
|
|
||||||
|
if($this->closed){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timings->startTiming();
|
||||||
|
|
||||||
|
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||||
|
$this->lastUpdate = $currentTick;
|
||||||
|
|
||||||
|
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
if(!$this->dead){
|
||||||
|
if($this->ticksLived === 1){
|
||||||
|
$block = $this->level->getBlock($pos = (new Vector3($this->x, $this->y, $this->z))->floor());
|
||||||
|
if($block->getID() != $this->blockId){
|
||||||
|
$this->kill();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$this->level->setBlock($pos, Block::get(0), true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->motionY -= $this->gravity;
|
||||||
|
|
||||||
|
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||||
|
|
||||||
|
$friction = 1 - $this->drag;
|
||||||
|
|
||||||
|
$this->motionX *= $friction;
|
||||||
|
$this->motionY *= 1 - $this->drag;
|
||||||
|
$this->motionZ *= $friction;
|
||||||
|
|
||||||
|
$pos = (new Vector3($this->x, $this->y, $this->z))->floor();
|
||||||
|
|
||||||
|
if($this->onGround){
|
||||||
|
$this->kill();
|
||||||
|
$block = $this->level->getBlock($pos);
|
||||||
|
if(!$block->isFullBlock){
|
||||||
|
$this->getLevel()->dropItem($this, ItemItem::get($this->getBlock(), $this->getDamage(), 1));
|
||||||
|
}else{
|
||||||
|
$this->server->getPluginManager()->callEvent($ev = new EntityBlockChangeEvent($this, $block, Block::get($this->getBlock(), $this->getDamage())));
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$this->getLevel()->setBlock($pos, $ev->getTo(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$hasUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updateMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hasUpdate or !$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlock(){
|
||||||
|
return $this->blockId;
|
||||||
|
}
|
||||||
|
public function getDamage(){
|
||||||
|
return $this->damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveNBT(){
|
||||||
|
$this->namedtag->TileID = new Int("TileID", $this->blockId);
|
||||||
|
$this->namedtag->Data = new Byte("Data", $this->damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function spawnTo(Player $player){
|
||||||
|
$pk = new AddEntityPacket();
|
||||||
|
$pk->type = FallingSand::NETWORK_ID;
|
||||||
|
$pk->eid = $this->getID();
|
||||||
|
$pk->x = $this->x;
|
||||||
|
$pk->y = $this->y;
|
||||||
|
$pk->z = $this->z;
|
||||||
|
$pk->did = -($this->getBlock() | $this->getDamage() << 0x10);
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
$pk = new SetEntityMotionPacket();
|
||||||
|
$pk->entities = [
|
||||||
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
|
];
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
parent::spawnTo($player);
|
||||||
|
}
|
||||||
|
}
|
@ -23,16 +23,16 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
use pocketmine\inventory\InventoryHolder;
|
use pocketmine\inventory\InventoryHolder;
|
||||||
use pocketmine\inventory\PlayerInventory;
|
use pocketmine\inventory\PlayerInventory;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item as ItemItem;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\tag\Byte;
|
use pocketmine\nbt\tag\Byte;
|
||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
use pocketmine\nbt\tag\Enum;
|
use pocketmine\nbt\tag\Enum;
|
||||||
use pocketmine\nbt\tag\Short;
|
use pocketmine\nbt\tag\Short;
|
||||||
|
use pocketmine\Network;
|
||||||
use pocketmine\network\protocol\AddPlayerPacket;
|
use pocketmine\network\protocol\AddPlayerPacket;
|
||||||
use pocketmine\network\protocol\RemovePlayerPacket;
|
use pocketmine\network\protocol\RemovePlayerPacket;
|
||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
use pocketmine\Network;
|
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\TextFormat;
|
use pocketmine\utils\TextFormat;
|
||||||
|
|
||||||
@ -67,9 +67,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
|
if($item["Slot"] >= 0 and $item["Slot"] < 9){ //Hotbar
|
||||||
$this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1);
|
$this->inventory->setHotbarSlotIndex($item["Slot"], isset($item["TrueSlot"]) ? $item["TrueSlot"] : -1);
|
||||||
}elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor
|
}elseif($item["Slot"] >= 100 and $item["Slot"] < 104){ //Armor
|
||||||
$this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, Item::get($item["id"], $item["Damage"], $item["Count"]), $this);
|
$this->inventory->setItem($this->inventory->getSize() + $item["Slot"] - 100, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this);
|
||||||
}else{
|
}else{
|
||||||
$this->inventory->setItem($item["Slot"] - 9, Item::get($item["id"], $item["Damage"], $item["Count"]), $this);
|
$this->inventory->setItem($item["Slot"] - 9, ItemItem::get($item["id"], $item["Damage"], $item["Count"]), $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
//Armor
|
//Armor
|
||||||
for($slot = 100; $slot < 104; ++$slot){
|
for($slot = 100; $slot < 104; ++$slot){
|
||||||
$item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
|
$item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100);
|
||||||
if($item instanceof Item and $item->getID() !== Item::AIR){
|
if($item instanceof ItemItem and $item->getID() !== ItemItem::AIR){
|
||||||
$this->namedtag->Inventory[$slot] = new Compound(false, [
|
$this->namedtag->Inventory[$slot] = new Compound(false, [
|
||||||
new Byte("Count", $item->getCount()),
|
new Byte("Count", $item->getCount()),
|
||||||
new Short("Damage", $item->getDamage()),
|
new Short("Damage", $item->getDamage()),
|
||||||
@ -156,7 +156,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
if($player !== $this and !isset($this->hasSpawned[$player->getID()])){
|
if($player !== $this and !isset($this->hasSpawned[$player->getID()])){
|
||||||
$this->hasSpawned[$player->getID()] = $player;
|
$this->hasSpawned[$player->getID()] = $player;
|
||||||
|
|
||||||
$pk = new AddPlayerPacket;
|
$pk = new AddPlayerPacket();
|
||||||
$pk->clientID = 0;
|
$pk->clientID = 0;
|
||||||
if($player->getRemoveFormat()){
|
if($player->getRemoveFormat()){
|
||||||
$pk->username = TextFormat::clean($this->nameTag);
|
$pk->username = TextFormat::clean($this->nameTag);
|
||||||
@ -174,7 +174,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
$pk->metadata = $this->getData();
|
$pk->metadata = $this->getData();
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
$pk = new SetEntityMotionPacket;
|
$pk = new SetEntityMotionPacket();
|
||||||
$pk->entities = [
|
$pk->entities = [
|
||||||
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
];
|
];
|
||||||
@ -188,7 +188,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
|
|
||||||
public function despawnFrom(Player $player){
|
public function despawnFrom(Player $player){
|
||||||
if(isset($this->hasSpawned[$player->getID()])){
|
if(isset($this->hasSpawned[$player->getID()])){
|
||||||
$pk = new RemovePlayerPacket;
|
$pk = new RemovePlayerPacket();
|
||||||
$pk->eid = $this->id;
|
$pk->eid = $this->id;
|
||||||
$pk->clientID = 0;
|
$pk->clientID = 0;
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
@ -208,22 +208,19 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
17 => ["type" => 6, "value" => [0, 0, 0]],
|
17 => ["type" => 6, "value" => [0, 0, 0]],
|
||||||
];
|
];
|
||||||
|
|
||||||
/*if($this->class === ENTITY_MOB and $this->type === MOB_SHEEP){
|
|
||||||
if(!isset($this->data["Sheared"])){
|
|
||||||
$this->data["Sheared"] = 0;
|
|
||||||
$this->data["Color"] = mt_rand(0,15);
|
|
||||||
}
|
|
||||||
$d[16]["value"] = (($this->data["Sheared"] == 1 ? 1:0) << 4) | ($this->data["Color"] & 0x0F);
|
|
||||||
}elseif($this->type === OBJECT_PRIMEDTNT){
|
|
||||||
$d[16]["value"] = (int) max(0, $this->data["fuse"] - (microtime(true) - $this->spawntime) * 20);
|
|
||||||
}elseif($this->class === ENTITY_PLAYER){
|
|
||||||
if($this->player->sleeping !== false){
|
|
||||||
$d[16]["value"] = 2;
|
|
||||||
$d[17]["value"] = array($this->player->sleeping->x, $this->player->sleeping->y, $this->player->sleeping->z);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return $d;
|
return $d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function close(){
|
||||||
|
if(!$this->closed){
|
||||||
|
if(!($this instanceof Player) or $this->loggedIn){
|
||||||
|
foreach($this->getInventory()->getViewers() as $player){
|
||||||
|
$this->getInventory()->close($player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->inventory = null;
|
||||||
|
parent::close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
|
use pocketmine\event\entity\ItemDespawnEvent;
|
||||||
|
use pocketmine\event\entity\ItemSpawnEvent;
|
||||||
|
use pocketmine\item\Item as ItemItem;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\Byte;
|
use pocketmine\nbt\tag\Byte;
|
||||||
use pocketmine\nbt\tag\Compound;
|
use pocketmine\nbt\tag\Compound;
|
||||||
@ -32,12 +35,13 @@ use pocketmine\network\protocol\AddItemEntityPacket;
|
|||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
class DroppedItem extends Entity{
|
class Item extends Entity{
|
||||||
|
const NETWORK_ID = 64;
|
||||||
|
|
||||||
protected $owner = null;
|
protected $owner = null;
|
||||||
protected $thrower = null;
|
protected $thrower = null;
|
||||||
protected $pickupDelay = 0;
|
protected $pickupDelay = 0;
|
||||||
/** @var Item */
|
/** @var ItemItem */
|
||||||
protected $item;
|
protected $item;
|
||||||
|
|
||||||
public $width = 0.25;
|
public $width = 0.25;
|
||||||
@ -46,10 +50,11 @@ class DroppedItem extends Entity{
|
|||||||
protected $gravity = 0.04;
|
protected $gravity = 0.04;
|
||||||
protected $drag = 0.02;
|
protected $drag = 0.02;
|
||||||
|
|
||||||
|
public $canCollide = false;
|
||||||
|
|
||||||
protected function initEntity(){
|
protected function initEntity(){
|
||||||
$this->namedtag->id = new String("id", "Item");
|
|
||||||
$this->setMaxHealth(5);
|
$this->setMaxHealth(5);
|
||||||
$this->setHealth(@$this->namedtag["Health"]);
|
$this->setHealth($this->namedtag["Health"]);
|
||||||
if(isset($this->namedtag->Age)){
|
if(isset($this->namedtag->Age)){
|
||||||
$this->age = $this->namedtag["Age"];
|
$this->age = $this->namedtag["Age"];
|
||||||
}
|
}
|
||||||
@ -62,57 +67,86 @@ class DroppedItem extends Entity{
|
|||||||
if(isset($this->namedtag->Thrower)){
|
if(isset($this->namedtag->Thrower)){
|
||||||
$this->thrower = $this->namedtag["Thrower"];
|
$this->thrower = $this->namedtag["Thrower"];
|
||||||
}
|
}
|
||||||
$this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
|
$this->item = ItemItem::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
|
||||||
|
|
||||||
|
|
||||||
|
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onUpdate(){
|
public function onUpdate($currentTick){
|
||||||
$this->entityBaseTick();
|
|
||||||
|
|
||||||
if($this->closed !== false){
|
if($this->closed !== false){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
|
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||||
--$this->pickupDelay;
|
$this->lastUpdate = $currentTick;
|
||||||
|
|
||||||
|
$this->timings->startTiming();
|
||||||
|
|
||||||
|
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
if(!$this->dead){
|
||||||
|
|
||||||
|
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
|
||||||
|
$this->pickupDelay -= $tickDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->motionY -= $this->gravity;
|
||||||
|
|
||||||
|
$this->keepMovement = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
||||||
|
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||||
|
|
||||||
|
$friction = 1 - $this->drag;
|
||||||
|
|
||||||
|
if($this->onGround and ($this->motionX != 0 or $this->motionZ != 0)){
|
||||||
|
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->motionX *= $friction;
|
||||||
|
$this->motionY *= 1 - $this->drag;
|
||||||
|
$this->motionZ *= $friction;
|
||||||
|
|
||||||
|
$this->updateMovement();
|
||||||
|
|
||||||
|
if($this->onGround){
|
||||||
|
$this->motionY *= -0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->age > 6000){
|
||||||
|
$this->server->getPluginManager()->callEvent($ev = new ItemDespawnEvent($this));
|
||||||
|
if($ev->isCancelled()){
|
||||||
|
$this->age = 0;
|
||||||
|
}else{
|
||||||
|
$this->kill();
|
||||||
|
$hasUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->motionY -= $this->gravity;
|
$this->timings->stopTiming();
|
||||||
|
|
||||||
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
return $hasUpdate or !$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0;
|
||||||
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
|
||||||
|
|
||||||
$friction = 1 - $this->drag;
|
|
||||||
|
|
||||||
if($this->onGround){
|
|
||||||
$friction = $this->getLevel()->getBlock(new Vector3($this->getFloorX(), $this->getFloorY() - 1, $this->getFloorZ()))->frictionFactor * $friction;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->motionX *= $friction;
|
|
||||||
$this->motionY *= 1 - $this->drag;
|
|
||||||
$this->motionZ *= $friction;
|
|
||||||
|
|
||||||
if($this->onGround){
|
|
||||||
$this->motionY *= -0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->age > 6000){
|
|
||||||
$this->kill();
|
|
||||||
}
|
|
||||||
$this->updateMovement();
|
|
||||||
|
|
||||||
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||||
|
if($source instanceof EntityDamageEvent){
|
||||||
|
$this->server->getPluginManager()->callEvent($source);
|
||||||
|
$damage = $source->getFinalDamage();
|
||||||
|
if($source->isCancelled()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->setLastDamageCause($source);
|
$this->setLastDamageCause($source);
|
||||||
$this->setHealth($this->getHealth() - $damage);
|
$this->setHealth($this->getHealth() - $damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function heal($amount){
|
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveNBT(){
|
public function saveNBT(){
|
||||||
|
parent::saveNBT();
|
||||||
$this->namedtag->Item = new Compound("Item", [
|
$this->namedtag->Item = new Compound("Item", [
|
||||||
"id" => new Short("id", $this->item->getID()),
|
"id" => new Short("id", $this->item->getID()),
|
||||||
"Damage" => new Short("Damage", $this->item->getDamage()),
|
"Damage" => new Short("Damage", $this->item->getDamage()),
|
||||||
@ -139,7 +173,7 @@ class DroppedItem extends Entity{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Item
|
* @return ItemItem
|
||||||
*/
|
*/
|
||||||
public function getItem(){
|
public function getItem(){
|
||||||
return $this->item;
|
return $this->item;
|
||||||
@ -203,7 +237,7 @@ class DroppedItem extends Entity{
|
|||||||
$pk->item = $this->getItem();
|
$pk->item = $this->getItem();
|
||||||
$player->dataPacket($pk);
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
$pk = new SetEntityMotionPacket;
|
$pk = new SetEntityMotionPacket();
|
||||||
$pk->entities = [
|
$pk->entities = [
|
||||||
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
];
|
];
|
@ -22,16 +22,18 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
use pocketmine\event\entity\EntityDeathEvent;
|
use pocketmine\event\entity\EntityDeathEvent;
|
||||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item as ItemItem;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\Short;
|
use pocketmine\nbt\tag\Short;
|
||||||
use pocketmine\network\protocol\EntityEventPacket;
|
use pocketmine\network\protocol\EntityEventPacket;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
use pocketmine\utils\BlockIterator;
|
||||||
|
|
||||||
abstract class Living extends Entity implements Damageable{
|
abstract class Living extends Entity implements Damageable{
|
||||||
|
|
||||||
@ -62,13 +64,29 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
|
|
||||||
public function hasLineOfSight(Entity $entity){
|
public function hasLineOfSight(Entity $entity){
|
||||||
//TODO: head height
|
//TODO: head height
|
||||||
return $this->getLevel()->rayTraceBlocks(new Vector3($this->x, $this->y + $this->height, $this->z), new Vector3($entity->x, $entity->y + $entity->height, $entity->z)) === null;
|
return true;
|
||||||
|
//return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||||
if($this->attackTime > 0){
|
if($this->attackTime > 0){
|
||||||
$lastCause = $this->getLastDamageCause();
|
$lastCause = $this->getLastDamageCause();
|
||||||
if($lastCause instanceof EntityDamageEvent and $lastCause->getDamage() >= $damage){
|
if($lastCause instanceof EntityDamageEvent and $lastCause->getDamage() >= $damage){
|
||||||
|
if($source instanceof EntityDamageEvent){
|
||||||
|
$source->setCancelled();
|
||||||
|
$this->server->getPluginManager()->callEvent($source);
|
||||||
|
$damage = $source->getFinalDamage();
|
||||||
|
if($source->isCancelled()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}elseif($source instanceof EntityDamageEvent){
|
||||||
|
$this->server->getPluginManager()->callEvent($source);
|
||||||
|
$damage = $source->getFinalDamage();
|
||||||
|
if($source->isCancelled()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,26 +96,41 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
$pk->event = 2; //Ouch!
|
$pk->event = 2; //Ouch!
|
||||||
Server::broadcastPacket($this->hasSpawned, $pk);
|
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||||
$this->setLastDamageCause($source);
|
$this->setLastDamageCause($source);
|
||||||
$motion = new Vector3(0, 0, 0);
|
|
||||||
if($source instanceof EntityDamageByEntityEvent){
|
if($source instanceof EntityDamageByEntityEvent){
|
||||||
$e = $source->getDamager();
|
$e = $source->getDamager();
|
||||||
$deltaX = $this->x - $e->x;
|
$deltaX = $this->x - $e->x;
|
||||||
$deltaZ = $this->z - $e->z;
|
$deltaZ = $this->z - $e->z;
|
||||||
$yaw = atan2($deltaX, $deltaZ);
|
$yaw = atan2($deltaX, $deltaZ);
|
||||||
$motion->x = sin($yaw) * 0.5;
|
$this->knockBack($e, $damage, sin($yaw), cos($yaw));
|
||||||
$motion->z = cos($yaw) * 0.5;
|
|
||||||
}
|
}
|
||||||
$this->setMotion($motion);
|
|
||||||
$this->setHealth($this->getHealth() - $damage);
|
$this->setHealth($this->getHealth() - $damage);
|
||||||
|
|
||||||
$this->attackTime = 10; //0.5 seconds cooldown
|
$this->attackTime = 10; //0.5 seconds cooldown
|
||||||
}
|
}
|
||||||
|
|
||||||
public function heal($amount){
|
public function knockBack(Entity $attacker, $damage, $x, $z){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount));
|
$f = sqrt($x ** 2 + $z ** 2);
|
||||||
if($ev->isCancelled()){
|
$base = 0.4;
|
||||||
return;
|
|
||||||
|
$motion = new Vector3($this->motionX, $this->motionY, $this->motionZ);
|
||||||
|
|
||||||
|
$motion->x /= 2;
|
||||||
|
$motion->y /= 2;
|
||||||
|
$motion->z /= 2;
|
||||||
|
$motion->x += ($x / $f) * $base;
|
||||||
|
$motion->y += $base;
|
||||||
|
$motion->z += ($z / $f) * $base;
|
||||||
|
|
||||||
|
if($motion->y > $base){
|
||||||
|
$motion->y = $base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setMotion($motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||||
$this->setHealth($this->getHealth() + $amount);
|
$this->setHealth($this->getHealth() + $amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,44 +145,100 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entityBaseTick(){
|
public function entityBaseTick($tickDiff = 1){
|
||||||
Timings::$timerEntityBaseTick->startTiming();
|
Timings::$timerEntityBaseTick->startTiming();
|
||||||
parent::entityBaseTick();
|
parent::entityBaseTick($tickDiff);
|
||||||
|
|
||||||
if($this->dead !== true and $this->isInsideOfSolid()){
|
if($this->dead !== true and $this->isInsideOfSolid()){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1));
|
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1);
|
||||||
if(!$ev->isCancelled()){
|
$this->attack($ev->getFinalDamage(), $ev);
|
||||||
$this->attack($ev->getFinalDamage(), $ev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->dead !== true and $this->isInsideOfWater()){
|
if($this->dead !== true and $this->isInsideOfWater()){
|
||||||
--$this->airTicks;
|
$this->airTicks -= $tickDiff;
|
||||||
if($this->airTicks <= -20){
|
if($this->airTicks <= -20){
|
||||||
$this->airTicks = 0;
|
$this->airTicks = 0;
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2));
|
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2);
|
||||||
if(!$ev->isCancelled()){
|
$this->attack($ev->getFinalDamage(), $ev);
|
||||||
$this->attack($ev->getFinalDamage(), $ev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->extinguish();
|
|
||||||
}else{
|
}else{
|
||||||
$this->airTicks = 300;
|
$this->airTicks = 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->attackTime > 0){
|
if($this->attackTime > 0){
|
||||||
--$this->attackTime;
|
$this->attackTime -= $tickDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timings::$timerEntityBaseTick->stopTiming();
|
Timings::$timerEntityBaseTick->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Item[]
|
* @return ItemItem[]
|
||||||
*/
|
*/
|
||||||
public function getDrops(){
|
public function getDrops(){
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $maxDistance
|
||||||
|
* @param int $maxLength
|
||||||
|
* @param array $transparent
|
||||||
|
*
|
||||||
|
* @return Block[]
|
||||||
|
*/
|
||||||
|
public function getLineOfSight($maxDistance, $maxLength = 0, array $transparent = []){
|
||||||
|
if($maxDistance > 120){
|
||||||
|
$maxDistance = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count($transparent) === 0){
|
||||||
|
$transparent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocks = [];
|
||||||
|
$nextIndex = 0;
|
||||||
|
|
||||||
|
$itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance);
|
||||||
|
|
||||||
|
while($itr->valid()){
|
||||||
|
$itr->next();
|
||||||
|
$block = $itr->current();
|
||||||
|
$blocks[$nextIndex++] = $block;
|
||||||
|
|
||||||
|
if($maxLength !== 0 and count($blocks) > $maxLength){
|
||||||
|
array_shift($blocks);
|
||||||
|
--$nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = $block->getID();
|
||||||
|
|
||||||
|
if($transparent === null){
|
||||||
|
if($id !== 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(!isset($transparent[$id])){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $maxDistance
|
||||||
|
* @param array $transparent
|
||||||
|
*
|
||||||
|
* @return Block
|
||||||
|
*/
|
||||||
|
public function getTargetBlock($maxDistance, array $transparent = []){
|
||||||
|
$block = array_shift($this->getLineOfSight($maxDistance, 1, $transparent));
|
||||||
|
if($block instanceof Block){
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
class Ozelot extends Animal implements Tameable{
|
||||||
|
|
||||||
class Ocelot extends Animal implements Tameable{
|
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Ozelot");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Painting extends Hanging{
|
class Painting extends Hanging{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Painting");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Pig extends Animal implements Rideable{
|
class Pig extends Animal implements Rideable{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Pig");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class PigZombie extends Zombie{
|
class PigZombie extends Zombie{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "PigZombie");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,137 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
|
use pocketmine\event\entity\ExplosionPrimeEvent;
|
||||||
|
use pocketmine\level\Explosion;
|
||||||
|
use pocketmine\nbt\tag\Byte;
|
||||||
|
use pocketmine\network\protocol\AddEntityPacket;
|
||||||
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
class PrimedTNT extends Entity implements Explosive{
|
class PrimedTNT extends Entity implements Explosive{
|
||||||
|
const NETWORK_ID = 65;
|
||||||
|
|
||||||
|
public $width = 0.98;
|
||||||
|
public $length = 0.98;
|
||||||
|
public $height = 0.98;
|
||||||
|
|
||||||
|
protected $gravity = 0.04;
|
||||||
|
protected $drag = 0.02;
|
||||||
|
|
||||||
|
protected $fuse;
|
||||||
|
|
||||||
|
public $canCollide = false;
|
||||||
|
|
||||||
protected function initEntity(){
|
protected function initEntity(){
|
||||||
$this->namedtag->id = new String("id", "PrimedTNT");
|
if(isset($this->namedtag->Fuse)){
|
||||||
|
$this->fuse = $this->namedtag["Fuse"];
|
||||||
|
}else{
|
||||||
|
$this->fuse = 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function canCollideWith(Entity $entity){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData(){
|
||||||
|
return [
|
||||||
|
16 => ["type" => 0, "value" => $this->fuse],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveNBT(){
|
||||||
|
parent::saveNBT();
|
||||||
|
$this->namedtag->Fuse = new Byte("Fuse", $this->fuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate($currentTick){
|
||||||
|
|
||||||
|
if($this->closed){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timings->startTiming();
|
||||||
|
|
||||||
|
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||||
|
$this->lastUpdate = $currentTick;
|
||||||
|
|
||||||
|
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
if(!$this->dead){
|
||||||
|
|
||||||
|
$this->motionY -= $this->gravity;
|
||||||
|
|
||||||
|
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||||
|
|
||||||
|
$friction = 1 - $this->drag;
|
||||||
|
|
||||||
|
$this->motionX *= $friction;
|
||||||
|
$this->motionY *= $friction;
|
||||||
|
$this->motionZ *= $friction;
|
||||||
|
|
||||||
|
$this->updateMovement();
|
||||||
|
|
||||||
|
if($this->onGround){
|
||||||
|
$this->motionY *= -0.5;
|
||||||
|
$this->motionX *= 0.7;
|
||||||
|
$this->motionZ *= 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fuse -= $tickDiff;
|
||||||
|
|
||||||
|
if($this->fuse <= 0){
|
||||||
|
$this->kill();
|
||||||
|
$this->explode();
|
||||||
|
}else{
|
||||||
|
$this->sendMetadata($this->getViewers());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $hasUpdate or $this->fuse >= 0 or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function explode(){
|
||||||
|
$this->server->getPluginManager()->callEvent($ev = new ExplosionPrimeEvent($this, 4));
|
||||||
|
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$explosion = new Explosion($this, $ev->getForce(), $this);
|
||||||
|
if($ev->isBlockBreaking()){
|
||||||
|
$explosion->explodeA();
|
||||||
|
}
|
||||||
|
$explosion->explodeB();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function spawnTo(Player $player){
|
||||||
|
$pk = new AddEntityPacket();
|
||||||
|
$pk->type = PrimedTNT::NETWORK_ID;
|
||||||
|
$pk->eid = $this->getID();
|
||||||
|
$pk->x = $this->x;
|
||||||
|
$pk->y = $this->y;
|
||||||
|
$pk->z = $this->z;
|
||||||
|
$pk->did = 0;
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
$pk = new SetEntityMotionPacket();
|
||||||
|
$pk->entities = [
|
||||||
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
|
];
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
parent::spawnTo($player);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,6 +22,171 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
|
use pocketmine\event\entity\EntityCombustByEntityEvent;
|
||||||
|
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
|
||||||
|
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||||
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
|
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||||
|
use pocketmine\event\entity\ProjectileHitEvent;
|
||||||
|
use pocketmine\level\MovingObjectPosition;
|
||||||
|
use pocketmine\math\Vector3;
|
||||||
|
use pocketmine\nbt\tag\Short;
|
||||||
|
|
||||||
abstract class Projectile extends Entity{
|
abstract class Projectile extends Entity{
|
||||||
|
/** @var Entity */
|
||||||
|
public $shootingEntity = null;
|
||||||
|
protected $damage = 0;
|
||||||
|
|
||||||
|
private $hadCollision = false;
|
||||||
|
|
||||||
|
protected function initEntity(){
|
||||||
|
$this->setMaxHealth(1);
|
||||||
|
$this->setHealth(1);
|
||||||
|
if(isset($this->namedtag->Age)){
|
||||||
|
$this->age = $this->namedtag["Age"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canCollideWith(Entity $entity){
|
||||||
|
return $entity instanceof Living and !$this->onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData(){
|
||||||
|
$flags = 0;
|
||||||
|
$flags |= $this->fireTicks > 0 ? 1 : 0;
|
||||||
|
|
||||||
|
return [
|
||||||
|
0 => ["type" => 0, "value" => $flags],
|
||||||
|
1 => ["type" => 1, "value" => $this->airTicks],
|
||||||
|
16 => ["type" => 0, "value" => 0] //Is critical
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveNBT(){
|
||||||
|
parent::saveNBT();
|
||||||
|
$this->namedtag->Age = new Short("Age", $this->age);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate($currentTick){
|
||||||
|
if($this->closed){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||||
|
$this->lastUpdate = $currentTick;
|
||||||
|
|
||||||
|
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
if(!$this->dead){
|
||||||
|
|
||||||
|
$movingObjectPosition = null;
|
||||||
|
|
||||||
|
if(!$this->isCollided){
|
||||||
|
$this->motionY -= $this->gravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->keepMovement = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
||||||
|
|
||||||
|
$moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
|
||||||
|
|
||||||
|
$list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
|
||||||
|
|
||||||
|
$nearDistance = PHP_INT_MAX;
|
||||||
|
$nearEntity = null;
|
||||||
|
|
||||||
|
foreach($list as $entity){
|
||||||
|
if(/*!$entity->canCollideWith($this) or */
|
||||||
|
($entity === $this->shootingEntity and $this->ticksLived < 5)
|
||||||
|
){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
|
||||||
|
$ob = $axisalignedbb->calculateIntercept($this, $moveVector);
|
||||||
|
|
||||||
|
if($ob === null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$distance = $this->distance($ob->hitVector);
|
||||||
|
|
||||||
|
if($distance < $nearDistance){
|
||||||
|
$nearDistance = $distance;
|
||||||
|
$nearEntity = $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($nearEntity !== null){
|
||||||
|
$movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($movingObjectPosition !== null){
|
||||||
|
if($movingObjectPosition->entityHit !== null){
|
||||||
|
|
||||||
|
$this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this));
|
||||||
|
|
||||||
|
$motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2);
|
||||||
|
$damage = ceil($motion * $this->damage);
|
||||||
|
|
||||||
|
if($this->shootingEntity === null){
|
||||||
|
$ev = new EntityDamageByEntityEvent($this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
|
||||||
|
}else{
|
||||||
|
$ev = new EntityDamageByChildEntityEvent($this->shootingEntity, $this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
$movingObjectPosition->entityHit->attack($ev->getFinalDamage(), $ev);
|
||||||
|
|
||||||
|
|
||||||
|
if($this->fireTicks > 0){
|
||||||
|
$ev = new EntityCombustByEntityEvent($this, $movingObjectPosition->entityHit, 5);
|
||||||
|
$this->server->getPluginManager()->callEvent($ev);
|
||||||
|
if(!$ev->isCancelled()){
|
||||||
|
$movingObjectPosition->entityHit->setOnFire($ev->getDuration());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->kill();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||||
|
|
||||||
|
if($this->isCollided and !$this->hadCollision){
|
||||||
|
$this->hadCollision = true;
|
||||||
|
|
||||||
|
$this->motionX = 0;
|
||||||
|
$this->motionY = 0;
|
||||||
|
$this->motionZ = 0;
|
||||||
|
|
||||||
|
$this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this));
|
||||||
|
}elseif(!$this->isCollided and !$this->hadCollision){
|
||||||
|
$this->hadCollision = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0){
|
||||||
|
$f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2));
|
||||||
|
$this->yaw = (atan2($this->motionX, $this->motionZ) * 180 / M_PI);
|
||||||
|
$this->pitch = (atan2($this->motionY, $f) * 180 / M_PI);
|
||||||
|
$hasUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updateMovement();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hasUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Sheep extends Animal implements Colorable{
|
class Sheep extends Animal implements Colorable{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Sheep");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Silverfish extends Monster{
|
class Silverfish extends Monster{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Silverfish");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -21,9 +21,6 @@
|
|||||||
|
|
||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
class Skeleton extends Monster implements ProjectileSource{
|
class Skeleton extends Monster implements ProjectileSource{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new Skeleton("id", "Chicken");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Slime extends Living{
|
class Slime extends Living{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Slime");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,10 +22,62 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
use pocketmine\level\format\FullChunk;
|
||||||
|
use pocketmine\nbt\tag\Compound;
|
||||||
|
use pocketmine\network\protocol\AddEntityPacket;
|
||||||
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
class Snowball extends Projectile{
|
class Snowball extends Projectile{
|
||||||
protected function initEntity(){
|
const NETWORK_ID = 81;
|
||||||
$this->namedtag->id = new String("id", "Snowball");
|
|
||||||
|
public $width = 0.25;
|
||||||
|
public $length = 0.25;
|
||||||
|
public $height = 0.25;
|
||||||
|
|
||||||
|
protected $gravity = 0.03;
|
||||||
|
protected $drag = 0.01;
|
||||||
|
|
||||||
|
public function __construct(FullChunk $chunk, Compound $nbt, Entity $shootingEntity = null){
|
||||||
|
$this->shootingEntity = $shootingEntity;
|
||||||
|
parent::__construct($chunk, $nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onUpdate($currentTick){
|
||||||
|
if($this->closed){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timings->startTiming();
|
||||||
|
|
||||||
|
$hasUpdate = parent::onUpdate($currentTick);
|
||||||
|
|
||||||
|
if($this->age > 1200 or $this->isCollided){
|
||||||
|
$this->kill();
|
||||||
|
$hasUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->timings->stopTiming();
|
||||||
|
|
||||||
|
return $hasUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function spawnTo(Player $player){
|
||||||
|
$pk = new AddEntityPacket();
|
||||||
|
$pk->type = Snowball::NETWORK_ID;
|
||||||
|
$pk->eid = $this->getID();
|
||||||
|
$pk->x = $this->x;
|
||||||
|
$pk->y = $this->y;
|
||||||
|
$pk->z = $this->z;
|
||||||
|
$pk->did = 0; //TODO: send motion here
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
$pk = new SetEntityMotionPacket();
|
||||||
|
$pk->entities = [
|
||||||
|
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||||
|
];
|
||||||
|
$player->dataPacket($pk);
|
||||||
|
|
||||||
|
parent::spawnTo($player);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Spider extends Monster{
|
class Spider extends Monster{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Spider");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -23,7 +23,6 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\Int;
|
use pocketmine\nbt\tag\Int;
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
use pocketmine\network\protocol\AddMobPacket;
|
use pocketmine\network\protocol\AddMobPacket;
|
||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -48,7 +47,6 @@ class Villager extends Creature implements NPC, Ageable{
|
|||||||
|
|
||||||
protected function initEntity(){
|
protected function initEntity(){
|
||||||
parent::initEntity();
|
parent::initEntity();
|
||||||
$this->namedtag->id = new String("id", "Villager");
|
|
||||||
if(!isset($this->namedtag->Profession)){
|
if(!isset($this->namedtag->Profession)){
|
||||||
$this->setProfession(self::PROFESSION_GENERIC);
|
$this->setProfession(self::PROFESSION_GENERIC);
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
|
|
||||||
class Wolf extends Animal implements Tameable{
|
class Wolf extends Animal implements Tameable{
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Wolf");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -23,8 +23,7 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
|
|
||||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item as ItemItem;
|
||||||
use pocketmine\nbt\tag\String;
|
|
||||||
use pocketmine\network\protocol\AddMobPacket;
|
use pocketmine\network\protocol\AddMobPacket;
|
||||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
@ -36,10 +35,6 @@ class Zombie extends Monster{
|
|||||||
public $length = 0.6;
|
public $length = 0.6;
|
||||||
public $height = 1.8;
|
public $height = 1.8;
|
||||||
|
|
||||||
protected function initEntity(){
|
|
||||||
$this->namedtag->id = new String("id", "Zombie");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName(){
|
public function getName(){
|
||||||
return "Zombie";
|
return "Zombie";
|
||||||
}
|
}
|
||||||
@ -83,19 +78,19 @@ class Zombie extends Monster{
|
|||||||
|
|
||||||
public function getDrops(){
|
public function getDrops(){
|
||||||
$drops = [
|
$drops = [
|
||||||
Item::get(Item::FEATHER, 0, 1)
|
ItemItem::get(ItemItem::FEATHER, 0, 1)
|
||||||
];
|
];
|
||||||
if($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player){
|
if($this->lastDamageCause instanceof EntityDamageByEntityEvent and $this->lastDamageCause->getEntity() instanceof Player){
|
||||||
if(mt_rand(0, 199) < 5){
|
if(mt_rand(0, 199) < 5){
|
||||||
switch(mt_rand(0, 2)){
|
switch(mt_rand(0, 2)){
|
||||||
case 0:
|
case 0:
|
||||||
$drops[] = Item::get(Item::IRON_INGOT, 0, 1);
|
$drops[] = ItemItem::get(ItemItem::IRON_INGOT, 0, 1);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
$drops[] = Item::get(Item::CARROT, 0, 1);
|
$drops[] = ItemItem::get(ItemItem::CARROT, 0, 1);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
$drops[] = Item::get(Item::POTATO, 0, 1);
|
$drops[] = ItemItem::get(ItemItem::POTATO, 0, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ abstract class Event{
|
|||||||
* Any callable event must declare the static variable
|
* Any callable event must declare the static variable
|
||||||
*
|
*
|
||||||
* public static $handlerList = null;
|
* public static $handlerList = null;
|
||||||
|
* public static $eventPool = [];
|
||||||
|
* public static $nextEvent = 0;
|
||||||
*
|
*
|
||||||
* Not doing so will deny the proper event initialization
|
* Not doing so will deny the proper event initialization
|
||||||
*/
|
*/
|
||||||
@ -41,7 +43,7 @@ abstract class Event{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
final public function getEventName(){
|
final public function getEventName(){
|
||||||
return $this->eventName !== null ? get_class($this) : $this->eventName;
|
return $this->eventName === null ? get_class($this) : $this->eventName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +56,7 @@ abstract class Event{
|
|||||||
throw new \BadMethodCallException("Event is not Cancellable");
|
throw new \BadMethodCallException("Event is not Cancellable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var Event $this */
|
||||||
return $this->isCancelled === true;
|
return $this->isCancelled === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +71,8 @@ abstract class Event{
|
|||||||
if(!($this instanceof Cancellable)){
|
if(!($this instanceof Cancellable)){
|
||||||
throw new \BadMethodCallException("Event is not Cancellable");
|
throw new \BadMethodCallException("Event is not Cancellable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var Event $this */
|
||||||
$this->isCancelled = (bool) $value;
|
$this->isCancelled = (bool) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class HandlerList{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(isset($this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)])){
|
if(isset($this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)])){
|
||||||
throw new \Exception("This listener is already registered to priority " . $listener->getPriority());
|
throw new \InvalidStateException("This listener is already registered to priority " . $listener->getPriority());
|
||||||
}
|
}
|
||||||
$this->handlers = null;
|
$this->handlers = null;
|
||||||
$this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)] = $listener;
|
$this->handlerSlots[$listener->getPriority()][spl_object_hash($listener)] = $listener;
|
||||||
|
@ -56,6 +56,11 @@ class LevelTimings{
|
|||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
public $tickEntities;
|
public $tickEntities;
|
||||||
|
|
||||||
|
/** @var TimingsHandler */
|
||||||
|
public $syncChunkSendTimer;
|
||||||
|
/** @var TimingsHandler */
|
||||||
|
public $syncChunkSendPrepareTimer;
|
||||||
|
|
||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
public $syncChunkLoadTimer;
|
public $syncChunkLoadTimer;
|
||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
@ -87,6 +92,9 @@ class LevelTimings{
|
|||||||
$this->tileEntityTick = new TimingsHandler("** " . $name . "tileEntityTick");
|
$this->tileEntityTick = new TimingsHandler("** " . $name . "tileEntityTick");
|
||||||
$this->tileEntityPending = new TimingsHandler("** " . $name . "tileEntityPending");
|
$this->tileEntityPending = new TimingsHandler("** " . $name . "tileEntityPending");
|
||||||
|
|
||||||
|
$this->syncChunkSendTimer = new TimingsHandler("** " . $name . "syncChunkSend");
|
||||||
|
$this->syncChunkSendPrepareTimer = new TimingsHandler("** " . $name . "syncChunkSendPrepare");
|
||||||
|
|
||||||
$this->syncChunkLoadTimer = new TimingsHandler("** " . $name . "syncChunkLoad");
|
$this->syncChunkLoadTimer = new TimingsHandler("** " . $name . "syncChunkLoad");
|
||||||
$this->syncChunkLoadDataTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Data");
|
$this->syncChunkLoadDataTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Data");
|
||||||
$this->syncChunkLoadStructuresTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Structures");
|
$this->syncChunkLoadStructuresTimer = new TimingsHandler("** " . $name . "syncChunkLoad - Structures");
|
||||||
|
@ -101,7 +101,7 @@ class TimingsHandler{
|
|||||||
if(PluginManager::$useTimings){
|
if(PluginManager::$useTimings){
|
||||||
foreach(self::$HANDLERS as $timings){
|
foreach(self::$HANDLERS as $timings){
|
||||||
if($timings->curTickTotal > 0.05){
|
if($timings->curTickTotal > 0.05){
|
||||||
$timings->violations += ceil($timings->curTickTotal / 0.05);
|
$timings->violations += round($timings->curTickTotal / 0.05);
|
||||||
}
|
}
|
||||||
$timings->curTickTotal = 0;
|
$timings->curTickTotal = 0;
|
||||||
$timings->timingDepth = 0;
|
$timings->timingDepth = 0;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user