From 4128b22e85abdcecdcb35f3ff1d349700763b697 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Wed, 30 Jul 2014 16:38:56 +0200 Subject: [PATCH] Reuse McRegion classes on Anvil --- src/pocketmine/level/format/anvil/Anvil.php | 144 +------------ .../level/format/anvil/RegionLoader.php | 193 +----------------- .../level/format/mcregion/RegionLoader.php | 6 +- 3 files changed, 10 insertions(+), 333 deletions(-) diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index 349247bff..b21720122 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -22,6 +22,7 @@ namespace pocketmine\level\format\anvil; use pocketmine\level\format\generic\BaseLevelProvider; +use pocketmine\level\format\mcregion\McRegion; use pocketmine\level\format\SimpleChunk; use pocketmine\level\generator\Generator; use pocketmine\level\Level; @@ -34,7 +35,7 @@ use pocketmine\nbt\tag\Long; use pocketmine\nbt\tag\String; use pocketmine\Player; -class Anvil extends BaseLevelProvider{ +class Anvil extends McRegion{ /** @var RegionLoader[] */ protected $regions = []; @@ -69,68 +70,6 @@ class Anvil extends BaseLevelProvider{ return $isValid; } - public static function generate($path, $name, $seed, $generator, array $options = []){ - @mkdir($path, 0777, true); - @mkdir($path . "/region", 0777); - //TODO, add extra details - $levelData = new Compound("Data", [ - "hardcore" => new Byte("hardcore", 0), - "initialized" => new Byte("initialized", 1), - "GameType" => new Int("GameType", 0), - "generatorVersion" => new Int("generatorVersion", 1), //2 in MCPE - "SpawnX" => new Int("SpawnX", 128), - "SpawnY" => new Int("SpawnY", 70), - "SpawnZ" => new Int("SpawnZ", 128), - "version" => new Int("version", 19133), - "DayTime" => new Int("DayTime", 0), - "LastPlayed" => new Long("LastPlayed", microtime(true) * 1000), - "RandomSeed" => new Long("RandomSeed", $seed), - "SizeOnDisk" => new Long("SizeOnDisk", 0), - "Time" => new Long("Time", 0), - "generatorName" => new String("generatorName", Generator::getGeneratorName($generator)), - "generatorOptions" => new String("generatorOptions", isset($options["preset"]) ? $options["preset"] : ""), - "LevelName" => new String("LevelName", $name), - "GameRules" => new Compound("GameRules", []) - ]); - $nbt = new NBT(NBT::BIG_ENDIAN); - $nbt->setData(new Compound(null, [ - "Data" => $levelData - ])); - $buffer = $nbt->writeCompressed(); - @file_put_contents($path . "level.dat", $buffer); - } - - public static function getRegionIndex($chunkX, $chunkZ, &$x, &$z){ - $x = $chunkX >> 5; - $z = $chunkZ >> 5; - } - - public function unloadChunks(){ - $this->chunks = []; - } - - public function getGenerator(){ - return $this->levelData["generatorName"]; - } - - public function getGeneratorOptions(){ - return ["preset" => $this->levelData["generatorOptions"]]; - } - - public function getLoadedChunks(){ - return $this->chunks; - } - - public function isChunkLoaded($x, $z){ - return isset($this->chunks[Level::chunkHash($x, $z)]); - } - - public function saveChunks(){ - foreach($this->chunks as $chunk){ - $this->saveChunk($chunk->getX(), $chunk->getZ()); - } - } - public function loadChunk($chunkX, $chunkZ, $create = false){ $index = Level::chunkHash($chunkX, $chunkZ); if(isset($this->chunks[$index])){ @@ -151,54 +90,6 @@ class Anvil extends BaseLevelProvider{ } } - public function unloadChunk($x, $z, $safe = true){ - $chunk = $this->getChunk($x, $z, false); - if($chunk instanceof Chunk){ - if($safe === true and $this->isChunkLoaded($x, $z)){ - foreach($chunk->getEntities() as $entity){ - if($entity instanceof Player){ - return false; - } - } - } - - foreach($chunk->getEntities() as $entity){ - $entity->close(); - } - - foreach($chunk->getTiles() as $tile){ - $tile->close(); - } - - $this->chunks[$index = Level::chunkHash($x, $z)] = null; - - unset($this->chunks[$index]); - } - return true; - } - - public function saveChunk($x, $z){ - if($this->isChunkLoaded($x, $z)){ - $this->getRegion($x >> 5, $z >> 5)->writeChunk($this->getChunk($x, $z)); - - return true; - } - - return false; - } - - /** - * @param $x - * @param $z - * - * @return RegionLoader - */ - protected function getRegion($x, $z){ - $index = $x . ":" . $z; - - return isset($this->regions[$index]) ? $this->regions[$index] : null; - } - /** * @param int $chunkX * @param int $chunkZ @@ -207,13 +98,7 @@ class Anvil extends BaseLevelProvider{ * @return Chunk */ public function getChunk($chunkX, $chunkZ, $create = false){ - $index = Level::chunkHash($chunkX, $chunkZ); - if(isset($this->chunks[$index])){ - return $this->chunks[$index]; - }else{ - $this->loadChunk($chunkX, $chunkZ, $create); - return isset($this->chunks[$index]) ? $this->chunks[$index] : null; - } + return parent::getChunk($chunkX, $chunkZ, $create); } public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){ @@ -249,9 +134,9 @@ class Anvil extends BaseLevelProvider{ return new ChunkSection(new Compound(null, [ "Y" => new Byte("Y", $Y), "Blocks" => new ByteArray("Blocks", str_repeat("\xff", 4096)), - "Data" => new ByteArray("Data", str_repeat("\xff", 2048)), - "SkyLight" => new ByteArray("SkyLight", str_repeat("\xff", 2048)), //TODO - "BlockLight" => new ByteArray("BlockLight", str_repeat("\x00", 2048)) //TODO + "Data" => new ByteArray("Data", $half = str_repeat("\xff", 2048)), + "SkyLight" => new ByteArray("SkyLight", $half), + "BlockLight" => new ByteArray("BlockLight", $half) ])); } @@ -263,15 +148,6 @@ class Anvil extends BaseLevelProvider{ return false; } - public function isChunkPopulated($chunkX, $chunkZ){ - $chunk = $this->getChunk($chunkX, $chunkZ); - if($chunk instanceof Chunk){ - return $chunk->isPopulated(); - }else{ - return false; - } - } - protected function loadRegion($x, $z){ $index = $x . ":" . $z; if(isset($this->regions[$index])){ @@ -282,12 +158,4 @@ class Anvil extends BaseLevelProvider{ return true; } - - public function close(){ - $this->unloadChunks(); - foreach($this->regions as $index => $region){ - $region->close(); - unset($this->regions[$index]); - } - } } \ No newline at end of file diff --git a/src/pocketmine/level/format/anvil/RegionLoader.php b/src/pocketmine/level/format/anvil/RegionLoader.php index 0c7885eef..b465e1be0 100644 --- a/src/pocketmine/level/format/anvil/RegionLoader.php +++ b/src/pocketmine/level/format/anvil/RegionLoader.php @@ -33,21 +33,12 @@ use pocketmine\nbt\tag\Long; use pocketmine\Player; use pocketmine\utils\Binary; -class RegionLoader{ +class RegionLoader extends \pocketmine\level\format\mcregion\RegionLoader{ const VERSION = 1; const COMPRESSION_GZIP = 1; const COMPRESSION_ZLIB = 2; public static $COMPRESSION_LEVEL = 7; - protected $x; - protected $z; - protected $filePath; - protected $filePointer; - protected $lastSector; - /** @var LevelProvider */ - protected $levelProvider; - protected $locationTable = []; - public function __construct(LevelProvider $level, $regionX, $regionZ){ $this->x = $regionX; $this->z = $regionZ; @@ -65,19 +56,6 @@ class RegionLoader{ } } - public function __destruct(){ - if(is_resource($this->filePointer)){ - $this->cleanGarbage(); - $this->writeLocationTable(); - flock($this->filePointer, LOCK_UN); - fclose($this->filePointer); - } - } - - protected function isChunkGenerated($index){ - return !($this->locationTable[$index][0] === 0 or $this->locationTable[$index][1] === 0); - } - public function readChunk($x, $z, $generate = true){ $index = self::getChunkOffset($x, $z); if($index < 0 or $index >= 4096){ @@ -131,10 +109,6 @@ class RegionLoader{ return new Chunk($this->levelProvider, $chunk->Level); } - public function chunkExists($x, $z){ - return $this->isChunkGenerated(self::getChunkOffset($x, $z)); - } - public function generateChunk($x, $z){ $nbt = new Compound("Level", []); $nbt->xPos = new Int("xPos", ($this->getX() * 32) + $x); @@ -158,30 +132,6 @@ class RegionLoader{ $this->saveChunk($x, $z, $nbt); } - protected function saveChunk($x, $z, Compound $nbt){ - $writer = new NBT(NBT::BIG_ENDIAN); - $nbt->setName("Level"); - $writer->setData(new Compound("", array("Level" => $nbt))); - $chunkData = $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, self::$COMPRESSION_LEVEL); - $length = strlen($chunkData) + 1; - $sectors = (int) ceil(($length + 4) / 4096); - $index = self::getChunkOffset($x, $z); - if($this->locationTable[$index][1] < $sectors){ - $this->locationTable[$index][0] = $this->lastSector += $sectors; //The GC will clean this shift later - } - $this->locationTable[$index][1] = $sectors; - - fseek($this->filePointer, $this->locationTable[$index][0] << 12); - fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $sectors << 12, "\x00", STR_PAD_RIGHT)); - $this->writeLocationIndex($index); - } - - public function removeChunk($x, $z){ - $index = self::getChunkOffset($x, $z); - $this->locationTable[$index][0] = 0; - $this->locationTable[$index][1] = 0; - } - public function writeChunk(Chunk $chunk){ $nbt = $chunk->getNBT(); $nbt->Sections = new Enum("Sections", []); @@ -226,145 +176,4 @@ class RegionLoader{ $this->saveChunk($chunk->getX() - ($this->getX() * 32), $chunk->getZ() - ($this->getZ() * 32), $nbt); } - protected static function getChunkOffset($x, $z){ - return $x + ($z << 5); - } - - public function close(){ - $this->writeLocationTable(); - flock($this->filePointer, LOCK_UN); - fclose($this->filePointer); - } - - public function doSlowCleanUp(){ - for($i = 0; $i < 1024; ++$i){ - if($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0){ - continue; - } - fseek($this->filePointer, $this->locationTable[$i][0] << 12); - $chunk = fread($this->filePointer, $this->locationTable[$i][1] << 12); - $length = Binary::readInt(substr($chunk, 0, 4)); - if($length <= 1){ - $this->locationTable[$i] = array(0, 0, 0); //Non-generated chunk, remove it from index - } - $chunk = zlib_decode(substr($chunk, 5)); - if(strlen($chunk) <= 1){ - $this->locationTable[$i] = array(0, 0, 0); //Corrupted chunk, remove it - continue; - } - $chunk = chr(self::COMPRESSION_ZLIB) . zlib_encode($chunk, 15, 9); - $chunk = Binary::writeInt(strlen($chunk)) . $chunk; - $sectors = (int) ceil(strlen($chunk) / 4096); - if($sectors > $this->locationTable[$i][1]){ - $this->locationTable[$i][0] = $this->lastSector += $sectors; - } - fseek($this->filePointer, $this->locationTable[$i][0] << 12); - fwrite($this->filePointer, str_pad($chunk, $sectors << 12, "\x00", STR_PAD_RIGHT)); - } - $this->writeLocationTable(); - $n = $this->cleanGarbage(); - $this->writeLocationTable(); - - return $n; - } - - private function cleanGarbage(){ - $sectors = []; - foreach($this->locationTable as $index => $data){ //Calculate file usage - if($data[0] === 0 or $data[1] === 0){ - $this->locationTable[$index] = array(0, 0, 0); - continue; - } - for($i = 0; $i < $data[1]; ++$i){ - $sectors[$data[0]] = $index; - } - } - - if(count($sectors) === ($this->lastSector - 2)){ //No collection needed - return 0; - } - - ksort($sectors); - $shift = 0; - $lastSector = 1; //First chunk - 1 - - fseek($this->filePointer, 8192); - $sector = 2; - foreach($sectors as $sector => $index){ - if(($sector - $lastSector) > 1){ - $shift += $sector - $lastSector - 1; - } - if($shift > 0){ - fseek($this->filePointer, $sector << 12); - $old = fread($this->filePointer, 4096); - fseek($this->filePointer, ($sector - $shift) << 12); - fwrite($this->filePointer, $old, 4096); - } - $this->locationTable[$index][0] -= $shift; - $lastSector = $sector; - } - ftruncate($this->filePointer, ($sector + 1) << 12); //Truncate to the end of file written - return $shift; - } - - private function loadLocationTable(){ - fseek($this->filePointer, 0); - $this->lastSector = 1; - $table = fread($this->filePointer, 4 * 1024 * 2); - for($i = 0; $i < 1024; ++$i){ - $index = Binary::readInt(substr($table, $i << 2, 4)); - $this->locationTable[$i] = array(($index & ~0xff) >> 8, $index & 0xff, Binary::readInt(substr($table, 4096 + ($i << 2), 4))); - if(($this->locationTable[$i][0] + $this->locationTable[$i][1] - 1) > $this->lastSector){ - $this->lastSector = $this->locationTable[$i][0] + $this->locationTable[$i][1] - 1; - } - } - } - - private function writeLocationTable(){ - $table = ""; - - for($i = 0; $i < 1024; ++$i){ - $table .= Binary::writeInt(($this->locationTable[$i][0] << 8) | $this->locationTable[$i][1]); - } - for($i = 0; $i < 1024; ++$i){ - $table .= Binary::writeInt($this->locationTable[$i][2]); - } - fseek($this->filePointer, 0); - fwrite($this->filePointer, $table, 4096 * 2); - } - - private function writeLocationIndex($index){ - fseek($this->filePointer, $index << 2); - fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index][0] << 8) | $this->locationTable[$index][1]), 4); - fseek($this->filePointer, 4096 + ($index << 2)); - fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index][2]), 4); - } - - private function createBlank(){ - fseek($this->filePointer, 0); - ftruncate($this->filePointer, 0); - $this->lastSector = 1; - $table = ""; - for($i = 0; $i < 1024; ++$i){ - $this->locationTable[$i] = array(0, 0); - $table .= Binary::writeInt(0); - } - - $time = time(); - for($i = 0; $i < 1024; ++$i){ - $this->locationTable[$i][2] = $time; - $table .= Binary::writeInt($time); - } - - fwrite($this->filePointer, $table, 4096 * 2); - } - - public function getX(){ - return $this->x; - } - - public function getZ(){ - return $this->z; - } - } \ No newline at end of file diff --git a/src/pocketmine/level/format/mcregion/RegionLoader.php b/src/pocketmine/level/format/mcregion/RegionLoader.php index 9fe5c70c1..4021574ba 100644 --- a/src/pocketmine/level/format/mcregion/RegionLoader.php +++ b/src/pocketmine/level/format/mcregion/RegionLoader.php @@ -305,7 +305,7 @@ class RegionLoader{ return $shift; } - private function loadLocationTable(){ + protected function loadLocationTable(){ fseek($this->filePointer, 0); $this->lastSector = 1; $table = fread($this->filePointer, 4 * 1024 * 2); @@ -331,14 +331,14 @@ class RegionLoader{ fwrite($this->filePointer, $table, 4096 * 2); } - private function writeLocationIndex($index){ + protected function writeLocationIndex($index){ fseek($this->filePointer, $index << 2); fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index][0] << 8) | $this->locationTable[$index][1]), 4); fseek($this->filePointer, 4096 + ($index << 2)); fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index][2]), 4); } - private function createBlank(){ + protected function createBlank(){ fseek($this->filePointer, 0); ftruncate($this->filePointer, 0); $this->lastSector = 1;