diff --git a/src/pocketmine/OfflinePlayer.php b/src/pocketmine/OfflinePlayer.php index 2b1d87a85..9e9d88e14 100644 --- a/src/pocketmine/OfflinePlayer.php +++ b/src/pocketmine/OfflinePlayer.php @@ -45,9 +45,7 @@ class OfflinePlayer implements IPlayer, Metadatable{ public function __construct(Server $server, string $name){ $this->server = $server; $this->name = $name; - if($this->server->hasOfflinePlayerData($this->name)){ - $this->namedtag = $this->server->getOfflinePlayerData($this->name); - } + $this->namedtag = $this->server->getOfflinePlayerData($this->name); } public function isOnline() : bool{ diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 25a4664ed..193c8e58a 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -32,6 +32,7 @@ use pocketmine\command\CommandSender; use pocketmine\entity\effect\Effect; use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\Entity; +use pocketmine\entity\EntityFactory; use pocketmine\entity\Human; use pocketmine\entity\object\ItemEntity; use pocketmine\entity\projectile\Arrow; @@ -1847,21 +1848,37 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function _actuallyConstruct(){ $namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async - if(($level = $this->server->getLevelManager()->getLevelByName($namedtag->getString("Level", "", true))) === null){ - /** @var Level $level */ - $level = $this->server->getLevelManager()->getDefaultLevel(); //TODO: default level may be null + $spawnReset = false; - $spawnLocation = $level->getSafeSpawn(); - $namedtag->setTag(new ListTag("Pos", [ - new DoubleTag("", $spawnLocation->x), - new DoubleTag("", $spawnLocation->y), - new DoubleTag("", $spawnLocation->z) - ])); + if($namedtag !== null and ($level = $this->server->getLevelManager()->getLevelByName($namedtag->getString("Level", "", true))) !== null){ + /** @var float[] $pos */ + $pos = $namedtag->getListTag("Pos")->getAllValues(); + $spawn = new Vector3($pos[0], $pos[1], $pos[2]); + }else{ + $level = $this->server->getLevelManager()->getDefaultLevel(); //TODO: default level might be null + $spawn = $level->getSpawnLocation(); + $spawnReset = true; } - /** @var float[] $pos */ - $pos = $namedtag->getListTag("Pos")->getAllValues(); - $level->registerChunkLoader($this, ((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4, true); + //load the spawn chunk so we can see the terrain + $level->registerChunkLoader($this, $spawn->getFloorX() >> 4, $spawn->getFloorZ() >> 4, true); + if($spawnReset){ + $spawn = $level->getSafeSpawn($spawn); + } + + if($namedtag === null){ + $namedtag = EntityFactory::createBaseNBT($spawn); + + $namedtag->setByte("OnGround", 1); //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move + //TODO: old code had a TODO for SpawnForced + + }elseif($spawnReset){ + $namedtag->setTag(new ListTag("Pos", [ + new DoubleTag("", $spawn->x), + new DoubleTag("", $spawn->y), + new DoubleTag("", $spawn->z) + ])); + } parent::__construct($level, $namedtag); $ev = new PlayerLoginEvent($this, "Plugin reason"); diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 071606e28..fd721f7c5 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -648,31 +648,21 @@ class Server{ /** * @param string $name * - * @return CompoundTag + * @return CompoundTag|null */ - public function getOfflinePlayerData(string $name) : CompoundTag{ + public function getOfflinePlayerData(string $name) : ?CompoundTag{ $name = strtolower($name); $path = $this->getDataPath() . "players/"; - if($this->shouldSavePlayerData()){ - if(file_exists($path . "$name.dat")){ - try{ - return (new BigEndianNbtSerializer())->readCompressed(file_get_contents($path . "$name.dat")); - }catch(NbtDataException $e){ //zlib decode error / corrupt data - rename($path . "$name.dat", $path . "$name.dat.bak"); - $this->logger->error($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name])); - } + + if(file_exists($path . "$name.dat")){ + try{ + return (new BigEndianNbtSerializer())->readCompressed(file_get_contents($path . "$name.dat")); + }catch(NbtDataException $e){ //zlib decode error / corrupt data + rename($path . "$name.dat", $path . "$name.dat.bak"); + $this->logger->error($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name])); } - $this->logger->notice($this->getLanguage()->translateString("pocketmine.data.playerNotFound", [$name])); } - $spawn = $this->levelManager->getDefaultLevel()->getSafeSpawn(); - - $nbt = EntityFactory::createBaseNBT($spawn); - - $nbt->setString("Level", $this->levelManager->getDefaultLevel()->getFolderName()); - $nbt->setByte("OnGround", 1); //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move - //TODO: old code had a TODO for SpawnForced - - return $nbt; + return null; } /**