Removed entanglement between chunks and providers. WARNING: BREAKING API CHANGES.

- All entity and tile constructors now require a \pocketmine\level\Level instead of a \pocketmine\level\format\Chunk.
- Chunk->getProvider() and Chunk->setProvider() have been removed.
- Chunk::__construct() has had the $provider parameter removed.
- Chunk->unload() has had the unused $save parameter removed.
- ChunkEvents now take a Level parameter instead of going through the Chunk

API bump to 3.0.0-ALPHA4
This commit is contained in:
Dylan K. Taylor
2017-02-21 17:03:45 +00:00
parent 0a8826b21f
commit c21197ef17
37 changed files with 123 additions and 170 deletions

View File

@ -173,7 +173,7 @@ class Explosion{
foreach($this->affectedBlocks as $block){
if($block->getId() === Block::TNT){
$mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = Entity::createEntity("PrimedTNT", $this->level->getChunk($block->x >> 4, $block->z >> 4), new CompoundTag("", [
$tnt = Entity::createEntity("PrimedTNT", $this->level, new CompoundTag("", [
"Pos" => new ListTag("Pos", [
new DoubleTag("", $block->x + 0.5),
new DoubleTag("", $block->y),

View File

@ -1452,7 +1452,7 @@ class Level implements ChunkManager, Metadatable{
$itemTag->setName("Item");
if($item->getId() > 0 and $item->getCount() > 0){
$itemEntity = Entity::createEntity("Item", $this->getChunk($source->getX() >> 4, $source->getZ() >> 4, true), new CompoundTag("", [
$itemEntity = Entity::createEntity("Item", $this, new CompoundTag("", [
"Pos" => new ListTag("Pos", [
new DoubleTag("", $source->getX()),
new DoubleTag("", $source->getY()),
@ -2126,11 +2126,10 @@ class Level implements ChunkManager, Metadatable{
}
}
unset($this->chunkPopulationQueue[$index]);
$chunk->setProvider($this->provider);
$this->setChunk($x, $z, $chunk, false);
$chunk = $this->getChunk($x, $z, false);
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated() and $chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated()){
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($this, $chunk));
foreach($this->getChunkLoaders($x, $z) as $loader){
$loader->onChunkPopulated($chunk);
@ -2139,10 +2138,8 @@ class Level implements ChunkManager, Metadatable{
}elseif(isset($this->chunkGenerationQueue[$index]) or isset($this->chunkPopulationLock[$index])){
unset($this->chunkGenerationQueue[$index]);
unset($this->chunkPopulationLock[$index]);
$chunk->setProvider($this->provider);
$this->setChunk($x, $z, $chunk, false);
}else{
$chunk->setProvider($this->provider);
$this->setChunk($x, $z, $chunk, false);
}
Timings::$generationCallbackTimer->stopTiming();
@ -2435,15 +2432,9 @@ class Level implements ChunkManager, Metadatable{
}
$this->chunks[$index] = $chunk;
$chunk->initChunk();
$chunk->initChunk($this);
if($chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent(new ChunkLoadEvent($chunk, !$chunk->isGenerated()));
}else{
$this->unloadChunk($x, $z, false);
$this->timings->syncChunkLoadTimer->stopTiming();
return false;
}
$this->server->getPluginManager()->callEvent(new ChunkLoadEvent($this, $chunk, !$chunk->isGenerated()));
if(!$chunk->isLightPopulated() and $chunk->isPopulated() and $this->getServer()->getProperty("chunk-ticking.light-updates", false)){
$this->getServer()->getScheduler()->scheduleAsyncTask(new LightPopulationTask($this, $chunk));
@ -2494,10 +2485,10 @@ class Level implements ChunkManager, Metadatable{
$index = Level::chunkHash($x, $z);
$chunk = $this->getChunk($x, $z);
$chunk = $this->chunks[$index] ?? null;
if($chunk !== null and $chunk->getProvider() !== null){
$this->server->getPluginManager()->callEvent($ev = new ChunkUnloadEvent($chunk));
if($chunk !== null){
$this->server->getPluginManager()->callEvent($ev = new ChunkUnloadEvent($this, $chunk));
if($ev->isCancelled()){
$this->timings->doChunkUnload->stopTiming();
return false;

View File

@ -29,7 +29,7 @@ namespace pocketmine\level\format;
use pocketmine\block\Block;
use pocketmine\entity\Entity;
use pocketmine\level\format\io\ChunkException;
use pocketmine\level\format\io\LevelProvider;
use pocketmine\level\Level;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\Player;
@ -41,9 +41,6 @@ class Chunk{
const MAX_SUBCHUNKS = 16;
/** @var LevelProvider */
protected $provider;
protected $x;
protected $z;
@ -85,7 +82,6 @@ class Chunk{
protected $NBTentities = [];
/**
* @param LevelProvider $provider
* @param int $chunkX
* @param int $chunkZ
* @param SubChunk[] $subChunks
@ -94,12 +90,11 @@ class Chunk{
* @param string $biomeIds
* @param int[] $heightMap
*/
public function __construct($provider, int $chunkX, int $chunkZ, array $subChunks = [], array $entities = [], array $tiles = [], string $biomeIds = "", array $heightMap = []){
$this->provider = $provider;
public function __construct(int $chunkX, int $chunkZ, array $subChunks = [], array $entities = [], array $tiles = [], string $biomeIds = "", array $heightMap = []){
$this->x = $chunkX;
$this->z = $chunkZ;
$this->height = $provider !== null ? ($provider->getWorldHeight() >> 4) : 16;
$this->height = Chunk::MAX_SUBCHUNKS; //TODO: add a way of changing this
$this->emptySubChunk = new EmptySubChunk();
@ -164,20 +159,6 @@ class Chunk{
$this->z = $z;
}
/**
* @return LevelProvider|null
*/
public function getProvider(){
return $this->provider;
}
/**
* @param LevelProvider $provider
*/
public function setProvider(LevelProvider $provider){
$this->provider = $provider;
}
/**
* Returns the chunk height in count of subchunks.
*
@ -661,20 +642,12 @@ class Chunk{
/**
* Unloads the chunk, closing entities and tiles.
*
* @param bool $save
* @param bool $safe Whether to check if there are still players using this chunk
*
* @return bool
*/
public function unload(bool $save = true, bool $safe = true) : bool{
$level = $this->getProvider();
if($level === null){
return true;
}
if($save === true and $this->hasChanged){
$level->saveChunk($this->getX(), $this->getZ());
}
if($safe === true){
public function unload(bool $safe = true) : bool{
if($safe){
foreach($this->getEntities() as $entity){
if($entity instanceof Player){
return false;
@ -688,22 +661,24 @@ class Chunk{
}
$entity->close();
}
foreach($this->getTiles() as $tile){
$tile->close();
}
$this->provider = null;
return true;
}
/**
* Deserializes tiles and entities from NBT
* TODO: remove this
*
* @param Level $level
*/
public function initChunk(){
if($this->getProvider() instanceof LevelProvider and !$this->isInit){
public function initChunk(Level $level){
if(!$this->isInit){
$changed = false;
if($this->NBTentities !== null){
$this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
$level->timings->syncChunkLoadEntitiesTimer->startTiming();
foreach($this->NBTentities as $nbt){
if($nbt instanceof CompoundTag){
if(!isset($nbt->id)){
@ -716,7 +691,7 @@ class Chunk{
continue; //Fixes entities allocated in wrong chunks.
}
if(($entity = Entity::createEntity($nbt["id"], $this, $nbt)) instanceof Entity){
if(($entity = Entity::createEntity($nbt["id"], $level, $nbt)) instanceof Entity){
$entity->spawnToAll();
}else{
$changed = true;
@ -724,9 +699,9 @@ class Chunk{
}
}
}
$this->getProvider()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
$level->timings->syncChunkLoadEntitiesTimer->stopTiming();
$this->getProvider()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
$level->timings->syncChunkLoadTileEntitiesTimer->startTiming();
foreach($this->NBTtiles as $nbt){
if($nbt instanceof CompoundTag){
if(!isset($nbt->id)){
@ -739,14 +714,14 @@ class Chunk{
continue; //Fixes tiles allocated in wrong chunks.
}
if(Tile::createTile($nbt["id"], $this, $nbt) === null){
if(Tile::createTile($nbt["id"], $level, $nbt) === null){
$changed = true;
continue;
}
}
}
$this->getProvider()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
$level->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
$this->NBTentities = null;
$this->NBTtiles = null;
@ -954,12 +929,11 @@ class Chunk{
/**
* Deserializes a fast-serialized chunk
*
* @param string $data
* @param LevelProvider|null $provider
* @param string $data
*
* @return Chunk
*/
public static function fastDeserialize(string $data, LevelProvider $provider = null){
public static function fastDeserialize(string $data){
$stream = new BinaryStream();
$stream->setBuffer($data);
$data = null;
@ -973,7 +947,7 @@ class Chunk{
$heightMap = array_values(unpack("C*", $stream->get(256)));
$biomeIds = $stream->get(256);
$chunk = new Chunk($provider, $x, $z, $subChunks, [], [], $biomeIds, $heightMap);
$chunk = new Chunk($x, $z, $subChunks, [], [], $biomeIds, $heightMap);
$flags = $stream->getByte();
$chunk->lightPopulated = (bool) ($flags & 4);
$chunk->terrainPopulated = (bool) ($flags & 2);
@ -982,8 +956,8 @@ class Chunk{
}
//TODO: get rid of this
public static function getEmptyChunk(int $x, int $z, LevelProvider $provider = null) : Chunk{
return new Chunk($provider, $x, $z);
public static function getEmptyChunk(int $x, int $z) : Chunk{
return new Chunk($x, $z);
}
/**

View File

@ -258,7 +258,7 @@ class LevelDB extends BaseLevelProvider{
$this->level->timings->syncChunkLoadDataTimer->startTiming();
$chunk = $this->readChunk($chunkX, $chunkZ);
if($chunk === null and $create){
$chunk = Chunk::getEmptyChunk($chunkX, $chunkZ, $this);
$chunk = Chunk::getEmptyChunk($chunkX, $chunkZ);
}
$this->level->timings->syncChunkLoadDataTimer->stopTiming();
@ -392,7 +392,6 @@ class LevelDB extends BaseLevelProvider{
}*/ //TODO
$chunk = new Chunk(
$this,
$chunkX,
$chunkZ,
$subChunks,
@ -469,7 +468,7 @@ class LevelDB extends BaseLevelProvider{
public function unloadChunk(int $x, int $z, bool $safe = true) : bool{
$chunk = $this->chunks[$index = Level::chunkHash($x, $z)] ?? null;
if($chunk instanceof Chunk and $chunk->unload(false, $safe)){
if($chunk instanceof Chunk and $chunk->unload($safe)){
unset($this->chunks[$index]);
return true;
@ -514,8 +513,6 @@ class LevelDB extends BaseLevelProvider{
}
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk){
$chunk->setProvider($this);
$chunk->setX($chunkX);
$chunk->setZ($chunkZ);

View File

@ -134,7 +134,6 @@ class Anvil extends McRegion{
}
$result = new Chunk(
$this,
$chunk["xPos"],
$chunk["zPos"],
$subChunks,

View File

@ -188,7 +188,6 @@ class McRegion extends BaseLevelProvider{
}
$result = new Chunk(
$this,
$chunk["xPos"],
$chunk["zPos"],
$subChunks,
@ -294,9 +293,6 @@ class McRegion extends BaseLevelProvider{
}
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk){
$chunk->setProvider($this);
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($regionX, $regionZ);
@ -354,7 +350,7 @@ class McRegion extends BaseLevelProvider{
public function unloadChunk(int $chunkX, int $chunkZ, bool $safe = true) : bool{
$chunk = $this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] ?? null;
if($chunk instanceof Chunk and $chunk->unload(false, $safe)){
if($chunk instanceof Chunk and $chunk->unload($safe)){
unset($this->chunks[$index]);
return true;
}
@ -422,7 +418,7 @@ class McRegion extends BaseLevelProvider{
* @return Chunk
*/
public function getEmptyChunk(int $chunkX, int $chunkZ){
return Chunk::getEmptyChunk($chunkX, $chunkZ, $this);
return Chunk::getEmptyChunk($chunkX, $chunkZ);
}
/**

View File

@ -129,7 +129,6 @@ class PMAnvil extends Anvil{
}
$result = new Chunk(
$this,
$chunk["xPos"],
$chunk["zPos"],
$subChunks,

View File

@ -75,7 +75,7 @@ class GenerationTask extends AsyncTask{
return;
}
/** @var Chunk $chunk */
$chunk = Chunk::fastDeserialize($this->chunk, $level->getProvider());
$chunk = Chunk::fastDeserialize($this->chunk);
if($chunk === null){
//TODO error
return;

View File

@ -55,7 +55,7 @@ class LightPopulationTask extends AsyncTask{
$level = $server->getLevel($this->levelId);
if($level !== null){
/** @var Chunk $chunk */
$chunk = Chunk::fastDeserialize($this->chunk, $level->getProvider());
$chunk = Chunk::fastDeserialize($this->chunk);
if($chunk === null){
//TODO error
return;

View File

@ -152,7 +152,7 @@ class PopulationTask extends AsyncTask{
return;
}
$chunk = Chunk::fastDeserialize($this->chunk, $level->getProvider());
$chunk = Chunk::fastDeserialize($this->chunk);
if($chunk === null){
//TODO error
@ -165,7 +165,7 @@ class PopulationTask extends AsyncTask{
}
$c = $this->{"chunk$i"};
if($c !== null){
$c = Chunk::fastDeserialize($c, $level->getProvider());
$c = Chunk::fastDeserialize($c);
$level->generateChunkCallback($c->getX(), $c->getZ(), $c);
}
}