mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-13 09:19:42 +00:00
Updated to v0.9.0 build 2, now using Anvil worlds
This commit is contained in:
parent
fa50cbf4b3
commit
109b6dbf44
@ -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){
|
||||
|
@ -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) !== ""){
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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", []);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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(){
|
||||
|
@ -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;
|
||||
|
@ -122,9 +122,9 @@ class GenerationManager{
|
||||
$chunkX = $r[1];
|
||||
$chunkZ = $r[2];
|
||||
$this->generateChunk($levelID, $chunkX, $chunkZ);
|
||||
|
||||
}else{
|
||||
$this->readPacket();
|
||||
}
|
||||
$this->readPacket();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 345009779b039fa9c0238fd0a57df5eeff2a2753
|
||||
Subproject commit cac93ad971a0b2792f4bb9873c73a76254dd1f7d
|
Loading…
x
Reference in New Issue
Block a user