*/ protected $queue; /** * @var TaskHandler[] */ protected $tasks = array(); /** * @var int */ private $ids = 1; /** * @var int */ protected $currentTick = 0; public function __construct(){ $this->queue = new \SplPriorityQueue(); } /** * @param Task $task * * @return null|TaskHandler */ public function scheduleTask(Task $task){ return $this->addTask($task, -1, -1); } /** * @param Task $task * @param int $delay * * @return null|TaskHandler */ public function scheduleDelayedTask(Task $task, $delay){ return $this->addTask($task, (int) $delay, -1); } /** * @param Task $task * @param int $period * * @return null|TaskHandler */ public function scheduleRepeatingTask(Task $task, $period){ return $this->addTask($task, -1, (int) $period); } /** * @param Task $task * @param int $delay * @param int $period * * @return null|TaskHandler */ public function scheduleDelayedRepeatingTask(Task $task, $delay, $period){ return $this->addTask($task, (int) $delay, (int) $period); } /** * @param int $taskId */ public function cancelTask($taskId){ if(isset($this->tasks[$taskId])){ $this->tasks[$taskId]->cancel(); unset($this->tasks[$taskId]); } } /** * @param Plugin $plugin */ public function cancelTasks(Plugin $plugin){ foreach($this->tasks as $taskId => $task){ if($task->getTask() instanceof PluginTask){ $task->cancel(); unset($this->tasks[$taskId]); } } } public function cancelAllTasks(){ foreach($this->tasks as $task){ $task->cancel(); } $this->tasks = array(); } /** * @param int $taskId * * @return bool */ public function isQueued($taskId){ return isset($this->tasks[$taskId]); } private function addTask(Task $task, $delay, $period){ if($task instanceof PluginTask and !$task->getOwner()->isEnabled()){ trigger_error("Plugin attempted to register a task while disabled", E_USER_WARNING); return null; } if($delay <= 0){ $delay = -1; } if($period === 1){ $period = 1; }elseif($period < -1){ $period = -1; } return $this->handle(new TaskHandler($task, $this->nextId(), $delay, $period)); } private function handle(TaskHandler $handler){ if($handler->isDelayed()){ $nextRun = $this->currentTick + $handler->getDelay(); }else{ $nextRun = $this->currentTick; } $handler->setNextRun($nextRun); $this->tasks[$handler->getTaskId()] = $handler; $this->queue->insert($handler, $nextRun); return $handler; } /** * @param int $currentTick */ public function mainThreadHeartbeat($currentTick){ $this->currentTick = $currentTick; while($this->isReady($this->currentTick)){ $task = $this->queue->extract(); if($task->isCancelled()){ unset($this->tasks[$task->getTaskId()]); continue; }else{ $task->run(); } if($task->isRepeating()){ $task->setNextRun($this->currentTick + $task->getPeriod()); $this->queue->insert($task, $this->currentTick + $task->getPeriod()); }else{ $task->remove(); unset($this->tasks[$task->getTaskId()]); } } } private function isReady($currentTicks){ return count($this->tasks) > 0 and $this->queue->current()->getNextRun() <= $currentTicks; } /** * @return int */ private function nextId(){ return $this->ids++; } }