diff --git a/src/pocketmine/block/BlockFactory.php b/src/pocketmine/block/BlockFactory.php index b1573b6c23..4db1f4b9e6 100644 --- a/src/pocketmine/block/BlockFactory.php +++ b/src/pocketmine/block/BlockFactory.php @@ -114,6 +114,7 @@ class BlockFactory{ self::register(new DoublePlant(new BID(Block::DOUBLE_PLANT, 5), "Peony")); self::register(new DoubleTallGrass(new BID(Block::DOUBLE_PLANT, 2), "Double Tallgrass")); self::register(new DoubleTallGrass(new BID(Block::DOUBLE_PLANT, 3), "Large Fern")); + self::register(new DragonEgg(new BID(Block::DRAGON_EGG), "Dragon Egg")); self::register(new Emerald(new BID(Block::EMERALD_BLOCK), "Emerald Block")); self::register(new EmeraldOre(new BID(Block::EMERALD_ORE), "Emerald Ore")); self::register(new EnchantingTable(new BID(Block::ENCHANTING_TABLE, 0, null, \pocketmine\tile\EnchantTable::class), "Enchanting Table")); diff --git a/src/pocketmine/block/DragonEgg.php b/src/pocketmine/block/DragonEgg.php new file mode 100644 index 0000000000..8879681665 --- /dev/null +++ b/src/pocketmine/block/DragonEgg.php @@ -0,0 +1,87 @@ +teleport(); + return true; + } + + public function onAttack(Item $item, int $face, ?Player $player = null) : bool{ + $this->teleport(); + return true; + } + + protected function teleport() : void{ + for($tries = 0; $tries < 16; ++$tries){ + $block = $this->level->getBlockAt( + $this->x + mt_rand(-16, 16), + max(0, min(Level::Y_MAX - 1, $this->y + mt_rand(-8, 8))), + $this->z + mt_rand(-16, 16) + ); + if($block instanceof Air){ + $this->level->addParticle($this, new DragonEggTeleportParticle($this->x - $block->x, $this->y - $block->y, $this->z - $block->z)); + //TODO: add events + $this->level->setBlock($this, BlockFactory::get(Block::AIR)); + $this->level->setBlock($block, $this); + break; + } + } + } +} diff --git a/src/pocketmine/level/particle/DragonEggTeleportParticle.php b/src/pocketmine/level/particle/DragonEggTeleportParticle.php new file mode 100644 index 0000000000..65b2e75408 --- /dev/null +++ b/src/pocketmine/level/particle/DragonEggTeleportParticle.php @@ -0,0 +1,66 @@ +xDiff = self::boundOrThrow($xDiff); + $this->yDiff = self::boundOrThrow($yDiff); + $this->zDiff = self::boundOrThrow($zDiff); + } + + private static function boundOrThrow(int $v) : int{ + if($v < -255 or $v > 255){ + throw new \InvalidArgumentException("Value must be between -255 and 255"); + } + return $v; + } + + public function encode(Vector3 $pos){ + $pk = new LevelEventPacket(); + $pk->evid = LevelEventPacket::EVENT_PARTICLE_DRAGON_EGG_TELEPORT; + $pk->position = $pos; + $pk->data = + ($this->zDiff < 0 ? 1 << 26 : 0) | + ($this->yDiff < 0 ? 1 << 25 : 0) | + ($this->xDiff < 0 ? 1 << 24 : 0) | + (abs($this->xDiff) << 16) | + (abs($this->yDiff) << 8) | + abs($this->zDiff); + + return $pk; + } +} diff --git a/src/pocketmine/network/mcpe/protocol/LevelEventPacket.php b/src/pocketmine/network/mcpe/protocol/LevelEventPacket.php index aa3fc980ce..73510dca7b 100644 --- a/src/pocketmine/network/mcpe/protocol/LevelEventPacket.php +++ b/src/pocketmine/network/mcpe/protocol/LevelEventPacket.php @@ -81,6 +81,7 @@ class LevelEventPacket extends DataPacket implements ClientboundPacket{ public const EVENT_PARTICLE_BLOCK_FORCE_FIELD = 2008; public const EVENT_PARTICLE_PROJECTILE_HIT = 2009; + public const EVENT_PARTICLE_DRAGON_EGG_TELEPORT = 2010; public const EVENT_PARTICLE_ENDERMAN_TELEPORT = 2013; public const EVENT_PARTICLE_PUNCH_BLOCK = 2014;