diff --git a/src/pocketmine/block/Bed.php b/src/pocketmine/block/Bed.php index a6901e9df..39be79b1d 100644 --- a/src/pocketmine/block/Bed.php +++ b/src/pocketmine/block/Bed.php @@ -38,6 +38,8 @@ use pocketmine\tile\Tile; use pocketmine\utils\TextFormat; class Bed extends Transparent{ + const BITFLAG_OCCUPIED = 0x04; + const BITFLAG_HEAD = 0x08; protected $id = self::BED_BLOCK; @@ -64,8 +66,62 @@ class Bed extends Transparent{ ); } - public function onActivate(Item $item, Player $player = null){ + public function isHeadPart() : bool{ + return ($this->meta & self::BITFLAG_HEAD) !== 0; + } + /** + * @return bool + */ + public function isOccupied() : bool{ + return ($this->meta & self::BITFLAG_OCCUPIED) !== 0; + } + + /** + * @param int $meta + * @param bool $isHead + * + * @return int + */ + public static function getOtherHalfSide(int $meta, bool $isHead = false) : int{ + $rotation = $meta & 0x03; + $side = -1; + + switch($rotation){ + case 0x00: //South + $side = Vector3::SIDE_SOUTH; + break; + case 0x01: //West + $side = Vector3::SIDE_WEST; + break; + case 0x02: //North + $side = Vector3::SIDE_NORTH; + break; + case 0x03: //East + $side = Vector3::SIDE_EAST; + break; + } + + if($isHead){ + $side = Vector3::getOppositeSide($side); + } + + return $side; + } + + /** + * @return Bed|null + */ + public function getOtherHalf(){ + $other = $this->getSide(self::getOtherHalfSide($this->meta, $this->isHeadPart())); + if($other instanceof Bed and $other->getId() === $this->getId() and $other->isHeadPart() !== $this->isHeadPart() and (($other->getDamage() & 0x03) === ($this->getDamage() & 0x03))){ + return $other; + } + + return null; + } + + public function onActivate(Item $item, Player $player = null){ $time = $this->getLevel()->getTime() % Level::TIME_FULL; $isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE); @@ -75,31 +131,19 @@ class Bed extends Transparent{ return true; } - $blockNorth = $this->getSide(2); //Gets the blocks around them - $blockSouth = $this->getSide(3); - $blockEast = $this->getSide(5); - $blockWest = $this->getSide(4); - if(($this->meta & 0x08) === 0x08){ //This is the Top part of bed - $b = $this; - }else{ //Bottom Part of Bed - if($blockNorth->getId() === $this->id and ($blockNorth->meta & 0x08) === 0x08){ - $b = $blockNorth; - }elseif($blockSouth->getId() === $this->id and ($blockSouth->meta & 0x08) === 0x08){ - $b = $blockSouth; - }elseif($blockEast->getId() === $this->id and ($blockEast->meta & 0x08) === 0x08){ - $b = $blockEast; - }elseif($blockWest->getId() === $this->id and ($blockWest->meta & 0x08) === 0x08){ - $b = $blockWest; - }else{ - if($player instanceof Player){ - $player->sendMessage(TextFormat::GRAY . "This bed is incomplete"); - } - - return true; + $other = $this->getOtherHalf(); + if($other === null){ + if($player instanceof Player){ + $player->sendMessage(TextFormat::GRAY . "This bed is incomplete"); } + + return true; } + $b = ($this->isHeadPart() ? $this : $other); + if($player instanceof Player and $player->sleepOn($b) === false){ + //TODO: change this to use the meta bitflags $player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.occupied")); } @@ -108,20 +152,12 @@ class Bed extends Transparent{ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ $down = $this->getSide(Vector3::SIDE_DOWN); - if($down->isTransparent() === false){ - $faces = [ - 0 => 3, - 1 => 4, - 2 => 2, - 3 => 5, - ]; - $d = $player instanceof Player ? $player->getDirection() : 0; - $next = $this->getSide($faces[($d + 3) % 4]); - $downNext = $next->getSide(Vector3::SIDE_DOWN); - if($next->canBeReplaced() === true and $downNext->isTransparent() === false){ - $meta = (($d + 3) % 4) & 0x03; + if(!$down->isTransparent()){ + $meta = (($player instanceof Player ? $player->getDirection() : 0) - 1) & 0x03; + $next = $this->getSide(self::getOtherHalfSide($meta)); + if($next->canBeReplaced() === true and !$next->getSide(Vector3::SIDE_DOWN)->isTransparent()){ $this->getLevel()->setBlock($block, Block::get($this->id, $meta), true, true); - $this->getLevel()->setBlock($next, Block::get($this->id, $meta | 0x08), true, true); + $this->getLevel()->setBlock($next, Block::get($this->id, $meta | self::BITFLAG_HEAD), true, true); $nbt = new CompoundTag("", [ new StringTag("id", Tile::BED), @@ -146,47 +182,28 @@ class Bed extends Transparent{ } public function onBreak(Item $item){ - $blockNorth = $this->getSide(2); //Gets the blocks around them - $blockSouth = $this->getSide(3); - $blockEast = $this->getSide(5); - $blockWest = $this->getSide(4); - - if(($this->meta & 0x08) === 0x08){ //This is the Top part of bed - if($blockNorth->getId() === $this->id and $blockNorth->meta !== 0x08){ //Checks if the block ID and meta are right - $this->getLevel()->setBlock($blockNorth, new Air(), true, true); - }elseif($blockSouth->getId() === $this->id and $blockSouth->meta !== 0x08){ - $this->getLevel()->setBlock($blockSouth, new Air(), true, true); - }elseif($blockEast->getId() === $this->id and $blockEast->meta !== 0x08){ - $this->getLevel()->setBlock($blockEast, new Air(), true, true); - }elseif($blockWest->getId() === $this->id and $blockWest->meta !== 0x08){ - $this->getLevel()->setBlock($blockWest, new Air(), true, true); - } - }else{ //Bottom Part of Bed - if($blockNorth->getId() === $this->id and ($blockNorth->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($blockNorth, new Air(), true, true); - }elseif($blockSouth->getId() === $this->id and ($blockSouth->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($blockSouth, new Air(), true, true); - }elseif($blockEast->getId() === $this->id and ($blockEast->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($blockEast, new Air(), true, true); - }elseif($blockWest->getId() === $this->id and ($blockWest->meta & 0x08) === 0x08){ - $this->getLevel()->setBlock($blockWest, new Air(), true, true); - } + $this->getLevel()->setBlock($this, Block::get(Block::AIR), true, true); + if(($other = $this->getOtherHalf()) !== null){ + $this->getLevel()->useBreakOn($other); //make sure tiles get removed } - $this->getLevel()->setBlock($this, new Air(), true, true); return true; } public function getDrops(Item $item){ - $tile = $this->getLevel()->getTile($this); - if($tile instanceof TileBed){ - return [ - [Item::BED, $tile->getColor(), 1] - ]; + if($this->isHeadPart()){ + $tile = $this->getLevel()->getTile($this); + if($tile instanceof TileBed){ + return [ + [Item::BED, $tile->getColor(), 1] + ]; + }else{ + return [ + [Item::BED, 14, 1] //Red + ]; + } }else{ - return [ - [Item::BED, 14, 1] //Red - ]; + return []; } }