mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-16 14:25:05 +00:00
Compare commits
79 Commits
Author | SHA1 | Date | |
---|---|---|---|
c38e2c5ccb | |||
02ef0bfbb4 | |||
4a6841a5a4 | |||
09985c5763 | |||
196cf8a68d | |||
45c9caa38c | |||
41fd03f329 | |||
0c9946621c | |||
1983964f9e | |||
c4c55a45c9 | |||
78923177f9 | |||
b7062e7bff | |||
97980d4516 | |||
d9220395d1 | |||
2858db430e | |||
32836cbfb8 | |||
8316e00927 | |||
fd459cda54 | |||
a66dd4a7d9 | |||
3617eba4a3 | |||
e79cc98883 | |||
d259b2c9ee | |||
10fa74b417 | |||
17ceb27af4 | |||
adbd1c7bed | |||
cf20e626e2 | |||
d75c830a7e | |||
722924a779 | |||
60e1b29462 | |||
5b511f6d06 | |||
426dee04a6 | |||
bb1944ca40 | |||
d1a20ecb4a | |||
f6a8ec83a1 | |||
28137efb53 | |||
7b0836d399 | |||
cea146e335 | |||
8db1ccc1ae | |||
5d56030afa | |||
d9c251b613 | |||
8085b81f5c | |||
33d3fff3c5 | |||
7c092b93b4 | |||
aa05650994 | |||
758d9b9784 | |||
24a6bf7365 | |||
9a5d51fd3d | |||
6a7f39978b | |||
c52e1ea9f9 | |||
a0bb747d6d | |||
4bc0d850b1 | |||
97583c8b04 | |||
107192c753 | |||
870f9abc20 | |||
0e2bbc44db | |||
d9768abe47 | |||
e9b84ecc8b | |||
c83d12790e | |||
5863d4c066 | |||
7d54d18732 | |||
bfbc845efa | |||
2ff4228fb7 | |||
06c4f31db7 | |||
6c70e84fa2 | |||
7d0e631a75 | |||
65b751d080 | |||
27effff403 | |||
a940cc5b5e | |||
15e654131c | |||
6e6cda91ce | |||
53a76c0d14 | |||
69500fe183 | |||
5af4dd20df | |||
c7d58db7eb | |||
a3b78236eb | |||
d8e27e6081 | |||
14a2ffa51b | |||
c447d51e3f | |||
9f4722f537 |
22
composer.lock
generated
22
composer.lock
generated
@ -76,16 +76,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/nbt",
|
"name": "pocketmine/nbt",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/NBT.git",
|
"url": "https://github.com/pmmp/NBT.git",
|
||||||
"reference": "a4ee39f313c6870153fb7c7e513b211217f7daf8"
|
"reference": "474f0cf0a47656d0122b4f3f71302e694ed6977b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/a4ee39f313c6870153fb7c7e513b211217f7daf8",
|
"url": "https://api.github.com/repos/pmmp/NBT/zipball/474f0cf0a47656d0122b4f3f71302e694ed6977b",
|
||||||
"reference": "a4ee39f313c6870153fb7c7e513b211217f7daf8",
|
"reference": "474f0cf0a47656d0122b4f3f71302e694ed6977b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -109,10 +109,10 @@
|
|||||||
],
|
],
|
||||||
"description": "PHP library for working with Named Binary Tags",
|
"description": "PHP library for working with Named Binary Tags",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/pmmp/NBT/tree/0.2.1",
|
"source": "https://github.com/pmmp/NBT/tree/0.2.2",
|
||||||
"issues": "https://github.com/pmmp/NBT/issues"
|
"issues": "https://github.com/pmmp/NBT/issues"
|
||||||
},
|
},
|
||||||
"time": "2018-09-04T10:36:02+00:00"
|
"time": "2018-10-12T08:26:44+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/raklib",
|
"name": "pocketmine/raklib",
|
||||||
@ -191,16 +191,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/spl",
|
"name": "pocketmine/spl",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/SPL.git",
|
"url": "https://github.com/pmmp/SPL.git",
|
||||||
"reference": "ca3912099543ddc4b4b14f40e258d84ca547dfa5"
|
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/SPL/zipball/ca3912099543ddc4b4b14f40e258d84ca547dfa5",
|
"url": "https://api.github.com/repos/pmmp/SPL/zipball/7fd53857cd000491ba69e8db865792a024dd2c49",
|
||||||
"reference": "ca3912099543ddc4b4b14f40e258d84ca547dfa5",
|
"reference": "7fd53857cd000491ba69e8db865792a024dd2c49",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -219,7 +219,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/pmmp/SPL/tree/master"
|
"source": "https://github.com/pmmp/SPL/tree/master"
|
||||||
},
|
},
|
||||||
"time": "2018-06-09T17:30:36+00:00"
|
"time": "2018-08-12T15:17:39+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [],
|
"packages-dev": [],
|
||||||
|
@ -212,11 +212,11 @@ class CrashDump{
|
|||||||
$this->addLine("Code:");
|
$this->addLine("Code:");
|
||||||
$this->data["code"] = [];
|
$this->data["code"] = [];
|
||||||
|
|
||||||
if($this->server->getProperty("auto-report.send-code", true) !== false){
|
if($this->server->getProperty("auto-report.send-code", true) !== false and file_exists($error["fullFile"])){
|
||||||
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
|
||||||
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10; ++$l){
|
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){
|
||||||
$this->addLine("[" . ($l + 1) . "] " . @$file[$l]);
|
$this->addLine("[" . ($l + 1) . "] " . $file[$l]);
|
||||||
$this->data["code"][$l + 1] = @$file[$l];
|
$this->data["code"][$l + 1] = $file[$l];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ class MemoryManager{
|
|||||||
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
self::continueDump($value, $data[$key], $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize);
|
||||||
}
|
}
|
||||||
}elseif(is_string($from)){
|
}elseif(is_string($from)){
|
||||||
$data = "(string) len(". strlen($from) .") " . substr(Utils::printable($from), 0, $maxStringSize);
|
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||||
}elseif(is_resource($from)){
|
}elseif(is_resource($from)){
|
||||||
$data = "(resource) " . print_r($from, true);
|
$data = "(resource) " . print_r($from, true);
|
||||||
}else{
|
}else{
|
||||||
|
@ -173,6 +173,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks a supplied username and checks it is valid.
|
* Checks a supplied username and checks it is valid.
|
||||||
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -1326,6 +1327,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
* TODO: remove this when Spectator Mode gets added properly to MCPE
|
* TODO: remove this when Spectator Mode gets added properly to MCPE
|
||||||
*
|
*
|
||||||
* @param int $gamemode
|
* @param int $gamemode
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getClientFriendlyGamemode(int $gamemode) : int{
|
public static function getClientFriendlyGamemode(int $gamemode) : int{
|
||||||
@ -2266,6 +2268,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
* Don't expect much from this handler. Most of it is roughly hacked and duct-taped together.
|
* Don't expect much from this handler. Most of it is roughly hacked and duct-taped together.
|
||||||
*
|
*
|
||||||
* @param InventoryTransactionPacket $packet
|
* @param InventoryTransactionPacket $packet
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
|
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
|
||||||
@ -2721,7 +2724,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
|
|
||||||
$target = $this->level->getBlock($pos);
|
$target = $this->level->getBlock($pos);
|
||||||
|
|
||||||
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $packet->face, $target->getId() === 0 ? PlayerInteractEvent::LEFT_CLICK_AIR : PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $target, null, $packet->face, PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||||
if($this->level->checkSpawnProtection($this, $target)){
|
if($this->level->checkSpawnProtection($this, $target)){
|
||||||
$ev->setCancelled();
|
$ev->setCancelled();
|
||||||
}
|
}
|
||||||
@ -2785,7 +2788,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
break; //TODO
|
break; //TODO
|
||||||
case PlayerActionPacket::ACTION_CONTINUE_BREAK:
|
case PlayerActionPacket::ACTION_CONTINUE_BREAK:
|
||||||
$block = $this->level->getBlock($pos);
|
$block = $this->level->getBlock($pos);
|
||||||
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_PARTICLE_PUNCH_BLOCK, BlockFactory::toStaticRuntimeId($block->getId(), $block->getDamage()) | ($packet->face << 24));
|
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_PARTICLE_PUNCH_BLOCK, $block->getRuntimeId() | ($packet->face << 24));
|
||||||
//TODO: destroy-progress level event
|
//TODO: destroy-progress level event
|
||||||
break;
|
break;
|
||||||
case PlayerActionPacket::ACTION_START_SWIMMING:
|
case PlayerActionPacket::ACTION_START_SWIMMING:
|
||||||
@ -2845,6 +2848,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
* Drops an item on the ground in front of the player. Returns if the item drop was successful.
|
* Drops an item on the ground in front of the player. Returns if the item drop was successful.
|
||||||
*
|
*
|
||||||
* @param Item $item
|
* @param Item $item
|
||||||
|
*
|
||||||
* @return bool if the item was dropped or if the item was null
|
* @return bool if the item was dropped or if the item was null
|
||||||
*/
|
*/
|
||||||
public function dropItem(Item $item) : bool{
|
public function dropItem(Item $item) : bool{
|
||||||
@ -3365,6 +3369,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
$pk = new ModalFormRequestPacket();
|
$pk = new ModalFormRequestPacket();
|
||||||
$pk->formId = $id;
|
$pk->formId = $id;
|
||||||
$pk->formData = json_encode($form);
|
$pk->formData = json_encode($form);
|
||||||
|
if($pk->formData === false){
|
||||||
|
throw new \InvalidArgumentException("Failed to encode form JSON: " . json_last_error_msg());
|
||||||
|
}
|
||||||
if($this->dataPacket($pk)){
|
if($this->dataPacket($pk)){
|
||||||
$this->forms[$id] = $form;
|
$this->forms[$id] = $form;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ namespace pocketmine {
|
|||||||
use pocketmine\wizard\SetupWizard;
|
use pocketmine\wizard\SetupWizard;
|
||||||
|
|
||||||
const NAME = "PocketMine-MP";
|
const NAME = "PocketMine-MP";
|
||||||
const BASE_VERSION = "3.2.2";
|
const BASE_VERSION = "3.2.6";
|
||||||
const IS_DEVELOPMENT_BUILD = false;
|
const IS_DEVELOPMENT_BUILD = false;
|
||||||
const BUILD_NUMBER = 0;
|
const BUILD_NUMBER = 0;
|
||||||
|
|
||||||
@ -145,12 +145,18 @@ namespace pocketmine {
|
|||||||
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
define('pocketmine\PATH', dirname(__FILE__, 3) . DIRECTORY_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', \pocketmine\PATH . 'vendor/autoload.php');
|
$opts = getopt("", ["bootstrap:"]);
|
||||||
|
if(isset($opts["bootstrap"])){
|
||||||
|
$bootstrap = realpath($opts["bootstrap"]) ?: $opts["bootstrap"];
|
||||||
|
}else{
|
||||||
|
$bootstrap = \pocketmine\PATH . 'vendor/autoload.php';
|
||||||
|
}
|
||||||
|
define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap);
|
||||||
|
|
||||||
if(is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
if(\pocketmine\COMPOSER_AUTOLOADER_PATH !== false and is_file(\pocketmine\COMPOSER_AUTOLOADER_PATH)){
|
||||||
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||||
}else{
|
}else{
|
||||||
critical_error("Composer autoloader not found.");
|
critical_error("Composer autoloader not found at " . $bootstrap);
|
||||||
critical_error("Please install/update Composer dependencies or use provided builds.");
|
critical_error("Please install/update Composer dependencies or use provided builds.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -991,6 +991,7 @@ class Server{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @param Level $level
|
* @param Level $level
|
||||||
*/
|
*/
|
||||||
public function removeLevel(Level $level) : void{
|
public function removeLevel(Level $level) : void{
|
||||||
@ -2195,6 +2196,14 @@ class Server{
|
|||||||
|
|
||||||
if($this->getProperty("auto-report.enabled", true) !== false){
|
if($this->getProperty("auto-report.enabled", true) !== false){
|
||||||
$report = true;
|
$report = true;
|
||||||
|
|
||||||
|
$stamp = $this->getDataPath() . "crashdumps/.last_crash";
|
||||||
|
$crashInterval = 120; //2 minutes
|
||||||
|
if(file_exists($stamp) and !($report = (filemtime($stamp) + $crashInterval < time()))){
|
||||||
|
$this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago");
|
||||||
|
}
|
||||||
|
@touch($stamp); //update file timestamp
|
||||||
|
|
||||||
$plugin = $dump->getData()["plugin"];
|
$plugin = $dump->getData()["plugin"];
|
||||||
if(is_string($plugin)){
|
if(is_string($plugin)){
|
||||||
$p = $this->pluginManager->getPlugin($plugin);
|
$p = $this->pluginManager->getPlugin($plugin);
|
||||||
@ -2348,11 +2357,15 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Do level ticks
|
//Do level ticks
|
||||||
foreach($this->getLevels() as $level){
|
foreach($this->levels as $k => $level){
|
||||||
|
if(!isset($this->levels[$k])){
|
||||||
|
// Level unloaded during the tick of a level earlier in this loop, perhaps by plugin
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if($level->getTickRate() > $this->baseTickRate and --$level->tickRateCounter > 0){
|
if($level->getTickRate() > $this->baseTickRate and --$level->tickRateCounter > 0){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try{
|
|
||||||
$levelTime = microtime(true);
|
$levelTime = microtime(true);
|
||||||
$level->doTick($currentTick);
|
$level->doTick($currentTick);
|
||||||
$tickMs = (microtime(true) - $levelTime) * 1000;
|
$tickMs = (microtime(true) - $levelTime) * 1000;
|
||||||
@ -2376,14 +2389,6 @@ class Server{
|
|||||||
$level->tickRateCounter = $level->getTickRate();
|
$level->tickRateCounter = $level->getTickRate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(\Throwable $e){
|
|
||||||
if(!$level->isClosed()){
|
|
||||||
$this->logger->critical($this->getLanguage()->translateString("pocketmine.level.tickError", [$level->getName(), $e->getMessage()]));
|
|
||||||
}else{
|
|
||||||
$this->logger->critical($this->getLanguage()->translateString("pocketmine.level.tickUnloadError", [$level->getName()]));
|
|
||||||
}
|
|
||||||
$this->logger->logException($e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,21 +192,25 @@ class Bed extends Transparent{
|
|||||||
|
|
||||||
public function getDropsForCompatibleTool(Item $item) : array{
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
if($this->isHeadPart()){
|
if($this->isHeadPart()){
|
||||||
$tile = $this->getLevel()->getTile($this);
|
return [$this->getItem()];
|
||||||
if($tile instanceof TileBed){
|
|
||||||
return [
|
|
||||||
ItemFactory::get($this->getItemId(), $tile->getColor())
|
|
||||||
];
|
|
||||||
}else{
|
|
||||||
return [
|
|
||||||
ItemFactory::get($this->getItemId(), 14) //Red
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return $this->getItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getItem() : Item{
|
||||||
|
$tile = $this->getLevel()->getTile($this);
|
||||||
|
if($tile instanceof TileBed){
|
||||||
|
return ItemFactory::get($this->getItemId(), $tile->getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ItemFactory::get($this->getItemId(), 14); //Red
|
||||||
|
}
|
||||||
|
|
||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,14 @@ class Block extends Position implements BlockIds, Metadatable{
|
|||||||
return $this->itemId ?? $this->getId();
|
return $this->itemId ?? $this->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRuntimeId() : int{
|
||||||
|
return BlockFactory::toStaticRuntimeId($this->getId(), $this->getDamage());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
@ -330,6 +330,10 @@ class BlockFactory{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isInit() : bool{
|
||||||
|
return self::$fullList !== null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a block type into the index. Plugins may use this method to register new block types or override
|
* Registers a block type into the index. Plugins may use this method to register new block types or override
|
||||||
* existing ones.
|
* existing ones.
|
||||||
@ -411,6 +415,7 @@ class BlockFactory{
|
|||||||
* Returns whether a specified block ID is already registered in the block factory.
|
* Returns whether a specified block ID is already registered in the block factory.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isRegistered(int $id) : bool{
|
public static function isRegistered(int $id) : bool{
|
||||||
|
@ -23,12 +23,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\TieredTool;
|
use pocketmine\item\TieredTool;
|
||||||
|
|
||||||
class BrewingStand extends Transparent{
|
class BrewingStand extends Transparent{
|
||||||
|
|
||||||
protected $id = self::BREWING_STAND_BLOCK;
|
protected $id = self::BREWING_STAND_BLOCK;
|
||||||
|
|
||||||
|
protected $itemId = Item::BREWING_STAND;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ class Cake extends Transparent implements FoodSource{
|
|||||||
|
|
||||||
protected $id = self::CAKE_BLOCK;
|
protected $id = self::CAKE_BLOCK;
|
||||||
|
|
||||||
|
protected $itemId = Item::CAKE;
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
$this->meta = $meta;
|
$this->meta = $meta;
|
||||||
}
|
}
|
||||||
|
@ -47,4 +47,8 @@ abstract class DoubleSlab extends Solid{
|
|||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get($this->getSlabId(), $this->getVariant());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,4 +111,8 @@ class Farmland extends Transparent{
|
|||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return ItemFactory::get(Item::DIRT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,8 @@ class RedstoneOre extends Solid{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onActivate(Item $item, Player $player = null) : bool{
|
public function onActivate(Item $item, Player $player = null) : bool{
|
||||||
return $this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
$this->getLevel()->setBlock($this, BlockFactory::get(Block::GLOWING_REDSTONE_ORE, $this->meta));
|
||||||
|
return false; //this shouldn't prevent block placement
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onNearbyBlockChange() : void{
|
public function onNearbyBlockChange() : void{
|
||||||
|
@ -71,18 +71,20 @@ class Skull extends Flowable{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDropsForCompatibleTool(Item $item) : array{
|
private function getItem() : Item{
|
||||||
$tile = $this->level->getTile($this);
|
$tile = $this->level->getTile($this);
|
||||||
if($tile instanceof TileSkull){
|
return ItemFactory::get(Item::SKULL, $tile instanceof TileSkull ? $tile->getType() : 0);
|
||||||
return [
|
|
||||||
ItemFactory::get(Item::SKULL, $tile->getType())
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
public function getDropsForCompatibleTool(Item $item) : array{
|
||||||
|
return [$this->getItem()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAffectedBySilkTouch() : bool{
|
public function isAffectedBySilkTouch() : bool{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPickedItem() : Item{
|
||||||
|
return $this->getItem();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,11 +100,7 @@ abstract class Thin extends Transparent{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: currently there's no proper way to tell if a block is a full-block, so we check the bounding box size
|
//FIXME: currently there's no proper way to tell if a block is a full-block, so we check the bounding box size
|
||||||
$bbs = $block->getCollisionBoxes();
|
$bb = $block->getBoundingBox();
|
||||||
if(count($bbs) === 1){
|
return $bb !== null and $bb->getAverageEdgeLength() >= 1;
|
||||||
return $bbs[0]->getAverageEdgeLength() >= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class Torch extends Flowable{
|
|||||||
5 => Vector3::SIDE_DOWN
|
5 => Vector3::SIDE_DOWN
|
||||||
];
|
];
|
||||||
|
|
||||||
if($this->getSide($faces[$side])->isTransparent() and !($side === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
|
if($this->getSide($faces[$side])->isTransparent() and !($faces[$side] === Vector3::SIDE_DOWN and ($below->getId() === self::FENCE or $below->getId() === self::COBBLESTONE_WALL))){
|
||||||
$this->getLevel()->useBreakOn($this);
|
$this->getLevel()->useBreakOn($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine\command;
|
|||||||
|
|
||||||
use pocketmine\snooze\SleeperNotifier;
|
use pocketmine\snooze\SleeperNotifier;
|
||||||
use pocketmine\Thread;
|
use pocketmine\Thread;
|
||||||
|
use pocketmine\utils\Utils;
|
||||||
|
|
||||||
class CommandReader extends Thread{
|
class CommandReader extends Thread{
|
||||||
|
|
||||||
@ -47,9 +48,9 @@ class CommandReader extends Thread{
|
|||||||
$this->buffer = new \Threaded;
|
$this->buffer = new \Threaded;
|
||||||
$this->notifier = $notifier;
|
$this->notifier = $notifier;
|
||||||
|
|
||||||
$opts = getopt("", ["disable-readline"]);
|
$opts = getopt("", ["disable-readline", "enable-readline"]);
|
||||||
|
|
||||||
if(extension_loaded("readline") and !isset($opts["disable-readline"]) and !$this->isPipe(STDIN)){
|
if(extension_loaded("readline") and (Utils::getOS() === "win" ? isset($opts["enable-readline"]) : !isset($opts["disable-readline"])) and !$this->isPipe(STDIN)){
|
||||||
$this->type = self::TYPE_READLINE;
|
$this->type = self::TYPE_READLINE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,6 +95,7 @@ class CommandReader extends Thread{
|
|||||||
* Checks if the specified stream is a FIFO pipe.
|
* Checks if the specified stream is a FIFO pipe.
|
||||||
*
|
*
|
||||||
* @param resource $stream
|
* @param resource $stream
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function isPipe($stream) : bool{
|
private function isPipe($stream) : bool{
|
||||||
|
@ -54,6 +54,7 @@ interface CommandSender extends Permissible{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the line height used for command output pagination for this command sender. `null` will reset it to default.
|
* Sets the line height used for command output pagination for this command sender. `null` will reset it to default.
|
||||||
|
*
|
||||||
* @param int|null $height
|
* @param int|null $height
|
||||||
*/
|
*/
|
||||||
public function setScreenLineHeight(int $height = null);
|
public function setScreenLineHeight(int $height = null);
|
||||||
|
@ -144,6 +144,7 @@ class DataPropertyManager{
|
|||||||
public function getItem(int $key) : ?Item{
|
public function getItem(int $key) : ?Item{
|
||||||
$value = $this->getPropertyValue($key, Entity::DATA_TYPE_SLOT);
|
$value = $this->getPropertyValue($key, Entity::DATA_TYPE_SLOT);
|
||||||
assert($value instanceof Item or $value === null);
|
assert($value instanceof Item or $value === null);
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ class EffectInstance{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $duration
|
* @param int $duration
|
||||||
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
|
@ -342,7 +342,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
*
|
*
|
||||||
* @return CompoundTag
|
* @return CompoundTag
|
||||||
*/
|
*/
|
||||||
public static function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null , float $yaw = 0.0, float $pitch = 0.0) : CompoundTag{
|
public static function createBaseNBT(Vector3 $pos, ?Vector3 $motion = null, float $yaw = 0.0, float $pitch = 0.0) : CompoundTag{
|
||||||
return new CompoundTag("", [
|
return new CompoundTag("", [
|
||||||
new ListTag("Pos", [
|
new ListTag("Pos", [
|
||||||
new DoubleTag("", $pos->x),
|
new DoubleTag("", $pos->x),
|
||||||
@ -408,8 +408,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
public $boundingBox;
|
public $boundingBox;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
public $onGround;
|
public $onGround;
|
||||||
/** @var int */
|
|
||||||
protected $age = 0;
|
|
||||||
|
|
||||||
/** @var float */
|
/** @var float */
|
||||||
public $eyeHeight = null;
|
public $eyeHeight = null;
|
||||||
@ -934,6 +932,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
* Called to tick entities while dead. Returns whether the entity should be flagged for despawn yet.
|
* Called to tick entities while dead. Returns whether the entity should be flagged for despawn yet.
|
||||||
*
|
*
|
||||||
* @param int $tickDiff
|
* @param int $tickDiff
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function onDeathUpdate(int $tickDiff) : bool{
|
protected function onDeathUpdate(int $tickDiff) : bool{
|
||||||
@ -1041,7 +1040,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->age += $tickDiff;
|
|
||||||
$this->ticksLived += $tickDiff;
|
$this->ticksLived += $tickDiff;
|
||||||
|
|
||||||
return $hasUpdate;
|
return $hasUpdate;
|
||||||
@ -1393,7 +1391,6 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
Timings::$timerEntityBaseTick->stopTiming();
|
Timings::$timerEntityBaseTick->stopTiming();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->timings->stopTiming();
|
$this->timings->stopTiming();
|
||||||
|
|
||||||
//if($this->isStatic())
|
//if($this->isStatic())
|
||||||
@ -2074,6 +2071,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
|
|||||||
* Wrapper around {@link Entity#getDataFlag} for generic data flag reading.
|
* Wrapper around {@link Entity#getDataFlag} for generic data flag reading.
|
||||||
*
|
*
|
||||||
* @param int $flagId
|
* @param int $flagId
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getGenericFlag(int $flagId) : bool{
|
public function getGenericFlag(int $flagId) : bool{
|
||||||
|
@ -888,6 +888,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
* Wrapper around {@link Entity#getDataFlag} for player-specific data flag reading.
|
* Wrapper around {@link Entity#getDataFlag} for player-specific data flag reading.
|
||||||
*
|
*
|
||||||
* @param int $flagId
|
* @param int $flagId
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getPlayerFlag(int $flagId) : bool{
|
public function getPlayerFlag(int $flagId) : bool{
|
||||||
|
@ -329,6 +329,7 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the mob's potion effects to the specified player.
|
* Sends the mob's potion effects to the specified player.
|
||||||
|
*
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
*/
|
*/
|
||||||
public function sendPotionEffects(Player $player) : void{
|
public function sendPotionEffects(Player $player) : void{
|
||||||
@ -771,6 +772,7 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of air ticks left in the entity's air supply.
|
* Sets the number of air ticks left in the entity's air supply.
|
||||||
|
*
|
||||||
* @param int $ticks
|
* @param int $ticks
|
||||||
*/
|
*/
|
||||||
public function setAirSupplyTicks(int $ticks) : void{
|
public function setAirSupplyTicks(int $ticks) : void{
|
||||||
@ -787,6 +789,7 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum amount of air ticks the air supply can hold.
|
* Sets the maximum amount of air ticks the air supply can hold.
|
||||||
|
*
|
||||||
* @param int $ticks
|
* @param int $ticks
|
||||||
*/
|
*/
|
||||||
public function setMaxAirSupplyTicks(int $ticks) : void{
|
public function setMaxAirSupplyTicks(int $ticks) : void{
|
||||||
|
@ -88,6 +88,9 @@ class ExperienceOrb extends Entity{
|
|||||||
public $gravity = 0.04;
|
public $gravity = 0.04;
|
||||||
public $drag = 0.02;
|
public $drag = 0.02;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $age = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
* Ticker used for determining interval in which to look for new target players.
|
* Ticker used for determining interval in which to look for new target players.
|
||||||
@ -159,6 +162,7 @@ class ExperienceOrb extends Entity{
|
|||||||
public function entityBaseTick(int $tickDiff = 1) : bool{
|
public function entityBaseTick(int $tickDiff = 1) : bool{
|
||||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||||
|
|
||||||
|
$this->age += $tickDiff;
|
||||||
if($this->age > 6000){
|
if($this->age > 6000){
|
||||||
$this->flagForDespawn();
|
$this->flagForDespawn();
|
||||||
return true;
|
return true;
|
||||||
|
@ -71,7 +71,7 @@ class FallingBlock extends Entity{
|
|||||||
|
|
||||||
$this->block = BlockFactory::get($blockId, $damage);
|
$this->block = BlockFactory::get($blockId, $damage);
|
||||||
|
|
||||||
$this->propertyManager->setInt(self::DATA_VARIANT, BlockFactory::toStaticRuntimeId($this->block->getId(), $this->block->getDamage()));
|
$this->propertyManager->setInt(self::DATA_VARIANT, $this->block->getRuntimeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canCollideWith(Entity $entity) : bool{
|
public function canCollideWith(Entity $entity) : bool{
|
||||||
|
@ -53,6 +53,9 @@ class ItemEntity extends Entity{
|
|||||||
|
|
||||||
public $canCollide = false;
|
public $canCollide = false;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $age = 0;
|
||||||
|
|
||||||
protected function initEntity() : void{
|
protected function initEntity() : void{
|
||||||
parent::initEntity();
|
parent::initEntity();
|
||||||
|
|
||||||
@ -70,6 +73,9 @@ class ItemEntity extends Entity{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->item = Item::nbtDeserialize($itemTag);
|
$this->item = Item::nbtDeserialize($itemTag);
|
||||||
|
if($this->item->isNull()){
|
||||||
|
throw new \UnexpectedValueException("Item for " . get_class($this) . " is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
|
$this->server->getPluginManager()->callEvent(new ItemSpawnEvent($this));
|
||||||
@ -82,14 +88,13 @@ class ItemEntity extends Entity{
|
|||||||
|
|
||||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||||
|
|
||||||
if(!$this->isFlaggedForDespawn()){
|
if(!$this->isFlaggedForDespawn() and $this->pickupDelay > -1 and $this->pickupDelay < 32767){ //Infinite delay
|
||||||
if($this->pickupDelay > 0 and $this->pickupDelay < 32767){ //Infinite delay
|
|
||||||
$this->pickupDelay -= $tickDiff;
|
$this->pickupDelay -= $tickDiff;
|
||||||
if($this->pickupDelay < 0){
|
if($this->pickupDelay < 0){
|
||||||
$this->pickupDelay = 0;
|
$this->pickupDelay = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
$this->age += $tickDiff;
|
||||||
if($this->age > 6000){
|
if($this->age > 6000){
|
||||||
$this->server->getPluginManager()->callEvent($ev = new ItemDespawnEvent($this));
|
$this->server->getPluginManager()->callEvent($ev = new ItemDespawnEvent($this));
|
||||||
if($ev->isCancelled()){
|
if($ev->isCancelled()){
|
||||||
@ -99,7 +104,6 @@ class ItemEntity extends Entity{
|
|||||||
$hasUpdate = true;
|
$hasUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hasUpdate;
|
return $hasUpdate;
|
||||||
|
@ -73,6 +73,7 @@ class PaintingMotive{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
* @return PaintingMotive|null
|
* @return PaintingMotive|null
|
||||||
*/
|
*/
|
||||||
public static function getMotiveByName(string $name) : ?PaintingMotive{
|
public static function getMotiveByName(string $name) : ?PaintingMotive{
|
||||||
|
@ -61,6 +61,9 @@ class Arrow extends Projectile{
|
|||||||
/** @var float */
|
/** @var float */
|
||||||
protected $punchKnockback = 0.0;
|
protected $punchKnockback = 0.0;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $collideTicks = 0;
|
||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){
|
public function __construct(Level $level, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){
|
||||||
parent::__construct($level, $nbt, $shootingEntity);
|
parent::__construct($level, $nbt, $shootingEntity);
|
||||||
$this->setCritical($critical);
|
$this->setCritical($critical);
|
||||||
@ -70,12 +73,14 @@ class Arrow extends Projectile{
|
|||||||
parent::initEntity();
|
parent::initEntity();
|
||||||
|
|
||||||
$this->pickupMode = $this->namedtag->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true);
|
$this->pickupMode = $this->namedtag->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true);
|
||||||
|
$this->collideTicks = $this->namedtag->getShort("life", $this->collideTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveNBT() : void{
|
public function saveNBT() : void{
|
||||||
parent::saveNBT();
|
parent::saveNBT();
|
||||||
|
|
||||||
$this->namedtag->setByte(self::TAG_PICKUP, $this->pickupMode, true);
|
$this->namedtag->setByte(self::TAG_PICKUP, $this->pickupMode, true);
|
||||||
|
$this->namedtag->setShort("life", $this->collideTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isCritical() : bool{
|
public function isCritical() : bool{
|
||||||
@ -116,10 +121,15 @@ class Arrow extends Projectile{
|
|||||||
|
|
||||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||||
|
|
||||||
if($this->age > 1200){
|
if($this->isCollided){
|
||||||
|
$this->collideTicks += $tickDiff;
|
||||||
|
if($this->collideTicks > 1200){
|
||||||
$this->flagForDespawn();
|
$this->flagForDespawn();
|
||||||
$hasUpdate = true;
|
$hasUpdate = true;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
$this->collideTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return $hasUpdate;
|
return $hasUpdate;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,5 @@ class EnderPearl extends Throwable{
|
|||||||
|
|
||||||
$owner->attack(new EntityDamageEvent($owner, EntityDamageEvent::CAUSE_FALL, 5));
|
$owner->attack(new EntityDamageEvent($owner, EntityDamageEvent::CAUSE_FALL, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->flagForDespawn();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,5 @@ class ExperienceBottle extends Throwable{
|
|||||||
$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_GLASS);
|
$this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_GLASS);
|
||||||
|
|
||||||
$this->level->dropExperience($this, mt_rand(3, 11));
|
$this->level->dropExperience($this, mt_rand(3, 11));
|
||||||
|
|
||||||
$this->flagForDespawn();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,6 @@ abstract class Projectile extends Entity{
|
|||||||
|
|
||||||
$this->setMaxHealth(1);
|
$this->setMaxHealth(1);
|
||||||
$this->setHealth(1);
|
$this->setHealth(1);
|
||||||
$this->age = $this->namedtag->getShort("Age", $this->age);
|
|
||||||
$this->damage = $this->namedtag->getDouble("damage", $this->damage);
|
$this->damage = $this->namedtag->getDouble("damage", $this->damage);
|
||||||
|
|
||||||
do{
|
do{
|
||||||
@ -144,7 +143,6 @@ abstract class Projectile extends Entity{
|
|||||||
public function saveNBT() : void{
|
public function saveNBT() : void{
|
||||||
parent::saveNBT();
|
parent::saveNBT();
|
||||||
|
|
||||||
$this->namedtag->setShort("Age", $this->age);
|
|
||||||
$this->namedtag->setDouble("damage", $this->damage);
|
$this->namedtag->setDouble("damage", $this->damage);
|
||||||
|
|
||||||
if($this->blockHit !== null){
|
if($this->blockHit !== null){
|
||||||
|
@ -27,8 +27,8 @@ use pocketmine\block\Block;
|
|||||||
use pocketmine\block\BlockFactory;
|
use pocketmine\block\BlockFactory;
|
||||||
use pocketmine\entity\EffectInstance;
|
use pocketmine\entity\EffectInstance;
|
||||||
use pocketmine\entity\Living;
|
use pocketmine\entity\Living;
|
||||||
use pocketmine\event\entity\ProjectileHitEntityEvent;
|
|
||||||
use pocketmine\event\entity\ProjectileHitBlockEvent;
|
use pocketmine\event\entity\ProjectileHitBlockEvent;
|
||||||
|
use pocketmine\event\entity\ProjectileHitEntityEvent;
|
||||||
use pocketmine\event\entity\ProjectileHitEvent;
|
use pocketmine\event\entity\ProjectileHitEvent;
|
||||||
use pocketmine\item\Potion;
|
use pocketmine\item\Potion;
|
||||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||||
@ -124,8 +124,6 @@ class SplashPotion extends Throwable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->flagForDespawn();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,6 +151,7 @@ class SplashPotion extends Throwable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether this splash potion will create an area-effect-cloud when it lands.
|
* Sets whether this splash potion will create an area-effect-cloud when it lands.
|
||||||
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*/
|
*/
|
||||||
public function setLinger(bool $value = true) : void{
|
public function setLinger(bool $value = true) : void{
|
||||||
|
@ -23,6 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\entity\projectile;
|
namespace pocketmine\entity\projectile;
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\math\RayTraceResult;
|
||||||
|
|
||||||
abstract class Throwable extends Projectile{
|
abstract class Throwable extends Projectile{
|
||||||
|
|
||||||
public $width = 0.25;
|
public $width = 0.25;
|
||||||
@ -31,18 +34,8 @@ abstract class Throwable extends Projectile{
|
|||||||
protected $gravity = 0.03;
|
protected $gravity = 0.03;
|
||||||
protected $drag = 0.01;
|
protected $drag = 0.01;
|
||||||
|
|
||||||
public function entityBaseTick(int $tickDiff = 1) : bool{
|
protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{
|
||||||
if($this->closed){
|
parent::onHitBlock($blockHit, $hitResult);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
|
||||||
|
|
||||||
if($this->age > 1200 or $this->isCollided){
|
|
||||||
$this->flagForDespawn();
|
$this->flagForDespawn();
|
||||||
$hasUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hasUpdate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ abstract class ExperienceUtils{
|
|||||||
* Calculates and returns the amount of XP needed to get from level 0 to level $level
|
* Calculates and returns the amount of XP needed to get from level 0 to level $level
|
||||||
*
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getXpToReachLevel(int $level) : int{
|
public static function getXpToReachLevel(int $level) : int{
|
||||||
|
@ -63,6 +63,7 @@ class PlayerChangeSkinEvent extends PlayerEvent implements Cancellable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Skin $skin
|
* @param Skin $skin
|
||||||
|
*
|
||||||
* @throws \InvalidArgumentException if the specified skin is not valid
|
* @throws \InvalidArgumentException if the specified skin is not valid
|
||||||
*/
|
*/
|
||||||
public function setNewSkin(Skin $skin) : void{
|
public function setNewSkin(Skin $skin) : void{
|
||||||
|
@ -384,6 +384,7 @@ abstract class BaseInventory implements Inventory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the inventory window from all players currently viewing it.
|
* Removes the inventory window from all players currently viewing it.
|
||||||
|
*
|
||||||
* @param bool $force Force removal of permanent windows such as the player's own inventory. Used internally.
|
* @param bool $force Force removal of permanent windows such as the player's own inventory. Used internally.
|
||||||
*/
|
*/
|
||||||
public function removeAllViewers(bool $force = false) : void{
|
public function removeAllViewers(bool $force = false) : void{
|
||||||
|
@ -244,6 +244,7 @@ interface Inventory{
|
|||||||
* Returns whether the specified slot exists in the inventory.
|
* Returns whether the specified slot exists in the inventory.
|
||||||
*
|
*
|
||||||
* @param int $slot
|
* @param int $slot
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function slotExists(int $slot) : bool;
|
public function slotExists(int $slot) : bool;
|
||||||
|
@ -87,6 +87,7 @@ class PlayerInventory extends BaseInventory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $slot
|
* @param int $slot
|
||||||
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
private function throwIfNotHotbarSlot(int $slot){
|
private function throwIfNotHotbarSlot(int $slot){
|
||||||
@ -99,6 +100,7 @@ class PlayerInventory extends BaseInventory{
|
|||||||
* Returns the item in the specified hotbar slot.
|
* Returns the item in the specified hotbar slot.
|
||||||
*
|
*
|
||||||
* @param int $hotbarSlot
|
* @param int $hotbarSlot
|
||||||
|
*
|
||||||
* @return Item
|
* @return Item
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if the hotbar slot index is out of range
|
* @throws \InvalidArgumentException if the hotbar slot index is out of range
|
||||||
@ -159,6 +161,7 @@ class PlayerInventory extends BaseInventory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the currently-held item to specified targets.
|
* Sends the currently-held item to specified targets.
|
||||||
|
*
|
||||||
* @param Player|Player[] $target
|
* @param Player|Player[] $target
|
||||||
*/
|
*/
|
||||||
public function sendHeldItem($target){
|
public function sendHeldItem($target){
|
||||||
|
@ -54,6 +54,7 @@ class DropItemAction extends InventoryAction{
|
|||||||
* Drops the target item in front of the player.
|
* Drops the target item in front of the player.
|
||||||
*
|
*
|
||||||
* @param Player $source
|
* @param Player $source
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function execute(Player $source) : bool{
|
public function execute(Player $source) : bool{
|
||||||
|
@ -53,6 +53,7 @@ abstract class Armor extends Durable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the dyed colour of this armour piece. This generally only applies to leather armour.
|
* Sets the dyed colour of this armour piece. This generally only applies to leather armour.
|
||||||
|
*
|
||||||
* @param Color $color
|
* @param Color $color
|
||||||
*/
|
*/
|
||||||
public function setCustomColor(Color $color) : void{
|
public function setCustomColor(Color $color) : void{
|
||||||
|
@ -79,7 +79,7 @@ class Bow extends Tool{
|
|||||||
$entity->setBaseDamage($entity->getBaseDamage() + (($powerLevel + 1) / 2));
|
$entity->setBaseDamage($entity->getBaseDamage() + (($powerLevel + 1) / 2));
|
||||||
}
|
}
|
||||||
if($this->hasEnchantment(Enchantment::FLAME)){
|
if($this->hasEnchantment(Enchantment::FLAME)){
|
||||||
$entity->setOnFire($entity->getFireTicks() * 20 + 100);
|
$entity->setOnFire(intdiv($entity->getFireTicks(), 20) + 100);
|
||||||
}
|
}
|
||||||
$ev = new EntityShootBowEvent($player, $this, $entity, $force);
|
$ev = new EntityShootBowEvent($player, $this, $entity, $force);
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@ class Bucket extends Item implements Consumable{
|
|||||||
if($blockClicked instanceof Liquid and $blockClicked->getDamage() === 0){
|
if($blockClicked instanceof Liquid and $blockClicked->getDamage() === 0){
|
||||||
$stack = clone $this;
|
$stack = clone $this;
|
||||||
|
|
||||||
$resultItem = $stack->pop();
|
$stack->pop();
|
||||||
$resultItem->setDamage($blockClicked->getFlowingForm()->getId());
|
$resultItem = ItemFactory::get(Item::BUCKET, $blockClicked->getFlowingForm()->getId());
|
||||||
$player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem));
|
$player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem));
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$player->getLevel()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true);
|
$player->getLevel()->setBlock($blockClicked, BlockFactory::get(Block::AIR), true, true);
|
||||||
@ -80,9 +80,7 @@ class Bucket extends Item implements Consumable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}elseif($resultBlock instanceof Liquid and $blockReplace->canBeReplaced()){
|
}elseif($resultBlock instanceof Liquid and $blockReplace->canBeReplaced()){
|
||||||
$resultItem = clone $this;
|
$player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, ItemFactory::get(Item::BUCKET)));
|
||||||
$resultItem->setDamage(0);
|
|
||||||
$player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, $resultItem));
|
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
|
$player->getLevel()->setBlock($blockReplace, $resultBlock->getFlowingForm(), true, true);
|
||||||
$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
|
$player->getLevel()->broadcastLevelSoundEvent($blockClicked->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
|
||||||
|
@ -47,17 +47,17 @@ class ChorusFruit extends Food{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onConsume(Living $consumer){
|
public function onConsume(Living $consumer){
|
||||||
|
$level = $consumer->getLevel();
|
||||||
|
assert($level !== null);
|
||||||
|
|
||||||
$minX = $consumer->getFloorX() - 8;
|
$minX = $consumer->getFloorX() - 8;
|
||||||
$minY = $consumer->getFloorY() - 8;
|
$minY = min($consumer->getFloorY(), $consumer->getLevel()->getWorldHeight()) - 8;
|
||||||
$minZ = $consumer->getFloorZ() - 8;
|
$minZ = $consumer->getFloorZ() - 8;
|
||||||
|
|
||||||
$maxX = $minX + 16;
|
$maxX = $minX + 16;
|
||||||
$maxY = $minY + 16;
|
$maxY = $minY + 16;
|
||||||
$maxZ = $minZ + 16;
|
$maxZ = $minZ + 16;
|
||||||
|
|
||||||
$level = $consumer->getLevel();
|
|
||||||
assert($level !== null);
|
|
||||||
|
|
||||||
for($attempts = 0; $attempts < 16; ++$attempts){
|
for($attempts = 0; $attempts < 16; ++$attempts){
|
||||||
$x = mt_rand($minX, $maxX);
|
$x = mt_rand($minX, $maxX);
|
||||||
$y = mt_rand($minY, $maxY);
|
$y = mt_rand($minY, $maxY);
|
||||||
|
@ -38,6 +38,7 @@ abstract class Durable extends Item{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the item will take damage when used.
|
* Sets whether the item will take damage when used.
|
||||||
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*/
|
*/
|
||||||
public function setUnbreakable(bool $value = true){
|
public function setUnbreakable(bool $value = true){
|
||||||
@ -46,6 +47,7 @@ abstract class Durable extends Item{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies damage to the item.
|
* Applies damage to the item.
|
||||||
|
*
|
||||||
* @param int $amount
|
* @param int $amount
|
||||||
*
|
*
|
||||||
* @return bool if any damage was applied to the item
|
* @return bool if any damage was applied to the item
|
||||||
|
@ -523,6 +523,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
* @return NamedTag|null
|
* @return NamedTag|null
|
||||||
*/
|
*/
|
||||||
public function getNamedTagEntry(string $name) : ?NamedTag{
|
public function getNamedTagEntry(string $name) : ?NamedTag{
|
||||||
@ -557,6 +558,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the Item's NBT from the supplied CompoundTag object.
|
* Sets the Item's NBT from the supplied CompoundTag object.
|
||||||
|
*
|
||||||
* @param CompoundTag $tag
|
* @param CompoundTag $tag
|
||||||
*
|
*
|
||||||
* @return Item
|
* @return Item
|
||||||
@ -589,6 +591,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $count
|
* @param int $count
|
||||||
|
*
|
||||||
* @return Item
|
* @return Item
|
||||||
*/
|
*/
|
||||||
public function setCount(int $count) : Item{
|
public function setCount(int $count) : Item{
|
||||||
@ -669,6 +672,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $meta
|
* @param int $meta
|
||||||
|
*
|
||||||
* @return Item
|
* @return Item
|
||||||
*/
|
*/
|
||||||
public function setDamage(int $meta) : Item{
|
public function setDamage(int $meta) : Item{
|
||||||
@ -779,6 +783,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
* Returns whether the item was changed, for example count decrease or durability change.
|
* Returns whether the item was changed, for example count decrease or durability change.
|
||||||
*
|
*
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function onReleaseUsing(Player $player) : bool{
|
public function onReleaseUsing(Player $player) : bool{
|
||||||
@ -844,6 +849,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack.
|
* Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack.
|
||||||
|
*
|
||||||
* @param Item $other
|
* @param Item $other
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -888,6 +894,7 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
* Returns an Item from properties created in an array by {@link Item#jsonSerialize}
|
* Returns an Item from properties created in an array by {@link Item#jsonSerialize}
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return Item
|
* @return Item
|
||||||
*/
|
*/
|
||||||
final public static function jsonDeserialize(array $data) : Item{
|
final public static function jsonDeserialize(array $data) : Item{
|
||||||
@ -956,7 +963,12 @@ class Item implements ItemIds, \JsonSerializable{
|
|||||||
if($idTag instanceof ShortTag){
|
if($idTag instanceof ShortTag){
|
||||||
$item = ItemFactory::get($idTag->getValue(), $meta, $count);
|
$item = ItemFactory::get($idTag->getValue(), $meta, $count);
|
||||||
}elseif($idTag instanceof StringTag){ //PC item save format
|
}elseif($idTag instanceof StringTag){ //PC item save format
|
||||||
|
try{
|
||||||
$item = ItemFactory::fromString($idTag->getValue());
|
$item = ItemFactory::fromString($idTag->getValue());
|
||||||
|
}catch(\InvalidArgumentException $e){
|
||||||
|
//TODO: improve error handling
|
||||||
|
return ItemFactory::get(Item::AIR, 0, 0);
|
||||||
|
}
|
||||||
$item->setDamage($meta);
|
$item->setDamage($meta);
|
||||||
$item->setCount($count);
|
$item->setCount($count);
|
||||||
}else{
|
}else{
|
||||||
|
@ -71,9 +71,8 @@ class Potion extends Item implements Consumable{
|
|||||||
* Returns a list of effects applied by potions with the specified ID.
|
* Returns a list of effects applied by potions with the specified ID.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return EffectInstance[]
|
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if the potion type is unknown
|
* @return EffectInstance[]
|
||||||
*/
|
*/
|
||||||
public static function getPotionEffectsById(int $id) : array{
|
public static function getPotionEffectsById(int $id) : array{
|
||||||
switch($id){
|
switch($id){
|
||||||
@ -213,7 +212,7 @@ class Potion extends Item implements Consumable{
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \InvalidArgumentException("Unknown potion type $id");
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
|
@ -27,8 +27,8 @@ use pocketmine\entity\Entity;
|
|||||||
use pocketmine\entity\projectile\Projectile;
|
use pocketmine\entity\projectile\Projectile;
|
||||||
use pocketmine\event\entity\ProjectileLaunchEvent;
|
use pocketmine\event\entity\ProjectileLaunchEvent;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
|
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
|
|
||||||
abstract class ProjectileItem extends Item{
|
abstract class ProjectileItem extends Item{
|
||||||
|
@ -69,6 +69,7 @@ class EnchantmentInstance{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the level of the enchantment.
|
* Sets the level of the enchantment.
|
||||||
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
|
@ -62,6 +62,7 @@ class ProtectionEnchantment extends Enchantment{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the base EPF this enchantment type offers for the given enchantment level.
|
* Returns the base EPF this enchantment type offers for the given enchantment level.
|
||||||
|
*
|
||||||
* @param int $level
|
* @param int $level
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
@ -72,6 +73,7 @@ class ProtectionEnchantment extends Enchantment{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this enchantment type offers protection from the specified damage source's cause.
|
* Returns whether this enchantment type offers protection from the specified damage source's cause.
|
||||||
|
*
|
||||||
* @param EntityDamageEvent $event
|
* @param EntityDamageEvent $event
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
|
@ -284,6 +284,7 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $str
|
* @param string $str
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getDifficultyFromString(string $str) : int{
|
public static function getDifficultyFromString(string $str) : int{
|
||||||
@ -872,16 +873,12 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
$pk->z = $b->z;
|
$pk->z = $b->z;
|
||||||
|
|
||||||
if($b instanceof Block){
|
if($b instanceof Block){
|
||||||
$blockId = $b->getId();
|
$pk->blockRuntimeId = $b->getRuntimeId();
|
||||||
$blockData = $b->getDamage();
|
|
||||||
}else{
|
}else{
|
||||||
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
||||||
$blockId = $fullBlock >> 4;
|
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||||
$blockData = $fullBlock & 0xf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($blockId, $blockData);
|
|
||||||
|
|
||||||
$pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE;
|
$pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE;
|
||||||
|
|
||||||
$packets[] = $pk;
|
$packets[] = $pk;
|
||||||
@ -898,16 +895,12 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
$pk->z = $b->z;
|
$pk->z = $b->z;
|
||||||
|
|
||||||
if($b instanceof Block){
|
if($b instanceof Block){
|
||||||
$blockId = $b->getId();
|
$pk->blockRuntimeId = $b->getRuntimeId();
|
||||||
$blockData = $b->getDamage();
|
|
||||||
}else{
|
}else{
|
||||||
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
|
||||||
$blockId = $fullBlock >> 4;
|
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
|
||||||
$blockData = $fullBlock & 0xf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($blockId, $blockData);
|
|
||||||
|
|
||||||
$pk->flags = $flags;
|
$pk->flags = $flags;
|
||||||
|
|
||||||
$packets[] = $pk;
|
$packets[] = $pk;
|
||||||
@ -979,13 +972,20 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
foreach($this->chunkTickList as $index => $loaders){
|
foreach($this->chunkTickList as $index => $loaders){
|
||||||
Level::getXZ($index, $chunkX, $chunkZ);
|
Level::getXZ($index, $chunkX, $chunkZ);
|
||||||
|
|
||||||
if(($chunk = $this->chunks[$index] ?? null) === null){
|
for($cx = -1; $cx <= 1; ++$cx){
|
||||||
|
for($cz = -1; $cz <= 1; ++$cz){
|
||||||
|
if(!isset($this->chunks[Level::chunkHash($chunkX + $cx, $chunkZ + $cz)])){
|
||||||
unset($this->chunkTickList[$index]);
|
unset($this->chunkTickList[$index]);
|
||||||
continue;
|
goto skip_to_next; //no "continue 3" thanks!
|
||||||
}elseif($loaders <= 0){
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($loaders <= 0){
|
||||||
unset($this->chunkTickList[$index]);
|
unset($this->chunkTickList[$index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$chunk = $this->chunks[$index];
|
||||||
foreach($chunk->getEntities() as $entity){
|
foreach($chunk->getEntities() as $entity){
|
||||||
$entity->scheduleUpdate();
|
$entity->scheduleUpdate();
|
||||||
}
|
}
|
||||||
@ -1014,6 +1014,8 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_to_next: //dummy label to break out of nested loops
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->clearChunksOnTick){
|
if($this->clearChunksOnTick){
|
||||||
@ -1776,7 +1778,7 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($player !== null){
|
if($player !== null){
|
||||||
$ev = new PlayerInteractEvent($player, $item, $blockClicked, $clickVector, $face, $blockClicked->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
$ev = new PlayerInteractEvent($player, $item, $blockClicked, $clickVector, $face, PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
||||||
if($this->checkSpawnProtection($player, $blockClicked)){
|
if($this->checkSpawnProtection($player, $blockClicked)){
|
||||||
$ev->setCancelled(); //set it to cancelled so plugins can bypass this
|
$ev->setCancelled(); //set it to cancelled so plugins can bypass this
|
||||||
}
|
}
|
||||||
@ -1864,7 +1866,7 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($playSound){
|
if($playSound){
|
||||||
$this->broadcastLevelSoundEvent($hand, LevelSoundEventPacket::SOUND_PLACE, 1, BlockFactory::toStaticRuntimeId($hand->getId(), $hand->getDamage()));
|
$this->broadcastLevelSoundEvent($hand, LevelSoundEventPacket::SOUND_PLACE, 1, $hand->getRuntimeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$item->pop();
|
$item->pop();
|
||||||
|
@ -51,7 +51,7 @@ class Chunk{
|
|||||||
/** @var bool */
|
/** @var bool */
|
||||||
protected $isInit = false;
|
protected $isInit = false;
|
||||||
|
|
||||||
/** @var bool*/
|
/** @var bool */
|
||||||
protected $lightPopulated = false;
|
protected $lightPopulated = false;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
protected $terrainGenerated = false;
|
protected $terrainGenerated = false;
|
||||||
@ -366,6 +366,7 @@ class Chunk{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the heightmap value at the specified X/Z chunk block coordinates
|
* Returns the heightmap value at the specified X/Z chunk block coordinates
|
||||||
|
*
|
||||||
* @param int $x 0-15
|
* @param int $x 0-15
|
||||||
* @param int $z 0-15
|
* @param int $z 0-15
|
||||||
* @param int $value
|
* @param int $value
|
||||||
@ -465,6 +466,7 @@ class Chunk{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a column of block IDs from bottom to top at the specified X/Z chunk block coordinates.
|
* Returns a column of block IDs from bottom to top at the specified X/Z chunk block coordinates.
|
||||||
|
*
|
||||||
* @param int $x 0-15
|
* @param int $x 0-15
|
||||||
* @param int $z 0-15
|
* @param int $z 0-15
|
||||||
*
|
*
|
||||||
@ -475,11 +477,13 @@ class Chunk{
|
|||||||
foreach($this->subChunks as $subChunk){
|
foreach($this->subChunks as $subChunk){
|
||||||
$result .= $subChunk->getBlockIdColumn($x, $z);
|
$result .= $subChunk->getBlockIdColumn($x, $z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a column of block meta values from bottom to top at the specified X/Z chunk block coordinates.
|
* Returns a column of block meta values from bottom to top at the specified X/Z chunk block coordinates.
|
||||||
|
*
|
||||||
* @param int $x 0-15
|
* @param int $x 0-15
|
||||||
* @param int $z 0-15
|
* @param int $z 0-15
|
||||||
*
|
*
|
||||||
@ -495,6 +499,7 @@ class Chunk{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a column of sky light values from bottom to top at the specified X/Z chunk block coordinates.
|
* Returns a column of sky light values from bottom to top at the specified X/Z chunk block coordinates.
|
||||||
|
*
|
||||||
* @param int $x 0-15
|
* @param int $x 0-15
|
||||||
* @param int $z 0-15
|
* @param int $z 0-15
|
||||||
*
|
*
|
||||||
@ -510,6 +515,7 @@ class Chunk{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a column of block light values from bottom to top at the specified X/Z chunk block coordinates.
|
* Returns a column of block light values from bottom to top at the specified X/Z chunk block coordinates.
|
||||||
|
*
|
||||||
* @param int $x 0-15
|
* @param int $x 0-15
|
||||||
* @param int $z 0-15
|
* @param int $z 0-15
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@ interface SubChunkInterface{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $checkLight
|
* @param bool $checkLight
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isEmpty(bool $checkLight = true) : bool;
|
public function isEmpty(bool $checkLight = true) : bool;
|
||||||
|
@ -148,6 +148,7 @@ interface LevelProvider{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the world difficulty.
|
* Sets the world difficulty.
|
||||||
|
*
|
||||||
* @param int $difficulty
|
* @param int $difficulty
|
||||||
*/
|
*/
|
||||||
public function setDifficulty(int $difficulty);
|
public function setDifficulty(int $difficulty);
|
||||||
|
@ -35,7 +35,6 @@ class RegionLoader{
|
|||||||
|
|
||||||
public const MAX_SECTOR_LENGTH = 256 << 12; //256 sectors, (1 MiB)
|
public const MAX_SECTOR_LENGTH = 256 << 12; //256 sectors, (1 MiB)
|
||||||
public const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps
|
public const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps
|
||||||
public const MAX_REGION_FILE_SIZE = 32 * 32 * self::MAX_SECTOR_LENGTH + self::REGION_HEADER_LENGTH; //32 * 32 1MiB chunks + header size
|
|
||||||
|
|
||||||
public static $COMPRESSION_LEVEL = 7;
|
public static $COMPRESSION_LEVEL = 7;
|
||||||
|
|
||||||
@ -64,14 +63,9 @@ class RegionLoader{
|
|||||||
$exists = file_exists($this->filePath);
|
$exists = file_exists($this->filePath);
|
||||||
if(!$exists){
|
if(!$exists){
|
||||||
touch($this->filePath);
|
touch($this->filePath);
|
||||||
}else{
|
}elseif(filesize($this->filePath) % 4096 !== 0){
|
||||||
$fileSize = filesize($this->filePath);
|
|
||||||
if($fileSize > self::MAX_REGION_FILE_SIZE){
|
|
||||||
throw new CorruptedRegionException("Corrupted oversized region file found, should be a maximum of " . self::MAX_REGION_FILE_SIZE . " bytes, got " . $fileSize . " bytes");
|
|
||||||
}elseif($fileSize % 4096 !== 0){
|
|
||||||
throw new CorruptedRegionException("Region file should be padded to a multiple of 4KiB");
|
throw new CorruptedRegionException("Region file should be padded to a multiple of 4KiB");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$this->filePointer = fopen($this->filePath, "r+b");
|
$this->filePointer = fopen($this->filePath, "r+b");
|
||||||
stream_set_read_buffer($this->filePointer, 1024 * 16); //16KB
|
stream_set_read_buffer($this->filePointer, 1024 * 16); //16KB
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\level\light;
|
namespace pocketmine\level\light;
|
||||||
|
|
||||||
|
use pocketmine\block\BlockFactory;
|
||||||
use pocketmine\level\format\Chunk;
|
use pocketmine\level\format\Chunk;
|
||||||
use pocketmine\level\Level;
|
use pocketmine\level\Level;
|
||||||
use pocketmine\scheduler\AsyncTask;
|
use pocketmine\scheduler\AsyncTask;
|
||||||
@ -39,6 +40,9 @@ class LightPopulationTask extends AsyncTask{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onRun(){
|
public function onRun(){
|
||||||
|
if(!BlockFactory::isInit()){
|
||||||
|
BlockFactory::init();
|
||||||
|
}
|
||||||
/** @var Chunk $chunk */
|
/** @var Chunk $chunk */
|
||||||
$chunk = Chunk::fastDeserialize($this->chunk);
|
$chunk = Chunk::fastDeserialize($this->chunk);
|
||||||
|
|
||||||
|
@ -54,14 +54,6 @@ abstract class LightUpdate{
|
|||||||
$this->subChunkHandler = new SubChunkIteratorManager($this->level);
|
$this->subChunkHandler = new SubChunkIteratorManager($this->level);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addSpreadNode(int $x, int $y, int $z){
|
|
||||||
$this->spreadQueue->enqueue([$x, $y, $z]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addRemoveNode(int $x, int $y, int $z, int $oldLight){
|
|
||||||
$this->spreadQueue->enqueue([$x, $y, $z, $oldLight]);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected function getLight(int $x, int $y, int $z) : int;
|
abstract protected function getLight(int $x, int $y, int $z) : int;
|
||||||
|
|
||||||
abstract protected function setLight(int $x, int $y, int $z, int $level);
|
abstract protected function setLight(int $x, int $y, int $z, int $level);
|
||||||
@ -114,6 +106,8 @@ abstract class LightUpdate{
|
|||||||
while(!$this->spreadQueue->isEmpty()){
|
while(!$this->spreadQueue->isEmpty()){
|
||||||
list($x, $y, $z) = $this->spreadQueue->dequeue();
|
list($x, $y, $z) = $this->spreadQueue->dequeue();
|
||||||
|
|
||||||
|
unset($this->spreadVisited[Level::blockHash($x, $y, $z)]);
|
||||||
|
|
||||||
if(!$this->subChunkHandler->moveTo($x, $y, $z)){
|
if(!$this->subChunkHandler->moveTo($x, $y, $z)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\level\particle;
|
namespace pocketmine\level\particle;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\block\Block;
|
||||||
use pocketmine\block\BlockFactory;
|
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ class DestroyBlockParticle extends Particle{
|
|||||||
|
|
||||||
public function __construct(Vector3 $pos, Block $b){
|
public function __construct(Vector3 $pos, Block $b){
|
||||||
parent::__construct($pos->x, $pos->y, $pos->z);
|
parent::__construct($pos->x, $pos->y, $pos->z);
|
||||||
$this->data = BlockFactory::toStaticRuntimeId($b->getId(), $b->getDamage());
|
$this->data = $b->getRuntimeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function encode(){
|
public function encode(){
|
||||||
|
@ -24,11 +24,10 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\level\particle;
|
namespace pocketmine\level\particle;
|
||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\block\Block;
|
||||||
use pocketmine\block\BlockFactory;
|
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
|
|
||||||
class TerrainParticle extends GenericParticle{
|
class TerrainParticle extends GenericParticle{
|
||||||
public function __construct(Vector3 $pos, Block $b){
|
public function __construct(Vector3 $pos, Block $b){
|
||||||
parent::__construct($pos, Particle::TYPE_TERRAIN, BlockFactory::toStaticRuntimeId($b->getId(), $b->getDamage()));
|
parent::__construct($pos, Particle::TYPE_TERRAIN, $b->getRuntimeId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,10 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handleDataPacket(DataPacket $packet){
|
public function handleDataPacket(DataPacket $packet){
|
||||||
|
if(!$this->player->isConnected()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$timings = Timings::getReceiveDataPacketTimings($packet);
|
$timings = Timings::getReceiveDataPacketTimings($packet);
|
||||||
$timings->startTiming();
|
$timings->startTiming();
|
||||||
|
|
||||||
|
@ -76,10 +76,6 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
|
|||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
|
|
||||||
$this->sleeper = new SleeperNotifier();
|
$this->sleeper = new SleeperNotifier();
|
||||||
$server->getTickSleeper()->addNotifier($this->sleeper, function() : void{
|
|
||||||
$this->server->getNetwork()->processInterface($this);
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->rakLib = new RakLibServer(
|
$this->rakLib = new RakLibServer(
|
||||||
$this->server->getLogger(),
|
$this->server->getLogger(),
|
||||||
\pocketmine\COMPOSER_AUTOLOADER_PATH,
|
\pocketmine\COMPOSER_AUTOLOADER_PATH,
|
||||||
@ -92,6 +88,9 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function start(){
|
public function start(){
|
||||||
|
$this->server->getTickSleeper()->addNotifier($this->sleeper, function() : void{
|
||||||
|
$this->server->getNetwork()->processInterface($this);
|
||||||
|
});
|
||||||
$this->rakLib->start(PTHREADS_INHERIT_CONSTANTS | PTHREADS_INHERIT_INI); //HACK: MainLogger needs INI and constants
|
$this->rakLib->start(PTHREADS_INHERIT_CONSTANTS | PTHREADS_INHERIT_INI); //HACK: MainLogger needs INI and constants
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ class MoveEntityDeltaPacket extends DataPacket{
|
|||||||
public const FLAG_HAS_ROT_Y = 0x10;
|
public const FLAG_HAS_ROT_Y = 0x10;
|
||||||
public const FLAG_HAS_ROT_Z = 0x20;
|
public const FLAG_HAS_ROT_Z = 0x20;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $entityRuntimeId;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
public $flags;
|
public $flags;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
@ -67,6 +69,7 @@ class MoveEntityDeltaPacket extends DataPacket{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function decodePayload(){
|
protected function decodePayload(){
|
||||||
|
$this->entityRuntimeId = $this->getEntityRuntimeId();
|
||||||
$this->flags = $this->getByte();
|
$this->flags = $this->getByte();
|
||||||
$this->xDiff = $this->maybeReadCoord(self::FLAG_HAS_X);
|
$this->xDiff = $this->maybeReadCoord(self::FLAG_HAS_X);
|
||||||
$this->yDiff = $this->maybeReadCoord(self::FLAG_HAS_Y);
|
$this->yDiff = $this->maybeReadCoord(self::FLAG_HAS_Y);
|
||||||
@ -89,6 +92,7 @@ class MoveEntityDeltaPacket extends DataPacket{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
|
$this->putEntityRuntimeId($this->entityRuntimeId);
|
||||||
$this->putByte($this->flags);
|
$this->putByte($this->flags);
|
||||||
$this->maybeWriteCoord(self::FLAG_HAS_X, $this->xDiff);
|
$this->maybeWriteCoord(self::FLAG_HAS_X, $this->xDiff);
|
||||||
$this->maybeWriteCoord(self::FLAG_HAS_Y, $this->yDiff);
|
$this->maybeWriteCoord(self::FLAG_HAS_Y, $this->yDiff);
|
||||||
|
@ -159,6 +159,7 @@ class PacketPool{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $pid
|
* @param int $pid
|
||||||
|
*
|
||||||
* @return DataPacket
|
* @return DataPacket
|
||||||
*/
|
*/
|
||||||
public static function getPacketById(int $pid) : DataPacket{
|
public static function getPacketById(int $pid) : DataPacket{
|
||||||
@ -167,6 +168,7 @@ class PacketPool{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $buffer
|
* @param string $buffer
|
||||||
|
*
|
||||||
* @return DataPacket
|
* @return DataPacket
|
||||||
*/
|
*/
|
||||||
public static function getPacket(string $buffer) : DataPacket{
|
public static function getPacket(string $buffer) : DataPacket{
|
||||||
|
@ -42,20 +42,20 @@ class ResourcePackStackPacket extends DataPacket{
|
|||||||
public $resourcePackStack = [];
|
public $resourcePackStack = [];
|
||||||
|
|
||||||
protected function decodePayload(){
|
protected function decodePayload(){
|
||||||
/*$this->mustAccept = $this->getBool();
|
$this->mustAccept = $this->getBool();
|
||||||
$behaviorPackCount = $this->getUnsignedVarInt();
|
$behaviorPackCount = $this->getUnsignedVarInt();
|
||||||
while($behaviorPackCount-- > 0){
|
while($behaviorPackCount-- > 0){
|
||||||
$packId = $this->getString();
|
$this->getString();
|
||||||
$version = $this->getString();
|
$this->getString();
|
||||||
$this->behaviorPackStack[] = new ResourcePackInfoEntry($packId, $version);
|
$this->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
$resourcePackCount = $this->getUnsignedVarInt();
|
$resourcePackCount = $this->getUnsignedVarInt();
|
||||||
while($resourcePackCount-- > 0){
|
while($resourcePackCount-- > 0){
|
||||||
$packId = $this->getString();
|
$this->getString();
|
||||||
$version = $this->getString();
|
$this->getString();
|
||||||
$this->resourcePackStack[] = new ResourcePackInfoEntry($packId, $version);
|
$this->getString();
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
|
@ -40,24 +40,26 @@ class ResourcePacksInfoPacket extends DataPacket{
|
|||||||
public $resourcePackEntries = [];
|
public $resourcePackEntries = [];
|
||||||
|
|
||||||
protected function decodePayload(){
|
protected function decodePayload(){
|
||||||
/*$this->mustAccept = $this->getBool();
|
$this->mustAccept = $this->getBool();
|
||||||
$behaviorPackCount = $this->getLShort();
|
$behaviorPackCount = $this->getLShort();
|
||||||
while($behaviorPackCount-- > 0){
|
while($behaviorPackCount-- > 0){
|
||||||
$id = $this->getString();
|
$this->getString();
|
||||||
$version = $this->getString();
|
$this->getString();
|
||||||
$size = $this->getLLong();
|
$this->getLLong();
|
||||||
$this->behaviorPackEntries[] = new ResourcePackInfoEntry($id, $version, $size);
|
$this->getString();
|
||||||
|
$this->getString();
|
||||||
$this->getString();
|
$this->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
$resourcePackCount = $this->getLShort();
|
$resourcePackCount = $this->getLShort();
|
||||||
while($resourcePackCount-- > 0){
|
while($resourcePackCount-- > 0){
|
||||||
$id = $this->getString();
|
|
||||||
$version = $this->getString();
|
|
||||||
$size = $this->getLLong();
|
|
||||||
$this->resourcePackEntries[] = new ResourcePackInfoEntry($id, $version, $size);
|
|
||||||
$this->getString();
|
$this->getString();
|
||||||
}*/
|
$this->getString();
|
||||||
|
$this->getLLong();
|
||||||
|
$this->getString();
|
||||||
|
$this->getString();
|
||||||
|
$this->getString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
|
@ -64,7 +64,7 @@ class StartGamePacket extends DataPacket{
|
|||||||
public $difficulty;
|
public $difficulty;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
public $spawnX;
|
public $spawnX;
|
||||||
/** @var int*/
|
/** @var int */
|
||||||
public $spawnY;
|
public $spawnY;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
public $spawnZ;
|
public $spawnZ;
|
||||||
|
@ -92,6 +92,7 @@ class NetworkInventoryAction{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param InventoryTransactionPacket $packet
|
* @param InventoryTransactionPacket $packet
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function read(InventoryTransactionPacket $packet){
|
public function read(InventoryTransactionPacket $packet){
|
||||||
|
@ -85,7 +85,6 @@ class RCON{
|
|||||||
public function stop(){
|
public function stop(){
|
||||||
$this->instance->close();
|
$this->instance->close();
|
||||||
socket_write($this->ipcMainSocket, "\x00"); //make select() return
|
socket_write($this->ipcMainSocket, "\x00"); //make select() return
|
||||||
Server::microSleep(50000);
|
|
||||||
$this->instance->quit();
|
$this->instance->quit();
|
||||||
|
|
||||||
@socket_close($this->socket);
|
@socket_close($this->socket);
|
||||||
|
@ -119,6 +119,7 @@ class BanEntry{
|
|||||||
* @link https://bugs.php.net/bug.php?id=75992
|
* @link https://bugs.php.net/bug.php?id=75992
|
||||||
*
|
*
|
||||||
* @param \DateTime $dateTime
|
* @param \DateTime $dateTime
|
||||||
|
*
|
||||||
* @throws \RuntimeException if the argument can't be parsed from a formatted date string
|
* @throws \RuntimeException if the argument can't be parsed from a formatted date string
|
||||||
*/
|
*/
|
||||||
private static function validateDate(\DateTime $dateTime) : void{
|
private static function validateDate(\DateTime $dateTime) : void{
|
||||||
|
@ -166,9 +166,7 @@ class PermissibleBase implements Permissible{
|
|||||||
|
|
||||||
public function clearPermissions(){
|
public function clearPermissions(){
|
||||||
$permManager = PermissionManager::getInstance();
|
$permManager = PermissionManager::getInstance();
|
||||||
foreach(array_keys($this->permissions) as $name){
|
$permManager->unsubscribeFromAllPermissions($this->parent ?? $this);
|
||||||
$permManager->unsubscribeFromPermission($name, $this->parent ?? $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
$permManager->unsubscribeFromDefaultPerms(false, $this->parent ?? $this);
|
$permManager->unsubscribeFromDefaultPerms(false, $this->parent ?? $this);
|
||||||
$permManager->unsubscribeFromDefaultPerms(true, $this->parent ?? $this);
|
$permManager->unsubscribeFromDefaultPerms(true, $this->parent ?? $this);
|
||||||
|
@ -160,6 +160,18 @@ class PermissionManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Permissible $permissible
|
||||||
|
*/
|
||||||
|
public function unsubscribeFromAllPermissions(Permissible $permissible) : void{
|
||||||
|
foreach($this->permSubs as $permission => &$subs){
|
||||||
|
unset($subs[spl_object_hash($permissible)]);
|
||||||
|
if(empty($subs)){
|
||||||
|
unset($this->permSubs[$permission]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $permission
|
* @param string $permission
|
||||||
*
|
*
|
||||||
|
@ -55,6 +55,12 @@ interface Plugin extends CommandExecutor{
|
|||||||
public function isEnabled() : bool;
|
public function isEnabled() : bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Called by the plugin manager when the plugin is enabled or disabled to inform the plugin of its enabled state.
|
||||||
|
*
|
||||||
|
* @internal This is intended for core use only and should not be used by plugins
|
||||||
|
* @see PluginManager::enablePlugin()
|
||||||
|
* @see PluginManager::disablePlugin()
|
||||||
|
*
|
||||||
* @param bool $enabled
|
* @param bool $enabled
|
||||||
*/
|
*/
|
||||||
public function setEnabled(bool $enabled = true) : void;
|
public function setEnabled(bool $enabled = true) : void;
|
||||||
|
@ -93,6 +93,12 @@ abstract class PluginBase implements Plugin{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Called by the plugin manager when the plugin is enabled or disabled to inform the plugin of its enabled state.
|
||||||
|
*
|
||||||
|
* @internal This is intended for core use only and should not be used by plugins
|
||||||
|
* @see PluginManager::enablePlugin()
|
||||||
|
* @see PluginManager::disablePlugin()
|
||||||
|
*
|
||||||
* @param bool $enabled
|
* @param bool $enabled
|
||||||
*/
|
*/
|
||||||
final public function setEnabled(bool $enabled = true) : void{
|
final public function setEnabled(bool $enabled = true) : void{
|
||||||
|
@ -359,6 +359,7 @@ class PluginManager{
|
|||||||
* Returns whether a specified API version string is considered compatible with the server's API version.
|
* Returns whether a specified API version string is considered compatible with the server's API version.
|
||||||
*
|
*
|
||||||
* @param string ...$versions
|
* @param string ...$versions
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isCompatibleApi(string ...$versions) : bool{
|
public function isCompatibleApi(string ...$versions) : bool{
|
||||||
@ -475,6 +476,16 @@ class PluginManager{
|
|||||||
PermissionManager::getInstance()->unsubscribeFromPermission($permission, $permissible);
|
PermissionManager::getInstance()->unsubscribeFromPermission($permission, $permissible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* @see PermissionManager::unsubscribeFromAllPermissions()
|
||||||
|
*
|
||||||
|
* @param Permissible $permissible
|
||||||
|
*/
|
||||||
|
public function unsubscribeFromAllPermissions(Permissible $permissible) : void{
|
||||||
|
PermissionManager::getInstance()->unsubscribeFromAllPermissions($permissible);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
* @see PermissionManager::getPermissionSubscriptions()
|
* @see PermissionManager::getPermissionSubscriptions()
|
||||||
|
@ -138,6 +138,7 @@ class ResourcePackManager{
|
|||||||
* Returns the resource pack matching the specified UUID string, or null if the ID was not recognized.
|
* Returns the resource pack matching the specified UUID string, or null if the ID was not recognized.
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
|
*
|
||||||
* @return ResourcePack|null
|
* @return ResourcePack|null
|
||||||
*/
|
*/
|
||||||
public function getPackById(string $id){
|
public function getPackById(string $id){
|
||||||
|
@ -32,6 +32,7 @@ class ZippedResourcePack implements ResourcePack{
|
|||||||
* TODO: add more manifest validation
|
* TODO: add more manifest validation
|
||||||
*
|
*
|
||||||
* @param \stdClass $manifest
|
* @param \stdClass $manifest
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function verifyManifest(\stdClass $manifest) : bool{
|
public static function verifyManifest(\stdClass $manifest) : bool{
|
||||||
|
@ -289,12 +289,20 @@ class AsyncPool{
|
|||||||
*/
|
*/
|
||||||
public function collectTasks() : void{
|
public function collectTasks() : void{
|
||||||
foreach($this->tasks as $task){
|
foreach($this->tasks as $task){
|
||||||
if(!$task->isGarbage()){
|
|
||||||
$task->checkProgressUpdates($this->server);
|
$task->checkProgressUpdates($this->server);
|
||||||
}
|
|
||||||
if($task->isGarbage() and !$task->isRunning() and !$task->isCrashed()){
|
if($task->isGarbage() and !$task->isRunning() and !$task->isCrashed()){
|
||||||
if(!$task->hasCancelledRun()){
|
if(!$task->hasCancelledRun()){
|
||||||
try{
|
try{
|
||||||
|
/*
|
||||||
|
* It's possible for a task to submit a progress update and then finish before the progress
|
||||||
|
* update is detected by the parent thread, so here we consume any missed updates.
|
||||||
|
*
|
||||||
|
* When this happens, it's possible for a progress update to arrive between the previous
|
||||||
|
* checkProgressUpdates() call and the next isGarbage() call, causing progress updates to be
|
||||||
|
* lost. Thus, it's necessary to do one last check here to make sure all progress updates have
|
||||||
|
* been consumed before completing.
|
||||||
|
*/
|
||||||
|
$task->checkProgressUpdates($this->server);
|
||||||
$task->onCompletion($this->server);
|
$task->onCompletion($this->server);
|
||||||
if($task->removeDanglingStoredObjects()){
|
if($task->removeDanglingStoredObjects()){
|
||||||
$this->logger->notice("AsyncTask " . get_class($task) . " stored local complex data but did not remove them after completion");
|
$this->logger->notice("AsyncTask " . get_class($task) . " stored local complex data but did not remove them after completion");
|
||||||
|
@ -129,6 +129,7 @@ abstract class AsyncTask extends Collectable{
|
|||||||
* @see AsyncWorker::getFromThreadStore()
|
* @see AsyncWorker::getFromThreadStore()
|
||||||
*
|
*
|
||||||
* @param string $identifier
|
* @param string $identifier
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFromThreadStore(string $identifier){
|
public function getFromThreadStore(string $identifier){
|
||||||
|
@ -102,6 +102,7 @@ class AsyncWorker extends Worker{
|
|||||||
* Objects stored in this storage may ONLY be retrieved while the task is running.
|
* Objects stored in this storage may ONLY be retrieved while the task is running.
|
||||||
*
|
*
|
||||||
* @param string $identifier
|
* @param string $identifier
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFromThreadStore(string $identifier){
|
public function getFromThreadStore(string $identifier){
|
||||||
|
@ -101,6 +101,7 @@ class AutoUpdater{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a warning to a player to tell them there is an update available
|
* Shows a warning to a player to tell them there is an update available
|
||||||
|
*
|
||||||
* @param Player $player
|
* @param Player $player
|
||||||
*/
|
*/
|
||||||
public function showPlayerUpdate(Player $player){
|
public function showPlayerUpdate(Player $player){
|
||||||
|
@ -47,6 +47,7 @@ class Color{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the alpha (opacity) value of this colour, lower = more transparent
|
* Sets the alpha (opacity) value of this colour, lower = more transparent
|
||||||
|
*
|
||||||
* @param int $a
|
* @param int $a
|
||||||
*/
|
*/
|
||||||
public function setA(int $a){
|
public function setA(int $a){
|
||||||
@ -63,6 +64,7 @@ class Color{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the red value of this colour.
|
* Sets the red value of this colour.
|
||||||
|
*
|
||||||
* @param int $r
|
* @param int $r
|
||||||
*/
|
*/
|
||||||
public function setR(int $r){
|
public function setR(int $r){
|
||||||
@ -79,6 +81,7 @@ class Color{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the green value of this colour.
|
* Sets the green value of this colour.
|
||||||
|
*
|
||||||
* @param int $g
|
* @param int $g
|
||||||
*/
|
*/
|
||||||
public function setG(int $g){
|
public function setG(int $g){
|
||||||
@ -95,6 +98,7 @@ class Color{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the blue value of this colour.
|
* Sets the blue value of this colour.
|
||||||
|
*
|
||||||
* @param int $b
|
* @param int $b
|
||||||
*/
|
*/
|
||||||
public function setB(int $b){
|
public function setB(int $b){
|
||||||
@ -105,6 +109,7 @@ class Color{
|
|||||||
* Mixes the supplied list of colours together to produce a result colour.
|
* Mixes the supplied list of colours together to produce a result colour.
|
||||||
*
|
*
|
||||||
* @param Color ...$colors
|
* @param Color ...$colors
|
||||||
|
*
|
||||||
* @return Color
|
* @return Color
|
||||||
*/
|
*/
|
||||||
public static function mix(Color ...$colors) : Color{
|
public static function mix(Color ...$colors) : Color{
|
||||||
@ -127,6 +132,7 @@ class Color{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Color from the supplied RGB colour code (24-bit)
|
* Returns a Color from the supplied RGB colour code (24-bit)
|
||||||
|
*
|
||||||
* @param int $code
|
* @param int $code
|
||||||
*
|
*
|
||||||
* @return Color
|
* @return Color
|
||||||
|
@ -232,6 +232,7 @@ class Config{
|
|||||||
* Sets the options for the JSON encoding when saving
|
* Sets the options for the JSON encoding when saving
|
||||||
*
|
*
|
||||||
* @param int $options
|
* @param int $options
|
||||||
|
*
|
||||||
* @return Config $this
|
* @return Config $this
|
||||||
* @throws \RuntimeException if the Config is not in JSON
|
* @throws \RuntimeException if the Config is not in JSON
|
||||||
* @see json_encode
|
* @see json_encode
|
||||||
@ -250,6 +251,7 @@ class Config{
|
|||||||
* Enables the given option in addition to the currently set JSON options
|
* Enables the given option in addition to the currently set JSON options
|
||||||
*
|
*
|
||||||
* @param int $option
|
* @param int $option
|
||||||
|
*
|
||||||
* @return Config $this
|
* @return Config $this
|
||||||
* @throws \RuntimeException if the Config is not in JSON
|
* @throws \RuntimeException if the Config is not in JSON
|
||||||
* @see json_encode
|
* @see json_encode
|
||||||
@ -268,6 +270,7 @@ class Config{
|
|||||||
* Disables the given option for the JSON encoding when saving
|
* Disables the given option for the JSON encoding when saving
|
||||||
*
|
*
|
||||||
* @param int $option
|
* @param int $option
|
||||||
|
*
|
||||||
* @return Config $this
|
* @return Config $this
|
||||||
* @throws \RuntimeException if the Config is not in JSON
|
* @throws \RuntimeException if the Config is not in JSON
|
||||||
* @see json_encode
|
* @see json_encode
|
||||||
|
@ -47,6 +47,7 @@ class UUID{
|
|||||||
*
|
*
|
||||||
* @param string $uuid
|
* @param string $uuid
|
||||||
* @param int $version
|
* @param int $version
|
||||||
|
*
|
||||||
* @return UUID
|
* @return UUID
|
||||||
*/
|
*/
|
||||||
public static function fromString(string $uuid, int $version = null) : UUID{
|
public static function fromString(string $uuid, int $version = null) : UUID{
|
||||||
@ -58,6 +59,7 @@ class UUID{
|
|||||||
*
|
*
|
||||||
* @param string $uuid
|
* @param string $uuid
|
||||||
* @param int $version
|
* @param int $version
|
||||||
|
*
|
||||||
* @return UUID
|
* @return UUID
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
@ -74,6 +76,7 @@ class UUID{
|
|||||||
* Creates an UUIDv3 from binary data or list of binary data
|
* Creates an UUIDv3 from binary data or list of binary data
|
||||||
*
|
*
|
||||||
* @param string ...$data
|
* @param string ...$data
|
||||||
|
*
|
||||||
* @return UUID
|
* @return UUID
|
||||||
*/
|
*/
|
||||||
public static function fromData(string ...$data) : UUID{
|
public static function fromData(string ...$data) : UUID{
|
||||||
|
@ -246,6 +246,7 @@ class Utils{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $recalculate
|
* @param bool $recalculate
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function getCoreCount(bool $recalculate = false) : int{
|
public static function getCoreCount(bool $recalculate = false) : int{
|
||||||
|
@ -55,7 +55,7 @@ class VersionString{
|
|||||||
$this->development = $isDevBuild;
|
$this->development = $isDevBuild;
|
||||||
$this->build = $buildNumber;
|
$this->build = $buildNumber;
|
||||||
|
|
||||||
preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(.*))?$/', $this->baseVersion, $matches);
|
preg_match('/(\d+)\.(\d+)\.(\d+)(?:-(.*))?$/', $this->baseVersion, $matches);
|
||||||
if(count($matches) < 4){
|
if(count($matches) < 4){
|
||||||
throw new \InvalidArgumentException("Invalid base version \"$baseVersion\", should contain at least 3 version digits");
|
throw new \InvalidArgumentException("Invalid base version \"$baseVersion\", should contain at least 3 version digits");
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ if exist PocketMine-MP.phar (
|
|||||||
if exist src\pocketmine\PocketMine.php (
|
if exist src\pocketmine\PocketMine.php (
|
||||||
set POCKETMINE_FILE=src\pocketmine\PocketMine.php
|
set POCKETMINE_FILE=src\pocketmine\PocketMine.php
|
||||||
) else (
|
) else (
|
||||||
echo "Couldn't find a valid PocketMine-MP installation"
|
echo Couldn't find a valid PocketMine-MP installation
|
||||||
pause
|
pause
|
||||||
exit 1
|
exit 1
|
||||||
)
|
)
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
PHP_BINARY="php"
|
PHP_BINARY="php"
|
||||||
DIR=""
|
DIR=""
|
||||||
|
FIND="find"
|
||||||
|
|
||||||
while getopts "p:d:" OPTION 2> /dev/null; do
|
while getopts "p:d:f:" OPTION 2> /dev/null; do
|
||||||
case ${OPTION} in
|
case ${OPTION} in
|
||||||
p)
|
p)
|
||||||
PHP_BINARY="$OPTARG"
|
PHP_BINARY="$OPTARG"
|
||||||
@ -11,6 +12,9 @@ while getopts "p:d:" OPTION 2> /dev/null; do
|
|||||||
d)
|
d)
|
||||||
DIR="$OPTARG"
|
DIR="$OPTARG"
|
||||||
;;
|
;;
|
||||||
|
f)
|
||||||
|
FIND="$OPTARG"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -21,7 +25,7 @@ fi
|
|||||||
|
|
||||||
echo Running PHP lint scans on \"$DIR\"...
|
echo Running PHP lint scans on \"$DIR\"...
|
||||||
|
|
||||||
OUTPUT=`find "$DIR" -name "*.php" -print0 | xargs -0 -n1 -P4 "$PHP_BINARY" -l`
|
OUTPUT=`$FIND "$DIR" -name "*.php" -print0 | xargs -0 -n1 -P4 "$PHP_BINARY" -l`
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo $OUTPUT | grep -v "No syntax errors"
|
echo $OUTPUT | grep -v "No syntax errors"
|
||||||
|
@ -44,7 +44,8 @@ class Main extends PluginBase implements Listener{
|
|||||||
|
|
||||||
$this->waitingTests = [
|
$this->waitingTests = [
|
||||||
new tests\AsyncTaskMemoryLeakTest($this),
|
new tests\AsyncTaskMemoryLeakTest($this),
|
||||||
new tests\AsyncTaskMainLoggerTest($this)
|
new tests\AsyncTaskMainLoggerTest($this),
|
||||||
|
new tests\AsyncTaskPublishProgressRaceTest($this)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pmmp\TesterPlugin\tests;
|
||||||
|
|
||||||
|
use pmmp\TesterPlugin\Test;
|
||||||
|
use pocketmine\scheduler\AsyncTask;
|
||||||
|
use pocketmine\Server;
|
||||||
|
|
||||||
|
class AsyncTaskPublishProgressRaceTest extends Test{
|
||||||
|
|
||||||
|
public function getName() : string{
|
||||||
|
return "Verify progress updates work as expected when finishing task";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription() : string{
|
||||||
|
return "Progress updates would be lost when finishing a task before its remaining progress updates were detected.";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run() : void{
|
||||||
|
//this test is racy, but it should fail often enough to be a pest if something is broken
|
||||||
|
|
||||||
|
$this->getPlugin()->getServer()->getAsyncPool()->submitTask(new class($this) extends AsyncTask{
|
||||||
|
private static $success = false;
|
||||||
|
|
||||||
|
public function __construct(AsyncTaskPublishProgressRaceTest $t){
|
||||||
|
$this->storeLocal($t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onRun() : void{
|
||||||
|
$this->publishProgress("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onProgressUpdate(Server $server, $progress) : void{
|
||||||
|
if($progress === "hello"){
|
||||||
|
// thread local on main thread
|
||||||
|
self::$success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onCompletion(Server $server) : void{
|
||||||
|
/** @var AsyncTaskPublishProgressRaceTest $t */
|
||||||
|
$t = $this->fetchLocal();
|
||||||
|
$t->setResult(self::$success ? Test::RESULT_OK : Test::RESULT_FAILED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user