|
|
@ -269,6 +269,9 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static function blockHash(int $x, int $y, int $z){
|
|
|
|
public static function blockHash(int $x, int $y, int $z){
|
|
|
|
|
|
|
|
if($y < 0 or $y >= Level::Y_MAX){
|
|
|
|
|
|
|
|
throw new \InvalidArgumentException("Y coordinate $y is out of range!");
|
|
|
|
|
|
|
|
}
|
|
|
|
return (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF);
|
|
|
|
return (($x & 0xFFFFFFF) << 36) | (($y & Level::Y_MASK) << 28) | ($z & 0xFFFFFFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1078,7 +1081,10 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @param int $delay
|
|
|
|
* @param int $delay
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay){
|
|
|
|
public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay){
|
|
|
|
if(isset($this->scheduledBlockUpdateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->scheduledBlockUpdateQueueIndex[$index] <= $delay){
|
|
|
|
if(
|
|
|
|
|
|
|
|
!$this->isInWorld($pos->x, $pos->y, $pos->z) or
|
|
|
|
|
|
|
|
(isset($this->scheduledBlockUpdateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->scheduledBlockUpdateQueueIndex[$index] <= $delay)
|
|
|
|
|
|
|
|
){
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->scheduledBlockUpdateQueueIndex[$index] = $delay;
|
|
|
|
$this->scheduledBlockUpdateQueueIndex[$index] = $delay;
|
|
|
@ -1094,12 +1100,12 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
public function scheduleNeighbourBlockUpdates(Vector3 $pos){
|
|
|
|
public function scheduleNeighbourBlockUpdates(Vector3 $pos){
|
|
|
|
$pos = $pos->floor();
|
|
|
|
$pos = $pos->floor();
|
|
|
|
|
|
|
|
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x + 1, $pos->y, $pos->z));
|
|
|
|
for($i = 0; $i <= 5; ++$i){
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x - 1, $pos->y, $pos->z));
|
|
|
|
$side = $pos->getSide($i);
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y + 1, $pos->z));
|
|
|
|
if($this->isInWorld($side->x, $side->y, $side->z)){
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y - 1, $pos->z));
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($side->x, $side->y, $side->z));
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y, $pos->z + 1));
|
|
|
|
}
|
|
|
|
$this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y, $pos->z - 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -1298,23 +1304,39 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, false)->getFullBlock($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, false)->getFullBlock($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function isInWorld(float $x, float $y, float $z) : bool{
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
$x <= INT32_MAX and $x >= INT32_MIN and
|
|
|
|
|
|
|
|
$y < $this->getWorldHeight() and $y >= 0 and
|
|
|
|
|
|
|
|
$z <= INT32_MAX and $z >= INT32_MIN
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Gets the Block object on the Vector3 location
|
|
|
|
* Gets the Block object at the Vector3 location
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Note for plugin developers: If you are using this method a lot (thousands of times for many positions for
|
|
|
|
|
|
|
|
* example), you may want to set addToCache to false to avoid using excessive amounts of memory.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param Vector3 $pos
|
|
|
|
* @param Vector3 $pos
|
|
|
|
* @param bool $cached
|
|
|
|
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
|
|
|
|
|
|
|
|
* @param bool $addToCache Whether to cache the block object created by this method call.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return Block
|
|
|
|
* @return Block
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlock(Vector3 $pos, $cached = true) : Block{
|
|
|
|
public function getBlock(Vector3 $pos, bool $cached = true, bool $addToCache = true) : Block{
|
|
|
|
$pos = $pos->floor();
|
|
|
|
$pos = $pos->floor();
|
|
|
|
$index = Level::blockHash($pos->x, $pos->y, $pos->z);
|
|
|
|
|
|
|
|
if($cached and isset($this->blockCache[$index])){
|
|
|
|
$fullState = 0;
|
|
|
|
return $this->blockCache[$index];
|
|
|
|
$index = null;
|
|
|
|
}elseif($pos->y >= 0 and $pos->y < $this->provider->getWorldHeight() and isset($this->chunks[$chunkIndex = Level::chunkHash($pos->x >> 4, $pos->z >> 4)])){
|
|
|
|
|
|
|
|
$fullState = $this->chunks[$chunkIndex]->getFullBlock($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f);
|
|
|
|
if($this->isInWorld($pos->x, $pos->y, $pos->z)){
|
|
|
|
}else{
|
|
|
|
$index = Level::blockHash($pos->x, $pos->y, $pos->z);
|
|
|
|
$fullState = 0;
|
|
|
|
if($cached and isset($this->blockCache[$index])){
|
|
|
|
|
|
|
|
return $this->blockCache[$index];
|
|
|
|
|
|
|
|
}elseif(isset($this->chunks[$chunkIndex = Level::chunkHash($pos->x >> 4, $pos->z >> 4)])){
|
|
|
|
|
|
|
|
$fullState = $this->chunks[$chunkIndex]->getFullBlock($pos->x & 0x0f, $pos->y, $pos->z & 0x0f);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$block = clone $this->blockStates[$fullState & 0xfff];
|
|
|
|
$block = clone $this->blockStates[$fullState & 0xfff];
|
|
|
@ -1324,7 +1346,11 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
$block->z = $pos->z;
|
|
|
|
$block->z = $pos->z;
|
|
|
|
$block->level = $this;
|
|
|
|
$block->level = $this;
|
|
|
|
|
|
|
|
|
|
|
|
return $this->blockCache[$index] = $block;
|
|
|
|
if($addToCache and $index !== null){
|
|
|
|
|
|
|
|
$this->blockCache[$index] = $block;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $block;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function updateAllLight(Vector3 $pos){
|
|
|
|
public function updateAllLight(Vector3 $pos){
|
|
|
@ -1446,13 +1472,13 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlock(Vector3 $pos, Block $block, bool $direct = false, bool $update = true) : bool{
|
|
|
|
public function setBlock(Vector3 $pos, Block $block, bool $direct = false, bool $update = true) : bool{
|
|
|
|
$pos = $pos->floor();
|
|
|
|
$pos = $pos->floor();
|
|
|
|
if($pos->y < 0 or $pos->y >= $this->provider->getWorldHeight()){
|
|
|
|
if(!$this->isInWorld($pos->x, $pos->y, $pos->z)){
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->timings->setBlock->startTiming();
|
|
|
|
$this->timings->setBlock->startTiming();
|
|
|
|
|
|
|
|
|
|
|
|
if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f, $block->getId(), $block->getDamage())){
|
|
|
|
if($this->getChunk($pos->x >> 4, $pos->z >> 4, true)->setBlock($pos->x & 0x0f, $pos->y, $pos->z & 0x0f, $block->getId(), $block->getDamage())){
|
|
|
|
if(!($pos instanceof Position)){
|
|
|
|
if(!($pos instanceof Position)){
|
|
|
|
$pos = $this->temporalPosition->setComponents($pos->x, $pos->y, $pos->z);
|
|
|
|
$pos = $this->temporalPosition->setComponents($pos->x, $pos->y, $pos->z);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1942,7 +1968,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
$chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false);
|
|
|
|
$chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false);
|
|
|
|
|
|
|
|
|
|
|
|
if($chunk !== null){
|
|
|
|
if($chunk !== null){
|
|
|
|
return $chunk->getTile($pos->x & 0x0f, $pos->y & Level::Y_MASK, $pos->z & 0x0f);
|
|
|
|
return $chunk->getTile($pos->x & 0x0f, $pos->y, $pos->z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
@ -1982,7 +2008,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @return int 0-255
|
|
|
|
* @return int 0-255
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlockIdAt(int $x, int $y, int $z) : int{
|
|
|
|
public function getBlockIdAt(int $x, int $y, int $z) : int{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockId($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockId($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -1995,7 +2021,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlockIdAt(int $x, int $y, int $z, int $id){
|
|
|
|
public function setBlockIdAt(int $x, int $y, int $z, int $id){
|
|
|
|
unset($this->blockCache[Level::blockHash($x, $y, $z)]);
|
|
|
|
unset($this->blockCache[Level::blockHash($x, $y, $z)]);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $id & 0xff);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockId($x & 0x0f, $y, $z & 0x0f, $id & 0xff);
|
|
|
|
|
|
|
|
|
|
|
|
if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){
|
|
|
|
if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){
|
|
|
|
$this->changedBlocks[$index] = [];
|
|
|
|
$this->changedBlocks[$index] = [];
|
|
|
@ -2016,7 +2042,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @return int 16-bit
|
|
|
|
* @return int 16-bit
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlockExtraDataAt(int $x, int $y, int $z) : int{
|
|
|
|
public function getBlockExtraDataAt(int $x, int $y, int $z) : int{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockExtraData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockExtraData($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2029,7 +2055,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @param int $data
|
|
|
|
* @param int $data
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlockExtraDataAt(int $x, int $y, int $z, int $id, int $data){
|
|
|
|
public function setBlockExtraDataAt(int $x, int $y, int $z, int $id, int $data){
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockExtraData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, ($data << 8) | $id);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockExtraData($x & 0x0f, $y, $z & 0x0f, ($data << 8) | $id);
|
|
|
|
|
|
|
|
|
|
|
|
$this->sendBlockExtraData($x, $y, $z, $id, $data);
|
|
|
|
$this->sendBlockExtraData($x, $y, $z, $id, $data);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -2044,7 +2070,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @return int 0-15
|
|
|
|
* @return int 0-15
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlockDataAt(int $x, int $y, int $z) : int{
|
|
|
|
public function getBlockDataAt(int $x, int $y, int $z) : int{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockData($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2057,7 +2083,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlockDataAt(int $x, int $y, int $z, int $data){
|
|
|
|
public function setBlockDataAt(int $x, int $y, int $z, int $data){
|
|
|
|
unset($this->blockCache[Level::blockHash($x, $y, $z)]);
|
|
|
|
unset($this->blockCache[Level::blockHash($x, $y, $z)]);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $data & 0x0f);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockData($x & 0x0f, $y, $z & 0x0f, $data & 0x0f);
|
|
|
|
|
|
|
|
|
|
|
|
if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){
|
|
|
|
if(!isset($this->changedBlocks[$index = Level::chunkHash($x >> 4, $z >> 4)])){
|
|
|
|
$this->changedBlocks[$index] = [];
|
|
|
|
$this->changedBlocks[$index] = [];
|
|
|
@ -2078,7 +2104,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @return int 0-15
|
|
|
|
* @return int 0-15
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlockSkyLightAt(int $x, int $y, int $z) : int{
|
|
|
|
public function getBlockSkyLightAt(int $x, int $y, int $z) : int{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockSkyLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockSkyLight($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2090,7 +2116,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @param int $level 0-15
|
|
|
|
* @param int $level 0-15
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
|
|
|
|
public function setBlockSkyLightAt(int $x, int $y, int $z, int $level){
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $level & 0x0f);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockSkyLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2103,7 +2129,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @return int 0-15
|
|
|
|
* @return int 0-15
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function getBlockLightAt(int $x, int $y, int $z) : int{
|
|
|
|
public function getBlockLightAt(int $x, int $y, int $z) : int{
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f);
|
|
|
|
return $this->getChunk($x >> 4, $z >> 4, true)->getBlockLight($x & 0x0f, $y, $z & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2115,7 +2141,7 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
* @param int $level 0-15
|
|
|
|
* @param int $level 0-15
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public function setBlockLightAt(int $x, int $y, int $z, int $level){
|
|
|
|
public function setBlockLightAt(int $x, int $y, int $z, int $level){
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y & Level::Y_MASK, $z & 0x0f, $level & 0x0f);
|
|
|
|
$this->getChunk($x >> 4, $z >> 4, true)->setBlockLight($x & 0x0f, $y, $z & 0x0f, $level & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -2763,6 +2789,10 @@ class Level implements ChunkManager, Metadatable{
|
|
|
|
$this->provider->setSeed($seed);
|
|
|
|
$this->provider->setSeed($seed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getWorldHeight() : int{
|
|
|
|
|
|
|
|
return $this->provider->getWorldHeight();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function populateChunk(int $x, int $z, bool $force = false) : bool{
|
|
|
|
public function populateChunk(int $x, int $z, bool $force = false) : bool{
|
|
|
|
if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)]) or (count($this->chunkPopulationQueue) >= $this->chunkPopulationQueueSize and !$force)){
|
|
|
|
if(isset($this->chunkPopulationQueue[$index = Level::chunkHash($x, $z)]) or (count($this->chunkPopulationQueue) >= $this->chunkPopulationQueueSize and !$force)){
|
|
|
|