i need make when player destroyed specified block type so after 30 seconds block appear again at the same coordinates. I know i should use sheduleRepeatingTask but i dont know how to control unknown amount of blocks. so base code here: PHP: private $time; public function onRun($ticks){ if($this->regenerate == true){ $this->time++; if($this->time == 30){ $level = Server::getInstance()->getLevelByName("level"); $level->setBlockIdAt($x, $y, $z, 57); } } } public function onBlockBreak(BlockBreakEvent $e){ $b = $e->getBlock(); if($b->getId() == 57){ $this->regenerate = true; } }
Main class that extends pocketmine\plugin\PluginBase and implements pocketmine\event\Listener: PHP: /** @var BlockRestoreTask */private $task;public function onEnable(){ $this->getServer()->getScheduler()->scheduleRepeatingTask($this->task = new BlockRestoreTask($this), 20); $this->getServer()->getPluginManager()->registerEvents($this, $this);}/*** @param BlockBreakEvent* @priority MONITOR* @ignoreCancelled true*/public function onBreakBlock(BlockBreakEvent $ev){ // MONITOR means the event has been finalized // you can do an if-check for the whole function if necessary $this->task->push($ev->getBlock());} BlockRestoreTask that extends pocketmine\scheduler\PluginTask: PHP: private $pool = [];public function onRun($currentTick){ while(($block = $this->next($currentTick) !== null){ if($block->isValid()){ // don't do anything if the level is unloaded $block->getLevel()->setBlock($block, $block); // add the $update parameter if needed } }}public function onCancel(){ // restore everything changed when the plugin is disabled foreach($this->pool as $string){ $block = $this->unhashString($string); if($block->isValid()){ // don't do anything if the level is unloaded $block->getLevel()->setBlock($block, $block); // add the $update parameter if needed } }}public function push(Block $block){ $restoreTick = $this->getOwner()->getServer()->getTick() + 600; // 600 means 600 ticks, i.e. 30 seconds. Change it if you like $this->pool[] = "$restoreTick:$block->x:$block->y:$block->z:{$block->getId()}:{$block->getDamage()}:{$block->getLevel()->getName()}"; // we do not want to hold the instances, especially those holding a Level instance, because it will cause server issues if the level is unloaded}public function next($currentTick){ $nextTick = (int) strstr($this->pool[0], ":", true); if($nextTick <= $currentTick){ return $this->unhashBlock(array_shift($this->pool)); } return null;}private function unhashBlock($string){ list(, $x, $y, $z, $id, $damage, $lvName) = explode(":", $string); return Block::get($id, $damage, new Position($x, $y, $z, $this->getOwner()->getServer()->getLevelByName($lvName)));} The above code is in the public domain, i.e. nobody has patent to use or own it, but please, don't use that code if you don't understand all of it. You are welcome to ask any questions about it, but don't copy it if you don't understand what I am doing.
yes but when lots of players are breaking blocks.. but i think it doesn´t metter if a check it per tick or per second.
The task checks if it needs to restore, not if there are block breaks. After the block is broken, a string representing the information of the original block (coords, level name, id, damage, time/tick to restore) is pushed into the BlockRestoreTask->pool array. Every 20 ticks, the task checks if the next (i.e. first) block in the array should be restored. If yes, restore it and move to the next block (shift the restored one out of the array first, as is array_shift). (That's why I used while, such that multiple restores can be executed one task run) If no, exit the function and wait until the next task run. If the plugin is going to be disabled, let's not wait but restore all the pending changes in the pool all-in-once.
No. It is a while block, not an if block. If it is an if block, it will only run once or not run at all. If it is is a while block, if the condition is true, it will run the block, and check the condition again, and run again, keep looping until the condition is false.