mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-13 04:45:08 +00:00
Compare commits
204 Commits
Alpha_1.4d
...
Alpha_1.4d
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
593b0497b0 | |||
0907aedcef | |||
0a29e66b62 | |||
3cc4afbcd6 | |||
b3ae6eae04 | |||
3b56b536b6 | |||
9258281546 | |||
e7897be7cd | |||
5ff01de413 | |||
f191ada405 | |||
addd74d09e | |||
4e9d2d0a7f | |||
d04e994d1b | |||
3d870629f2 | |||
8dbe834dc3 | |||
36d8100e17 | |||
b880bf13f8 | |||
1ac08ce404 | |||
689b2ea877 | |||
d1f22ee395 | |||
056ed4802f | |||
bcb65e9a48 | |||
5404ba77d0 | |||
ae54426836 | |||
ee7d84dfbd | |||
3e1ea23036 | |||
d312d2a143 | |||
8c627bd0af | |||
6fb7170556 | |||
50f5c6d8ed | |||
f9d5c5bd37 |
@ -9,7 +9,7 @@ branches:
|
||||
before_script:
|
||||
- mkdir plugins
|
||||
- wget -O plugins/DevTools.phar https://github.com/PocketMine/DevTools/releases/download/v1.9.0/DevTools_v1.9.0.phar
|
||||
- pecl install channel://pecl.php.net/pthreads-2.0.8
|
||||
- pecl install channel://pecl.php.net/pthreads-2.0.10
|
||||
- pecl install channel://pecl.php.net/weakref-0.2.4
|
||||
- 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
|
||||
|
||||
### Labels
|
||||
@ -91,6 +104,7 @@ Category labels are prefixed by `C:`. Multiple category labels may be applied to
|
||||
Pull Requests are prefixed by `PR:`. Only one label may be applied for a Pull Request.
|
||||
- PR: Bug Fix - This label is applied when the Pull Request fixes a bug.
|
||||
- PR: Contribution - This label is applied when the Pull Request contributes code to PocketMine-MP such as a new feature or an improvement.
|
||||
- PR: RFC - Request for Comments
|
||||
|
||||
#### Status
|
||||
Status labels show the status of the issue. Multiple status labels may be applied.
|
||||
|
@ -22,6 +22,7 @@
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\network\protocol\Info;
|
||||
use pocketmine\plugin\PluginBase;
|
||||
use pocketmine\plugin\PluginLoadOrder;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
@ -179,7 +180,7 @@ class CrashDump{
|
||||
$this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN");
|
||||
$this->data["plugin"] = true;
|
||||
|
||||
$reflection = new \ReflectionClass("pocketmine\\plugin\\PluginBase");
|
||||
$reflection = new \ReflectionClass(PluginBase::class);
|
||||
$file = $reflection->getProperty("file");
|
||||
$file->setAccessible(true);
|
||||
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,13 +70,19 @@ namespace pocketmine {
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\wizard\Installer;
|
||||
use raklib\RakLib;
|
||||
|
||||
const VERSION = "Alpha_1.4dev";
|
||||
const API_VERSION = "1.4.0";
|
||||
const API_VERSION = "1.6.0";
|
||||
const CODENAME = "絶好(Zekkou)ケーキ(Cake)";
|
||||
const MINECRAFT_VERSION = "v0.9.5 alpha";
|
||||
|
||||
/*
|
||||
* Startup code. Do not look at it, it may harm you.
|
||||
* Most of them are hacks to fix date-related bugs, or basic functions used after this
|
||||
* This is the only non-class based file on this project.
|
||||
* Enjoy it as much as I did writing it. I don't want to do it again.
|
||||
*/
|
||||
|
||||
if(\Phar::running(true) !== ""){
|
||||
@define("pocketmine\\PATH", \Phar::running(true) . "/");
|
||||
}else{
|
||||
@ -101,40 +107,9 @@ namespace pocketmine {
|
||||
$autoloader->addPath(\pocketmine\PATH . "src" . DIRECTORY_SEPARATOR . "raklib");
|
||||
$autoloader->register(true);
|
||||
|
||||
//Startup code. Do not look at it, it can harm you. Most of them are hacks to fix date-related bugs, or basic functions used after this
|
||||
|
||||
set_time_limit(0); //Who set it to 30 seconds?!?!
|
||||
|
||||
if(ini_get("date.timezone") == ""){ //No Timezone set
|
||||
date_default_timezone_set("GMT");
|
||||
if(strpos(" " . strtoupper(php_uname("s")), " WIN") !== false){
|
||||
$time = time();
|
||||
$time -= $time % 60;
|
||||
//TODO: Parse different time & date formats by region. ¬¬ world
|
||||
//Example: USA
|
||||
@exec("time.exe /T", $hour);
|
||||
$i = array_map("intval", explode(":", trim($hour[0])));
|
||||
@exec("date.exe /T", $date);
|
||||
$j = array_map("intval", explode(substr($date[0], 2, 1), trim($date[0])));
|
||||
$offset = @round((mktime($i[0], $i[1], 0, $j[1], $j[0], $j[2]) - $time) / 60) * 60;
|
||||
}else{
|
||||
@exec("date +%s", $t);
|
||||
$offset = @round((intval(trim($t[0])) - time()) / 60) * 60;
|
||||
}
|
||||
|
||||
$daylight = (int) date("I");
|
||||
$d = timezone_name_from_abbr("", $offset, $daylight);
|
||||
@ini_set("date.timezone", $d);
|
||||
date_default_timezone_set($d);
|
||||
}else{
|
||||
$d = @date_default_timezone_get();
|
||||
if(strpos($d, "/") === false){
|
||||
$d = timezone_name_from_abbr($d);
|
||||
@ini_set("date.timezone", $d);
|
||||
date_default_timezone_set($d);
|
||||
}
|
||||
}
|
||||
|
||||
gc_enable();
|
||||
error_reporting(-1);
|
||||
ini_set("allow_url_fopen", 1);
|
||||
@ -150,10 +125,153 @@ namespace pocketmine {
|
||||
define("pocketmine\\DATA", isset($opts["data"]) ? realpath($opts["data"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
|
||||
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? realpath($opts["plugins"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
|
||||
|
||||
define("pocketmine\\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"]));
|
||||
|
||||
//Logger has a dependency on timezone, so we'll set it to UTC until we can get the actual timezone.
|
||||
date_default_timezone_set("UTC");
|
||||
$logger = new MainLogger(\pocketmine\DATA . "server.log", \pocketmine\ANSI);
|
||||
|
||||
if(!ini_get("date.timezone")){
|
||||
if(($timezone = detect_system_timezone()) and date_default_timezone_set($timezone)){
|
||||
//Success! Timezone has already been set and validated in the if statement.
|
||||
//This here is just for redundancy just in case some 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(function_exists("profiler_enable")){
|
||||
\profiler_enable();
|
||||
@ -209,9 +327,9 @@ namespace pocketmine {
|
||||
return rtrim(str_replace(["\\", ".php", "phar://", rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PATH), "/"), rtrim(str_replace(["\\", "phar://"], ["/", ""], \pocketmine\PLUGIN_PATH), "/")], ["/", "", "", "", ""], $path), "/");
|
||||
}
|
||||
|
||||
function error_handler($errno, $errstr, $errfile, $errline, $trace = null){
|
||||
function error_handler($errno, $errstr, $errfile, $errline, $context, $trace = null){
|
||||
global $lastError;
|
||||
if(error_reporting() === 0){ //@ error-control
|
||||
if(error_reporting() === 0){ //@ error-con..trol
|
||||
return false;
|
||||
}
|
||||
$errorConversion = [
|
||||
@ -231,7 +349,7 @@ namespace pocketmine {
|
||||
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;
|
||||
$type = ($errno === E_ERROR or $errno === E_USER_ERROR) ? LogLevel::ERROR : (($errno === E_USER_WARNING or $errno === E_WARNING) ? LogLevel::WARNING : LogLevel::NOTICE);
|
||||
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno;
|
||||
if(($pos = strpos($errstr, "\n")) !== false){
|
||||
$errstr = substr($errstr, 0, $pos);
|
||||
@ -244,6 +362,7 @@ namespace pocketmine {
|
||||
foreach(($trace = getTrace($trace === null ? 3 : 0, $trace)) as $i => $line){
|
||||
$logger->debug($line);
|
||||
}
|
||||
|
||||
$lastError = [
|
||||
"type" => $type,
|
||||
"message" => $errstr,
|
||||
@ -358,14 +477,14 @@ namespace pocketmine {
|
||||
$logger->debug("Stopping " . (new \ReflectionClass($thread))->getShortName() . " thread");
|
||||
if($thread instanceof Thread){
|
||||
$thread->kill();
|
||||
|
||||
if($thread->isRunning() or !$thread->join()){
|
||||
sleep(1);
|
||||
if($thread->isRunning()){
|
||||
$thread->detach();
|
||||
}
|
||||
}elseif($thread instanceof Worker){
|
||||
$thread->kill();
|
||||
sleep(1);
|
||||
if($thread->isRunning() or !$thread->join()){
|
||||
if($thread->isRunning()){
|
||||
$thread->detach();
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use pocketmine\command\CommandSender;
|
||||
use pocketmine\command\ConsoleCommandSender;
|
||||
use pocketmine\command\PluginIdentifiableCommand;
|
||||
use pocketmine\command\SimpleCommandMap;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\HandlerList;
|
||||
use pocketmine\event\level\LevelInitEvent;
|
||||
use pocketmine\event\level\LevelLoadEvent;
|
||||
@ -42,9 +41,14 @@ use pocketmine\inventory\CraftingManager;
|
||||
use pocketmine\inventory\InventoryType;
|
||||
use pocketmine\inventory\Recipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\format\anvil\Anvil;
|
||||
use pocketmine\level\format\LevelProviderManager;
|
||||
use pocketmine\level\format\mcregion\McRegion;
|
||||
use pocketmine\level\generator\Flat;
|
||||
use pocketmine\level\generator\GenerationInstanceManager;
|
||||
use pocketmine\level\generator\GenerationRequestManager;
|
||||
use pocketmine\level\generator\Generator;
|
||||
use pocketmine\level\generator\Normal;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\metadata\EntityMetadataStore;
|
||||
use pocketmine\metadata\LevelMetadataStore;
|
||||
@ -74,12 +78,13 @@ use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\scheduler\CallbackTask;
|
||||
use pocketmine\scheduler\SendUsageTask;
|
||||
use pocketmine\scheduler\ServerScheduler;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\updater\AutoUpdater;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\Cache;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\TextWrapper;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
|
||||
@ -135,6 +140,7 @@ class Server{
|
||||
|
||||
/** @var CommandReader */
|
||||
private $console = null;
|
||||
private $consoleThreaded;
|
||||
|
||||
/** @var SimpleCommandMap */
|
||||
private $commandMap = null;
|
||||
@ -148,6 +154,9 @@ class Server{
|
||||
/** @var int */
|
||||
private $maxPlayers;
|
||||
|
||||
/** @var bool */
|
||||
private $autoSave;
|
||||
|
||||
/** @var RCON */
|
||||
private $rcon;
|
||||
|
||||
@ -280,14 +289,31 @@ class Server{
|
||||
* @return string
|
||||
*/
|
||||
public function getIp(){
|
||||
return $this->getConfigString("server-ip", "");
|
||||
return $this->getConfigString("server-ip", "0.0.0.0");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getServerName(){
|
||||
return $this->getConfigString("server-name", "Unknown server");
|
||||
return $this->getConfigString("motd", "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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -888,7 +914,7 @@ class Server{
|
||||
* @return bool
|
||||
*/
|
||||
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()]);
|
||||
|
||||
return true;
|
||||
@ -942,6 +968,8 @@ class Server{
|
||||
|
||||
$this->levels[$level->getID()] = $level;
|
||||
|
||||
$level->initLevel();
|
||||
|
||||
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
||||
|
||||
/*foreach($entities->getAll() as $entity){
|
||||
@ -1057,7 +1085,7 @@ class Server{
|
||||
|
||||
$seed = $seed === null ? Binary::readInt(Utils::getRandomBytes(4, false)) : (int) $seed;
|
||||
|
||||
if($generator !== null and class_exists($generator) and is_subclass_of($generator, "pocketmine\\level\\generator\\Generator")){
|
||||
if($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)){
|
||||
$generator = new $generator($options);
|
||||
}else{
|
||||
$options["preset"] = $this->getConfigString("generator-settings", "");
|
||||
@ -1075,6 +1103,8 @@ class Server{
|
||||
$level = new Level($this, $name, $path, $provider);
|
||||
$this->levels[$level->getID()] = $level;
|
||||
|
||||
$level->initLevel();
|
||||
|
||||
$this->getPluginManager()->callEvent(new LevelInitEvent($level));
|
||||
|
||||
$this->getPluginManager()->callEvent(new LevelLoadEvent($level));
|
||||
@ -1085,14 +1115,14 @@ class Server{
|
||||
$radiusSquared = ($this->getViewDistance() + 1) / M_PI;
|
||||
$radius = ceil(sqrt($radiusSquared));
|
||||
|
||||
$centerX = $level->getSpawn()->getX() >> 4;
|
||||
$centerZ = $level->getSpawn()->getZ() >> 4;
|
||||
$centerX = $level->getSpawnLocation()->getX() >> 4;
|
||||
$centerZ = $level->getSpawnLocation()->getZ() >> 4;
|
||||
|
||||
$order = [];
|
||||
|
||||
for($X = -$radius; $X <= $radius; ++$X){
|
||||
for($Z = -$radius; $Z <= $radius; ++$Z){
|
||||
$distance = ($X * $X) + ($Z * $Z);
|
||||
$distance = $X ** 2 + $Z ** 2;
|
||||
if($distance > $radiusSquared){
|
||||
continue;
|
||||
}
|
||||
@ -1419,7 +1449,8 @@ class Server{
|
||||
$this->banByIP = new BanList($this->dataPath . "banned-ips.txt");
|
||||
$this->banByIP->load();
|
||||
|
||||
$this->console = new CommandReader();
|
||||
$this->consoleThreaded = new \Threaded();
|
||||
$this->console = new CommandReader($this->consoleThreaded);
|
||||
|
||||
$version = new VersionString($this->getPocketMineVersion());
|
||||
$this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
|
||||
@ -1470,6 +1501,7 @@ class Server{
|
||||
}
|
||||
|
||||
$this->maxPlayers = $this->getConfigInt("max-players", 20);
|
||||
$this->setAutoSave($this->getConfigBoolean("auto-save", true));
|
||||
|
||||
if(($memory = str_replace("B", "", strtoupper($this->getConfigString("memory-limit", "256M")))) !== false){
|
||||
$value = ["M" => 1, "G" => 1024];
|
||||
@ -1495,7 +1527,7 @@ class Server{
|
||||
$this->logger->info("Advanced cache enabled");
|
||||
}
|
||||
|
||||
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 7);
|
||||
Level::$COMPRESSION_LEVEL = $this->getProperty("chunk-sending.compression-level", 8);
|
||||
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0){
|
||||
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
|
||||
@ -1507,7 +1539,7 @@ class Server{
|
||||
|
||||
$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);
|
||||
|
||||
PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins");
|
||||
@ -1519,12 +1551,13 @@ class Server{
|
||||
InventoryType::init();
|
||||
Block::init();
|
||||
Item::init();
|
||||
TextWrapper::init();
|
||||
$this->craftingManager = new CraftingManager();
|
||||
|
||||
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
||||
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
|
||||
$this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false));
|
||||
$this->pluginManager->registerInterface("pocketmine\\plugin\\PharPluginLoader");
|
||||
$this->pluginManager->registerInterface(PharPluginLoader::class);
|
||||
|
||||
set_exception_handler([$this, "exceptionHandler"]);
|
||||
register_shutdown_function([$this, "crashDump"]);
|
||||
@ -1536,18 +1569,22 @@ class Server{
|
||||
|
||||
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
||||
|
||||
$this->generationManager = new GenerationRequestManager($this);
|
||||
if($this->getProperty("chunk-generation.use-async", true)){
|
||||
$this->generationManager = new GenerationRequestManager($this);
|
||||
}else{
|
||||
$this->generationManager = new GenerationInstanceManager($this);
|
||||
}
|
||||
|
||||
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil");
|
||||
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\mcregion\\McRegion");
|
||||
LevelProviderManager::addProvider($this, Anvil::class);
|
||||
LevelProviderManager::addProvider($this, McRegion::class);
|
||||
|
||||
|
||||
Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat");
|
||||
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal");
|
||||
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default");
|
||||
Generator::addGenerator(Flat::class, "flat");
|
||||
Generator::addGenerator(Normal::class, "normal");
|
||||
Generator::addGenerator(Normal::class, "default");
|
||||
|
||||
//Temporal workaround, pthreads static property nullification test
|
||||
if(PluginManager::$pluginParentTimer === null){
|
||||
if(PluginManager::$pluginParentTimer === null or Timings::$serverTickTimer === null){
|
||||
$this->getLogger()->emergency("You are using an invalid pthreads version. Please update your binaries.");
|
||||
kill(getmypid());
|
||||
return;
|
||||
@ -1595,8 +1632,8 @@ class Server{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask("pocketmine\\utils\\Cache::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){
|
||||
$this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([Cache::class, "cleanup"]), $this->getProperty("ticks-per.cache-cleanup", 900), $this->getProperty("ticks-per.cache-cleanup", 900));
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1611,11 +1648,17 @@ class Server{
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param Player[]|null $recipients
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function broadcastMessage($message){
|
||||
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
||||
public function broadcastMessage($message, $recipients = null){
|
||||
if(!is_array($recipients)){
|
||||
return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS);
|
||||
}
|
||||
foreach($recipients as $recipient){
|
||||
$recipient->sendMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1649,8 +1692,10 @@ class Server{
|
||||
* @param DataPacket $packet
|
||||
*/
|
||||
public static function broadcastPacket(array $players, DataPacket $packet){
|
||||
$packet->encode();
|
||||
$packet->isEncoded = true;
|
||||
foreach($players as $player){
|
||||
$player->dataPacket(clone $packet);
|
||||
$player->dataPacket($packet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1709,8 +1754,14 @@ class Server{
|
||||
* @param string $commandLine
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function dispatchCommand(CommandSender $sender, $commandLine){
|
||||
if(!($sender instanceof CommandSender)){
|
||||
throw new \Exception("CommandSender is not valid");
|
||||
}
|
||||
|
||||
if($this->commandMap->dispatch($sender, $commandLine)){
|
||||
return true;
|
||||
}
|
||||
@ -1760,7 +1811,7 @@ class Server{
|
||||
$this->operators->reload();
|
||||
|
||||
|
||||
$this->pluginManager->registerInterface("pocketmine\\plugin\\PharPluginLoader");
|
||||
$this->pluginManager->registerInterface(PharPluginLoader::class);
|
||||
$this->pluginManager->loadPlugins($this->pluginPath);
|
||||
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
||||
$this->enablePlugins(PluginLoadOrder::POSTWORLD);
|
||||
@ -1883,7 +1934,7 @@ class Server{
|
||||
return;
|
||||
}
|
||||
|
||||
error_handler(E_ERROR, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTrace());
|
||||
error_handler(E_ERROR, $e->getMessage(), $e->getFile(), $e->getLine(), [], $e->getTrace());
|
||||
global $lastExceptionError, $lastError;
|
||||
$lastExceptionError = $lastError;
|
||||
$this->crashDump();
|
||||
@ -1913,7 +1964,7 @@ class Server{
|
||||
}elseif(\Phar::running(true) == ""){
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1941,7 +1992,6 @@ class Server{
|
||||
}
|
||||
|
||||
private function tickProcessor(){
|
||||
$lastLoop = 0;
|
||||
while($this->isRunning){
|
||||
$this->tick();
|
||||
usleep((int) max(1, ($this->nextTick - microtime(true)) * 1000000));
|
||||
@ -1961,19 +2011,21 @@ class Server{
|
||||
}
|
||||
|
||||
public function doAutoSave(){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->getOnlinePlayers() as $index => $player){
|
||||
if($player->isOnline()){
|
||||
$player->save();
|
||||
}elseif(!$player->isConnected()){
|
||||
unset($this->players[$index]);
|
||||
if($this->getAutoSave()){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->getOnlinePlayers() as $index => $player){
|
||||
if($player->isOnline()){
|
||||
$player->save();
|
||||
}elseif(!$player->isConnected()){
|
||||
unset($this->players[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->save(false);
|
||||
foreach($this->getLevels() as $level){
|
||||
$level->save(false);
|
||||
}
|
||||
Timings::$worldSaveTimer->stopTiming();
|
||||
}
|
||||
Timings::$worldSaveTimer->stopTiming();
|
||||
}
|
||||
|
||||
public function doLevelGC(){
|
||||
@ -1997,13 +2049,14 @@ class Server{
|
||||
|
||||
$version = new VersionString();
|
||||
$this->lastSendUsage = new SendUsageTask("http://stats.pocketmine.net/usage.php", [
|
||||
"serverid" => Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . ":" . $this->getPort()), 0, 8)),
|
||||
"serverid" => $this->serverID,
|
||||
"port" => $this->getPort(),
|
||||
"os" => Utils::getOS(),
|
||||
"name" => $this->getName(),
|
||||
"memory_total" => $this->getConfigString("memory-limit"),
|
||||
"memory_usage" => memory_get_usage(),
|
||||
"php_version" => PHP_VERSION,
|
||||
"version" => $version->get(false),
|
||||
"version" => $version->get(true),
|
||||
"build" => $version->getBuild(),
|
||||
"mc_version" => \pocketmine\MINECRAFT_VERSION,
|
||||
"protocol" => network\protocol\Info::CURRENT_PROTOCOL,
|
||||
@ -2056,7 +2109,7 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
$this->generationManager->handlePackets();
|
||||
$this->generationManager->process();
|
||||
|
||||
Timings::$serverTickTimer->stopTiming();
|
||||
|
||||
@ -2072,7 +2125,6 @@ class Server{
|
||||
$this->nextTick = $tickTime;
|
||||
}
|
||||
$this->nextTick += 0.05;
|
||||
$this->inTick = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -36,7 +36,11 @@ class Bed extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -22,65 +22,10 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Beetroot extends Flowable{
|
||||
class Beetroot extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
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){
|
||||
|
@ -39,7 +39,7 @@ use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
|
||||
|
||||
abstract class Block extends Position implements Metadatable{
|
||||
class Block extends Position implements Metadatable{
|
||||
const AIR = 0;
|
||||
const STONE = 1;
|
||||
const GRASS = 2;
|
||||
@ -167,7 +167,8 @@ abstract class Block extends Position implements Metadatable{
|
||||
const MELON_BLOCK = 103;
|
||||
const PUMPKIN_STEM = 104;
|
||||
const MELON_STEM = 105;
|
||||
|
||||
const VINE = 106;
|
||||
const VINES = 106;
|
||||
const FENCE_GATE = 107;
|
||||
const BRICK_STAIRS = 108;
|
||||
const STONE_BRICK_STAIRS = 109;
|
||||
@ -345,7 +346,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
[Item::SNOW_LAYER, 0],
|
||||
[Item::GLASS, 0],
|
||||
[Item::GLOWSTONE_BLOCK, 0],
|
||||
//TODO: Vines
|
||||
[Item::VINES, 0],
|
||||
[Item::NETHER_REACTOR, 0],
|
||||
[Item::LADDER, 0],
|
||||
[Item::SPONGE, 0],
|
||||
@ -362,7 +363,6 @@ abstract class Block extends Position implements Metadatable{
|
||||
[Item::STONECUTTER, 0],
|
||||
[Item::CHEST, 0],
|
||||
[Item::FURNACE, 0],
|
||||
//TODO: End Portal
|
||||
[Item::END_PORTAL, 0],
|
||||
[Item::DANDELION, 0],
|
||||
[Item::POPPY, 0],
|
||||
@ -512,6 +512,8 @@ abstract class Block extends Position implements Metadatable{
|
||||
protected $name = "Unknown";
|
||||
protected $breakTime = 0.20;
|
||||
protected $hardness = 10;
|
||||
protected $boundingBox = null;
|
||||
public $hasEntityCollision = false;
|
||||
public $isActivable = false;
|
||||
public $breakable = true;
|
||||
public $isFlowable = false;
|
||||
@ -621,7 +623,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
self::MELON_BLOCK => Melon::class,
|
||||
self::PUMPKIN_STEM => PumpkinStem::class,
|
||||
self::MELON_STEM => MelonStem::class,
|
||||
|
||||
self::VINE => Vine::class,
|
||||
self::FENCE_GATE => FenceGate::class,
|
||||
self::BRICK_STAIRS => BrickStairs::class,
|
||||
self::STONE_BRICK_STAIRS => StoneBrickStairs::class,
|
||||
@ -682,11 +684,14 @@ abstract class Block extends Position implements Metadatable{
|
||||
$block = self::$list[$id];
|
||||
$block = new $block($meta);
|
||||
}else{
|
||||
$block = new Generic($id, $meta);
|
||||
$block = new Block($id, $meta);
|
||||
}
|
||||
|
||||
if($pos instanceof Position){
|
||||
$block->position($pos);
|
||||
$block->x = $pos->x;
|
||||
$block->y = $pos->y;
|
||||
$block->z = $pos->z;
|
||||
$block->level = $pos->level;
|
||||
}
|
||||
|
||||
return $block;
|
||||
@ -703,6 +708,69 @@ abstract class Block extends Position implements Metadatable{
|
||||
$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
|
||||
*/
|
||||
@ -724,6 +792,10 @@ abstract class Block extends Position implements Metadatable{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity, Vector3 $vector){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
@ -748,6 +820,7 @@ abstract class Block extends Position implements Metadatable{
|
||||
$this->y = (int) $v->y;
|
||||
$this->z = (int) $v->z;
|
||||
$this->level = $v->level;
|
||||
$this->boundingBox = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -802,24 +875,6 @@ abstract class Block extends Position implements Metadatable{
|
||||
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
|
||||
*
|
||||
@ -844,7 +899,11 @@ abstract class Block extends Position implements Metadatable{
|
||||
* @return AxisAlignedBB
|
||||
*/
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -936,41 +995,6 @@ abstract class Block extends Position implements Metadatable{
|
||||
return MovingObjectPosition::fromBlock($this->x, $this->y, $this->z, $f, $vector->add($this->x, $this->y, $this->z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Block $block
|
||||
* @param Block $target
|
||||
* @param int $face
|
||||
* @param float $fx
|
||||
* @param float $fy
|
||||
* @param float $fz
|
||||
* @param Player $player = null
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null);
|
||||
|
||||
/**
|
||||
* Do actions when activated by Item. Returns if it has done anything
|
||||
*
|
||||
* @param Item $item
|
||||
* @param Player $player
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract function onActivate(Item $item, Player $player = null);
|
||||
|
||||
/**
|
||||
* Fires a block update on the Block
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract function onUpdate($type);
|
||||
|
||||
public function setMetadata($metadataKey, MetadataValue $metadataValue){
|
||||
if($this->getLevel() instanceof Level){
|
||||
$this->getLevel()->getBlockMetadata()->setMetadata($this, $metadataKey, $metadataValue);
|
||||
|
@ -33,9 +33,8 @@ class BrownMushroom extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ class BurningFurnace extends Solid{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
new Furnace($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onBreak(Item $item){
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -81,7 +81,7 @@ class BurningFurnace extends Solid{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$furnace = new Furnace($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$furnace = new Furnace($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
}
|
||||
|
||||
if(($player->getGamemode() & 0x01) === 0x01){
|
||||
@ -116,15 +116,6 @@ class BurningFurnace extends Solid{
|
||||
if($item->isPickaxe() >= 1){
|
||||
$drops[] = [Item::FURNACE, 0, 1];
|
||||
}
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
if($t instanceof Furnace){
|
||||
for($s = 0; $s < $t->getInventory()->getSize(); ++$s){
|
||||
$slot = $t->getInventory()->getItem($s);
|
||||
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
|
||||
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
|
@ -21,16 +21,21 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Cactus extends Transparent{
|
||||
|
||||
public $hasEntityCollision = true;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::CACTUS, $meta, "Cactus");
|
||||
$this->isFullBlock = false;
|
||||
@ -38,7 +43,11 @@ class Cactus extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
@ -49,7 +58,7 @@ class Cactus extends Transparent{
|
||||
}
|
||||
|
||||
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);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
@ -59,19 +68,13 @@ class Cactus extends Transparent{
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){ //Replace with common break method
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
|
||||
return;
|
||||
if($down->getID() !== self::SAND and $down->getID() !== self::CACTUS){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if(!$b->isFlowable){
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id));
|
||||
|
||||
return;
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,8 +84,10 @@ class Cactus extends Transparent{
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
if($b->getID() === self::AIR){
|
||||
$this->getLevel()->setBlock($b, new Cactus(), true);
|
||||
break;
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Cactus()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->meta = 0;
|
||||
@ -91,8 +96,6 @@ class Cactus extends Transparent{
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,12 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Cake extends Transparent{
|
||||
public function __construct($meta = 0){
|
||||
@ -36,9 +38,13 @@ class Cake extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$f = (1 + $this->getDamage() * 2) / 16;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + $f,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
@ -78,7 +84,10 @@ class Cake extends Transparent{
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($player instanceof Player and $player->getHealth() < 20){
|
||||
++$this->meta;
|
||||
$player->heal(3, "cake");
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($player, 3, EntityRegainHealthEvent::CAUSE_EATING));
|
||||
if(!$ev->isCancelled()){
|
||||
$player->heal($ev->getAmount(), $ev);
|
||||
}
|
||||
if($this->meta >= 0x06){
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
}else{
|
||||
|
@ -54,7 +54,11 @@ class Carpet extends Flowable{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -77,9 +81,8 @@ class Carpet extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === self::AIR){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
if($this->getSide(0)->getID() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -22,67 +22,10 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Carrot extends Flowable{
|
||||
class Carrot extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
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){
|
||||
|
@ -43,12 +43,16 @@ class Chest extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + 0.0625,
|
||||
$this->y,
|
||||
$this->z + 0.0625,
|
||||
$this->x + 0.9375,
|
||||
$this->y + 0.875,
|
||||
$this->y + 0.9475,
|
||||
$this->z + 0.9375
|
||||
);
|
||||
}
|
||||
@ -89,7 +93,7 @@ class Chest extends Transparent{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$tile = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$tile = new TileChest($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
|
||||
if($chest instanceof TileChest){
|
||||
$chest->pairWith($tile);
|
||||
@ -104,7 +108,7 @@ class Chest extends Transparent{
|
||||
if($t instanceof TileChest){
|
||||
$t->unpair();
|
||||
}
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -129,7 +133,7 @@ class Chest extends Transparent{
|
||||
new Int("z", $this->z)
|
||||
]);
|
||||
$nbt->Items->setTagType(NBT::TAG_Compound);
|
||||
$chest = new TileChest($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), $nbt);
|
||||
$chest = new TileChest($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
|
||||
}
|
||||
|
||||
|
||||
@ -143,19 +147,8 @@ class Chest extends Transparent{
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
$drops = [
|
||||
return [
|
||||
[$this->id, 0, 1],
|
||||
];
|
||||
$t = $this->getLevel()->getTile($this);
|
||||
if($t instanceof TileChest){
|
||||
for($s = 0; $s < $t->getRealInventory()->getSize(); ++$s){
|
||||
$slot = $t->getRealInventory()->getItem($s);
|
||||
if($slot->getID() > Item::AIR and $slot->getCount() > 0){
|
||||
$drops[] = [$slot->getID(), $slot->getDamage(), $slot->getCount()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $drops;
|
||||
}
|
||||
}
|
@ -21,10 +21,13 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class Cobweb extends Flowable{
|
||||
|
||||
public $hasEntityCollision = true;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(self::COBWEB, 0, "Cobweb");
|
||||
$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){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -49,10 +49,8 @@ class Dandelion extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -53,6 +53,10 @@ abstract class Door extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$f = 0.1875;
|
||||
$damage = $this->getFullDamage();
|
||||
|
||||
@ -195,7 +199,7 @@ abstract class Door extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
return $bb;
|
||||
return $this->boundingBox = $bb;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
|
@ -30,7 +30,11 @@ class EndPortal extends Solid{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -21,17 +21,17 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\entity\FallingBlock;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\Double;
|
||||
use pocketmine\nbt\tag\Float;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
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;
|
||||
|
||||
class Fallable extends Solid{
|
||||
abstract class Fallable extends Solid{
|
||||
|
||||
public $hasPhysics = true;
|
||||
|
||||
@ -45,13 +45,12 @@ class Fallable extends Solid{
|
||||
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::AIR or ($down instanceof Liquid)){
|
||||
$fall = new FallingBlock($this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||
$fall = new FallingBlock($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||
"Pos" => new Enum("Pos", [
|
||||
new Double("", $this->x + 0.5),
|
||||
new Double("", $this->y + 0.5),
|
||||
new Double("", $this->y),
|
||||
new Double("", $this->z + 0.5)
|
||||
]),
|
||||
//TODO: add random motion with physics
|
||||
"Motion" => new Enum("Motion", [
|
||||
new Double("", 0),
|
||||
new Double("", 0),
|
||||
|
@ -31,7 +31,11 @@ class Farmland extends Solid{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -23,7 +23,6 @@ namespace pocketmine\block;
|
||||
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
|
||||
class Fence extends Transparent{
|
||||
public function __construct(){
|
||||
@ -33,6 +32,10 @@ class Fence extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$flag = $this->canConnect($this->getSide(2));
|
||||
$flag1 = $this->canConnect($this->getSide(3));
|
||||
$flag2 = $this->canConnect($this->getSide(4));
|
||||
@ -43,7 +46,7 @@ class Fence extends Transparent{
|
||||
$f2 = $flag ? 0 : 0.375;
|
||||
$f3 = $flag1 ? 1 : 0.625;
|
||||
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + $f,
|
||||
$this->y,
|
||||
$this->z + $f2,
|
||||
|
@ -39,13 +39,17 @@ class FenceGate extends Transparent{
|
||||
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
$i = ($this->getDamage() & 0x03);
|
||||
if($i === 2 and $i === 0){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 0.375,
|
||||
@ -54,7 +58,7 @@ class FenceGate extends Transparent{
|
||||
$this->z + 0.625
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + 0.375,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -21,13 +21,18 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Fire extends Flowable{
|
||||
|
||||
public $hasEntityCollision = true;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::FIRE, $meta, "Fire");
|
||||
$this->isReplaceable = true;
|
||||
@ -41,12 +46,17 @@ class Fire extends Flowable{
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->setOnFire(8);
|
||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->setOnFire($ev->getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
|
@ -22,7 +22,7 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class Flowable extends Transparent{
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public $isFlowable = true;
|
||||
public $isFullBlock = false;
|
||||
|
@ -21,11 +21,13 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\generator\object\TallGrass as TallGrassObject;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Random;
|
||||
|
||||
class Grass extends Solid{
|
||||
@ -56,7 +58,10 @@ class Grass extends Solid{
|
||||
if($block === 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){
|
||||
$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;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class Ladder extends Transparent{
|
||||
|
||||
public $hasEntityCollision = true;
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::LADDER, $meta, "Ladder");
|
||||
$this->isSolid = false;
|
||||
@ -37,13 +40,18 @@ class Ladder extends Transparent{
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->fallDistance = 0;
|
||||
$entity->onGround = true;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$f = 0.125;
|
||||
|
||||
if($this->meta === 2){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z + 1 - $f,
|
||||
@ -52,7 +60,7 @@ class Ladder extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}elseif($this->meta === 3){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -61,7 +69,7 @@ class Ladder extends Transparent{
|
||||
$this->z + $f
|
||||
);
|
||||
}elseif($this->meta === 4){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + 1 - $f,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -70,7 +78,7 @@ class Ladder extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}elseif($this->meta === 5){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -21,150 +21,41 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\event\entity\EntityCombustByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
|
||||
class Lava extends Liquid{
|
||||
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::LAVA, $meta, "Lava");
|
||||
$this->hardness = 0;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->setOnFire(15);
|
||||
$ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
$entity->fallDistance *= 0.5;
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
$entity->attack(4, EntityDamageEvent::CAUSE_LAVA);
|
||||
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 15);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->setOnFire($ev->getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevel()->scheduleUpdate(clone $this, 40);
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getSourceCount(){
|
||||
$count = 0;
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
if($this->getSide($side) instanceof Lava){
|
||||
$b = $this->getSide($side);
|
||||
$level = $b->meta & 0x07;
|
||||
if($level == 0x00){
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function checkWater(){
|
||||
for($side = 1; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Water){
|
||||
$level = $this->meta & 0x07;
|
||||
if($level == 0x00){
|
||||
$this->getLevel()->setBlock($this, new Obsidian(), false, false, true);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Cobblestone(), false, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFrom(){
|
||||
for($side = 0; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
$tlevel = $b->meta & 0x07;
|
||||
$level = $this->meta & 0x07;
|
||||
if(($tlevel + 2) == $level || ($side == 0x01 && $level == 0x01) || ($tlevel == 6 && $level == 7)){
|
||||
return $b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
return false;
|
||||
$newId = $this->id;
|
||||
$level = $this->meta & 0x07;
|
||||
if($type !== Level::BLOCK_UPDATE_NORMAL){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->checkWater()){
|
||||
return;
|
||||
}
|
||||
|
||||
$falling = $this->meta >> 3;
|
||||
$down = $this->getSide(0);
|
||||
|
||||
$from = $this->getFrom();
|
||||
if($from !== null || $level == 0x00){
|
||||
if($level !== 0x07){
|
||||
if($down instanceof Air || $down instanceof Lava){
|
||||
$this->getLevel()->setBlock($down, new Lava(0x01), false, false, true);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(new Position($down, 0, 0, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}else{
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$b = $this->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
|
||||
}elseif($b->isFlowable === true){
|
||||
$this->getLevel()->setBlock($b, new Lava(min($level + 2, 7)), false, false, true);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//Extend Remove for Left Lavas
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
$sb = $this->getSide($side);
|
||||
if($sb instanceof Lava){
|
||||
$tlevel = $sb->meta & 0x07;
|
||||
if($tlevel != 0x00){
|
||||
for($s = 0; $s <= 5; $s++){
|
||||
$ssb = $sb->getSide($s);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->getLevel()->setBlock($sb, new Air(), false, false, true);
|
||||
}
|
||||
}
|
||||
$b = $this->getSide(0)->getSide($side);
|
||||
if($b instanceof Lava){
|
||||
$tlevel = $b->meta & 0x07;
|
||||
if($tlevel != 0x00){
|
||||
for($s = 0; $s <= 5; $s++){
|
||||
$ssb = $sb->getSide($s);
|
||||
Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($ssb, $this->level), 40, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
$this->getLevel()->setBlock($b, new Air(), false, false, true);
|
||||
}
|
||||
}
|
||||
//Server::getInstance()->api->block->scheduleBlockUpdate(Position::fromObject($b, $this->level), 10, Level::BLOCK_UPDATE_NORMAL);
|
||||
}
|
||||
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\LeavesDecayEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Leaves extends Transparent{
|
||||
const OAK = 0;
|
||||
@ -121,16 +123,13 @@ class Leaves extends Transparent{
|
||||
$this->meta &= 0x03;
|
||||
$visited = [];
|
||||
$check = 0;
|
||||
if($this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false, true);
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
|
||||
|
||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
|
||||
}
|
||||
if(($this->meta & 0x03) === self::OAK and mt_rand(1, 200) === 1){ //Apples
|
||||
$this->getLevel()->dropItem($this, Item::get(Item::APPLE, 0, 1));
|
||||
}
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\LeavesDecayEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Leaves2 extends Leaves{
|
||||
|
||||
@ -113,13 +115,13 @@ class Leaves2 extends Leaves{
|
||||
$this->meta &= 0x03;
|
||||
$visited = [];
|
||||
$check = 0;
|
||||
if($this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false, true);
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new LeavesDecayEvent($this));
|
||||
|
||||
if($ev->isCancelled() or $this->findLog($this, $visited, 0, $check) === true){
|
||||
$this->getLevel()->setBlock($this, $this, false, false);
|
||||
}else{
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
$this->getLevel()->dropItem($this, Item::get($this->id, $this->meta & 0x03, 1));
|
||||
}
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -22,13 +22,24 @@
|
||||
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 $breakable = false;
|
||||
public $isReplaceable = true;
|
||||
public $isSolid = false;
|
||||
public $isFullBlock = true;
|
||||
|
||||
public $adjacentSources = 0;
|
||||
public $isOptimalFlowDirection = [0, 0, 0, 0];
|
||||
public $flowCost = [0, 0, 0, 0];
|
||||
|
||||
public function getFluidHeightPercent(){
|
||||
$d = $this->meta;
|
||||
if($d >= 8){
|
||||
@ -37,4 +48,374 @@ class Liquid extends Transparent{
|
||||
|
||||
return ($d + 1) / 9;
|
||||
}
|
||||
|
||||
protected function getFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
}
|
||||
|
||||
if($pos->getID() !== $this->getID()){
|
||||
return -1;
|
||||
}else{
|
||||
return $pos->getDamage();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEffectiveFlowDecay(Vector3 $pos){
|
||||
if(!($pos instanceof Block)){
|
||||
$pos = $this->getLevel()->getBlock($pos);
|
||||
}
|
||||
|
||||
if($pos->getID() !== $this->getID()){
|
||||
return -1;
|
||||
}
|
||||
|
||||
$decay = $pos->getDamage();
|
||||
|
||||
if($decay >= 8){
|
||||
$decay = 0;
|
||||
}
|
||||
|
||||
return $decay;
|
||||
}
|
||||
|
||||
public function getFlowVector(){
|
||||
$vector = new Vector3(0, 0, 0);
|
||||
|
||||
$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;
|
||||
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class MelonStem extends Flowable{
|
||||
class MelonStem extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::MELON_STEM, $meta, "Melon Stem");
|
||||
$this->isActivable = true;
|
||||
$this->hardness = 0;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$down = $this->getSide(0);
|
||||
if($down->getID() === self::FARMLAND){
|
||||
$this->getLevel()->setBlock($block, $this, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //TODO: Replace with common break method
|
||||
$this->getLevel()->dropItem($this, Item::get(Item::MELON_SEEDS, 0, mt_rand(0, 2)));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$block = clone $this;
|
||||
++$block->meta;
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
||||
}
|
||||
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}else{
|
||||
@ -73,7 +58,10 @@ class MelonStem extends Flowable{
|
||||
$side = $this->getSide(mt_rand(2, 5));
|
||||
$d = $side->getSide(0);
|
||||
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
|
||||
$this->getLevel()->setBlock($side, new Melon(), true);
|
||||
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;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$this->meta = 0x07;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [
|
||||
[Item::MELON_SEEDS, 0, mt_rand(0, 2)],
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Mycelium extends Solid{
|
||||
public function __construct(){
|
||||
@ -47,7 +49,10 @@ class Mycelium extends Solid{
|
||||
if($block === 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){
|
||||
$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;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Potato extends Flowable{
|
||||
class Potato extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
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){
|
||||
|
@ -21,47 +21,31 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class PumpkinStem extends Flowable{
|
||||
class PumpkinStem extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
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){
|
||||
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(PUMPKIN_SEEDS, 0, mt_rand(0, 2)));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
}elseif($type === Level::BLOCK_UPDATE_RANDOM){
|
||||
if(mt_rand(0, 2) == 1){
|
||||
if($this->meta < 0x07){
|
||||
++$this->meta;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
$block = clone $this;
|
||||
++$block->meta;
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($this, $block));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($this, $ev->getNewState(), true);
|
||||
}
|
||||
|
||||
return Level::BLOCK_UPDATE_RANDOM;
|
||||
}else{
|
||||
@ -74,7 +58,10 @@ class PumpkinStem extends Flowable{
|
||||
$side = $this->getSide(mt_rand(2, 5));
|
||||
$d = $side->getSide(0);
|
||||
if($side->getID() === self::AIR and ($d->getID() === self::FARMLAND or $d->getID() === self::GRASS or $d->getID() === self::DIRT)){
|
||||
$this->getLevel()->setBlock($side, new 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;
|
||||
}
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::DYE and $item->getDamage() === 0x0F){ //Bonemeal
|
||||
$this->meta = 0x07;
|
||||
$this->getLevel()->setBlock($this, $this, true);
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->count--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item){
|
||||
return [
|
||||
[Item::PUMPKIN_SEEDS, 0, mt_rand(0, 2)],
|
||||
|
@ -38,10 +38,8 @@ class RedMushroom extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false);
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -81,10 +81,8 @@ class Sapling extends Flowable{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->isTransparent === true){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($this->getSide(0)->isTransparent === true){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -64,10 +64,8 @@ class SignPost extends Transparent{
|
||||
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
if($this->getSide(0)->getID() === self::AIR){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get(SIGN, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), true, true, true);
|
||||
if($this->getSide(0)->getID() === self::AIR){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -48,8 +48,12 @@ class Slab extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
if(($this->meta & 0x08) > 0){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
@ -58,7 +62,7 @@ class Slab extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -94,7 +98,7 @@ class Slab extends Transparent{
|
||||
return true;
|
||||
}
|
||||
//TODO: check for collision
|
||||
}elseif(!($player instanceof Player)){
|
||||
}else{
|
||||
if($block->getID() === self::SLAB){
|
||||
if(($block->getDamage() & 0x07) === ($this->meta & 0x07)){
|
||||
$this->getLevel()->setBlock($block, Block::get(Item::DOUBLE_SLAB, $this->meta), true);
|
||||
@ -108,9 +112,8 @@ class Slab extends Transparent{
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($block->getID() === self::SLAB and ($target->getDamage() & 0x07) !== ($this->meta & 0x07)){
|
||||
return false;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
namespace pocketmine\block;
|
||||
|
||||
|
||||
class Solid extends Generic{
|
||||
abstract class Solid extends Block{
|
||||
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
|
@ -31,7 +31,11 @@ class SoulSand extends Solid{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return new AxisAlignedBB(
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -25,7 +25,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Stair extends Transparent{
|
||||
abstract class Stair extends Transparent{
|
||||
|
||||
public function __construct($id, $meta = 0, $name = "Unknown"){
|
||||
parent::__construct($id, $meta, $name);
|
||||
@ -114,8 +114,12 @@ class Stair extends Transparent{
|
||||
*/
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
if(($this->getDamage() & 0x04) > 0){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
@ -124,7 +128,7 @@ class Stair extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
|
@ -21,28 +21,10 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class StillLava extends Liquid{
|
||||
class StillLava extends Lava{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::STILL_LAVA, $meta, "Still Lava");
|
||||
$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);
|
||||
}
|
||||
|
||||
}
|
@ -37,6 +37,10 @@ class StoneWall extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$flag = $this->canConnect($this->getSide(2));
|
||||
$flag1 = $this->canConnect($this->getSide(3));
|
||||
$flag2 = $this->canConnect($this->getSide(4));
|
||||
@ -58,7 +62,7 @@ class StoneWall extends Transparent{
|
||||
$f3 = 0.6875;
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + $f,
|
||||
$this->y,
|
||||
$this->z + $f2,
|
||||
|
@ -21,10 +21,12 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
class Sugarcane extends Flowable{
|
||||
public function __construct($meta = 0){
|
||||
@ -49,7 +51,10 @@ class Sugarcane extends Flowable{
|
||||
for($y = 1; $y < 3; ++$y){
|
||||
$b = $this->getLevel()->getBlock(new Vector3($this->x, $this->y + $y, $this->z));
|
||||
if($b->getID() === self::AIR){
|
||||
$this->getLevel()->setBlock($b, new Sugarcane(), true);
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new BlockGrowEvent($b, new Sugarcane()));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($b, $ev->getNewState(), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -69,10 +74,8 @@ class Sugarcane extends Flowable{
|
||||
public function onUpdate($type){
|
||||
if($type === Level::BLOCK_UPDATE_NORMAL){
|
||||
$down = $this->getSide(0);
|
||||
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get(SUGARCANE));
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
if($down->isTransparent === true and $down->getID() !== self::SUGARCANE_BLOCK){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
return Level::BLOCK_UPDATE_NORMAL;
|
||||
}
|
||||
|
@ -21,8 +21,15 @@
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\entity\PrimedTNT;
|
||||
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\utils\Random;
|
||||
|
||||
class TNT extends Solid{
|
||||
public function __construct(){
|
||||
@ -33,20 +40,29 @@ class TNT extends Solid{
|
||||
|
||||
public function onActivate(Item $item, Player $player = null){
|
||||
if($item->getID() === Item::FLINT_STEEL){
|
||||
if(($player->gamemode & 0x01) === 0){
|
||||
$item->useOn($this);
|
||||
}
|
||||
$data = [
|
||||
"x" => $this->x + 0.5,
|
||||
"y" => $this->y + 0.5,
|
||||
"z" => $this->z + 0.5,
|
||||
"power" => 4,
|
||||
"fuse" => 20 * 4, //4 seconds
|
||||
];
|
||||
$item->useOn($this);
|
||||
$this->getLevel()->setBlock($this, new Air(), false, false, true);
|
||||
//TODO
|
||||
//$e = Server::getInstance()->api->entity->add($this->level, ENTITY_OBJECT, OBJECT_PRIMEDTNT, $data);
|
||||
//$e->spawnToAll();
|
||||
|
||||
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
|
||||
$tnt = new PrimedTNT($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
|
||||
"Pos" => new Enum("Pos", [
|
||||
new Double("", $this->x + 0.5),
|
||||
new Double("", $this->y),
|
||||
new Double("", $this->z + 0.5)
|
||||
]),
|
||||
"Motion" => new Enum("Motion", [
|
||||
new Double("", -sin($mot) * 0.02),
|
||||
new Double("", 0.2),
|
||||
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;
|
||||
}
|
||||
|
@ -24,12 +24,16 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
class Thin extends Transparent{
|
||||
abstract class Thin extends Transparent{
|
||||
|
||||
public $isFullBlock = false;
|
||||
public $isSolid = false;
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$f = 0.4375;
|
||||
$f1 = 0.5625;
|
||||
$f2 = 0.4375;
|
||||
@ -62,7 +66,7 @@ class Thin extends Transparent{
|
||||
$f3 = 1;
|
||||
}
|
||||
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x + $f,
|
||||
$this->y,
|
||||
$this->z + $f2,
|
||||
|
@ -49,10 +49,8 @@ class Torch extends Flowable{
|
||||
0 => 0,
|
||||
];
|
||||
|
||||
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){ //Replace with common break method
|
||||
//TODO
|
||||
//Server::getInstance()->api->entity->drop($this, Item::get($this->id, 0, 1));
|
||||
$this->getLevel()->setBlock($this, new Air(), true);
|
||||
if($this->getSide($faces[$side])->isTransparent === true and !($side === 0 and $this->getSide(0)->getID() === self::FENCE)){
|
||||
$this->getLevel()->useBreakOn($this);
|
||||
|
||||
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 $breakable = true;
|
||||
public $isFlowable = false;
|
||||
|
@ -38,6 +38,10 @@ class Trapdoor extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$damage = $this->getDamage();
|
||||
|
||||
$f = 0.1875;
|
||||
@ -104,7 +108,7 @@ class Trapdoor extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
return $bb;
|
||||
return $this->boundingBox = $bb;
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
|
175
src/pocketmine/block/Vine.php
Normal file
175
src/pocketmine/block/Vine.php
Normal file
@ -0,0 +1,175 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
$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 $this->boundingBox = 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,27 @@
|
||||
|
||||
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\item\Item;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Water extends Liquid{
|
||||
public function __construct($meta = 0){
|
||||
parent::__construct(self::WATER, $meta, "Water");
|
||||
$this->hardness = 500;
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onEntityCollide(Entity $entity){
|
||||
$entity->fallDistance = 0;
|
||||
$entity->extinguish();
|
||||
if($entity->fireTicks > 0){
|
||||
$entity->extinguish();
|
||||
}
|
||||
}
|
||||
|
||||
public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true);
|
||||
$this->getLevel()->scheduleUpdate(clone $this, 10);
|
||||
$ret = $this->getLevel()->setBlock($this, $this, true, false);
|
||||
$this->getLevel()->scheduleUpdate($this, $this->tickRate());
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function getSourceCount(){
|
||||
$count = 0;
|
||||
for($side = 2; $side <= 5; ++$side){
|
||||
if($this->getSide($side) instanceof 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;
|
||||
}
|
||||
}
|
||||
|
@ -25,62 +25,9 @@ use pocketmine\item\Item;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Wheat extends Flowable{
|
||||
class Wheat extends Crops{
|
||||
public function __construct($meta = 0){
|
||||
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){
|
||||
|
@ -46,8 +46,12 @@ class WoodSlab extends Transparent{
|
||||
}
|
||||
|
||||
public function getBoundingBox(){
|
||||
if($this->boundingBox !== null){
|
||||
return $this->boundingBox;
|
||||
}
|
||||
|
||||
if(($this->meta & 0x08) > 0){
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y + 0.5,
|
||||
$this->z,
|
||||
@ -56,7 +60,7 @@ class WoodSlab extends Transparent{
|
||||
$this->z + 1
|
||||
);
|
||||
}else{
|
||||
return new AxisAlignedBB(
|
||||
return $this->boundingBox = new AxisAlignedBB(
|
||||
$this->x,
|
||||
$this->y,
|
||||
$this->z,
|
||||
@ -91,7 +95,7 @@ class WoodSlab extends Transparent{
|
||||
|
||||
return true;
|
||||
}
|
||||
}elseif(!($player instanceof Player)){ //TODO: collision
|
||||
}else{ //TODO: collision
|
||||
if($block->getID() === self::WOOD_SLAB){
|
||||
if(($block->getDamage() & 0x07) === ($this->meta & 0x07)){
|
||||
$this->getLevel()->setBlock($block, Block::get(Item::DOUBLE_WOOD_SLAB, $this->meta), true);
|
||||
@ -105,9 +109,8 @@ class WoodSlab extends Transparent{
|
||||
$this->meta |= 0x08;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($block->getID() === self::WOOD_SLAB and ($target->getDamage() & 0x07) !== ($this->meta & 0x07)){
|
||||
return false;
|
||||
}
|
||||
|
@ -31,13 +31,15 @@ class CommandReader extends Thread{
|
||||
private $readline;
|
||||
|
||||
/** @var \Threaded */
|
||||
private $buffer;
|
||||
protected $buffer;
|
||||
|
||||
/**
|
||||
* @param \Threaded $threaded
|
||||
* @param string $stream
|
||||
*/
|
||||
public function __construct($stream = "php://stdin"){
|
||||
public function __construct(\Threaded $threaded, $stream = "php://stdin"){
|
||||
$this->stream = $stream;
|
||||
$this->buffer = $threaded;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
@ -70,7 +72,6 @@ class CommandReader extends Thread{
|
||||
}
|
||||
|
||||
public function run(){
|
||||
$this->buffer = new \Threaded;
|
||||
$opts = getopt("", ["disable-readline"]);
|
||||
if(extension_loaded("readline") and $this->stream === "php://stdin" and !isset($opts["disable-readline"])){
|
||||
$this->readline = true;
|
||||
|
@ -178,7 +178,11 @@ class SimpleCommandMap implements CommandMap{
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
return true;
|
||||
|
@ -45,9 +45,7 @@ class KillCommand extends VanillaCommand{
|
||||
}
|
||||
|
||||
if($sender instanceof Player){
|
||||
//TODO: EntityDamageEvent
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||
$sender->getServer()->getPluginManager()->callEvent($ev = new EntityDamageEvent($sender, EntityDamageEvent::CAUSE_SUICIDE, 1000));
|
||||
|
||||
if($ev->isCancelled()){
|
||||
return true;
|
||||
|
@ -41,9 +41,7 @@ class SaveOffCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach($sender->getServer()->getLevels() as $level){
|
||||
$level->setAutoSave(false);
|
||||
}
|
||||
$sender->getServer()->setAutoSave(false);
|
||||
|
||||
Command::broadcastCommandMessage($sender, "Disabled level saving");
|
||||
|
||||
|
@ -41,9 +41,7 @@ class SaveOnCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach($sender->getServer()->getLevels() as $level){
|
||||
$level->setAutoSave(true);
|
||||
}
|
||||
$sender->getServer()->setAutoSave(true);
|
||||
|
||||
Command::broadcastCommandMessage($sender, "Enabled level saving");
|
||||
|
||||
|
@ -66,7 +66,7 @@ class SpawnpointCommand extends VanillaCommand{
|
||||
|
||||
if(count($args) === 4){
|
||||
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]);
|
||||
$y = $this->getRelativeDouble($pos->y, $sender, $args[2], 0, 128);
|
||||
$z = $this->getRelativeDouble($pos->z, $sender, $args[3]);
|
||||
|
@ -43,6 +43,7 @@ class StatusCommand extends VanillaCommand{
|
||||
$server = $sender->getServer();
|
||||
$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----");
|
||||
$sender->sendMessage(TextFormat::GOLD . "TPS: " . TextFormat::WHITE . $server->getTicksPerSecond());
|
||||
$sender->sendMessage(TextFormat::GOLD . "TPS Load: " . TextFormat::WHITE . $server->getTickUsage() . "%");
|
||||
//TODO: implement network speed
|
||||
//$sender->sendMessage(TextFormat::GOLD . "Upload: " . TextFormat::WHITE . round($server->getNetwork()->getUploadSpeed() / 1024, 2) . " kB/s");
|
||||
//$sender->sendMessage(TextFormat::GOLD . "Download: " . TextFormat::WHITE . round($server->getNetwork()->getDownloadSpeed() / 1024, 2) . " kB/s");
|
||||
@ -50,4 +51,4 @@ class StatusCommand extends VanillaCommand{
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,11 @@
|
||||
namespace pocketmine\entity;
|
||||
|
||||
|
||||
use pocketmine\event\entity\EntityCombustByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\event\entity\ProjectileHitEvent;
|
||||
use pocketmine\level\format\FullChunk;
|
||||
use pocketmine\level\MovingObjectPosition;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -64,112 +67,129 @@ class Arrow extends Projectile{
|
||||
|
||||
}
|
||||
|
||||
public function onUpdate(){
|
||||
$this->entityBaseTick();
|
||||
|
||||
if($this->closed !== false){
|
||||
public function onUpdate($currentTick){
|
||||
if($this->closed){
|
||||
return false;
|
||||
}
|
||||
|
||||
$movingObjectPosition = null;
|
||||
$this->timings->startTiming();
|
||||
|
||||
$this->motionY -= $this->gravity;
|
||||
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||
$this->lastUpdate = $currentTick;
|
||||
|
||||
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
||||
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||
|
||||
$moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
|
||||
if(!$this->dead){
|
||||
|
||||
$list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
|
||||
$movingObjectPosition = null;
|
||||
|
||||
$nearDistance = PHP_INT_MAX;
|
||||
$nearEntity = null;
|
||||
$this->motionY -= $this->gravity;
|
||||
|
||||
foreach($list as $entity){
|
||||
if(!$entity->canCollideWith($this) or ($entity === $this->shootingEntity and $this->ticksLived < 5)){
|
||||
continue;
|
||||
}
|
||||
$this->inBlock = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
|
||||
|
||||
$axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
|
||||
$ob = $axisalignedbb->calculateIntercept($this, $moveVector);
|
||||
$moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
|
||||
|
||||
if($ob === null){
|
||||
continue;
|
||||
}
|
||||
$list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
|
||||
|
||||
$distance = $this->distance($ob->hitVector);
|
||||
$nearDistance = PHP_INT_MAX;
|
||||
$nearEntity = null;
|
||||
|
||||
if($distance < $nearDistance){
|
||||
$nearDistance = $distance;
|
||||
$nearEntity = $entity;
|
||||
}
|
||||
}
|
||||
foreach($list as $entity){
|
||||
if(/*!$entity->canCollideWith($this) or */
|
||||
($entity === $this->shootingEntity and $this->ticksLived < 5)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($nearEntity !== null){
|
||||
$movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity);
|
||||
}
|
||||
$axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
|
||||
$ob = $axisalignedbb->calculateIntercept($this, $moveVector);
|
||||
|
||||
if($movingObjectPosition !== null){
|
||||
if($movingObjectPosition->entityHit !== null){
|
||||
$motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2);
|
||||
$damage = ceil($motion * $this->damage);
|
||||
if($ob === null){
|
||||
continue;
|
||||
}
|
||||
|
||||
$distance = $this->distance($ob->hitVector);
|
||||
|
||||
$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();
|
||||
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);
|
||||
|
||||
|
||||
$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($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->onGround and ($this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0)){
|
||||
$this->motionX = 0;
|
||||
$this->motionY = 0;
|
||||
$this->motionZ = 0;
|
||||
|
||||
$this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if($this->age > 1200){
|
||||
$this->kill();
|
||||
$hasUpdate = true;
|
||||
}
|
||||
$this->updateMovement();
|
||||
|
||||
}
|
||||
|
||||
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||
$this->timings->stopTiming();
|
||||
|
||||
$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){
|
||||
$this->kill();
|
||||
}
|
||||
$this->updateMovement();
|
||||
|
||||
return !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
||||
return $hasUpdate;
|
||||
}
|
||||
|
||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||
$this->setLastDamageCause($source);
|
||||
$this->setHealth($this->getHealth() - $damage);
|
||||
|
||||
}
|
||||
|
||||
public function heal($amount){
|
||||
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||
|
||||
}
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Age = new Short("Age", $this->age);
|
||||
}
|
||||
|
||||
@ -178,7 +198,9 @@ class Arrow extends Projectile{
|
||||
$flags |= $this->fireTicks > 0 ? 1 : 0;
|
||||
|
||||
return [
|
||||
0 => ["type" => 0, "value" => $flags]
|
||||
0 => ["type" => 0, "value" => $flags],
|
||||
1 => ["type" => 1, "value" => $this->airTicks],
|
||||
16 => ["type" => 0, "value" => 0] //Is critical
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,9 @@
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\event\entity\ItemDespawnEvent;
|
||||
use pocketmine\event\entity\ItemSpawnEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
@ -46,10 +49,12 @@ class DroppedItem extends Entity{
|
||||
protected $gravity = 0.04;
|
||||
protected $drag = 0.02;
|
||||
|
||||
public $canCollide = false;
|
||||
|
||||
protected function initEntity(){
|
||||
$this->namedtag->id = new String("id", "Item");
|
||||
$this->setMaxHealth(5);
|
||||
$this->setHealth(@$this->namedtag["Health"]);
|
||||
$this->setHealth($this->namedtag["Health"]);
|
||||
if(isset($this->namedtag->Age)){
|
||||
$this->age = $this->namedtag["Age"];
|
||||
}
|
||||
@ -63,44 +68,65 @@ class DroppedItem extends Entity{
|
||||
$this->thrower = $this->namedtag["Thrower"];
|
||||
}
|
||||
$this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
|
||||
|
||||
|
||||
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
|
||||
}
|
||||
|
||||
public function onUpdate(){
|
||||
$this->entityBaseTick();
|
||||
|
||||
public function onUpdate($currentTick){
|
||||
if($this->closed !== false){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
|
||||
--$this->pickupDelay;
|
||||
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||
$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->inBlock = $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);
|
||||
$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);
|
||||
return $hasUpdate or !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
||||
}
|
||||
|
||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||
@ -108,11 +134,12 @@ class DroppedItem extends Entity{
|
||||
$this->setHealth($this->getHealth() - $damage);
|
||||
}
|
||||
|
||||
public function heal($amount){
|
||||
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||
|
||||
}
|
||||
|
||||
public function saveNBT(){
|
||||
parent::saveNBT();
|
||||
$this->namedtag->Item = new Compound("Item", [
|
||||
"id" => new Short("id", $this->item->getID()),
|
||||
"Damage" => new Short("Damage", $this->item->getDamage()),
|
||||
|
@ -24,21 +24,22 @@
|
||||
*/
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\Water;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityDespawnEvent;
|
||||
use pocketmine\event\entity\EntityLevelChangeEvent;
|
||||
use pocketmine\event\entity\EntityMotionEvent;
|
||||
use pocketmine\event\entity\EntityMoveEvent;
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\event\entity\EntitySpawnEvent;
|
||||
use pocketmine\event\entity\EntityTeleportEvent;
|
||||
use pocketmine\event\Timings;
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\FullChunk;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Location;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Math;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
use pocketmine\metadata\Metadatable;
|
||||
use pocketmine\metadata\MetadataValue;
|
||||
@ -48,8 +49,8 @@ use pocketmine\nbt\tag\Double;
|
||||
use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\Float;
|
||||
use pocketmine\nbt\tag\Short;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\Network;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\network\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\protocol\RemoveEntityPacket;
|
||||
use pocketmine\network\protocol\SetEntityDataPacket;
|
||||
@ -59,7 +60,7 @@ use pocketmine\Player;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\Server;
|
||||
|
||||
abstract class Entity extends Position implements Metadatable{
|
||||
abstract class Entity extends Location implements Metadatable{
|
||||
|
||||
const NETWORK_ID = -1;
|
||||
|
||||
@ -96,8 +97,6 @@ abstract class Entity extends Position implements Metadatable{
|
||||
public $lastMotionY;
|
||||
public $lastMotionZ;
|
||||
|
||||
public $yaw;
|
||||
public $pitch;
|
||||
public $lastYaw;
|
||||
public $lastPitch;
|
||||
|
||||
@ -132,17 +131,16 @@ abstract class Entity extends Position implements Metadatable{
|
||||
public $fireTicks;
|
||||
public $airTicks;
|
||||
public $namedtag;
|
||||
public $canCollide = true;
|
||||
|
||||
protected $isStatic = false;
|
||||
protected $isColliding = false;
|
||||
|
||||
protected $inWater;
|
||||
public $noDamageTicks;
|
||||
private $justCreated;
|
||||
protected $fireProof;
|
||||
private $invulnerable;
|
||||
|
||||
protected $spawnTime;
|
||||
|
||||
protected $gravity;
|
||||
protected $drag;
|
||||
|
||||
@ -151,14 +149,19 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
public $closed = false;
|
||||
|
||||
/** @var \pocketmine\event\TimingsHandler */
|
||||
protected $timings;
|
||||
|
||||
|
||||
public function __construct(FullChunk $chunk, Compound $nbt){
|
||||
if($chunk === null or $chunk->getProvider() === null){
|
||||
throw new \Exception("Invalid garbage Chunk given to Entity");
|
||||
}
|
||||
|
||||
$this->timings = Timings::getEntityTimings($this);
|
||||
|
||||
if($this->eyeHeight === null){
|
||||
$this->eyeHeight = $this->height;
|
||||
$this->eyeHeight = $this->height / 2 + 0.1;
|
||||
}
|
||||
|
||||
$this->id = Entity::$entityCount++;
|
||||
@ -197,7 +200,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$this->airTicks = $this->namedtag["Air"];
|
||||
|
||||
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;
|
||||
|
||||
@ -207,9 +210,9 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false;
|
||||
|
||||
$this->chunk->addEntity($this);
|
||||
$this->getLevel()->addEntity($this);
|
||||
$this->level->addEntity($this);
|
||||
$this->initEntity();
|
||||
$this->lastUpdate = $this->spawnTime = microtime(true);
|
||||
$this->lastUpdate = $this->server->getTick();
|
||||
$this->server->getPluginManager()->callEvent(new EntitySpawnEvent($this));
|
||||
|
||||
$this->scheduleUpdate();
|
||||
@ -270,13 +273,15 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$pk = new SetEntityDataPacket();
|
||||
$pk->eid = $this->id;
|
||||
$pk->metadata = $this->getData();
|
||||
$pk->encode();
|
||||
$pk->isEncoded = true;
|
||||
foreach($player as $p){
|
||||
if($p === $this){
|
||||
/** @var Player $p */
|
||||
$pk = new SetEntityDataPacket();
|
||||
$pk->eid = 0;
|
||||
$pk->metadata = $this->getData();
|
||||
$p->dataPacket($pk);
|
||||
$pk2 = new SetEntityDataPacket();
|
||||
$pk2->eid = 0;
|
||||
$pk2->metadata = $this->getData();
|
||||
$p->dataPacket($pk2);
|
||||
}else{
|
||||
$p->dataPacket($pk);
|
||||
}
|
||||
@ -299,11 +304,15 @@ abstract class Entity extends Position implements Metadatable{
|
||||
* @param float $damage
|
||||
* @param int|EntityDamageEvent $source
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
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
|
||||
@ -376,17 +385,17 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$diffY = $y - $j;
|
||||
$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))){
|
||||
if(count($list) === 0 and !$this->level->isFullBlock(new Vector3($i, $j, $k))){
|
||||
return false;
|
||||
}else{
|
||||
$flag = !$this->getLevel()->isFullBlock(new Vector3($i - 1, $j, $k));
|
||||
$flag1 = !$this->getLevel()->isFullBlock(new Vector3($i + 1, $j, $k));
|
||||
//$flag2 = !$this->getLevel()->isFullBlock(new Vector3($i, $j - 1, $k));
|
||||
$flag3 = !$this->getLevel()->isFullBlock(new Vector3($i, $j + 1, $k));
|
||||
$flag4 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k - 1));
|
||||
$flag5 = !$this->getLevel()->isFullBlock(new Vector3($i, $j, $k + 1));
|
||||
$flag = !$this->level->isFullBlock(new Vector3($i - 1, $j, $k));
|
||||
$flag1 = !$this->level->isFullBlock(new Vector3($i + 1, $j, $k));
|
||||
//$flag2 = !$this->level->isFullBlock(new Vector3($i, $j - 1, $k));
|
||||
$flag3 = !$this->level->isFullBlock(new Vector3($i, $j + 1, $k));
|
||||
$flag4 = !$this->level->isFullBlock(new Vector3($i, $j, $k - 1));
|
||||
$flag5 = !$this->level->isFullBlock(new Vector3($i, $j, $k + 1));
|
||||
|
||||
$direction = 3; //UP!
|
||||
$limit = 9999;
|
||||
@ -452,72 +461,65 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}
|
||||
}
|
||||
|
||||
public function entityBaseTick(){
|
||||
public function entityBaseTick($tickDiff = 1){
|
||||
|
||||
Timings::$tickEntityTimer->startTiming();
|
||||
//TODO: check vehicles
|
||||
|
||||
$this->justCreated = false;
|
||||
$isPlayer = $this instanceof Player;
|
||||
|
||||
if($this->dead === true and !($this instanceof Player)){
|
||||
$this->close();
|
||||
|
||||
return false;
|
||||
}elseif($this->dead === true){
|
||||
if($this->dead === true){
|
||||
$this->despawnFromAll();
|
||||
if(!$isPlayer){
|
||||
$this->close();
|
||||
}
|
||||
Timings::$tickEntityTimer->stopTiming();
|
||||
return $isPlayer;
|
||||
}
|
||||
|
||||
$hasUpdate = false;
|
||||
$this->updateMovement();
|
||||
|
||||
$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){
|
||||
$this->server->getPluginManager()->callEvent($ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
$hasUpdate = true;
|
||||
}
|
||||
|
||||
if($this->fireTicks > 0){
|
||||
if($this->fireProof){
|
||||
$this->fireTicks -= 4;
|
||||
$this->fireTicks -= 4 * $tickDiff;
|
||||
if($this->fireTicks < 0){
|
||||
$this->fireTicks = 0;
|
||||
}
|
||||
}else{
|
||||
if(($this->fireTicks % 20) === 0){
|
||||
if(($this->fireTicks % 20) === 0 or $tickDiff > 20){
|
||||
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FIRE_TICK, 1);
|
||||
$this->server->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$this->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
}
|
||||
--$this->fireTicks;
|
||||
$this->fireTicks -= $tickDiff;
|
||||
}
|
||||
|
||||
if($this->fireTicks <= 0){
|
||||
$this->extinguish();
|
||||
}else{
|
||||
$hasUpdate = true;
|
||||
}
|
||||
|
||||
$hasUpdate = true;
|
||||
}
|
||||
|
||||
if($this->handleLavaMovement()){
|
||||
//$this->attack(4, EntityDamageEvent::CAUSE_LAVA);
|
||||
//$this->setOnFire(15);
|
||||
$hasUpdate = true;
|
||||
$this->fallDistance *= 0.5;
|
||||
}
|
||||
$this->age += $tickDiff;
|
||||
$this->ticksLived += $tickDiff;
|
||||
|
||||
++$this->age;
|
||||
++$this->ticksLived;
|
||||
Timings::$tickEntityTimer->stopTiming();
|
||||
|
||||
return $hasUpdate;
|
||||
}
|
||||
|
||||
public function updateMovement(){
|
||||
@ -533,7 +535,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$pk = new MovePlayerPacket;
|
||||
$pk->eid = $this->id;
|
||||
$pk->x = $this->x;
|
||||
$pk->y = $this->y; //teleport from head
|
||||
$pk->y = $this->y;
|
||||
$pk->z = $this->z;
|
||||
$pk->yaw = $this->yaw;
|
||||
$pk->pitch = $this->pitch;
|
||||
@ -542,13 +544,11 @@ abstract class Entity extends Position implements Metadatable{
|
||||
//TODO: add to move list
|
||||
$pk = new MoveEntityPacket();
|
||||
$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){
|
||||
$player->directDataPacket($pk);
|
||||
}
|
||||
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||
}
|
||||
|
||||
if(($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){
|
||||
@ -560,6 +560,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$pk->entities = [
|
||||
[$this->getID(), $this->motionX, $this->motionY, $this->motionZ]
|
||||
];
|
||||
|
||||
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||
|
||||
if($this instanceof Player){
|
||||
@ -585,15 +586,24 @@ abstract class Entity extends Position implements Metadatable{
|
||||
return new Vector3($x, $y, $z);
|
||||
}
|
||||
|
||||
public function onUpdate(){
|
||||
if($this->closed !== false){
|
||||
public function onUpdate($currentTick){
|
||||
if($this->closed){
|
||||
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())
|
||||
return true;
|
||||
return $hasUpdate;
|
||||
//return !($this instanceof Player);
|
||||
}
|
||||
|
||||
@ -673,10 +683,6 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}
|
||||
}
|
||||
|
||||
public function handleWaterMovement(){ //TODO
|
||||
|
||||
}
|
||||
|
||||
public function handleLavaMovement(){ //TODO
|
||||
|
||||
}
|
||||
@ -695,12 +701,12 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
protected function switchLevel(Level $targetLevel){
|
||||
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()){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->getLevel()->removeEntity($this);
|
||||
$this->level->removeEntity($this);
|
||||
$this->chunk->removeEntity($this);
|
||||
$this->despawnFromAll();
|
||||
if($this instanceof Player){
|
||||
@ -708,21 +714,21 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$X = null;
|
||||
$Z = null;
|
||||
Level::getXZ($index, $X, $Z);
|
||||
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
||||
foreach($this->level->getChunkEntities($X, $Z) as $entity){
|
||||
$entity->despawnFrom($this);
|
||||
}
|
||||
|
||||
}
|
||||
$this->getLevel()->freeAllChunks($this);
|
||||
$this->level->freeAllChunks($this);
|
||||
}
|
||||
}
|
||||
$this->setLevel($targetLevel, $this instanceof Player ? true : false); //Hard reference
|
||||
$this->getLevel()->addEntity($this);
|
||||
$this->level->addEntity($this);
|
||||
if($this instanceof Player){
|
||||
$this->usedChunks = [];
|
||||
$pk = new SetTimePacket();
|
||||
$pk->time = $this->getLevel()->getTime();
|
||||
$pk->started = $this->getLevel()->stopTime == false;
|
||||
$pk->time = $this->level->getTime();
|
||||
$pk->started = $this->level->stopTime == false;
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
$this->chunk = null;
|
||||
@ -731,11 +737,15 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}
|
||||
|
||||
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(){
|
||||
$block = $this->getLevel()->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
|
||||
$block = $this->level->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
|
||||
|
||||
if($block instanceof Water){
|
||||
$f = ($pos->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
|
||||
@ -746,26 +756,14 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}
|
||||
|
||||
public function isInsideOfSolid(){
|
||||
for($i = 0; $i < 8; ++$i){
|
||||
$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());
|
||||
$block = $this->level->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
|
||||
|
||||
if($block->isSolid){
|
||||
return true;
|
||||
}
|
||||
$bb = $block->getBoundingBox();
|
||||
|
||||
if($bb !== null and $block->isSolid and !$block->isTransparent and $bb->intersectsWith($this->getBoundingBox())){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
$block = $this->getLevel()->getBlock($pos = (new Vector3($this->x, $y = ($this->y + $this->getEyeHeight()), $this->z))->floor());
|
||||
|
||||
if($block instanceof Water){
|
||||
$f = ($pos->y + 1) - ($block->getFluidHeightPercent() - 0.1111111);
|
||||
return $y < $f;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function collision(){
|
||||
@ -811,7 +809,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
/*$sneakFlag = $this->onGround and $this instanceof Player;
|
||||
|
||||
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){
|
||||
$dx = 0;
|
||||
}elseif($dx > 0){
|
||||
@ -821,7 +819,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){
|
||||
$dz = 0;
|
||||
}elseif($dz > 0){
|
||||
@ -834,7 +832,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
//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), false);
|
||||
|
||||
|
||||
foreach($list as $bb){
|
||||
@ -888,7 +886,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
$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){
|
||||
$dy = $bb->calculateYOffset($this->boundingBox, $dy);
|
||||
@ -946,7 +944,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
|
||||
$pos = new Vector3(
|
||||
($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
|
||||
);
|
||||
|
||||
@ -958,8 +956,10 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}else{
|
||||
|
||||
if($this instanceof Player){
|
||||
if(($this->onGround and $movY != 0) or (!$this->onGround and $movY <= 0)){
|
||||
if(count($this->getLevel()->getCollisionBlocks($this->boundingBox->getOffsetBoundingBox(0, $movY - 0.1, 0))) > 0){
|
||||
if(($this->onGround and $movY != 0) or (!$this->onGround and $movY < 0)){
|
||||
$bb = clone $this->boundingBox;
|
||||
$bb->maxY = $bb->minY + 0.5;
|
||||
if(count($this->level->getCollisionBlocks($bb->expand(0.01, 0.01, 0.01))) > 0){
|
||||
$isColliding = true;
|
||||
}else{
|
||||
$isColliding = false;
|
||||
@ -994,27 +994,40 @@ abstract class Entity extends Position implements Metadatable{
|
||||
}
|
||||
|
||||
protected function checkBlockCollision(){
|
||||
$minX = floor($this->boundingBox->minX - 0.001);
|
||||
$minY = floor($this->boundingBox->minY - 0.001);
|
||||
$minZ = floor($this->boundingBox->minZ - 0.001);
|
||||
$maxX = floor($this->boundingBox->maxX + 0.001);
|
||||
$maxY = floor($this->boundingBox->maxY + 0.001);
|
||||
$maxZ = floor($this->boundingBox->maxZ + 0.001);
|
||||
$minX = Math::floorFloat($this->boundingBox->minX + 0.001);
|
||||
$minY = Math::floorFloat($this->boundingBox->minY + 0.001);
|
||||
$minZ = Math::floorFloat($this->boundingBox->minZ + 0.001);
|
||||
$maxX = Math::floorFloat($this->boundingBox->maxX - 0.001);
|
||||
$maxY = Math::floorFloat($this->boundingBox->maxY - 0.001);
|
||||
$maxZ = Math::floorFloat($this->boundingBox->maxZ - 0.001);
|
||||
|
||||
$vector = new Vector3(0, 0, 0);
|
||||
|
||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||
for($x = $minX; $x <= $maxX; ++$x){
|
||||
for($y = $minY; $y <= $maxY; ++$y){
|
||||
$block = $this->getLevel()->getBlock(new Vector3($x, $y, $z));
|
||||
if($block !== null and $block->getID() > 0){
|
||||
$block = $this->level->getBlock(new Vector3($x, $y, $z));
|
||||
if($block !== null and $block->hasEntityCollision){
|
||||
$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){
|
||||
if($this->setPosition($pos, $force) === true){
|
||||
public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){
|
||||
if($this->setPosition($pos) === true){
|
||||
$this->setRotation($yaw, $pitch);
|
||||
|
||||
return true;
|
||||
@ -1029,22 +1042,13 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$this->scheduleUpdate();
|
||||
}
|
||||
|
||||
public function setPosition(Vector3 $pos, $force = false){
|
||||
if($pos instanceof Position and $pos->getLevel() instanceof Level and $pos->getLevel() !== $this->getLevel()){
|
||||
public function setPosition(Vector3 $pos){
|
||||
if($pos instanceof Position and $pos->level instanceof Level and $pos->level !== $this->level){
|
||||
if($this->switchLevel($pos->getLevel()) === false){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->justCreated and $force !== true){
|
||||
$ev = new EntityMoveEvent($this, $pos);
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev);
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->x = $pos->x;
|
||||
$this->y = $pos->y;
|
||||
$this->z = $pos->z;
|
||||
@ -1057,11 +1061,11 @@ abstract class Entity extends Position implements Metadatable{
|
||||
if($this->chunk instanceof FullChunk){
|
||||
$this->chunk->removeEntity($this);
|
||||
}
|
||||
$this->getLevel()->loadChunk($this->x >> 4, $this->z >> 4);
|
||||
$this->chunk = $this->getLevel()->getChunkAt($this->x >> 4, $this->z >> 4);
|
||||
$this->level->loadChunk($this->x >> 4, $this->z >> 4);
|
||||
$this->chunk = $this->level->getChunk($this->x >> 4, $this->z >> 4);
|
||||
|
||||
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){
|
||||
if(!isset($newChunk[$player->getID()])){
|
||||
$this->despawnFrom($player);
|
||||
@ -1091,9 +1095,11 @@ abstract class Entity extends Position implements Metadatable{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->motionX = $motion->x;
|
||||
$this->motionY = $motion->y;
|
||||
$this->motionZ = $motion->z;
|
||||
|
||||
if(!$this->justCreated){
|
||||
if($this instanceof Player){
|
||||
$pk = new SetEntityMotionPacket;
|
||||
@ -1121,9 +1127,20 @@ abstract class Entity extends Position implements Metadatable{
|
||||
$this->scheduleUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Vector3|Position|Location $pos
|
||||
* @param float $yaw
|
||||
* @param float $pitch
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){
|
||||
$from = Position::fromObject($this, $this->getLevel());
|
||||
$to = Position::fromObject($pos, $pos instanceof Position ? $pos->getLevel() : $this->getLevel());
|
||||
if($pos instanceof Location){
|
||||
$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));
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
@ -1142,12 +1159,12 @@ abstract class Entity extends Position implements Metadatable{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getID(){
|
||||
public function getId(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
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){
|
||||
$this->spawnTo($player);
|
||||
}
|
||||
@ -1168,7 +1185,7 @@ abstract class Entity extends Position implements Metadatable{
|
||||
if($this->chunk instanceof FullChunk){
|
||||
$this->chunk->removeEntity($this);
|
||||
}
|
||||
if(($level = $this->getLevel()) instanceof Level){
|
||||
if(($level = $this->level) instanceof Level){
|
||||
$level->removeEntity($this);
|
||||
}
|
||||
$this->despawnFromAll();
|
||||
|
@ -24,4 +24,5 @@ namespace pocketmine\entity;
|
||||
|
||||
interface Explosive{
|
||||
|
||||
public function explode();
|
||||
}
|
@ -22,14 +22,16 @@
|
||||
namespace pocketmine\entity;
|
||||
|
||||
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\entity\EntityBlockChangeEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityRegainHealthEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\network\protocol\AddEntityPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
|
||||
class FallingBlock extends Entity{
|
||||
|
||||
@ -43,6 +45,8 @@ class FallingBlock extends Entity{
|
||||
protected $drag = 0.02;
|
||||
protected $blockId = 0;
|
||||
|
||||
public $canCollide = false;
|
||||
|
||||
protected function initEntity(){
|
||||
$this->namedtag->id = new String("id", "FallingSand");
|
||||
if(isset($this->namedtag->Tile)){
|
||||
@ -62,48 +66,60 @@ class FallingBlock extends Entity{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function onUpdate(){
|
||||
$this->entityBaseTick();
|
||||
public function onUpdate($currentTick){
|
||||
|
||||
if($this->closed !== false){
|
||||
if($this->closed){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->motionY -= $this->gravity;
|
||||
$this->timings->startTiming();
|
||||
|
||||
$this->move($this->motionX, $this->motionY, $this->motionZ);
|
||||
$tickDiff = max(1, $currentTick - $this->lastUpdate);
|
||||
$this->lastUpdate = $currentTick;
|
||||
|
||||
$friction = 1 - $this->drag;
|
||||
$hasUpdate = $this->entityBaseTick($tickDiff);
|
||||
|
||||
$this->motionX *= $friction;
|
||||
$this->motionY *= 1 - $this->drag;
|
||||
$this->motionZ *= $friction;
|
||||
if(!$this->dead){
|
||||
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);
|
||||
|
||||
$pos = $this->floor();
|
||||
}
|
||||
|
||||
if($this->ticksLived === 1){
|
||||
$block = $this->level->getBlock($pos);
|
||||
if($block->getID() != $this->blockId){
|
||||
$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();
|
||||
return true;
|
||||
$block = $this->level->getBlock($pos);
|
||||
if(!$block->isFullBlock){
|
||||
$this->getLevel()->dropItem($this, Item::get($this->getBlock(), 0, 1));
|
||||
}else{
|
||||
$this->server->getPluginManager()->callEvent($ev = new EntityBlockChangeEvent($this, $block, Block::get($this->getBlock(), 0)));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getLevel()->setBlock($pos, $ev->getTo(), true);
|
||||
}
|
||||
}
|
||||
$hasUpdate = true;
|
||||
}
|
||||
$this->level->setBlock($pos, Block::get(0, true));
|
||||
|
||||
$this->updateMovement();
|
||||
}
|
||||
|
||||
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);
|
||||
return $hasUpdate or !$this->onGround or ($this->motionX == 0 and $this->motionY == 0 and $this->motionZ == 0);
|
||||
}
|
||||
|
||||
public function getBlock(){
|
||||
@ -118,7 +134,7 @@ class FallingBlock extends Entity{
|
||||
|
||||
}
|
||||
|
||||
public function heal($amount){
|
||||
public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,10 @@ use pocketmine\nbt\tag\Byte;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\Short;
|
||||
use pocketmine\Network;
|
||||
use pocketmine\network\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\protocol\RemovePlayerPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\Network;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
namespace pocketmine\entity;
|
||||
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityDeathEvent;
|
||||
@ -32,6 +33,7 @@ use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\Short;
|
||||
use pocketmine\network\protocol\EntityEventPacket;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\BlockIterator;
|
||||
|
||||
abstract class Living extends Entity implements Damageable{
|
||||
|
||||
@ -62,7 +64,8 @@ abstract class Living extends Entity implements Damageable{
|
||||
|
||||
public function hasLineOfSight(Entity $entity){
|
||||
//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(new Vector3($this->x, $this->y + $this->height, $this->z), new Vector3($entity->x, $entity->y + $entity->height, $entity->z)) === null;
|
||||
}
|
||||
|
||||
public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
|
||||
@ -78,26 +81,41 @@ abstract class Living extends Entity implements Damageable{
|
||||
$pk->event = 2; //Ouch!
|
||||
Server::broadcastPacket($this->hasSpawned, $pk);
|
||||
$this->setLastDamageCause($source);
|
||||
$motion = new Vector3(0, 0, 0);
|
||||
|
||||
if($source instanceof EntityDamageByEntityEvent){
|
||||
$e = $source->getDamager();
|
||||
$deltaX = $this->x - $e->x;
|
||||
$deltaZ = $this->z - $e->z;
|
||||
$yaw = atan2($deltaX, $deltaZ);
|
||||
$motion->x = sin($yaw) * 0.5;
|
||||
$motion->z = cos($yaw) * 0.5;
|
||||
$this->knockBack($e, $damage, sin($yaw), cos($yaw));
|
||||
}
|
||||
$this->setMotion($motion);
|
||||
|
||||
$this->setHealth($this->getHealth() - $damage);
|
||||
|
||||
$this->attackTime = 10; //0.5 seconds cooldown
|
||||
}
|
||||
|
||||
public function heal($amount){
|
||||
$this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount));
|
||||
if($ev->isCancelled()){
|
||||
return;
|
||||
public function knockBack(Entity $attacker, $damage, $x, $z){
|
||||
$f = sqrt($x ** 2 + $z ** 2);
|
||||
$base = 0.4;
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
@ -112,7 +130,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
}
|
||||
|
||||
public function entityBaseTick(){
|
||||
public function entityBaseTick($tickDiff = 1){
|
||||
Timings::$timerEntityBaseTick->startTiming();
|
||||
parent::entityBaseTick();
|
||||
|
||||
@ -124,7 +142,7 @@ abstract class Living extends Entity implements Damageable{
|
||||
}
|
||||
|
||||
if($this->dead !== true and $this->isInsideOfWater()){
|
||||
--$this->airTicks;
|
||||
$this->airTicks -= $tickDiff;
|
||||
if($this->airTicks <= -20){
|
||||
$this->airTicks = 0;
|
||||
|
||||
@ -133,14 +151,12 @@ abstract class Living extends Entity implements Damageable{
|
||||
$this->attack($ev->getFinalDamage(), $ev);
|
||||
}
|
||||
}
|
||||
|
||||
$this->extinguish();
|
||||
}else{
|
||||
$this->airTicks = 300;
|
||||
}
|
||||
|
||||
if($this->attackTime > 0){
|
||||
--$this->attackTime;
|
||||
$this->attackTime -= $tickDiff;
|
||||
}
|
||||
|
||||
Timings::$timerEntityBaseTick->stopTiming();
|
||||
@ -152,4 +168,63 @@ abstract class Living extends Entity implements Damageable{
|
||||
public function getDrops(){
|
||||
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 = [];
|
||||
$itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance);
|
||||
|
||||
while($itr->valid()){
|
||||
$itr->next();
|
||||
$block = $itr->current();
|
||||
$blocks[] = $block;
|
||||
|
||||
if($maxLength !== 0 and count($blocks) > $maxLength){
|
||||
array_shift($blocks);
|
||||
}
|
||||
|
||||
$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,139 @@
|
||||
namespace pocketmine\entity;
|
||||
|
||||
|
||||
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\nbt\tag\String;
|
||||
use pocketmine\network\protocol\AddEntityPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\Player;
|
||||
|
||||
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(){
|
||||
$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 and $this->motionY == 0 and $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);
|
||||
}
|
||||
}
|
@ -21,9 +21,10 @@
|
||||
|
||||
namespace pocketmine\entity;
|
||||
|
||||
use pocketmine\nbt\tag\String;
|
||||
|
||||
class Skeleton extends Monster implements ProjectileSource{
|
||||
protected function initEntity(){
|
||||
$this->namedtag->id = new Skeleton("id", "Chicken");
|
||||
$this->namedtag->id = new String("id", "Chicken");
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ abstract class Event{
|
||||
throw new \BadMethodCallException("Event is not Cancellable");
|
||||
}
|
||||
|
||||
/** @var Event $this */
|
||||
return $this->isCancelled === true;
|
||||
}
|
||||
|
||||
@ -68,6 +69,8 @@ abstract class Event{
|
||||
if(!($this instanceof Cancellable)){
|
||||
throw new \BadMethodCallException("Event is not Cancellable");
|
||||
}
|
||||
|
||||
/** @var Event $this */
|
||||
$this->isCancelled = (bool) $value;
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ class TimingsHandler{
|
||||
if(PluginManager::$useTimings){
|
||||
foreach(self::$HANDLERS as $timings){
|
||||
if($timings->curTickTotal > 0.05){
|
||||
$timings->violations += ceil($timings->curTickTotal / 0.05);
|
||||
$timings->violations += round($timings->curTickTotal / 0.05);
|
||||
}
|
||||
$timings->curTickTotal = 0;
|
||||
$timings->timingDepth = 0;
|
||||
|
@ -34,7 +34,7 @@ abstract class BlockEvent extends Event{
|
||||
/**
|
||||
* @param Block $block
|
||||
*/
|
||||
protected function __construct(Block $block){
|
||||
public function __construct(Block $block){
|
||||
$this->block = $block;
|
||||
}
|
||||
|
||||
|
34
src/pocketmine/event/block/BlockFormEvent.php
Normal file
34
src/pocketmine/event/block/BlockFormEvent.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class BlockFormEvent extends BlockGrowEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
public function __construct(Block $block, Block $newState){
|
||||
parent::__construct($block, $newState);
|
||||
}
|
||||
|
||||
}
|
45
src/pocketmine/event/block/BlockGrowEvent.php
Normal file
45
src/pocketmine/event/block/BlockGrowEvent.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class BlockGrowEvent extends BlockEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
/** @var Block */
|
||||
private $newState;
|
||||
|
||||
public function __construct(Block $block, Block $newState){
|
||||
parent::__construct($block);
|
||||
$this->newState = $newState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getNewState(){
|
||||
return $this->newState;
|
||||
}
|
||||
|
||||
}
|
45
src/pocketmine/event/block/BlockSpreadEvent.php
Normal file
45
src/pocketmine/event/block/BlockSpreadEvent.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class BlockSpreadEvent extends BlockFormEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
/** @var Block */
|
||||
private $source;
|
||||
|
||||
public function __construct(Block $block, Block $source, Block $newState){
|
||||
parent::__construct($block, $newState);
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getSource(){
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
}
|
34
src/pocketmine/event/block/BlockUpdateEvent.php
Normal file
34
src/pocketmine/event/block/BlockUpdateEvent.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Player;
|
||||
|
||||
/**
|
||||
* Called when a block tries to be updated due to a neighbor change
|
||||
*/
|
||||
class BlockUpdateEvent extends BlockEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
}
|
34
src/pocketmine/event/block/LeavesDecayEvent.php
Normal file
34
src/pocketmine/event/block/LeavesDecayEvent.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class LeavesDecayEvent extends BlockEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
public function __construct(Block $block){
|
||||
parent::__construct($block);
|
||||
}
|
||||
|
||||
}
|
@ -22,8 +22,8 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class EntityArmorChangeEvent extends EntityEvent implements Cancellable{
|
||||
|
57
src/pocketmine/event/entity/EntityBlockChangeEvent.php
Normal file
57
src/pocketmine/event/entity/EntityBlockChangeEvent.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
/**
|
||||
* Called when an Entity, excluding players, changes a block directly
|
||||
*/
|
||||
class EntityBlockChangeEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
private $from;
|
||||
private $to;
|
||||
|
||||
public function __construct(Entity $entity, Block $from, Block $to){
|
||||
$this->entity = $entity;
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getBlock(){
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getTo(){
|
||||
return $this->to;
|
||||
}
|
||||
|
||||
}
|
48
src/pocketmine/event/entity/EntityCombustByBlockEvent.php
Normal file
48
src/pocketmine/event/entity/EntityCombustByBlockEvent.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?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\event\entity;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class EntityCombustByBlockEvent extends EntityCombustEvent{
|
||||
|
||||
protected $combuster;
|
||||
|
||||
/**
|
||||
* @param Block $combuster
|
||||
* @param Entity $combustee
|
||||
* @param int $duration
|
||||
*/
|
||||
public function __construct(Block $combuster, Entity $combustee, $duration){
|
||||
parent::__construct($combustee, $duration);
|
||||
$this->combuster = $combuster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getCombuster(){
|
||||
return $this->combuster;
|
||||
}
|
||||
|
||||
}
|
47
src/pocketmine/event/entity/EntityCombustByEntityEvent.php
Normal file
47
src/pocketmine/event/entity/EntityCombustByEntityEvent.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class EntityCombustByEntityEvent extends EntityCombustEvent{
|
||||
|
||||
protected $combuster;
|
||||
|
||||
/**
|
||||
* @param Entity $combuster
|
||||
* @param Entity $combustee
|
||||
* @param int $duration
|
||||
*/
|
||||
public function __construct(Entity $combuster, Entity $combustee, $duration){
|
||||
parent::__construct($combustee, $duration);
|
||||
$this->combuster = $combuster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Entity
|
||||
*/
|
||||
public function getCombuster(){
|
||||
return $this->combuster;
|
||||
}
|
||||
|
||||
}
|
49
src/pocketmine/event/entity/EntityCombustEvent.php
Normal file
49
src/pocketmine/event/entity/EntityCombustEvent.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?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\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class EntityCombustEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
protected $duration;
|
||||
|
||||
/**
|
||||
* @param Entity $combustee
|
||||
* @param int $duration
|
||||
*/
|
||||
public function __construct(Entity $combustee, $duration){
|
||||
$this->entity = $combustee;
|
||||
$this->duration = $duration;
|
||||
}
|
||||
|
||||
public function getDuration(){
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
public function setDuration($duration){
|
||||
$this->duration = (int) $duration;
|
||||
}
|
||||
|
||||
}
|
52
src/pocketmine/event/entity/EntityDamageByBlockEvent.php
Normal file
52
src/pocketmine/event/entity/EntityDamageByBlockEvent.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?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\event\entity;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\entity\Entity;
|
||||
|
||||
class EntityDamageByBlockEvent extends EntityDamageEvent{
|
||||
|
||||
/** @var Block */
|
||||
private $damager;
|
||||
|
||||
|
||||
/**
|
||||
* @param Block $damager
|
||||
* @param Entity $entity
|
||||
* @param int $cause
|
||||
* @param int|int[] $damage
|
||||
*/
|
||||
public function __construct(Block $damager, Entity $entity, $cause, $damage){
|
||||
$this->damager = $damager;
|
||||
parent::__construct($entity, $cause, $damage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
public function getDamager(){
|
||||
return $this->damager;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -34,19 +34,21 @@ use pocketmine\entity\Vehicle;
|
||||
class EntityDespawnEvent extends EntityEvent{
|
||||
public static $handlerList = null;
|
||||
|
||||
private $entityType;
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function __construct(Entity $entity){
|
||||
$this->entity = $entity;
|
||||
$this->entityType = $entity::NETWORK_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getType(){
|
||||
//TODO: implement Entity types
|
||||
return -1;
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,8 +22,8 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class EntityInventoryChangeEvent extends EntityEvent implements Cancellable{
|
||||
|
@ -22,8 +22,8 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\level\Level;
|
||||
|
||||
class EntityLevelChangeEvent extends EntityEvent implements Cancellable{
|
||||
|
@ -22,8 +22,8 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
|
||||
class EntityMotionEvent extends EntityEvent implements Cancellable{
|
||||
|
@ -22,10 +22,13 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\math\Vector3 as Vector3;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class EntityMoveEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
|
@ -27,18 +27,24 @@ use pocketmine\event\Cancellable;
|
||||
class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
//TODO: add cause
|
||||
const CAUSE_REGEN = 0;
|
||||
const CAUSE_EATING = 1;
|
||||
const CAUSE_MAGIC = 2;
|
||||
const CAUSE_CUSTOM = 3;
|
||||
|
||||
private $amount;
|
||||
private $reason;
|
||||
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
* @param float $amount
|
||||
* @param int $regainReason
|
||||
*/
|
||||
public function __construct(Entity $entity, $amount){
|
||||
public function __construct(Entity $entity, $amount, $regainReason){
|
||||
$this->entity = $entity;
|
||||
$this->amount = $amount;
|
||||
$this->reason = (int) $regainReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,4 +61,8 @@ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
|
||||
$this->amount = $amount;
|
||||
}
|
||||
|
||||
public function getRegainReason(){
|
||||
return $this->reason;
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\entity\Projectile;
|
||||
use pocketmine\event\Cancellable;
|
||||
@ -64,12 +65,25 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Projectile
|
||||
* @return Entity
|
||||
*/
|
||||
public function getProjectile(){
|
||||
return $this->projectile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity $projectile
|
||||
*/
|
||||
public function setProjectile(Entity $projectile){
|
||||
if($projectile !== $this->projectile){
|
||||
if(count($this->projectile->getViewers()) === 0){
|
||||
$this->projectile->kill();
|
||||
$this->projectile->close();
|
||||
}
|
||||
$this->projectile = $projectile;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
@ -77,5 +91,12 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{
|
||||
return $this->force;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $force
|
||||
*/
|
||||
public function setForce($force){
|
||||
$this->force = $force;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -34,11 +34,14 @@ use pocketmine\entity\Vehicle;
|
||||
class EntitySpawnEvent extends EntityEvent{
|
||||
public static $handlerList = null;
|
||||
|
||||
private $entityType;
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function __construct(Entity $entity){
|
||||
$this->entity = $entity;
|
||||
$this->entityType = $entity::NETWORK_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,8 +55,7 @@ class EntitySpawnEvent extends EntityEvent{
|
||||
* @return int
|
||||
*/
|
||||
public function getType(){
|
||||
//TODO: implement Entity types
|
||||
return -1;
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,8 +22,8 @@
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\level\Position;
|
||||
|
||||
class EntityTeleportEvent extends EntityEvent implements Cancellable{
|
||||
|
71
src/pocketmine/event/entity/ExplosionPrimeEvent.php
Normal file
71
src/pocketmine/event/entity/ExplosionPrimeEvent.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?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\event\entity;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
/**
|
||||
* Called when a entity decides to explode
|
||||
*/
|
||||
class ExplosionPrimeEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
protected $force;
|
||||
private $blockBreaking;
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
* @param float $force
|
||||
*/
|
||||
public function __construct(Entity $entity, $force){
|
||||
$this->entity = $entity;
|
||||
$this->force = $force;
|
||||
$this->blockBreaking = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getForce(){
|
||||
return $this->force;
|
||||
}
|
||||
|
||||
public function setForce($force){
|
||||
$this->force = (float) $force;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isBlockBreaking(){
|
||||
return $this->blockBreaking;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $affectsBlocks
|
||||
*/
|
||||
public function setBlockBreaking($affectsBlocks){
|
||||
$this->blockBreaking = (bool) $affectsBlocks;
|
||||
}
|
||||
|
||||
}
|
45
src/pocketmine/event/entity/ItemDespawnEvent.php
Normal file
45
src/pocketmine/event/entity/ItemDespawnEvent.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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\event\entity;
|
||||
|
||||
use pocketmine\entity\DroppedItem;
|
||||
use pocketmine\event\Cancellable;
|
||||
|
||||
class ItemDespawnEvent extends EntityEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
/**
|
||||
* @param DroppedItem $item
|
||||
*/
|
||||
public function __construct(DroppedItem $item){
|
||||
$this->entity = $item;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DroppedItem
|
||||
*/
|
||||
public function getEntity(){
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
}
|
44
src/pocketmine/event/entity/ItemSpawnEvent.php
Normal file
44
src/pocketmine/event/entity/ItemSpawnEvent.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\DroppedItem;
|
||||
|
||||
class ItemSpawnEvent extends EntityEvent{
|
||||
public static $handlerList = null;
|
||||
|
||||
/**
|
||||
* @param DroppedItem $item
|
||||
*/
|
||||
public function __construct(DroppedItem $item){
|
||||
$this->entity = $item;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DroppedItem
|
||||
*/
|
||||
public function getEntity(){
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
}
|
44
src/pocketmine/event/entity/ProjectileHitEvent.php
Normal file
44
src/pocketmine/event/entity/ProjectileHitEvent.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\entity;
|
||||
|
||||
use pocketmine\entity\Projectile;
|
||||
|
||||
class ProjectileHitEvent extends EntityEvent{
|
||||
public static $handlerList = null;
|
||||
|
||||
/**
|
||||
* @param Projectile $entity
|
||||
*/
|
||||
public function __construct(Projectile $entity){
|
||||
$this->entity = $entity;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Projectile
|
||||
*/
|
||||
public function getEntity(){
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user