mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 09:56:06 +00:00
Merge branch 'master' into mcpe-1.2
This commit is contained in:
@ -26,28 +26,8 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace pocketmine\level;
|
||||
|
||||
use pocketmine\block\Beetroot;
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockFactory;
|
||||
use pocketmine\block\BrownMushroom;
|
||||
use pocketmine\block\Cactus;
|
||||
use pocketmine\block\Carrot;
|
||||
use pocketmine\block\Farmland;
|
||||
use pocketmine\block\Fire;
|
||||
use pocketmine\block\Grass;
|
||||
use pocketmine\block\Ice;
|
||||
use pocketmine\block\Leaves;
|
||||
use pocketmine\block\Leaves2;
|
||||
use pocketmine\block\MelonStem;
|
||||
use pocketmine\block\Mycelium;
|
||||
use pocketmine\block\NetherWartPlant;
|
||||
use pocketmine\block\Potato;
|
||||
use pocketmine\block\PumpkinStem;
|
||||
use pocketmine\block\RedMushroom;
|
||||
use pocketmine\block\Sapling;
|
||||
use pocketmine\block\SnowLayer;
|
||||
use pocketmine\block\Sugarcane;
|
||||
use pocketmine\block\Wheat;
|
||||
use pocketmine\entity\Arrow;
|
||||
use pocketmine\entity\Effect;
|
||||
use pocketmine\entity\Entity;
|
||||
@ -227,30 +207,8 @@ class Level implements ChunkManager, Metadatable{
|
||||
private $chunkTickList = [];
|
||||
private $chunksPerTick;
|
||||
private $clearChunksOnTick;
|
||||
private $randomTickBlocks = [
|
||||
Block::GRASS => Grass::class,
|
||||
Block::SAPLING => Sapling::class,
|
||||
Block::LEAVES => Leaves::class,
|
||||
Block::WHEAT_BLOCK => Wheat::class,
|
||||
Block::FARMLAND => Farmland::class,
|
||||
Block::SNOW_LAYER => SnowLayer::class,
|
||||
Block::ICE => Ice::class,
|
||||
Block::CACTUS => Cactus::class,
|
||||
Block::SUGARCANE_BLOCK => Sugarcane::class,
|
||||
Block::RED_MUSHROOM => RedMushroom::class,
|
||||
Block::BROWN_MUSHROOM => BrownMushroom::class,
|
||||
Block::PUMPKIN_STEM => PumpkinStem::class,
|
||||
Block::MELON_STEM => MelonStem::class,
|
||||
//Block::VINE => true,
|
||||
Block::MYCELIUM => Mycelium::class,
|
||||
//Block::COCOA_BLOCK => true,
|
||||
Block::CARROT_BLOCK => Carrot::class,
|
||||
Block::POTATO_BLOCK => Potato::class,
|
||||
Block::LEAVES2 => Leaves2::class,
|
||||
Block::FIRE => Fire::class,
|
||||
Block::BEETROOT_BLOCK => Beetroot::class,
|
||||
Block::NETHER_WART_PLANT => NetherWartPlant::class
|
||||
];
|
||||
/** @var \SplFixedArray<Block> */
|
||||
private $randomTickBlocks = null;
|
||||
|
||||
/** @var LevelTimings */
|
||||
public $timings;
|
||||
@ -344,10 +302,19 @@ class Level implements ChunkManager, Metadatable{
|
||||
$this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true);
|
||||
$this->cacheChunks = (bool) $this->server->getProperty("chunk-sending.cache-chunks", false);
|
||||
|
||||
$this->randomTickBlocks = \SplFixedArray::fromArray(array_filter(BlockFactory::$list->toArray(), function(Block $block = null){
|
||||
return $block !== null and $block->ticksRandomly();
|
||||
}));
|
||||
$this->randomTickBlocks->setSize(256);
|
||||
|
||||
$dontTickBlocks = $this->server->getProperty("chunk-ticking.disable-block-ticking", []);
|
||||
foreach($dontTickBlocks as $id){
|
||||
if(isset($this->randomTickBlocks[$id])){
|
||||
unset($this->randomTickBlocks[$id]);
|
||||
try{
|
||||
if(isset($this->randomTickBlocks[$id])){
|
||||
$this->randomTickBlocks[$id] = null;
|
||||
}
|
||||
}catch(\RuntimeException $e){
|
||||
//index out of bounds
|
||||
}
|
||||
}
|
||||
|
||||
@ -912,11 +879,11 @@ class Level implements ChunkManager, Metadatable{
|
||||
}
|
||||
|
||||
public function addRandomTickedBlock(int $id){
|
||||
$this->randomTickBlocks[$id] = get_class(BlockFactory::$list[$id]);
|
||||
$this->randomTickBlocks[$id] = BlockFactory::get($id);
|
||||
}
|
||||
|
||||
public function removeRandomTickedBlock(int $id){
|
||||
unset($this->randomTickBlocks[$id]);
|
||||
$this->randomTickBlocks[$id] = null;
|
||||
}
|
||||
|
||||
private function tickChunks(){
|
||||
@ -964,17 +931,18 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
||||
if(!$subChunk->isEmpty()){
|
||||
$k = mt_rand(0, 0x7fffffff);
|
||||
for($i = 0; $i < 3; ++$i, $k >>= 10){
|
||||
for($i = 0; $i < 3; ++$i){
|
||||
$k = mt_rand(0, 0xfff);
|
||||
$x = $k & 0x0f;
|
||||
$y = ($k >> 8) & 0x0f;
|
||||
$z = ($k >> 16) & 0x0f;
|
||||
$y = ($k >> 4) & 0x0f;
|
||||
$z = ($k >> 8) & 0x0f;
|
||||
|
||||
$blockId = $subChunk->getBlockId($x, $y, $z);
|
||||
if(isset($this->randomTickBlocks[$blockId])){
|
||||
$class = $this->randomTickBlocks[$blockId];
|
||||
if($this->randomTickBlocks[$blockId] !== null){
|
||||
/** @var Block $block */
|
||||
$block = new $class($subChunk->getBlockData($x, $y, $z));
|
||||
$block = clone $this->randomTickBlocks[$blockId];
|
||||
$block->setDamage($subChunk->getBlockData($x, $y, $z));
|
||||
|
||||
$block->x = $chunkX * 16 + $x;
|
||||
$block->y = ($Y << 4) + $y;
|
||||
$block->z = $chunkZ * 16 + $z;
|
||||
@ -1567,6 +1535,27 @@ class Level implements ChunkManager, Metadatable{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the level spawn protection radius will prevent the player from using items or building at the specified
|
||||
* Vector3 position.
|
||||
*
|
||||
* @param Player $player
|
||||
* @param Vector3 $vector
|
||||
*
|
||||
* @return bool false if spawn protection cancelled the action, true if not.
|
||||
*/
|
||||
protected function checkSpawnProtection(Player $player, Vector3 $vector) : bool{
|
||||
if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){
|
||||
$t = new Vector2($vector->x, $vector->z);
|
||||
$s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z);
|
||||
if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to break a block using a item, including Player time checks if available
|
||||
* It'll try to lower the durability if Item is a tool, and set it to Air if broken.
|
||||
@ -1590,12 +1579,8 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
if(($player->isSurvival() and $item instanceof Item and !$target->isBreakable($item)) or $player->isSpectator()){
|
||||
$ev->setCancelled();
|
||||
}elseif(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){
|
||||
$t = new Vector2($target->x, $target->z);
|
||||
$s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z);
|
||||
if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this
|
||||
$ev->setCancelled();
|
||||
}
|
||||
}elseif($this->checkSpawnProtection($player, $target)){
|
||||
$ev->setCancelled(); //set it to cancelled so plugins can bypass this
|
||||
}
|
||||
|
||||
if($player->isAdventure(true) and !$ev->isCancelled()){
|
||||
@ -1710,30 +1695,26 @@ class Level implements ChunkManager, Metadatable{
|
||||
* @return bool
|
||||
*/
|
||||
public function useItemOn(Vector3 $vector, Item &$item, int $face, Vector3 $facePos = null, Player $player = null, bool $playSound = false) : bool{
|
||||
$target = $this->getBlock($vector);
|
||||
$block = $target->getSide($face);
|
||||
$blockClicked = $this->getBlock($vector);
|
||||
$blockReplace = $blockClicked->getSide($face);
|
||||
|
||||
if($facePos === null){
|
||||
$facePos = new Vector3(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
if($block->y >= $this->provider->getWorldHeight() or $block->y < 0){
|
||||
if($blockReplace->y >= $this->provider->getWorldHeight() or $blockReplace->y < 0){
|
||||
//TODO: build height limit messages for custom world heights and mcregion cap
|
||||
return false;
|
||||
}
|
||||
|
||||
if($target->getId() === Item::AIR){
|
||||
if($blockClicked->getId() === Item::AIR){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($player !== null){
|
||||
$ev = new PlayerInteractEvent($player, $item, $target, $face, $target->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
||||
if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){
|
||||
$t = new Vector2($target->x, $target->z);
|
||||
$s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z);
|
||||
if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this
|
||||
$ev->setCancelled();
|
||||
}
|
||||
$ev = new PlayerInteractEvent($player, $item, $blockClicked, $face, $blockClicked->getId() === 0 ? PlayerInteractEvent::RIGHT_CLICK_AIR : PlayerInteractEvent::RIGHT_CLICK_BLOCK);
|
||||
if($this->checkSpawnProtection($player, $blockClicked)){
|
||||
$ev->setCancelled(); //set it to cancelled so plugins can bypass this
|
||||
}
|
||||
|
||||
if($player->isAdventure(true) and !$ev->isCancelled()){
|
||||
@ -1743,7 +1724,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
foreach($tag as $v){
|
||||
if($v instanceof StringTag){
|
||||
$entry = ItemFactory::fromString($v->getValue());
|
||||
if($entry->getId() > 0 and $entry->getBlock() !== null and $entry->getBlock()->getId() === $target->getId()){
|
||||
if($entry->getId() > 0 and $entry->getBlock() !== null and $entry->getBlock()->getId() === $blockClicked->getId()){
|
||||
$canPlace = true;
|
||||
break;
|
||||
}
|
||||
@ -1756,12 +1737,12 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev);
|
||||
if(!$ev->isCancelled()){
|
||||
$target->onUpdate(self::BLOCK_UPDATE_TOUCH);
|
||||
if(!$player->isSneaking() and $target->onActivate($item, $player) === true){
|
||||
$blockClicked->onUpdate(self::BLOCK_UPDATE_TOUCH);
|
||||
if(!$player->isSneaking() and $blockClicked->onActivate($item, $player) === true){
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!$player->isSneaking() and $item->onActivate($this, $player, $block, $target, $face, $facePos)){
|
||||
if(!$player->isSneaking() and $item->onActivate($this, $player, $blockReplace, $blockClicked, $face, $facePos)){
|
||||
if($item->getCount() <= 0){
|
||||
$item = ItemFactory::get(Item::AIR, 0, 0);
|
||||
|
||||
@ -1771,7 +1752,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}elseif($target->onActivate($item, $player) === true){
|
||||
}elseif($blockClicked->onActivate($item, $player) === true){
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1781,13 +1762,13 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
$hand = $item->getBlock();
|
||||
|
||||
if($target->canBeReplaced($hand)){
|
||||
$block = $target;
|
||||
}elseif(!$block->canBeReplaced($hand)){
|
||||
if($blockClicked->canBeReplaced($hand)){
|
||||
$blockReplace = $blockClicked;
|
||||
}elseif(!$blockReplace->canBeReplaced($hand)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$hand->position($block);
|
||||
$hand->position($blockReplace);
|
||||
|
||||
if($hand->isSolid() === true and $hand->getBoundingBox() !== null){
|
||||
$entities = $this->getCollidingEntities($hand->getBoundingBox());
|
||||
@ -1815,21 +1796,18 @@ class Level implements ChunkManager, Metadatable{
|
||||
|
||||
|
||||
if($player !== null){
|
||||
$ev = new BlockPlaceEvent($player, $hand, $block, $target, $item);
|
||||
if(!$player->hasPermission("pocketmine.spawnprotect.bypass") and ($distance = $this->server->getSpawnRadius()) > -1){
|
||||
$t = new Vector2($target->x, $target->z);
|
||||
$s = new Vector2($this->getSpawnLocation()->x, $this->getSpawnLocation()->z);
|
||||
if(count($this->server->getOps()->getAll()) > 0 and $t->distance($s) <= $distance){ //set it to cancelled so plugins can bypass this
|
||||
$ev->setCancelled();
|
||||
}
|
||||
$ev = new BlockPlaceEvent($player, $hand, $blockReplace, $blockClicked, $item);
|
||||
if($this->checkSpawnProtection($player, $blockClicked)){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev);
|
||||
if($ev->isCancelled()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$hand->place($item, $block, $target, $face, $facePos, $player)){
|
||||
if(!$hand->place($item, $blockReplace, $blockClicked, $face, $facePos, $player)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user