Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated to PocketMine-MP 5.0.0 #27

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4222238
Port to API 4.0.0
Muqsit Apr 20, 2020
d0fb744
4.0 changes
Muqsit Apr 24, 2020
1777ade
4.0 changes to EntityFactory
Muqsit Apr 25, 2020
a09c186
4.0 changes
Muqsit May 4, 2020
6c6bf3b
4.0: Entity::NETWORK_ID -> Entity::getNetworkTypeId()
Muqsit May 18, 2020
970137c
4.0 changes
Muqsit May 24, 2020
1e24e7c
4.0: Changes to entity save data
Muqsit Jun 20, 2020
3bf14a3
Fix FireworksRocket crashing on spawn
Muqsit Jun 27, 2020
91d1623
4.0: Position::getWorldNonNull() -> Position::getWorld(), Item::__con…
Muqsit Jul 10, 2020
490b5f3
Fix #12, Fix #13, Use broadcastAnimation && syncNetworkData
inxomnyaa Dec 24, 2020
1f42817
Fix branch not building
inxomnyaa Dec 24, 2020
719a510
Fix fireworks not spawning
inxomnyaa Dec 24, 2020
96581ae
Add sounds
inxomnyaa Dec 24, 2020
fca1c5c
Merge pull request #15 from thebigsmileXD/4.0
Muqsit Dec 24, 2020
9f5dde8
4.0: width/height -> getInitialSizeInfo()
unickorn Mar 18, 2021
63655b8
Merge pull request #18 from Unickorn/4.0
Muqsit Mar 18, 2021
fdefc53
PM4: getPos() -> getPosition()
unickorn Sep 4, 2021
dc2a4f6
Merge pull request #20 from Unickorn/patch-1
Muqsit Sep 4, 2021
ceba835
Update to latest PocketMine-MP and fix fireworks not being nbt-deseri…
Wertzui123 May 17, 2022
c3b9f7e
Merge pull request #26 from Wertzui123/4.0
jasonw4331 Jun 5, 2022
ab7e600
Updated code to 5.0.0-ALPHA5
JavierLeon9966 Dec 1, 2022
fddb943
Bump api to 5.0.0
JavierLeon9966 Dec 1, 2022
a975d5a
Merge branch 'master' into pm5
JavierLeon9966 Jun 21, 2023
8d4da64
Do not save fireworks to disk
JavierLeon9966 Jun 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ Adds fireworks to your PocketMine server<br>
Download the compiled `.phar` format of Fireworks from the [Poggit CI](https://poggit.pmmp.io/ci/BlockHorizons/Fireworks).
## API
### Adding firework items to a player's inventory
Giving players fireworks is easy as pie. Here are some examples (where `$player` is a `\pocketmine\Player` object):
Giving players fireworks is easy as pie. Here are some examples (where `$player` is a `\pocketmine\player\Player`
object):
- **Base firework**
```php
/** @var Fireworks $fw */
Expand Down
4 changes: 2 additions & 2 deletions plugin.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Fireworks
main: BlockHorizons\Fireworks\Loader
api: ["3.9.0", "3.17.1"]
version: 0.0.4
api: 5.0.0
version: 0.0.4.1
20 changes: 10 additions & 10 deletions src/BlockHorizons/Fireworks/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@

namespace BlockHorizons\Fireworks;

use BlockHorizons\Fireworks\entity\FireworksRocket;
use BlockHorizons\Fireworks\item\Fireworks;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\data\bedrock\item\ItemTypeNames;
use pocketmine\data\bedrock\item\SavedItemData;
use pocketmine\item\ItemIdentifier;
use pocketmine\item\ItemTypeIds;
use pocketmine\plugin\PluginBase;
use pocketmine\world\format\io\GlobalItemDataHandlers;

class Loader extends PluginBase {
class Loader extends PluginBase
{

public function onEnable(): void
{
ItemFactory::registerItem(new Fireworks(), true);
Item::initCreativeItems(); //will load firework rockets from pocketmine's resources folder
if (!Entity::registerEntity(FireworksRocket::class, false, ["FireworksRocket", "minecraft:fireworks_rocket"])) {
$this->getLogger()->error("Failed to register FireworksRocket entity with savename 'FireworksRocket'");
}
$fireworks = new Fireworks(new ItemIdentifier(ItemTypeIds::newId()), "Fireworks");
GlobalItemDataHandlers::getSerializer()->map($fireworks, static fn() => new SavedItemData(ItemTypeNames::FIREWORK_ROCKET));
GlobalItemDataHandlers::getDeserializer()->map(ItemTypeNames::FIREWORK_ROCKET, static fn() => clone $fireworks);
}
}
123 changes: 100 additions & 23 deletions src/BlockHorizons/Fireworks/entity/FireworksRocket.php
Original file line number Diff line number Diff line change
@@ -1,73 +1,150 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

namespace BlockHorizons\Fireworks\entity;

use BlockHorizons\Fireworks\entity\animation\FireworkParticleAnimation;
use BlockHorizons\Fireworks\item\Fireworks;
use pocketmine\entity\Entity;
use pocketmine\level\Level;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
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 NETWORK_ID = Entity::FIREWORKS_ROCKET;
class FireworksRocket extends Entity
{

public const DATA_FIREWORK_ITEM = 16; //firework item

public $width = 0.25;
public $height = 0.25;
public static function getNetworkTypeId(): string
{
return EntityIds::FIREWORKS_ROCKET;
}

/** @var int */
protected $lifeTime = 0;
/** @var Fireworks */
protected $fireworks;

public function __construct(Level $level, CompoundTag $nbt, ?Fireworks $fireworks = null){
parent::__construct($level, $nbt);
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 !== null && $fireworks->getNamedTagEntry("Fireworks") instanceof CompoundTag) {
$this->propertyManager->setCompoundTag(self::DATA_FIREWORK_ITEM, $fireworks->getNamedTag());
$this->setLifeTime($fireworks->getRandomizedFlightDuration());
if ($fireworks->getNamedTag()->getCompoundTag("Fireworks") !== null) {
$this->setLifeTime($lifeTime ?? $fireworks->getRandomizedFlightDuration());
}

$level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_LAUNCH);
$location->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::nonActorSound(LevelSoundEvent::LAUNCH, $this->location->asVector3(), false));
}

protected function getInitialDragMultiplier(): float{
return 0.99;
}

protected function getInitialGravity(): float{
return 0.05;
}

protected function tryChangeMovement(): void {
/**
* TODO: The entity should be saved and loaded, but this is not possible.
* @see https://bugs.mojang.com/browse/MCPE-165230
*/
public function canSaveWithChunk(): bool{
return false;
}

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) {
public function entityBaseTick(int $tickDiff = 1): bool
{
if ($this->closed) {
return false;
}

$hasUpdate = parent::entityBaseTick($tickDiff);
if($this->doLifeTimeTick()) {
if ($this->doLifeTimeTick()) {
$hasUpdate = true;
}

return $hasUpdate;
}

public function setLifeTime(int $life): void {
public function setLifeTime(int $life): void
{
$this->lifeTime = $life;
}

protected function doLifeTimeTick(): bool {
if(!$this->isFlaggedForDespawn() and --$this->lifeTime < 0) {
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->broadcastEntityEvent(ActorEventPacket::FIREWORK_PARTICLES);
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::nonActorSound(LevelSoundEvent::LARGE_BLAST, $this->location->asVector3(), false));
} else {
$this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLAST, $this->location->asVector3(), false));
}

if ($info->getByte("FireworkFlicker", 0) === 1) {
$this->getWorld()->broadcastPacketToViewers($this->location, LevelSoundEventPacket::nonActorSound(LevelSoundEvent::TWINKLE, $this->location->asVector3(), false));
}
}
}
}

public function syncNetworkData(EntityMetadataCollection $properties): void
{
parent::syncNetworkData($properties);
$properties->setCompoundTag(self::DATA_FIREWORK_ITEM, new CacheableNbt($this->fireworks->getNamedTag()));
}

protected function getInitialSizeInfo(): EntitySizeInfo
{
return new EntitySizeInfo(0.25, 0.25);
}

public function saveNBT(): CompoundTag
{
$nbt = parent::saveNBT();
$nbt->setTag("Item", $this->fireworks->nbtSerialize());
return $nbt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace BlockHorizons\Fireworks\entity\animation;

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;

public function __construct(FireworksRocket $firework)
{
$this->firework = $firework;
}

public function encode(): array
{
return [
ActorEventPacket::create($this->firework->getId(), ActorEvent::FIREWORK_PARTICLES, 0)
];
}
}
65 changes: 32 additions & 33 deletions src/BlockHorizons/Fireworks/item/Fireworks.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

namespace BlockHorizons\Fireworks\item;

use BlockHorizons\Fireworks\entity\FireworksRocket;
use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\entity\Location;
use pocketmine\item\Item;
use pocketmine\item\ItemUseResult;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\Player;
use pocketmine\player\Player;

class Fireworks extends Item {

Expand Down Expand Up @@ -38,10 +40,6 @@ class Fireworks extends Item {
public const COLOR_GOLD = "\x0e";
public const COLOR_WHITE = "\x0f";

public function __construct(int $meta = 0) {
parent::__construct(self::FIREWORKS, $meta, "Fireworks");
}

public function getFlightDuration(): int {
return $this->getExplosionsTag()->getByte("Flight", 1);
}
Expand All @@ -51,41 +49,42 @@ public function getRandomizedFlightDuration(): int {
}

public function setFlightDuration(int $duration): void {
$tag = $this->getExplosionsTag();
$tag->setByte("Flight", $duration);
$this->setNamedTagEntry($tag);
$this->getExplosionsTag()->setByte("Flight", $duration);
}

public function addExplosion(int $type, string $color, string $fade = "", bool $flicker = false, bool $trail = false): void
{
$explosion = new CompoundTag();
$explosion->setByte("FireworkType", $type);
$explosion->setByteArray("FireworkColor", $color);
$explosion->setByteArray("FireworkFade", $fade);
$explosion->setByte("FireworkFlicker", $flicker ? 1 : 0);
$explosion->setByte("FireworkTrail", $trail ? 1 : 0);

$tag = $this->getExplosionsTag();
$explosions = $tag->getListTag("Explosions") ?? new ListTag("Explosions");
$explosions->push($explosion);
$tag->setTag($explosions);
$this->setNamedTagEntry($tag);
}
$explosions = $tag->getListTag("Explosions");
if($explosions === null){
$tag->setTag("Explosions", $explosions = new ListTag());
}

protected function getExplosionsTag(): CompoundTag {
return $this->getNamedTag()->getCompoundTag("Fireworks") ?? new CompoundTag("Fireworks");
$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 onActivate(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector): bool {
$nbt = Entity::createBaseNBT($blockReplace->add(0.5, 0, 0.5), new Vector3(0.001, 0.05, 0.001), lcg_value() * 360, 90);
protected function getExplosionsTag(): CompoundTag
{
$tag = $this->getNamedTag()->getCompoundTag("Fireworks");
if ($tag === null) {
$this->getNamedTag()->setTag("Fireworks", $tag = CompoundTag::create());
}
return $tag;
}

$entity = Entity::createEntity("FireworksRocket", $player->getLevel(), $nbt, $this);
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems): ItemUseResult
{
$entity = new FireworksRocket(Location::fromObject($blockReplace->getPosition()->add(0.5, 0, 0.5), $player->getWorld(), lcg_value() * 360, 90), $this);

if($entity instanceof Entity) {
--$this->count;
$entity->spawnToAll();
return true;
}
return false;
$this->pop();
$entity->spawnToAll();
//TODO: what if the entity was marked for deletion?
return ItemUseResult::SUCCESS();
}
}
}