PocketMine-MP 5.35.1 git-e32e836dad793a3a3c8ddd8927c00e112b1e576a
Loading...
Searching...
No Matches
entity/object/FireworkRocket.php
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
22declare(strict_types=1);
23
24namespace pocketmine\entity\object;
25
35use pocketmine\item\FireworkRocket as FireworkItem;
47use function count;
48use function sqrt;
49
51
52 public function getNetworkTypeId() : string{ return EntityIds::FIREWORKS_ROCKET; }
53
54 protected int $maxFlightTimeTicks;
55
57 protected array $explosions = [];
58
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
81 public function getMaxFlightTimeTicks() : int{
82 return $this->maxFlightTimeTicks;
83 }
84
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
101 public function getExplosions() : array{
102 return $this->explosions;
103 }
104
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}
__construct(Location $location, int $maxFlightTimeTicks, array $explosions, ?CompoundTag $nbt=null)