diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 035912671..31f2b8225 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -83,6 +83,7 @@ use pocketmine\scheduler\CallbackTask; use pocketmine\tile\Sign; use pocketmine\tile\Spawnable; use pocketmine\tile\Tile; +use pocketmine\utils\ReversePriorityQueue; use pocketmine\utils\TextFormat; /** @@ -199,7 +200,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ } protected function initEntity(){ - $this->getLevel()->players[spl_object_hash($this)] = $this; parent::initEntity(); } @@ -515,7 +515,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ return false; }else{ $index = null; - LevelFormat::getXZ($index, $this->lastChunk[0], $this->lastChunk[1]); + Level::getXZ($index, $this->lastChunk[0], $this->lastChunk[1]); unset($this->chunksLoaded[$index]); } }else{*/ @@ -535,16 +535,17 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $index = key($this->chunksOrder); $distance = @$this->chunksOrder[$index]; + if($index === null or $distance === null){ + $this->orderChunks(); if($this->chunkScheduled === 0){ $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), 60); } - return false; } $X = null; $Z = null; - LevelFormat::getXZ($index, $X, $Z); + Level::getXZ($index, $X, $Z); if(!$this->getLevel()->isChunkPopulated($X, $Z)){ $this->orderChunks(); if($this->chunkScheduled === 0 or $force === true){ @@ -564,8 +565,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $pk = new FullChunkDataPacket; $pk->chunkX = $X; $pk->chunkZ = $Z; - $pk->data = $this->getLevel()->getOrderedChunk($X, $Z, $Yndex); + $pk->data = $this->getLevel()->getNetworkChunk($X, $Z, $Yndex); $cnt = $this->dataPacket($pk, true); + if($cnt === false){ return false; } @@ -622,43 +624,38 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $startZ = $centerZ - $this->viewDistance; $finalX = $centerX + $this->viewDistance; $finalZ = $centerZ + $this->viewDistance; + $generateQueue = new ReversePriorityQueue(); for($X = $startX; $X <= $finalX; ++$X){ for($Z = $startZ; $Z <= $finalZ; ++$Z){ $distance = abs($X - $centerX) + abs($Z - $centerZ); - $index = LevelFormat::getIndex($X, $Z); + $index = Level::chunkHash($X, $Z); if(!isset($this->chunksLoaded[$index]) or $this->chunksLoaded[$index] !== 0){ - $newOrder[$index] = $distance; + if($this->getLevel()->isChunkPopulated($X, $Z)){ + $newOrder[$index] = $distance; + }else{ + $generateQueue->insert([$X, $Z], $distance); + } } unset($lastChunk[$index]); } } + asort($newOrder); $this->chunksOrder = $newOrder; - $index = key($this->chunksOrder); - LevelFormat::getXZ($index, $X, $Z); - $radius = 1; - for($z = $Z - $radius; $z <= ($Z + $radius); ++$z){ - for($x = $X - $radius; $x <= ($X + $radius); ++$x){ - $this->getLevel()->loadChunk($x, $z); - if(!$this->getLevel()->isChunkPopulated($x, $z)){ - $this->getLevel()->loadChunk($x - 1, $z); - $this->getLevel()->loadChunk($x + 1, $z); - $this->getLevel()->loadChunk($x, $z - 1); - $this->getLevel()->loadChunk($x, $z + 1); - $this->getLevel()->loadChunk($x + 1, $z + 1); - $this->getLevel()->loadChunk($x + 1, $z - 1); - $this->getLevel()->loadChunk($x - 1, $z - 1); - $this->getLevel()->loadChunk($x - 1, $z + 1); - } - } + $i = 0; + while($generateQueue->count() > 0 and $i < 8){ + $d = $generateQueue->extract(); + $this->getLevel()->generateChunk($d[0], $d[1]); + ++$i; } + foreach($lastChunk as $index => $Yndex){ if($Yndex === 0){ $X = null; $Z = null; - LevelFormat::getXZ($index, $X, $Z); + Level::getXZ($index, $X, $Z); foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){ if($entity !== $this){ $entity->despawnFrom($this); @@ -1146,7 +1143,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $nbt["lastPlayed"] = floor(microtime(true) * 1000); $this->server->saveOfflinePlayerData($this->username, $nbt); - parent::__construct($this->getLevel(), $nbt); + parent::__construct($this->getLevel()->getChunkAt($nbt["Pos"][0], $nbt["Pos"][2], true), $nbt); $this->inventory->setHeldItemSlot($this->getCreativeBlock(Item::get(Item::STONE, 0, 1))); $this->loggedIn = true; @@ -1971,7 +1968,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ */ public function close($message = "", $reason = "generic reason"){ if($this->connected === true){ - unset($this->getLevel()->players[spl_object_hash($this)]); if($this->username != ""){ $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message)); if($this->loggedIn === true){ diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index d984e9c90..f2269bd3d 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -75,7 +75,7 @@ namespace pocketmine { const VERSION = "Alpha_1.4dev"; const API_VERSION = "1.0.0"; const CODENAME = "絶好(Zekkou)ケーキ(Cake)"; - const MINECRAFT_VERSION = "v0.9.0 alpha build 1"; + const MINECRAFT_VERSION = "v0.9.0 alpha build 2"; const PHP_VERSION = "5.5"; if(\Phar::running(true) !== ""){ diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 3189946fb..eb663445c 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -776,7 +776,7 @@ class Server{ * @param Level $level */ public function setDefaultLevel($level){ - if($level === null or ($this->isLevelLoaded($level->getName()) and $level !== $this->levelDefault)){ + if($level === null or ($this->isLevelLoaded($level->getFolderName()) and $level !== $this->levelDefault)){ $this->levelDefault = $level; } } @@ -810,7 +810,7 @@ class Server{ */ public function getLevelByName($name){ foreach($this->getLevels() as $level){ - if($level->getName() === $name){ + if($level->getFolderName() === $name){ return $level; } } @@ -823,7 +823,7 @@ class Server{ * @param bool $forceUnload */ public function unloadLevel(Level $level, $forceUnload = false){ - if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getName())){ + if($level->unload($forceUnload) === true and $this->isLevelLoaded($level->getFolderName())){ unset($this->levels[$level->getID()]); } } @@ -852,6 +852,7 @@ class Server{ $path = $this->getDataPath() . "worlds/" . $name . "/"; $provider = LevelProviderManager::getProvider($path); + if($provider === null){ $this->logger->error("Could not load level \"" . $name . "\""); @@ -862,7 +863,7 @@ class Server{ // @rename($path . "tileEntities.yml", $path . "tiles.yml"); //} - $level = new Level($this, $path, $provider); + $level = new Level($this, $name, $path, $provider); $this->levels[$level->getID()] = $level; /*foreach($entities->getAll() as $entity){ if(!isset($entity["id"])){ @@ -994,7 +995,7 @@ class Server{ /** @var \pocketmine\level\format\LevelProvider $provider */ $provider::generate($path, $name, $seed, $generator, $options); - $level = new Level($this, $path, $provider); + $level = new Level($this, $name, $path, $provider); $this->levels[$level->getID()] = $level; for($Z = 6; $Z <= 10; ++$Z){ for($X = 6; $X <= 10; ++$X){ @@ -1015,15 +1016,19 @@ class Server{ return false; } $path = $this->getDataPath() . "worlds/" . $name . "/"; - if(!($this->getLevelByName($name) instanceof Level) and !file_exists($path . "level.pmf")){ - if(file_exists($path)){ + if(!($this->getLevelByName($name) instanceof Level)){ + + if(LevelProviderManager::getProvider($path) === null){ + return false; + } + /*if(file_exists($path)){ $level = new LevelImport($path); if($level->import() === false){ //Try importing a world return false; } }else{ return false; - } + }*/ } return true; @@ -1356,9 +1361,9 @@ class Server{ LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil"); - Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat"); - Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal"); - Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default"); + //Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat"); + //Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal"); + //Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default"); if($this->getDefaultLevel() === null){ $default = $this->getConfigString("level-name", "world"); diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index a45e3b4ef..be37cd39d 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -589,7 +589,7 @@ abstract class Entity extends Position implements Metadatable{ if($Yndex !== 0xff){ $X = null; $Z = null; - LevelFormat::getXZ($index, $X, $Z); + Level::getXZ($index, $X, $Z); foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){ $entity->despawnFrom($this); } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 270ed8980..23b7e0c0d 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -60,6 +60,7 @@ use pocketmine\tile\Sign; use pocketmine\tile\Tile; use pocketmine\utils\Cache; use pocketmine\utils\ReversePriorityQueue; +use raklib\Binary; class Level implements ChunkManager, Metadatable{ @@ -109,6 +110,8 @@ class Level implements ChunkManager, Metadatable{ private $startCheck; private $startTime; + private $folderName; + /** @var Block[][] */ protected $changedBlocks = []; protected $changedCount = []; @@ -140,12 +143,13 @@ class Level implements ChunkManager, Metadatable{ * Init the default level data * * @param Server $server + * @param string $name * @param string $path * @param string $provider Class that extends LevelProvider * * @throws \Exception */ - public function __construct(Server $server, $path, $provider){ + public function __construct(Server $server, $name, $path, $provider){ $this->levelId = static::$levelIdCounter++; $this->server = $server; if(is_subclass_of($provider, "pocketmine\\level\\format\\LevelProvider", true)){ @@ -157,6 +161,8 @@ class Level implements ChunkManager, Metadatable{ $generator = Generator::getGenerator($this->provider->getGenerator()); $this->server->getGenerationManager()->openLevel($this, $generator, $this->provider->getGeneratorOptions()); + $this->folderName = $name; + $this->startTime = $this->time = (int) $this->provider->getTime(); $this->nextSave = $this->startCheck = microtime(true); $this->nextSave = microtime(true) + 90; @@ -523,7 +529,7 @@ class Level implements ChunkManager, Metadatable{ public function getBlock(Vector3 $pos){ $blockId = null; $meta = null; - $this->getChunkAt($pos->x >> 4, $pos->z >> 4)->getBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f, $blockId, $meta); + $this->getChunkAt($pos->x >> 4, $pos->z >> 4, true)->getBlock($pos->x & 0x0f, $pos->y & 0x7f, $pos->z & 0x0f, $blockId, $meta); return Block::get($blockId, $meta, Position::fromObject(clone $pos, $this)); } @@ -1059,7 +1065,7 @@ class Level implements ChunkManager, Metadatable{ * @return Chunk */ public function getChunkAt($x, $z, $create = false){ - $this->provider->getChunk($x, $z, $create); + return $this->provider->getChunk($x, $z, $create); } /** @@ -1160,6 +1166,63 @@ class Level implements ChunkManager, Metadatable{ $this->server->getPluginManager()->callEvent(new SpawnChangeEvent($this, $previousSpawn)); } + /** + * Gets a full chunk or parts of it for networking usage, allows cache usage + * + * @param int $X + * @param int $Z + * @param int $Yndex bitmap of chunks to be returned + * + * @return bool|mixed|string + */ + public function getNetworkChunk($X, $Z, $Yndex){ + if(ADVANCED_CACHE == true and $Yndex === 0xff){ + $identifier = "world:".($this->getName()).":" . Level::chunkHash($X, $Z); + if(($cache = Cache::get($identifier)) !== false){ + return $cache; + } + } + + $orderedIds = ""; + $orderedData = ""; + $orderedSkyLight = ""; + $orderedLight = ""; + $flag = chr($Yndex); + + /** @var \pocketmine\level\format\ChunkSection[] $sections */ + $sections = []; + foreach($this->getChunkAt($X, $Z, true)->getSections() as $section){ + $sections[$section->getY()] = $section; + } + + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 16; ++$z){ + for($Y = 0; $Y < 8; ++$Y){ + $orderedIds .= $sections[$Y]->getBlockIdColumn($x, $z); + $orderedData .= $sections[$Y]->getBlockDataColumn($x, $z); + $orderedSkyLight .= $sections[$Y]->getBlockSkyLightColumn($x, $z); + $orderedLight .= $sections[$Y]->getBlockLightColumn($x, $z); + } + } + } + + + $biomeIDs = str_repeat("\x04", 256); + if($X % 5 === 0 and $Z % 5 === 0){ + $ppm = base64_decode("mpqahISEbW1tZmZmZmZmXl5eXl5eXl5eXl5eXl5eXl5eZmZmZmZmbW1thISEmpqafX19bW1tbW1tS5ubS5qdfbXTSpSbS5ubTJ6cSpWZfbXTSpWZTJ6cbW1tbW1tfX19bW1tbW1tfbXSfbbVSI+dfdL/fbrafbfVSZKefbjYfbjYfbXSSpWZfbTRbW1tbW1tZmZmTKGdSpSbfbrbfbzdfdL/SI+dfbnZfdL/fdL/SZKeSpKYSYyWfbbVS5iaZmZmXl5eS6CiSZmmfdL/fbzeSZCcSpSbfbfVSJKifdL/SpegfbXTfbfWfbXTS5ubXl5eXl5efdL/fdL/fdL/fbrbfbbVSpKYfbTRSpecSpieSZCcfbjYSZCcSpegS52iXl5eXl5eSpegfbnZSZSfSZGafbbVxsYAxsYAxsYAxsYAfbjYfdL/SZikfdL/fdL/Xl5eXl5eSpSbfbjYSpegS5qdfbTRxsYA1tYA1tYAxsYASpegfdL/SZahfbfXSpegXl5eXl5efbfWfdL/AAAAAAAAAAAAxsYA1tYAAAAAxsYAS56gSp2lAAAAfbfVS5iaXl5eXl5efbXSSZWjAAAAfbnZfbjYAAAAxsYAAAAAAAAASZOgAAAAAAAAfbfWSpWZXl5eXl5eTJ6cS56gAAAAAAAAAAAASpegS5ubAAAAfdL/AAAAfdL/AAAASZOgfbfVXl5eXl5eTKKfSp2lAAAAfdL/fdL/Sp2lS56gAAAAfdL/SZamSpyjAAAAfdL/fdL/Xl5eZmZmS6CifdL/AAAASZamSZmmfdL/SZqoAAAAfdL/SJOlfdL/AAAAfbnZSpegZmZmbW1tbW1tfdL/AAAAfbXSSpegfdL/fdL/AAAAfbfXfbrbfdL/AAAAfbbVbW1tbW1tfX19bW1tbW1tAAAAfbTRS5qdSp2lfdL/AAAAS5ubSpSbfbfVAAAAbW1tbW1tfX19mpqahISEbW1tZmZmZmZmXl5eXl5eXl5eXl5eXl5eXl5eZmZmZmZmbW1thISEmpqa"); + $grassColor = "\x01" . implode("\x01", str_split($ppm, 3)); + }else{ + $grassColor = str_repeat("\x01\x85\xb2\x4a", 256); + } + $ordered = zlib_encode(Binary::writeLInt($X) . Binary::writeLInt($Z) . $orderedIds . $orderedData . $orderedSkyLight . $orderedLight . $biomeIDs . $grassColor, ZLIB_ENCODING_DEFLATE, 8); + + if(ADVANCED_CACHE == true and $Yndex === 0xff){ + Cache::add($identifier, $ordered, 60); + } + + return $ordered; + } + /** * Removes the entity from the level index * @@ -1351,6 +1414,15 @@ class Level implements ChunkManager, Metadatable{ return $this->provider->getName(); } + /** + * Returns the Level folder name + * + * @return string + */ + public function getFolderName(){ + return $this->folderName; + } + /** * Sets the current time on the level * @@ -1395,7 +1467,7 @@ class Level implements ChunkManager, Metadatable{ * @param int $seed */ public function setSeed($seed){ - $this->provider->setSeed(); + $this->provider->setSeed($seed); } diff --git a/src/pocketmine/level/format/ChunkSection.php b/src/pocketmine/level/format/ChunkSection.php index c2fe54e01..a3929a8fc 100644 --- a/src/pocketmine/level/format/ChunkSection.php +++ b/src/pocketmine/level/format/ChunkSection.php @@ -117,7 +117,7 @@ interface ChunkSection{ public function setBlockLight($x, $y, $z, $level); /** - * Returns a id column from high y to low y + * Returns a id column from low y to high y * * @param int $x 0-15 * @param int $z 0-15 @@ -127,7 +127,7 @@ interface ChunkSection{ public function getBlockIdColumn($x, $z); /** - * Returns a data column from high y to low y + * Returns a data column from low y to high y * * @param int $x 0-15 * @param int $z 0-15 @@ -136,6 +136,26 @@ interface ChunkSection{ */ public function getBlockDataColumn($x, $z); + /** + * Returns a skylight column from low y to high y + * + * @param int $x 0-15 + * @param int $z 0-15 + * + * @return string[8] + */ + public function getBlockSkyLightColumn($x, $z); + + /** + * Returns a data column from low y to high y + * + * @param int $x 0-15 + * @param int $z 0-15 + * + * @return string[8] + */ + public function getBlockLightColumn($x, $z); + public function getIdArray(); public function getDataArray(); diff --git a/src/pocketmine/level/format/LevelProvider.php b/src/pocketmine/level/format/LevelProvider.php index 227f8e454..fae814185 100644 --- a/src/pocketmine/level/format/LevelProvider.php +++ b/src/pocketmine/level/format/LevelProvider.php @@ -91,12 +91,13 @@ interface LevelProvider{ public function unloadChunks(); /** - * @param int $X - * @param int $Z + * @param int $X + * @param int $Z + * @param bool $create * * @return bool */ - public function loadChunk($X, $Z); + public function loadChunk($X, $Z, $create = false); /** * @param int $X diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index d04e56038..560d7f3b8 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -44,7 +44,7 @@ class Anvil extends BaseLevelProvider{ public static function isValid($path){ - return file_exists(realpath($path) . "level.dat") and file_exists(realpath($path) . "region/"); + return file_exists($path . "/level.dat") and is_dir($path . "/region/"); } public static function generate($path, $name, $seed, $generator, array $options = []){ @@ -109,7 +109,7 @@ class Anvil extends BaseLevelProvider{ } } - public function loadChunk($chunkX, $chunkZ){ + public function loadChunk($chunkX, $chunkZ, $create = false){ $index = Level::chunkHash($chunkX, $chunkZ); if(isset($this->chunks[$index])){ return true; @@ -117,7 +117,8 @@ class Anvil extends BaseLevelProvider{ $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); $this->loadRegion($regionX, $regionZ); - $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32, true); //generate empty chunk if not loaded + $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32, $create); //generate empty chunk if not loaded + if($chunk instanceof Chunk){ $this->chunks[$index] = $chunk; }else{ @@ -173,13 +174,10 @@ class Anvil extends BaseLevelProvider{ $index = Level::chunkHash($chunkX, $chunkZ); if(isset($this->chunks[$index])){ return $this->chunks[$index]; - }elseif($create !== true){ - return null; + }else{ + $this->loadChunk($chunkX, $chunkZ, $create); + return isset($this->chunks[$index]) ? $this->chunks[$index] : null; } - - $this->loadChunk($chunkX, $chunkZ); - - return $this->getChunk($chunkX, $chunkZ, false); } public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){ @@ -195,8 +193,8 @@ class Anvil extends BaseLevelProvider{ "Y" => new Byte("Y", $y), "Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)), "Data" => new ByteArray("Data", $chunk->getSectionData($y)), - "BlockLight" => new ByteArray("BlockLight", str_repeat("\xff", 2048)), //TODO - "SkyLight" => new ByteArray("SkyLight", str_repeat("\x00", 2048)) //TODO + "SkyLight" => new ByteArray("SkyLight", str_repeat("\xff", 2048)), //TODO + "BlockLight" => new ByteArray("BlockLight", str_repeat("\x00", 2048)) //TODO ])); $newChunk->setSection($y, $section); } @@ -239,7 +237,6 @@ class Anvil extends BaseLevelProvider{ public function close(){ $this->unloadChunks(); foreach($this->regions as $index => $region){ - $region->doSlowCleanUp(); $region->close(); unset($this->regions[$index]); } diff --git a/src/pocketmine/level/format/anvil/Chunk.php b/src/pocketmine/level/format/anvil/Chunk.php index 912dda509..290f99903 100644 --- a/src/pocketmine/level/format/anvil/Chunk.php +++ b/src/pocketmine/level/format/anvil/Chunk.php @@ -37,28 +37,28 @@ class Chunk extends BaseChunk{ public function __construct(LevelProvider $level, Compound $nbt){ $this->nbt = $nbt; - if($this->nbt->Entities instanceof Enum){ + if(isset($this->nbt->Entities) and $this->nbt->Entities instanceof Enum){ $this->nbt->Entities->setTagType(NBT::TAG_Compound); }else{ $this->nbt->Entities = new Enum("Entities", []); $this->nbt->Entities->setTagType(NBT::TAG_Compound); } - if($this->nbt->TileEntities instanceof Enum){ + if(isset($this->nbt->TileEntities) and $this->nbt->TileEntities instanceof Enum){ $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); }else{ $this->nbt->TileEntities = new Enum("TileEntities", []); $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); } - if($this->nbt->TileTicks instanceof Enum){ + if(isset($this->nbt->TileTicks) and $this->nbt->TileTicks instanceof Enum){ $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); }else{ $this->nbt->TileTicks = new Enum("TileTicks", []); $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); } - if($this->nbt->Sections instanceof Enum){ + if(isset($this->nbt->Sections) and $this->nbt->Sections instanceof Enum){ $this->nbt->Sections->setTagType(NBT::TAG_Compound); }else{ $this->nbt->Sections = new Enum("Sections", []); diff --git a/src/pocketmine/level/format/anvil/ChunkSection.php b/src/pocketmine/level/format/anvil/ChunkSection.php index 8ddc2c6fa..9ec74df6a 100644 --- a/src/pocketmine/level/format/anvil/ChunkSection.php +++ b/src/pocketmine/level/format/anvil/ChunkSection.php @@ -138,19 +138,38 @@ class ChunkSection implements \pocketmine\level\format\ChunkSection{ public function getBlockIdColumn($x, $z){ $i = ($z << 4) + $x; - $column = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - for($y = 15; $y >= 0; --$y){ - $column{15 - $y} = $this->blocks{($y << 8) + $i}; + $column = ""; + for($y = 0; $y < 16; ++$y){ + $column .= $this->blocks{($y << 8) + $i}; } - return $column; } public function getBlockDataColumn($x, $z){ $i = ($z << 3) + ($x >> 1); - $column = "\x00\x00\x00\x00\x00\x00\x00\x00"; - for($y = 7; $y >= 0; --$y){ - $column{7 - $y} = $this->data{($y << 7) + $i}; + $column = ""; + for($y = 0; $y < 8; ++$y){ + $column .= $this->data{($y << 7) + $i}; + } + + return $column; + } + + public function getBlockSkyLightColumn($x, $z){ + $i = ($z << 3) + ($x >> 1); + $column = ""; + for($y = 0; $y < 8; ++$y){ + $column .= $this->skyLight{($y << 7) + $i}; + } + + return $column; + } + + public function getBlockLightColumn($x, $z){ + $i = ($z << 3) + ($x >> 1); + $column = ""; + for($y = 0; $y < 8; ++$y){ + $column .= $this->blockLight{($y << 7) + $i}; } return $column; diff --git a/src/pocketmine/level/format/anvil/RegionLoader.php b/src/pocketmine/level/format/anvil/RegionLoader.php index 55464a093..3998552bc 100644 --- a/src/pocketmine/level/format/anvil/RegionLoader.php +++ b/src/pocketmine/level/format/anvil/RegionLoader.php @@ -120,13 +120,12 @@ class RegionLoader{ $nbt = new NBT(NBT::BIG_ENDIAN); $nbt->readCompressed(fread($this->filePointer, $length - 1), $compression); - $chunk = $nbt->getData()->Level; - - if(!$chunk instanceof Compound){ + $chunk = $nbt->getData(); + if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){ return false; } - return new Chunk($this->levelProvider, $chunk); + return new Chunk($this->levelProvider, $chunk->Level); } public function chunkExists($x, $z){ @@ -159,7 +158,8 @@ class RegionLoader{ protected function saveChunk($x, $z, Compound $nbt){ $writer = new NBT(NBT::BIG_ENDIAN); - $writer->setData(new Compound("", array($nbt))); + $nbt->setName("Level"); + $writer->setData(new Compound("", array("Level" => $nbt))); $chunkData = $writer->writeCompressed(self::COMPRESSION_ZLIB, self::$COMPRESSION_LEVEL); $length = strlen($chunkData) + 1; $sectors = (int) ceil(($length + 4) / 4096); @@ -171,6 +171,7 @@ class RegionLoader{ 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){ @@ -225,6 +226,7 @@ class RegionLoader{ } public function close(){ + $this->writeLocationTable(); flock($this->filePointer, LOCK_UN); fclose($this->filePointer); } diff --git a/src/pocketmine/level/format/generic/BaseChunk.php b/src/pocketmine/level/format/generic/BaseChunk.php index 194b532d5..507d0f33a 100644 --- a/src/pocketmine/level/format/generic/BaseChunk.php +++ b/src/pocketmine/level/format/generic/BaseChunk.php @@ -132,43 +132,43 @@ abstract class BaseChunk implements Chunk{ } public function getBlock($x, $y, $z, &$blockId, &$meta = null){ - return $this->sections[$y >> 4]->getBlock($x, $y - ($y >> 4), $z, $blockId, $meta); + return $this->sections[$y >> 4]->getBlock($x, $y & 0x0f, $z, $blockId, $meta); } public function setBlock($x, $y, $z, $blockId = null, $meta = null){ - $this->sections[$y >> 4]->setBlock($x, $y - ($y >> 4), $z, $blockId, $meta); + $this->sections[$y >> 4]->setBlock($x, $y & 0x0f, $z, $blockId, $meta); } public function getBlockId($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockId($x, $y - ($y >> 4), $z); + return $this->sections[$y >> 4]->getBlockId($x, $y & 0x0f, $z); } public function setBlockId($x, $y, $z, $id){ - $this->sections[$y >> 4]->setBlockId($x, $y - ($y >> 4), $z, $id); + $this->sections[$y >> 4]->setBlockId($x, $y & 0x0f, $z, $id); } public function getBlockData($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockData($x, $y - ($y >> 4), $z); + return $this->sections[$y >> 4]->getBlockData($x, $y & 0x0f, $z); } public function setBlockData($x, $y, $z, $data){ - $this->sections[$y >> 4]->setBlockData($x, $y - ($y >> 4), $z, $data); + $this->sections[$y >> 4]->setBlockData($x, $y & 0x0f, $z, $data); } public function getBlockSkyLight($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockSkyLight($x, $y - ($y >> 4), $z); + return $this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z); } public function setBlockSkyLight($x, $y, $z, $data){ - $this->sections[$y >> 4]->getBlockSkyLight($x, $y - ($y >> 4), $z, $data); + $this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data); } public function getBlockLight($x, $y, $z){ - return $this->sections[$y >> 4]->getBlockSkyLight($x, $y - ($y >> 4), $z); + return $this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z); } public function setBlockLight($x, $y, $z, $data){ - $this->sections[$y >> 4]->getBlockSkyLight($x, $y - ($y >> 4), $z, $data); + $this->sections[$y >> 4]->getBlockSkyLight($x, $y & 0x0f, $z, $data); } public function getHighestBlockAt($x, $z){ diff --git a/src/pocketmine/level/format/generic/BaseLevelProvider.php b/src/pocketmine/level/format/generic/BaseLevelProvider.php index ad7caab53..0897c2f01 100644 --- a/src/pocketmine/level/format/generic/BaseLevelProvider.php +++ b/src/pocketmine/level/format/generic/BaseLevelProvider.php @@ -37,7 +37,7 @@ abstract class BaseLevelProvider implements LevelProvider{ protected $levelData; public function __construct(Level $level, $path){ - $this->level = $level->getServer(); + $this->level = $level; $this->path = $path; @mkdir($this->path, 0777, true); $nbt = new NBT(NBT::BIG_ENDIAN); diff --git a/src/pocketmine/level/format/generic/EmptyChunkSection.php b/src/pocketmine/level/format/generic/EmptyChunkSection.php index 8f47f078a..87f770c33 100644 --- a/src/pocketmine/level/format/generic/EmptyChunkSection.php +++ b/src/pocketmine/level/format/generic/EmptyChunkSection.php @@ -50,6 +50,14 @@ class EmptyChunkSection implements ChunkSection{ return "\x00\x00\x00\x00\x00\x00\x00\x00"; } + final public function getBlockSkyLightColumn($x, $z){ + return "\x00\x00\x00\x00\x00\x00\x00\x00"; + } + + final public function getBlockLightColumn($x, $z){ + return "\x00\x00\x00\x00\x00\x00\x00\x00"; + } + final public function getBlock($x, $y, $z, &$id = null, &$meta = null){ $id = 0; $meta = 0; diff --git a/src/pocketmine/level/generator/Flat.php b/src/pocketmine/level/generator/Flat.php index 59459ff99..5cab14e55 100644 --- a/src/pocketmine/level/generator/Flat.php +++ b/src/pocketmine/level/generator/Flat.php @@ -59,7 +59,7 @@ class Flat extends Generator{ $this->preset = "2;7,2x3,2;1;"; //$this->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)"; $this->options = $options; - if(isset($options["preset"])){ + if(isset($options["preset"]) and $options["preset"] != ""){ $this->parsePreset($options["preset"]); }else{ $this->parsePreset($this->preset); @@ -112,19 +112,14 @@ class Flat extends Generator{ $this->chunk = new SimpleChunk(null, null, SimpleChunk::FLAG_GENERATED); - for($Y = 0; $Y < 8; ++$Y){ - $this->chunks[$Y] = ""; - $startY = $Y << 4; - $endY = $startY + 16; - for($Z = 0; $Z < 16; ++$Z){ - for($X = 0; $X < 16; ++$X){ - for($y = $startY; $y < $endY; ++$y){ - if($this->structure[$y][0] !== 0){ - $this->chunk->setBlockId($X, $y, $Z, $this->structure[$y][0]); - } - if($this->structure[$y][0] !== 0){ - $this->chunk->setBlockData($X, $y, $Z, $this->structure[$y][1]); - } + for($Z = 0; $Z < 16; ++$Z){ + for($X = 0; $X < 16; ++$X){ + for($y = 0; $y < 128; ++$y){ + if($this->structure[$y][0] !== 0){ + $this->chunk->setBlockId($X, $y, $Z, $this->structure[$y][0]); + } + if($this->structure[$y][0] !== 0){ + $this->chunk->setBlockData($X, $y, $Z, $this->structure[$y][1]); } } } @@ -164,6 +159,7 @@ class Flat extends Generator{ foreach($this->populators as $populator){ $populator->populate($this->level, $chunkX, $chunkZ, $this->random); } + } public function getSpawn(){ diff --git a/src/pocketmine/level/generator/GenerationChunkManager.php b/src/pocketmine/level/generator/GenerationChunkManager.php index 2c458f0c4..ee7e56671 100644 --- a/src/pocketmine/level/generator/GenerationChunkManager.php +++ b/src/pocketmine/level/generator/GenerationChunkManager.php @@ -83,6 +83,7 @@ class GenerationChunkManager implements ChunkManager{ public function generateChunk($chunkX, $chunkZ){ $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = new SimpleChunk($chunkX, $chunkZ, 0); $this->generator->generateChunk($chunkX, $chunkZ); + $this->setChunkGenerated($chunkX, $chunkZ); } public function populateChunk($chunkX, $chunkZ){ @@ -99,6 +100,8 @@ class GenerationChunkManager implements ChunkManager{ } $this->generator->populateChunk($chunkX, $chunkZ); + $this->setChunkPopulated($chunkX, $chunkZ); + } public function isChunkGenerated($chunkX, $chunkZ){ @@ -109,6 +112,14 @@ class GenerationChunkManager implements ChunkManager{ return $this->getChunk($chunkX, $chunkZ)->isPopulated(); } + public function setChunkGenerated($chunkX, $chunkZ){ + $this->getChunk($chunkX, $chunkZ)->setGenerated(true); + } + + public function setChunkPopulated($chunkX, $chunkZ){ + $this->getChunk($chunkX, $chunkZ)->setPopulated(true); + } + protected function requestChunk($chunkX, $chunkZ){ $chunk = $this->manager->requestChunk($this->levelID, $chunkX, $chunkZ); $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; diff --git a/src/pocketmine/level/generator/GenerationManager.php b/src/pocketmine/level/generator/GenerationManager.php index 369870501..047693996 100644 --- a/src/pocketmine/level/generator/GenerationManager.php +++ b/src/pocketmine/level/generator/GenerationManager.php @@ -122,9 +122,9 @@ class GenerationManager{ $chunkX = $r[1]; $chunkZ = $r[2]; $this->generateChunk($levelID, $chunkX, $chunkZ); - + }else{ + $this->readPacket(); } - $this->readPacket(); } } diff --git a/src/pocketmine/level/generator/Generator.php b/src/pocketmine/level/generator/Generator.php index 38a524a10..8541d405e 100644 --- a/src/pocketmine/level/generator/Generator.php +++ b/src/pocketmine/level/generator/Generator.php @@ -44,7 +44,8 @@ abstract class Generator{ return Generator::$list[$name]; } - return "pocketmine\\level\\generator\\Normal"; + //return "pocketmine\\level\\generator\\Normal"; + return "pocketmine\\level\\generator\\Flat"; } public static function getGeneratorName($class){ diff --git a/src/pocketmine/network/protocol/Info.php b/src/pocketmine/network/protocol/Info.php index d5dcc462a..e58090d95 100644 --- a/src/pocketmine/network/protocol/Info.php +++ b/src/pocketmine/network/protocol/Info.php @@ -30,7 +30,7 @@ interface Info{ /** * Actual Minecraft: PE protocol version */ - const CURRENT_PROTOCOL = 14; //WTF Mojang + const CURRENT_PROTOCOL = 15; const LOGIN_PACKET = 0x82; diff --git a/src/raklib b/src/raklib index 345009779..cac93ad97 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit 345009779b039fa9c0238fd0a57df5eeff2a2753 +Subproject commit cac93ad971a0b2792f4bb9873c73a76254dd1f7d