Updated to v0.9.0 build 2, now using Anvil worlds

This commit is contained in:
Shoghi Cervantes 2014-06-11 00:06:46 +02:00
parent fa50cbf4b3
commit 109b6dbf44
20 changed files with 235 additions and 107 deletions

View File

@ -83,6 +83,7 @@ use pocketmine\scheduler\CallbackTask;
use pocketmine\tile\Sign; use pocketmine\tile\Sign;
use pocketmine\tile\Spawnable; use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\ReversePriorityQueue;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
/** /**
@ -199,7 +200,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
} }
protected function initEntity(){ protected function initEntity(){
$this->getLevel()->players[spl_object_hash($this)] = $this;
parent::initEntity(); parent::initEntity();
} }
@ -515,7 +515,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
return false; return false;
}else{ }else{
$index = null; $index = null;
LevelFormat::getXZ($index, $this->lastChunk[0], $this->lastChunk[1]); Level::getXZ($index, $this->lastChunk[0], $this->lastChunk[1]);
unset($this->chunksLoaded[$index]); unset($this->chunksLoaded[$index]);
} }
}else{*/ }else{*/
@ -535,16 +535,17 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$index = key($this->chunksOrder); $index = key($this->chunksOrder);
$distance = @$this->chunksOrder[$index]; $distance = @$this->chunksOrder[$index];
if($index === null or $distance === null){ if($index === null or $distance === null){
$this->orderChunks();
if($this->chunkScheduled === 0){ if($this->chunkScheduled === 0){
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), 60); $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), 60);
} }
return false; return false;
} }
$X = null; $X = null;
$Z = null; $Z = null;
LevelFormat::getXZ($index, $X, $Z); Level::getXZ($index, $X, $Z);
if(!$this->getLevel()->isChunkPopulated($X, $Z)){ if(!$this->getLevel()->isChunkPopulated($X, $Z)){
$this->orderChunks(); $this->orderChunks();
if($this->chunkScheduled === 0 or $force === true){ if($this->chunkScheduled === 0 or $force === true){
@ -564,8 +565,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$pk = new FullChunkDataPacket; $pk = new FullChunkDataPacket;
$pk->chunkX = $X; $pk->chunkX = $X;
$pk->chunkZ = $Z; $pk->chunkZ = $Z;
$pk->data = $this->getLevel()->getOrderedChunk($X, $Z, $Yndex); $pk->data = $this->getLevel()->getNetworkChunk($X, $Z, $Yndex);
$cnt = $this->dataPacket($pk, true); $cnt = $this->dataPacket($pk, true);
if($cnt === false){ if($cnt === false){
return false; return false;
} }
@ -622,43 +624,38 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$startZ = $centerZ - $this->viewDistance; $startZ = $centerZ - $this->viewDistance;
$finalX = $centerX + $this->viewDistance; $finalX = $centerX + $this->viewDistance;
$finalZ = $centerZ + $this->viewDistance; $finalZ = $centerZ + $this->viewDistance;
$generateQueue = new ReversePriorityQueue();
for($X = $startX; $X <= $finalX; ++$X){ for($X = $startX; $X <= $finalX; ++$X){
for($Z = $startZ; $Z <= $finalZ; ++$Z){ for($Z = $startZ; $Z <= $finalZ; ++$Z){
$distance = abs($X - $centerX) + abs($Z - $centerZ); $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){ 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]); unset($lastChunk[$index]);
} }
} }
asort($newOrder); asort($newOrder);
$this->chunksOrder = $newOrder; $this->chunksOrder = $newOrder;
$index = key($this->chunksOrder); $i = 0;
LevelFormat::getXZ($index, $X, $Z); while($generateQueue->count() > 0 and $i < 8){
$radius = 1; $d = $generateQueue->extract();
for($z = $Z - $radius; $z <= ($Z + $radius); ++$z){ $this->getLevel()->generateChunk($d[0], $d[1]);
for($x = $X - $radius; $x <= ($X + $radius); ++$x){ ++$i;
$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);
}
}
} }
foreach($lastChunk as $index => $Yndex){ foreach($lastChunk as $index => $Yndex){
if($Yndex === 0){ if($Yndex === 0){
$X = null; $X = null;
$Z = null; $Z = null;
LevelFormat::getXZ($index, $X, $Z); Level::getXZ($index, $X, $Z);
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){ foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
if($entity !== $this){ if($entity !== $this){
$entity->despawnFrom($this); $entity->despawnFrom($this);
@ -1146,7 +1143,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$nbt["lastPlayed"] = floor(microtime(true) * 1000); $nbt["lastPlayed"] = floor(microtime(true) * 1000);
$this->server->saveOfflinePlayerData($this->username, $nbt); $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->inventory->setHeldItemSlot($this->getCreativeBlock(Item::get(Item::STONE, 0, 1)));
$this->loggedIn = true; $this->loggedIn = true;
@ -1971,7 +1968,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
*/ */
public function close($message = "", $reason = "generic reason"){ public function close($message = "", $reason = "generic reason"){
if($this->connected === true){ if($this->connected === true){
unset($this->getLevel()->players[spl_object_hash($this)]);
if($this->username != ""){ if($this->username != ""){
$this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message)); $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message));
if($this->loggedIn === true){ if($this->loggedIn === true){

View File

@ -75,7 +75,7 @@ namespace pocketmine {
const VERSION = "Alpha_1.4dev"; const VERSION = "Alpha_1.4dev";
const API_VERSION = "1.0.0"; const API_VERSION = "1.0.0";
const CODENAME = "絶好(Zekkou)ケーキ(Cake)"; 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"; const PHP_VERSION = "5.5";
if(\Phar::running(true) !== ""){ if(\Phar::running(true) !== ""){

View File

@ -776,7 +776,7 @@ class Server{
* @param Level $level * @param Level $level
*/ */
public function setDefaultLevel($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; $this->levelDefault = $level;
} }
} }
@ -810,7 +810,7 @@ class Server{
*/ */
public function getLevelByName($name){ public function getLevelByName($name){
foreach($this->getLevels() as $level){ foreach($this->getLevels() as $level){
if($level->getName() === $name){ if($level->getFolderName() === $name){
return $level; return $level;
} }
} }
@ -823,7 +823,7 @@ class Server{
* @param bool $forceUnload * @param bool $forceUnload
*/ */
public function unloadLevel(Level $level, $forceUnload = false){ 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()]); unset($this->levels[$level->getID()]);
} }
} }
@ -852,6 +852,7 @@ class Server{
$path = $this->getDataPath() . "worlds/" . $name . "/"; $path = $this->getDataPath() . "worlds/" . $name . "/";
$provider = LevelProviderManager::getProvider($path); $provider = LevelProviderManager::getProvider($path);
if($provider === null){ if($provider === null){
$this->logger->error("Could not load level \"" . $name . "\""); $this->logger->error("Could not load level \"" . $name . "\"");
@ -862,7 +863,7 @@ class Server{
// @rename($path . "tileEntities.yml", $path . "tiles.yml"); // @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; $this->levels[$level->getID()] = $level;
/*foreach($entities->getAll() as $entity){ /*foreach($entities->getAll() as $entity){
if(!isset($entity["id"])){ if(!isset($entity["id"])){
@ -994,7 +995,7 @@ class Server{
/** @var \pocketmine\level\format\LevelProvider $provider */ /** @var \pocketmine\level\format\LevelProvider $provider */
$provider::generate($path, $name, $seed, $generator, $options); $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; $this->levels[$level->getID()] = $level;
for($Z = 6; $Z <= 10; ++$Z){ for($Z = 6; $Z <= 10; ++$Z){
for($X = 6; $X <= 10; ++$X){ for($X = 6; $X <= 10; ++$X){
@ -1015,15 +1016,19 @@ class Server{
return false; return false;
} }
$path = $this->getDataPath() . "worlds/" . $name . "/"; $path = $this->getDataPath() . "worlds/" . $name . "/";
if(!($this->getLevelByName($name) instanceof Level) and !file_exists($path . "level.pmf")){ if(!($this->getLevelByName($name) instanceof Level)){
if(file_exists($path)){
if(LevelProviderManager::getProvider($path) === null){
return false;
}
/*if(file_exists($path)){
$level = new LevelImport($path); $level = new LevelImport($path);
if($level->import() === false){ //Try importing a world if($level->import() === false){ //Try importing a world
return false; return false;
} }
}else{ }else{
return false; return false;
} }*/
} }
return true; return true;
@ -1356,9 +1361,9 @@ class Server{
LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil"); LevelProviderManager::addProvider($this, "pocketmine\\level\\format\\anvil\\Anvil");
Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat"); //Generator::addGenerator("pocketmine\\level\\generator\\Flat", "flat");
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal"); //Generator::addGenerator("pocketmine\\level\\generator\\Normal", "normal");
Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default"); //Generator::addGenerator("pocketmine\\level\\generator\\Normal", "default");
if($this->getDefaultLevel() === null){ if($this->getDefaultLevel() === null){
$default = $this->getConfigString("level-name", "world"); $default = $this->getConfigString("level-name", "world");

View File

@ -589,7 +589,7 @@ abstract class Entity extends Position implements Metadatable{
if($Yndex !== 0xff){ if($Yndex !== 0xff){
$X = null; $X = null;
$Z = null; $Z = null;
LevelFormat::getXZ($index, $X, $Z); Level::getXZ($index, $X, $Z);
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){ foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
$entity->despawnFrom($this); $entity->despawnFrom($this);
} }

View File

@ -60,6 +60,7 @@ use pocketmine\tile\Sign;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\Cache; use pocketmine\utils\Cache;
use pocketmine\utils\ReversePriorityQueue; use pocketmine\utils\ReversePriorityQueue;
use raklib\Binary;
class Level implements ChunkManager, Metadatable{ class Level implements ChunkManager, Metadatable{
@ -109,6 +110,8 @@ class Level implements ChunkManager, Metadatable{
private $startCheck; private $startCheck;
private $startTime; private $startTime;
private $folderName;
/** @var Block[][] */ /** @var Block[][] */
protected $changedBlocks = []; protected $changedBlocks = [];
protected $changedCount = []; protected $changedCount = [];
@ -140,12 +143,13 @@ class Level implements ChunkManager, Metadatable{
* Init the default level data * Init the default level data
* *
* @param Server $server * @param Server $server
* @param string $name
* @param string $path * @param string $path
* @param string $provider Class that extends LevelProvider * @param string $provider Class that extends LevelProvider
* *
* @throws \Exception * @throws \Exception
*/ */
public function __construct(Server $server, $path, $provider){ public function __construct(Server $server, $name, $path, $provider){
$this->levelId = static::$levelIdCounter++; $this->levelId = static::$levelIdCounter++;
$this->server = $server; $this->server = $server;
if(is_subclass_of($provider, "pocketmine\\level\\format\\LevelProvider", true)){ 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()); $generator = Generator::getGenerator($this->provider->getGenerator());
$this->server->getGenerationManager()->openLevel($this, $generator, $this->provider->getGeneratorOptions()); $this->server->getGenerationManager()->openLevel($this, $generator, $this->provider->getGeneratorOptions());
$this->folderName = $name;
$this->startTime = $this->time = (int) $this->provider->getTime(); $this->startTime = $this->time = (int) $this->provider->getTime();
$this->nextSave = $this->startCheck = microtime(true); $this->nextSave = $this->startCheck = microtime(true);
$this->nextSave = microtime(true) + 90; $this->nextSave = microtime(true) + 90;
@ -523,7 +529,7 @@ class Level implements ChunkManager, Metadatable{
public function getBlock(Vector3 $pos){ public function getBlock(Vector3 $pos){
$blockId = null; $blockId = null;
$meta = 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)); return Block::get($blockId, $meta, Position::fromObject(clone $pos, $this));
} }
@ -1059,7 +1065,7 @@ class Level implements ChunkManager, Metadatable{
* @return Chunk * @return Chunk
*/ */
public function getChunkAt($x, $z, $create = false){ 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)); $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 * Removes the entity from the level index
* *
@ -1351,6 +1414,15 @@ class Level implements ChunkManager, Metadatable{
return $this->provider->getName(); return $this->provider->getName();
} }
/**
* Returns the Level folder name
*
* @return string
*/
public function getFolderName(){
return $this->folderName;
}
/** /**
* Sets the current time on the level * Sets the current time on the level
* *
@ -1395,7 +1467,7 @@ class Level implements ChunkManager, Metadatable{
* @param int $seed * @param int $seed
*/ */
public function setSeed($seed){ public function setSeed($seed){
$this->provider->setSeed(); $this->provider->setSeed($seed);
} }

View File

@ -117,7 +117,7 @@ interface ChunkSection{
public function setBlockLight($x, $y, $z, $level); 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 $x 0-15
* @param int $z 0-15 * @param int $z 0-15
@ -127,7 +127,7 @@ interface ChunkSection{
public function getBlockIdColumn($x, $z); 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 $x 0-15
* @param int $z 0-15 * @param int $z 0-15
@ -136,6 +136,26 @@ interface ChunkSection{
*/ */
public function getBlockDataColumn($x, $z); 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 getIdArray();
public function getDataArray(); public function getDataArray();

View File

@ -91,12 +91,13 @@ interface LevelProvider{
public function unloadChunks(); public function unloadChunks();
/** /**
* @param int $X * @param int $X
* @param int $Z * @param int $Z
* @param bool $create
* *
* @return bool * @return bool
*/ */
public function loadChunk($X, $Z); public function loadChunk($X, $Z, $create = false);
/** /**
* @param int $X * @param int $X

View File

@ -44,7 +44,7 @@ class Anvil extends BaseLevelProvider{
public static function isValid($path){ 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 = []){ 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); $index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){ if(isset($this->chunks[$index])){
return true; return true;
@ -117,7 +117,8 @@ class Anvil extends BaseLevelProvider{
$regionX = $regionZ = null; $regionX = $regionZ = null;
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
$this->loadRegion($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){ if($chunk instanceof Chunk){
$this->chunks[$index] = $chunk; $this->chunks[$index] = $chunk;
}else{ }else{
@ -173,13 +174,10 @@ class Anvil extends BaseLevelProvider{
$index = Level::chunkHash($chunkX, $chunkZ); $index = Level::chunkHash($chunkX, $chunkZ);
if(isset($this->chunks[$index])){ if(isset($this->chunks[$index])){
return $this->chunks[$index]; return $this->chunks[$index];
}elseif($create !== true){ }else{
return null; $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){ public function setChunk($chunkX, $chunkZ, SimpleChunk $chunk){
@ -195,8 +193,8 @@ class Anvil extends BaseLevelProvider{
"Y" => new Byte("Y", $y), "Y" => new Byte("Y", $y),
"Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)), "Blocks" => new ByteArray("Blocks", $chunk->getSectionIds($y)),
"Data" => new ByteArray("Data", $chunk->getSectionData($y)), "Data" => new ByteArray("Data", $chunk->getSectionData($y)),
"BlockLight" => new ByteArray("BlockLight", str_repeat("\xff", 2048)), //TODO "SkyLight" => new ByteArray("SkyLight", str_repeat("\xff", 2048)), //TODO
"SkyLight" => new ByteArray("SkyLight", str_repeat("\x00", 2048)) //TODO "BlockLight" => new ByteArray("BlockLight", str_repeat("\x00", 2048)) //TODO
])); ]));
$newChunk->setSection($y, $section); $newChunk->setSection($y, $section);
} }
@ -239,7 +237,6 @@ class Anvil extends BaseLevelProvider{
public function close(){ public function close(){
$this->unloadChunks(); $this->unloadChunks();
foreach($this->regions as $index => $region){ foreach($this->regions as $index => $region){
$region->doSlowCleanUp();
$region->close(); $region->close();
unset($this->regions[$index]); unset($this->regions[$index]);
} }

View File

@ -37,28 +37,28 @@ class Chunk extends BaseChunk{
public function __construct(LevelProvider $level, Compound $nbt){ public function __construct(LevelProvider $level, Compound $nbt){
$this->nbt = $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); $this->nbt->Entities->setTagType(NBT::TAG_Compound);
}else{ }else{
$this->nbt->Entities = new Enum("Entities", []); $this->nbt->Entities = new Enum("Entities", []);
$this->nbt->Entities->setTagType(NBT::TAG_Compound); $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); $this->nbt->TileEntities->setTagType(NBT::TAG_Compound);
}else{ }else{
$this->nbt->TileEntities = new Enum("TileEntities", []); $this->nbt->TileEntities = new Enum("TileEntities", []);
$this->nbt->TileEntities->setTagType(NBT::TAG_Compound); $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); $this->nbt->TileTicks->setTagType(NBT::TAG_Compound);
}else{ }else{
$this->nbt->TileTicks = new Enum("TileTicks", []); $this->nbt->TileTicks = new Enum("TileTicks", []);
$this->nbt->TileTicks->setTagType(NBT::TAG_Compound); $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); $this->nbt->Sections->setTagType(NBT::TAG_Compound);
}else{ }else{
$this->nbt->Sections = new Enum("Sections", []); $this->nbt->Sections = new Enum("Sections", []);

View File

@ -138,19 +138,38 @@ class ChunkSection implements \pocketmine\level\format\ChunkSection{
public function getBlockIdColumn($x, $z){ public function getBlockIdColumn($x, $z){
$i = ($z << 4) + $x; $i = ($z << 4) + $x;
$column = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; $column = "";
for($y = 15; $y >= 0; --$y){ for($y = 0; $y < 16; ++$y){
$column{15 - $y} = $this->blocks{($y << 8) + $i}; $column .= $this->blocks{($y << 8) + $i};
} }
return $column; return $column;
} }
public function getBlockDataColumn($x, $z){ public function getBlockDataColumn($x, $z){
$i = ($z << 3) + ($x >> 1); $i = ($z << 3) + ($x >> 1);
$column = "\x00\x00\x00\x00\x00\x00\x00\x00"; $column = "";
for($y = 7; $y >= 0; --$y){ for($y = 0; $y < 8; ++$y){
$column{7 - $y} = $this->data{($y << 7) + $i}; $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; return $column;

View File

@ -120,13 +120,12 @@ class RegionLoader{
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new NBT(NBT::BIG_ENDIAN);
$nbt->readCompressed(fread($this->filePointer, $length - 1), $compression); $nbt->readCompressed(fread($this->filePointer, $length - 1), $compression);
$chunk = $nbt->getData()->Level; $chunk = $nbt->getData();
if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){
if(!$chunk instanceof Compound){
return false; return false;
} }
return new Chunk($this->levelProvider, $chunk); return new Chunk($this->levelProvider, $chunk->Level);
} }
public function chunkExists($x, $z){ public function chunkExists($x, $z){
@ -159,7 +158,8 @@ class RegionLoader{
protected function saveChunk($x, $z, Compound $nbt){ protected function saveChunk($x, $z, Compound $nbt){
$writer = new NBT(NBT::BIG_ENDIAN); $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); $chunkData = $writer->writeCompressed(self::COMPRESSION_ZLIB, self::$COMPRESSION_LEVEL);
$length = strlen($chunkData) + 1; $length = strlen($chunkData) + 1;
$sectors = (int) ceil(($length + 4) / 4096); $sectors = (int) ceil(($length + 4) / 4096);
@ -171,6 +171,7 @@ class RegionLoader{
fseek($this->filePointer, $this->locationTable[$index][0] << 12); 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)); 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){ public function removeChunk($x, $z){
@ -225,6 +226,7 @@ class RegionLoader{
} }
public function close(){ public function close(){
$this->writeLocationTable();
flock($this->filePointer, LOCK_UN); flock($this->filePointer, LOCK_UN);
fclose($this->filePointer); fclose($this->filePointer);
} }

View File

@ -132,43 +132,43 @@ abstract class BaseChunk implements Chunk{
} }
public function getBlock($x, $y, $z, &$blockId, &$meta = null){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ public function getHighestBlockAt($x, $z){

View File

@ -37,7 +37,7 @@ abstract class BaseLevelProvider implements LevelProvider{
protected $levelData; protected $levelData;
public function __construct(Level $level, $path){ public function __construct(Level $level, $path){
$this->level = $level->getServer(); $this->level = $level;
$this->path = $path; $this->path = $path;
@mkdir($this->path, 0777, true); @mkdir($this->path, 0777, true);
$nbt = new NBT(NBT::BIG_ENDIAN); $nbt = new NBT(NBT::BIG_ENDIAN);

View File

@ -50,6 +50,14 @@ class EmptyChunkSection implements ChunkSection{
return "\x00\x00\x00\x00\x00\x00\x00\x00"; 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){ final public function getBlock($x, $y, $z, &$id = null, &$meta = null){
$id = 0; $id = 0;
$meta = 0; $meta = 0;

View File

@ -59,7 +59,7 @@ class Flat extends Generator{
$this->preset = "2;7,2x3,2;1;"; $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->preset = "2;7,59x1,3x3,2;1;spawn(radius=10 block=89),decoration(treecount=80 grasscount=45)";
$this->options = $options; $this->options = $options;
if(isset($options["preset"])){ if(isset($options["preset"]) and $options["preset"] != ""){
$this->parsePreset($options["preset"]); $this->parsePreset($options["preset"]);
}else{ }else{
$this->parsePreset($this->preset); $this->parsePreset($this->preset);
@ -112,19 +112,14 @@ class Flat extends Generator{
$this->chunk = new SimpleChunk(null, null, SimpleChunk::FLAG_GENERATED); $this->chunk = new SimpleChunk(null, null, SimpleChunk::FLAG_GENERATED);
for($Y = 0; $Y < 8; ++$Y){ for($Z = 0; $Z < 16; ++$Z){
$this->chunks[$Y] = ""; for($X = 0; $X < 16; ++$X){
$startY = $Y << 4; for($y = 0; $y < 128; ++$y){
$endY = $startY + 16; if($this->structure[$y][0] !== 0){
for($Z = 0; $Z < 16; ++$Z){ $this->chunk->setBlockId($X, $y, $Z, $this->structure[$y][0]);
for($X = 0; $X < 16; ++$X){ }
for($y = $startY; $y < $endY; ++$y){ if($this->structure[$y][0] !== 0){
if($this->structure[$y][0] !== 0){ $this->chunk->setBlockData($X, $y, $Z, $this->structure[$y][1]);
$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){ foreach($this->populators as $populator){
$populator->populate($this->level, $chunkX, $chunkZ, $this->random); $populator->populate($this->level, $chunkX, $chunkZ, $this->random);
} }
} }
public function getSpawn(){ public function getSpawn(){

View File

@ -83,6 +83,7 @@ class GenerationChunkManager implements ChunkManager{
public function generateChunk($chunkX, $chunkZ){ public function generateChunk($chunkX, $chunkZ){
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = new SimpleChunk($chunkX, $chunkZ, 0); $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = new SimpleChunk($chunkX, $chunkZ, 0);
$this->generator->generateChunk($chunkX, $chunkZ); $this->generator->generateChunk($chunkX, $chunkZ);
$this->setChunkGenerated($chunkX, $chunkZ);
} }
public function populateChunk($chunkX, $chunkZ){ public function populateChunk($chunkX, $chunkZ){
@ -99,6 +100,8 @@ class GenerationChunkManager implements ChunkManager{
} }
$this->generator->populateChunk($chunkX, $chunkZ); $this->generator->populateChunk($chunkX, $chunkZ);
$this->setChunkPopulated($chunkX, $chunkZ);
} }
public function isChunkGenerated($chunkX, $chunkZ){ public function isChunkGenerated($chunkX, $chunkZ){
@ -109,6 +112,14 @@ class GenerationChunkManager implements ChunkManager{
return $this->getChunk($chunkX, $chunkZ)->isPopulated(); 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){ protected function requestChunk($chunkX, $chunkZ){
$chunk = $this->manager->requestChunk($this->levelID, $chunkX, $chunkZ); $chunk = $this->manager->requestChunk($this->levelID, $chunkX, $chunkZ);
$this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk;

View File

@ -122,9 +122,9 @@ class GenerationManager{
$chunkX = $r[1]; $chunkX = $r[1];
$chunkZ = $r[2]; $chunkZ = $r[2];
$this->generateChunk($levelID, $chunkX, $chunkZ); $this->generateChunk($levelID, $chunkX, $chunkZ);
}else{
$this->readPacket();
} }
$this->readPacket();
} }
} }

View File

@ -44,7 +44,8 @@ abstract class Generator{
return Generator::$list[$name]; return Generator::$list[$name];
} }
return "pocketmine\\level\\generator\\Normal"; //return "pocketmine\\level\\generator\\Normal";
return "pocketmine\\level\\generator\\Flat";
} }
public static function getGeneratorName($class){ public static function getGeneratorName($class){

View File

@ -30,7 +30,7 @@ interface Info{
/** /**
* Actual Minecraft: PE protocol version * Actual Minecraft: PE protocol version
*/ */
const CURRENT_PROTOCOL = 14; //WTF Mojang const CURRENT_PROTOCOL = 15;
const LOGIN_PACKET = 0x82; const LOGIN_PACKET = 0x82;

@ -1 +1 @@
Subproject commit 345009779b039fa9c0238fd0a57df5eeff2a2753 Subproject commit cac93ad971a0b2792f4bb9873c73a76254dd1f7d