diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 29f81b379..24925571e 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine; use pocketmine\block\Air; +use pocketmine\block\Bed; use pocketmine\block\Block; use pocketmine\command\Command; use pocketmine\command\CommandSender; @@ -250,7 +251,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ protected $iusername; protected $displayName; protected $startAction = -1; - /** @var Vector3 */ + /** @var Vector3|null */ protected $sleeping = null; protected $clientID = null; @@ -1125,19 +1126,17 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return false; } - foreach($this->level->getNearbyEntities($this->boundingBox->grow(2, 1, 2), $this) as $p){ - if($p instanceof Player){ - if($p->sleeping !== null and $pos->distance($p->sleeping) <= 0.1){ - return false; - } - } - } + $b = $this->level->getBlock($pos); - $this->server->getPluginManager()->callEvent($ev = new PlayerBedEnterEvent($this, $this->level->getBlock($pos))); + $this->server->getPluginManager()->callEvent($ev = new PlayerBedEnterEvent($this, $b)); if($ev->isCancelled()){ return false; } + if($b instanceof Bed){ + $b->setOccupied(); + } + $this->sleeping = clone $pos; $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [$pos->x, $pos->y, $pos->z]); @@ -1174,7 +1173,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function stopSleep(){ if($this->sleeping instanceof Vector3){ - $this->server->getPluginManager()->callEvent($ev = new PlayerBedLeaveEvent($this, $this->level->getBlock($this->sleeping))); + $b = $this->level->getBlock($this->sleeping); + if($b instanceof Bed){ + $b->setOccupied(false); + } + $this->server->getPluginManager()->callEvent($ev = new PlayerBedLeaveEvent($this, $b)); $this->sleeping = null; $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0]); @@ -3409,6 +3412,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ */ final public function close($message = "", $reason = "generic reason", $notify = true){ if($this->connected and !$this->closed){ + try{ if($notify and strlen((string) $reason) > 0){ $pk = new DisconnectPacket(); @@ -3422,6 +3426,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this); $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this); + $this->stopSleep(); + if($this->joined){ try{ $this->save(); diff --git a/src/pocketmine/block/Bed.php b/src/pocketmine/block/Bed.php index 39be79b1d..11e202b1a 100644 --- a/src/pocketmine/block/Bed.php +++ b/src/pocketmine/block/Bed.php @@ -77,6 +77,20 @@ class Bed extends Transparent{ return ($this->meta & self::BITFLAG_OCCUPIED) !== 0; } + public function setOccupied(bool $occupied = true){ + if($occupied){ + $this->meta |= self::BITFLAG_OCCUPIED; + }else{ + $this->meta &= ~self::BITFLAG_OCCUPIED; + } + + $this->getLevel()->setBlock($this, $this, false, false); + + if(($other = $this->getOtherHalf()) !== null and !$other->isOccupied()){ + $other->setOccupied($occupied); + } + } + /** * @param int $meta * @param bool $isHead @@ -122,32 +136,40 @@ class Bed extends Transparent{ } 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); - - if($player instanceof Player and !$isNight){ - $player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.noSleep")); - return true; - } - - $other = $this->getOtherHalf(); - if($other === null){ - if($player instanceof Player){ + if($player !== null){ + $other = $this->getOtherHalf(); + if($other === null){ $player->sendMessage(TextFormat::GRAY . "This bed is incomplete"); + + return true; + }elseif($player->distanceSquared($this) > 4 and $player->distanceSquared($other) > 4){ + //MCPE doesn't have messages for bed too far away + return true; } - return true; - } + $time = $this->getLevel()->getTime() % Level::TIME_FULL; - $b = ($this->isHeadPart() ? $this : $other); + $isNight = ($time >= Level::TIME_NIGHT and $time < Level::TIME_SUNRISE); - 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")); + if(!$isNight){ + $player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.noSleep")); + + return true; + } + + $b = ($this->isHeadPart() ? $this : $other); + + if($b->isOccupied()){ + $player->sendMessage(new TranslationContainer(TextFormat::GRAY . "%tile.bed.occupied")); + + return true; + } + + $player->sleepOn($b); } return true; + } public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){