I am making this plugin that places a block on top of the other. Basically, when I place a coarse dirt, I want it to place a flower or tall grass on top of the coarse dirt. Code: public function onBlockPlace(BlockPlaceEvent $event) { $block = $event->getBlock(); $player = $event->getPlayer(); $level = $player->getLevel(); $above = $block->add(0, 1, 0); if ($block->getId() == Block::DIRT) { if($block->getDamage() === 1){ if($block->getLevel()->getBlock($above)->getId() === Block::AIR){ switch(mt_rand(1, 50)) { case 1: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 2: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 3: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 4: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 5: $block->getLevel()->setBlock($above, Block::get(38, 1)); break; case 6: $block->getLevel()->setBlock($above, Block::get(38, 2)); break; case 7: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; // [...] case 50: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; } } } } } Instead of placing a flower (38,2 and 38,1), it only drops the item. It also dosen't place tall grass(31,1) on top of the coarse dirt, nothing happens. I don't know what to do. I tested it by replacing the flowers and the tall grass with stone and it worked. It was placing stone on top of the coarse dirt. Sorry for my bad english, I am french.
Yup Code: public function onEnable() { $this->getServer()->getPluginManager()->registerEvents($this, $this); } I think that the tall grass/flowers automatically breaks themselves because they don't detect that there is a block of coarse dirt under them. Is there a way I could prevent the block from breaking themselves?
When BlockPlaceEvent is called, the coarse dirt is not set in the level yet, you need to delay the setblock of the flower by using task eg ClosureTask
Like this? Code: public function onBlockPlace(BlockPlaceEvent $event) { $block = $event->getBlock(); $player = $event->getPlayer(); $level = $player->getLevel(); $above = $block->add(0, 1, 0); if ($block->getId() == Block::DIRT) { if($block->getDamage() === 1){ if($block->getLevel()->getBlock($above)->getId() === Block::AIR){ $this->getScheduler()->scheduleDelayedTask(new ClosureTask( function(int $currentTick){ switch(mt_rand(1, 50)) { case 1: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 2: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 3: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 4: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; case 5: $block->getLevel()->setBlock($above, Block::get(38, 1)); break; case 6: $block->getLevel()->setBlock($above, Block::get(38, 2)); break; case 7: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; // [...] case 50: $block->getLevel()->setBlock($above, Block::get(31, 1)); break; } } ), 20); } } } }
change PHP: function(int $currentTick){ to PHP: function(int $currentTick) use ($block,$above){ and it should work Also be sure to check the level is not closed before setting the block to prevent setblock on null
How exactly am I doing that? I don't understand... [01:46:19] [Server thread/CRITICAL]: Error: "Class 'Vinc\Generator\ClosureTask' not found" (EXCEPTION) in "plugins/Generator/src/Vinc/Generator/Main" at line 216
What about simply set the block without updates like this PHP: $block->getLevel()->setBlock($above, Block::get(31, 1), false, false); Check here to understand why: https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/level/Level.php#L1590
What's this now? [16:09:34] [Server thread/CRITICAL]: TypeError: "Declaration of callable `function ( int $currentTick )` must be compatible with `function ( int $currentTick ) : void`" (EXCEPTION) in "src/pocketmine/utils/Utils" at line 714