diff --git a/src/BlockHorizons/Fireworks/Loader.php b/src/BlockHorizons/Fireworks/Loader.php index 6167880..cd498af 100644 --- a/src/BlockHorizons/Fireworks/Loader.php +++ b/src/BlockHorizons/Fireworks/Loader.php @@ -1,6 +1,5 @@ register(new Fireworks(new ItemIdentifier(ItemIds::FIREWORKS, 0), "Fireworks"), true); - EntityFactory::getInstance()->register(FireworksRocket::class, static function (World $world, CompoundTag $nbt): FireworksRocket { - return new FireworksRocket(EntityDataHelper::parseLocation($nbt, $world), ItemFactory::getInstance()->get(ItemIds::FIREWORKS)); - }, ["FireworksRocket", EntityIds::FIREWORKS_ROCKET], EntityLegacyIds::FIREWORKS_ROCKET); - } + public function onEnable(): void + { + $item = new Fireworks(new ItemIdentifier(ItemIds::FIREWORKS, 0), "Fireworks"); + ItemFactory::getInstance()->register($item, true); + EntityFactory::getInstance()->register(FireworksRocket::class, static function (World $world, CompoundTag $nbt) use ($item): FireworksRocket { + return new FireworksRocket(EntityDataHelper::parseLocation($nbt, $world), $item); + }, ["FireworksRocket", EntityIds::FIREWORKS_ROCKET], EntityLegacyIds::FIREWORKS_ROCKET); + } } \ No newline at end of file diff --git a/src/BlockHorizons/Fireworks/entity/FireworksRocket.php b/src/BlockHorizons/Fireworks/entity/FireworksRocket.php index fb1fdc2..931b62d 100644 --- a/src/BlockHorizons/Fireworks/entity/FireworksRocket.php +++ b/src/BlockHorizons/Fireworks/entity/FireworksRocket.php @@ -12,114 +12,119 @@ use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class FireworksRocket extends Entity { - - public const DATA_FIREWORK_ITEM = 16; //firework item - - public static function getNetworkTypeId(): string - { - return EntityIds::FIREWORKS_ROCKET; - } - - /** @var int */ - protected $lifeTime = 0; - /** @var Fireworks */ - protected $fireworks; - - public function __construct(Location $location, Fireworks $fireworks, ?int $lifeTime = null) - { - $this->fireworks = $fireworks; - parent::__construct($location, $fireworks->getNamedTag()); - $this->setMotion(new Vector3(0.001, 0.05, 0.001)); - - if ($fireworks->getNamedTag()->getCompoundTag("Fireworks") !== null) { - $this->setLifeTime($lifeTime ?? $fireworks->getRandomizedFlightDuration()); - } - - $location->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_LAUNCH, $this->location->asVector3())); - } - - protected function tryChangeMovement(): void - { - $this->motion->x *= 1.15; - $this->motion->y += 0.04; - $this->motion->z *= 1.15; - } - - public function entityBaseTick(int $tickDiff = 1): bool - { - if ($this->closed) { - return false; - } - - $hasUpdate = parent::entityBaseTick($tickDiff); - if ($this->doLifeTimeTick()) { - $hasUpdate = true; - } - - return $hasUpdate; - } - - public function setLifeTime(int $life): void - { - $this->lifeTime = $life; - } - - protected function doLifeTimeTick(): bool - { - if (--$this->lifeTime < 0 && !$this->isFlaggedForDespawn()) { - $this->doExplosionAnimation(); - $this->playSounds(); - $this->flagForDespawn(); - return true; - } - - return false; - } - - protected function doExplosionAnimation(): void - { - $this->broadcastAnimation(new FireworkParticleAnimation($this), $this->getViewers()); - } - - public function playSounds(): void - { - // This late in, there's 0 chance fireworks tag is null - $fireworksTag = $this->fireworks->getNamedTag()->getCompoundTag("Fireworks"); - $explosionsTag = $fireworksTag->getListTag("Explosions"); - if ($explosionsTag === null) { - // We don't throw an error here since there are fireworks that can die without noise or particles, - // which means they are lacking an explosion tag. - return; - } - - foreach ($explosionsTag->getValue() as $info) { - if ($info instanceof CompoundTag) { - if ($info->getByte("FireworkType", 0) === Fireworks::TYPE_HUGE_SPHERE) { - $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_LARGE_BLAST, $this->location->asVector3())); - } else { - $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BLAST, $this->location->asVector3())); - } - - if ($info->getByte("FireworkFlicker", 0) === 1) { - $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_TWINKLE, $this->location->asVector3())); - } - } - } - } - - public function syncNetworkData(EntityMetadataCollection $properties): void - { - parent::syncNetworkData($properties); - $properties->setCompoundTag(self::DATA_FIREWORK_ITEM, $this->fireworks->getNamedTag()); - } - - protected function getInitialSizeInfo(): EntitySizeInfo - { - return new EntitySizeInfo(0.25, 0.25); - } + public const DATA_FIREWORK_ITEM = 16; //firework item + protected int $lifeTime = 0; + protected Fireworks $fireworks; + + /** + * @throws \Exception + */ + public function __construct(Location $location, Fireworks $fireworks, ?int $lifeTime = null) + { + $this->fireworks = $fireworks; + parent::__construct($location, $fireworks->getNamedTag()); + $this->setMotion(new Vector3(0.001, 0.05, 0.001)); + + if ($fireworks->getNamedTag()->getCompoundTag("Fireworks") !== null) { + $this->setLifeTime($lifeTime ?? $fireworks->getRandomizedFlightDuration()); + } + + $location->getWorld()->broadcastPacketToViewers($location, LevelSoundEventPacket::create(LevelSoundEvent::LAUNCH, $location, -1, ":", false, false)); + } + + public function setLifeTime(int $life): void + { + $this->lifeTime = $life; + } + + public static function getNetworkTypeId(): string + { + return EntityIds::FIREWORKS_ROCKET; + } + + public function entityBaseTick(int $tickDiff = 1): bool + { + if ($this->closed) { + return false; + } + + $hasUpdate = parent::entityBaseTick($tickDiff); + if ($this->doLifeTimeTick()) { + $hasUpdate = true; + } + + return $hasUpdate; + } + + protected function doLifeTimeTick(): bool + { + if (--$this->lifeTime < 0 && !$this->isFlaggedForDespawn()) { + $this->doExplosionAnimation(); + $this->playSounds(); + $this->flagForDespawn(); + return true; + } + + return false; + } + + protected function doExplosionAnimation(): void + { + $this->broadcastAnimation(new FireworkParticleAnimation($this), $this->getViewers()); + } + + public function playSounds(): void + { + // This late in, there's 0 chance fireworks tag is null + $fireworksTag = $this->fireworks->getNamedTag()->getCompoundTag("Fireworks"); + if (!isset($fireworksTag)) { + return; + + } + $explosionsTag = $fireworksTag->getListTag("Explosions"); + if ($explosionsTag === null) { + // We don't throw an error here since there are fireworks that can die without noise or particles, + // which means they are lacking an explosion tag. + return; + } + + foreach ($explosionsTag->getValue() as $info) { + if ($info instanceof CompoundTag) { + if ($info->getByte("FireworkType", 0) === Fireworks::TYPE_HUGE_SPHERE) { + $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEvent::LARGE_BLAST, $this->location, -1, ":", false, false)); + } else { + $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEvent::BLAST, $this->location, -1, ":", false, false)); + } + + if ($info->getByte("FireworkFlicker", 0) === 1) { + $this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::create(LevelSoundEvent::TWINKLE, $this->location, -1, ":", false, false)); + } + } + } + } + + public function syncNetworkData(EntityMetadataCollection $properties): void + { + parent::syncNetworkData($properties); + $properties->setCompoundTag(self::DATA_FIREWORK_ITEM, new CacheableNbt($this->fireworks->getNamedTag())); + } + + protected function tryChangeMovement(): void + { + $this->motion->x *= 1.15; + $this->motion->y += 0.04; + $this->motion->z *= 1.15; + } + + protected function getInitialSizeInfo(): EntitySizeInfo + { + return new EntitySizeInfo(0.25, 0.25); + } } \ No newline at end of file diff --git a/src/BlockHorizons/Fireworks/entity/animation/FireworkParticleAnimation.php b/src/BlockHorizons/Fireworks/entity/animation/FireworkParticleAnimation.php index 2c46658..165e6cf 100644 --- a/src/BlockHorizons/Fireworks/entity/animation/FireworkParticleAnimation.php +++ b/src/BlockHorizons/Fireworks/entity/animation/FireworkParticleAnimation.php @@ -7,21 +7,21 @@ use BlockHorizons\Fireworks\entity\FireworksRocket; use pocketmine\entity\animation\Animation; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; class FireworkParticleAnimation implements Animation { - /** @var FireworksRocket */ - private $firework; + private FireworksRocket $firework; - public function __construct(FireworksRocket $firework) - { - $this->firework = $firework; - } + public function __construct(FireworksRocket $firework) + { + $this->firework = $firework; + } - public function encode(): array - { - return [ - ActorEventPacket::create($this->firework->getId(), ActorEventPacket::FIREWORK_PARTICLES, 0) - ]; - } + public function encode(): array + { + return [ + ActorEventPacket::create($this->firework->getId(), ActorEvent::FIREWORK_PARTICLES, 0) + ]; + } } \ No newline at end of file diff --git a/src/BlockHorizons/Fireworks/item/Fireworks.php b/src/BlockHorizons/Fireworks/item/Fireworks.php index 363ee0a..45998af 100644 --- a/src/BlockHorizons/Fireworks/item/Fireworks.php +++ b/src/BlockHorizons/Fireworks/item/Fireworks.php @@ -1,6 +1,6 @@ getExplosionsTag()->getByte("Flight", 1); - } + /** + * @throws \Exception + */ + public function getRandomizedFlightDuration(): int + { + return ($this->getFlightDuration() + 1) * 10 + random_int(0, 5) + random_int(0, 6); + } - public function getRandomizedFlightDuration(): int { - return ($this->getFlightDuration() + 1) * 10 + mt_rand(0, 5) + mt_rand(0, 6); - } + public function getFlightDuration(): int + { + return $this->getExplosionsTag()->getByte("Flight", 1); + } - public function setFlightDuration(int $duration): void { - $this->getExplosionsTag()->setByte("Flight", $duration); - } + protected function getExplosionsTag(): CompoundTag + { + $tag = $this->getNamedTag()->getCompoundTag("Fireworks"); + if ($tag === null) { + $this->getNamedTag()->setTag("Fireworks", $tag = CompoundTag::create()); + } + return $tag; + } - public function addExplosion(int $type, string $color, string $fade = "", bool $flicker = false, bool $trail = false): void + public function setFlightDuration(int $duration): void { - $tag = $this->getExplosionsTag(); - $explosions = $tag->getListTag("Explosions"); - if($explosions === null){ - $tag->setTag("Explosions", $explosions = new ListTag()); - } + $this->getExplosionsTag()->setByte("Flight", $duration); + } - $explosions->push(CompoundTag::create() - ->setByte("FireworkType", $type) - ->setByteArray("FireworkColor", $color) - ->setByteArray("FireworkFade", $fade) - ->setByte("FireworkFlicker", $flicker ? 1 : 0) - ->setByte("FireworkTrail", $trail ? 1 : 0) - ); - } + public function addExplosion(int $type, string $color, string $fade = "", bool $flicker = false, bool $trail = false): void + { + $tag = $this->getExplosionsTag(); + $explosions = $tag->getListTag("Explosions"); + if ($explosions === null) { + $tag->setTag("Explosions", $explosions = new ListTag()); + } - protected function getExplosionsTag(): CompoundTag - { - $tag = $this->getNamedTag()->getCompoundTag("Fireworks"); - if ($tag === null) { - $this->getNamedTag()->setTag("Fireworks", $tag = CompoundTag::create()); - } - return $tag; - } + $explosions->push(CompoundTag::create() + ->setByte("FireworkType", $type) + ->setByteArray("FireworkColor", $color) + ->setByteArray("FireworkFade", $fade) + ->setByte("FireworkFlicker", $flicker ? 1 : 0) + ->setByte("FireworkTrail", $trail ? 1 : 0) + ); + } - public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector): ItemUseResult - { - $entity = new FireworksRocket(Location::fromObject($blockReplace->getPosition()->add(0.5, 0, 0.5), $player->getWorld(), lcg_value() * 360, 90), $this); + public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector): ItemUseResult + { + $entity = new FireworksRocket(Location::fromObject($blockReplace->getPosition()->add(0.5, 0, 0.5), $player->getWorld(), lcg_value() * 360, 90), $this); - $this->pop(); - $entity->spawnToAll(); - //TODO: what if the entity was marked for deletion? - return ItemUseResult::SUCCESS(); - } + $this->pop(); + $entity->spawnToAll(); + //TODO: what if the entity was marked for deletion? + return ItemUseResult::SUCCESS(); + } }