44 public const TAG_TILE_X =
"TileX";
45 public const TAG_TILE_Y =
"TileY";
46 public const TAG_TILE_Z =
"TileZ";
47 public const TAG_FACING_JE =
"Facing";
48 public const TAG_DIRECTION_BE =
"Direction";
49 public const TAG_MOTIVE =
"Motive";
51 public static function getNetworkTypeId() :
string{
return EntityIds::PAINTING; }
53 public const DATA_TO_FACING = [
59 private const FACING_TO_DATA = [
67 protected int $facing;
71 $this->motive = $motive;
73 $this->facing = $facing;
74 parent::__construct($location, $nbt);
86 protected function initEntity(
CompoundTag $nbt) : void{
87 $this->setMaxHealth(1);
89 parent::initEntity($nbt);
93 $nbt = parent::saveNBT();
94 $nbt->
setInt(self::TAG_TILE_X, (
int) $this->blockIn->x);
95 $nbt->setInt(self::TAG_TILE_Y, (
int) $this->blockIn->y);
96 $nbt->setInt(self::TAG_TILE_Z, (
int) $this->blockIn->z);
98 $nbt->setByte(self::TAG_FACING_JE, self::FACING_TO_DATA[$this->facing]);
99 $nbt->setByte(self::TAG_DIRECTION_BE, self::FACING_TO_DATA[$this->facing]);
101 $nbt->setString(self::TAG_MOTIVE, $this->motive->getName());
112 $killer = $this->lastDamageCause->getDamager();
120 $this->getWorld()->dropItem($this->location, VanillaItems::PAINTING());
122 $this->getWorld()->addParticle($this->location->add(0.5, 0.5, 0.5),
new BlockBreakParticle(VanillaBlocks::OAK_PLANKS()));
125 protected function recalculateBoundingBox() : void{
126 $side = $this->blockIn->getSide($this->facing);
127 $this->boundingBox = self::getPaintingBB($this->facing, $this->getMotive())->offset($side->x, $side->y, $side->z);
130 public function onNearbyBlockChange() : void{
131 parent::onNearbyBlockChange();
133 if(!self::canFit($this->getWorld(), $this->blockIn->getSide($this->facing), $this->facing,
false, $this->getMotive())){
142 public function hasMovementUpdate() : bool{
146 protected function updateMovement(
bool $teleport =
false) : void{
150 public function canBeCollidedWith() : bool{
159 ($this->boundingBox->minX + $this->boundingBox->maxX) / 2,
160 ($this->boundingBox->minY + $this->boundingBox->maxY) / 2,
161 ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2
163 self::FACING_TO_DATA[$this->facing],
164 $this->motive->getName()
172 return $this->motive;
175 public function getFacing() : int{
176 return $this->facing;
183 $width = $motive->getWidth();
184 $height = $motive->getHeight();
186 $horizontalStart = (int) (ceil($width / 2) - 1);
187 $verticalStart = (int) (ceil($height / 2) - 1);
189 return AxisAlignedBB::one()
190 ->trim($facing, 15 / 16)
191 ->extend(Facing::rotateY($facing,
true), $horizontalStart)
192 ->extend(Facing::rotateY($facing,
false), -$horizontalStart + $width - 1)
193 ->extend(Facing::DOWN, $verticalStart)
194 ->extend(Facing::UP, -$verticalStart + $height - 1);
201 $width = $motive->getWidth();
202 $height = $motive->getHeight();
204 $horizontalStart = (int) (ceil($width / 2) - 1);
205 $verticalStart = (int) (ceil($height / 2) - 1);
207 $rotatedFace = Facing::rotateY($facing,
false);
209 $oppositeSide = Facing::opposite($facing);
211 $startPos = $blockIn->
asVector3()->getSide(Facing::opposite($rotatedFace), $horizontalStart)->getSide(Facing::DOWN, $verticalStart);
213 for($w = 0; $w < $width; ++$w){
214 for($h = 0; $h < $height; ++$h){
215 $pos = $startPos->getSide($rotatedFace, $w)->getSide(Facing::UP, $h);
217 $block = $world->
getBlockAt($pos->x, $pos->y, $pos->z);
218 if($block->isSolid() || !$block->getSide($oppositeSide)->isSolid()){
225 $bb = self::getPaintingBB($facing, $motive)->offset($blockIn->x, $blockIn->y, $blockIn->z);
228 if($entity instanceof
self){