PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
TaskScheduler.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
28namespace pocketmine\scheduler;
29
32
34 private bool $enabled = true;
35
38
43 protected ObjectSet $tasks;
44
45 protected int $currentTick = 0;
46
47 public function __construct(
48 private ?string $owner = null
49 ){
50 $this->queue = new ReversePriorityQueue();
51 $this->tasks = new ObjectSet();
52 }
53
54 public function scheduleTask(Task $task) : TaskHandler{
55 return $this->addTask($task, -1, -1);
56 }
57
58 public function scheduleDelayedTask(Task $task, int $delay) : TaskHandler{
59 return $this->addTask($task, $delay, -1);
60 }
61
62 public function scheduleRepeatingTask(Task $task, int $period) : TaskHandler{
63 return $this->addTask($task, -1, $period);
64 }
65
66 public function scheduleDelayedRepeatingTask(Task $task, int $delay, int $period) : TaskHandler{
67 return $this->addTask($task, $delay, $period);
68 }
69
70 public function cancelAllTasks() : void{
71 foreach($this->tasks as $id => $task){
72 $task->cancel();
73 }
74 $this->tasks->clear();
75 while(!$this->queue->isEmpty()){
76 $this->queue->extract();
77 }
78 }
79
80 public function isQueued(TaskHandler $task) : bool{
81 return $this->tasks->contains($task);
82 }
83
84 private function addTask(Task $task, int $delay, int $period) : TaskHandler{
85 if(!$this->enabled){
86 throw new \LogicException("Tried to schedule task to disabled scheduler");
87 }
88
89 if($delay <= 0){
90 $delay = -1;
91 }
92
93 if($period <= -1){
94 $period = -1;
95 }elseif($period < 1){
96 $period = 1;
97 }
98
99 return $this->handle(new TaskHandler($task, $delay, $period, $this->owner));
100 }
101
102 private function handle(TaskHandler $handler) : TaskHandler{
103 if($handler->isDelayed()){
104 $nextRun = $this->currentTick + $handler->getDelay();
105 }else{
106 $nextRun = $this->currentTick;
107 }
108
109 $handler->setNextRun($nextRun);
110 $this->tasks->add($handler);
111 $this->queue->insert($handler, $nextRun);
112
113 return $handler;
114 }
115
116 public function shutdown() : void{
117 $this->enabled = false;
118 $this->cancelAllTasks();
119 }
120
121 public function setEnabled(bool $enabled) : void{
122 $this->enabled = $enabled;
123 }
124
125 public function mainThreadHeartbeat(int $currentTick) : void{
126 if(!$this->enabled){
127 throw new \LogicException("Cannot run heartbeat on a disabled scheduler");
128 }
129 $this->currentTick = $currentTick;
130 while($this->isReady($this->currentTick)){
132 $task = $this->queue->extract();
133 if($task->isCancelled()){
134 $this->tasks->remove($task);
135 continue;
136 }
137 $task->run();
138 if(!$task->isCancelled() && $task->isRepeating()){
139 $task->setNextRun($this->currentTick + $task->getPeriod());
140 $this->queue->insert($task, $this->currentTick + $task->getPeriod());
141 }else{
142 $task->remove();
143 $this->tasks->remove($task);
144 }
145 }
146 }
147
148 private function isReady(int $currentTick) : bool{
149 return !$this->queue->isEmpty() && $this->queue->current()->getNextRun() <= $currentTick;
150 }
151}