Use this file to discover all available pages before exploring further.
The task scheduler allows you to run code at specific times, with delays, or repeatedly. This is essential for timers, countdowns, auto-save systems, and more.
Tasks extend the Task class and implement onRun():
src/MyPlugin/tasks/MyTask.php
<?phpdeclare(strict_types=1);namespace MyPlugin\tasks;use pocketmine\scheduler\Task;use MyPlugin\Main;class MyTask extends Task { public function __construct( private Main $plugin ){} public function onRun() : void { // This code runs when the task executes $this->plugin->getLogger()->info("Task executed!"); }}
// Run after 20 ticks (1 second)$this->getScheduler()->scheduleDelayedTask(new MyTask($this), 20);// Run after 5 seconds (100 ticks)$this->getScheduler()->scheduleDelayedTask(new MyTask($this), 100);
PocketMine-MP runs at 20 ticks per second (TPS). 1 tick = 0.05 seconds = 50ms.
// Run every 20 ticks (every second)$this->getScheduler()->scheduleRepeatingTask( new MyTask($this), 20 // period in ticks);// Run every 5 seconds$this->getScheduler()->scheduleRepeatingTask( new MyTask($this), 100);
Execute a task repeatedly, but start after a delay:
// Wait 60 ticks (3 seconds), then run every 20 ticks (1 second)$this->getScheduler()->scheduleDelayedRepeatingTask( new MyTask($this), 60, // delay before first run 20 // period between runs);
// Save the handler when scheduling$handler = $this->getScheduler()->scheduleRepeatingTask( new MyTask($this), 20);// Cancel the task later$handler->cancel();
<?phpdeclare(strict_types=1);namespace MyPlugin\tasks;use pocketmine\scheduler\Task;use MyPlugin\Main;class AutoSaveTask extends Task { public function __construct( private Main $plugin ){} public function onRun() : void { // Save all player data foreach($this->plugin->getServer()->getOnlinePlayers() as $player) { $this->plugin->savePlayerData($player); } // Save plugin data $this->plugin->getConfig()->save(); $this->plugin->getLogger()->info("Auto-saved player data"); }}// In Main.php onEnable():protected function onEnable() : void { // Auto-save every 5 minutes (6000 ticks) $this->getScheduler()->scheduleRepeatingTask( new AutoSaveTask($this), 6000 );}
public function teleportWithDelay(Player $player, Position $destination) : void { $player->sendMessage("§eTeleporting in 3 seconds..."); // Save player's position to check if they moved $originalPos = $player->getPosition(); $this->getScheduler()->scheduleDelayedTask( new ClosureTask(function() use ($player, $destination, $originalPos) : void { // Check if player moved if($player->getPosition()->distance($originalPos) > 0.5) { $player->sendMessage("§cTeleport cancelled - you moved!"); return; } $player->teleport($destination); $player->sendMessage("§aTeleported!"); }), 60 // 3 seconds );}
<?phpdeclare(strict_types=1);namespace MyPlugin\tasks;use pocketmine\scheduler\AsyncTask;class MyAsyncTask extends AsyncTask { private string $data; public function __construct(string $data) { $this->data = $data; } // Runs on worker thread (cannot access Server) public function onRun() : void { // Do heavy computation $result = []; for($i = 0; $i < 1000000; $i++) { $result[] = hash('sha256', $this->data . $i); } // Store result (must be serializable) $this->setResult(count($result)); } // Runs on main thread when task completes public function onCompletion() : void { $result = $this->getResult(); // Can access Server here }}
class TimeHelper { public const TICKS_PER_SECOND = 20; public const TICKS_PER_MINUTE = 20 * 60; public const TICKS_PER_HOUR = 20 * 60 * 60; public static function secondsToTicks(float $seconds) : int { return (int) ($seconds * self::TICKS_PER_SECOND); } public static function minutesToTicks(float $minutes) : int { return (int) ($minutes * self::TICKS_PER_MINUTE); }}// Usage:$this->getScheduler()->scheduleDelayedTask( new MyTask($this), TimeHelper::secondsToTicks(5) // 5 seconds);$this->getScheduler()->scheduleRepeatingTask( new MyTask($this), TimeHelper::minutesToTicks(1) // every minute);
$handler = $this->getScheduler()->scheduleRepeatingTask(new MyTask($this), 20);// Cancel the task$handler->cancel();// Check if cancelledif($handler->isCancelled()) { // Task is cancelled}// Check if it's a repeating taskif($handler->isRepeating()) { // This is a repeating task}// Check if it has a delayif($handler->isDelayed()) { // This task has a delay before first run}// Get the task instance$task = $handler->getTask();
$this->getScheduler()->scheduleDelayedTask( new ClosureTask(fn() => $player->sendMessage("Hello!")), 20);
Create Task classes for complex logic:
class ComplexTask extends Task { // Multiple methods, properties, logic}
Always cancel repeating tasks:
private ?TaskHandler $repeatingTask = null;protected function onEnable() : void { $this->repeatingTask = $this->getScheduler()->scheduleRepeatingTask(...);}protected function onDisable() : void { $this->repeatingTask?->cancel();}
Don’t schedule too many tasks:
Each task has overhead. Instead of 1000 individual tasks, use one task that processes multiple items.Use delays wisely:
Don’t schedule a task every tick (20 times per second) unless absolutely necessary. This impacts performance.
class DebugTask extends Task { private int $runCount = 0; public function __construct( private Main $plugin ){} public function onRun() : void { $this->runCount++; $this->plugin->getLogger()->debug( "Task ran {$this->runCount} times" ); // Auto-cancel after 10 runs if($this->runCount >= 10) { $this->plugin->getLogger()->info("Task finished"); $this->getHandler()->cancel(); } }}