diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index cc6b4abe4..401d1c1b7 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -2469,7 +2469,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()){ }elseif($this->isCreative()){ $item = $this->inventory->getItemInHand(); - if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){ + if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this, true) === true){ return true; } }elseif(!$this->inventory->getItemInHand()->equals($packet->item)){ @@ -2478,7 +2478,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $item = $this->inventory->getItemInHand(); $oldItem = clone $item; //TODO: Implement adventure mode checks - if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)){ + if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this, true)){ if(!$item->equals($oldItem) or $item->getCount() !== $oldItem->getCount()){ $this->inventory->setItemInHand($item); $this->inventory->sendHeldItem($this->hasSpawned); diff --git a/src/pocketmine/block/TNT.php b/src/pocketmine/block/TNT.php index 5b93b2d3a..e1faeac94 100644 --- a/src/pocketmine/block/TNT.php +++ b/src/pocketmine/block/TNT.php @@ -54,32 +54,35 @@ class TNT extends Solid{ public function onActivate(Item $item, Player $player = null){ if($item->getId() === Item::FLINT_STEEL){ $item->useOn($this); - $this->getLevel()->setBlock($this, new Air(), true); - - $mot = (new Random())->nextSignedFloat() * M_PI * 2; - $tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), new CompoundTag("", [ - "Pos" => new ListTag("Pos", [ - new DoubleTag("", $this->x + 0.5), - new DoubleTag("", $this->y), - new DoubleTag("", $this->z + 0.5) - ]), - "Motion" => new ListTag("Motion", [ - new DoubleTag("", -sin($mot) * 0.02), - new DoubleTag("", 0.2), - new DoubleTag("", -cos($mot) * 0.02) - ]), - "Rotation" => new ListTag("Rotation", [ - new FloatTag("", 0), - new FloatTag("", 0) - ]), - "Fuse" => new ByteTag("Fuse", 80) - ])); - - $tnt->spawnToAll(); - + $this->ignite(); return true; } return false; } + + public function ignite(int $fuse = 80){ + $this->getLevel()->setBlock($this, new Air(), true); + + $mot = (new Random())->nextSignedFloat() * M_PI * 2; + $tnt = Entity::createEntity("PrimedTNT", $this->getLevel(), new CompoundTag("", [ + "Pos" => new ListTag("Pos", [ + new DoubleTag("", $this->x + 0.5), + new DoubleTag("", $this->y), + new DoubleTag("", $this->z + 0.5) + ]), + "Motion" => new ListTag("Motion", [ + new DoubleTag("", -sin($mot) * 0.02), + new DoubleTag("", 0.2), + new DoubleTag("", -cos($mot) * 0.02) + ]), + "Rotation" => new ListTag("Rotation", [ + new FloatTag("", 0), + new FloatTag("", 0) + ]), + "Fuse" => new ByteTag("Fuse", $fuse) + ])); + + $tnt->spawnToAll(); + } } \ No newline at end of file diff --git a/src/pocketmine/entity/PrimedTNT.php b/src/pocketmine/entity/PrimedTNT.php index d547d5bb9..9eb7825d1 100644 --- a/src/pocketmine/entity/PrimedTNT.php +++ b/src/pocketmine/entity/PrimedTNT.php @@ -26,6 +26,7 @@ use pocketmine\event\entity\ExplosionPrimeEvent; use pocketmine\level\Explosion; use pocketmine\nbt\tag\ByteTag; use pocketmine\network\mcpe\protocol\AddEntityPacket; +use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\Player; class PrimedTNT extends Entity implements Explosive{ @@ -62,6 +63,8 @@ class PrimedTNT extends Entity implements Explosive{ $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_IGNITED, true); $this->setDataProperty(self::DATA_FUSE_LENGTH, self::DATA_TYPE_INT, $this->fuse); + + $this->level->broadcastLevelEvent($this, LevelEventPacket::EVENT_SOUND_IGNITE); } diff --git a/src/pocketmine/level/Explosion.php b/src/pocketmine/level/Explosion.php index 0fe5b3e6b..22e203160 100644 --- a/src/pocketmine/level/Explosion.php +++ b/src/pocketmine/level/Explosion.php @@ -22,6 +22,7 @@ namespace pocketmine\level; use pocketmine\block\Block; +use pocketmine\block\TNT; use pocketmine\entity\Entity; use pocketmine\event\block\BlockUpdateEvent; use pocketmine\event\entity\EntityDamageByBlockEvent; @@ -39,6 +40,7 @@ use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\ListTag; use pocketmine\network\mcpe\protocol\ExplodePacket; +use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\utils\Random; class Explosion{ @@ -171,26 +173,8 @@ class Explosion{ $air = Item::get(Item::AIR); foreach($this->affectedBlocks as $block){ - if($block->getId() === Block::TNT){ - $mot = (new Random())->nextSignedFloat() * M_PI * 2; - $tnt = Entity::createEntity("PrimedTNT", $this->level, new CompoundTag("", [ - "Pos" => new ListTag("Pos", [ - new DoubleTag("", $block->x + 0.5), - new DoubleTag("", $block->y), - new DoubleTag("", $block->z + 0.5) - ]), - "Motion" => new ListTag("Motion", [ - new DoubleTag("", -sin($mot) * 0.02), - new DoubleTag("", 0.2), - new DoubleTag("", -cos($mot) * 0.02) - ]), - "Rotation" => new ListTag("Rotation", [ - new FloatTag("", 0), - new FloatTag("", 0) - ]), - "Fuse" => new ByteTag("Fuse", mt_rand(10, 30)) - ])); - $tnt->spawnToAll(); + if($block instanceof TNT){ + $block->ignite(mt_rand(10, 30)); }elseif(mt_rand(0, 100) < $yield){ foreach($block->getDrops($air) as $drop){ $this->level->dropItem($block->add(0.5, 0.5, 0.5), Item::get(...$drop)); @@ -223,6 +207,7 @@ class Explosion{ $this->level->addChunkPacket($source->x >> 4, $source->z >> 4, $pk); $this->level->addParticle(new HugeExplodeSeedParticle($source)); + $this->level->broadcastLevelSoundEvent($source, LevelSoundEventPacket::SOUND_EXPLODE); return true; } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index e3e00e723..f0a45b0c7 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -94,6 +94,7 @@ use pocketmine\network\mcpe\protocol\BatchPacket; use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\FullChunkDataPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\MoveEntityPacket; use pocketmine\network\mcpe\protocol\SetEntityMotionPacket; use pocketmine\network\mcpe\protocol\SetTimePacket; @@ -493,6 +494,38 @@ class Level implements ChunkManager, Metadatable{ } } + /** + * Broadcasts a LevelEvent to players in the area. This could be sound, particles, weather changes, etc. + * + * @param Vector3 $pos + * @param int $evid + * @param int $data + */ + public function broadcastLevelEvent(Vector3 $pos, int $evid, int $data = 0){ + $pk = new LevelEventPacket(); + $pk->evid = $evid; + $pk->data = $data; + list($pk->x, $pk->y, $pk->z) = [$pos->x, $pos->y, $pos->z]; + $this->addChunkPacket($pos->x >> 4, $pos->z >> 4, $pk); + } + + /** + * Broadcasts a LevelSoundEvent to players in the area. + * + * @param Vector3 $pos + * @param int $soundId + * @param int $pitch + * @param int $extraData + */ + public function broadcastLevelSoundEvent(Vector3 $pos, int $soundId, int $pitch = 1, int $extraData = -1){ + $pk = new LevelSoundEventPacket(); + $pk->sound = $soundId; + $pk->pitch = $pitch; + $pk->extraData = $extraData; + list($pk->x, $pk->y, $pk->z) = [$pos->x, $pos->y, $pos->z]; + $this->addChunkPacket($pos->x >> 4, $pos->z >> 4, $pk); + } + public function getAutoSave() : bool{ return $this->autoSave; } @@ -1657,10 +1690,11 @@ class Level implements ChunkManager, Metadatable{ * @param float $fy default 0.0 * @param float $fz default 0.0 * @param Player $player default null + * @param bool $playSound Whether to play a block-place sound if the block was placed successfully. * * @return bool */ - public function useItemOn(Vector3 $vector, Item &$item, int $face, float $fx = 0.0, float $fy = 0.0, float $fz = 0.0, Player $player = null) : bool{ + public function useItemOn(Vector3 $vector, Item &$item, int $face, float $fx = 0.0, float $fy = 0.0, float $fz = 0.0, Player $player = null, bool $playSound = false) : bool{ $target = $this->getBlock($vector); $block = $target->getSide($face); @@ -1783,6 +1817,10 @@ class Level implements ChunkManager, Metadatable{ return false; } + if($playSound){ + $this->broadcastLevelSoundEvent($hand, LevelSoundEventPacket::SOUND_PLACE, 1, $hand->getId()); + } + $item->setCount($item->getCount() - 1); if($item->getCount() <= 0){ $item = Item::get(Item::AIR, 0, 0); diff --git a/src/pocketmine/level/particle/DestroyBlockParticle.php b/src/pocketmine/level/particle/DestroyBlockParticle.php index 5ced4462f..869e02d84 100644 --- a/src/pocketmine/level/particle/DestroyBlockParticle.php +++ b/src/pocketmine/level/particle/DestroyBlockParticle.php @@ -31,7 +31,7 @@ class DestroyBlockParticle extends Particle{ public function __construct(Vector3 $pos, Block $b){ parent::__construct($pos->x, $pos->y, $pos->z); - $this->data = $b->getId() + ($b->getDamage() << 12); + $this->data = $b->getId() | ($b->getDamage() << 8); } public function encode(){