Fixed a wide range of bugs with floating-point coordinates getting incorrectly int-casted

This causes lots of bugs in negative coordinates.

This fixes #1789 after world load & save.
This commit is contained in:
Dylan K. Taylor 2018-02-15 10:27:42 +00:00
parent 4e9e285e37
commit e7e4645c0b
7 changed files with 31 additions and 29 deletions

View File

@ -1017,8 +1017,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$newOrder = [];
$unloadChunks = $this->usedChunks;
$centerX = $this->x >> 4;
$centerZ = $this->z >> 4;
$centerX = $this->getFloorX() >> 4;
$centerZ = $this->getFloorZ() >> 4;
for($x = 0; $x < $radius; ++$x){
for($z = 0; $z <= $x; ++$z){
@ -1127,9 +1127,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
$this->spawnPosition = new WeakPosition($pos->x, $pos->y, $pos->z, $level);
$pk = new SetSpawnPositionPacket();
$pk->x = (int) $this->spawnPosition->x;
$pk->y = (int) $this->spawnPosition->y;
$pk->z = (int) $this->spawnPosition->z;
$pk->x = $this->spawnPosition->getFloorX();
$pk->y = $this->spawnPosition->getFloorY();
$pk->z = $this->spawnPosition->getFloorZ();
$pk->spawnType = SetSpawnPositionPacket::TYPE_PLAYER_SPAWN;
$pk->spawnForced = false;
$this->dataPacket($pk);
@ -1476,7 +1476,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$revert = true;
}else{
if($this->chunk === null or !$this->chunk->isGenerated()){
$chunk = $this->level->getChunk($newPos->x >> 4, $newPos->z >> 4, false);
$chunk = $this->level->getChunk($newPos->getFloorX() >> 4, $newPos->getFloorZ() >> 4, false);
if($chunk === null or !$chunk->isGenerated()){
$revert = true;
$this->nextChunkOrderRun = 0;
@ -3349,9 +3349,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($this->hasValidSpawnPosition()){
$this->namedtag->setString("SpawnLevel", $this->spawnPosition->getLevel()->getFolderName());
$this->namedtag->setInt("SpawnX", (int) $this->spawnPosition->x);
$this->namedtag->setInt("SpawnY", (int) $this->spawnPosition->y);
$this->namedtag->setInt("SpawnZ", (int) $this->spawnPosition->z);
$this->namedtag->setInt("SpawnX", $this->spawnPosition->getFloorX());
$this->namedtag->setInt("SpawnY", $this->spawnPosition->getFloorY());
$this->namedtag->setInt("SpawnZ", $this->spawnPosition->getFloorZ());
if(!$this->isAlive()){
//hack for respawn after quit

View File

@ -775,9 +775,9 @@ class Server{
], NBT::TAG_Double),
new StringTag("Level", $this->getDefaultLevel()->getFolderName()),
//new StringTag("SpawnLevel", $this->getDefaultLevel()->getFolderName()),
//new IntTag("SpawnX", (int) $spawn->x),
//new IntTag("SpawnY", (int) $spawn->y),
//new IntTag("SpawnZ", (int) $spawn->z),
//new IntTag("SpawnX", $spawn->getFloorX()),
//new IntTag("SpawnY", $spawn->getFloorY()),
//new IntTag("SpawnZ", $spawn->getFloorZ()),
//new ByteTag("SpawnForced", 1), //TODO
new ListTag("Inventory", [], NBT::TAG_Compound),
new ListTag("EnderChestInventory", [], NBT::TAG_Compound),
@ -1103,8 +1103,8 @@ class Server{
$this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));
$spawnLocation = $level->getSpawnLocation();
$centerX = $spawnLocation->x >> 4;
$centerZ = $spawnLocation->z >> 4;
$centerX = $spawnLocation->getFloorX() >> 4;
$centerZ = $spawnLocation->getFloorZ() >> 4;
$order = [];

View File

@ -83,7 +83,7 @@ class SpawnpointCommand extends VanillaCommand{
}
}elseif(count($args) <= 1){
if($sender instanceof Player){
$pos = new Position((int) $sender->x, (int) $sender->y, (int) $sender->z, $sender->getLevel());
$pos = new Position($sender->getFloorX(), $sender->getFloorY(), $sender->getFloorZ(), $sender->getLevel());
$target->setSpawn($pos);
Command::broadcastCommandMessage($sender, new TranslationContainer("commands.spawnpoint.success", [$target->getName(), round($pos->x, 2), round($pos->y, 2), round($pos->z, 2)]));

View File

@ -484,7 +484,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
/** @var float[] $pos */
$pos = $this->namedtag->getListTag("Pos")->getAllValues();
$this->chunk = $level->getChunk(((int) $pos[0]) >> 4, ((int) $pos[2]) >> 4, true);
$this->chunk = $level->getChunk(((int) floor($pos[0])) >> 4, ((int) floor($pos[2])) >> 4, true);
if($this->chunk === null){
throw new \InvalidStateException("Cannot create entities in unloaded chunks");
}
@ -1757,14 +1757,16 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function checkChunks(){
if($this->chunk === null or ($this->chunk->getX() !== ($this->x >> 4) or $this->chunk->getZ() !== ($this->z >> 4))){
$chunkX = $this->getFloorX() >> 4;
$chunkZ = $this->getFloorZ() >> 4;
if($this->chunk === null or ($this->chunk->getX() !== $chunkX or $this->chunk->getZ() !== $chunkZ)){
if($this->chunk !== null){
$this->chunk->removeEntity($this);
}
$this->chunk = $this->level->getChunk($this->x >> 4, $this->z >> 4, true);
$this->chunk = $this->level->getChunk($chunkX, $chunkZ, true);
if(!$this->justCreated){
$newChunk = $this->level->getChunkPlayers($this->x >> 4, $this->z >> 4);
$newChunk = $this->level->getChunkPlayers($chunkX, $chunkZ);
foreach($this->hasSpawned as $player){
if(!isset($newChunk[$player->getLoaderId()])){
$this->despawnFrom($player);

View File

@ -233,7 +233,7 @@ class Explosion{
$pk->position = $this->source->asVector3();
$pk->radius = $this->size;
$pk->records = $send;
$this->level->addChunkPacket($source->x >> 4, $source->z >> 4, $pk);
$this->level->addChunkPacket($source->getFloorX() >> 4, $source->getFloorZ() >> 4, $pk);
$this->level->addParticle(new HugeExplodeSeedParticle($source));
$this->level->broadcastLevelSoundEvent($source, LevelSoundEventPacket::SOUND_EXPLODE);

View File

@ -478,7 +478,7 @@ class Level implements ChunkManager, Metadatable{
if($players === null){
foreach($pk as $e){
$this->addChunkPacket($sound->x >> 4, $sound->z >> 4, $e);
$this->addChunkPacket($sound->getFloorX() >> 4, $sound->getFloorZ() >> 4, $e);
}
}else{
$this->server->batchPackets($players, $pk, false);
@ -493,7 +493,7 @@ class Level implements ChunkManager, Metadatable{
if($players === null){
foreach($pk as $e){
$this->addChunkPacket($particle->x >> 4, $particle->z >> 4, $e);
$this->addChunkPacket($particle->getFloorX() >> 4, $particle->getFloorZ() >> 4, $e);
}
}else{
$this->server->batchPackets($players, $pk, false);
@ -513,7 +513,7 @@ class Level implements ChunkManager, Metadatable{
$pk->data = $data;
if($pos !== null){
$pk->position = $pos->asVector3();
$this->addChunkPacket($pos->x >> 4, $pos->z >> 4, $pk);
$this->addChunkPacket($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4, $pk);
}else{
$pk->position = null;
$this->addGlobalPacket($pk);
@ -538,7 +538,7 @@ class Level implements ChunkManager, Metadatable{
$pk->unknownBool = $unknown;
$pk->disableRelativeVolume = $disableRelativeVolume;
$pk->position = $pos->asVector3();
$this->addChunkPacket($pos->x >> 4, $pos->z >> 4, $pk);
$this->addChunkPacket($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4, $pk);
}
public function getAutoSave() : bool{
@ -987,8 +987,8 @@ class Level implements ChunkManager, Metadatable{
$randRange = (int) ($randRange > $this->chunkTickRadius ? $this->chunkTickRadius : $randRange);
foreach($this->loaders as $loader){
$chunkX = $loader->getX() >> 4;
$chunkZ = $loader->getZ() >> 4;
$chunkX = (int) floor($loader->getX()) >> 4;
$chunkZ = (int) floor($loader->getZ()) >> 4;
$index = Level::chunkHash($chunkX, $chunkZ);
$existingLoaders = max(0, $this->chunkTickList[$index] ?? 0);

View File

@ -89,9 +89,9 @@ abstract class BaseLevelProvider implements LevelProvider{
}
public function setSpawn(Vector3 $pos){
$this->levelData->setInt("SpawnX", (int) $pos->x);
$this->levelData->setInt("SpawnY", (int) $pos->y);
$this->levelData->setInt("SpawnZ", (int) $pos->z);
$this->levelData->setInt("SpawnX", $pos->getFloorX());
$this->levelData->setInt("SpawnY", $pos->getFloorY());
$this->levelData->setInt("SpawnZ", $pos->getFloorZ());
}
public function doGarbageCollection(){