Fixed chunks not loading when respawning and some minor spawn sequence cleanup (#1153)

* Fixed chunks not loading when respawning and some minor spawn sequence cleanup

* This causes too much unexpected behaviour to be useful

Revert "Make use of Mojang's pitch hack, close #821"

This reverts commit c2dfef700feaf7235ece2fc140e93d02ae3f4af4.

* Removed delayed-teleport system and cleaned up movement reset for dead players

* Fixed health resetting to max when quitting and rejoining
This commit is contained in:
Dylan K. Taylor 2017-07-05 10:31:16 +01:00 committed by GitHub
parent b8a30309bb
commit 394f420059
3 changed files with 54 additions and 122 deletions

View File

@ -271,10 +271,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
protected $randomClientId; protected $randomClientId;
/** @var Vector3 */
protected $forceMovement = null;
/** @var Vector3 */
protected $teleportPosition = null;
protected $connected = true; protected $connected = true;
protected $ip; protected $ip;
protected $removeFormat = true; protected $removeFormat = true;
@ -660,7 +656,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->spawnPosition = null; $this->spawnPosition = null;
$this->gamemode = $this->server->getGamemode(); $this->gamemode = $this->server->getGamemode();
$this->setLevel($this->server->getDefaultLevel()); $this->setLevel($this->server->getDefaultLevel());
$this->newPosition = new Vector3(0, 0, 0);
$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0); $this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
$this->uuid = null; $this->uuid = null;
@ -827,7 +822,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
} }
if($this->chunkLoadCount >= $this->spawnThreshold and $this->spawned === false and $this->teleportPosition === null){ if($this->chunkLoadCount >= $this->spawnThreshold and $this->spawned === false){
$this->doFirstSpawn(); $this->doFirstSpawn();
} }
} }
@ -877,14 +872,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->inventory->sendArmorContents($this); $this->inventory->sendArmorContents($this);
$this->inventory->sendHeldItem($this); $this->inventory->sendHeldItem($this);
$pos = $this->level->getSafeSpawn($this);
$this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $pos));
$pos = $ev->getRespawnPosition();
$this->sendRespawnPacket($pos);
$this->sendPlayStatus(PlayStatusPacket::PLAYER_SPAWN); $this->sendPlayStatus(PlayStatusPacket::PLAYER_SPAWN);
if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){ if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
@ -914,8 +901,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
} }
$this->teleport($pos);
$this->spawnToAll(); $this->spawnToAll();
if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE) and $this->server->getProperty("auto-updater.on-update.warn-ops", true)){ if($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE) and $this->server->getProperty("auto-updater.on-update.warn-ops", true)){
@ -1413,8 +1398,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
protected function checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz){ protected function checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz){
if(!$this->onGround or $movY != 0){ if(!$this->onGround or $movY != 0){
$bb = clone $this->boundingBox; $bb = clone $this->boundingBox;
$bb->maxY = $bb->minY + 0.5; $bb->minY = $this->y - 0.01;
$bb->minY -= 1; $bb->maxY = $this->y + 0.01;
if(count($this->level->getCollisionBlocks($bb, true)) > 0){ if(count($this->level->getCollisionBlocks($bb, true)) > 0){
$this->onGround = true; $this->onGround = true;
}else{ }else{
@ -1493,10 +1479,13 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
protected function processMovement($tickDiff){ protected function processMovement($tickDiff){
if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->teleportPosition !== null or $this->isSleeping()){ if(!$this->isAlive() or !$this->spawned or $this->newPosition === null or $this->isSleeping()){
return; return;
} }
assert($this->x !== null and $this->y !== null and $this->z !== null);
assert($this->newPosition->x !== null and $this->newPosition->y !== null and $this->newPosition->z !== null);
$newPos = $this->newPosition; $newPos = $this->newPosition;
$distanceSquared = $newPos->distanceSquared($this); $distanceSquared = $newPos->distanceSquared($this);
@ -1504,6 +1493,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if(($distanceSquared / ($tickDiff ** 2)) > 100 and !$this->allowMovementCheats){ if(($distanceSquared / ($tickDiff ** 2)) > 100 and !$this->allowMovementCheats){
$this->server->getLogger()->warning($this->getName() . " moved too fast, reverting movement"); $this->server->getLogger()->warning($this->getName() . " moved too fast, reverting movement");
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
$revert = true; $revert = true;
}else{ }else{
if($this->chunk === null or !$this->chunk->isGenerated()){ if($this->chunk === null or !$this->chunk->isGenerated()){
@ -1542,6 +1532,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$revert = true; $revert = true;
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()])); $this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidMove", [$this->getName()]));
$this->server->getLogger()->debug("Old position: " . $this->asVector3() . ", new position: " . $this->newPosition);
} }
} }
@ -1608,9 +1599,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->lastPitch = $from->pitch; $this->lastPitch = $from->pitch;
$this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET); $this->sendPosition($from, $from->yaw, $from->pitch, MovePlayerPacket::MODE_RESET);
$this->forceMovement = new Vector3($from->x, $from->y, $from->z);
}else{ }else{
$this->forceMovement = null;
if($distanceSquared != 0 and $this->nextChunkOrderRun > 20){ if($distanceSquared != 0 and $this->nextChunkOrderRun > 20){
$this->nextChunkOrderRun = 20; $this->nextChunkOrderRun = 20;
} }
@ -1713,8 +1702,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
} }
$this->checkTeleportPosition();
$this->timings->stopTiming(); $this->timings->stopTiming();
return true; return true;
@ -1861,7 +1848,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$pk->entityRuntimeId = $this->id; $pk->entityRuntimeId = $this->id;
$pk->playerGamemode = Player::getClientFriendlyGamemode($this->gamemode); $pk->playerGamemode = Player::getClientFriendlyGamemode($this->gamemode);
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y + $this->baseOffset;
$pk->z = $this->z; $pk->z = $this->z;
$pk->pitch = $this->pitch; $pk->pitch = $this->pitch;
$pk->yaw = $this->yaw; $pk->yaw = $this->yaw;
@ -1917,8 +1904,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->inventory->sendCreativeContents(); $this->inventory->sendCreativeContents();
} }
$this->forceMovement = $this->teleportPosition = $this->getPosition();
$this->server->addOnlinePlayer($this); $this->server->addOnlinePlayer($this);
$this->server->onPlayerLogin($this); $this->server->onPlayerLogin($this);
@ -2141,14 +2126,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
public function handleMovePlayer(MovePlayerPacket $packet) : bool{ public function handleMovePlayer(MovePlayerPacket $packet) : bool{
$newPos = new Vector3($packet->x, $packet->y - $this->baseOffset, $packet->z); $newPos = new Vector3($packet->x, $packet->y - $this->baseOffset, $packet->z);
$revert = false; if((!$this->isAlive() or $this->spawned !== true) and $newPos->distanceSquared($this) > 0.01){
if(!$this->isAlive() or $this->spawned !== true){ $this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET);
$revert = true; $this->server->getLogger()->debug("Reverted movement of " . $this->getName() . " due to not alive or not spawned, received " . $newPos . ", locked at " . $this->asVector3());
$this->forceMovement = new Vector3($this->x, $this->y, $this->z);
}
if($this->teleportPosition !== null or ($this->forceMovement instanceof Vector3 and ($newPos->distanceSquared($this->forceMovement) > 0.1 or $revert))){
$this->sendPosition($this->forceMovement, $packet->yaw, $packet->pitch, MovePlayerPacket::MODE_RESET);
}else{ }else{
$packet->yaw %= 360; $packet->yaw %= 360;
$packet->pitch %= 360; $packet->pitch %= 360;
@ -2159,7 +2139,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->setRotation($packet->yaw, $packet->pitch); $this->setRotation($packet->yaw, $packet->pitch);
$this->newPosition = $newPos; $this->newPosition = $newPos;
$this->forceMovement = null;
} }
return true; return true;
@ -2726,7 +2705,16 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn())); $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $this->getSpawn()));
$this->teleport($ev->getRespawnPosition()); $realSpawn = $ev->getRespawnPosition()->add(0.5, 0, 0.5);
if($realSpawn->distanceSquared($this->getSpawn()->add(0.5, 0, 0.5)) > 0.01){
$this->teleport($realSpawn); //If the destination was modified by plugins
}else{
$this->setPosition($realSpawn); //The client will move to the position of its own accord once chunks are sent
$this->nextChunkOrderRun = 0;
}
$this->resetLastMovements();
$this->setSprinting(false); $this->setSprinting(false);
$this->setSneaking(false); $this->setSneaking(false);
@ -3966,14 +3954,14 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
} }
public function sendPosition(Vector3 $pos, $yaw = null, $pitch = null, $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null){ public function sendPosition(Vector3 $pos, float $yaw = null, float $pitch = null, int $mode = MovePlayerPacket::MODE_NORMAL, array $targets = null, float $baseOffsetOverride = null){
$yaw = $yaw === null ? $this->yaw : $yaw; $yaw = $yaw === null ? $this->yaw : $yaw;
$pitch = $pitch === null ? $this->pitch : $pitch; $pitch = $pitch === null ? $this->pitch : $pitch;
$pk = new MovePlayerPacket(); $pk = new MovePlayerPacket();
$pk->entityRuntimeId = $this->getId(); $pk->entityRuntimeId = $this->getId();
$pk->x = $pos->x; $pk->x = $pos->x;
$pk->y = $pos->y + $this->baseOffset; $pk->y = $pos->y + ($baseOffsetOverride ?? $this->baseOffset);
$pk->z = $pos->z; $pk->z = $pos->z;
$pk->bodyYaw = $yaw; $pk->bodyYaw = $yaw;
$pk->pitch = $pitch; $pk->pitch = $pitch;
@ -3986,18 +3974,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->dataPacket($pk); $this->dataPacket($pk);
} }
//TODO: Remove this hack for client bug
$pk = new MovePlayerPacket();
$pk->entityRuntimeId = $this->getId();
$pk->x = $pos->x;
$pk->y = $pos->y + $this->baseOffset;
$pk->z = $pos->z;
$pk->bodyYaw = $yaw;
$pk->pitch = $pitch;
$pk->yaw = $yaw;
$pk->mode = MovePlayerPacket::MODE_PITCH;
$this->dataPacket($pk);
$this->newPosition = null; $this->newPosition = null;
} }
@ -4036,46 +4012,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
} }
} }
protected function checkTeleportPosition(){
if($this->teleportPosition !== null){
$chunkX = $this->teleportPosition->x >> 4;
$chunkZ = $this->teleportPosition->z >> 4;
for($X = -1; $X <= 1; ++$X){
for($Z = -1; $Z <= 1; ++$Z){
if(!isset($this->usedChunks[$index = Level::chunkHash($chunkX + $X, $chunkZ + $Z)]) or $this->usedChunks[$index] === false){
return false;
}
}
}
$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET);
//This only needs to be sent to players who could see us before the teleport.
$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET, $this->getViewers());
$this->spawnToAll();
$this->forceMovement = $this->teleportPosition;
$this->teleportPosition = null;
return true;
}
return true;
}
/** /**
* @param Vector3|Position|Location $pos * {@inheritdoc}
* @param float $yaw
* @param float $pitch
*
* @return bool
*/ */
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){ public function teleport(Vector3 $pos, float $yaw = null, float $pitch = null) : bool{
if(!$this->isOnline()){
return false;
}
$oldPos = $this->getPosition();
if(parent::teleport($pos, $yaw, $pitch)){ if(parent::teleport($pos, $yaw, $pitch)){
foreach($this->windowIndex as $window){ foreach($this->windowIndex as $window){
@ -4085,49 +4025,31 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->removeWindow($window); $this->removeWindow($window);
} }
$this->teleportPosition = new Vector3($this->x, $this->y, $this->z); $this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_TELEPORT, null, 0.0);
$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_TELEPORT, $this->getViewers(), 0.0);
if(!$this->checkTeleportPosition()){ $this->spawnToAll();
$this->forceMovement = $oldPos;
}else{
$this->spawnToAll();
}
$this->resetFallDistance(); $this->resetFallDistance();
$this->nextChunkOrderRun = 0; $this->nextChunkOrderRun = 0;
$this->newPosition = null; $this->newPosition = null;
$this->stopSleep(); $this->stopSleep();
return true; return true;
} }
return false; return false;
} }
/** /**
* This method may not be reliable. Clients don't like to be moved into unloaded chunks. * @deprecated This functionality is now performed in {@link Player#teleport}.
* Use teleport() for a delayed teleport after chunks have been sent.
* *
* @param Vector3 $pos * @param Vector3 $pos
* @param float $yaw * @param float|null $yaw
* @param float $pitch * @param float|null $pitch
*/ */
public function teleportImmediate(Vector3 $pos, $yaw = null, $pitch = null){ public function teleportImmediate(Vector3 $pos, float $yaw = null, float $pitch = null) : bool{
if(parent::teleport($pos, $yaw, $pitch)){ return $this->teleport($pos, $yaw, $pitch);
foreach($this->windowIndex as $window){
if($window === $this->inventory){
continue;
}
$this->removeWindow($window);
}
$this->forceMovement = new Vector3($this->x, $this->y, $this->z);
$this->sendPosition($this, $this->yaw, $this->pitch, MovePlayerPacket::MODE_RESET);
$this->resetFallDistance();
$this->orderChunks();
$this->nextChunkOrderRun = 0;
$this->newPosition = null;
}
} }
/** /**

View File

@ -365,6 +365,8 @@ abstract class Entity extends Location implements Metadatable{
$this->setMotion($this->temporalVector->setComponents(0, 0, 0)); $this->setMotion($this->temporalVector->setComponents(0, 0, 0));
} }
$this->resetLastMovements();
assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z)); assert(!is_nan($this->x) and !is_infinite($this->x) and !is_nan($this->y) and !is_infinite($this->y) and !is_nan($this->z) and !is_infinite($this->z));
if(!isset($this->namedtag->FallDistance)){ if(!isset($this->namedtag->FallDistance)){
@ -1744,6 +1746,12 @@ abstract class Entity extends Location implements Metadatable{
return true; return true;
} }
protected function resetLastMovements(){
list($this->lastX, $this->lastY, $this->lastZ) = [$this->x, $this->y, $this->z];
list($this->lastYaw, $this->lastPitch) = [$this->yaw, $this->pitch];
list($this->lastMotionX, $this->lastMotionY, $this->lastMotionZ) = [$this->motionX, $this->motionY, $this->motionZ];
}
public function getMotion(){ public function getMotion(){
return new Vector3($this->motionX, $this->motionY, $this->motionZ); return new Vector3($this->motionX, $this->motionY, $this->motionZ);
} }
@ -1778,12 +1786,12 @@ abstract class Entity extends Location implements Metadatable{
/** /**
* @param Vector3|Position|Location $pos * @param Vector3|Position|Location $pos
* @param float $yaw * @param float|null $yaw
* @param float $pitch * @param float|null $pitch
* *
* @return bool * @return bool
*/ */
public function teleport(Vector3 $pos, $yaw = null, $pitch = null){ public function teleport(Vector3 $pos, float $yaw = null, float $pitch = null) : bool{
if($pos instanceof Location){ if($pos instanceof Location){
$yaw = $yaw === null ? $pos->yaw : $yaw; $yaw = $yaw === null ? $pos->yaw : $yaw;
$pitch = $pitch === null ? $pos->pitch : $pitch; $pitch = $pitch === null ? $pos->pitch : $pitch;

View File

@ -54,8 +54,10 @@ abstract class Living extends Entity implements Damageable{
if(isset($this->namedtag->HealF)){ if(isset($this->namedtag->HealF)){
$this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag["HealF"]); $this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag["HealF"]);
unset($this->namedtag->HealF); unset($this->namedtag->HealF);
}elseif(isset($this->namedtag->Health) and !($this->namedtag->Health instanceof FloatTag)){ }elseif(isset($this->namedtag->Health)){
$this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag->Health->getValue()); if(!($this->namedtag->Health instanceof FloatTag)){
$this->namedtag->Health = new FloatTag("Health", (float) $this->namedtag->Health->getValue());
}
}else{ }else{
$this->namedtag->Health = new FloatTag("Health", (float) $this->getMaxHealth()); $this->namedtag->Health = new FloatTag("Health", (float) $this->getMaxHealth());
} }