mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-13 09:19:42 +00:00
Moved chunk population to async tasks, and no more cut trees!
This commit is contained in:
parent
72c4c01542
commit
08f2b7f291
@ -68,6 +68,7 @@ use pocketmine\level\format\generic\EmptyChunkSection;
|
|||||||
use pocketmine\level\format\LevelProvider;
|
use pocketmine\level\format\LevelProvider;
|
||||||
use pocketmine\level\generator\GenerationTask;
|
use pocketmine\level\generator\GenerationTask;
|
||||||
use pocketmine\level\generator\Generator;
|
use pocketmine\level\generator\Generator;
|
||||||
|
use pocketmine\level\generator\PopulationTask;
|
||||||
use pocketmine\math\AxisAlignedBB;
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Math;
|
use pocketmine\math\Math;
|
||||||
use pocketmine\math\Vector2;
|
use pocketmine\math\Vector2;
|
||||||
@ -173,8 +174,11 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
private $chunkSendQueue = [];
|
private $chunkSendQueue = [];
|
||||||
private $chunkSendTasks = [];
|
private $chunkSendTasks = [];
|
||||||
|
|
||||||
|
private $chunkPopulationQueue = [];
|
||||||
|
private $chunkPopulationLock = [];
|
||||||
private $chunkGenerationQueue = [];
|
private $chunkGenerationQueue = [];
|
||||||
private $chunkGenerationQueueSize = 16;
|
private $chunkGenerationQueueSize = 8;
|
||||||
|
private $chunkPopulationQueueSize = 2;
|
||||||
|
|
||||||
private $autoSave = true;
|
private $autoSave = true;
|
||||||
|
|
||||||
@ -195,8 +199,6 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
protected $chunkTickRadius;
|
protected $chunkTickRadius;
|
||||||
protected $chunkTickList = [];
|
protected $chunkTickList = [];
|
||||||
protected $chunksPerTick;
|
protected $chunksPerTick;
|
||||||
protected $chunksPopulatedPerTick;
|
|
||||||
protected $chunksPopulated = 0;
|
|
||||||
protected $clearChunksOnTick;
|
protected $clearChunksOnTick;
|
||||||
protected $randomTickBlocks = [
|
protected $randomTickBlocks = [
|
||||||
Block::GRASS => Grass::class,
|
Block::GRASS => Grass::class,
|
||||||
@ -306,9 +308,9 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
$this->time = (int) $this->provider->getTime();
|
$this->time = (int) $this->provider->getTime();
|
||||||
|
|
||||||
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
|
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4)));
|
||||||
$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 260);
|
$this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 40);
|
||||||
$this->chunksPopulatedPerTick = (int) $this->server->getProperty("chunk-generation.populations-per-tick", 1);
|
$this->chunkGenerationQueueSize = (int) $this->server->getProperty("chunk-generation.queue-size", 8);
|
||||||
$this->chunkGenerationQueueSize = (int) $this->server->getProperty("chunk-generation.queue-size", 16);
|
$this->chunkPopulationQueueSize = (int) $this->server->getProperty("chunk-generation.population-queue-size", 2);
|
||||||
$this->chunkTickList = [];
|
$this->chunkTickList = [];
|
||||||
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", false);
|
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", false);
|
||||||
|
|
||||||
@ -599,8 +601,6 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
|
|
||||||
$this->processChunkRequest();
|
$this->processChunkRequest();
|
||||||
|
|
||||||
$this->chunksPopulated = 0;
|
|
||||||
|
|
||||||
$this->timings->doTick->stopTiming();
|
$this->timings->doTick->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1820,15 +1820,25 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
|
|
||||||
public function generateChunkCallback($x, $z, FullChunk $chunk){
|
public function generateChunkCallback($x, $z, FullChunk $chunk){
|
||||||
Timings::$generationTimer->startTiming();
|
Timings::$generationTimer->startTiming();
|
||||||
if(isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
|
if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)])){
|
||||||
$oldChunk = $this->getChunk($x, $z, false);
|
$oldChunk = $this->getChunk($x, $z, false);
|
||||||
unset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)]);
|
for($xx = -1; $xx <= 1; ++$xx){
|
||||||
|
for($zz = -1; $zz <= 1; ++$zz){
|
||||||
|
unset($this->chunkPopulationLock[Level::chunkHash($x + $xx, $z + $zz)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($this->chunkPopulationQueue[$index]);
|
||||||
$chunk->setProvider($this->provider);
|
$chunk->setProvider($this->provider);
|
||||||
$this->setChunk($x, $z, $chunk);
|
$this->setChunk($x, $z, $chunk);
|
||||||
$chunk = $this->getChunk($x, $z, false);
|
$chunk = $this->getChunk($x, $z, false);
|
||||||
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated() and $chunk->getProvider() !== null){
|
if($chunk !== null and ($oldChunk === null or $oldChunk->isPopulated() === false) and $chunk->isPopulated() and $chunk->getProvider() !== null){
|
||||||
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
|
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
|
||||||
}
|
}
|
||||||
|
}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);
|
||||||
}
|
}
|
||||||
Timings::$generationTimer->stopTiming();
|
Timings::$generationTimer->stopTiming();
|
||||||
}
|
}
|
||||||
@ -2285,34 +2295,48 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
|
|
||||||
|
|
||||||
public function populateChunk($x, $z, $force = false){
|
public function populateChunk($x, $z, $force = false){
|
||||||
|
if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)])){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timings::$generationTimer->startTiming();
|
||||||
if(!$this->isChunkPopulated($x, $z)){
|
if(!$this->isChunkPopulated($x, $z)){
|
||||||
$populate = true;
|
$populate = true;
|
||||||
for($xx = -1; $xx <= 1; ++$xx){
|
for($xx = -1; $xx <= 1; ++$xx){
|
||||||
for($zz = -1; $zz <= 1; ++$zz){
|
for($zz = -1; $zz <= 1; ++$zz){
|
||||||
if(!$this->isChunkGenerated($x + $xx, $z + $zz)){
|
if(isset($this->chunkPopulationLock[Level::chunkHash($x + $xx, $z + $zz)])){
|
||||||
|
$populate = false;
|
||||||
|
}elseif(!$this->isChunkGenerated($x + $xx, $z + $zz)){
|
||||||
$populate = false;
|
$populate = false;
|
||||||
$this->generateChunk($x + $xx, $z + $zz, $force);
|
$this->generateChunk($x + $xx, $z + $zz, $force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->chunksPopulated < $this->chunksPopulatedPerTick and $populate){
|
if($populate){
|
||||||
Timings::$generationTimer->startTiming();
|
if(count($this->chunkPopulationQueue) >= $this->chunkPopulationQueueSize and !$force){
|
||||||
$this->generatorInstance->populateChunk($x, $z);
|
|
||||||
$chunk = $this->getChunk($x, $z);
|
|
||||||
$chunk->setPopulated(true);
|
|
||||||
if($chunk->getProvider() !== null){
|
|
||||||
$this->server->getPluginManager()->callEvent(new ChunkPopulateEvent($chunk));
|
|
||||||
}else{
|
|
||||||
$this->unloadChunk($x, $z, false);
|
|
||||||
}
|
|
||||||
++$this->chunksPopulated;
|
|
||||||
Timings::$generationTimer->stopTiming();
|
Timings::$generationTimer->stopTiming();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!isset($this->chunkPopulationQueue[$index])){
|
||||||
|
$this->chunkPopulationQueue[$index] = true;
|
||||||
|
for($xx = -1; $xx <= 1; ++$xx){
|
||||||
|
for($zz = -1; $zz <= 1; ++$zz){
|
||||||
|
$this->chunkPopulationLock[Level::chunkHash($x + $xx, $z + $zz)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$task = new PopulationTask($this, $this->generatorInstance, $this->getChunk($x, $z, true));
|
||||||
|
$this->server->getScheduler()->scheduleAsyncTask($task);
|
||||||
|
}
|
||||||
|
Timings::$generationTimer->stopTiming();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timings::$generationTimer->stopTiming();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Timings::$generationTimer->stopTiming();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2322,9 +2346,11 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
|
if(!isset($this->chunkGenerationQueue[$index = Level::chunkHash($x, $z)])){
|
||||||
|
Timings::$generationTimer->startTiming();
|
||||||
$this->chunkGenerationQueue[$index] = true;
|
$this->chunkGenerationQueue[$index] = true;
|
||||||
$task = new GenerationTask($this, $this->generatorInstance, $this->getChunk($x, $z, true));
|
$task = new GenerationTask($this, $this->generatorInstance, $this->getChunk($x, $z, true));
|
||||||
$this->server->getScheduler()->scheduleAsyncTask($task);
|
$this->server->getScheduler()->scheduleAsyncTask($task);
|
||||||
|
Timings::$generationTimer->stopTiming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +310,8 @@ interface FullChunk{
|
|||||||
|
|
||||||
public function toBinary();
|
public function toBinary();
|
||||||
|
|
||||||
|
public function toFastBinary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
@ -328,4 +330,12 @@ interface FullChunk{
|
|||||||
*/
|
*/
|
||||||
public static function fromBinary($data, LevelProvider $provider = null);
|
public static function fromBinary($data, LevelProvider $provider = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
* @param LevelProvider $provider
|
||||||
|
*
|
||||||
|
* @return FullChunk
|
||||||
|
*/
|
||||||
|
public static function fromFastBinary($data, LevelProvider $provider = null);
|
||||||
|
|
||||||
}
|
}
|
@ -357,4 +357,12 @@ abstract class BaseFullChunk implements FullChunk{
|
|||||||
$this->hasChanged = (bool) $changed;
|
$this->hasChanged = (bool) $changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromFastBinary($data, LevelProvider $provider = null){
|
||||||
|
self::fromBinary($data, $provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toFastBinary(){
|
||||||
|
return $this->toBinary();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -221,6 +221,10 @@ class Chunk extends BaseFullChunk{
|
|||||||
$this->isGenerated = (bool) $value;
|
$this->isGenerated = (bool) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromFastBinary($data, LevelProvider $provider = null){
|
||||||
|
return self::fromBinary($data, $provider);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $data
|
* @param string $data
|
||||||
* @param LevelProvider $provider
|
* @param LevelProvider $provider
|
||||||
@ -272,6 +276,10 @@ class Chunk extends BaseFullChunk{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toFastBinary(){
|
||||||
|
return $this->toBinary(false);
|
||||||
|
}
|
||||||
|
|
||||||
public function toBinary($saveExtra = false){
|
public function toBinary($saveExtra = false){
|
||||||
$chunkIndex = LevelDB::chunkIndex($this->getX(), $this->getZ());
|
$chunkIndex = LevelDB::chunkIndex($this->getX(), $this->getZ());
|
||||||
|
|
||||||
|
@ -38,7 +38,12 @@ class Chunk extends BaseFullChunk{
|
|||||||
/** @var Compound */
|
/** @var Compound */
|
||||||
protected $nbt;
|
protected $nbt;
|
||||||
|
|
||||||
public function __construct($level, Compound $nbt){
|
public function __construct($level, Compound $nbt = null){
|
||||||
|
if($nbt === null){
|
||||||
|
$this->nbt = new Compound("Level", []);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->nbt = $nbt;
|
$this->nbt = $nbt;
|
||||||
|
|
||||||
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){
|
||||||
@ -89,6 +94,9 @@ class Chunk extends BaseFullChunk{
|
|||||||
unset($this->nbt->Data);
|
unset($this->nbt->Data);
|
||||||
unset($this->nbt->SkyLight);
|
unset($this->nbt->SkyLight);
|
||||||
unset($this->nbt->BlockLight);
|
unset($this->nbt->BlockLight);
|
||||||
|
unset($this->nbt->BiomeColors);
|
||||||
|
unset($this->nbt->HeightMap);
|
||||||
|
unset($this->nbt->Biomes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBlockId($x, $y, $z){
|
public function getBlockId($x, $y, $z){
|
||||||
@ -231,28 +239,35 @@ class Chunk extends BaseFullChunk{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isPopulated(){
|
public function isPopulated(){
|
||||||
return $this->nbt["TerrainPopulated"] > 0;
|
return isset($this->nbt->TerrainPopulated) and $this->nbt->TerrainPopulated->getValue() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $value
|
* @param int $value
|
||||||
*/
|
*/
|
||||||
public function setPopulated($value = 1){
|
public function setPopulated($value = 1){
|
||||||
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", $value);
|
$this->nbt->TerrainPopulated = new Byte("TerrainPopulated", (int) $value);
|
||||||
|
$this->hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isGenerated(){
|
public function isGenerated(){
|
||||||
return $this->nbt["TerrainPopulated"] > 0 or (isset($this->nbt->TerrainGenerated) and $this->nbt["TerrainGenerated"] > 0);
|
if(isset($this->nbt->TerrainGenerated)){
|
||||||
|
return $this->nbt->TerrainGenerated->getValue() > 0;
|
||||||
|
}elseif(isset($this->nbt->TerrainPopulated)){
|
||||||
|
return $this->nbt->TerrainPopulated->getValue() > 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $value
|
* @param int $value
|
||||||
*/
|
*/
|
||||||
public function setGenerated($value = 1){
|
public function setGenerated($value = 1){
|
||||||
$this->nbt->TerrainGenerated = new Byte("TerrainGenerated", $value);
|
$this->nbt->TerrainGenerated = new Byte("TerrainGenerated", (int) $value);
|
||||||
|
$this->hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,6 +293,70 @@ class Chunk extends BaseFullChunk{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromFastBinary($data, LevelProvider $provider = null){
|
||||||
|
|
||||||
|
try{
|
||||||
|
$offset = 0;
|
||||||
|
|
||||||
|
$chunk = new Chunk($provider instanceof LevelProvider ? $provider : McRegion::class, null);
|
||||||
|
$chunk->provider = $provider;
|
||||||
|
$chunk->x = Binary::readInt(substr($data, $offset, 4));
|
||||||
|
$offset += 4;
|
||||||
|
$chunk->z = Binary::readInt(substr($data, $offset, 4));
|
||||||
|
$offset += 4;
|
||||||
|
|
||||||
|
$chunk->blocks = substr($data, $offset, 32768);
|
||||||
|
$offset += 32768;
|
||||||
|
$chunk->data = substr($data, $offset, 16384);
|
||||||
|
$offset += 16384;
|
||||||
|
$chunk->skyLight = substr($data, $offset, 16384);
|
||||||
|
$offset += 16384;
|
||||||
|
$chunk->blockLight = substr($data, $offset, 16384);
|
||||||
|
$offset += 16384;
|
||||||
|
|
||||||
|
$chunk->biomeIds = substr($data, $offset, 256);
|
||||||
|
$offset += 256;
|
||||||
|
|
||||||
|
$chunk->biomeColors = [];
|
||||||
|
$chunk->heightMap = [];
|
||||||
|
$bc = unpack("N*", substr($data, $offset, 1024));
|
||||||
|
$offset += 1024;
|
||||||
|
$hm = unpack("N*", substr($data, $offset, 1024));
|
||||||
|
$offset += 1024;
|
||||||
|
|
||||||
|
for($i = 0; $i < 256; ++$i){
|
||||||
|
$chunk->biomeColors[$i] = $bc[$i + 1];
|
||||||
|
$chunk->heightMap[$i] = $hm[$i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$flags = ord($data{$offset++});
|
||||||
|
|
||||||
|
$chunk->nbt->TerrainGenerated = new Byte("TerrainGenerated", $flags & 0b1);
|
||||||
|
$chunk->nbt->TerrainPopulated = new Byte("TerrainPopulated", $flags >> 1);
|
||||||
|
|
||||||
|
return $chunk;
|
||||||
|
}catch(\Exception $e){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toFastBinary(){
|
||||||
|
$biomeColors = pack("N*", ...$this->getBiomeColorArray());
|
||||||
|
$heightMap = pack("N*", ...$this->getHeightMapArray());
|
||||||
|
|
||||||
|
return
|
||||||
|
Binary::writeInt($this->x) .
|
||||||
|
Binary::writeInt($this->z) .
|
||||||
|
$this->getBlockIdArray() .
|
||||||
|
$this->getBlockDataArray() .
|
||||||
|
$this->getBlockSkyLightArray() .
|
||||||
|
$this->getBlockLightArray() .
|
||||||
|
$this->getBiomeIdArray() .
|
||||||
|
$biomeColors .
|
||||||
|
$heightMap .
|
||||||
|
chr(($this->isPopulated() ? 1 << 1 : 0) + ($this->isGenerated() ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
public function toBinary(){
|
public function toBinary(){
|
||||||
$nbt = clone $this->getNBT();
|
$nbt = clone $this->getNBT();
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class GenerationTask extends AsyncTask{
|
|||||||
$this->settings = $generator->getSettings();
|
$this->settings = $generator->getSettings();
|
||||||
$this->seed = $level->getSeed();
|
$this->seed = $level->getSeed();
|
||||||
$this->levelId = $level->getId();
|
$this->levelId = $level->getId();
|
||||||
$this->chunk = $chunk->toBinary();
|
$this->chunk = $chunk->toFastBinary();
|
||||||
$this->chunkClass = get_class($chunk);
|
$this->chunkClass = get_class($chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class GenerationTask extends AsyncTask{
|
|||||||
|
|
||||||
/** @var FullChunk $chunk */
|
/** @var FullChunk $chunk */
|
||||||
$chunk = $this->chunkClass;
|
$chunk = $this->chunkClass;
|
||||||
$chunk = $chunk::fromBinary($this->chunk);
|
$chunk = $chunk::fromFastBinary($this->chunk);
|
||||||
if($chunk === null){
|
if($chunk === null){
|
||||||
//TODO error
|
//TODO error
|
||||||
return;
|
return;
|
||||||
@ -79,7 +79,7 @@ class GenerationTask extends AsyncTask{
|
|||||||
|
|
||||||
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
|
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
|
||||||
$chunk->setGenerated(true);
|
$chunk->setGenerated(true);
|
||||||
$this->chunk = $chunk->toBinary();
|
$this->chunk = $chunk->toFastBinary();
|
||||||
|
|
||||||
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
|
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ class GenerationTask extends AsyncTask{
|
|||||||
if($level !== null){
|
if($level !== null){
|
||||||
/** @var FullChunk $chunk */
|
/** @var FullChunk $chunk */
|
||||||
$chunk = $this->chunkClass;
|
$chunk = $this->chunkClass;
|
||||||
$chunk = $chunk::fromBinary($this->chunk);
|
$chunk = $chunk::fromFastBinary($this->chunk, $level->getProvider());
|
||||||
if($chunk === null){
|
if($chunk === null){
|
||||||
//TODO error
|
//TODO error
|
||||||
return;
|
return;
|
||||||
|
181
src/pocketmine/level/generator/PopulationTask.php
Normal file
181
src/pocketmine/level/generator/PopulationTask.php
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace pocketmine\level\generator;
|
||||||
|
|
||||||
|
use pocketmine\block\Block;
|
||||||
|
use pocketmine\level\format\FullChunk;
|
||||||
|
use pocketmine\level\generator\biome\Biome;
|
||||||
|
use pocketmine\level\Level;
|
||||||
|
use pocketmine\level\SimpleChunkManager;
|
||||||
|
use pocketmine\scheduler\AsyncTask;
|
||||||
|
use pocketmine\Server;
|
||||||
|
use pocketmine\utils\Random;
|
||||||
|
|
||||||
|
class PopulationTask extends AsyncTask{
|
||||||
|
|
||||||
|
public $generator;
|
||||||
|
public $settings;
|
||||||
|
public $seed;
|
||||||
|
public $levelId;
|
||||||
|
public $chunk;
|
||||||
|
public $chunkClass;
|
||||||
|
|
||||||
|
public $chunk00;
|
||||||
|
public $chunk01;
|
||||||
|
public $chunk02;
|
||||||
|
public $chunk10;
|
||||||
|
//center chunk
|
||||||
|
public $chunk12;
|
||||||
|
public $chunk20;
|
||||||
|
public $chunk21;
|
||||||
|
public $chunk22;
|
||||||
|
|
||||||
|
public function __construct(Level $level, Generator $generator, FullChunk $chunk){
|
||||||
|
$this->generator = get_class($generator);
|
||||||
|
$this->settings = $generator->getSettings();
|
||||||
|
$this->seed = $level->getSeed();
|
||||||
|
$this->levelId = $level->getId();
|
||||||
|
$this->chunk = $chunk->toFastBinary();
|
||||||
|
$this->chunkClass = get_class($chunk);
|
||||||
|
|
||||||
|
$this->chunk00 = $level->getChunk($chunk->getX() - 1, $chunk->getZ() - 1, true)->toFastBinary();
|
||||||
|
$this->chunk01 = $level->getChunk($chunk->getX() - 1, $chunk->getZ(), true)->toFastBinary();
|
||||||
|
$this->chunk02 = $level->getChunk($chunk->getX() - 1, $chunk->getZ() + 1, true)->toFastBinary();
|
||||||
|
$this->chunk10 = $level->getChunk($chunk->getX(), $chunk->getZ() - 1, true)->toFastBinary();
|
||||||
|
|
||||||
|
$this->chunk12 = $level->getChunk($chunk->getX(), $chunk->getZ() + 1, true)->toFastBinary();
|
||||||
|
$this->chunk20 = $level->getChunk($chunk->getX() + 1, $chunk->getZ() - 1, true)->toFastBinary();
|
||||||
|
$this->chunk21 = $level->getChunk($chunk->getX() + 1, $chunk->getZ(), true)->toFastBinary();
|
||||||
|
$this->chunk22 = $level->getChunk($chunk->getX() + 1, $chunk->getZ() + 1, true)->toFastBinary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onRun(){
|
||||||
|
/** @var SimpleChunkManager $manager */
|
||||||
|
$manager = $this->getFromThreadStore($key = "generation.level{$this->levelId}.manager");
|
||||||
|
/** @var Generator $generator */
|
||||||
|
$generator = $this->getFromThreadStore($gKey = "generation.level{$this->levelId}.generator");
|
||||||
|
if($manager === null or $generator === null){
|
||||||
|
Block::init();
|
||||||
|
Biome::init();
|
||||||
|
$manager = new SimpleChunkManager($this->seed);
|
||||||
|
$this->saveToThreadStore($key, $manager);
|
||||||
|
/** @var Generator $generator */
|
||||||
|
$generator = $this->generator;
|
||||||
|
$generator = new $generator($this->settings);
|
||||||
|
$generator->init($manager, new Random($manager->getSeed()));
|
||||||
|
$this->saveToThreadStore($gKey, $generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var FullChunk[] $chunks */
|
||||||
|
$chunks = [];
|
||||||
|
/** @var FullChunk $chunkC */
|
||||||
|
$chunkC = $this->chunkClass;
|
||||||
|
|
||||||
|
$chunks[0] = $chunkC::fromFastBinary($this->chunk00);
|
||||||
|
$chunks[1] = $chunkC::fromFastBinary($this->chunk01);
|
||||||
|
$chunks[2] = $chunkC::fromFastBinary($this->chunk02);
|
||||||
|
$chunks[3] = $chunkC::fromFastBinary($this->chunk10);
|
||||||
|
$chunk = $chunkC::fromFastBinary($this->chunk);
|
||||||
|
$chunks[5] = $chunkC::fromFastBinary($this->chunk12);
|
||||||
|
$chunks[6] = $chunkC::fromFastBinary($this->chunk20);
|
||||||
|
$chunks[7] = $chunkC::fromFastBinary($this->chunk21);
|
||||||
|
$chunks[8] = $chunkC::fromFastBinary($this->chunk22);
|
||||||
|
|
||||||
|
if($chunk === null){
|
||||||
|
//TODO error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
|
||||||
|
|
||||||
|
foreach($chunks as $c){
|
||||||
|
if($c !== null){
|
||||||
|
$manager->setChunk($c->getX(), $c->getZ(), $c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$generator->populateChunk($chunk->getX(), $chunk->getZ());
|
||||||
|
|
||||||
|
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
|
||||||
|
$chunk->setPopulated(true);
|
||||||
|
$this->chunk = $chunk->toFastBinary();
|
||||||
|
|
||||||
|
$manager->setChunk($chunk->getX(), $chunk->getZ(), null);
|
||||||
|
|
||||||
|
foreach($chunks as $i => $c){
|
||||||
|
if($c !== null){
|
||||||
|
$c = $chunks[$i] = $manager->getChunk($c->getX(), $c->getZ());
|
||||||
|
if(!$c->hasChanged()){
|
||||||
|
$chunks[$i] = null;
|
||||||
|
}
|
||||||
|
$manager->setChunk($c->getX(), $c->getZ(), null);
|
||||||
|
}else{
|
||||||
|
//This way non-changed chunks are not set
|
||||||
|
$chunks[$i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->chunk00 = $chunks[0] !== null ? $chunks[0]->toFastBinary() : null;
|
||||||
|
$this->chunk01 = $chunks[1] !== null ? $chunks[1]->toFastBinary() : null;
|
||||||
|
$this->chunk02 = $chunks[2] !== null ? $chunks[2]->toFastBinary() : null;
|
||||||
|
$this->chunk10 = $chunks[3] !== null ? $chunks[3]->toFastBinary() : null;
|
||||||
|
|
||||||
|
$this->chunk12 = $chunks[5] !== null ? $chunks[5]->toFastBinary() : null;
|
||||||
|
$this->chunk20 = $chunks[6] !== null ? $chunks[6]->toFastBinary() : null;
|
||||||
|
$this->chunk21 = $chunks[7] !== null ? $chunks[7]->toFastBinary() : null;
|
||||||
|
$this->chunk22 = $chunks[8] !== null ? $chunks[8]->toFastBinary() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onCompletion(Server $server){
|
||||||
|
$level = $server->getLevel($this->levelId);
|
||||||
|
if($level !== null){
|
||||||
|
/** @var FullChunk[] $chunks */
|
||||||
|
$chunks = [];
|
||||||
|
/** @var FullChunk $chunkC */
|
||||||
|
$chunkC = $this->chunkClass;
|
||||||
|
|
||||||
|
$chunks[0] = $chunkC::fromFastBinary($this->chunk00, $level->getProvider());
|
||||||
|
$chunks[1] = $chunkC::fromFastBinary($this->chunk01, $level->getProvider());
|
||||||
|
$chunks[2] = $chunkC::fromFastBinary($this->chunk02, $level->getProvider());
|
||||||
|
$chunks[3] = $chunkC::fromFastBinary($this->chunk10, $level->getProvider());
|
||||||
|
$chunk = $chunkC::fromFastBinary($this->chunk, $level->getProvider());
|
||||||
|
$chunks[5] = $chunkC::fromFastBinary($this->chunk12, $level->getProvider());
|
||||||
|
$chunks[6] = $chunkC::fromFastBinary($this->chunk20, $level->getProvider());
|
||||||
|
$chunks[7] = $chunkC::fromFastBinary($this->chunk21, $level->getProvider());
|
||||||
|
$chunks[8] = $chunkC::fromFastBinary($this->chunk22, $level->getProvider());
|
||||||
|
|
||||||
|
foreach($chunks as $c){
|
||||||
|
if($c !== null){
|
||||||
|
$level->generateChunkCallback($c->getX(), $c->getZ(), $c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if($chunk === null){
|
||||||
|
//TODO error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -158,7 +158,6 @@ class Normal extends Generator{
|
|||||||
$cover = new GroundCover();
|
$cover = new GroundCover();
|
||||||
$this->generationPopulators[] = $cover;
|
$this->generationPopulators[] = $cover;
|
||||||
|
|
||||||
|
|
||||||
$ores = new Ore();
|
$ores = new Ore();
|
||||||
$ores->setOreTypes([
|
$ores->setOreTypes([
|
||||||
new OreType(new CoalOre(), 20, 16, 0, 128),
|
new OreType(new CoalOre(), 20, 16, 0, 128),
|
||||||
@ -168,7 +167,7 @@ class Normal extends Generator{
|
|||||||
new OreType(new GoldOre(), 2, 8, 0, 32),
|
new OreType(new GoldOre(), 2, 8, 0, 32),
|
||||||
new OreType(new DiamondOre(), 1, 7, 0, 16),
|
new OreType(new DiamondOre(), 1, 7, 0, 16),
|
||||||
new OreType(new Dirt(), 20, 32, 0, 128),
|
new OreType(new Dirt(), 20, 32, 0, 128),
|
||||||
new OreType(new Gravel(), 10, 16, 0, 128),
|
new OreType(new Gravel(), 10, 16, 0, 128)
|
||||||
]);
|
]);
|
||||||
$this->populators[] = $ores;
|
$this->populators[] = $ores;
|
||||||
}
|
}
|
||||||
@ -252,7 +251,7 @@ class Normal extends Generator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getSpawn(){
|
public function getSpawn(){
|
||||||
return $this->level->getSafeSpawn(new Vector3(127.5, 128, 127.5));
|
return new Vector3(127.5, 128, 127.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -81,6 +81,7 @@ class Ore{
|
|||||||
|
|
||||||
if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === 1){
|
if(($sizeX + $sizeY + $sizeZ) < 1 and $level->getBlockIdAt($x, $y, $z) === 1){
|
||||||
$level->setBlockIdAt($x, $y, $z, $this->type->material->getId());
|
$level->setBlockIdAt($x, $y, $z, $this->type->material->getId());
|
||||||
|
if($this->type->material->getDamage() !== 0){
|
||||||
$level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage());
|
$level->setBlockDataAt($x, $y, $z, $this->type->material->getDamage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,5 +91,6 @@ class Ore{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -114,6 +114,9 @@ class NBT{
|
|||||||
$this->read(zlib_decode($buffer));
|
$this->read(zlib_decode($buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|bool
|
||||||
|
*/
|
||||||
public function write(){
|
public function write(){
|
||||||
$this->offset = 0;
|
$this->offset = 0;
|
||||||
if($this->data instanceof Compound){
|
if($this->data instanceof Compound){
|
||||||
|
@ -265,7 +265,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
|
|||||||
$pk = $packet->__encapsulatedPacket;
|
$pk = $packet->__encapsulatedPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$needACK and $packet->pid() !== ProtocolInfo::BATCH_PACKET
|
if(!$immediate and !$needACK and $packet->pid() !== ProtocolInfo::BATCH_PACKET
|
||||||
and Network::$BATCH_THRESHOLD >= 0
|
and Network::$BATCH_THRESHOLD >= 0
|
||||||
and strlen($packet->buffer) >= Network::$BATCH_THRESHOLD){
|
and strlen($packet->buffer) >= Network::$BATCH_THRESHOLD){
|
||||||
$this->batchedPackets[$this->identifiers[$player]] .= $packet->buffer;
|
$this->batchedPackets[$this->identifiers[$player]] .= $packet->buffer;
|
||||||
|
@ -51,7 +51,7 @@ chunk-sending:
|
|||||||
|
|
||||||
chunk-ticking:
|
chunk-ticking:
|
||||||
#Max amount of chunks processed each tick
|
#Max amount of chunks processed each tick
|
||||||
per-tick: 24
|
per-tick: 40
|
||||||
#Radius of chunks around a player to tick
|
#Radius of chunks around a player to tick
|
||||||
tick-radius: 3
|
tick-radius: 3
|
||||||
#NOTE: This is currently not implemented
|
#NOTE: This is currently not implemented
|
||||||
@ -59,11 +59,11 @@ chunk-ticking:
|
|||||||
clear-tick-list: false
|
clear-tick-list: false
|
||||||
|
|
||||||
chunk-generation:
|
chunk-generation:
|
||||||
#Max. amount of chunks in the waiting queue ot be generated
|
#Max. amount of chunks in the waiting queue to be generated
|
||||||
#It's recommended to set this to 8 * settings.async-workers
|
#It's recommended to set this to 4 * settings.async-workers
|
||||||
queue-size: 16
|
queue-size: 8
|
||||||
#Max. amount of chunks to populate per tick
|
#Max. amount of chunks in the waiting queue to be populated
|
||||||
populations-per-tick: 1
|
population-queue-size: 2
|
||||||
|
|
||||||
chunk-gc:
|
chunk-gc:
|
||||||
period-in-ticks: 600
|
period-in-ticks: 600
|
||||||
|
@ -31,7 +31,7 @@ use pocketmine\utils\PluginException;
|
|||||||
use pocketmine\utils\ReversePriorityQueue;
|
use pocketmine\utils\ReversePriorityQueue;
|
||||||
|
|
||||||
class ServerScheduler{
|
class ServerScheduler{
|
||||||
public static $WORKERS = 1;
|
public static $WORKERS = 2;
|
||||||
/**
|
/**
|
||||||
* @var ReversePriorityQueue<Task>
|
* @var ReversePriorityQueue<Task>
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user