mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 17:59:48 +00:00
Added support for extra data, improved BinaryStream
This commit is contained in:
@ -90,6 +90,7 @@ use pocketmine\nbt\tag\String;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\protocol\FullChunkDataPacket;
|
||||
use pocketmine\network\protocol\LevelEventPacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\network\protocol\SetTimePacket;
|
||||
@ -280,6 +281,10 @@ class Level implements ChunkManager, Metadatable{
|
||||
return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFF) << 35) | (($y & 0x7f) << 28) | ($z & 0xFFFFFFF) : $x . ":" . $y .":". $z;
|
||||
}
|
||||
|
||||
public static function chunkBlockHash($x, $y, $z){
|
||||
return ($x << 11) | ($z << 7) | $y;
|
||||
}
|
||||
|
||||
public static function getBlockXYZ($hash, &$x, &$y, &$z){
|
||||
if(PHP_INT_SIZE === 8){
|
||||
$x = ($hash >> 35) << 36 >> 36;
|
||||
@ -798,6 +803,17 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
}
|
||||
|
||||
public function sendBlockExtraData($x, $y, $z, $id, $data, array $targets = null){
|
||||
$pk = new LevelEventPacket;
|
||||
$pk->evid = LevelEventPacket::EVENT_SET_DATA;
|
||||
$pk->x = $x + 0.5;
|
||||
$pk->y = $y + 0.5;
|
||||
$pk->z = $z + 0.5;
|
||||
$pk->data = ($data << 8) | $id;
|
||||
|
||||
Server::broadcastPacket($targets === null ? $this->getChunkPlayers($x >> 4, $z >> 4) : $targets, $pk->setChannel(Network::CHANNEL_WORLD_EVENTS));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Player[] $target
|
||||
* @param Block[] $blocks
|
||||
@ -1920,6 +1936,34 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw block extra data
|
||||
*
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
*
|
||||
* @return int 16-bit
|
||||
*/
|
||||
public function getBlockExtraDataAt($x, $y, $z){
|
||||
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockExtraData($x & 0x0f, $y & 0x7f, $z & 0x0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the raw block metadata.
|
||||
*
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $z
|
||||
* @param int $id
|
||||
* @param int $data
|
||||
*/
|
||||
public function setBlockExtraDataAt($x, $y, $z, $id, $data){
|
||||
$this->getChunk($x >> 4, $z >> 4, true)->setBlockExtraData($x & 0x0f, $y & 0x7f, $z & 0x0f, ($data << 8) | $id);
|
||||
|
||||
$this->sendBlockExtraData($x, $y, $z, $id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw block metadata
|
||||
*
|
||||
|
@ -119,6 +119,23 @@ interface FullChunk{
|
||||
*/
|
||||
public function setBlockData($x, $y, $z, $data);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int (16-bit)
|
||||
*/
|
||||
public function getBlockExtraData($x, $y, $z);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
* @param int $z 0-15
|
||||
* @param int $data (16-bit)
|
||||
*/
|
||||
public function setBlockExtraData($x, $y, $z, $data);
|
||||
|
||||
/**
|
||||
* @param int $x 0-15
|
||||
* @param int $y 0-127
|
||||
@ -312,6 +329,8 @@ interface FullChunk{
|
||||
|
||||
public function getBlockDataArray();
|
||||
|
||||
public function getBlockExtraDataArray();
|
||||
|
||||
public function getBlockSkyLightArray();
|
||||
|
||||
public function getBlockLightArray();
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\nbt\tag\ByteArray;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\network\protocol\FullChunkDataPacket;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ChunkException;
|
||||
use raklib\Binary;
|
||||
|
||||
@ -89,14 +90,20 @@ class Anvil extends McRegion{
|
||||
$tiles = $nbt->write();
|
||||
}
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putLInt(count($chunk->getBlockExtraDataArray()));
|
||||
foreach($chunk->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putLInt($key);
|
||||
$extraData->putLShort($value);
|
||||
}
|
||||
|
||||
$ordered = $chunk->getBlockIdArray() .
|
||||
$chunk->getBlockDataArray() .
|
||||
$chunk->getBlockSkyLightArray() .
|
||||
$chunk->getBlockLightArray() .
|
||||
pack("C*", ...$chunk->getHeightMapArray()) .
|
||||
pack("N*", ...$chunk->getBiomeColorArray()) .
|
||||
//TODO extra data
|
||||
Binary::writeInt(0) .
|
||||
$extraData->getBuffer() .
|
||||
$tiles;
|
||||
|
||||
$this->getLevel()->chunkRequestCallback($x, $z, $ordered, FullChunkDataPacket::ORDER_LAYERED);
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\nbt\tag\IntArray;
|
||||
use pocketmine\nbt\tag\Long;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
|
||||
class Chunk extends BaseChunk{
|
||||
|
||||
@ -92,14 +93,27 @@ class Chunk extends BaseChunk{
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
|
||||
$extraData = [];
|
||||
|
||||
if(!isset($this->nbt->ExtraData) or !($this->nbt->ExtraData instanceof ByteArray)){
|
||||
$this->nbt->ExtraData = new ByteArray("ExtraData", Binary::writeInt(0));
|
||||
}else{
|
||||
$stream = new BinaryStream($this->nbt->ExtraData->getValue());
|
||||
$count = $stream->getInt();
|
||||
for($i = 0; $i < $count; ++$i){
|
||||
$key = $stream->getInt();
|
||||
$extraData[$key] = $stream->getShort(false);
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue(), $extraData);
|
||||
|
||||
if(isset($this->nbt->Biomes)){
|
||||
$this->checkOldBiomes($this->nbt->Biomes->getValue());
|
||||
unset($this->nbt->Biomes);
|
||||
}
|
||||
|
||||
unset($this->nbt->Sections);
|
||||
unset($this->nbt->Sections, $this->nbt->ExtraData);
|
||||
}
|
||||
|
||||
public function isLightPopulated(){
|
||||
@ -240,6 +254,16 @@ class Chunk extends BaseChunk{
|
||||
|
||||
$nbt->TileEntities = new Enum("TileEntities", $tiles);
|
||||
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putInt(count($this->getBlockExtraDataArray()));
|
||||
foreach($this->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putInt($key);
|
||||
$extraData->putShort($value);
|
||||
}
|
||||
|
||||
$nbt->ExtraData = new ByteArray("ExtraData", $extraData->getBuffer());
|
||||
|
||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->setName("Level");
|
||||
$writer->setData(new Compound("", ["Level" => $nbt]));
|
||||
@ -293,6 +317,16 @@ class Chunk extends BaseChunk{
|
||||
|
||||
$nbt->TileEntities = new Enum("TileEntities", $tiles);
|
||||
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putInt(count($this->getBlockExtraDataArray()));
|
||||
foreach($this->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putInt($key);
|
||||
$extraData->putShort($value);
|
||||
}
|
||||
|
||||
$nbt->ExtraData = new ByteArray("ExtraData", $extraData->getBuffer());
|
||||
|
||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->setName("Level");
|
||||
$writer->setData(new Compound("", ["Level" => $nbt]));
|
||||
|
@ -26,6 +26,7 @@ use pocketmine\entity\Entity;
|
||||
use pocketmine\level\format\FullChunk;
|
||||
use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\level\generator\biome\Biome;
|
||||
use pocketmine\level\Level;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\tile\Tile;
|
||||
@ -59,6 +60,8 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
|
||||
protected $NBTentities;
|
||||
|
||||
protected $extraData = [];
|
||||
|
||||
/** @var LevelProvider */
|
||||
protected $provider;
|
||||
|
||||
@ -82,7 +85,7 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
* @param Compound[] $entities
|
||||
* @param Compound[] $tiles
|
||||
*/
|
||||
protected function __construct($provider, $x, $z, $blocks, $data, $skyLight, $blockLight, array $biomeColors = [], array $heightMap = [], array $entities = [], array $tiles = []){
|
||||
protected function __construct($provider, $x, $z, $blocks, $data, $skyLight, $blockLight, array $biomeColors = [], array $heightMap = [], array $entities = [], array $tiles = [], array $extraData = []){
|
||||
$this->provider = $provider;
|
||||
$this->x = (int) $x;
|
||||
$this->z = (int) $z;
|
||||
@ -95,7 +98,7 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
if(count($biomeColors) === 256){
|
||||
$this->biomeColors = $biomeColors;
|
||||
}else{
|
||||
$this->biomeColors = array_fill(0, 256, Binary::readInt("\xff\x00\x00\x00\x00"));
|
||||
$this->biomeColors = array_fill(0, 256, 0);
|
||||
}
|
||||
|
||||
if(count($heightMap) === 256){
|
||||
@ -104,6 +107,8 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
$this->heightMap = array_fill(0, 256, 127);
|
||||
}
|
||||
|
||||
$this->extraData = $extraData;
|
||||
|
||||
$this->NBTtiles = $tiles;
|
||||
$this->NBTentities = $entities;
|
||||
}
|
||||
@ -254,6 +259,24 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockExtraData($x, $y, $z){
|
||||
if(isset($this->extraData[$index = Level::chunkBlockHash($x, $y, $z)])){
|
||||
return $this->extraData[$index];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function setBlockExtraData($x, $y, $z, $data){
|
||||
if($data === 0){
|
||||
unset($this->extraData[Level::chunkBlockHash($x, $y, $z)]);
|
||||
}else{
|
||||
$this->extraData[Level::chunkBlockHash($x, $y, $z)] = $data;
|
||||
}
|
||||
|
||||
$this->setChanged(true);
|
||||
}
|
||||
|
||||
public function populateSkyLight(){
|
||||
for($z = 0; $z < 16; ++$z){
|
||||
for($x = 0; $x < 16; ++$x){
|
||||
@ -336,6 +359,10 @@ abstract class BaseFullChunk implements FullChunk{
|
||||
return $this->tiles;
|
||||
}
|
||||
|
||||
public function getBlockExtraDataArray(){
|
||||
return $this->extraData;
|
||||
}
|
||||
|
||||
public function getTile($x, $y, $z){
|
||||
$index = ($z << 12) | ($x << 8) | $y;
|
||||
return isset($this->tileList[$index]) ? $this->tileList[$index] : null;
|
||||
|
@ -26,6 +26,7 @@ use pocketmine\level\format\LevelProvider;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
|
||||
class Chunk extends BaseFullChunk{
|
||||
|
||||
@ -260,6 +261,7 @@ class Chunk extends BaseFullChunk{
|
||||
|
||||
$entities = null;
|
||||
$tiles = null;
|
||||
$extraData = [];
|
||||
|
||||
if($provider instanceof LevelDB){
|
||||
$nbt = new NBT(NBT::LITTLE_ENDIAN);
|
||||
@ -280,6 +282,16 @@ class Chunk extends BaseFullChunk{
|
||||
$tiles = [$tiles];
|
||||
}
|
||||
}
|
||||
$tileData = $provider->getDatabase()->get(substr($data, 0, 8) . LevelDB::ENTRY_EXTRA_DATA);
|
||||
if($tileData !== false and strlen($tileData) > 0){
|
||||
$stream = new BinaryStream($tileData);
|
||||
$count = $stream->getInt();
|
||||
for($i = 0; $i < $count; ++$i){
|
||||
$key = $stream->getInt();
|
||||
$value = $stream->getShort(false);
|
||||
$extraData[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$chunk = new Chunk($provider instanceof LevelProvider ? $provider : LevelDB::class, $chunkX, $chunkZ, $chunkData, $entities, $tiles);
|
||||
@ -341,6 +353,17 @@ class Chunk extends BaseFullChunk{
|
||||
$provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_TILES);
|
||||
}
|
||||
|
||||
if(count($this->getBlockExtraDataArray()) > 0){
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putInt(count($this->getBlockExtraDataArray()));
|
||||
foreach($this->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putInt($key);
|
||||
$extraData->putShort($value);
|
||||
}
|
||||
$provider->getDatabase()->put($chunkIndex . LevelDB::ENTRY_EXTRA_DATA, $extraData->getBuffer());
|
||||
}else{
|
||||
$provider->getDatabase()->delete($chunkIndex . LevelDB::ENTRY_EXTRA_DATA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\nbt\tag\Long;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ChunkException;
|
||||
use pocketmine\utils\LevelException;
|
||||
|
||||
@ -40,6 +41,7 @@ class LevelDB extends BaseLevelProvider{
|
||||
|
||||
const ENTRY_VERSION = "v";
|
||||
const ENTRY_FLAGS = "f";
|
||||
const ENTRY_EXTRA_DATA = "4";
|
||||
const ENTRY_TICKS = "3";
|
||||
const ENTRY_ENTITIES = "2";
|
||||
const ENTRY_TILES = "1";
|
||||
@ -156,14 +158,20 @@ class LevelDB extends BaseLevelProvider{
|
||||
$heightmap = pack("C*", ...$chunk->getHeightMapArray());
|
||||
$biomeColors = pack("N*", ...$chunk->getBiomeColorArray());
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putLInt(count($chunk->getBlockExtraDataArray()));
|
||||
foreach($chunk->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putLInt($key);
|
||||
$extraData->putLShort($value);
|
||||
}
|
||||
|
||||
$ordered = $chunk->getBlockIdArray() .
|
||||
$chunk->getBlockDataArray() .
|
||||
$chunk->getBlockSkyLightArray() .
|
||||
$chunk->getBlockLightArray() .
|
||||
$heightmap .
|
||||
$biomeColors .
|
||||
//TODO extra data
|
||||
Binary::writeInt(0) .
|
||||
$extraData->getBuffer() .
|
||||
$tiles;
|
||||
|
||||
$this->getLevel()->chunkRequestCallback($x, $z, $ordered);
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\nbt\tag\IntArray;
|
||||
use pocketmine\nbt\tag\Long;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
|
||||
class Chunk extends BaseFullChunk{
|
||||
|
||||
@ -87,7 +88,20 @@ class Chunk extends BaseFullChunk{
|
||||
$this->nbt->BlockLight = new ByteArray("BlockLight", $half);
|
||||
}
|
||||
|
||||
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt->Blocks->getValue(), $this->nbt->Data->getValue(), $this->nbt->SkyLight->getValue(), $this->nbt->BlockLight->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue());
|
||||
$extraData = [];
|
||||
|
||||
if(!isset($this->nbt->ExtraData) or !($this->nbt->ExtraData instanceof ByteArray)){
|
||||
$this->nbt->ExtraData = new ByteArray("ExtraData", Binary::writeInt(0));
|
||||
}else{
|
||||
$stream = new BinaryStream($this->nbt->ExtraData->getValue());
|
||||
$count = $stream->getInt();
|
||||
for($i = 0; $i < $count; ++$i){
|
||||
$key = $stream->getInt();
|
||||
$extraData[$key] = $stream->getShort(false);
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $this->nbt->Blocks->getValue(), $this->nbt->Data->getValue(), $this->nbt->SkyLight->getValue(), $this->nbt->BlockLight->getValue(), $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue(), $extraData);
|
||||
|
||||
if(isset($this->nbt->Biomes)){
|
||||
$this->checkOldBiomes($this->nbt->Biomes->getValue());
|
||||
@ -395,6 +409,16 @@ class Chunk extends BaseFullChunk{
|
||||
|
||||
$nbt->TileEntities = new Enum("TileEntities", $tiles);
|
||||
$nbt->TileEntities->setTagType(NBT::TAG_Compound);
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putInt(count($this->getBlockExtraDataArray()));
|
||||
foreach($this->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putInt($key);
|
||||
$extraData->putShort($value);
|
||||
}
|
||||
|
||||
$nbt->ExtraData = new ByteArray("ExtraData", $extraData->getBuffer());
|
||||
|
||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
||||
$nbt->setName("Level");
|
||||
$writer->setData(new Compound("", ["Level" => $nbt]));
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\nbt\tag\Long;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\tile\Spawnable;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ChunkException;
|
||||
|
||||
class McRegion extends BaseLevelProvider{
|
||||
@ -132,14 +133,20 @@ class McRegion extends BaseLevelProvider{
|
||||
$tiles = $nbt->write();
|
||||
}
|
||||
|
||||
$extraData = new BinaryStream();
|
||||
$extraData->putLInt(count($chunk->getBlockExtraDataArray()));
|
||||
foreach($chunk->getBlockExtraDataArray() as $key => $value){
|
||||
$extraData->putLInt($key);
|
||||
$extraData->putLShort($value);
|
||||
}
|
||||
|
||||
$ordered = $chunk->getBlockIdArray() .
|
||||
$chunk->getBlockDataArray() .
|
||||
$chunk->getBlockSkyLightArray() .
|
||||
$chunk->getBlockLightArray() .
|
||||
pack("C*", ...$chunk->getHeightMapArray()) .
|
||||
pack("N*", ...$chunk->getBiomeColorArray()) .
|
||||
//TODO extra data
|
||||
Binary::writeInt(0) .
|
||||
$extraData->getBuffer() .
|
||||
$tiles;
|
||||
|
||||
$this->getLevel()->chunkRequestCallback($x, $z, $ordered);
|
||||
|
Reference in New Issue
Block a user