34    private bool $enabled = 
true;
 
   45    protected int $currentTick = 0;
 
   47    public function __construct(
 
   48        private ?
string $owner = 
null 
   61        return $this->addTask($task, -1, -1);
 
 
   71        return $this->addTask($task, $delay, -1);
 
 
   81        return $this->addTask($task, -1, $period);
 
 
   91        return $this->addTask($task, $delay, $period);
 
 
   94    public function cancelAllTasks() : void{
 
   95        foreach($this->tasks as $id => $task){
 
   98        $this->tasks->clear();
 
   99        while(!$this->queue->isEmpty()){
 
  100            $this->queue->extract();
 
  108        return $this->tasks->contains($task);
 
 
  117    private function addTask(
Task $task, 
int $delay, 
int $period) : 
TaskHandler{
 
  119            throw new \LogicException(
"Tried to schedule task to disabled scheduler");
 
  128        }elseif($period < 1){
 
  132        return $this->handle(
new TaskHandler($task, $delay, $period, $this->owner));
 
  140    private function handle(TaskHandler $handler) : TaskHandler{
 
  141        if($handler->isDelayed()){
 
  142            $nextRun = $this->currentTick + $handler->getDelay();
 
  144            $nextRun = $this->currentTick;
 
  147        $handler->setNextRun($nextRun);
 
  148        $this->tasks->add($handler);
 
  149        $this->queue->insert($handler, $nextRun);
 
  154    public function shutdown() : void{
 
  155        $this->enabled = false;
 
  156        $this->cancelAllTasks();
 
  159    public function setEnabled(
bool $enabled) : void{
 
  160        $this->enabled = $enabled;
 
  163    public function mainThreadHeartbeat(
int $currentTick) : void{
 
  165            throw new \LogicException(
"Cannot run heartbeat on a disabled scheduler");
 
  167        $this->currentTick = $currentTick;
 
  168        while($this->isReady($this->currentTick)){
 
  170            $task = $this->queue->extract();
 
  171            if($task->isCancelled()){
 
  172                $this->tasks->remove($task);
 
  176            if(!$task->isCancelled() && $task->isRepeating()){
 
  177                $task->setNextRun($this->currentTick + $task->getPeriod());
 
  178                $this->queue->insert($task, $this->currentTick + $task->getPeriod());
 
  181                $this->tasks->remove($task);
 
  186    private function isReady(
int $currentTick) : bool{
 
  187        return !$this->queue->isEmpty() && $this->queue->current()->getNextRun() <= $currentTick;