diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index aaf729dc3..b3c9399e4 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -499,10 +499,10 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $entity->despawnFrom($this); } } - $pk = new UnloadChunkPacket(); + /*$pk = new UnloadChunkPacket(); $pk->chunkX = $x; $pk->chunkZ = $z; - $this->dataPacket($pk); + $this->dataPacket($pk);*/ $this->getLevel()->freeChunk($x, $z, $this); unset($this->usedChunks[$index]); @@ -584,7 +584,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->chunkLoadTask->setNextRun($this->chunkLoadTask->getNextRun() + 30); }else{ $count = 0; - $limit = (int) $this->server->getProperty("chunk-sending.per-tick", 1); + $limit = (int) $this->server->getProperty("chunk-sending.per-tick", 4); foreach($this->loadQueue as $index => $distance){ if($count >= $limit){ break; @@ -594,8 +594,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $Z = null; Level::getXZ($index, $X, $Z); if(!$this->getLevel()->isChunkPopulated($X, $Z)){ - $this->chunkLoadTask->setNextRun($this->chunkLoadTask->getNextRun() + 5); - return; + continue; } unset($this->loadQueue[$index]); @@ -713,10 +712,10 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $entity->despawnFrom($this); } } - $pk = new UnloadChunkPacket(); + /*$pk = new UnloadChunkPacket(); $pk->chunkX = $X; $pk->chunkZ = $Z; - $this->dataPacket($pk); + $this->dataPacket($pk);*/ unset($this->usedChunks[$index]); } } diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 2e3172656..e041d977b 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -726,17 +726,12 @@ abstract class Block extends Position implements Metadatable{ * Sets the block position to a new Position object * * @param Position $v - * - * @throws \RuntimeException */ final public function position(Position $v){ - if(!$v->isValid()){ - throw new \RuntimeException("Undefined Level reference"); - } $this->x = (int) $v->x; $this->y = (int) $v->y; $this->z = (int) $v->z; - $this->setLevel($v->getLevel(), false); + $this->level = $v->level; } /** diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 169d53aa7..cec50207a 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -494,7 +494,7 @@ abstract class Entity extends Position implements Metadatable{ Server::broadcastPacket($this->hasSpawned, $pk); } - if(!($this instanceof Player) and ($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){ + if(($this->lastMotionX != $this->motionX or $this->lastMotionY != $this->motionY or $this->lastMotionZ != $this->motionZ)){ $this->lastMotionX = $this->motionX; $this->lastMotionY = $this->motionY; $this->lastMotionZ = $this->motionZ; @@ -504,6 +504,12 @@ abstract class Entity extends Position implements Metadatable{ [$this->getID(), $this->motionX, $this->motionY, $this->motionZ] ]; Server::broadcastPacket($this->hasSpawned, $pk); + + if($this instanceof Player){ + $this->motionX = 0; + $this->motionY = 0; + $this->motionZ = 0; + } } } @@ -640,10 +646,10 @@ abstract class Entity extends Position implements Metadatable{ $entity->despawnFrom($this); } - $pk = new UnloadChunkPacket(); + /*$pk = new UnloadChunkPacket(); $pk->chunkX = $X; $pk->chunkZ = $Z; - $this->dataPacket($pk); + $this->dataPacket($pk);*/ } $this->getLevel()->freeAllChunks($this); } diff --git a/src/pocketmine/level/ChunkRequestTask.php b/src/pocketmine/level/ChunkRequestTask.php index db0c46486..4ade4ba40 100644 --- a/src/pocketmine/level/ChunkRequestTask.php +++ b/src/pocketmine/level/ChunkRequestTask.php @@ -34,14 +34,8 @@ class ChunkRequestTask extends AsyncTask{ protected $chunkZ; protected $compressionLevel; - /** @var string[4096] */ - protected $ids; - /** @var string[2048] */ - protected $meta; - /** @var string[2048] */ - protected $blockLight; - /** @var string[2048] */ - protected $skyLight; + /** @var \pocketmine\level\format\ChunkSection[] */ + protected $sections; /** @var string[256] */ protected $biomeIds; /** @var int[] */ @@ -54,30 +48,10 @@ class ChunkRequestTask extends AsyncTask{ $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; $chunk = $level->getChunkAt($chunkX, $chunkZ); - $ids = ""; - $meta = ""; - $blockLight = ""; - $skyLight = ""; $this->biomeIds = $chunk->getBiomeIdArray(); - $biomeColors = ""; - foreach($chunk->getBiomeColorArray() as $color){ - $biomeColors .= Binary::writeInt($color); - } + $this->biomeColors = $chunk->getBiomeColorArray(); - $this->biomeColors = $biomeColors; - - for($s = 0; $s < 8; ++$s){ - $section = $chunk->getSection($s); - $ids .= $section->getIdArray(); - $meta .= $section->getDataArray(); - $blockLight .= $section->getLightArray(); - $skyLight .= $section->getSkyLightArray(); - } - - $this->ids = $ids; - $this->meta = $meta; - $this->blockLight = $blockLight; - $this->skyLight = $skyLight; + $this->sections = $chunk->getSections(); $tiles = ""; $nbt = new NBT(NBT::LITTLE_ENDIAN); @@ -100,16 +74,33 @@ class ChunkRequestTask extends AsyncTask{ $orderedSkyLight = ""; $orderedLight = ""; + $ids = ""; + $meta = ""; + $blockLight = ""; + $skyLight = ""; + $biomeColors = ""; + + foreach($this->sections as $section){ + $ids .= $section->getIdArray(); + $meta .= $section->getDataArray(); + $blockLight .= $section->getLightArray(); + $skyLight .= $section->getSkyLightArray(); + } + for($x = 0; $x < 16; ++$x){ for($z = 0; $z < 16; ++$z){ - $orderedIds .= $this->getColumn($this->ids, $x, $z); - $orderedData .= $this->getHalfColumn($this->meta, $x, $z); - $orderedSkyLight .= $this->getHalfColumn($this->skyLight, $x, $z); - $orderedLight .= $this->getHalfColumn($this->blockLight, $x, $z); + $orderedIds .= $this->getColumn($ids, $x, $z); + $orderedData .= $this->getHalfColumn($meta, $x, $z); + $orderedSkyLight .= $this->getHalfColumn($skyLight, $x, $z); + $orderedLight .= $this->getHalfColumn($blockLight, $x, $z); } } - $ordered = zlib_encode(Binary::writeLInt($this->chunkX) . Binary::writeLInt($this->chunkZ) . $orderedIds . $orderedData . $orderedSkyLight . $orderedLight . $this->biomeIds . $this->biomeColors . $this->tiles, ZLIB_ENCODING_DEFLATE, $this->compressionLevel); + foreach($this->biomeColors as $color){ + $biomeColors .= Binary::writeInt($color); + } + + $ordered = zlib_encode(Binary::writeLInt($this->chunkX) . Binary::writeLInt($this->chunkZ) . $orderedIds . $orderedData . $orderedSkyLight . $orderedLight . $this->biomeIds . $biomeColors . $this->tiles, ZLIB_ENCODING_DEFLATE, $this->compressionLevel); $this->setResult($ordered); } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index a2fa2d341..10fd571c5 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -37,6 +37,7 @@ use pocketmine\event\LevelTimings; use pocketmine\event\player\PlayerInteractEvent; use pocketmine\item\Item; use pocketmine\level\format\Chunk; +use pocketmine\level\format\generic\EmptyChunkSection; use pocketmine\level\format\LevelProvider; use pocketmine\level\format\SimpleChunk; use pocketmine\level\generator\Generator; @@ -114,6 +115,9 @@ class Level implements ChunkManager, Metadatable{ private $folderName; + /** @var Chunk[] */ + private $chunks = []; + /** @var Block[][] */ protected $changedBlocks = []; protected $changedCount = []; @@ -211,7 +215,7 @@ class Level implements ChunkManager, Metadatable{ $this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 3))); $this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 128); $this->chunkTickList = []; - $this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true); + $this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", false); $this->timings = new LevelTimings($this); } @@ -501,15 +505,17 @@ class Level implements ChunkManager, Metadatable{ } $chunk = $this->getChunkAt($chunkX, $chunkZ, true); - for($Y = 0; $Y < 8; ++$Y){ - if(!$chunk->isSectionEmpty($Y)){ - $section = $chunk->getSection($Y); + + foreach($chunk->getSections() as $section){ + if(!($section instanceof EmptyChunkSection)){ + $Y = $section->getY(); + $k = mt_rand(0, PHP_INT_MAX); for($i = 0; $i < 3; ++$i){ - $k = mt_rand(0, PHP_INT_MAX); $j = $k >> 2; $x = $j & 0x0f; $y = ($j >> 8) & 0x0f; $z = ($j >> 16) & 0x0f; + $k %= 1073741827; $blockId = $section->getBlockId($x, $y, $z); if(isset($this->randomTickBlocks[$blockId])){ $block = Block::get($blockId, $section->getBlockData($x, $y, $z), new Position($chunkX * 16 + $x, $Y * 16 + $y, $chunkZ * 16 + $z, $this)); @@ -1236,7 +1242,7 @@ class Level implements ChunkManager, Metadatable{ * @return Chunk */ public function getChunkAt($x, $z, $create = false){ - return $this->provider->getChunk($x, $z, $create); + return isset($this->chunks[$index = "$x:$z"]) ? $this->chunks[$index] : $this->chunks[$index] = $this->provider->getChunk($x, $z, $create); } /** @@ -1272,7 +1278,9 @@ class Level implements ChunkManager, Metadatable{ foreach($this->getUsingChunk($x, $z) as $player){ $player->unloadChunk($x, $z); } + unset($this->chunks[Level::chunkHash($x, $z)]); $this->provider->setChunk($x, $z, $chunk); + $this->loadChunk($x, $z); } /** @@ -1298,7 +1306,7 @@ class Level implements ChunkManager, Metadatable{ * @return bool */ public function isChunkLoaded($x, $z){ - return $this->provider->isChunkLoaded($x, $z); + return isset($this->chunks["$x:$z"]) or $this->provider->isChunkLoaded($x, $z); } /** @@ -1488,13 +1496,18 @@ class Level implements ChunkManager, Metadatable{ $chunk = $this->provider->getChunk($x, $z, false); if($chunk instanceof Chunk){ + $this->chunks[Level::chunkHash($x, $z)] = $chunk; return true; }else{ $this->timings->syncChunkLoadTimer->startTiming(); $this->provider->loadChunk($x, $z); $this->timings->syncChunkLoadTimer->stopTiming(); - return $this->provider->getChunk($x, $z) instanceof Chunk; + if(($chunk = $this->provider->getChunk($x, $z)) instanceof Chunk){ + $this->chunks[Level::chunkHash($x, $z)] = $chunk; + return true; + } + return false; } } @@ -1522,8 +1535,9 @@ class Level implements ChunkManager, Metadatable{ } $this->timings->doChunkUnload->startTiming(); + unset($this->chunks[$index = Level::chunkHash($x, $z)]); $this->provider->unloadChunk($x, $z, $safe); - unset($this->usedChunks[Level::chunkHash($x, $z)]); + unset($this->usedChunks[$index]); Cache::remove("world:" . $this->getID() . ":$x:$z"); $this->timings->doChunkUnload->stopTiming(); diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 94c07ee80..3b7926525 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -19,14 +19,14 @@ debug: commands: false chunk-sending: - per-tick: 1 - compression-level: 7 + per-tick: 4 + compression-level: 9 chunk-ticking: per-tick: 80 tick-radius: 2 light-updates: false - clear-tick-list: true + clear-tick-list: false chunk-gc: period-in-ticks: 600 diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index 5a2724cd1..9f5e757ca 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -29,22 +29,18 @@ use pocketmine\Server; */ abstract class AsyncTask extends \Threaded{ - private $complete = null; - private $finished = null; - private $result = null; + public $complete = null; + public $finished = null; + public $result = null; public function run(){ - $this->lock(); $this->finished = false; $this->complete = false; $this->result = null; - $this->unlock(); $this->onRun(); - $this->lock(); $this->finished = true; - $this->unlock(); } @@ -52,7 +48,6 @@ abstract class AsyncTask extends \Threaded{ * @return bool */ public function isFinished(){ - return $this->finished === true; } @@ -88,6 +83,14 @@ abstract class AsyncTask extends \Threaded{ $this->result = @serialize($result); } + public function setTaskId($taskId){ + $this->taskId = $taskId; + } + + public function getTaskId(){ + return $this->taskId; + } + /** * Actions to execute when run * diff --git a/src/pocketmine/scheduler/ServerScheduler.php b/src/pocketmine/scheduler/ServerScheduler.php index 40e7c9d45..4ddfa381c 100644 --- a/src/pocketmine/scheduler/ServerScheduler.php +++ b/src/pocketmine/scheduler/ServerScheduler.php @@ -77,8 +77,10 @@ class ServerScheduler{ * @return void */ public function scheduleAsyncTask(AsyncTask $task){ + $id = $this->nextId(); + $task->setTaskId($id); $this->asyncPool->submit($task); - $this->asyncTaskStorage[spl_object_hash($task)] = $task; + $this->asyncTaskStorage[$id] = $task; ++$this->asyncTasks; } @@ -222,6 +224,12 @@ class ServerScheduler{ if($this->asyncTasks > 0){ //Garbage collector $this->asyncPool->collect([$this, "collectAsyncTask"]); + + foreach($this->asyncTaskStorage as $asyncTask){ + if($asyncTask->isFinished() and !$asyncTask->isCompleted()){ + $this->collectAsyncTask($asyncTask); + } + } } } @@ -230,7 +238,7 @@ class ServerScheduler{ --$this->asyncTasks; $task->onCompletion(Server::getInstance()); $task->setCompleted(); - unset($this->asyncTaskStorage[spl_object_hash($task)]); + unset($this->asyncTaskStorage[$task->getTaskId()]); return true; } return false;