diff --git a/src/entity/object/PrimedTNT.php b/src/entity/object/PrimedTNT.php index f3f299d70c6..0e983c75ad2 100644 --- a/src/entity/object/PrimedTNT.php +++ b/src/entity/object/PrimedTNT.php @@ -23,6 +23,7 @@ namespace pocketmine\entity\object; +use pocketmine\block\BlockTypeIds; use pocketmine\block\VanillaBlocks; use pocketmine\entity\Entity; use pocketmine\entity\EntitySizeInfo; @@ -120,8 +121,7 @@ public function explode() : void{ $ev = new EntityPreExplodeEvent($this, 4); $ev->call(); if(!$ev->isCancelled()){ - //TODO: deal with underwater TNT (underwater TNT treats water as if it has a blast resistance of 0) - $explosion = new Explosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->getWorld()), $ev->getRadius(), $this, $ev->getFireChance()); + $explosion = new Explosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->getWorld()), $ev->getRadius(), $this, $ev->getFireChance(), $this->worksUnderwater ? [BlockTypeIds::WATER] : []); if($ev->isBlockBreaking()){ $explosion->explodeA(); } diff --git a/src/world/Explosion.php b/src/world/Explosion.php index 88968a77e35..9a23bdc0137 100644 --- a/src/world/Explosion.php +++ b/src/world/Explosion.php @@ -46,7 +46,9 @@ use pocketmine\world\sound\ExplodeSound; use pocketmine\world\utils\SubChunkExplorer; use pocketmine\world\utils\SubChunkExplorerStatus; +use function array_fill_keys; use function ceil; +use function count; use function floor; use function min; use function mt_rand; @@ -69,11 +71,22 @@ class Explosion{ private SubChunkExplorer $subChunkExplorer; + /** + * @var true[] + * @phpstan-var array + */ + private array $excludedBlockTypeIds = []; + + /** + * @param int[] $excludedBlockTypeIds + * @phpstan-param array $excludedBlockTypeIds + */ public function __construct( public Position $source, public float $radius, private Entity|Block|null $what = null, - private float $fireChance = 0.0 + private float $fireChance = 0.0, + array $excludedBlockTypeIds = [] ){ if(!$this->source->isValid()){ throw new \InvalidArgumentException("Position does not have a valid world"); @@ -87,6 +100,8 @@ public function __construct( throw new \InvalidArgumentException("Explosion radius must be greater than 0, got $radius"); } $this->subChunkExplorer = new SubChunkExplorer($this->world); + + $this->excludedBlockTypeIds = array_fill_keys($excludedBlockTypeIds, true); } /** @@ -135,6 +150,9 @@ public function explodeA() : bool{ } $state = $subChunk->getBlockStateId($vBlockX & SubChunk::COORD_MASK, $vBlockY & SubChunk::COORD_MASK, $vBlockZ & SubChunk::COORD_MASK); + if(count($this->excludedBlockTypeIds) > 0 && isset($this->excludedBlockTypeIds[$blockFactory->fromStateId($state)->getTypeId()])){ + continue; + } $blastResistance = $blockFactory->blastResistance[$state] ?? 0; if($blastResistance >= 0){