Skip to content

Commit ebeee29

Browse files
IvanCraft623dktappsipad54
authored
Implement firework rocket & firework star (#5455)
Co-authored-by: Dylan T <[email protected]> Co-authored-by: ipad54 <[email protected]>
1 parent dd9cbb7 commit ebeee29

17 files changed

+975
-2
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
*
5+
* ____ _ _ __ __ _ __ __ ____
6+
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7+
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8+
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9+
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Lesser General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* @author PocketMine Team
17+
* @link http://www.pocketmine.net/
18+
*
19+
*
20+
*/
21+
22+
declare(strict_types=1);
23+
24+
namespace pocketmine\data\bedrock;
25+
26+
use pocketmine\item\FireworkRocketType;
27+
use pocketmine\utils\SingletonTrait;
28+
29+
final class FireworkRocketTypeIdMap{
30+
use SingletonTrait;
31+
/** @phpstan-use IntSaveIdMapTrait<FireworkRocketType> */
32+
use IntSaveIdMapTrait;
33+
34+
private function __construct(){
35+
foreach(FireworkRocketType::cases() as $case){
36+
$this->register(match($case){
37+
FireworkRocketType::SMALL_BALL => FireworkRocketTypeIds::SMALL_BALL,
38+
FireworkRocketType::LARGE_BALL => FireworkRocketTypeIds::LARGE_BALL,
39+
FireworkRocketType::STAR => FireworkRocketTypeIds::STAR,
40+
FireworkRocketType::CREEPER => FireworkRocketTypeIds::CREEPER,
41+
FireworkRocketType::BURST => FireworkRocketTypeIds::BURST,
42+
}, $case);
43+
}
44+
}
45+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
*
5+
* ____ _ _ __ __ _ __ __ ____
6+
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7+
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8+
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9+
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Lesser General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* @author PocketMine Team
17+
* @link http://www.pocketmine.net/
18+
*
19+
*
20+
*/
21+
22+
declare(strict_types=1);
23+
24+
namespace pocketmine\data\bedrock;
25+
26+
final class FireworkRocketTypeIds{
27+
public const SMALL_BALL = 0;
28+
public const LARGE_BALL = 1;
29+
public const STAR = 2;
30+
public const CREEPER = 3;
31+
public const BURST = 4;
32+
}

src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use pocketmine\data\bedrock\SuspiciousStewTypeIdMap;
4141
use pocketmine\item\Banner;
4242
use pocketmine\item\Dye;
43+
use pocketmine\item\FireworkStar;
4344
use pocketmine\item\GoatHorn;
4445
use pocketmine\item\Item;
4546
use pocketmine\item\Medicine;
@@ -246,6 +247,7 @@ private function register1to1ItemMappings() : void{
246247
$this->map1to1Item(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
247248
$this->map1to1Item(Ids::FEATHER, Items::FEATHER());
248249
$this->map1to1Item(Ids::FERMENTED_SPIDER_EYE, Items::FERMENTED_SPIDER_EYE());
250+
$this->map1to1Item(Ids::FIREWORK_ROCKET, Items::FIREWORK_ROCKET());
249251
$this->map1to1Item(Ids::FIRE_CHARGE, Items::FIRE_CHARGE());
250252
$this->map1to1Item(Ids::FISHING_ROD, Items::FISHING_ROD());
251253
$this->map1to1Item(Ids::FLINT, Items::FLINT());
@@ -501,6 +503,14 @@ function(Bed $block, int $meta) : void{
501503
* in a unified manner.
502504
*/
503505
private function register1to1ItemWithMetaMappings() : void{
506+
$this->map1to1ItemWithMeta(
507+
Ids::FIREWORK_STAR,
508+
Items::FIREWORK_STAR(),
509+
function(FireworkStar $item, int $meta) : void{
510+
// Colors will be defined by CompoundTag deserialization.
511+
},
512+
fn(FireworkStar $item) => DyeColorIdMap::getInstance()->toInvertedId($item->getExplosion()->getFlashColor())
513+
);
504514
$this->map1to1ItemWithMeta(
505515
Ids::GOAT_HORN,
506516
Items::GOAT_HORN(),
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
*
5+
* ____ _ _ __ __ _ __ __ ____
6+
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7+
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8+
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9+
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Lesser General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* @author PocketMine Team
17+
* @link http://www.pocketmine.net/
18+
*
19+
*
20+
*/
21+
22+
declare(strict_types=1);
23+
24+
namespace pocketmine\entity\animation;
25+
26+
use pocketmine\entity\object\FireworkRocket;
27+
use pocketmine\network\mcpe\protocol\ActorEventPacket;
28+
use pocketmine\network\mcpe\protocol\types\ActorEvent;
29+
30+
final class FireworkParticlesAnimation implements Animation{
31+
32+
public function __construct(
33+
private FireworkRocket $entity
34+
){}
35+
36+
public function encode() : array{
37+
return [
38+
ActorEventPacket::create($this->entity->getId(), ActorEvent::FIREWORK_PARTICLES, 0)
39+
];
40+
}
41+
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
<?php
2+
3+
/*
4+
*
5+
* ____ _ _ __ __ _ __ __ ____
6+
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7+
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8+
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9+
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Lesser General Public License as published by
13+
* the Free Software Foundation, either version 3 of the License, or
14+
* (at your option) any later version.
15+
*
16+
* @author PocketMine Team
17+
* @link http://www.pocketmine.net/
18+
*
19+
*
20+
*/
21+
22+
declare(strict_types=1);
23+
24+
namespace pocketmine\entity\object;
25+
26+
use pocketmine\entity\animation\FireworkParticlesAnimation;
27+
use pocketmine\entity\Entity;
28+
use pocketmine\entity\EntitySizeInfo;
29+
use pocketmine\entity\Explosive;
30+
use pocketmine\entity\Living;
31+
use pocketmine\entity\Location;
32+
use pocketmine\entity\NeverSavedWithChunkEntity;
33+
use pocketmine\event\entity\EntityDamageByEntityEvent;
34+
use pocketmine\event\entity\EntityDamageEvent;
35+
use pocketmine\item\FireworkRocket as FireworkItem;
36+
use pocketmine\item\FireworkRocketExplosion;
37+
use pocketmine\math\VoxelRayTrace;
38+
use pocketmine\nbt\tag\CompoundTag;
39+
use pocketmine\nbt\tag\ListTag;
40+
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
41+
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
42+
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
43+
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
44+
use pocketmine\utils\Utils;
45+
use pocketmine\world\sound\FireworkCrackleSound;
46+
use pocketmine\world\sound\FireworkLaunchSound;
47+
use function count;
48+
use function sqrt;
49+
50+
class FireworkRocket extends Entity implements Explosive, NeverSavedWithChunkEntity{
51+
52+
public static function getNetworkTypeId() : string{ return EntityIds::FIREWORKS_ROCKET; }
53+
54+
protected int $maxFlightTimeTicks;
55+
56+
/** @var FireworkRocketExplosion[] */
57+
protected array $explosions = [];
58+
59+
/**
60+
* @param FireworkRocketExplosion[] $explosions
61+
*/
62+
public function __construct(Location $location, int $maxFlightTimeTicks, array $explosions, ?CompoundTag $nbt = null){
63+
if($maxFlightTimeTicks < 0){
64+
throw new \InvalidArgumentException("Life ticks cannot be negative");
65+
}
66+
$this->maxFlightTimeTicks = $maxFlightTimeTicks;
67+
$this->setExplosions($explosions);
68+
69+
parent::__construct($location, $nbt);
70+
}
71+
72+
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.25, 0.25); }
73+
74+
protected function getInitialDragMultiplier() : float{ return 0.0; }
75+
76+
protected function getInitialGravity() : float{ return 0.0; }
77+
78+
/**
79+
* Returns the total number of ticks the firework will fly for before it explodes.
80+
*/
81+
public function getMaxFlightTimeTicks() : int{
82+
return $this->maxFlightTimeTicks;
83+
}
84+
85+
/**
86+
* Sets the total number of ticks the firework will fly for before it explodes.
87+
*
88+
* @return $this
89+
*/
90+
public function setMaxFlightTimeTicks(int $maxFlightTimeTicks) : self{
91+
if($maxFlightTimeTicks < 0){
92+
throw new \InvalidArgumentException("Max flight time ticks cannot be negative");
93+
}
94+
$this->maxFlightTimeTicks = $maxFlightTimeTicks;
95+
return $this;
96+
}
97+
98+
/**
99+
* @return FireworkRocketExplosion[]
100+
*/
101+
public function getExplosions() : array{
102+
return $this->explosions;
103+
}
104+
105+
/**
106+
* @param FireworkRocketExplosion[] $explosions
107+
*
108+
* @return $this
109+
*/
110+
public function setExplosions(array $explosions) : self{
111+
Utils::validateArrayValueType($explosions, function(FireworkRocketExplosion $_) : void{});
112+
$this->explosions = $explosions;
113+
return $this;
114+
}
115+
116+
protected function onFirstUpdate(int $currentTick) : void{
117+
parent::onFirstUpdate($currentTick);
118+
119+
$this->broadcastSound(new FireworkLaunchSound());
120+
}
121+
122+
protected function entityBaseTick(int $tickDiff = 1) : bool{
123+
$hasUpdate = parent::entityBaseTick($tickDiff);
124+
125+
if(!$this->isFlaggedForDespawn()){
126+
//Don't keep accelerating long-lived fireworks - this gets very rapidly out of control and makes the server
127+
//die. Vanilla fireworks will only live for about 52 ticks maximum anyway, so this only makes sure plugin
128+
//created fireworks don't murder the server
129+
if($this->ticksLived < 60){
130+
$this->addMotion($this->motion->x * 0.15, 0.04, $this->motion->z * 0.15);
131+
}
132+
133+
if($this->ticksLived >= $this->maxFlightTimeTicks){
134+
$this->flagForDespawn();
135+
$this->explode();
136+
}
137+
}
138+
139+
return $hasUpdate;
140+
}
141+
142+
public function explode() : void{
143+
if(($explosionCount = count($this->explosions)) !== 0){
144+
$this->broadcastAnimation(new FireworkParticlesAnimation($this));
145+
foreach($this->explosions as $explosion){
146+
$this->broadcastSound($explosion->getType()->getExplosionSound());
147+
if($explosion->willTwinkle()){
148+
$this->broadcastSound(new FireworkCrackleSound());
149+
}
150+
}
151+
152+
$force = ($explosionCount * 2) + 5;
153+
$world = $this->getWorld();
154+
foreach($world->getCollidingEntities($this->getBoundingBox()->expandedCopy(5, 5, 5), $this) as $entity){
155+
if(!$entity instanceof Living){
156+
continue;
157+
}
158+
159+
$position = $entity->getPosition();
160+
$distance = $position->distanceSquared($this->location);
161+
if($distance > 25){
162+
continue;
163+
}
164+
165+
//cast two rays - one to the entity's feet and another to halfway up its body (according to Java, anyway)
166+
//this seems like it'd miss some cases but who am I to argue with vanilla logic :>
167+
$height = $entity->getBoundingBox()->getYLength();
168+
for($i = 0; $i < 2; $i++){
169+
$target = $position->add(0, 0.5 * $i * $height, 0);
170+
foreach(VoxelRayTrace::betweenPoints($this->location, $target) as $blockPos){
171+
if($world->getBlock($blockPos)->calculateIntercept($this->location, $target) !== null){
172+
continue 2; //obstruction, try another path
173+
}
174+
}
175+
176+
//no obstruction
177+
$damage = $force * sqrt((5 - $position->distance($this->location)) / 5);
178+
$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_EXPLOSION, $damage);
179+
$entity->attack($ev);
180+
break;
181+
}
182+
}
183+
}
184+
}
185+
186+
public function canBeCollidedWith() : bool{
187+
return false;
188+
}
189+
190+
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
191+
parent::syncNetworkData($properties);
192+
193+
$explosions = new ListTag();
194+
foreach($this->explosions as $explosion){
195+
$explosions->push($explosion->toCompoundTag());
196+
}
197+
$fireworksData = CompoundTag::create()
198+
->setTag(FireworkItem::TAG_FIREWORK_DATA, CompoundTag::create()
199+
->setTag(FireworkItem::TAG_EXPLOSIONS, $explosions)
200+
);
201+
202+
$properties->setCompoundTag(EntityMetadataProperties::FIREWORK_ITEM, new CacheableNbt($fireworksData));
203+
}
204+
}

src/event/player/PlayerDeathEvent.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use pocketmine\block\BlockTypeIds;
2727
use pocketmine\entity\Living;
2828
use pocketmine\entity\object\FallingBlock;
29+
use pocketmine\entity\object\FireworkRocket;
2930
use pocketmine\entity\projectile\Trident;
3031
use pocketmine\event\entity\EntityDamageByBlockEvent;
3132
use pocketmine\event\entity\EntityDamageByChildEntityEvent;
@@ -164,7 +165,9 @@ public static function deriveMessage(string $name, ?EntityDamageEvent $deathCaus
164165
case EntityDamageEvent::CAUSE_ENTITY_EXPLOSION:
165166
if($deathCause instanceof EntityDamageByEntityEvent){
166167
$e = $deathCause->getDamager();
167-
if($e instanceof Living){
168+
if($e instanceof FireworkRocket){
169+
return KnownTranslationFactory::death_attack_fireworks($name);
170+
}elseif($e instanceof Living){
168171
return KnownTranslationFactory::death_attack_explosion_player($name, $e->getDisplayName());
169172
}
170173
}

0 commit comments

Comments
 (0)