mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-21 16:24:05 +00:00
Player: Fixed a multitude of bugs with respawning
the following things are changed: - Player->getSpawn() no longer returns a safe spawn by default. Instead, if the player doesn't have a spawn set, it returns the world's stored spawn directly. This allows consistent behaviour of locating safe respawn positions without double calculation of safe spawn position, and also fixes crash issues during the login sequence if the player's spawn position referred to ungenerated terrain. - Player->respawn() is now asynchronous, using the promise returned by orderChunkPopulation() to complete respawn after the terrain is generated. This allows consistently selecting a safe respawn position and fixes crashes when respawning if the spawn location was in ungenerated terrain. There remains a problem that ragequit respawns are still only handled right after PlayerJoinEvent, which leads to the original spawn terrain being sent to the player, which is obviously very wasteful. However, that's a problem for a later commit.
This commit is contained in:
parent
094c949e86
commit
ab0500ae4f
@ -810,6 +810,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}
|
||||
|
||||
if($this->getHealth() <= 0){
|
||||
$this->logger->debug("Quit while dead, forcing respawn");
|
||||
$this->respawn();
|
||||
}
|
||||
}
|
||||
@ -907,7 +908,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
}else{
|
||||
$world = $this->server->getWorldManager()->getDefaultWorld();
|
||||
|
||||
return $world->getSafeSpawn();
|
||||
return $world->getSpawnLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2059,16 +2060,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$nbt->setInt("SpawnZ", $spawn->getFloorZ());
|
||||
}
|
||||
|
||||
if(!$this->isAlive()){
|
||||
$spawn = $this->getSpawn();
|
||||
//hack for respawn after quit
|
||||
$nbt->setTag("Pos", new ListTag([
|
||||
new DoubleTag($spawn->getFloorX()),
|
||||
new DoubleTag($spawn->getFloorY()),
|
||||
new DoubleTag($spawn->getFloorZ())
|
||||
]));
|
||||
}
|
||||
|
||||
$nbt->setInt("playerGameType", $this->gamemode->getMagicNumber());
|
||||
$nbt->setLong("firstPlayed", $this->firstPlayed);
|
||||
$nbt->setLong("lastPlayed", (int) floor(microtime(true) * 1000));
|
||||
@ -2133,31 +2124,47 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
return;
|
||||
}
|
||||
|
||||
$ev = new PlayerRespawnEvent($this, $this->getSpawn());
|
||||
$ev->call();
|
||||
$this->logger->debug("Waiting for spawn terrain generation for respawn");
|
||||
$spawn = $this->getSpawn();
|
||||
$spawn->getWorld()->orderChunkPopulation($spawn->getFloorX() >> 4, $spawn->getFloorZ() >> 4, null)->onCompletion(
|
||||
function() use ($spawn) : void{
|
||||
if(!$this->isConnected()){
|
||||
return;
|
||||
}
|
||||
$this->logger->debug("Spawn terrain generation done, completing respawn");
|
||||
$spawn = $spawn->getWorld()->getSafeSpawn($spawn);
|
||||
$ev = new PlayerRespawnEvent($this, $spawn);
|
||||
$ev->call();
|
||||
|
||||
$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getWorld());
|
||||
$this->teleport($realSpawn);
|
||||
$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getWorld());
|
||||
$this->teleport($realSpawn);
|
||||
|
||||
$this->setSprinting(false);
|
||||
$this->setSneaking(false);
|
||||
$this->setSprinting(false);
|
||||
$this->setSneaking(false);
|
||||
|
||||
$this->extinguish();
|
||||
$this->setAirSupplyTicks($this->getMaxAirSupplyTicks());
|
||||
$this->deadTicks = 0;
|
||||
$this->noDamageTicks = 60;
|
||||
$this->extinguish();
|
||||
$this->setAirSupplyTicks($this->getMaxAirSupplyTicks());
|
||||
$this->deadTicks = 0;
|
||||
$this->noDamageTicks = 60;
|
||||
|
||||
$this->effectManager->clear();
|
||||
$this->setHealth($this->getMaxHealth());
|
||||
$this->effectManager->clear();
|
||||
$this->setHealth($this->getMaxHealth());
|
||||
|
||||
foreach($this->attributeMap->getAll() as $attr){
|
||||
$attr->resetToDefault();
|
||||
}
|
||||
foreach($this->attributeMap->getAll() as $attr){
|
||||
$attr->resetToDefault();
|
||||
}
|
||||
|
||||
$this->spawnToAll();
|
||||
$this->scheduleUpdate();
|
||||
$this->spawnToAll();
|
||||
$this->scheduleUpdate();
|
||||
|
||||
$this->getNetworkSession()->onServerRespawn();
|
||||
$this->getNetworkSession()->onServerRespawn();
|
||||
},
|
||||
function() : void{
|
||||
if($this->isConnected()){
|
||||
$this->disconnect("Unable to find a respawn position");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
|
||||
|
Loading…
x
Reference in New Issue
Block a user