Bukkit Delayed Task Inside a For Loop

不想你离开。 提交于 2019-12-11 10:15:18

问题


I've been trying to make gun plugin for Bukkit, and I'm trying to build a burst fire feature. I have a for loop that contains a delayed task, and inside that delayed task is the code to create a bullet and all that. Theoretically, the code would add some bullets, wait one tick, and add some more bullets, wait one tick, etc until the for loop is done.

public void fire(final Player p, final Gun g) {
    for(int i=0; i<shotsPerBurst; i++) {
        Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
            public void run() {
                for(int i=0; i<bulletsPerShot; i++) {
                    Bullet b = new Bullet(p, g);
                    GunsV1.bullets.add(b);
                }
            }
        }, 1L);
    }
}

Eclipse demands that Player p and Gun g both be final, I don't know why, and when I try to run fire(p, g), nothing happens. How can I set up my code so the for loop will run with a delay of 1 tick between cycles?


回答1:


To resolve one question:

Eclipse demands that Player p and Gun g both be final, I don't know why

You are passing the Player p and the Gun g to an new Thread/new Runnable and Eclipse tells you that those 2 Object's shouldn't be modified or changed because the Thread/Runnable also uses these 2 Object's inside the run method (as you can see).

I would suggest you to write your issue directly in here: http://bukkit.org/forums/plugin-development.5/ because there are also developer which know more and in detail about the Bukkit Server for Minecraft.

I will try to find a solution that fit's your needs now - but maybe you already try to find a solution in the forum.

Found this link for you - it may help you a little bit: http://www.programcreek.com/java-api-examples/index.php?api=org.bukkit.scheduler.BukkitScheduler




回答2:


There's no easy way to run the for loop with a delay without freezing Bukkit's main thread. The best thing to do in this case is to use plugin.getServer().getScheduler().runTaskLater():

plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
  public void run(){
    //shoot the gun
  }
},1L);//run after 1 tick

But, if you use this, the gun will only fire one shot. To fix this, you should keep running the scheduler:

public static void runTask(){
  plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
    public void run(){
      //shoot the gun
      runTask(); //run the task again
    }
  },1L);//run after 1 tick
}

But this way, the gun will keep firing every tick, and never stop. So, you should count the number of times it has ran, and stop running the task once the number is reached:

public static void runTask(final int timesLeft){
  plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
    public void run(){
      //shoot the gun
      if(timesLeft > 0){
        runTask(timesLeft - 1); //run the task again after removing from the times left
      }
    }
  },1L);//run after 1 tick
}

So, in the end, your loop method could look something like this:

public static void fire(final Player player, final Gun gun, final int timesLeft){
  plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
    public void run(){
      Bullet bullet = new Bullet(player, gun);
      GunsV1.bullets.add(bullet);

      if(timesLeft > 0){
        fire(player, gun, timesLeft - 1); //run the task again after removing from the times left
      }
    }
  },1L);//run after 1 tick
}

and you could call it by using:

fire(player, gun, shotsPerBurst);



回答3:


After experimenting with some longer delays and looking at the spigot reference, I realized that the ticks of delay are not ticks until the next task, but until the runnable runs. Knowing this, I was able to use the for loop to increase the ticks of delay proportionally:

public void fire(final Player p, final Gun g) {
    for(int i=0; i<shotsPerBurst; i++) {
        Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
            public void run() {
                for(int i=0; i<bulletsPerShot; i++) {
                    Bullet b = new Bullet(p, g);
                    GunsV1.bullets.add(b);
                }
            }
        }, i*3);
    }
}

Now it runs each task three ticks after the previous one, and fires in a burst



来源:https://stackoverflow.com/questions/29463608/bukkit-delayed-task-inside-a-for-loop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!