LevelProvider: Remove cyclic dependency between Level and LevelProvider

This will now allow LevelProviders to be constructed on threads.
This commit is contained in:
Dylan K. Taylor 2017-12-31 17:06:18 +00:00
parent d19683b7dd
commit 1a615591e2
5 changed files with 17 additions and 29 deletions

View File

@ -343,7 +343,7 @@ class Level implements ChunkManager, Metadatable{
/** @var LevelProvider $provider */ /** @var LevelProvider $provider */
if(is_subclass_of($provider, LevelProvider::class, true)){ if(is_subclass_of($provider, LevelProvider::class, true)){
$this->provider = new $provider($this, $path); $this->provider = new $provider($path);
}else{ }else{
throw new LevelException("Provider is not a subclass of LevelProvider"); throw new LevelException("Provider is not a subclass of LevelProvider");
} }
@ -2546,7 +2546,7 @@ class Level implements ChunkManager, Metadatable{
} }
$this->timings->syncChunkSendPrepareTimer->startTiming(); $this->timings->syncChunkSendPrepareTimer->startTiming();
$chunk = $this->provider->getChunk($x, $z, false); $chunk = $this->provider->getChunk($x, $z);
if(!($chunk instanceof Chunk)){ if(!($chunk instanceof Chunk)){
throw new ChunkException("Invalid Chunk sent"); throw new ChunkException("Invalid Chunk sent");
} }
@ -2686,7 +2686,13 @@ class Level implements ChunkManager, Metadatable{
$this->cancelUnloadChunkRequest($x, $z); $this->cancelUnloadChunkRequest($x, $z);
$chunk = $this->provider->getChunk($x, $z, $generate); $this->timings->syncChunkLoadDataTimer->startTiming();
$this->provider->loadChunk($x, $z, $generate);
$chunk = $this->provider->getChunk($x, $z);
$this->timings->syncChunkLoadDataTimer->stopTiming();
if($chunk === null){ if($chunk === null){
if($generate){ if($generate){
throw new \InvalidStateException("Could not create new Chunk"); throw new \InvalidStateException("Could not create new Chunk");

View File

@ -33,8 +33,6 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
abstract class BaseLevelProvider implements LevelProvider{ abstract class BaseLevelProvider implements LevelProvider{
/** @var Level */
protected $level;
/** @var string */ /** @var string */
protected $path; protected $path;
/** @var CompoundTag */ /** @var CompoundTag */
@ -42,8 +40,7 @@ abstract class BaseLevelProvider implements LevelProvider{
/** @var Chunk[] */ /** @var Chunk[] */
protected $chunks = []; protected $chunks = [];
public function __construct(Level $level, string $path){ public function __construct(string $path){
$this->level = $level;
$this->path = $path; $this->path = $path;
if(!file_exists($this->path)){ if(!file_exists($this->path)){
mkdir($this->path, 0777, true); mkdir($this->path, 0777, true);
@ -120,15 +117,8 @@ abstract class BaseLevelProvider implements LevelProvider{
file_put_contents($this->getPath() . "level.dat", $buffer); file_put_contents($this->getPath() . "level.dat", $buffer);
} }
public function getChunk(int $chunkX, int $chunkZ, bool $create = false){ public function getChunk(int $chunkX, int $chunkZ){
$index = Level::chunkHash($chunkX, $chunkZ); return $this->chunks[Level::chunkHash($chunkX, $chunkZ)] ?? null;
if(isset($this->chunks[$index])){
return $this->chunks[$index];
}else{
$this->loadChunk($chunkX, $chunkZ, $create);
return $this->chunks[$index] ?? null;
}
} }
public function isChunkLoaded(int $chunkX, int $chunkZ) : bool{ public function isChunkLoaded(int $chunkX, int $chunkZ) : bool{
@ -145,12 +135,10 @@ abstract class BaseLevelProvider implements LevelProvider{
return true; return true;
} }
$this->level->timings->syncChunkLoadDataTimer->startTiming();
$chunk = $this->readChunk($chunkX, $chunkZ); $chunk = $this->readChunk($chunkX, $chunkZ);
if($chunk === null and $create){ if($chunk === null and $create){
$chunk = new Chunk($chunkX, $chunkZ); $chunk = new Chunk($chunkX, $chunkZ);
} }
$this->level->timings->syncChunkLoadDataTimer->stopTiming();
if($chunk !== null){ if($chunk !== null){
$this->chunks[$index] = $chunk; $this->chunks[$index] = $chunk;

View File

@ -24,16 +24,14 @@ declare(strict_types=1);
namespace pocketmine\level\format\io; namespace pocketmine\level\format\io;
use pocketmine\level\format\Chunk; use pocketmine\level\format\Chunk;
use pocketmine\level\Level;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
interface LevelProvider{ interface LevelProvider{
/** /**
* @param Level $level
* @param string $path * @param string $path
*/ */
public function __construct(Level $level, string $path); public function __construct(string $path);
/** /**
* Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format. * Returns the full provider name, like "anvil" or "mcregion", will be used to find the correct format.
@ -91,13 +89,12 @@ interface LevelProvider{
* Gets the Chunk object * Gets the Chunk object
* This method must be implemented by all the level formats. * This method must be implemented by all the level formats.
* *
* @param int $chunkX * @param int $chunkX
* @param int $chunkZ * @param int $chunkZ
* @param bool $create
* *
* @return Chunk|null * @return Chunk|null
*/ */
public function getChunk(int $chunkX, int $chunkZ, bool $create = false); public function getChunk(int $chunkX, int $chunkZ);
/** /**
* @param int $chunkX * @param int $chunkX

View File

@ -87,10 +87,9 @@ class LevelDB extends BaseLevelProvider{
} }
} }
public function __construct(Level $level, string $path){ public function __construct(string $path){
self::checkForLevelDBExtension(); self::checkForLevelDBExtension();
$this->level = $level;
$this->path = $path; $this->path = $path;
if(!file_exists($this->path)){ if(!file_exists($this->path)){
mkdir($this->path, 0777, true); mkdir($this->path, 0777, true);
@ -530,6 +529,5 @@ class LevelDB extends BaseLevelProvider{
public function close(){ public function close(){
$this->unloadChunks(); $this->unloadChunks();
$this->db->close(); $this->db->close();
$this->level = null;
} }
} }

View File

@ -355,7 +355,6 @@ class McRegion extends BaseLevelProvider{
$region->close(); $region->close();
unset($this->regions[$index]); unset($this->regions[$index]);
} }
$this->level = null;
} }
protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{ protected function readChunk(int $chunkX, int $chunkZ) : ?Chunk{