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

Implement firework rocket & firework star #5455

Open
wants to merge 63 commits into
base: minor-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
ba76a33
Implement Firework Rocket & Firework Star
IvanCraft623 Dec 16, 2022
06a9da3
Fix PHPStan
IvanCraft623 Dec 16, 2022
bd83e99
Make PHPStan happy
IvanCraft623 Dec 16, 2022
58605e7
...
IvanCraft623 Dec 16, 2022
d01a8c3
Implement explosion multi-color & firework star custom color
IvanCraft623 Dec 17, 2022
fd04e93
Add TODO comment
IvanCraft623 Dec 17, 2022
15b1281
Some API improvements
IvanCraft623 Dec 17, 2022
a0a4ace
Make PHPStan happy
IvanCraft623 Dec 17, 2022
21f0edf
shut up!
IvanCraft623 Dec 17, 2022
ce28e49
Simplification
IvanCraft623 Dec 19, 2022
d4e8692
Firework types name parity with vanilla
IvanCraft623 Dec 19, 2022
d20f685
FireworkRocketTypeIdMap: fixed uninitialized fields
IvanCraft623 Dec 19, 2022
80557d7
oops
IvanCraft623 Dec 19, 2022
98291ec
Remove unused var
IvanCraft623 Dec 23, 2022
6e22547
Call parent::onFirstUpdate()
IvanCraft623 Dec 23, 2022
66a8145
Merge branch 'next-major' into firework
IvanCraft623 Dec 24, 2022
4f6f667
Merge branch 'next-major' into firework
IvanCraft623 Dec 27, 2022
0ce16d8
Implement firework death message
IvanCraft623 Dec 28, 2022
a4e412e
Implement Explosive interface
IvanCraft623 Jan 4, 2023
6c3522c
Merge branch 'major-next' into firework
IvanCraft623 May 9, 2023
bb7ca1e
Use `addMotion` instead of mutating the vector directly
IvanCraft623 May 9, 2023
ff080d7
Use appropriate constant for firework item metadata
IvanCraft623 May 9, 2023
c850a7e
Throw `SavedDataLoadingException` on finding an unknown color
IvanCraft623 May 9, 2023
15b4c95
Make `encodeColors` static and move it near to `decodeColors`
IvanCraft623 May 9, 2023
252cfd6
Fix typo on `getColorMix` doc
IvanCraft623 May 9, 2023
e2fbb8e
Remove useless closures for sound getter
IvanCraft623 May 9, 2023
e90f3ad
Better use the new `Color::equals()` method :P
IvanCraft623 May 9, 2023
5a50525
Remove `clearCustomColor()` in favour of passing `null` to `setCustom…
IvanCraft623 May 9, 2023
1df07e9
Merge branch 'firework' of https://github.com/IvanCraft623/PocketMine…
IvanCraft623 May 9, 2023
1122009
Fix little cs
IvanCraft623 May 9, 2023
291c086
Apply dylan's CS suggestion
IvanCraft623 May 9, 2023
0b710a2
Fix flight duaration range to wrap into a signed byte range
IvanCraft623 May 9, 2023
69501b2
Document flight duration
IvanCraft623 May 9, 2023
87504e4
Make FireworkRocket setters fluent
IvanCraft623 May 9, 2023
d093d22
Make FireworkRocketExplosion immutable
IvanCraft623 May 9, 2023
4139342
Use lists instead of arrays for PHPStan
IvanCraft623 May 9, 2023
12dc6b2
Improve FireworkRocketExplosion documentation
IvanCraft623 May 9, 2023
1a2715d
Rename getMainColor method
IvanCraft623 May 9, 2023
70d3d7a
Remove hasCustomColor() method
IvanCraft623 May 9, 2023
43ccb80
Improve FireworkStar documentation
IvanCraft623 May 9, 2023
07ffb21
Fix typo in TAG_FLIGH_DURATION
IvanCraft623 May 9, 2023
8e1b661
Rename `FireworkTwinkleSound` to `FireworkCrackleSound`
IvanCraft623 May 9, 2023
05e5565
Fix PHPStan lints
IvanCraft623 May 9, 2023
c4ce574
Remove unused import
IvanCraft623 May 9, 2023
7390c7f
Implement default values
IvanCraft623 May 9, 2023
1b0d74b
Fix tipo
IvanCraft623 May 10, 2023
5295e0c
Merge branch 'firework' of https://github.com/IvanCraft623/PocketMine…
IvanCraft623 May 10, 2023
0f32e84
Accept explosions instead of the whole item
IvanCraft623 May 10, 2023
9d08d9b
Update getFlightDuration and setFlightDuration
IvanCraft623 May 10, 2023
086eeea
Merge branch 'major-next' into firework
dktapps May 10, 2023
eff8d85
Rename flightDuration => flightDurationMultiplier
IvanCraft623 May 10, 2023
b1e8ceb
Rename $fireworksTag=> $fireworkData
IvanCraft623 May 10, 2023
3a0b96a
Merge branch 'minor-next' into firework
IvanCraft623 Jun 4, 2023
2437e64
Merge branch 'minor-next' into firework
dktapps Oct 18, 2023
82b6ba9
Merge branch 'minor-next' into firework
IvanCraft623 Feb 19, 2024
fdbefd0
Don't flagForDespawn inside explode()
IvanCraft623 Feb 19, 2024
e6c52fd
Use of native enum case accessor
IvanCraft623 Feb 19, 2024
93147f0
Merge branch 'minor-next' into firework
IvanCraft623 Aug 18, 2024
8273978
Modernize the FireworkRocketType enum
IvanCraft623 Aug 18, 2024
d2b0fd5
Merge branch 'minor-next' into firework
IvanCraft623 Sep 1, 2024
609c4c6
Group some rocket types in a single case
IvanCraft623 Sep 1, 2024
60d9650
Merge branch 'minor-next' into firework
dktapps Nov 23, 2024
b112c59
Merge branch 'minor-next' into firework
IvanCraft623 Dec 2, 2024
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
45 changes: 45 additions & 0 deletions src/data/bedrock/FireworkRocketTypeIdMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\data\bedrock;

use pocketmine\item\FireworkRocketType;
use pocketmine\utils\SingletonTrait;

final class FireworkRocketTypeIdMap{
use SingletonTrait;
/** @phpstan-use IntSaveIdMapTrait<FireworkRocketType> */
use IntSaveIdMapTrait;

private function __construct(){
foreach(FireworkRocketType::cases() as $case){
$this->register(match($case){
FireworkRocketType::SMALL_BALL => FireworkRocketTypeIds::SMALL_BALL,
FireworkRocketType::LARGE_BALL => FireworkRocketTypeIds::LARGE_BALL,
FireworkRocketType::STAR => FireworkRocketTypeIds::STAR,
FireworkRocketType::CREEPER => FireworkRocketTypeIds::CREEPER,
FireworkRocketType::BURST => FireworkRocketTypeIds::BURST,
}, $case);
}
}
}
32 changes: 32 additions & 0 deletions src/data/bedrock/FireworkRocketTypeIds.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\data\bedrock;

final class FireworkRocketTypeIds{
public const SMALL_BALL = 0;
public const LARGE_BALL = 1;
public const STAR = 2;
public const CREEPER = 3;
public const BURST = 4;
}
10 changes: 10 additions & 0 deletions src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use pocketmine\data\bedrock\SuspiciousStewTypeIdMap;
use pocketmine\item\Banner;
use pocketmine\item\Dye;
use pocketmine\item\FireworkStar;
use pocketmine\item\GoatHorn;
use pocketmine\item\Item;
use pocketmine\item\Medicine;
Expand Down Expand Up @@ -238,6 +239,7 @@ private function register1to1ItemMappings() : void{
$this->map1to1Item(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
$this->map1to1Item(Ids::FEATHER, Items::FEATHER());
$this->map1to1Item(Ids::FERMENTED_SPIDER_EYE, Items::FERMENTED_SPIDER_EYE());
$this->map1to1Item(Ids::FIREWORK_ROCKET, Items::FIREWORK_ROCKET());
$this->map1to1Item(Ids::FIRE_CHARGE, Items::FIRE_CHARGE());
$this->map1to1Item(Ids::FISHING_ROD, Items::FISHING_ROD());
$this->map1to1Item(Ids::FLINT, Items::FLINT());
Expand Down Expand Up @@ -486,6 +488,14 @@ function(Banner $item, int $meta) : void{
},
fn(Banner $item) => DyeColorIdMap::getInstance()->toInvertedId($item->getColor())
);
$this->map1to1ItemWithMeta(
Ids::FIREWORK_STAR,
Items::FIREWORK_STAR(),
function(FireworkStar $item, int $meta) : void{
// Colors will be defined by CompoundTag deserialization.
},
fn(FireworkStar $item) => DyeColorIdMap::getInstance()->toInvertedId($item->getExplosion()->getFlashColor())
);
$this->map1to1ItemWithMeta(
Ids::GOAT_HORN,
Items::GOAT_HORN(),
Expand Down
41 changes: 41 additions & 0 deletions src/entity/animation/FireworkParticlesAnimation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\entity\animation;

use pocketmine\entity\object\FireworkRocket;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\types\ActorEvent;

final class FireworkParticlesAnimation implements Animation{

public function __construct(
private FireworkRocket $entity
){}

public function encode() : array{
return [
ActorEventPacket::create($this->entity->getId(), ActorEvent::FIREWORK_PARTICLES, 0)
];
}
}
201 changes: 201 additions & 0 deletions src/entity/object/FireworkRocket.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\entity\object;

use pocketmine\entity\animation\FireworkParticlesAnimation;
use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Explosive;
use pocketmine\entity\Living;
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\FireworkRocket as FireworkItem;
use pocketmine\item\FireworkRocketExplosion;
use pocketmine\math\VoxelRayTrace;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
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\entity\EntityMetadataProperties;
use pocketmine\utils\Utils;
use pocketmine\world\sound\FireworkCrackleSound;
use pocketmine\world\sound\FireworkLaunchSound;
use function count;
use function sqrt;

class FireworkRocket extends Entity implements Explosive{

public static function getNetworkTypeId() : string{ return EntityIds::FIREWORKS_ROCKET; }

/* Maximum number of ticks this will live for. */
protected int $lifeTicks;

/** @var FireworkRocketExplosion[] */
protected array $explosions = [];

/**
* @param FireworkRocketExplosion[] $explosions
*/
public function __construct(Location $location, int $lifeTicks, array $explosions, ?CompoundTag $nbt = null){
if ($lifeTicks < 0) {
throw new \InvalidArgumentException("Life ticks cannot be negative");
}
$this->lifeTicks = $lifeTicks;
$this->setExplosions($explosions);

parent::__construct($location, $nbt);
}

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

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

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

/**
* Returns maximum number of ticks this will live for.
*/
public function getLifeTicks() : int{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getMaxAgeTicks() would be more clear IMO

return $this->lifeTicks;
}

/**
* Sets maximum number of ticks this will live for.
*
* @return $this
*/
public function setLifeTicks(int $lifeTicks) : self{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto here

if ($lifeTicks < 0) {
throw new \InvalidArgumentException("Life ticks cannot be negative");
}
$this->lifeTicks = $lifeTicks;
return $this;
}

/**
* @return FireworkRocketExplosion[]
*/
public function getExplosions() : array{
return $this->explosions;
}

/**
* @param FireworkRocketExplosion[] $explosions
*
* @return $this
*/
public function setExplosions(array $explosions) : self{
Utils::validateArrayValueType($explosions, function(FireworkRocketExplosion $_) : void{});
$this->explosions = $explosions;
return $this;
}

/**
* TODO: The entity should be saved and loaded, but this is not possible.
* @see https://bugs.mojang.com/browse/MCPE-165230
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not liking this. We should still save & restore them in PM, regardless of vanilla bugs that don't store them.

*/
public function canSaveWithChunk() : bool{
return false;
}

protected function onFirstUpdate(int $currentTick) : void{
parent::onFirstUpdate($currentTick);

$this->broadcastSound(new FireworkLaunchSound());
}

protected function entityBaseTick(int $tickDiff = 1) : bool{
$hasUpdate = parent::entityBaseTick($tickDiff);

if(!$this->isFlaggedForDespawn()){
$this->addMotion($this->motion->x * 0.15, 0.04, $this->motion->z * 0.15);

if($this->ticksLived >= $this->lifeTicks){
$this->flagForDespawn();
$this->explode();
}
}

return $hasUpdate;
}

public function explode() : void{
if(($expCount = count($this->explosions)) !== 0){
$this->broadcastAnimation(new FireworkParticlesAnimation($this));
foreach($this->explosions as $explosion){
$this->broadcastSound($explosion->getType()->getExplosionSound());
if($explosion->willTwinkle()){
$this->broadcastSound(new FireworkCrackleSound());
}
}

$force = ($expCount * 2) + 5;
foreach($this->getWorld()->getCollidingEntities($this->getBoundingBox()->expandedCopy(5, 5, 5), $this) as $entity){
if(!$entity instanceof Living){
continue;
}

$position = $entity->getEyePos();
$distance = $position->distance($this->location);
if($distance > 5){
continue;
}

$world = $this->getWorld();

//check for obstructing blocks
foreach(VoxelRayTrace::betweenPoints($this->location, $position) as $pos){
if($world->getBlockAt((int) $pos->x, (int) $pos->y, (int) $pos->z)->isSolid()){
continue 2;
}
}

$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_EXPLOSION, $force * sqrt((5 - $distance) / 5));
$entity->attack($ev);
}
}
}

public function canBeCollidedWith() : bool{
return false;
}

protected function syncNetworkData(EntityMetadataCollection $properties) : void{
parent::syncNetworkData($properties);

$explosions = new ListTag();
foreach($this->explosions as $explosion){
$explosions->push($explosion->toCompoundTag());
}
$fireworksData = CompoundTag::create()
->setTag(FireworkItem::TAG_FIREWORK_DATA, CompoundTag::create()
->setTag(FireworkItem::TAG_EXPLOSIONS, $explosions)
)
;

$properties->setCompoundTag(EntityMetadataProperties::FIREWORK_ITEM, new CacheableNbt($fireworksData));
}
}
5 changes: 4 additions & 1 deletion src/event/player/PlayerDeathEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use pocketmine\block\BlockTypeIds;
use pocketmine\entity\Living;
use pocketmine\entity\object\FallingBlock;
use pocketmine\entity\object\FireworkRocket;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
Expand Down Expand Up @@ -157,7 +158,9 @@ public static function deriveMessage(string $name, ?EntityDamageEvent $deathCaus
case EntityDamageEvent::CAUSE_ENTITY_EXPLOSION:
if($deathCause instanceof EntityDamageByEntityEvent){
$e = $deathCause->getDamager();
if($e instanceof Living){
if($e instanceof FireworkRocket){
return KnownTranslationFactory::death_attack_fireworks($name);
}elseif($e instanceof Living){
return KnownTranslationFactory::death_attack_explosion_player($name, $e->getDisplayName());
}
}
Expand Down
Loading