mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-01 17:53:41 +00:00
this fixes TNT spawning multiple entities when lit by flaming arrows. The problem here is a bit more complex (entities aren't immediately notified when local block updates happen, so they cache stuff that becomes unusable). The simplest option would be to just lose the cache, but that would have some impacts on performance. Barring a rethink of the block updating mechanism, this solution seems usable for now.
136 lines
3.8 KiB
PHP
136 lines
3.8 KiB
PHP
<?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\block;
|
|
|
|
use pocketmine\block\utils\BlockDataSerializer;
|
|
use pocketmine\entity\Entity;
|
|
use pocketmine\event\block\BlockGrowEvent;
|
|
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
|
use pocketmine\event\entity\EntityDamageEvent;
|
|
use pocketmine\item\Item;
|
|
use pocketmine\math\AxisAlignedBB;
|
|
use pocketmine\math\Facing;
|
|
use pocketmine\math\Vector3;
|
|
use pocketmine\player\Player;
|
|
use pocketmine\world\BlockTransaction;
|
|
|
|
class Cactus extends Transparent{
|
|
|
|
/** @var int */
|
|
protected $age = 0;
|
|
|
|
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
|
|
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.4));
|
|
}
|
|
|
|
protected function writeStateToMeta() : int{
|
|
return $this->age;
|
|
}
|
|
|
|
public function readStateFromData(int $id, int $stateMeta) : void{
|
|
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, 15);
|
|
}
|
|
|
|
public function getStateBitmask() : int{
|
|
return 0b1111;
|
|
}
|
|
|
|
public function hasEntityCollision() : bool{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return AxisAlignedBB[]
|
|
*/
|
|
protected function recalculateCollisionBoxes() : array{
|
|
static $shrinkSize = 1 / 16;
|
|
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
|
|
}
|
|
|
|
public function onEntityInside(Entity $entity) : bool{
|
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
|
|
$entity->attack($ev);
|
|
return true;
|
|
}
|
|
|
|
public function onNearbyBlockChange() : void{
|
|
$down = $this->getSide(Facing::DOWN);
|
|
if($down->getId() !== BlockLegacyIds::SAND and !$down->isSameType($this)){
|
|
$this->pos->getWorld()->useBreakOn($this->pos);
|
|
}else{
|
|
foreach(Facing::HORIZONTAL as $side){
|
|
$b = $this->getSide($side);
|
|
if($b->isSolid()){
|
|
$this->pos->getWorld()->useBreakOn($this->pos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function ticksRandomly() : bool{
|
|
return true;
|
|
}
|
|
|
|
public function onRandomTick() : void{
|
|
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
|
|
if($this->age === 15){
|
|
for($y = 1; $y < 3; ++$y){
|
|
$b = $this->pos->getWorld()->getBlockAt($this->pos->x, $this->pos->y + $y, $this->pos->z);
|
|
if($b->getId() === BlockLegacyIds::AIR){
|
|
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
|
|
$ev->call();
|
|
if($ev->isCancelled()){
|
|
break;
|
|
}
|
|
$this->pos->getWorld()->setBlock($b->pos, $ev->getNewState());
|
|
}else{
|
|
break;
|
|
}
|
|
}
|
|
$this->age = 0;
|
|
$this->pos->getWorld()->setBlock($this->pos, $this);
|
|
}else{
|
|
++$this->age;
|
|
$this->pos->getWorld()->setBlock($this->pos, $this);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
|
$down = $this->getSide(Facing::DOWN);
|
|
if($down->getId() === BlockLegacyIds::SAND or $down->isSameType($this)){
|
|
foreach(Facing::HORIZONTAL as $side){
|
|
if($this->getSide($side)->isSolid()){
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|