Asynchronous block remove!

Discussion in 'Plugin Development' started by Welite, Dec 5, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    Welite

    Hi I have had almost complete plugin for 1.6.4, then came 1.7.2, and now there is an interesting error, my plugin uses "block.setType(Material.AIR);" and exactly here is the problem. This line is in the java timer. And the error from console is following:


    Code:
    [22:11:13] [Timer-51/WARN]: Exception in thread "Timer-51" 
    [22:11:13] [Timer-51/WARN]: java.lang.IllegalStateException: Asynchronous block remove!
    [22:11:13] [Timer-51/WARN]: at net.minecraft.server.v1_7_R1.Block.remove(Block.java:441)
    [22:11:13] [Timer-51/WARN]: at net.minecraft.server.v1_7_R1.Chunk.a(Chunk.java:436)
    [22:11:13] [Timer-51/WARN]: at net.minecraft.server.v1_7_R1.World.setTypeAndData(World.java:344)
    [22:11:13] [Timer-51/WARN]: at org.bukkit.craftbukkit.v1_7_R1.block.CraftBlock.setTypeIdAndData(CraftBlock.java:127)
    [22:11:13] [Timer-51/WARN]: at org.bukkit.craftbukkit.v1_7_R1.block.CraftBlock.setTypeId(CraftBlock.java:122)
    [22:11:13] [Timer-51/WARN]: at org.bukkit.craftbukkit.v1_7_R1.block.CraftBlock.setTypeId(CraftBlock.java:118)
    [22:11:13] [Timer-51/WARN]: at org.bukkit.craftbukkit.v1_7_R1.block.CraftBlock.setType(CraftBlock.java:114)
    [22:11:13] [Timer-51/WARN]: at vip.prodction.dakado.wooljumper.Main.degenerate(Main.java:1356)
    [22:11:13] [Timer-51/WARN]: at vip.prodction.dakado.wooljumper.Main$7$1.run(Main.java:1604)
    [22:11:13] [Timer-51/WARN]: at java.util.TimerThread.mainLoop(Unknown Source)
    [22:11:13] [Timer-51/WARN]: at java.util.TimerThread.run(Unknown Source)
      
     
  2. Offline

    CubieX

    Are you calling this within an asynchronous task?
    If so, don't do it. Only call bukkit methods by using the main thread.
     
  3. Offline

    Rocoty

    It seems as though you are trying to remove a block from a thread separate from the main thread. I'd call a new synchronous task from the Bukkit API in your situation...either that, or see if you can do what you were doing synchronously instead.
     
  4. Offline

    Welite

    Here is my code, so I should change it to bukkit schedulers ? Please nooo.... I hate bukkit schedulers Java timers are much more better.

    http://pastebin.com/RUWe5Kmv

    In 1.6.4 it worked perfectly.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  5. Offline

    Rocoty

    I'm afraid the only way to schedule a task on the main thread from a separate thread is to use bukkit schedulers
     
  6. Offline

    Welite

    And what if I move this to a method to another class ? Would it help ?
     
  7. Offline

    fireblast709

  8. Offline

    desht

    No, in 1.6.4 you got lucky and didn't get an unexpected exception or corrupt yours or someone else's world.

    World modification from another thread is a big no-no and always has been.
     
    Cirno and Garris0n like this.
  9. Offline

    Welite

    OK, and can someone help me with the Bukkit schedulers ? I never used them, I read the tutorial on bukkit but it is not explained well.

    So for example I have this java timer and I want exactly the same but with bukkit timer what should I do ?
    (Task which is repeating every 10 seconds):
    Code:java
    1.  
    2. final Timer progresstimer= new Timer();
    3. TimerTask progresstask = new TimerTask(){
    4. public void run(){
    5. } };
    6. progresstimer.schedule(progresstask, 1000, 10*1000);
    7.  





    And delayed task which runs once with delay 5 ten seconds:
    Code:java
    1.  
    2. final Timer delaytimer= new Timer();
    3. TimerTask delaytask = new TimerTask(){
    4. public void run(){
    5. }};
    6. delaytimer.schedule(delaytask, 5*1000);
    7.  



    How can I rewrite those task to bukkit shceduler please ?
     
  10. Offline

    desht

    A simple example from one of my own plugins (subclassing BukkitRunnable):

    https://github.com/desht/checkers/blob/master/src/main/java/me/desht/checkers/TickTask.java

    and I create a TickTask and start it off here:

    https://github.com/desht/checkers/b...va/me/desht/checkers/CheckersPlugin.java#L170

    (delay of 20 ticks, and runs every 20 ticks, i.e. once per second).

    Another way to do it is to use BukkitScheduler to get yourself a BukkitTask object:

    PHP:
    BukkitTask task Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() {
      @
    Override
      
    public void run() { /* .... */ }
    }, 
    20L20L);
    BukkitTask gives you a few methods to help manage the task (in particular, .cancel()).
     
  11. Offline

    Welite


    Nice thanks, but one more question, how to check for some condition and cancel task inside itself ?


    Example:
    Code:java
    1.  
    2. final BukkitTask progresstask = Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() {
    3. @Override
    4. public void run() {
    5. //some code
    6.  
    7.  
    8. if (status.equals("lobby")) {
    9. progresstask.cancel(); //here I want to cancel, I need to check this condition every cycle, but it gives me that variable may not be initialized, how to cancel it here ?
    10.  
    11. }
    12. }
    13. }, 20L, (20*runtime) + 7*20L);
    14.  
     
  12. Offline

    The_Doctor_123

    Welite
    Declare progresstask as null, then initialize it. That will allow you to cancel the task.
     
  13. Offline

    Welite


    I tried this, but it wrote that I should change BukkitTask to final but when I do it then I cannot initialize it.
     
  14. Offline

    The_Doctor_123

    Welite
    I'm not sure if it is the best solution, but you could declare a private variable at the top of your class.
    Code:
    private volatile BukkitTask progresstask = null;
    Edit: Ehh.. That wouldn't work so hot if you had multiple tasks running at the same time.
     
  15. Offline

    fireblast709

    Welite (@The_Doctor_123) Use a BukkitRunnable. This
    Code:java
    1. final BukkitTask progresstask = Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() {
    2. @Override
    3. public void run()
    4. {
    5. //some code
    6. if (status.equals("lobby"))
    7. {
    8. progresstask.cancel(); //here I want to cancel, I need to check this condition every cycle, but it gives me that variable may not be initialized, how to cancel it here ?
    9. }
    10. }
    11. }, 20L, (20*runtime) + 7*20L);
    would be
    Code:java
    1. new BukkitRunnable()
    2. {
    3. @Override
    4. public void run()
    5. {
    6. //some code
    7. if (status.equals("lobby"))
    8. {
    9. // Yay, cancelling from within a BukkitRunnable
    10. this.cancel();
    11. }
    12. }
    13. }.runTaskTimer(plugin, 20L, (20*runtime) + 7*20L);
    They still return BukkitTasks, in case you need to cancel them from another point.

    I am amazed that so little people know about BukkitRunnables :confused:
     
Thread Status:
Not open for further replies.

Share This Page