mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-21 08:17:34 +00:00
Added block order detection, added support for non-sectioned level formats
This commit is contained in:
parent
8fafb85784
commit
016b08ecf2
@ -57,6 +57,7 @@ use pocketmine\inventory\InventoryHolder;
|
||||
use pocketmine\inventory\SimpleTransactionGroup;
|
||||
use pocketmine\inventory\StonecutterShapelessRecipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\level\Position;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -601,7 +602,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$this->usedChunks[$index] = [false, 0];
|
||||
|
||||
$this->getLevel()->useChunk($X, $Z, $this);
|
||||
$this->getLevel()->requestChunk($X, $Z, $this);
|
||||
$this->getLevel()->requestChunk($X, $Z, $this, LevelProvider::ORDER_ZXY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
/** @var BlockMetadataStore */
|
||||
private $blockMetadata;
|
||||
|
||||
private $useSections;
|
||||
private $blockOrder;
|
||||
|
||||
protected $chunkTickRadius;
|
||||
protected $chunkTickList = [];
|
||||
protected $chunksPerTick;
|
||||
@ -199,6 +202,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->levelId = static::$levelIdCounter++;
|
||||
$this->blockMetadata = new BlockMetadataStore($this);
|
||||
$this->server = $server;
|
||||
|
||||
/** @var LevelProvider $provider */
|
||||
|
||||
if(is_subclass_of($provider, "pocketmine\\level\\format\\LevelProvider", true)){
|
||||
$this->provider = new $provider($this, $path);
|
||||
}else{
|
||||
@ -208,6 +214,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
$generator = Generator::getGenerator($this->provider->getGenerator());
|
||||
$this->server->getGenerationManager()->openLevel($this, $generator, $this->provider->getGeneratorOptions());
|
||||
|
||||
$this->blockOrder = $provider::getProviderOrder();
|
||||
$this->useSections = $provider::usesChunkSection();
|
||||
|
||||
$this->folderName = $name;
|
||||
$this->updateQueue = new ReversePriorityQueue();
|
||||
$this->updateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
|
||||
@ -220,6 +229,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->chunkTickList = [];
|
||||
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", false);
|
||||
$this->timings = new LevelTimings($this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -509,9 +519,27 @@ class Level implements ChunkManager, Metadatable{
|
||||
$chunk = $this->getChunkAt($chunkX, $chunkZ, true);
|
||||
|
||||
|
||||
foreach($chunk->getSections() as $section){
|
||||
if(!($section instanceof EmptyChunkSection)){
|
||||
$Y = $section->getY();
|
||||
if($this->useSections){
|
||||
foreach($chunk->getSections() as $section){
|
||||
if(!($section instanceof EmptyChunkSection)){
|
||||
$Y = $section->getY();
|
||||
$k = mt_rand(0, PHP_INT_MAX);
|
||||
for($i = 0; $i < 3; ++$i){
|
||||
$j = $k >> 2;
|
||||
$x = $j & 0x0f;
|
||||
$y = ($j >> 8) & 0x0f;
|
||||
$z = ($j >> 16) & 0x0f;
|
||||
$k %= 1073741827;
|
||||
$blockId = $section->getBlockId($x, $y, $z);
|
||||
if(isset($this->randomTickBlocks[$blockId])){
|
||||
$block = Block::get($blockId, $section->getBlockData($x, $y, $z), new Position($chunkX * 16 + $x, ($Y << 4) + $y, $chunkZ * 16 + $z, $this));
|
||||
$block->onUpdate(self::BLOCK_UPDATE_RANDOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for($Y = 0; $Y < 8; ++$Y){
|
||||
$k = mt_rand(0, PHP_INT_MAX);
|
||||
for($i = 0; $i < 3; ++$i){
|
||||
$j = $k >> 2;
|
||||
@ -519,9 +547,9 @@ class Level implements ChunkManager, Metadatable{
|
||||
$y = ($j >> 8) & 0x0f;
|
||||
$z = ($j >> 16) & 0x0f;
|
||||
$k %= 1073741827;
|
||||
$blockId = $section->getBlockId($x, $y, $z);
|
||||
$blockId = $chunk->getBlockId($x, $y + ($Y << 4), $z);
|
||||
if(isset($this->randomTickBlocks[$blockId])){
|
||||
$block = Block::get($blockId, $section->getBlockData($x, $y, $z), new Position($chunkX * 16 + $x, $Y * 16 + $y, $chunkZ * 16 + $z, $this));
|
||||
$block = Block::get($blockId, $chunk->getBlockData($x, $y + ($Y << 4), $z), new Position($chunkX * 16 + $x, ($Y << 4) + $y, $chunkZ * 16 + $z, $this));
|
||||
$block->onUpdate(self::BLOCK_UPDATE_RANDOM);
|
||||
}
|
||||
}
|
||||
@ -1372,13 +1400,36 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->server->getPluginManager()->callEvent(new SpawnChangeEvent($this, $previousSpawn));
|
||||
}
|
||||
|
||||
public function requestChunk($x, $z, Player $player){
|
||||
$index = Level::chunkHash($x, $z);
|
||||
if(!isset($this->chunkSendQueue[$index])){
|
||||
$this->chunkSendQueue[$index] = [];
|
||||
public function requestChunk($x, $z, Player $player, $order = LevelProvider::ORDER_ZXY){
|
||||
if($this->blockOrder === $order){
|
||||
$player->sendChunk($x, $z, $this->getNetworkChunk($x, $z));
|
||||
}else{
|
||||
$index = Level::chunkHash($x, $z);
|
||||
if(!isset($this->chunkSendQueue[$index])){
|
||||
$this->chunkSendQueue[$index] = [];
|
||||
}
|
||||
|
||||
$this->chunkSendQueue[$index][spl_object_hash($player)] = $player;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getNetworkChunk($x, $z){
|
||||
$chunk = $this->getChunkAt($x, $z, true);
|
||||
$tiles = "";
|
||||
$nbt = new NBT(NBT::LITTLE_ENDIAN);
|
||||
foreach($chunk->getTiles() as $tile){
|
||||
if($tile instanceof Spawnable){
|
||||
$nbt->setData($tile->getSpawnCompound());
|
||||
$tiles .= $nbt->write();
|
||||
}
|
||||
}
|
||||
|
||||
$this->chunkSendQueue[$index][spl_object_hash($player)] = $player;
|
||||
$biomeColors = "";
|
||||
foreach($chunk->getBiomeColorArray() as $color){
|
||||
$biomeColors .= Binary::writeInt($color);
|
||||
}
|
||||
|
||||
return zlib_encode(Binary::writeLInt($x) . Binary::writeLInt($z) . $chunk->getBlockIdArray() . $chunk->getBlockDataArray() . $chunk->getBlockSkyLightArray() . $chunk->getBlockLightArray() . $chunk->getBiomeIdArray() . $biomeColors . $tiles, ZLIB_ENCODING_DEFLATE, Level::$COMPRESSION_LEVEL);
|
||||
}
|
||||
|
||||
protected function processChunkRequest(){
|
||||
|
@ -24,217 +24,9 @@ namespace pocketmine\level\format;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
interface Chunk{
|
||||
interface Chunk extends FullChunk{
|
||||
const SECTION_COUNT = 8;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getX();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getZ();
|
||||
|
||||
/**
|
||||
* @return \pocketmine\level\format\LevelProvider
|
||||
*/
|
||||
public function getLevel();
|
||||
|
||||
|
||||
/**
|
||||
* Modifies $blockId and $meta
|
||||
*
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int &$blockId
|
||||
* @param int &$meta
|
||||
*/
|
||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $blockId , if null, do not change
|
||||
* @param int $meta 0-15, if null, do not change
|
||||
*
|
||||
*/
|
||||
public function setBlock($x, $y, $z, $blockId = null, $meta = null);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-255
|
||||
*/
|
||||
public function getBlockId($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $id 0-255
|
||||
*/
|
||||
public function setBlockId($x, $y, $z, $id);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockData($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $data 0-15
|
||||
*/
|
||||
public function setBlockData($x, $y, $z, $data);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockSkyLight($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $level 0-15
|
||||
*/
|
||||
public function setBlockSkyLight($x, $y, $z, $level);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockLight($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $level 0-15
|
||||
*/
|
||||
public function setBlockLight($x, $y, $z, $level);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-127
|
||||
*/
|
||||
public function getHighestBlockAt($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-255
|
||||
*/
|
||||
public function getBiomeId($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
* @param int $biomeId 0-255
|
||||
*/
|
||||
public function setBiomeId($x, $z, $biomeId);
|
||||
|
||||
/**
|
||||
* @param int $x
|
||||
* @param int $z
|
||||
*
|
||||
* @return int[] RGB bytes
|
||||
*/
|
||||
public function getBiomeColor($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
* @param int $R 0-255
|
||||
* @param int $G 0-255
|
||||
* @param int $B 0-255
|
||||
*/
|
||||
public function setBiomeColor($x, $z, $R, $G, $B);
|
||||
|
||||
/**
|
||||
* Thread-safe read-only chunk
|
||||
*
|
||||
* @param bool $includeMaxBlockY
|
||||
* @param bool $includeBiome
|
||||
* @param bool $includeBiomeTemp
|
||||
*
|
||||
* @return ChunkSnapshot
|
||||
*/
|
||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false);
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function addEntity(Entity $entity);
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function removeEntity(Entity $entity);
|
||||
|
||||
/**
|
||||
* @param Tile $tile
|
||||
*/
|
||||
public function addTile(Tile $tile);
|
||||
|
||||
/**
|
||||
* @param Tile $tile
|
||||
*/
|
||||
public function removeTile(Tile $tile);
|
||||
|
||||
/**
|
||||
* @return \pocketmine\entity\Entity[]
|
||||
*/
|
||||
public function getEntities();
|
||||
|
||||
/**
|
||||
* @return \pocketmine\tile\Tile[]
|
||||
*/
|
||||
public function getTiles();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoaded();
|
||||
|
||||
/**
|
||||
* Loads the chunk
|
||||
*
|
||||
* @param bool $generate If the chunk does not exist, generate it
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function load($generate = true);
|
||||
|
||||
/**
|
||||
* @param bool $save
|
||||
* @param bool $safe If false, unload the chunk even if players are nearby
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function unload($save = true, $safe = true);
|
||||
|
||||
/**
|
||||
* Tests whether a section (mini-chunk) is empty
|
||||
*
|
||||
@ -264,14 +56,4 @@ interface Chunk{
|
||||
*/
|
||||
public function getSections();
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getBiomeIdArray();
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getBiomeColorArray();
|
||||
|
||||
}
|
263
src/pocketmine/level/format/FullChunk.php
Normal file
263
src/pocketmine/level/format/FullChunk.php
Normal file
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\level\format;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\tile\Tile;
|
||||
|
||||
interface FullChunk{
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getX();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getZ();
|
||||
|
||||
/**
|
||||
* @return \pocketmine\level\format\LevelProvider
|
||||
*/
|
||||
public function getLevel();
|
||||
|
||||
|
||||
/**
|
||||
* Modifies $blockId and $meta
|
||||
*
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int &$blockId
|
||||
* @param int &$meta
|
||||
*/
|
||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $blockId , if null, do not change
|
||||
* @param int $meta 0-15, if null, do not change
|
||||
*
|
||||
*/
|
||||
public function setBlock($x, $y, $z, $blockId = null, $meta = null);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-255
|
||||
*/
|
||||
public function getBlockId($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $id 0-255
|
||||
*/
|
||||
public function setBlockId($x, $y, $z, $id);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockData($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $data 0-15
|
||||
*/
|
||||
public function setBlockData($x, $y, $z, $data);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockSkyLight($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $level 0-15
|
||||
*/
|
||||
public function setBlockSkyLight($x, $y, $z, $level);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getBlockLight($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $level 0-15
|
||||
*/
|
||||
public function setBlockLight($x, $y, $z, $level);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-127
|
||||
*/
|
||||
public function getHighestBlockAt($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-255
|
||||
*/
|
||||
public function getBiomeId($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
* @param int $biomeId 0-255
|
||||
*/
|
||||
public function setBiomeId($x, $z, $biomeId);
|
||||
|
||||
/**
|
||||
* @param int $x
|
||||
* @param int $z
|
||||
*
|
||||
* @return int[] RGB bytes
|
||||
*/
|
||||
public function getBiomeColor($x, $z);
|
||||
|
||||
public function getBlockIdColumn($x, $z);
|
||||
|
||||
public function getBlockDataColumn($x, $z);
|
||||
|
||||
public function getBlockSkyLightColumn($x, $z);
|
||||
|
||||
public function getBlockLightColumn($x, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
* @param int $R 0-255
|
||||
* @param int $G 0-255
|
||||
* @param int $B 0-255
|
||||
*/
|
||||
public function setBiomeColor($x, $z, $R, $G, $B);
|
||||
|
||||
/**
|
||||
* Thread-safe read-only chunk
|
||||
*
|
||||
* @param bool $includeMaxBlockY
|
||||
* @param bool $includeBiome
|
||||
* @param bool $includeBiomeTemp
|
||||
*
|
||||
* @return ChunkSnapshot
|
||||
*/
|
||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false);
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function addEntity(Entity $entity);
|
||||
|
||||
/**
|
||||
* @param Entity $entity
|
||||
*/
|
||||
public function removeEntity(Entity $entity);
|
||||
|
||||
/**
|
||||
* @param Tile $tile
|
||||
*/
|
||||
public function addTile(Tile $tile);
|
||||
|
||||
/**
|
||||
* @param Tile $tile
|
||||
*/
|
||||
public function removeTile(Tile $tile);
|
||||
|
||||
/**
|
||||
* @return \pocketmine\entity\Entity[]
|
||||
*/
|
||||
public function getEntities();
|
||||
|
||||
/**
|
||||
* @return \pocketmine\tile\Tile[]
|
||||
*/
|
||||
public function getTiles();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isLoaded();
|
||||
|
||||
/**
|
||||
* Loads the chunk
|
||||
*
|
||||
* @param bool $generate If the chunk does not exist, generate it
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function load($generate = true);
|
||||
|
||||
/**
|
||||
* @param bool $save
|
||||
* @param bool $safe If false, unload the chunk even if players are nearby
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function unload($save = true, $safe = true);
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getBiomeIdArray();
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getBiomeColorArray();
|
||||
|
||||
public function getBlockIdArray();
|
||||
|
||||
public function getBlockDataArray();
|
||||
|
||||
public function getBlockSkyLightArray();
|
||||
|
||||
public function getBlockLightArray();
|
||||
|
||||
}
|
@ -26,6 +26,9 @@ use pocketmine\math\Vector3;
|
||||
|
||||
interface LevelProvider{
|
||||
|
||||
const ORDER_YZX = 0;
|
||||
const ORDER_ZXY = 1;
|
||||
|
||||
/**
|
||||
* @param Level $level
|
||||
* @param string $path
|
||||
@ -39,6 +42,16 @@ interface LevelProvider{
|
||||
*/
|
||||
public static function getProviderName();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function getProviderOrder();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function usesChunkSection();
|
||||
|
||||
/** @return string */
|
||||
public function getPath();
|
||||
|
||||
|
@ -46,6 +46,14 @@ class Anvil extends BaseLevelProvider{
|
||||
return "anvil";
|
||||
}
|
||||
|
||||
public static function getProviderOrder(){
|
||||
return self::ORDER_YZX;
|
||||
}
|
||||
|
||||
public static function usesChunkSection(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function isValid($path){
|
||||
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
|
||||
|
||||
|
@ -24,6 +24,7 @@ namespace pocketmine\level\format\generic;
|
||||
use pocketmine\entity\DroppedItem;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\FullChunk;
|
||||
use pocketmine\level\format\ChunkSection;
|
||||
use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
@ -34,7 +35,7 @@ use pocketmine\tile\Sign;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
abstract class BaseChunk implements Chunk{
|
||||
abstract class BaseChunk extends BaseFullChunk implements Chunk{
|
||||
|
||||
/** @var ChunkSection[] */
|
||||
protected $sections = [];
|
||||
@ -140,21 +141,6 @@ abstract class BaseChunk implements Chunk{
|
||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
||||
}
|
||||
|
||||
public function getX(){
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
public function getZ(){
|
||||
return $this->z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LevelProvider
|
||||
*/
|
||||
public function getLevel(){
|
||||
return $this->level->valid() ? $this->level->get() : null;
|
||||
}
|
||||
|
||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
|
||||
$this->sections[$y >> 4]->getBlock($x, $y & 0x0f, $z, $blockId, $meta);
|
||||
}
|
||||
@ -220,36 +206,36 @@ abstract class BaseChunk implements Chunk{
|
||||
}
|
||||
}
|
||||
|
||||
public function getBiomeId($x, $z){
|
||||
return ord($this->biomeIds{($z << 4) + $x});
|
||||
}
|
||||
|
||||
public function setBiomeId($x, $z, $biomeId){
|
||||
$this->biomeIds{($z << 4) + $x} = chr($biomeId);
|
||||
}
|
||||
|
||||
public function getBiomeColor($x, $z){
|
||||
$color = $this->biomeColors[($z << 4) + $x] & 0xFFFFFF;
|
||||
return [$color >> 16, ($color >> 8) & 0xFF, $color & 0xFF];
|
||||
}
|
||||
|
||||
public function setBiomeColor($x, $z, $R, $G, $B){
|
||||
$this->biomeColors[($z << 4) + $x] = 0 | (($R & 0xFF) << 16) | (($G & 0xFF) << 8) | ($B & 0xFF);
|
||||
}
|
||||
|
||||
public function getHighestBlockAt($x, $z){
|
||||
for($Y = self::SECTION_COUNT - 1; $Y >= 0; --$Y){
|
||||
if(!$this->isSectionEmpty($Y)){
|
||||
$column = $this->sections[$Y]->getBlockIdColumn($x, $z);
|
||||
for($y = 15; $y >= 0; --$y){
|
||||
if($column{$y} !== "\x00"){
|
||||
return $y + ($Y << 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function getBlockIdColumn($x, $z){
|
||||
$column = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$column .= $this->sections[$y]->getBlockIdColumn($x, $z);
|
||||
}
|
||||
return $column;
|
||||
}
|
||||
|
||||
return 0;
|
||||
public function getBlockDataColumn($x, $z){
|
||||
$column = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$column .= $this->sections[$y]->getBlockDataColumn($x, $z);
|
||||
}
|
||||
return $column;
|
||||
}
|
||||
|
||||
public function getBlockSkyLightColumn($x, $z){
|
||||
$column = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$column .= $this->sections[$y]->getBlockSkyLightColumn($x, $z);
|
||||
}
|
||||
return $column;
|
||||
}
|
||||
|
||||
public function getBlockLightColumn($x, $z){
|
||||
$column = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$column .= $this->sections[$y]->getBlockLightColumn($x, $z);
|
||||
}
|
||||
return $column;
|
||||
}
|
||||
|
||||
public function isSectionEmpty($fY){
|
||||
@ -268,54 +254,40 @@ abstract class BaseChunk implements Chunk{
|
||||
}
|
||||
}
|
||||
|
||||
public function addEntity(Entity $entity){
|
||||
$this->entities[$entity->getID()] = $entity;
|
||||
}
|
||||
|
||||
public function removeEntity(Entity $entity){
|
||||
unset($this->entities[$entity->getID()]);
|
||||
}
|
||||
|
||||
public function addTile(Tile $tile){
|
||||
$this->tiles[$tile->getID()] = $tile;
|
||||
}
|
||||
|
||||
public function removeTile(Tile $tile){
|
||||
unset($this->tiles[$tile->getID()]);
|
||||
}
|
||||
|
||||
public function getEntities(){
|
||||
return $this->entities;
|
||||
}
|
||||
|
||||
public function getTiles(){
|
||||
return $this->tiles;
|
||||
}
|
||||
|
||||
public function isLoaded(){
|
||||
return $this->getLevel() === null ? false : $this->getLevel()->isChunkLoaded($this->getX(), $this->getZ());
|
||||
}
|
||||
|
||||
public function load($generate = true){
|
||||
return $this->getLevel() === null ? false : $this->getLevel()->getChunk($this->getX(), $this->getZ(), true) instanceof Chunk;
|
||||
}
|
||||
|
||||
public function unload($save = true, $safe = true){
|
||||
$level = $this->getLevel();
|
||||
if($level === null){
|
||||
return true;
|
||||
public function getBlockIdArray(){
|
||||
$blocks = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$blocks .= $this->sections[$y]->getIdArray();
|
||||
}
|
||||
if($save === true){
|
||||
$level->saveChunk($this->getX(), $this->getZ());
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
public function getBlockDataArray(){
|
||||
$data = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$data .= $this->sections[$y]->getDataArray();
|
||||
}
|
||||
if($this->getLevel()->unloadChunk($this->getX(), $this->getZ(), $safe)){
|
||||
foreach($this->getEntities() as $entity){
|
||||
$entity->close();
|
||||
}
|
||||
foreach($this->getTiles() as $tile){
|
||||
$tile->close();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getBlockSkyLightArray(){
|
||||
$skyLight = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$skyLight .= $this->sections[$y]->getSkyLightArray();
|
||||
}
|
||||
return $skyLight;
|
||||
}
|
||||
|
||||
public function getBlockLightArray(){
|
||||
$blockLight = "";
|
||||
for($y = 0; $y < Chunk::SECTION_COUNT; ++$y){
|
||||
$blockLight .= $this->sections[$y]->getLightArray();
|
||||
}
|
||||
return $blockLight;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,12 +297,4 @@ abstract class BaseChunk implements Chunk{
|
||||
return $this->sections;
|
||||
}
|
||||
|
||||
public function getBiomeIdArray(){
|
||||
return $this->biomeIds;
|
||||
}
|
||||
|
||||
public function getBiomeColorArray(){
|
||||
return $this->biomeColors;
|
||||
}
|
||||
|
||||
}
|
260
src/pocketmine/level/format/generic/BaseFullChunk.php
Normal file
260
src/pocketmine/level/format/generic/BaseFullChunk.php
Normal file
@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\level\format\generic;
|
||||
|
||||
use pocketmine\entity\DroppedItem;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\level\format\FullChunk;
|
||||
use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\tile\Chest;
|
||||
use pocketmine\tile\Furnace;
|
||||
use pocketmine\tile\Sign;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
abstract class BaseFullChunk implements FullChunk{
|
||||
|
||||
/** @var Entity[] */
|
||||
protected $entities = [];
|
||||
|
||||
/** @var Tile[] */
|
||||
protected $tiles = [];
|
||||
|
||||
/** @var string */
|
||||
protected $biomeIds;
|
||||
|
||||
/** @var int[256] */
|
||||
protected $biomeColors;
|
||||
|
||||
protected $blocks;
|
||||
|
||||
protected $data;
|
||||
|
||||
protected $skyLight;
|
||||
|
||||
protected $blockLight;
|
||||
|
||||
/** @var \WeakRef<LevelProvider> */
|
||||
protected $level;
|
||||
|
||||
protected $x;
|
||||
protected $z;
|
||||
|
||||
/**
|
||||
* @param LevelProvider $level
|
||||
* @param int $x
|
||||
* @param int $z
|
||||
* @param string $blocks
|
||||
* @param string $data
|
||||
* @param string $skyLight
|
||||
* @param string $blockLight
|
||||
* @param string $biomeIds
|
||||
* @param int[] $biomeColors
|
||||
* @param Compound[] $entities
|
||||
* @param Compound[] $tiles
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function __construct(LevelProvider $level, $x, $z, $blocks, $data, $skyLight, $blockLight, $biomeIds = null, array $biomeColors = [], array $entities = [], array $tiles = []){
|
||||
$this->level = new \WeakRef($level);
|
||||
$this->x = (int) $x;
|
||||
$this->z = (int) $z;
|
||||
|
||||
$this->blocks = $blocks;
|
||||
$this->data = $data;
|
||||
$this->skyLight = $skyLight;
|
||||
$this->blockLight = $blockLight;
|
||||
|
||||
if(strlen($biomeIds) === 256){
|
||||
$this->biomeIds = $biomeIds;
|
||||
}else{
|
||||
$this->biomeIds = str_repeat("\x01", 256);
|
||||
}
|
||||
|
||||
if(count($biomeColors) === 256){
|
||||
$this->biomeColors = $biomeColors;
|
||||
}else{
|
||||
$this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a"));
|
||||
}
|
||||
|
||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming();
|
||||
foreach($entities as $nbt){
|
||||
if($nbt instanceof Compound){
|
||||
if(!isset($nbt->id)){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($nbt->id instanceof String){ //New format
|
||||
switch($nbt["id"]){
|
||||
case "Item":
|
||||
(new DroppedItem($this, $nbt))->spawnToAll();
|
||||
break;
|
||||
}
|
||||
}else{ //Old format
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming();
|
||||
|
||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming();
|
||||
foreach($tiles as $nbt){
|
||||
if($nbt instanceof Compound){
|
||||
if(!isset($nbt->id)){
|
||||
continue;
|
||||
}
|
||||
switch($nbt["id"]){
|
||||
case Tile::CHEST:
|
||||
new Chest($this, $nbt);
|
||||
break;
|
||||
case Tile::FURNACE:
|
||||
new Furnace($this, $nbt);
|
||||
break;
|
||||
case Tile::SIGN:
|
||||
new Sign($this, $nbt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming();
|
||||
}
|
||||
|
||||
public function getX(){
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
public function getZ(){
|
||||
return $this->z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LevelProvider
|
||||
*/
|
||||
public function getLevel(){
|
||||
return $this->level->valid() ? $this->level->get() : null;
|
||||
}
|
||||
|
||||
public function getBiomeId($x, $z){
|
||||
return ord($this->biomeIds{($z << 4) + $x});
|
||||
}
|
||||
|
||||
public function setBiomeId($x, $z, $biomeId){
|
||||
$this->biomeIds{($z << 4) + $x} = chr($biomeId);
|
||||
}
|
||||
|
||||
public function getBiomeColor($x, $z){
|
||||
$color = $this->biomeColors[($z << 4) + $x] & 0xFFFFFF;
|
||||
return [$color >> 16, ($color >> 8) & 0xFF, $color & 0xFF];
|
||||
}
|
||||
|
||||
public function setBiomeColor($x, $z, $R, $G, $B){
|
||||
$this->biomeColors[($z << 4) + $x] = 0 | (($R & 0xFF) << 16) | (($G & 0xFF) << 8) | ($B & 0xFF);
|
||||
}
|
||||
|
||||
public function getHighestBlockAt($x, $z){
|
||||
$column = $this->getBlockIdColumn($x, $z);
|
||||
for($y = 127; $y >= 0; --$y){
|
||||
if($column{$y} !== "\x00"){
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function addEntity(Entity $entity){
|
||||
$this->entities[$entity->getID()] = $entity;
|
||||
}
|
||||
|
||||
public function removeEntity(Entity $entity){
|
||||
unset($this->entities[$entity->getID()]);
|
||||
}
|
||||
|
||||
public function addTile(Tile $tile){
|
||||
$this->tiles[$tile->getID()] = $tile;
|
||||
}
|
||||
|
||||
public function removeTile(Tile $tile){
|
||||
unset($this->tiles[$tile->getID()]);
|
||||
}
|
||||
|
||||
public function getEntities(){
|
||||
return $this->entities;
|
||||
}
|
||||
|
||||
public function getTiles(){
|
||||
return $this->tiles;
|
||||
}
|
||||
|
||||
public function isLoaded(){
|
||||
return $this->getLevel() === null ? false : $this->getLevel()->isChunkLoaded($this->getX(), $this->getZ());
|
||||
}
|
||||
|
||||
public function load($generate = true){
|
||||
return $this->getLevel() === null ? false : $this->getLevel()->getChunk($this->getX(), $this->getZ(), true) instanceof FullChunk;
|
||||
}
|
||||
|
||||
public function unload($save = true, $safe = true){
|
||||
$level = $this->getLevel();
|
||||
if($level === null){
|
||||
return true;
|
||||
}
|
||||
if($save === true){
|
||||
$level->saveChunk($this->getX(), $this->getZ());
|
||||
}
|
||||
if($this->getLevel()->unloadChunk($this->getX(), $this->getZ(), $safe)){
|
||||
foreach($this->getEntities() as $entity){
|
||||
$entity->close();
|
||||
}
|
||||
foreach($this->getTiles() as $tile){
|
||||
$tile->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockIdArray(){
|
||||
return $this->blocks;
|
||||
}
|
||||
|
||||
public function getBlockDataArray(){
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getBlockSkyLightArray(){
|
||||
return $this->skyLight;
|
||||
}
|
||||
|
||||
public function getBlockLightArray(){
|
||||
return $this->blockLight;
|
||||
}
|
||||
|
||||
public function getBiomeIdArray(){
|
||||
return $this->biomeIds;
|
||||
}
|
||||
|
||||
public function getBiomeColorArray(){
|
||||
return $this->biomeColors;
|
||||
}
|
||||
|
||||
}
|
@ -21,8 +21,7 @@
|
||||
|
||||
namespace pocketmine\level\format\mcregion;
|
||||
|
||||
use pocketmine\level\format\generic\BaseChunk;
|
||||
use pocketmine\level\format\generic\EmptyChunkSection;
|
||||
use pocketmine\level\format\generic\BaseFullChunk;
|
||||
use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
@ -32,7 +31,7 @@ use pocketmine\nbt\tag\Enum;
|
||||
use pocketmine\nbt\tag\IntArray;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
class Chunk extends BaseChunk{
|
||||
class Chunk extends BaseFullChunk{
|
||||
|
||||
/** @var Compound */
|
||||
protected $nbt;
|
||||
@ -69,37 +68,131 @@ class Chunk extends BaseChunk{
|
||||
$this->nbt->BiomeColors = new IntArray("BiomeColors", array_fill(0, 156, Binary::readInt("\x00\x85\xb2\x4a")));
|
||||
}
|
||||
|
||||
/** @var ChunkSection[] $sections */
|
||||
$sections = [];
|
||||
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt["Blocks"], $this->nbt["Data"], $this->nbt["SkyLight"], $this->nbt["BLockLight"], $this->nbt->Biomes->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
|
||||
}
|
||||
|
||||
$blockLight = $skyLight = $datas = $blocks = [$fill = array_fill(0, 256, ""), $fill, $fill, $fill, $fill, $fill, $fill, $fill];
|
||||
public function getBlockId($x, $y, $z){
|
||||
return ord($this->blocks{($z << 11) + ($x << 7) + $y});
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
for($i = 0; $i < 256; ++$i){
|
||||
list($blocks[0][$i], $blocks[1][$i], $blocks[2][$i], $blocks[3][$i], $blocks[4][$i], $blocks[5][$i], $blocks[6][$i], $blocks[7][$i]) = str_split(substr($this->nbt["Blocks"], $offset << 1, 128), 16);
|
||||
list($datas[0][$i], $datas[1][$i], $datas[2][$i], $datas[3][$i], $datas[4][$i], $datas[5][$i], $datas[6][$i], $datas[7][$i]) = str_split(substr($this->nbt["Data"], $offset, 64), 8);
|
||||
list($skyLight[0][$i], $skyLight[1][$i], $skyLight[2][$i], $skyLight[3][$i], $skyLight[4][$i], $skyLight[5][$i], $skyLight[6][$i], $skyLight[7][$i]) = str_split(substr($this->nbt["SkyLight"], $offset, 64), 8);
|
||||
list($blockLight[0][$i], $blockLight[1][$i], $blockLight[2][$i], $blockLight[3][$i], $blockLight[4][$i], $blockLight[5][$i], $blockLight[6][$i], $blockLight[7][$i]) = str_split(substr($this->nbt["BlockLight"], $offset, 64), 8);
|
||||
$offset += 64;
|
||||
public function setBlockId($x, $y, $z, $id){
|
||||
$this->blocks{($z << 11) + ($x << 7) + $y} = chr($id);
|
||||
}
|
||||
|
||||
public function getBlockData($x, $y, $z){
|
||||
$m = ord($this->data{($z << 10) + ($x << 6) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $m >> 4;
|
||||
}else{
|
||||
return $m & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
for($Y = 0; $Y < 8; ++$Y){
|
||||
$sections[$Y] = new ChunkSection(
|
||||
$Y,
|
||||
implode($blocks[$Y]),
|
||||
implode($datas[$Y]),
|
||||
implode($skyLight[$Y]),
|
||||
implode($blockLight[$Y])
|
||||
);
|
||||
public function setBlockData($x, $y, $z, $data){
|
||||
$i = ($z << 10) + ($x << 6) + ($y >> 1);
|
||||
$old_m = ord($this->data{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
|
||||
}else{
|
||||
$this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
for($y = 0; $y < 8; ++$y){
|
||||
if(substr_count($sections[$y]->getIdArray(), "\x00") === 4096){
|
||||
$sections[$y] = new EmptyChunkSection($y);
|
||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
|
||||
$i = ($z << 11) + ($x << 7) + $y;
|
||||
$blockId = ord($this->blocks{$i});
|
||||
$m = ord($this->data{$i >> 1});
|
||||
if(($y & 1) === 0){
|
||||
$meta = $m >> 4;
|
||||
}else{
|
||||
$meta = $m & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlock($x, $y, $z, $blockId = null, $meta = null){
|
||||
$i = ($z << 11) + ($x << 7) + $y;
|
||||
|
||||
$changed = false;
|
||||
|
||||
if($blockId !== null){
|
||||
$blockId = chr($blockId);
|
||||
if($this->blocks{$i} !== $blockId){
|
||||
$this->blocks{$i} = $blockId;
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $sections, $this->nbt->Biomes->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
|
||||
if($meta !== null){
|
||||
$i >>= 1;
|
||||
$old_m = ord($this->data{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f));
|
||||
if((($old_m & 0xf0) >> 4) !== $meta){
|
||||
$changed = true;
|
||||
}
|
||||
}else{
|
||||
$this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f));
|
||||
if(($old_m & 0x0f) !== $meta){
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $changed;
|
||||
}
|
||||
|
||||
public function getBlockSkyLight($x, $y, $z){
|
||||
$sl = ord($this->skyLight{($z << 10) + ($x << 6) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $sl >> 4;
|
||||
}else{
|
||||
return $sl & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlockSkyLight($x, $y, $z, $level){
|
||||
$i = ($z << 10) + ($x << 6) + ($y >> 1);
|
||||
$old_sl = ord($this->skyLight{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f));
|
||||
}else{
|
||||
$this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockLight($x, $y, $z){
|
||||
$l = ord($this->blockLight{($z << 10) + ($x << 6) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $l >> 4;
|
||||
}else{
|
||||
return $l & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlockLight($x, $y, $z, $level){
|
||||
$i = ($z << 10) + ($x << 6) + ($y >> 1);
|
||||
$old_l = ord($this->blockLight{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f));
|
||||
}else{
|
||||
$this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockIdColumn($x, $z){
|
||||
return substr($this->blocks, ($z << 11) + ($x << 7), 128);
|
||||
}
|
||||
|
||||
public function getBlockDataColumn($x, $z){
|
||||
return substr($this->data, ($z << 10) + ($x << 6), 64);
|
||||
}
|
||||
|
||||
public function getBlockSkyLightColumn($x, $z){
|
||||
return substr($this->skyLight, ($z << 10) + ($x << 6), 64);
|
||||
}
|
||||
|
||||
public function getBlockLightColumn($x, $z){
|
||||
return substr($this->blockLight, ($z << 10) + ($x << 6), 64);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,34 +210,12 @@ class Chunk extends BaseChunk{
|
||||
}
|
||||
|
||||
public function getChunkSnapshot($includeMaxBlockY = true, $includeBiome = false, $includeBiomeTemp = false){
|
||||
$blockId = "";
|
||||
$blockData = "";
|
||||
$blockSkyLight = "";
|
||||
$blockLight = "";
|
||||
$emptySections = [false, false, false, false, false, false, false, false];
|
||||
|
||||
$emptyBlocks = str_repeat("\x00", 4096);
|
||||
$emptyHalf = str_repeat("\x00", 2048);
|
||||
|
||||
foreach($this->sections as $i => $section){
|
||||
if($section instanceof EmptyChunkSection){
|
||||
$blockId .= $emptyBlocks;
|
||||
$blockData .= $emptyHalf;
|
||||
$blockSkyLight .= $emptyHalf;
|
||||
$blockLight .= $emptyHalf;
|
||||
$emptySections[$i] = true;
|
||||
}else{
|
||||
$blockId .= $section->getIdArray();
|
||||
$blockData .= $section->getDataArray();
|
||||
$blockSkyLight .= $section->getSkyLightArray();
|
||||
$blockLight .= $section->getLightArray();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: maxBlockY, biomeMap, biomeTemp
|
||||
|
||||
//TODO: time
|
||||
return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0 /*$this->getLevel()->getTime()*/, $blockId, $blockData, $blockSkyLight, $blockLight, $emptySections, null, null, null, null);
|
||||
return new ChunkSnapshot($this->getX(), $this->getZ(), $this->getLevel()->getName(), 0 /*$this->getLevel()->getTime()*/, $this->getBlockIdArray(), $this->getBlockDataArray(), $this->getBlockSkyLightArray(), $this->getBlockLightArray(), $emptySections, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\level\format\mcregion;
|
||||
|
||||
class ChunkSection implements \pocketmine\level\format\ChunkSection{
|
||||
|
||||
private $y;
|
||||
private $blocks;
|
||||
private $data;
|
||||
private $blockLight;
|
||||
private $skyLight;
|
||||
|
||||
public function __construct($y, $blocks, $data, $blockLight, $skyLight){
|
||||
$this->y = $y;
|
||||
$this->blocks = $blocks;
|
||||
$this->data = $data;
|
||||
$this->blockLight = $blockLight;
|
||||
$this->skyLight = $skyLight;
|
||||
}
|
||||
|
||||
public function getY(){
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
public function getBlockId($x, $y, $z){
|
||||
return ord($this->blocks{($z << 8) + ($x << 4) + $y});
|
||||
}
|
||||
|
||||
public function setBlockId($x, $y, $z, $id){
|
||||
$this->blocks{($z << 8) + ($x << 4) + $y} = chr($id);
|
||||
}
|
||||
|
||||
public function getBlockData($x, $y, $z){
|
||||
$m = ord($this->data{($z << 7) + ($x << 3) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $m >> 4;
|
||||
}else{
|
||||
return $m & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlockData($x, $y, $z, $data){
|
||||
$i = ($z << 7) + ($x << 3) + ($y >> 1);
|
||||
$old_m = ord($this->data{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
|
||||
}else{
|
||||
$this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
|
||||
$i = ($z << 8) + ($x << 4) + $y;
|
||||
$blockId = ord($this->blocks{$i});
|
||||
$m = ord($this->data{$i >> 1});
|
||||
if(($y & 1) === 0){
|
||||
$meta = $m >> 4;
|
||||
}else{
|
||||
$meta = $m & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlock($x, $y, $z, $blockId = null, $meta = null){
|
||||
$i = ($z << 8) + ($x << 4) + $y;
|
||||
|
||||
$changed = false;
|
||||
|
||||
if($blockId !== null){
|
||||
$blockId = chr($blockId);
|
||||
if($this->blocks{$i} !== $blockId){
|
||||
$this->blocks{$i} = $blockId;
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($meta !== null){
|
||||
$i >>= 1;
|
||||
$old_m = ord($this->data{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f));
|
||||
if((($old_m & 0xf0) >> 4) !== $meta){
|
||||
$changed = true;
|
||||
}
|
||||
}else{
|
||||
$this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f));
|
||||
if(($old_m & 0x0f) !== $meta){
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $changed;
|
||||
}
|
||||
|
||||
public function getBlockSkyLight($x, $y, $z){
|
||||
$sl = ord($this->skyLight{($z << 7) + ($x << 3) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $sl >> 4;
|
||||
}else{
|
||||
return $sl & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlockSkyLight($x, $y, $z, $level){
|
||||
$i = ($z << 7) + ($x << 3) + ($y >> 1);
|
||||
$old_sl = ord($this->skyLight{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f));
|
||||
}else{
|
||||
$this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockLight($x, $y, $z){
|
||||
$l = ord($this->blockLight{($z << 7) + ($x << 3) + ($y >> 1)});
|
||||
if(($y & 1) === 0){
|
||||
return $l >> 4;
|
||||
}else{
|
||||
return $l & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
public function setBlockLight($x, $y, $z, $level){
|
||||
$i = ($z << 7) + ($x << 3) + ($y >> 1);
|
||||
$old_l = ord($this->blockLight{$i});
|
||||
if(($y & 1) === 0){
|
||||
$this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f));
|
||||
}else{
|
||||
$this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockIdColumn($x, $z){
|
||||
return substr($this->blocks, ($z << 8) + ($x << 4), 16);
|
||||
}
|
||||
|
||||
public function getBlockDataColumn($x, $z){
|
||||
return substr($this->data, ($z << 7) + ($x << 3), 8);
|
||||
}
|
||||
|
||||
public function getBlockSkyLightColumn($x, $z){
|
||||
return substr($this->skyLight, ($z << 7) + ($x << 3), 8);
|
||||
}
|
||||
|
||||
public function getBlockLightColumn($x, $z){
|
||||
return substr($this->blockLight, ($z << 7) + ($x << 3), 8);
|
||||
}
|
||||
|
||||
public function getIdArray(){
|
||||
return $this->blocks;
|
||||
}
|
||||
|
||||
public function getDataArray(){
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getSkyLightArray(){
|
||||
return $this->skyLight;
|
||||
}
|
||||
|
||||
public function getLightArray(){
|
||||
return $this->blockLight;
|
||||
}
|
||||
|
||||
}
|
@ -45,6 +45,14 @@ class McRegion extends BaseLevelProvider{
|
||||
return "mcregion";
|
||||
}
|
||||
|
||||
public static function getProviderOrder(){
|
||||
return self::ORDER_ZXY;
|
||||
}
|
||||
|
||||
public static function usesChunkSection(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function isValid($path){
|
||||
$isValid = (file_exists($path . "/level.dat") and is_dir($path . "/region/"));
|
||||
|
||||
|
@ -187,32 +187,12 @@ class RegionLoader{
|
||||
}
|
||||
|
||||
public function writeChunk(Chunk $chunk){
|
||||
//TODO
|
||||
$nbt = $chunk->getNBT();
|
||||
$nbt->Sections = new Enum("Sections", []);
|
||||
$nbt->Sections->setTagType(NBT::TAG_Compound);
|
||||
|
||||
$blocks = "";
|
||||
$data = "";
|
||||
$skyLight = "";
|
||||
$blockLight = "";
|
||||
$sections = $chunk->getSections();
|
||||
|
||||
for($i = 0; $i < 256; ++$i){
|
||||
$x = $i & 0x0F;
|
||||
$z = $i >> 4;
|
||||
for($s = 0; $s < 0; ++$s){
|
||||
$blocks .= $sections[$s]->getBlockIdColumn($x, $z);
|
||||
$data .= $sections[$s]->getBlockDataColumn($x, $z);
|
||||
$skyLight .= $sections[$s]->getBlockSkyLightColumn($x, $z);
|
||||
$blockLight .= $sections[$s]->getBlockLightColumn($x, $z);
|
||||
}
|
||||
}
|
||||
|
||||
$nbt->Blocks = new ByteArray("Blocks", $blocks);
|
||||
$nbt->Data = new ByteArray("Data", $data);
|
||||
$nbt->SkyLight = new ByteArray("SkyLight", $skyLight);
|
||||
$nbt->BlockLight = new ByteArray("BlockLight", $blockLight);
|
||||
$nbt->Blocks = new ByteArray("Blocks", $chunk->getBlockIdArray());
|
||||
$nbt->Data = new ByteArray("Data", $chunk->getBlockDataArray());
|
||||
$nbt->SkyLight = new ByteArray("SkyLight", $chunk->getBlockSkyLightArray());
|
||||
$nbt->BlockLight = new ByteArray("BlockLight", $chunk->getBlockLightArray());
|
||||
|
||||
$nbt->Biomes = new ByteArray("Biomes", $chunk->getBiomeIdArray());
|
||||
$nbt->BiomeColors = new IntArray("BiomeColors", $chunk->getBiomeColorArray());
|
||||
|
Loading…
x
Reference in New Issue
Block a user