1. The forums will be archived and moved to a read only mode in about 2 weeks (mid march).

Tutorial Using tasks

Discussion in 'Resources' started by Jack Noordhuis, Feb 15, 2019.

  1. Jack Noordhuis

    Jack Noordhuis Zombie Pigman Poggit Reviewer

    Messages:
    618
    GitHub:
    JackNoordhuis
    Introduction
    I've seen a lot of plugin developers confused with how to correctly use a task, and even more so since the recent changes where each plugin has its own scheduler. This post aims to demonstrate how to create and use each task type.

    When you register a task you need access to your main plugins context (the class extending pocketmine\plugin\PluginBase) or a reference to your plugins own scheduler. For the duration of this post, we'll assume we are working from within the main plugin class context.

    Repeating Tasks
    The most commonly used task (from my observations) is the repeating task. The method signature for scheduling a repeating task is as follows:
    PHP:
    TaskScheduler::scheduleRepeatingTask(\pocketmine\task\Task $taskint $period);
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleRepeatingTask(new class extends \pocketmine\scheduler\Task{
          public function 
    onRun(int $currentTick) : void{
             
    //some code here to repeat every 20 ticks (1 second)
          
    }
       }, 
    20); //period/interval
    }
    This code will schedule a task to repeat every 20 ticks until cancelled, or the server stops. For a server running at 20 TPS, this means every second this task will be run. If your server is 'lagging' (below 20 TPS) then you will have to check within the task to get the real time between executions.

    Delayed Tasks
    A delayed task only runs once after a delay specified in ticks (same pitfall as repeating tasks if the server TPS is below 20). The method signature for scheduling a delayed task is as follows:
    PHP:
    TaskScheduler::scheduleDelayedTask(\pocketmine\task\Task $taskint $period);
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleDelayedTask(new class extends \pocketmine\scheduler\Task{
          public function 
    onRun(int $currentTick) : void{
             
    //some code here to run after 20 ticks (1 second)
          
    }
       }, 
    20); //delay
    }
    This code schedules a task to execute once after 20 ticks have passed, the task will not execute if it is cancelled or the server stops before the number of ticks specified have passed.

    Instant Tasks
    An instant task (not really instant) is run at the next scheduler heartbeat, meaning it is not guaranteed it will be run on the current tick or the next tick. If you know your way around PocketMine's internals you can deliberately schedule the task before or after the current scheduler heartbeat has been executed to achieve the desired behaviour.

    This tasks usage has become more common in throughout the 3.x.x line of releases as it is currently not possible to kick players within events, you must kick players outside of the execution of events to avoid breaking the execution of the current tick. The method signature for scheduling an instant task is as follows:
    PHP:
    TaskScheduler::scheduleTask(\pocketmine\task\Task $task);
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleTask(new class extends \pocketmine\scheduler\Task{
          public function 
    onRun(int $currentTick) : void{
             
    //some code here to run on the next scheduler heartbeat (this tick or the next tick)
          
    }
       });
    }
    The above code will schedule a task to run at the next scheduler heartbeat.

    Delayed Repeating Tasks
    A delayed repeating task does as you might imagine -- schedules a repeating task to start with a delay.
    The method signature for scheduling adelayed repeating task is as follows:
    PHP:
    TaskScheduler::scheduleDelayedRepeatingTask(\pocketmine\task\Task $taskint $delayint $period);
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleDelayedRepeatingTask(new class extends \pocketmine\scheduler\Task{
          public function 
    onRun(int $currentTick) : void{
             
    //some code here to run after 20 ticks (1 second) have passed, every 20 ticks (1 second)
          
    }
       }, 
    20,20); //delay, period/interval
    }
    This code schedules a task to start repeating every 20 ticks ONCE 20 ticks have passed (a regular repeating task starts execution at the next scheduler heartbeat).

    Closure Tasks
    A closure task is a handy alternative to using the traditional class-extending \pocketmine\scheduler\Task method and provides somewhat similar functionality to the old callback task. We can just specify the code to run, schedule the task and be on our way rather than having to define a new class. We can use a closure task for any one of the four scheduler methods described above (repeating, delayed, instant and delayed repeating). An example of each of the task scheduler methods are in the spoilers below:
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleRepeatingTask(new ClosureTask(
          function(
    int $currentTick){
             
    //some code here to repeat every 20 ticks (1 second)
          
    }
       ), 
    20);
    }
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleDelayedTask(new ClosureTask(
          function(
    int $currentTick){
             
    //some code here to run after 20 ticks (1 second)
          
    }
       ), 
    20);
    }
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleTask(new ClosureTask(
          function(
    int $currentTick){
             
    //some code here to run on the next scheduler heartbeat (this tick or the next tick)
          
    }
       ));
    }
    An instant closure task is useful for kicking players during events, by kicking the player when the task is run at the next scheduler heartbeat we avoid breaking the player's connection state mid-tick.
    PHP:
    public function onChat(\pocketmine\event\player\PlayerChatEvent $event){
       
    $player $event->getPlayer(); //get the player into its own variable to avoid potentialy leaking the event object
       
    $this->getScheduler()->scheduleTask(new ClosureTask(
          function(
    int $currentTick) use($player){
             
    $player->kick();
          }
       ));
    }
    PHP:
    public function onEnable(){
       
    $this->getScheduler()->scheduleDelayedRepeatingTask(new ClosureTask(
          function(
    int $currentTick){
             
    //some code here to run after 20 ticks (1 second) have passed, every 20 ticks (1 second)
          
    }
       ), 
    2020);
    }
     
    Last edited: Feb 17, 2019
  2. b3st_Thunder78

    b3st_Thunder78 Spider Jockey

    Messages:
    38
    this is good
     
  3. TwistedFellow

    TwistedFellow Silverfish

    Messages:
    22
    GitHub:
    SilverzPlayz
    Q1: How do i connect my Main.php to my Task.php

    Q2: What do i change my
    to in my Task.php
     
  4. OnTheVerge

    OnTheVerge Spider Jockey

    Messages:
    46
    Hello there! In order for us, your fellow pmmp forum members to assist you, you must elaborate more in detail on what exactly you wanted to do. Providing some code of what exactly you have done so far would also be useful. However, as of right now your post is very vague so its quite difficult to help you.
     
  5. TwistedFellow

    TwistedFellow Silverfish

    Messages:
    22
    GitHub:
    SilverzPlayz
    So I want to know how to load my Task.php when the plugin loads, I got a Main.php that loads but how do I make the Task.php load aswell?
     
  6. OnTheVerge

    OnTheVerge Spider Jockey

    Messages:
    46
    Simply add the imports for the Task file's path within the plugin... I'm not exactly sure how exactly you structured your plugin so it's quite difficult to tell you what exactly to put. I suggest that you look at the source code of a few plugins on poggit that involves tasks.
     
  7. Deniel

    Deniel Spider Jockey

    Messages:
    42
    GitHub:
    DenielWorld
    @TwistedFellow Q1: Either "use" it, or no need for it. Q2: class TestTask extends Task{
     
    SpongeBoZZ and OnTheVerge like this.
  8. RJoLe

    RJoLe Creeper

    Messages:
    5
    Thanks Dude
     
  9. SpongeBoZZ

    SpongeBoZZ Creeper

    Messages:
    2
    Thank You, one question: can I make an extra method for this, like onFlyTask to make a Perk?
     
  10. DerCooleVonDem

    DerCooleVonDem Spider Jockey

    Messages:
    37
    GitHub:
    Soon
    Why don't work this code?

    $this->getScheduler()->scheduleDelayedTask(new class extends \pocketmine\scheduler\Task{
    public function onRun(int $currentTick) : void{
    $this->data->set("JoinPerm", 0);
    }
    }, 216.000);
     
  11. Levi

    Levi Skeleton

    Messages:
    955
    GitHub:
    captainleviftw
    any error? why is there a dot here?
    Code:
    216.000
     
    DerCooleVonDem likes this.
  12. DerCooleVonDem

    DerCooleVonDem Spider Jockey

    Messages:
    37
    GitHub:
    Soon
    Uh from my calculator

    But this was not the error

    PocketMine-MP Crash Dump Sat Sep 19 06:14:09 UTC 2020

    Error: syntax error, unexpected '$currentTick' (T_VARIABLE), expecting ')'
    File: plugins/Job (64).phar/src/derc/code/Job
    Line: 226
    Type: ParseError

    THIS CRASH WAS CAUSED BY A PLUGIN

    Code:
    [217] if($this->data->get("JoinPerm") == 0){
    [218] if($this->money->myMoney($sender) > $buy){
    [219] $this->money->reduceMoney($sender, $buy);
    [220] $sender->sendMessage("§aDu hast dir ein Jobticket gekauft!");
    [221]
    [222]
    [223]
    [224] $this->data->set("JoinPerm", 1);
    [225] $this->getScheduler()->scheduleDelayedTask(new class extends \pocketmine\scheduler\Task){
    [226] public function onRun(int $currentTick) : void{
    [227] $this->data->set("JoinPerm", 0);
    [228] }
    [229] }, 216.000); //delay
    [230] $this->IntroduceForm($player);
    [231] return true;
    [232] }else{
    [233] $sender->sendMessage("§cDu hast nicht genügend Geld dafür!");
    [234] return true;
    [235] }
    [236] }else{

    Can you help me
    ?
     
  13. Levi

    Levi Skeleton

    Messages:
    955
    GitHub:
    captainleviftw
    try using ClosureTask for what you’re trying to do
     
  14. DerCooleVonDem

    DerCooleVonDem Spider Jockey

    Messages:
    37
    GitHub:
    Soon
    I've tried the Tutorial...
     
  15. Levi

    Levi Skeleton

    Messages:
    955
    GitHub:
    captainleviftw
    You can achieve the same thing but easier with closure task
     
  16. Levi

    Levi Skeleton

    Messages:
    955
    GitHub:
    captainleviftw
    PHP:
    $this->plugin->getScheduler()->scheduleDelayedTask(new ClosureTask(function (int $currentTick) use($sender): void{
                
    $sender->sendMessage("HI!");
    }), 
    200);
     
    DerCooleVonDem likes this.
  17. GrieferHax

    GrieferHax Silverfish

    Messages:
    19
    how can i make a task that u can use a command every 24 hours
     
  18. HimbeersaftLP

    HimbeersaftLP Fish

    Messages:
    2,402
    GitHub:
    HimbeersaftLP
    You don’t. You save the current timestamp and compare it to the saved one when the player tries to run the command again.
     
    Primus likes this.
  19. Axon

    Axon Zombie

    Messages:
    276
    If you are wondering how to do it.
    Setting timestamp for player:
    PHP:
    $d1 = new Datetime();
    $this->playerData[$player->getName()] = $d1->format('U');
    Checking timestamp if it's over or under for player:
    PHP:
    $Date = new Datatime();
    $cDate $Date->format('U');

    // Add the old data with 86400 seconds.
    // 86400 = 24 hours
    $PlayerDate$this->playerData[$player->getName()] + 86400;

    if(
    $PlayerDate $cDate){
      
    // Do something if it's over 24 hours
    }else{
      
    // Do something if it's under 24 hours
    }
    Make sure to check if the data is_set and unset when the time is done.
     
    Agent, HimbeersaftLP and GrieferHax like this.
  20. Axon

    Axon Zombie

    Messages:
    276
    You can also save the data to a yaml file rather than leave it on the memory.
    Recommended if your server keeps turning off
    Example:
    Rather than $this->playerData[$player->getName()]
    You can use $this->getConfig->set($player->getName()), and for getting a data use $this->getConfig->get($player->getName);
    Then on the onDisable function you can save the data using $this->getConfig()->save()
     
    Agent, HimbeersaftLP and GrieferHax like this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.