Merge branch 'php/7.0' into mcpe-1.2

This commit is contained in:
Dylan K. Taylor 2017-09-01 23:10:58 +01:00
commit 5d75d3d5b6
54 changed files with 462 additions and 382 deletions

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine; namespace pocketmine;
abstract class Collectable extends \Threaded implements \Collectable{ abstract class Collectable extends \Threaded{
private $isGarbage = false; private $isGarbage = false;

View File

@ -2411,7 +2411,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$points += $armorItem->getDefensePoints(); $points += $armorItem->getDefensePoints();
} }
$damage[EntityDamageEvent::MODIFIER_ARMOR] = -floor($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04); $damage[EntityDamageEvent::MODIFIER_ARMOR] = -($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04);
} }
$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage); $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage);

View File

@ -89,8 +89,8 @@ namespace pocketmine {
* Enjoy it as much as I did writing it. I don't want to do it again. * Enjoy it as much as I did writing it. I don't want to do it again.
*/ */
if(version_compare("7.0", PHP_VERSION) > 0){ if(version_compare("7.0", PHP_VERSION) > 0 or version_compare("7.1", PHP_VERSION) <= 0){
echo "[CRITICAL] You must use PHP >= 7.0" . PHP_EOL; echo "[CRITICAL] You must use PHP 7.0" . PHP_EOL;
echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL; echo "[CRITICAL] Please use the installer provided on the homepage." . PHP_EOL;
exit(1); exit(1);
} }

View File

@ -31,9 +31,10 @@ use pocketmine\level\Position;
*/ */
class BlockFactory{ class BlockFactory{
/** @var \SplFixedArray<Block> */ /** @var \SplFixedArray<Block> */
public static $list = null; private static $list = null;
/** @var \SplFixedArray<Block> */ /** @var \SplFixedArray<Block> */
public static $fullList = null; private static $fullList = null;
/** @var \SplFixedArray<bool> */ /** @var \SplFixedArray<bool> */
public static $solid = null; public static $solid = null;
/** @var \SplFixedArray<bool> */ /** @var \SplFixedArray<bool> */
@ -59,6 +60,7 @@ class BlockFactory{
if(self::$list === null or $force){ if(self::$list === null or $force){
self::$list = new \SplFixedArray(256); self::$list = new \SplFixedArray(256);
self::$fullList = new \SplFixedArray(4096); self::$fullList = new \SplFixedArray(4096);
self::$light = new \SplFixedArray(256); self::$light = new \SplFixedArray(256);
self::$lightFilter = new \SplFixedArray(256); self::$lightFilter = new \SplFixedArray(256);
self::$solid = new \SplFixedArray(256); self::$solid = new \SplFixedArray(256);
@ -393,4 +395,12 @@ class BlockFactory{
return $block; return $block;
} }
/**
* @internal
* @return \SplFixedArray
*/
public static function getBlockStatesArray() : \SplFixedArray{
return self::$fullList;
}
} }

View File

@ -136,10 +136,6 @@ class Chest extends Transparent{
public function onActivate(Item $item, Player $player = null) : bool{ public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$top = $this->getSide(Vector3::SIDE_UP);
if($top->isTransparent() !== true){
return true;
}
$t = $this->getLevel()->getTile($this); $t = $this->getLevel()->getTile($this);
$chest = null; $chest = null;
@ -157,10 +153,12 @@ class Chest extends Transparent{
$chest = Tile::createTile("Chest", $this->getLevel(), $nbt); $chest = Tile::createTile("Chest", $this->getLevel(), $nbt);
} }
if(isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag){ if(
if($chest->namedtag->Lock->getValue() !== $item->getCustomName()){ !$this->getSide(Vector3::SIDE_UP)->isTransparent() or
return true; ($chest->isPaired() and !$chest->getPair()->getBlock()->getSide(Vector3::SIDE_UP)->isTransparent()) or
} (isset($chest->namedtag->Lock) and $chest->namedtag->Lock instanceof StringTag and $chest->namedtag->Lock->getValue() !== $item->getCustomName())
){
return true;
} }
$player->addWindow($chest->getInventory()); $player->addWindow($chest->getInventory());

View File

@ -254,48 +254,50 @@ abstract class Liquid extends Transparent{
//$this->updateFlow(); //$this->updateFlow();
} }
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z)); if($decay >= 0){
$bottomBlock = $this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y - 1, $this->z));
if($this instanceof Lava and $bottomBlock instanceof Water){ if($this instanceof Lava and $bottomBlock instanceof Water){
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true); $this->getLevel()->setBlock($bottomBlock, BlockFactory::get(Block::STONE), true, true);
}elseif($bottomBlock->canBeFlowedInto() or ($bottomBlock instanceof Liquid and ($bottomBlock->getDamage() & 0x07) !== 0)){ }elseif($bottomBlock->canBeFlowedInto() or ($bottomBlock instanceof Liquid and ($bottomBlock->getDamage() & 0x07) !== 0)){
$this->getLevel()->setBlock($bottomBlock, BlockFactory::get($this->id, $decay | 0x08), true, false); $this->getLevel()->setBlock($bottomBlock, BlockFactory::get($this->id, $decay | 0x08), true, false);
$this->getLevel()->scheduleDelayedBlockUpdate($bottomBlock, $this->tickRate()); $this->getLevel()->scheduleDelayedBlockUpdate($bottomBlock, $this->tickRate());
}elseif($decay >= 0 and ($decay === 0 or !$bottomBlock->canBeFlowedInto())){ }elseif($decay === 0 or !$bottomBlock->canBeFlowedInto()){
$flags = $this->getOptimalFlowDirections(); $flags = $this->getOptimalFlowDirections();
$l = $decay + $multiplier; $l = $decay + $multiplier;
if($decay >= 8){ if($decay >= 8){
$l = 1; $l = 1;
}
if($l >= 8){
$this->checkForHarden();
return;
}
if($flags[0]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
}
if($flags[1]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
}
if($flags[2]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
}
if($flags[3]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
}
} }
if($l >= 8){ $this->checkForHarden();
$this->checkForHarden();
return;
}
if($flags[0]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x - 1, $this->y, $this->z)), $l);
}
if($flags[1]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x + 1, $this->y, $this->z)), $l);
}
if($flags[2]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z - 1)), $l);
}
if($flags[3]){
$this->flowIntoBlock($this->level->getBlock($this->temporalVector->setComponents($this->x, $this->y, $this->z + 1)), $l);
}
} }
$this->checkForHarden();
} }
} }

View File

@ -396,11 +396,10 @@ class Effect{
* Adds this effect to the Entity, performing effect overriding as specified. * Adds this effect to the Entity, performing effect overriding as specified.
* *
* @param Entity $entity * @param Entity $entity
* @param bool $modify
* @param Effect|null $oldEffect * @param Effect|null $oldEffect
*/ */
public function add(Entity $entity, bool $modify = false, Effect $oldEffect = null){ public function add(Entity $entity, Effect $oldEffect = null){
$entity->getLevel()->getServer()->getPluginManager()->callEvent($ev = new EntityEffectAddEvent($entity, $this, $modify, $oldEffect)); $entity->getLevel()->getServer()->getPluginManager()->callEvent($ev = new EntityEffectAddEvent($entity, $this, $oldEffect));
if($ev->isCancelled()){ if($ev->isCancelled()){
return; return;
} }
@ -411,7 +410,7 @@ class Effect{
$pk->amplifier = $this->getAmplifier(); $pk->amplifier = $this->getAmplifier();
$pk->particles = $this->isVisible(); $pk->particles = $this->isVisible();
$pk->duration = $this->getDuration(); $pk->duration = $this->getDuration();
if($ev->willModify()){ if($oldEffect !== null){
$pk->eventId = MobEffectPacket::EVENT_MODIFY; $pk->eventId = MobEffectPacket::EVENT_MODIFY;
}else{ }else{
$pk->eventId = MobEffectPacket::EVENT_ADD; $pk->eventId = MobEffectPacket::EVENT_ADD;
@ -420,6 +419,10 @@ class Effect{
$entity->dataPacket($pk); $entity->dataPacket($pk);
} }
if($oldEffect !== null){
$oldEffect->remove($entity, false);
}
switch($this->id){ switch($this->id){
case Effect::INVISIBILITY: case Effect::INVISIBILITY:
$entity->setGenericFlag(Entity::DATA_FLAG_INVISIBLE, true); $entity->setGenericFlag(Entity::DATA_FLAG_INVISIBLE, true);
@ -427,35 +430,16 @@ class Effect{
break; break;
case Effect::SPEED: case Effect::SPEED:
$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
if($ev->willModify() and $oldEffect !== null){ $attr->setValue($attr->getValue() * (1 + 0.2 * $this->getEffectLevel()));
$speed = $attr->getValue() / (1 + 0.2 * $oldEffect->getEffectLevel());
}else{
$speed = $attr->getValue();
}
$speed *= (1 + 0.2 * $this->getEffectLevel());
$attr->setValue($speed);
break; break;
case Effect::SLOWNESS: case Effect::SLOWNESS:
$attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED);
if($ev->willModify() and $oldEffect !== null){ $attr->setValue($attr->getValue() * (1 - 0.15 * $this->getEffectLevel()), true);
$speed = $attr->getValue() / (1 - 0.15 * $oldEffect->getEffectLevel());
}else{
$speed = $attr->getValue();
}
$speed *= (1 - 0.15 * $this->getEffectLevel());
$attr->setValue($speed, true);
break; break;
case Effect::HEALTH_BOOST: case Effect::HEALTH_BOOST:
$attr = $entity->getAttributeMap()->getAttribute(Attribute::HEALTH); $attr = $entity->getAttributeMap()->getAttribute(Attribute::HEALTH);
if($ev->willModify() and $oldEffect !== null){ $attr->setMaxValue($attr->getMaxValue() + 4 * $this->getEffectLevel());
$max = $attr->getMaxValue() - (4 * $oldEffect->getEffectLevel());
}else{
$max = $attr->getMaxValue();
}
$max += (4 * $this->getEffectLevel());
$attr->setMaxValue($max);
break; break;
case Effect::ABSORPTION: case Effect::ABSORPTION:
$new = (4 * $this->getEffectLevel()); $new = (4 * $this->getEffectLevel());
@ -470,13 +454,15 @@ class Effect{
* Removes the effect from the entity, resetting any changed values back to their original defaults. * Removes the effect from the entity, resetting any changed values back to their original defaults.
* *
* @param Entity $entity * @param Entity $entity
* @param bool $send
*/ */
public function remove(Entity $entity){ public function remove(Entity $entity, bool $send = true){
$entity->getLevel()->getServer()->getPluginManager()->callEvent($ev = new EntityEffectRemoveEvent($entity, $this)); $entity->getLevel()->getServer()->getPluginManager()->callEvent($ev = new EntityEffectRemoveEvent($entity, $this));
if($ev->isCancelled()){ if($ev->isCancelled()){
return; return;
} }
if($entity instanceof Player){
if($send and $entity instanceof Player){
$pk = new MobEffectPacket(); $pk = new MobEffectPacket();
$pk->entityRuntimeId = $entity->getId(); $pk->entityRuntimeId = $entity->getId();
$pk->eventId = MobEffectPacket::EVENT_REMOVE; $pk->eventId = MobEffectPacket::EVENT_REMOVE;

View File

@ -307,8 +307,8 @@ abstract class Entity extends Location implements Metadatable{
/** @var float */ /** @var float */
protected $baseOffset = 0.0; protected $baseOffset = 0.0;
/** @var int */ /** @var float */
private $health = 20; private $health = 20.0;
private $maxHealth = 20; private $maxHealth = 20;
/** @var float */ /** @var float */
@ -931,9 +931,9 @@ abstract class Entity extends Location implements Metadatable{
} }
/** /**
* @return int * @return float
*/ */
public function getHealth(){ public function getHealth() : float{
return $this->health; return $this->health;
} }
@ -944,11 +944,10 @@ abstract class Entity extends Location implements Metadatable{
/** /**
* Sets the health of the Entity. This won't send any update to the players * Sets the health of the Entity. This won't send any update to the players
* *
* @param int $amount * @param float $amount
*/ */
public function setHealth($amount){ public function setHealth(float $amount){
$amount = (int) $amount; if($amount == $this->health){
if($amount === $this->health){
return; return;
} }
@ -957,7 +956,7 @@ abstract class Entity extends Location implements Metadatable{
$this->kill(); $this->kill();
} }
}elseif($amount <= $this->getMaxHealth() or $amount < $this->health){ }elseif($amount <= $this->getMaxHealth() or $amount < $this->health){
$this->health = (int) $amount; $this->health = $amount;
}else{ }else{
$this->health = $this->getMaxHealth(); $this->health = $this->getMaxHealth();
} }
@ -992,15 +991,15 @@ abstract class Entity extends Location implements Metadatable{
/** /**
* @return int * @return int
*/ */
public function getMaxHealth(){ public function getMaxHealth() : int{
return $this->maxHealth; return $this->maxHealth;
} }
/** /**
* @param int $amount * @param int $amount
*/ */
public function setMaxHealth($amount){ public function setMaxHealth(int $amount){
$this->maxHealth = (int) $amount; $this->maxHealth = $amount;
} }
public function canCollideWith(Entity $entity) : bool{ public function canCollideWith(Entity $entity) : bool{

View File

@ -549,7 +549,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
* @param int $flagId * @param int $flagId
* @return bool * @return bool
*/ */
public function getPlayerFlag(int $flagId){ public function getPlayerFlag(int $flagId) : bool{
return $this->getDataFlag(self::DATA_PLAYER_FLAGS, $flagId); return $this->getDataFlag(self::DATA_PLAYER_FLAGS, $flagId);
} }

View File

@ -58,7 +58,7 @@ class Item extends Entity{
parent::initEntity(); parent::initEntity();
$this->setMaxHealth(5); $this->setMaxHealth(5);
$this->setHealth($this->namedtag["Health"]); $this->setHealth((int) $this->namedtag["Health"]);
if(isset($this->namedtag->Age)){ if(isset($this->namedtag->Age)){
$this->age = $this->namedtag["Age"]; $this->age = $this->namedtag["Age"];
} }
@ -139,7 +139,7 @@ class Item extends Entity{
public function saveNBT(){ public function saveNBT(){
parent::saveNBT(); parent::saveNBT();
$this->namedtag->Item = $this->item->nbtSerialize(-1, "Item"); $this->namedtag->Item = $this->item->nbtSerialize(-1, "Item");
$this->namedtag->Health = new ShortTag("Health", $this->getHealth()); $this->namedtag->Health = new ShortTag("Health", (int) $this->getHealth());
$this->namedtag->Age = new ShortTag("Age", $this->age); $this->namedtag->Age = new ShortTag("Age", $this->age);
$this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay); $this->namedtag->PickupDelay = new ShortTag("PickupDelay", $this->pickupDelay);
if($this->owner !== null){ if($this->owner !== null){

View File

@ -73,7 +73,7 @@ abstract class Living extends Entity implements Damageable{
$this->namedtag->Health = new FloatTag("Health", (float) $this->getMaxHealth()); $this->namedtag->Health = new FloatTag("Health", (float) $this->getMaxHealth());
} }
$this->setHealth($this->namedtag["Health"]); $this->setHealth((float) $this->namedtag["Health"]);
if(isset($this->namedtag->ActiveEffects)){ if(isset($this->namedtag->ActiveEffects)){
foreach($this->namedtag->ActiveEffects->getValue() as $e){ foreach($this->namedtag->ActiveEffects->getValue() as $e){
@ -100,10 +100,10 @@ abstract class Living extends Entity implements Damageable{
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ABSORPTION)); $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ABSORPTION));
} }
public function setHealth($amount){ public function setHealth(float $amount){
$wasAlive = $this->isAlive(); $wasAlive = $this->isAlive();
parent::setHealth($amount); parent::setHealth($amount);
$this->attributeMap->getAttribute(Attribute::HEALTH)->setValue($this->getHealth(), true); $this->attributeMap->getAttribute(Attribute::HEALTH)->setValue(ceil($this->getHealth()), true);
if($this->isAlive() and !$wasAlive){ if($this->isAlive() and !$wasAlive){
$pk = new EntityEventPacket(); $pk = new EntityEventPacket();
$pk->entityRuntimeId = $this->getId(); $pk->entityRuntimeId = $this->getId();
@ -112,11 +112,11 @@ abstract class Living extends Entity implements Damageable{
} }
} }
public function getMaxHealth(){ public function getMaxHealth() : int{
return $this->attributeMap->getAttribute(Attribute::HEALTH)->getMaxValue(); return (int) $this->attributeMap->getAttribute(Attribute::HEALTH)->getMaxValue();
} }
public function setMaxHealth($amount){ public function setMaxHealth(int $amount){
$this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount); $this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount);
} }
@ -237,9 +237,9 @@ abstract class Living extends Entity implements Damageable{
){ ){
return; return;
} }
$effect->add($this, true, $oldEffect); $effect->add($this, $oldEffect);
}else{ }else{
$effect->add($this, false); $effect->add($this);
} }
$this->effects[$effect->getId()] = $effect; $this->effects[$effect->getId()] = $effect;

View File

@ -23,39 +23,7 @@ declare(strict_types=1);
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
use pocketmine\entity\Entity; class EntityArmorChangeEvent extends EntityInventoryChangeEvent{
use pocketmine\event\Cancellable;
use pocketmine\item\Item;
class EntityArmorChangeEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
private $oldItem;
private $newItem;
private $slot;
public function __construct(Entity $entity, Item $oldItem, Item $newItem, $slot){
$this->entity = $entity;
$this->oldItem = $oldItem;
$this->newItem = $newItem;
$this->slot = (int) $slot;
}
public function getSlot(){
return $this->slot;
}
public function getNewItem(){
return $this->newItem;
}
public function setNewItem(Item $item){
$this->newItem = $item;
}
public function getOldItem(){
return $this->oldItem;
}
} }

View File

@ -33,7 +33,9 @@ use pocketmine\event\Cancellable;
class EntityBlockChangeEvent extends EntityEvent implements Cancellable{ class EntityBlockChangeEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
/** @var Block */
private $from; private $from;
/** @var Block */
private $to; private $to;
public function __construct(Entity $entity, Block $from, Block $to){ public function __construct(Entity $entity, Block $from, Block $to){
@ -45,14 +47,14 @@ class EntityBlockChangeEvent extends EntityEvent implements Cancellable{
/** /**
* @return Block * @return Block
*/ */
public function getBlock(){ public function getBlock() : Block{
return $this->from; return $this->from;
} }
/** /**
* @return Block * @return Block
*/ */
public function getTo(){ public function getTo() : Block{
return $this->to; return $this->to;
} }

View File

@ -28,6 +28,7 @@ use pocketmine\entity\Entity;
class EntityCombustByBlockEvent extends EntityCombustEvent{ class EntityCombustByBlockEvent extends EntityCombustEvent{
/** @var Block */
protected $combuster; protected $combuster;
/** /**
@ -35,7 +36,7 @@ class EntityCombustByBlockEvent extends EntityCombustEvent{
* @param Entity $combustee * @param Entity $combustee
* @param int $duration * @param int $duration
*/ */
public function __construct(Block $combuster, Entity $combustee, $duration){ public function __construct(Block $combuster, Entity $combustee, int $duration){
parent::__construct($combustee, $duration); parent::__construct($combustee, $duration);
$this->combuster = $combuster; $this->combuster = $combuster;
} }
@ -43,7 +44,7 @@ class EntityCombustByBlockEvent extends EntityCombustEvent{
/** /**
* @return Block * @return Block
*/ */
public function getCombuster(){ public function getCombuster() : Block{
return $this->combuster; return $this->combuster;
} }

View File

@ -27,6 +27,7 @@ use pocketmine\entity\Entity;
class EntityCombustByEntityEvent extends EntityCombustEvent{ class EntityCombustByEntityEvent extends EntityCombustEvent{
/** @var Entity */
protected $combuster; protected $combuster;
/** /**
@ -34,7 +35,7 @@ class EntityCombustByEntityEvent extends EntityCombustEvent{
* @param Entity $combustee * @param Entity $combustee
* @param int $duration * @param int $duration
*/ */
public function __construct(Entity $combuster, Entity $combustee, $duration){ public function __construct(Entity $combuster, Entity $combustee, int $duration){
parent::__construct($combustee, $duration); parent::__construct($combustee, $duration);
$this->combuster = $combuster; $this->combuster = $combuster;
} }
@ -42,7 +43,7 @@ class EntityCombustByEntityEvent extends EntityCombustEvent{
/** /**
* @return Entity * @return Entity
*/ */
public function getCombuster(){ public function getCombuster() : Entity{
return $this->combuster; return $this->combuster;
} }

View File

@ -35,17 +35,21 @@ class EntityCombustEvent extends EntityEvent implements Cancellable{
* @param Entity $combustee * @param Entity $combustee
* @param int $duration * @param int $duration
*/ */
public function __construct(Entity $combustee, $duration){ public function __construct(Entity $combustee, int $duration){
$this->entity = $combustee; $this->entity = $combustee;
$this->duration = $duration; $this->duration = $duration;
} }
public function getDuration(){ /**
* Returns the duration in seconds the entity will burn for.
* @return int
*/
public function getDuration() : int{
return $this->duration; return $this->duration;
} }
public function setDuration($duration){ public function setDuration(int $duration){
$this->duration = (int) $duration; $this->duration = $duration;
} }
} }

View File

@ -36,12 +36,12 @@ class EntityDamageByBlockEvent extends EntityDamageEvent{
/** /**
* @param Block $damager * @param Block $damager
* @param Entity $entity * @param Entity $entity
* @param int $cause * @param int $cause
* @param int|int[] $damage * @param float|float[] $damage
*/ */
public function __construct(Block $damager, Entity $entity, $cause, $damage){ public function __construct(Block $damager, Entity $entity, int $cause, $damage){
$this->damager = $damager; $this->damager = $damager;
parent::__construct($entity, $cause, $damage); parent::__construct($entity, $cause, $damage);
} }
@ -49,7 +49,7 @@ class EntityDamageByBlockEvent extends EntityDamageEvent{
/** /**
* @return Block * @return Block
*/ */
public function getDamager(){ public function getDamager() : Block{
return $this->damager; return $this->damager;
} }

View File

@ -33,15 +33,14 @@ class EntityDamageByChildEntityEvent extends EntityDamageByEntityEvent{
/** @var int */ /** @var int */
private $childEntityEid; private $childEntityEid;
/** /**
* @param Entity $damager * @param Entity $damager
* @param Entity $childEntity * @param Entity $childEntity
* @param Entity $entity * @param Entity $entity
* @param int $cause * @param int $cause
* @param int|int[] $damage * @param float|float[] $damage
*/ */
public function __construct(Entity $damager, Entity $childEntity, Entity $entity, $cause, $damage){ public function __construct(Entity $damager, Entity $childEntity, Entity $entity, int $cause, $damage){
$this->childEntityEid = $childEntity->getId(); $this->childEntityEid = $childEntity->getId();
parent::__construct($damager, $entity, $cause, $damage); parent::__construct($damager, $entity, $cause, $damage);
} }

View File

@ -33,19 +33,19 @@ use pocketmine\entity\Living;
class EntityDamageByEntityEvent extends EntityDamageEvent{ class EntityDamageByEntityEvent extends EntityDamageEvent{
/** @var int */ /** @var int */
private $damagerEid; private $damagerEntityId;
/** @var float */ /** @var float */
private $knockBack; private $knockBack;
/** /**
* @param Entity $damager * @param Entity $damager
* @param Entity $entity * @param Entity $entity
* @param int $cause * @param int $cause
* @param int|int[] $damage * @param float|float[] $damage
* @param float $knockBack * @param float $knockBack
*/ */
public function __construct(Entity $damager, Entity $entity, $cause, $damage, $knockBack = 0.4){ public function __construct(Entity $damager, Entity $entity, int $cause, $damage, float $knockBack = 0.4){
$this->damagerEid = $damager->getId(); $this->damagerEntityId = $damager->getId();
$this->knockBack = $knockBack; $this->knockBack = $knockBack;
parent::__construct($entity, $cause, $damage); parent::__construct($entity, $cause, $damage);
$this->addAttackerModifiers($damager); $this->addAttackerModifiers($damager);
@ -69,20 +69,20 @@ class EntityDamageByEntityEvent extends EntityDamageEvent{
* @return Entity|null * @return Entity|null
*/ */
public function getDamager(){ public function getDamager(){
return $this->getEntity()->getLevel()->getServer()->findEntity($this->damagerEid, $this->getEntity()->getLevel()); return $this->getEntity()->getLevel()->getServer()->findEntity($this->damagerEntityId, $this->getEntity()->getLevel());
} }
/** /**
* @return float * @return float
*/ */
public function getKnockBack(){ public function getKnockBack() : float{
return $this->knockBack; return $this->knockBack;
} }
/** /**
* @param float $knockBack * @param float $knockBack
*/ */
public function setKnockBack($knockBack){ public function setKnockBack(float $knockBack){
$this->knockBack = $knockBack; $this->knockBack = $knockBack;
} }
} }

View File

@ -55,21 +55,20 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
const CAUSE_CUSTOM = 14; const CAUSE_CUSTOM = 14;
const CAUSE_STARVATION = 15; const CAUSE_STARVATION = 15;
/** @var int */
private $cause; private $cause;
/** @var array */ /** @var float[] */
private $modifiers; private $modifiers;
/** @var float[] */
private $originals; private $originals;
/** /**
* @param Entity $entity * @param Entity $entity
* @param int $cause * @param int $cause
* @param int|int[] $damage * @param float|float[] $damage
*
* @throws \Exception
*/ */
public function __construct(Entity $entity, $cause, $damage){ public function __construct(Entity $entity, int $cause, $damage){
$this->entity = $entity; $this->entity = $entity;
$this->cause = $cause; $this->cause = $cause;
if(is_array($damage)){ if(is_array($damage)){
@ -90,43 +89,41 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
/** /**
* @return int * @return int
*/ */
public function getCause(){ public function getCause() : int{
return $this->cause; return $this->cause;
} }
/** /**
* @param int $type * @param int $type
* *
* @return int * @return float
*/ */
public function getOriginalDamage($type = self::MODIFIER_BASE){ public function getOriginalDamage(int $type = self::MODIFIER_BASE) : float{
if(isset($this->originals[$type])){ if(isset($this->originals[$type])){
return $this->originals[$type]; return $this->originals[$type];
} }
return 0; return 0.0;
} }
/** /**
* @param int $type * @param int $type
* *
* @return int * @return float
*/ */
public function getDamage($type = self::MODIFIER_BASE){ public function getDamage(int $type = self::MODIFIER_BASE) : float{
if(isset($this->modifiers[$type])){ if(isset($this->modifiers[$type])){
return $this->modifiers[$type]; return $this->modifiers[$type];
} }
return 0; return 0.0;
} }
/** /**
* @param float $damage * @param float $damage
* @param int $type * @param int $type
*
* @throws \UnexpectedValueException
*/ */
public function setDamage($damage, $type = self::MODIFIER_BASE){ public function setDamage(float $damage, int $type = self::MODIFIER_BASE){
$this->modifiers[$type] = $damage; $this->modifiers[$type] = $damage;
} }
@ -135,20 +132,15 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
* *
* @return bool * @return bool
*/ */
public function isApplicable($type){ public function isApplicable(int $type) : bool{
return isset($this->modifiers[$type]); return isset($this->modifiers[$type]);
} }
/** /**
* @return int * @return float
*/ */
public function getFinalDamage(){ public function getFinalDamage() : float{
$damage = 0; return array_sum($this->modifiers);
foreach($this->modifiers as $type => $d){
$damage += $d;
}
return $damage;
} }
} }

View File

@ -52,7 +52,7 @@ class EntityDeathEvent extends EntityEvent{
/** /**
* @return Item[] * @return Item[]
*/ */
public function getDrops(){ public function getDrops() : array{
return $this->drops; return $this->drops;
} }

View File

@ -50,42 +50,42 @@ class EntityDespawnEvent extends EntityEvent{
/** /**
* @return int * @return int
*/ */
public function getType(){ public function getType() : int{
return $this->entityType; return $this->entityType;
} }
/** /**
* @return bool * @return bool
*/ */
public function isCreature(){ public function isCreature() : bool{
return $this->entity instanceof Creature; return $this->entity instanceof Creature;
} }
/** /**
* @return bool * @return bool
*/ */
public function isHuman(){ public function isHuman() : bool{
return $this->entity instanceof Human; return $this->entity instanceof Human;
} }
/** /**
* @return bool * @return bool
*/ */
public function isProjectile(){ public function isProjectile() : bool{
return $this->entity instanceof Projectile; return $this->entity instanceof Projectile;
} }
/** /**
* @return bool * @return bool
*/ */
public function isVehicle(){ public function isVehicle() : bool{
return $this->entity instanceof Vehicle; return $this->entity instanceof Vehicle;
} }
/** /**
* @return bool * @return bool
*/ */
public function isItem(){ public function isItem() : bool{
return $this->entity instanceof Item; return $this->entity instanceof Item;
} }

View File

@ -42,6 +42,9 @@ class EntityEatBlockEvent extends EntityEatEvent{
return parent::getResidue(); return parent::getResidue();
} }
/**
* @param Block $residue
*/
public function setResidue($residue){ public function setResidue($residue){
if(!($residue instanceof Block)){ if(!($residue instanceof Block)){
throw new \InvalidArgumentException("Eating a Block can only result in a Block residue"); throw new \InvalidArgumentException("Eating a Block can only result in a Block residue");

View File

@ -37,6 +37,7 @@ class EntityEatEvent extends EntityEvent implements Cancellable{
private $foodRestore; private $foodRestore;
/** @var float */ /** @var float */
private $saturationRestore; private $saturationRestore;
/** @var mixed */
private $residue; private $residue;
/** @var Effect[] */ /** @var Effect[] */
private $additionalEffects; private $additionalEffects;
@ -50,7 +51,7 @@ class EntityEatEvent extends EntityEvent implements Cancellable{
$this->additionalEffects = $foodSource->getAdditionalEffects(); $this->additionalEffects = $foodSource->getAdditionalEffects();
} }
public function getFoodSource(){ public function getFoodSource() : FoodSource{
return $this->foodSource; return $this->foodSource;
} }
@ -70,10 +71,17 @@ class EntityEatEvent extends EntityEvent implements Cancellable{
$this->saturationRestore = $saturationRestore; $this->saturationRestore = $saturationRestore;
} }
/**
* Returns the result of eating the food source.
* @return mixed
*/
public function getResidue(){ public function getResidue(){
return $this->residue; return $this->residue;
} }
/**
* @param mixed $residue
*/
public function setResidue($residue){ public function setResidue($residue){
$this->residue = $residue; $this->residue = $residue;
} }
@ -81,7 +89,7 @@ class EntityEatEvent extends EntityEvent implements Cancellable{
/** /**
* @return Effect[] * @return Effect[]
*/ */
public function getAdditionalEffects(){ public function getAdditionalEffects() : array{
return $this->additionalEffects; return $this->additionalEffects;
} }

View File

@ -39,6 +39,9 @@ class EntityEatItemEvent extends EntityEatEvent{
return parent::getResidue(); return parent::getResidue();
} }
/**
* @param Item $residue
*/
public function setResidue($residue){ public function setResidue($residue){
if(!($residue instanceof Item)){ if(!($residue instanceof Item)){
throw new \InvalidArgumentException("Eating an Item can only result in an Item residue"); throw new \InvalidArgumentException("Eating an Item can only result in an Item residue");

View File

@ -26,28 +26,37 @@ namespace pocketmine\event\entity;
use pocketmine\entity\Effect; use pocketmine\entity\Effect;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
/**
* Called when an effect is added to an Entity.
*/
class EntityEffectAddEvent extends EntityEffectEvent{ class EntityEffectAddEvent extends EntityEffectEvent{
public static $handlerList = null; public static $handlerList = null;
/** @var bool */ /** @var Effect|null */
private $modify;
/** @var Effect */
private $oldEffect; private $oldEffect;
public function __construct(Entity $entity, Effect $effect, $modify, $oldEffect){ /**
* @param Entity $entity
* @param Effect $effect
* @param Effect|null $oldEffect
*/
public function __construct(Entity $entity, Effect $effect, Effect $oldEffect = null){
parent::__construct($entity, $effect); parent::__construct($entity, $effect);
$this->modify = $modify;
$this->oldEffect = $oldEffect; $this->oldEffect = $oldEffect;
} }
/**
* Returns whether the effect addition will replace an existing effect already applied to the entity.
*
* @return bool
*/
public function willModify() : bool{ public function willModify() : bool{
return $this->modify; return $this->hasOldEffect();
}
public function setWillModify(bool $modify){
$this->modify = $modify;
} }
/**
* @return bool
*/
public function hasOldEffect() : bool{ public function hasOldEffect() : bool{
return $this->oldEffect instanceof Effect; return $this->oldEffect instanceof Effect;
} }
@ -59,5 +68,4 @@ class EntityEffectAddEvent extends EntityEffectEvent{
return $this->oldEffect; return $this->oldEffect;
} }
} }

View File

@ -23,6 +23,9 @@ declare(strict_types=1);
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
/**
* Called when an effect is removed from an entity.
*/
class EntityEffectRemoveEvent extends EntityEffectEvent{ class EntityEffectRemoveEvent extends EntityEffectEvent{
public static $handlerList = null; public static $handlerList = null;

View File

@ -33,6 +33,9 @@ abstract class EntityEvent extends Event{
/** @var Entity */ /** @var Entity */
protected $entity; protected $entity;
/**
* @return Entity
*/
public function getEntity(){ public function getEntity(){
return $this->entity; return $this->entity;
} }

View File

@ -51,7 +51,7 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
* @param Block[] $blocks * @param Block[] $blocks
* @param float $yield * @param float $yield
*/ */
public function __construct(Entity $entity, Position $position, array $blocks, $yield){ public function __construct(Entity $entity, Position $position, array $blocks, float $yield){
$this->entity = $entity; $this->entity = $entity;
$this->position = $position; $this->position = $position;
$this->blocks = $blocks; $this->blocks = $blocks;
@ -61,14 +61,14 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
/** /**
* @return Position * @return Position
*/ */
public function getPosition(){ public function getPosition() : Position{
return $this->position; return $this->position;
} }
/** /**
* @return Block[] * @return Block[]
*/ */
public function getBlockList(){ public function getBlockList() : array{
return $this->blocks; return $this->blocks;
} }
@ -82,14 +82,14 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
/** /**
* @return float * @return float
*/ */
public function getYield(){ public function getYield() : float{
return $this->yield; return $this->yield;
} }
/** /**
* @param float $yield * @param float $yield
*/ */
public function setYield($yield){ public function setYield(float $yield){
$this->yield = $yield; $this->yield = $yield;
} }

View File

@ -27,33 +27,54 @@ use pocketmine\entity\Entity;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
use pocketmine\item\Item; use pocketmine\item\Item;
/**
* Called before a slot in an entity's inventory changes.
*/
class EntityInventoryChangeEvent extends EntityEvent implements Cancellable{ class EntityInventoryChangeEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
/** @var Item */
private $oldItem; private $oldItem;
/** @var Item */
private $newItem; private $newItem;
/** @var int */
private $slot; private $slot;
public function __construct(Entity $entity, Item $oldItem, Item $newItem, $slot){ public function __construct(Entity $entity, Item $oldItem, Item $newItem, int $slot){
$this->entity = $entity; $this->entity = $entity;
$this->oldItem = $oldItem; $this->oldItem = $oldItem;
$this->newItem = $newItem; $this->newItem = $newItem;
$this->slot = (int) $slot; $this->slot = $slot;
} }
public function getSlot(){ /**
* Returns the inventory slot number affected by the event.
* @return int
*/
public function getSlot() : int{
return $this->slot; return $this->slot;
} }
public function getNewItem(){ /**
* Returns the item which will be in the slot after the event.
* @return Item
*/
public function getNewItem() : Item{
return $this->newItem; return $this->newItem;
} }
/**
* @param Item $item
*/
public function setNewItem(Item $item){ public function setNewItem(Item $item){
$this->newItem = $item; $this->newItem = $item;
} }
public function getOldItem(){ /**
* Returns the item currently in the slot.
* @return Item
*/
public function getOldItem() : Item{
return $this->oldItem; return $this->oldItem;
} }

View File

@ -30,7 +30,9 @@ use pocketmine\level\Level;
class EntityLevelChangeEvent extends EntityEvent implements Cancellable{ class EntityLevelChangeEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
/** @var Level */
private $originLevel; private $originLevel;
/** @var Level */
private $targetLevel; private $targetLevel;
public function __construct(Entity $entity, Level $originLevel, Level $targetLevel){ public function __construct(Entity $entity, Level $originLevel, Level $targetLevel){
@ -39,11 +41,11 @@ class EntityLevelChangeEvent extends EntityEvent implements Cancellable{
$this->targetLevel = $targetLevel; $this->targetLevel = $targetLevel;
} }
public function getOrigin(){ public function getOrigin() : Level{
return $this->originLevel; return $this->originLevel;
} }
public function getTarget(){ public function getTarget() : Level{
return $this->targetLevel; return $this->targetLevel;
} }
} }

View File

@ -30,6 +30,7 @@ use pocketmine\math\Vector3;
class EntityMotionEvent extends EntityEvent implements Cancellable{ class EntityMotionEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
/** @var Vector3 */
private $mot; private $mot;
public function __construct(Entity $entity, Vector3 $mot){ public function __construct(Entity $entity, Vector3 $mot){
@ -40,7 +41,7 @@ class EntityMotionEvent extends EntityEvent implements Cancellable{
/** /**
* @return Vector3 * @return Vector3
*/ */
public function getVector(){ public function getVector() : Vector3{
return $this->mot; return $this->mot;
} }

View File

@ -35,7 +35,9 @@ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
const CAUSE_CUSTOM = 3; const CAUSE_CUSTOM = 3;
const CAUSE_SATURATION = 4; const CAUSE_SATURATION = 4;
/** @var float */
private $amount; private $amount;
/** @var int */
private $reason; private $reason;
@ -44,27 +46,31 @@ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
* @param float $amount * @param float $amount
* @param int $regainReason * @param int $regainReason
*/ */
public function __construct(Entity $entity, $amount, $regainReason){ public function __construct(Entity $entity, float $amount, int $regainReason){
$this->entity = $entity; $this->entity = $entity;
$this->amount = $amount; $this->amount = $amount;
$this->reason = (int) $regainReason; $this->reason = $regainReason;
} }
/** /**
* @return float * @return float
*/ */
public function getAmount(){ public function getAmount() : float{
return $this->amount; return $this->amount;
} }
/** /**
* @param float $amount * @param float $amount
*/ */
public function setAmount($amount){ public function setAmount(float $amount){
$this->amount = $amount; $this->amount = $amount;
} }
public function getRegainReason(){ /**
* Returns one of the CAUSE_* constants to indicate why this regeneration occurred.
* @return int
*/
public function getRegainReason() : int{
return $this->reason; return $this->reason;
} }

View File

@ -45,7 +45,7 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{
* @param Projectile $projectile * @param Projectile $projectile
* @param float $force * @param float $force
*/ */
public function __construct(Living $shooter, Item $bow, Projectile $projectile, $force){ public function __construct(Living $shooter, Item $bow, Projectile $projectile, float $force){
$this->entity = $shooter; $this->entity = $shooter;
$this->bow = $bow; $this->bow = $bow;
$this->projectile = $projectile; $this->projectile = $projectile;
@ -62,14 +62,18 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{
/** /**
* @return Item * @return Item
*/ */
public function getBow(){ public function getBow() : Item{
return $this->bow; return $this->bow;
} }
/** /**
* Returns the entity considered as the projectile in this event.
*
* NOTE: This might not return a Projectile if a plugin modified the target entity.
*
* @return Entity * @return Entity
*/ */
public function getProjectile(){ public function getProjectile() : Entity{
return $this->projectile; return $this->projectile;
} }
@ -89,14 +93,14 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{
/** /**
* @return float * @return float
*/ */
public function getForce(){ public function getForce() : float{
return $this->force; return $this->force;
} }
/** /**
* @param float $force * @param float $force
*/ */
public function setForce($force){ public function setForce(float $force){
$this->force = $force; $this->force = $force;
} }

View File

@ -51,49 +51,49 @@ class EntitySpawnEvent extends EntityEvent{
/** /**
* @return Position * @return Position
*/ */
public function getPosition(){ public function getPosition() : Position{
return $this->entity->getPosition(); return $this->entity->getPosition();
} }
/** /**
* @return int * @return int
*/ */
public function getType(){ public function getType() : int{
return $this->entityType; return $this->entityType;
} }
/** /**
* @return bool * @return bool
*/ */
public function isCreature(){ public function isCreature() : bool{
return $this->entity instanceof Creature; return $this->entity instanceof Creature;
} }
/** /**
* @return bool * @return bool
*/ */
public function isHuman(){ public function isHuman() : bool{
return $this->entity instanceof Human; return $this->entity instanceof Human;
} }
/** /**
* @return bool * @return bool
*/ */
public function isProjectile(){ public function isProjectile() : bool{
return $this->entity instanceof Projectile; return $this->entity instanceof Projectile;
} }
/** /**
* @return bool * @return bool
*/ */
public function isVehicle(){ public function isVehicle() : bool{
return $this->entity instanceof Vehicle; return $this->entity instanceof Vehicle;
} }
/** /**
* @return bool * @return bool
*/ */
public function isItem(){ public function isItem() : bool{
return $this->entity instanceof Item; return $this->entity instanceof Item;
} }

View File

@ -44,11 +44,12 @@ class EntityTeleportEvent extends EntityEvent implements Cancellable{
/** /**
* @return Position * @return Position
*/ */
public function getFrom(){ public function getFrom() : Position{
return $this->from; return $this->from;
} }
/** /**
* @deprecated This method has no effect or use.
* @param Position $from * @param Position $from
*/ */
public function setFrom(Position $from){ public function setFrom(Position $from){
@ -58,7 +59,7 @@ class EntityTeleportEvent extends EntityEvent implements Cancellable{
/** /**
* @return Position * @return Position
*/ */
public function getTo(){ public function getTo() : Position{
return $this->to; return $this->to;
} }

View File

@ -32,14 +32,16 @@ use pocketmine\event\Cancellable;
class ExplosionPrimeEvent extends EntityEvent implements Cancellable{ class ExplosionPrimeEvent extends EntityEvent implements Cancellable{
public static $handlerList = null; public static $handlerList = null;
/** @var float */
protected $force; protected $force;
/** @var bool */
private $blockBreaking; private $blockBreaking;
/** /**
* @param Entity $entity * @param Entity $entity
* @param float $force * @param float $force
*/ */
public function __construct(Entity $entity, $force){ public function __construct(Entity $entity, float $force){
$this->entity = $entity; $this->entity = $entity;
$this->force = $force; $this->force = $force;
$this->blockBreaking = true; $this->blockBreaking = true;
@ -48,26 +50,26 @@ class ExplosionPrimeEvent extends EntityEvent implements Cancellable{
/** /**
* @return float * @return float
*/ */
public function getForce(){ public function getForce() : float{
return $this->force; return $this->force;
} }
public function setForce($force){ public function setForce(float $force){
$this->force = (float) $force; $this->force = $force;
} }
/** /**
* @return bool * @return bool
*/ */
public function isBlockBreaking(){ public function isBlockBreaking() : bool{
return $this->blockBreaking; return $this->blockBreaking;
} }
/** /**
* @param bool $affectsBlocks * @param bool $affectsBlocks
*/ */
public function setBlockBreaking($affectsBlocks){ public function setBlockBreaking(bool $affectsBlocks){
$this->blockBreaking = (bool) $affectsBlocks; $this->blockBreaking = $affectsBlocks;
} }
} }

View File

@ -27,6 +27,7 @@ use pocketmine\block\Air;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\block\BlockFactory; use pocketmine\block\BlockFactory;
use pocketmine\block\Liquid; use pocketmine\block\Liquid;
use pocketmine\event\player\PlayerBucketEmptyEvent;
use pocketmine\event\player\PlayerBucketFillEvent; use pocketmine\event\player\PlayerBucketFillEvent;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -70,7 +71,7 @@ class Bucket extends Item{
}elseif($targetBlock instanceof Liquid){ }elseif($targetBlock instanceof Liquid){
$result = clone $this; $result = clone $this;
$result->setDamage(0); $result->setDamage(0);
$player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketFillEvent($player, $block, $face, $this, $result)); $player->getServer()->getPluginManager()->callEvent($ev = new PlayerBucketEmptyEvent($player, $block, $face, $this, $result));
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$player->getLevel()->setBlock($block, $targetBlock, true, true); $player->getLevel()->setBlock($block, $targetBlock, true, true);
if($player->isSurvival()){ if($player->isSurvival()){

View File

@ -202,7 +202,7 @@ class Item implements ItemIds, \JsonSerializable{
$this->id = $id & 0xffff; $this->id = $id & 0xffff;
$this->meta = $meta !== -1 ? $meta & 0xffff : -1; $this->meta = $meta !== -1 ? $meta & 0xffff : -1;
$this->name = $name; $this->name = $name;
if(!isset($this->block) and $this->id <= 0xff and isset(BlockFactory::$list[$this->id])){ if(!isset($this->block) and $this->id <= 0xff){
$this->block = BlockFactory::get($this->id, $this->meta); $this->block = BlockFactory::get($this->id, $this->meta);
$this->name = $this->block->getName(); $this->name = $this->block->getName();
} }

View File

@ -32,7 +32,7 @@ use pocketmine\nbt\tag\CompoundTag;
class ItemFactory{ class ItemFactory{
/** @var \SplFixedArray */ /** @var \SplFixedArray */
public static $list = null; private static $list = null;
public static function init(){ public static function init(){
if(self::$list === null){ if(self::$list === null){

@ -1 +1 @@
Subproject commit 513b153f7081f0060b64723e640d7c87d0b69e6c Subproject commit c37468585286514a9e5a47f696e534789af26359

View File

@ -270,7 +270,7 @@ class Level implements ChunkManager, Metadatable{
* @throws \Exception * @throws \Exception
*/ */
public function __construct(Server $server, string $name, string $path, string $provider){ public function __construct(Server $server, string $name, string $path, string $provider){
$this->blockStates = BlockFactory::$fullList; $this->blockStates = BlockFactory::getBlockStatesArray();
$this->levelId = static::$levelIdCounter++; $this->levelId = static::$levelIdCounter++;
$this->blockMetadata = new BlockMetadataStore($this); $this->blockMetadata = new BlockMetadataStore($this);
$this->server = $server; $this->server = $server;
@ -302,19 +302,12 @@ class Level implements ChunkManager, Metadatable{
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true); $this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true);
$this->cacheChunks = (bool) $this->server->getProperty("chunk-sending.cache-chunks", false); $this->cacheChunks = (bool) $this->server->getProperty("chunk-sending.cache-chunks", false);
$this->randomTickBlocks = \SplFixedArray::fromArray(array_filter(BlockFactory::$list->toArray(), function(Block $block = null){
return $block !== null and $block->ticksRandomly();
}));
$this->randomTickBlocks->setSize(256);
$dontTickBlocks = $this->server->getProperty("chunk-ticking.disable-block-ticking", []); $dontTickBlocks = $this->server->getProperty("chunk-ticking.disable-block-ticking", []);
foreach($dontTickBlocks as $id){ $this->randomTickBlocks = new \SplFixedArray(256);
try{ foreach($this->randomTickBlocks as $id => $null){
if(isset($this->randomTickBlocks[$id])){ $block = BlockFactory::get($id); //Make sure it's a copy
$this->randomTickBlocks[$id] = null; if(!isset($dontTickBlocks[$id]) and $block->ticksRandomly()){
} $this->randomTickBlocks[$id] = $block;
}catch(\RuntimeException $e){
//index out of bounds
} }
} }
@ -839,21 +832,15 @@ class Level implements ChunkManager, Metadatable{
$this->server->batchPackets($target, $packets, false, false); $this->server->batchPackets($target, $packets, false, false);
} }
public function clearCache(bool $full = false){ public function clearCache(bool $force = false){
if($full){ if($force){
$this->chunkCache = []; $this->chunkCache = [];
$this->blockCache = []; $this->blockCache = [];
}else{ }else{
if(count($this->chunkCache) > 768){
$this->chunkCache = [];
}
if(count($this->blockCache) > 2048){ if(count($this->blockCache) > 2048){
$this->blockCache = []; $this->blockCache = [];
} }
} }
} }
public function clearChunkCache(int $chunkX, int $chunkZ){ public function clearChunkCache(int $chunkX, int $chunkZ){
@ -950,7 +937,7 @@ class Level implements ChunkManager, Metadatable{
* *
* @return bool * @return bool
*/ */
public function save(bool $force = false){ public function save(bool $force = false) : bool{
if(!$this->getAutoSave() and !$force){ if(!$this->getAutoSave() and !$force){
return false; return false;

View File

@ -634,7 +634,7 @@ class Chunk{
* @param Tile $tile * @param Tile $tile
*/ */
public function addTile(Tile $tile){ public function addTile(Tile $tile){
if($tile->closed){ if($tile->isClosed()){
throw new \InvalidArgumentException("Attempted to add a garbage closed Tile to a chunk"); throw new \InvalidArgumentException("Attempted to add a garbage closed Tile to a chunk");
} }
$this->tiles[$tile->getId()] = $tile; $this->tiles[$tile->getId()] = $tile;

View File

@ -23,84 +23,86 @@ declare(strict_types=1);
namespace pocketmine\level\format\io; namespace pocketmine\level\format\io;
class ChunkUtils{ if(!extension_loaded('pocketmine_chunkutils')){
class ChunkUtils{
/** /**
* Re-orders a byte array (YZX -> XZY and vice versa) * Re-orders a byte array (YZX -> XZY and vice versa)
* *
* @param string $array length 4096 * @param string $array length 4096
* *
* @return string length 4096 * @return string length 4096
*/ */
final public static function reorderByteArray(string $array) : string{ final public static function reorderByteArray(string $array) : string{
$result = str_repeat("\x00", 4096); $result = str_repeat("\x00", 4096);
if($array !== $result){ if($array !== $result){
$i = 0; $i = 0;
for($x = 0; $x < 16; ++$x){ for($x = 0; $x < 16; ++$x){
$zM = $x + 256; $zM = $x + 256;
for($z = $x; $z < $zM; $z += 16){ for($z = $x; $z < $zM; $z += 16){
$yM = $z + 4096; $yM = $z + 4096;
for($y = $z; $y < $yM; $y += 256){ for($y = $z; $y < $yM; $y += 256){
$result{$i} = $array{$y}; $result{$i} = $array{$y};
++$i; ++$i;
}
}
}
}
return $result;
}
/**
* Re-orders a nibble array (YZX -> XZY and vice versa)
*
* @param string $array length 2048
* @param string $commonValue length 1 common value to fill the default array with and to expect, may improve sort time
*
* @return string length 2048
*/
final public static function reorderNibbleArray(string $array, string $commonValue = "\x00") : string{
$result = str_repeat($commonValue, 2048);
if($array !== $result){
$i = 0;
for($x = 0; $x < 8; ++$x){
for($z = 0; $z < 16; ++$z){
$zx = (($z << 3) | $x);
for($y = 0; $y < 8; ++$y){
$j = (($y << 8) | $zx);
$j80 = ($j | 0x80);
if($array{$j} === $commonValue and $array{$j80} === $commonValue){
//values are already filled
}else{
$i1 = ord($array{$j});
$i2 = ord($array{$j80});
$result{$i} = chr(($i2 << 4) | ($i1 & 0x0f));
$result{$i | 0x80} = chr(($i1 >> 4) | ($i2 & 0xf0));
} }
$i++;
} }
} }
$i += 128;
} }
return $result;
} }
return $result; /**
} * Re-orders a nibble array (YZX -> XZY and vice versa)
*
* @param string $array length 2048
* @param string $commonValue length 1 common value to fill the default array with and to expect, may improve sort time
*
* @return string length 2048
*/
final public static function reorderNibbleArray(string $array, string $commonValue = "\x00") : string{
$result = str_repeat($commonValue, 2048);
/** if($array !== $result){
* Converts pre-MCPE-1.0 biome color array to biome ID array. $i = 0;
* for($x = 0; $x < 8; ++$x){
* @param int[] $array of biome color values for($z = 0; $z < 16; ++$z){
* $zx = (($z << 3) | $x);
* @return string for($y = 0; $y < 8; ++$y){
*/ $j = (($y << 8) | $zx);
public static function convertBiomeColors(array $array) : string{ $j80 = ($j | 0x80);
$result = str_repeat("\x00", 256); if($array{$j} === $commonValue and $array{$j80} === $commonValue){
foreach($array as $i => $color){ //values are already filled
$result{$i} = chr(($color >> 24) & 0xff); }else{
$i1 = ord($array{$j});
$i2 = ord($array{$j80});
$result{$i} = chr(($i2 << 4) | ($i1 & 0x0f));
$result{$i | 0x80} = chr(($i1 >> 4) | ($i2 & 0xf0));
}
$i++;
}
}
$i += 128;
}
}
return $result;
} }
return $result;
}
/**
* Converts pre-MCPE-1.0 biome color array to biome ID array.
*
* @param int[] $array of biome color values
*
* @return string
*/
public static function convertBiomeColors(array $array) : string{
$result = str_repeat("\x00", 256);
foreach($array as $i => $color){
$result{$i} = chr(($color >> 24) & 0xff);
}
return $result;
}
}
} }

View File

@ -38,6 +38,7 @@ use pocketmine\nbt\tag\{
ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag
}; };
use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\Player;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\BinaryStream; use pocketmine\utils\BinaryStream;
@ -501,7 +502,9 @@ class LevelDB extends BaseLevelProvider{
$this->db->put($index . self::TAG_STATE_FINALISATION, chr(self::FINALISATION_DONE)); $this->db->put($index . self::TAG_STATE_FINALISATION, chr(self::FINALISATION_DONE));
$this->writeTags($chunk->getTiles(), $index . self::TAG_BLOCK_ENTITY); $this->writeTags($chunk->getTiles(), $index . self::TAG_BLOCK_ENTITY);
$this->writeTags($chunk->getEntities(), $index . self::TAG_ENTITY); $this->writeTags(array_filter($chunk->getEntities(), function(Entity $entity) : bool{
return !($entity instanceof Player);
}), $index . self::TAG_ENTITY);
$this->db->delete($index . self::TAG_DATA_2D_LEGACY); $this->db->delete($index . self::TAG_DATA_2D_LEGACY);
$this->db->delete($index . self::TAG_LEGACY_TERRAIN); $this->db->delete($index . self::TAG_LEGACY_TERRAIN);
@ -514,8 +517,9 @@ class LevelDB extends BaseLevelProvider{
private function writeTags(array $targets, string $index){ private function writeTags(array $targets, string $index){
$nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt = new NBT(NBT::LITTLE_ENDIAN);
$out = []; $out = [];
/** @var Entity|Tile $target */
foreach($targets as $target){ foreach($targets as $target){
if(!$target->closed){ if(!$target->isClosed()){
$target->saveNBT(); $target->saveNBT();
$out[] = $target->namedtag; $out[] = $target->namedtag;
} }

View File

@ -133,6 +133,8 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
public function handleEncapsulated($identifier, EncapsulatedPacket $packet, $flags){ public function handleEncapsulated($identifier, EncapsulatedPacket $packet, $flags){
if(isset($this->players[$identifier])){ if(isset($this->players[$identifier])){
//get this now for blocking in case the player was closed before the exception was raised
$address = $this->players[$identifier]->getAddress();
try{ try{
if($packet->buffer !== ""){ if($packet->buffer !== ""){
$pk = $this->getPacket($packet->buffer); $pk = $this->getPacket($packet->buffer);
@ -143,7 +145,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
$logger->debug("Packet " . (isset($pk) ? get_class($pk) : "unknown") . " 0x" . bin2hex($packet->buffer)); $logger->debug("Packet " . (isset($pk) ? get_class($pk) : "unknown") . " 0x" . bin2hex($packet->buffer));
$logger->logException($e); $logger->logException($e);
$this->interface->blockAddress($this->players[$identifier]->getAddress(), 5); $this->interface->blockAddress($address, 5);
} }
} }
} }

View File

@ -34,11 +34,11 @@ class PlaySoundPacket extends DataPacket{
/** @var string */ /** @var string */
public $soundName; public $soundName;
/** @var int */ /** @var float */
public $x; public $x;
/** @var int */ /** @var float */
public $y; public $y;
/** @var int */ /** @var float */
public $z; public $z;
/** @var float */ /** @var float */
public $volume; public $volume;
@ -48,13 +48,16 @@ class PlaySoundPacket extends DataPacket{
protected function decodePayload(){ protected function decodePayload(){
$this->soundName = $this->getString(); $this->soundName = $this->getString();
$this->getBlockPosition($this->x, $this->y, $this->z); $this->getBlockPosition($this->x, $this->y, $this->z);
$this->x /= 8;
$this->y /= 8;
$this->z /= 8;
$this->volume = $this->getLFloat(); $this->volume = $this->getLFloat();
$this->pitch = $this->getLFloat(); $this->pitch = $this->getLFloat();
} }
protected function encodePayload(){ protected function encodePayload(){
$this->putString($this->soundName); $this->putString($this->soundName);
$this->putBlockPosition($this->x, $this->y, $this->z); $this->putBlockPosition((int) ($this->x * 8), (int) ($this->y * 8), (int) ($this->z * 8));
$this->putLFloat($this->volume); $this->putLFloat($this->volume);
$this->putLFloat($this->pitch); $this->putLFloat($this->pitch);
} }

View File

@ -23,12 +23,15 @@ declare(strict_types=1);
namespace pocketmine\plugin; namespace pocketmine\plugin;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\permission\Permission; use pocketmine\permission\Permission;
class PluginDescription{ class PluginDescription{
private $name; private $name;
private $main; private $main;
private $api; private $api;
/** @var int[] */
private $compatibleMcpeProtocols = [];
private $extensions = []; private $extensions = [];
private $depend = []; private $depend = [];
private $softDepend = []; private $softDepend = [];
@ -71,11 +74,13 @@ class PluginDescription{
$this->name = str_replace(" ", "_", $this->name); $this->name = str_replace(" ", "_", $this->name);
$this->version = (string) $plugin["version"]; $this->version = (string) $plugin["version"];
$this->main = $plugin["main"]; $this->main = $plugin["main"];
$this->api = array_map(function($v){ return (string) $v; }, !is_array($plugin["api"]) ? [$plugin["api"]] : $plugin["api"]);
if(stripos($this->main, "pocketmine\\") === 0){ if(stripos($this->main, "pocketmine\\") === 0){
throw new PluginException("Invalid PluginDescription main, cannot start within the PocketMine namespace"); throw new PluginException("Invalid PluginDescription main, cannot start within the PocketMine namespace");
} }
$this->api = array_map("strval", (array) $plugin["api"] ?? []);
$this->compatibleMcpeProtocols = array_map("intval", (array) ($plugin["mcpe-protocol"] ?? []));
if(isset($plugin["commands"]) and is_array($plugin["commands"])){ if(isset($plugin["commands"]) and is_array($plugin["commands"])){
$this->commands = $plugin["commands"]; $this->commands = $plugin["commands"];
} }
@ -94,22 +99,17 @@ class PluginDescription{
$this->extensions[$k] = is_array($v) ? $v : [$v]; $this->extensions[$k] = is_array($v) ? $v : [$v];
} }
} }
if(isset($plugin["softdepend"])){
$this->softDepend = (array) $plugin["softdepend"];
}
if(isset($plugin["loadbefore"])){
$this->loadBefore = (array) $plugin["loadbefore"];
}
if(isset($plugin["website"])){ $this->softDepend = (array) ($plugin["softdepend"] ?? $this->softDepend);
$this->website = $plugin["website"];
} $this->loadBefore = (array) ($plugin["loadbefore"] ?? $this->loadBefore);
if(isset($plugin["description"])){
$this->description = $plugin["description"]; $this->website = (string) ($plugin["website"] ?? $this->website);
}
if(isset($plugin["prefix"])){ $this->description = (string) ($plugin["description"] ?? $this->description);
$this->prefix = $plugin["prefix"];
} $this->prefix = (string) ($plugin["prefix"] ?? $this->prefix);
if(isset($plugin["load"])){ if(isset($plugin["load"])){
$order = strtoupper($plugin["load"]); $order = strtoupper($plugin["load"]);
if(!defined(PluginLoadOrder::class . "::" . $order)){ if(!defined(PluginLoadOrder::class . "::" . $order)){
@ -147,6 +147,13 @@ class PluginDescription{
return $this->api; return $this->api;
} }
/**
* @return int[]
*/
public function getCompatibleMcpeProtocols() : array{
return $this->compatibleMcpeProtocols;
}
/** /**
* @return string[] * @return string[]
*/ */

View File

@ -32,6 +32,7 @@ use pocketmine\event\HandlerList;
use pocketmine\event\Listener; use pocketmine\event\Listener;
use pocketmine\event\Timings; use pocketmine\event\Timings;
use pocketmine\event\TimingsHandler; use pocketmine\event\TimingsHandler;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\permission\Permissible; use pocketmine\permission\Permissible;
use pocketmine\permission\Permission; use pocketmine\permission\Permission;
use pocketmine\Server; use pocketmine\Server;
@ -237,7 +238,7 @@ class PluginManager{
continue; continue;
} }
$pluginNumbers = array_map("intval", explode(".", $pluginApi[0])); $pluginNumbers = array_map("intval", array_pad(explode(".", $pluginApi[0]), 3, "0")); //plugins might specify API like "3.0" or "3"
$serverNumbers = array_map("intval", explode(".", $serverApi[0])); $serverNumbers = array_map("intval", explode(".", $serverApi[0]));
if($pluginNumbers[0] !== $serverNumbers[0]){ //Completely different API version if($pluginNumbers[0] !== $serverNumbers[0]){ //Completely different API version
@ -254,10 +255,24 @@ class PluginManager{
} }
if($compatible === false){ if($compatible === false){
$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.incompatibleAPI"])); $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
$name,
$this->server->getLanguage()->translateString("%pocketmine.plugin.incompatibleAPI", [implode(", ", $description->getCompatibleApis())])
]));
continue; continue;
} }
if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){
$serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL];
if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){
$this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
$name,
$this->server->getLanguage()->translateString("%pocketmine.plugin.incompatibleProtocol", [implode(", ", $pluginMcpeProtocols)])
]));
continue;
}
}
$plugins[$name] = $file; $plugins[$name] = $file;
$softDependencies[$name] = $description->getSoftDepend(); $softDependencies[$name] = $description->getSoftDepend();
@ -287,7 +302,10 @@ class PluginManager{
if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
unset($dependencies[$name][$key]); unset($dependencies[$name][$key]);
}elseif(!isset($plugins[$dependency])){ }elseif(!isset($plugins[$dependency])){
$this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.unknownDependency"])); $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [
$name,
$this->server->getLanguage()->translateString("%pocketmine.plugin.unknownDependency", [$dependency])
]));
break; break;
} }
} }

View File

@ -92,9 +92,9 @@ class AsyncPool{
$this->taskWorkers[$task->getTaskId()] = $worker; $this->taskWorkers[$task->getTaskId()] = $worker;
} }
public function submitTask(AsyncTask $task){ public function submitTask(AsyncTask $task) : int{
if(isset($this->tasks[$task->getTaskId()]) or $task->isGarbage()){ if(isset($this->tasks[$task->getTaskId()]) or $task->isGarbage()){
return; return -1;
} }
$selectedWorker = mt_rand(0, $this->size - 1); $selectedWorker = mt_rand(0, $this->size - 1);
@ -107,6 +107,7 @@ class AsyncPool{
} }
$this->submitTaskToWorker($task, $selectedWorker); $this->submitTaskToWorker($task, $selectedWorker);
return $selectedWorker;
} }
private function removeTask(AsyncTask $task, bool $force = false){ private function removeTask(AsyncTask $task, bool $force = false){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
/** /**
* Task scheduling related classes * Task scheduling related classes
*/ */
namespace pocketmine\scheduler; namespace pocketmine\scheduler;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
@ -75,16 +76,16 @@ class ServerScheduler{
* *
* @param AsyncTask $task * @param AsyncTask $task
* *
* @return void * @return int
*/ */
public function scheduleAsyncTask(AsyncTask $task){ public function scheduleAsyncTask(AsyncTask $task) : int{
if($task->getTaskId() !== null){ if($task->getTaskId() !== null){
throw new \UnexpectedValueException("Attempt to schedule the same AsyncTask instance twice"); throw new \UnexpectedValueException("Attempt to schedule the same AsyncTask instance twice");
} }
$id = $this->nextId(); $id = $this->nextId();
$task->setTaskId($id); $task->setTaskId($id);
$task->progressUpdates = new \Threaded; $task->progressUpdates = new \Threaded;
$this->asyncPool->submitTask($task); return $this->asyncPool->submitTask($task);
} }
/** /**

View File

@ -64,8 +64,31 @@ class Sign extends Spawnable{
unset($this->namedtag->Creator); unset($this->namedtag->Creator);
} }
/**
* Changes contents of the specific lines to the string provided.
* Leaves contents of the specifc lines as is if null is provided.
*
* @param null|string $line1
* @param null|string $line2
* @param null|string $line3
* @param null|string $line4
*
* @return bool
*/
public function setText($line1 = "", $line2 = "", $line3 = "", $line4 = ""){ public function setText($line1 = "", $line2 = "", $line3 = "", $line4 = ""){
$this->text = [$line1, $line2, $line3, $line4]; if($line1 !== null){
$this->text[0] = $line1;
}
if($line2 !== null){
$this->text[1] = $line2;
}
if($line3 !== null){
$this->text[2] = $line3;
}
if($line4 !== null){
$this->text[3] = $line4;
}
$this->onChanged(); $this->onChanged();
} }

View File

@ -180,6 +180,10 @@ abstract class Tile extends Position{
$this->level->updateTiles[$this->id] = $this; $this->level->updateTiles[$this->id] = $this;
} }
public function isClosed() : bool{
return $this->closed;
}
public function __destruct(){ public function __destruct(){
$this->close(); $this->close();
} }

@ -1 +1 @@
Subproject commit 1fee79e4aac0f958ab720606e223b0aa690f5c47 Subproject commit 75b213db26755f67726784e0d5a36608158168cd