Server: fixed getOfflinePlayerData() trying to load terrain (?!?!?!?), closes #2725

getOfflinePlayerData() will now return NULL if there is no stored data for a given player. The responsibility of checking the spawn point is now delegated to the Player, after it registers a chunk loader on its spawn chunk.
This commit is contained in:
Dylan K. Taylor 2019-02-01 15:16:03 +00:00
parent 3e58708130
commit ad6ae20d6b
3 changed files with 40 additions and 35 deletions

View File

@ -45,10 +45,8 @@ class OfflinePlayer implements IPlayer, Metadatable{
public function __construct(Server $server, string $name){ public function __construct(Server $server, string $name){
$this->server = $server; $this->server = $server;
$this->name = $name; $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{ public function isOnline() : bool{
return $this->getPlayer() !== null; return $this->getPlayer() !== null;

View File

@ -32,6 +32,7 @@ use pocketmine\command\CommandSender;
use pocketmine\entity\effect\Effect; use pocketmine\entity\effect\Effect;
use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntityFactory;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\entity\object\ItemEntity; use pocketmine\entity\object\ItemEntity;
use pocketmine\entity\projectile\Arrow; use pocketmine\entity\projectile\Arrow;
@ -1847,21 +1848,37 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
public function _actuallyConstruct(){ public function _actuallyConstruct(){
$namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async $namedtag = $this->server->getOfflinePlayerData($this->username); //TODO: make this async
if(($level = $this->server->getLevelManager()->getLevelByName($namedtag->getString("Level", "", true))) === null){ $spawnReset = false;
/** @var Level $level */
$level = $this->server->getLevelManager()->getDefaultLevel(); //TODO: default level may be null
$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 */ /** @var float[] $pos */
$pos = $namedtag->getListTag("Pos")->getAllValues(); $pos = $namedtag->getListTag("Pos")->getAllValues();
$level->registerChunkLoader($this, ((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4, true); $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;
}
//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); parent::__construct($level, $namedtag);
$ev = new PlayerLoginEvent($this, "Plugin reason"); $ev = new PlayerLoginEvent($this, "Plugin reason");

View File

@ -648,12 +648,12 @@ class Server{
/** /**
* @param string $name * @param string $name
* *
* @return CompoundTag * @return CompoundTag|null
*/ */
public function getOfflinePlayerData(string $name) : CompoundTag{ public function getOfflinePlayerData(string $name) : ?CompoundTag{
$name = strtolower($name); $name = strtolower($name);
$path = $this->getDataPath() . "players/"; $path = $this->getDataPath() . "players/";
if($this->shouldSavePlayerData()){
if(file_exists($path . "$name.dat")){ if(file_exists($path . "$name.dat")){
try{ try{
return (new BigEndianNbtSerializer())->readCompressed(file_get_contents($path . "$name.dat")); return (new BigEndianNbtSerializer())->readCompressed(file_get_contents($path . "$name.dat"));
@ -662,17 +662,7 @@ class Server{
$this->logger->error($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name])); $this->logger->error($this->getLanguage()->translateString("pocketmine.data.playerCorrupted", [$name]));
} }
} }
$this->logger->notice($this->getLanguage()->translateString("pocketmine.data.playerNotFound", [$name])); return null;
}
$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;
} }
/** /**