Chunks no longer contain their own coordinates

This commit is contained in:
Dylan K. Taylor 2020-12-03 21:59:30 +00:00
parent 1f5998d24c
commit c808095978
23 changed files with 99 additions and 134 deletions

View File

@ -32,13 +32,23 @@ use pocketmine\world\World;
abstract class ChunkEvent extends WorldEvent{ abstract class ChunkEvent extends WorldEvent{
/** @var Chunk */ /** @var Chunk */
private $chunk; private $chunk;
/** @var int */
private $chunkX;
/** @var int */
private $chunkZ;
public function __construct(World $world, Chunk $chunk){ public function __construct(World $world, int $chunkX, int $chunkZ, Chunk $chunk){
parent::__construct($world); parent::__construct($world);
$this->chunk = $chunk; $this->chunk = $chunk;
$this->chunkX = $chunkX;
$this->chunkZ = $chunkZ;
} }
public function getChunk() : Chunk{ public function getChunk() : Chunk{
return $this->chunk; return $this->chunk;
} }
public function getChunkX() : int{ return $this->chunkX; }
public function getChunkZ() : int{ return $this->chunkZ; }
} }

View File

@ -33,8 +33,8 @@ class ChunkLoadEvent extends ChunkEvent{
/** @var bool */ /** @var bool */
private $newChunk; private $newChunk;
public function __construct(World $world, Chunk $chunk, bool $newChunk){ public function __construct(World $world, int $chunkX, int $chunkZ, Chunk $chunk, bool $newChunk){
parent::__construct($world, $chunk); parent::__construct($world, $chunkX, $chunkZ, $chunk);
$this->newChunk = $newChunk; $this->newChunk = $newChunk;
} }

View File

@ -66,7 +66,7 @@ class ChunkRequestTask extends AsyncTask{
} }
public function onRun() : void{ public function onRun() : void{
$chunk = FastChunkSerializer::deserialize($this->chunk, $this->chunkX, $this->chunkZ); $chunk = FastChunkSerializer::deserialize($this->chunk);
$subCount = ChunkSerializer::getSubChunkCount($chunk); $subCount = ChunkSerializer::getSubChunkCount($chunk);
$payload = ChunkSerializer::serialize($chunk, RuntimeBlockMapping::getInstance(), $this->tiles); $payload = ChunkSerializer::serialize($chunk, RuntimeBlockMapping::getInstance(), $this->tiles);
$this->setResult($this->compressor->compress(PacketBatch::fromPackets(LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer())); $this->setResult($this->compressor->compress(PacketBatch::fromPackets(LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer()));

View File

@ -183,9 +183,9 @@ class ChunkCache implements ChunkListener{
/** /**
* @see ChunkListener::onChunkChanged() * @see ChunkListener::onChunkChanged()
*/ */
public function onChunkChanged(Chunk $chunk) : void{ public function onChunkChanged(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//FIXME: this gets fired for stuff that doesn't change terrain related things (like lighting updates) //FIXME: this gets fired for stuff that doesn't change terrain related things (like lighting updates)
$this->destroyOrRestart($chunk->getX(), $chunk->getZ()); $this->destroyOrRestart($chunkX, $chunkZ);
} }
/** /**
@ -200,9 +200,9 @@ class ChunkCache implements ChunkListener{
/** /**
* @see ChunkListener::onChunkUnloaded() * @see ChunkListener::onChunkUnloaded()
*/ */
public function onChunkUnloaded(Chunk $chunk) : void{ public function onChunkUnloaded(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$this->destroy($chunk->getX(), $chunk->getZ()); $this->destroy($chunkX, $chunkZ);
$this->world->unregisterChunkListener($this, $chunk->getX(), $chunk->getZ()); $this->world->unregisterChunkListener($this, $chunkX, $chunkZ);
} }
/** /**

View File

@ -2358,18 +2358,18 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
onChunkUnloaded as private; onChunkUnloaded as private;
} }
public function onChunkChanged(Chunk $chunk) : void{ public function onChunkChanged(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$status = $this->usedChunks[$hash = World::chunkHash($chunk->getX(), $chunk->getZ())] ?? null; $status = $this->usedChunks[$hash = World::chunkHash($chunkX, $chunkZ)] ?? null;
if($status !== null && !$status->equals(UsedChunkStatus::NEEDED())){ if($status !== null && !$status->equals(UsedChunkStatus::NEEDED())){
$this->usedChunks[$hash] = UsedChunkStatus::NEEDED(); $this->usedChunks[$hash] = UsedChunkStatus::NEEDED();
$this->nextChunkOrderRun = 0; $this->nextChunkOrderRun = 0;
} }
} }
public function onChunkUnloaded(Chunk $chunk) : void{ public function onChunkUnloaded(int $chunkX, int $chunkZ, Chunk $chunk) : void{
if($this->isUsingChunk($chunk->getX(), $chunk->getZ())){ if($this->isUsingChunk($chunkX, $chunkZ)){
$this->logger->debug("Detected forced unload of chunk " . $chunk->getX() . " " . $chunk->getZ()); $this->logger->debug("Detected forced unload of chunk " . $chunkX . " " . $chunkZ);
$this->unloadChunk($chunk->getX(), $chunk->getZ()); $this->unloadChunk($chunkX, $chunkZ);
} }
} }
} }

View File

@ -43,23 +43,23 @@ interface ChunkListener{
/** /**
* This method will be called when a Chunk is replaced by a new one * This method will be called when a Chunk is replaced by a new one
*/ */
public function onChunkChanged(Chunk $chunk) : void; public function onChunkChanged(int $chunkX, int $chunkZ, Chunk $chunk) : void;
/** /**
* This method will be called when a registered chunk is loaded * This method will be called when a registered chunk is loaded
*/ */
public function onChunkLoaded(Chunk $chunk) : void; public function onChunkLoaded(int $chunkX, int $chunkZ, Chunk $chunk) : void;
/** /**
* This method will be called when a registered chunk is unloaded * This method will be called when a registered chunk is unloaded
*/ */
public function onChunkUnloaded(Chunk $chunk) : void; public function onChunkUnloaded(int $chunkX, int $chunkZ, Chunk $chunk) : void;
/** /**
* This method will be called when a registered chunk is populated * This method will be called when a registered chunk is populated
* Usually it'll be sent with another call to onChunkChanged() * Usually it'll be sent with another call to onChunkChanged()
*/ */
public function onChunkPopulated(Chunk $chunk) : void; public function onChunkPopulated(int $chunkX, int $chunkZ, Chunk $chunk) : void;
/** /**
* This method will be called when a block changes in a registered chunk * This method will be called when a block changes in a registered chunk

View File

@ -32,19 +32,19 @@ use pocketmine\world\format\Chunk;
*/ */
trait ChunkListenerNoOpTrait/* implements ChunkListener*/{ trait ChunkListenerNoOpTrait/* implements ChunkListener*/{
public function onChunkChanged(Chunk $chunk) : void{ public function onChunkChanged(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//NOOP //NOOP
} }
public function onChunkLoaded(Chunk $chunk) : void{ public function onChunkLoaded(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//NOOP //NOOP
} }
public function onChunkUnloaded(Chunk $chunk) : void{ public function onChunkUnloaded(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//NOOP //NOOP
} }
public function onChunkPopulated(Chunk $chunk) : void{ public function onChunkPopulated(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//NOOP //NOOP
} }

View File

@ -461,8 +461,9 @@ class World implements ChunkManager{
} }
$this->unloadCallbacks = []; $this->unloadCallbacks = [];
foreach($this->chunks as $chunk){ foreach($this->chunks as $chunkHash => $chunk){
$this->unloadChunk($chunk->getX(), $chunk->getZ(), false); self::getXZ($chunkHash, $chunkX, $chunkZ);
$this->unloadChunk($chunkX, $chunkZ, false);
} }
$this->save(); $this->save();
@ -796,7 +797,7 @@ class World implements ChunkManager{
if(count($blocks) > 512){ if(count($blocks) > 512){
$chunk = $this->getChunk($chunkX, $chunkZ); $chunk = $this->getChunk($chunkX, $chunkZ);
foreach($this->getChunkPlayers($chunkX, $chunkZ) as $p){ foreach($this->getChunkPlayers($chunkX, $chunkZ) as $p){
$p->onChunkChanged($chunk); $p->onChunkChanged($chunkX, $chunkZ, $chunk);
} }
}else{ }else{
foreach($this->createBlockUpdatePackets($blocks) as $packet){ foreach($this->createBlockUpdatePackets($blocks) as $packet){
@ -946,7 +947,7 @@ class World implements ChunkManager{
if($lightPopulatedState !== true){ if($lightPopulatedState !== true){
if($lightPopulatedState === false){ if($lightPopulatedState === false){
$this->chunks[$hash]->setLightPopulated(null); $this->chunks[$hash]->setLightPopulated(null);
$this->workerPool->submitTask(new LightPopulationTask($this, $this->chunks[$hash])); $this->workerPool->submitTask(new LightPopulationTask($this, $dx + $chunkX, $dz + $chunkZ, $this->chunks[$hash]));
} }
continue; continue;
} }
@ -1023,9 +1024,10 @@ class World implements ChunkManager{
public function saveChunks() : void{ public function saveChunks() : void{
$this->timings->syncChunkSaveTimer->startTiming(); $this->timings->syncChunkSaveTimer->startTiming();
try{ try{
foreach($this->chunks as $chunk){ foreach($this->chunks as $chunkHash => $chunk){
if($chunk->isDirty() and $chunk->isGenerated()){ if($chunk->isDirty() and $chunk->isGenerated()){
$this->provider->saveChunk($chunk); self::getXZ($chunkHash, $chunkX, $chunkZ);
$this->provider->saveChunk($chunkX, $chunkZ, $chunk);
$chunk->clearDirtyFlags(); $chunk->clearDirtyFlags();
} }
} }
@ -1979,10 +1981,10 @@ class World implements ChunkManager{
$oldChunk = $this->loadChunk($x, $z); $oldChunk = $this->loadChunk($x, $z);
$this->setChunk($x, $z, $chunk, false); $this->setChunk($x, $z, $chunk, false);
if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){
(new ChunkPopulateEvent($this, $chunk))->call(); (new ChunkPopulateEvent($this, $x, $z, $chunk))->call();
foreach($this->getChunkListeners($x, $z) as $listener){ foreach($this->getChunkListeners($x, $z) as $listener){
$listener->onChunkPopulated($chunk); $listener->onChunkPopulated($x, $z, $chunk);
} }
} }
} }
@ -2005,9 +2007,6 @@ class World implements ChunkManager{
return; return;
} }
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);
$chunkHash = World::chunkHash($chunkX, $chunkZ); $chunkHash = World::chunkHash($chunkX, $chunkZ);
$oldChunk = $this->loadChunk($chunkX, $chunkZ); $oldChunk = $this->loadChunk($chunkX, $chunkZ);
if($oldChunk !== null and $oldChunk !== $chunk){ if($oldChunk !== null and $oldChunk !== $chunk){
@ -2049,14 +2048,14 @@ class World implements ChunkManager{
} }
if($oldChunk === null){ if($oldChunk === null){
(new ChunkLoadEvent($this, $chunk, true))->call(); (new ChunkLoadEvent($this, $chunkX, $chunkZ, $chunk, true))->call();
foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){ foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){
$listener->onChunkLoaded($chunk); $listener->onChunkLoaded($chunkX, $chunkZ, $chunk);
} }
}else{ }else{
foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){ foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){
$listener->onChunkChanged($chunk); $listener->onChunkChanged($chunkX, $chunkZ, $chunk);
} }
} }
} }
@ -2233,16 +2232,16 @@ class World implements ChunkManager{
$this->chunks[$chunkHash] = $chunk; $this->chunks[$chunkHash] = $chunk;
unset($this->blockCache[$chunkHash]); unset($this->blockCache[$chunkHash]);
$this->initChunk($chunk); $this->initChunk($x, $z, $chunk);
(new ChunkLoadEvent($this, $chunk, false))->call(); (new ChunkLoadEvent($this, $x, $z, $chunk, false))->call();
if(!$this->isChunkInUse($x, $z)){ if(!$this->isChunkInUse($x, $z)){
$this->logger->debug("Newly loaded chunk $x $z has no loaders registered, will be unloaded at next available opportunity"); $this->logger->debug("Newly loaded chunk $x $z has no loaders registered, will be unloaded at next available opportunity");
$this->unloadChunkRequest($x, $z); $this->unloadChunkRequest($x, $z);
} }
foreach($this->getChunkListeners($x, $z) as $listener){ foreach($this->getChunkListeners($x, $z) as $listener){
$listener->onChunkLoaded($chunk); $listener->onChunkLoaded($x, $z, $chunk);
} }
$this->timings->syncChunkLoadTimer->stopTiming(); $this->timings->syncChunkLoadTimer->stopTiming();
@ -2250,7 +2249,7 @@ class World implements ChunkManager{
return $chunk; return $chunk;
} }
private function initChunk(Chunk $chunk) : void{ private function initChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
if($chunk->NBTentities !== null){ if($chunk->NBTentities !== null){
$this->timings->syncChunkLoadEntitiesTimer->startTiming(); $this->timings->syncChunkLoadEntitiesTimer->startTiming();
$entityFactory = EntityFactory::getInstance(); $entityFactory = EntityFactory::getInstance();
@ -2265,7 +2264,7 @@ class World implements ChunkManager{
}elseif($saveIdTag instanceof IntTag){ //legacy MCPE format }elseif($saveIdTag instanceof IntTag){ //legacy MCPE format
$saveId = "legacy(" . $saveIdTag->getValue() . ")"; $saveId = "legacy(" . $saveIdTag->getValue() . ")";
} }
$this->getLogger()->warning("Chunk " . $chunk->getX() . " " . $chunk->getZ() . ": Deleted unknown entity type $saveId"); $this->getLogger()->warning("Chunk $chunkX $chunkZ: Deleted unknown entity type $saveId");
continue; continue;
} }
}catch(\Exception $t){ //TODO: this shouldn't be here }catch(\Exception $t){ //TODO: this shouldn't be here
@ -2285,7 +2284,7 @@ class World implements ChunkManager{
if(($tile = $tileFactory->createFromData($this, $nbt)) !== null){ if(($tile = $tileFactory->createFromData($this, $nbt)) !== null){
$this->addTile($tile); $this->addTile($tile);
}else{ }else{
$this->getLogger()->warning("Chunk " . $chunk->getX() . " " . $chunk->getZ() . ": Deleted unknown tile entity type " . $nbt->getString("id", "<unknown>")); $this->getLogger()->warning("Chunk $chunkX $chunkZ: Deleted unknown tile entity type " . $nbt->getString("id", "<unknown>"));
continue; continue;
} }
} }
@ -2330,7 +2329,7 @@ class World implements ChunkManager{
$chunk = $this->chunks[$chunkHash] ?? null; $chunk = $this->chunks[$chunkHash] ?? null;
if($chunk !== null){ if($chunk !== null){
$ev = new ChunkUnloadEvent($this, $chunk); $ev = new ChunkUnloadEvent($this, $x, $z, $chunk);
$ev->call(); $ev->call();
if($ev->isCancelled()){ if($ev->isCancelled()){
$this->timings->doChunkUnload->stopTiming(); $this->timings->doChunkUnload->stopTiming();
@ -2341,14 +2340,14 @@ class World implements ChunkManager{
if($trySave and $this->getAutoSave() and $chunk->isGenerated() and $chunk->isDirty()){ if($trySave and $this->getAutoSave() and $chunk->isGenerated() and $chunk->isDirty()){
$this->timings->syncChunkSaveTimer->startTiming(); $this->timings->syncChunkSaveTimer->startTiming();
try{ try{
$this->provider->saveChunk($chunk); $this->provider->saveChunk($x, $z, $chunk);
}finally{ }finally{
$this->timings->syncChunkSaveTimer->stopTiming(); $this->timings->syncChunkSaveTimer->stopTiming();
} }
} }
foreach($this->getChunkListeners($x, $z) as $listener){ foreach($this->getChunkListeners($x, $z) as $listener){
$listener->onChunkUnloaded($chunk); $listener->onChunkUnloaded($x, $z, $chunk);
} }
$chunk->onUnload(); $chunk->onUnload();
@ -2509,7 +2508,7 @@ class World implements ChunkManager{
$chunk = $this->loadChunk($x, $z); $chunk = $this->loadChunk($x, $z);
if($chunk === null){ if($chunk === null){
$chunk = new Chunk($x, $z); $chunk = new Chunk();
} }
if(!$chunk->isPopulated()){ if(!$chunk->isPopulated()){
Timings::$populationTimer->startTiming(); Timings::$populationTimer->startTiming();
@ -2521,7 +2520,7 @@ class World implements ChunkManager{
} }
} }
$task = new PopulationTask($this, $chunk); $task = new PopulationTask($this, $x, $z, $chunk);
$workerId = $this->workerPool->selectWorker(); $workerId = $this->workerPool->selectWorker();
if(!isset($this->generatorRegisteredWorkers[$workerId])){ if(!isset($this->generatorRegisteredWorkers[$workerId])){
$this->registerGeneratorToWorker($workerId); $this->registerGeneratorToWorker($workerId);

View File

@ -45,11 +45,6 @@ class Chunk{
public const MAX_SUBCHUNKS = 16; public const MAX_SUBCHUNKS = 16;
/** @var int */
protected $x;
/** @var int */
protected $z;
/** @var int */ /** @var int */
private $dirtyFlags = 0; private $dirtyFlags = 0;
@ -89,10 +84,7 @@ class Chunk{
* @param CompoundTag[] $entities * @param CompoundTag[] $entities
* @param CompoundTag[] $tiles * @param CompoundTag[] $tiles
*/ */
public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], ?array $entities = null, ?array $tiles = null, ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null){ public function __construct(array $subChunks = [], ?array $entities = null, ?array $tiles = null, ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null){
$this->x = $chunkX;
$this->z = $chunkZ;
$this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS);
foreach($this->subChunks as $y => $null){ foreach($this->subChunks as $y => $null){
@ -107,22 +99,6 @@ class Chunk{
$this->NBTentities = $entities; $this->NBTentities = $entities;
} }
public function getX() : int{
return $this->x;
}
public function getZ() : int{
return $this->z;
}
public function setX(int $x) : void{
$this->x = $x;
}
public function setZ(int $z) : void{
$this->z = $z;
}
/** /**
* Returns the chunk height in count of subchunks. * Returns the chunk height in count of subchunks.
*/ */

View File

@ -66,11 +66,11 @@ abstract class BaseWorldProvider implements WorldProvider{
return $this->readChunk($chunkX, $chunkZ); return $this->readChunk($chunkX, $chunkZ);
} }
public function saveChunk(Chunk $chunk) : void{ public function saveChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
if(!$chunk->isGenerated()){ if(!$chunk->isGenerated()){
throw new \InvalidStateException("Cannot save un-generated chunk"); throw new \InvalidStateException("Cannot save un-generated chunk");
} }
$this->writeChunk($chunk); $this->writeChunk($chunkX, $chunkZ, $chunk);
} }
/** /**
@ -78,5 +78,5 @@ abstract class BaseWorldProvider implements WorldProvider{
*/ */
abstract protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk; abstract protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk;
abstract protected function writeChunk(Chunk $chunk) : void; abstract protected function writeChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void;
} }

View File

@ -107,7 +107,7 @@ final class FastChunkSerializer{
/** /**
* Deserializes a fast-serialized chunk * Deserializes a fast-serialized chunk
*/ */
public static function deserialize(string $data, int $chunkX, int $chunkZ) : Chunk{ public static function deserialize(string $data) : Chunk{
$stream = new BinaryStream($data); $stream = new BinaryStream($data);
$flags = $stream->getByte(); $flags = $stream->getByte();
@ -144,7 +144,7 @@ final class FastChunkSerializer{
} }
} }
$chunk = new Chunk($chunkX, $chunkZ, $subChunks, null, null, $biomeIds, $heightMap); $chunk = new Chunk($subChunks, null, null, $biomeIds, $heightMap);
$chunk->setGenerated($terrainGenerated); $chunk->setGenerated($terrainGenerated);
$chunk->setPopulated($terrainPopulated); $chunk->setPopulated($terrainPopulated);
$chunk->setLightPopulated($lightPopulated); $chunk->setLightPopulated($lightPopulated);

View File

@ -138,9 +138,10 @@ class FormatConverter{
$start = microtime(true); $start = microtime(true);
$thisRound = $start; $thisRound = $start;
foreach($this->oldProvider->getAllChunks(true, $this->logger) as $chunk){ foreach($this->oldProvider->getAllChunks(true, $this->logger) as $coords => $chunk){
[$chunkX, $chunkZ] = $coords;
$chunk->setDirty(); $chunk->setDirty();
$new->saveChunk($chunk); $new->saveChunk($chunkX, $chunkZ, $chunk);
$counter++; $counter++;
if(($counter % $this->chunksPerProgressUpdate) === 0){ if(($counter % $this->chunksPerProgressUpdate) === 0){
$time = microtime(true); $time = microtime(true);

View File

@ -75,6 +75,7 @@ interface WorldProvider{
* Returns a generator which yields all the chunks in this world. * Returns a generator which yields all the chunks in this world.
* *
* @return \Generator|Chunk[] * @return \Generator|Chunk[]
* @phpstan-return \Generator<array{int, int}, Chunk, void, void>
* @throws CorruptedChunkException * @throws CorruptedChunkException
*/ */
public function getAllChunks(bool $skipCorrupted = false, ?\Logger $logger = null) : \Generator; public function getAllChunks(bool $skipCorrupted = false, ?\Logger $logger = null) : \Generator;

View File

@ -39,5 +39,5 @@ interface WritableWorldProvider extends WorldProvider{
/** /**
* Saves a chunk (usually to disk). * Saves a chunk (usually to disk).
*/ */
public function saveChunk(Chunk $chunk) : void; public function saveChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void;
} }

View File

@ -398,8 +398,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
} }
$chunk = new Chunk( $chunk = new Chunk(
$chunkX,
$chunkZ,
$subChunks, $subChunks,
$entities, $entities,
$tiles, $tiles,
@ -417,9 +415,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
return $chunk; return $chunk;
} }
protected function writeChunk(Chunk $chunk) : void{ protected function writeChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$idMap = LegacyBlockIdToStringIdMap::getInstance(); $idMap = LegacyBlockIdToStringIdMap::getInstance();
$index = LevelDB::chunkIndex($chunk->getX(), $chunk->getZ()); $index = LevelDB::chunkIndex($chunkX, $chunkZ);
$write = new \LevelDBWriteBatch(); $write = new \LevelDBWriteBatch();
$write->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION)); $write->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION));
@ -509,7 +507,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$chunkZ = Binary::readLInt(substr($key, 4, 4)); $chunkZ = Binary::readLInt(substr($key, 4, 4));
try{ try{
if(($chunk = $this->loadChunk($chunkX, $chunkZ)) !== null){ if(($chunk = $this->loadChunk($chunkX, $chunkZ)) !== null){
yield $chunk; yield [$chunkX, $chunkZ] => $chunk;
} }
}catch(CorruptedChunkException $e){ }catch(CorruptedChunkException $e){
if(!$skipCorrupted){ if(!$skipCorrupted){

View File

@ -93,8 +93,6 @@ trait LegacyAnvilChunkTrait{
} }
$result = new Chunk( $result = new Chunk(
$chunk->getInt("xPos"),
$chunk->getInt("zPos"),
$subChunks, $subChunks,
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [], ($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],

View File

@ -89,8 +89,6 @@ class McRegion extends RegionWorldProvider{
} }
$result = new Chunk( $result = new Chunk(
$chunk->getInt("xPos"),
$chunk->getInt("zPos"),
$subChunks, $subChunks,
($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [],
($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [], ($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [],

View File

@ -228,10 +228,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
return null; return null;
} }
protected function writeChunk(Chunk $chunk) : void{ protected function writeChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$chunkX = $chunk->getX();
$chunkZ = $chunk->getZ();
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($regionX, $regionZ); $this->loadRegion($regionX, $regionZ);
@ -263,7 +260,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
try{ try{
$chunk = $this->loadChunk($chunkX, $chunkZ); $chunk = $this->loadChunk($chunkX, $chunkZ);
if($chunk !== null){ if($chunk !== null){
yield $chunk; yield [$chunkX, $chunkZ] => $chunk;
} }
}catch(CorruptedChunkException $e){ }catch(CorruptedChunkException $e){
if(!$skipCorrupted){ if(!$skipCorrupted){

View File

@ -145,7 +145,7 @@ class Flat extends Generator{
} }
protected function generateBaseChunk() : void{ protected function generateBaseChunk() : void{
$this->chunk = new Chunk(0, 0); $this->chunk = new Chunk();
$this->chunk->setGenerated(); $this->chunk->setGenerated();
for($Z = 0; $Z < 16; ++$Z){ for($Z = 0; $Z < 16; ++$Z){
@ -170,10 +170,7 @@ class Flat extends Generator{
} }
public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{ public function generateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{
$chunk = clone $this->chunk; $world->setChunk($chunkX, $chunkZ, clone $this->chunk);
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);
$world->setChunk($chunkX, $chunkZ, $chunk);
} }
public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{ public function populateChunk(ChunkManager $world, int $chunkX, int $chunkZ) : void{

View File

@ -65,14 +65,14 @@ class PopulationTask extends AsyncTask{
/** @var string */ /** @var string */
public $chunk8; public $chunk8;
public function __construct(World $world, Chunk $chunk){ public function __construct(World $world, int $chunkX, int $chunkZ, Chunk $chunk){
$this->state = true; $this->state = true;
$this->worldId = $world->getId(); $this->worldId = $world->getId();
$this->chunkX = $chunk->getX(); $this->chunkX = $chunkX;
$this->chunkZ = $chunk->getZ(); $this->chunkZ = $chunkZ;
$this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk);
foreach($world->getAdjacentChunks($chunk->getX(), $chunk->getZ()) as $i => $c){ foreach($world->getAdjacentChunks($chunkX, $chunkZ) as $i => $c){
$this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serializeWithoutLight($c) : null; $this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serializeWithoutLight($c) : null;
} }
@ -91,40 +91,40 @@ class PopulationTask extends AsyncTask{
/** @var Chunk[] $chunks */ /** @var Chunk[] $chunks */
$chunks = []; $chunks = [];
$chunk = FastChunkSerializer::deserialize($this->chunk, $this->chunkX, $this->chunkZ); $chunk = FastChunkSerializer::deserialize($this->chunk);
for($i = 0; $i < 9; ++$i){ for($i = 0; $i < 9; ++$i){
if($i === 4){ if($i === 4){
continue; continue;
} }
$xx = -1 + $i % 3;
$zz = -1 + (int) ($i / 3);
$ck = $this->{"chunk$i"}; $ck = $this->{"chunk$i"};
if($ck === null){ if($ck === null){
$chunks[$i] = new Chunk($this->chunkX + $xx, $this->chunkZ + $zz); $chunks[$i] = new Chunk();
}else{ }else{
$chunks[$i] = FastChunkSerializer::deserialize($ck, $this->chunkX + $xx, $this->chunkZ + $zz); $chunks[$i] = FastChunkSerializer::deserialize($ck);
} }
} }
$manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk); $manager->setChunk($this->chunkX, $this->chunkZ, $chunk);
if(!$chunk->isGenerated()){ if(!$chunk->isGenerated()){
$generator->generateChunk($manager, $chunk->getX(), $chunk->getZ()); $generator->generateChunk($manager, $this->chunkX, $this->chunkZ);
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ()); $chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
$chunk->setGenerated(); $chunk->setGenerated();
} }
foreach($chunks as $i => $c){ foreach($chunks as $i => $c){
$manager->setChunk($c->getX(), $c->getZ(), $c); $cX = (-1 + $i % 3) + $this->chunkX;
$cZ = (-1 + intdiv($i, 3)) + $this->chunkZ;
$manager->setChunk($cX, $cZ, $c);
if(!$c->isGenerated()){ if(!$c->isGenerated()){
$generator->generateChunk($manager, $c->getX(), $c->getZ()); $generator->generateChunk($manager, $cX, $cZ);
$chunks[$i] = $manager->getChunk($c->getX(), $c->getZ()); $chunks[$i] = $manager->getChunk($cX, $cZ);
$chunks[$i]->setGenerated(); $chunks[$i]->setGenerated();
} }
} }
$generator->populateChunk($manager, $chunk->getX(), $chunk->getZ()); $generator->populateChunk($manager, $this->chunkX, $this->chunkZ);
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ()); $chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
$chunk->setPopulated(); $chunk->setPopulated();
$this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk);
@ -142,7 +142,7 @@ class PopulationTask extends AsyncTask{
$world->registerGeneratorToWorker($this->worker->getAsyncWorkerId()); $world->registerGeneratorToWorker($this->worker->getAsyncWorkerId());
} }
$chunk = FastChunkSerializer::deserialize($this->chunk, $this->chunkX, $this->chunkZ); $chunk = FastChunkSerializer::deserialize($this->chunk);
for($i = 0; $i < 9; ++$i){ for($i = 0; $i < 9; ++$i){
if($i === 4){ if($i === 4){
@ -153,7 +153,7 @@ class PopulationTask extends AsyncTask{
$xx = -1 + $i % 3; $xx = -1 + $i % 3;
$zz = -1 + intdiv($i, 3); $zz = -1 + intdiv($i, 3);
$c = FastChunkSerializer::deserialize($c, $this->chunkX + $xx, $this->chunkZ + $zz); $c = FastChunkSerializer::deserialize($c);
$world->generateChunkCallback($this->chunkX + $xx, $this->chunkZ + $zz, $this->state ? $c : null); $world->generateChunkCallback($this->chunkX + $xx, $this->chunkZ + $zz, $this->state ? $c : null);
} }
} }

View File

@ -52,15 +52,15 @@ class LightPopulationTask extends AsyncTask{
/** @var string */ /** @var string */
private $resultBlockLightArrays; private $resultBlockLightArrays;
public function __construct(World $world, Chunk $chunk){ public function __construct(World $world, int $chunkX, int $chunkZ, Chunk $chunk){
$this->storeLocal(self::TLS_KEY_WORLD, $world); $this->storeLocal(self::TLS_KEY_WORLD, $world);
[$this->chunkX, $this->chunkZ] = [$chunk->getX(), $chunk->getZ()]; [$this->chunkX, $this->chunkZ] = [$chunkX, $chunkZ];
$chunk->setLightPopulated(null); $chunk->setLightPopulated(null);
$this->chunk = FastChunkSerializer::serialize($chunk); $this->chunk = FastChunkSerializer::serialize($chunk);
} }
public function onRun() : void{ public function onRun() : void{
$chunk = FastChunkSerializer::deserialize($this->chunk, $this->chunkX, $this->chunkZ); $chunk = FastChunkSerializer::deserialize($this->chunk);
$manager = new SimpleChunkManager(); $manager = new SimpleChunkManager();
$manager->setChunk($this->chunkX, $this->chunkZ, $chunk); $manager->setChunk($this->chunkX, $this->chunkZ, $chunk);

View File

@ -526,7 +526,7 @@ parameters:
path: ../../../src/world/Explosion.php path: ../../../src/world/Explosion.php
- -
message: "#^Parameter \\#1 \\$chunk of method pocketmine\\\\player\\\\Player\\:\\:onChunkChanged\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#" message: "#^Parameter \\#3 \\$chunk of method pocketmine\\\\player\\\\Player\\:\\:onChunkChanged\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#"
count: 1 count: 1
path: ../../../src/world/World.php path: ../../../src/world/World.php
@ -595,16 +595,6 @@ parameters:
count: 2 count: 2
path: ../../../src/world/generator/PopulationTask.php path: ../../../src/world/generator/PopulationTask.php
-
message: "#^Cannot call method getX\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#"
count: 5
path: ../../../src/world/generator/PopulationTask.php
-
message: "#^Cannot call method getZ\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#"
count: 5
path: ../../../src/world/generator/PopulationTask.php
- -
message: "#^Cannot call method isGenerated\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" message: "#^Cannot call method isGenerated\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#"
count: 1 count: 1

View File

@ -28,7 +28,7 @@ use PHPUnit\Framework\TestCase;
class ChunkTest extends TestCase{ class ChunkTest extends TestCase{
public function testClone() : void{ public function testClone() : void{
$chunk = new Chunk(0, 0); $chunk = new Chunk();
$chunk->setFullBlock(0, 0, 0, 1); $chunk->setFullBlock(0, 0, 0, 1);
$chunk->setBiomeId(0, 0, 1); $chunk->setBiomeId(0, 0, 1);
$chunk->setHeightMap(0, 0, 1); $chunk->setHeightMap(0, 0, 1);