delay in for loop

Discussion in 'Plugin Development' started by Vincent1468, Mar 29, 2013.

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

    Vincent1468

    Hello,

    I've got a question.
    I have a for loop and I want to add a delay to that. At the moment I do it like this:
    Code:
             for(Location loc : locs) {
                 try {
                 Thread.sleep(50);
    //Do something
            }
    
    But the Thread.sleep() lets the whole server sleep.
    So I've googled a bit and came out at Scheduler Programming.
    So my question is, how would I use my little loop with a delay using the scheduler?

    Thanks
     
  2. Offline

    chasechocolate

    BukkitRunnables.
     
  3. Offline

    Vincent1468

    Thanks but could you help me a little bit more?
    I extended BukkitRunnable, but where do I put my loop?
    In public void run()?
    And how to call the loop then?

    Thanks
     
  4. Offline

    LucasEmanuel

    If you want every iteration to be delayed, use a repeating task :)

    Example:
    Code:
    server.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
      public void run() {
        //do something
      }
    }, 20L, 20L);
    This will repeat once every 20 ticks (~1 second) :)
     
  5. Offline

    macguy8

    LucasEmanuel
    A BukkitRunnable is probably preferred as you can call cancel(); from inside the loop itself
     
  6. Offline

    LucasEmanuel

    Hmm, when did they add that? I havn't coded for bukkit since 1.4.6 :)
     
  7. Offline

    macguy8

    LucasEmanuel
    I don't know XD. Example usage would be something like..
    Code:
    new BukkitRunnable() {
    @Override
    public void run() {
    //Do stuff
    if (someReasonToCancelTask) {
    cancel();
    }
    }
    }.runTaskTimer(plugin, 20L, 20L);
     
  8. Offline

    LucasEmanuel

    macguy8
    Okey, i have some research to do then :)
     
  9. Offline

    dillyg10

    Simplest way (psudo code)
    for(i = 0; i < whatever; i++){
    scheduel(i*(delay), i*(delay));
    }
    If needed, I can write full code... but that should explain it pretty well
     
  10. Offline

    macguy8

    dillyg10
    I'm pretty sure a BukkitRunnable, as I posted above, would work best for this kind of stuff
     
  11. Offline

    dillyg10

    it could, but then you need to cancel the runnalbe, which means that you have to predict when the runnable is going to end, and cancle it. Which is more work than needs to be done... that's why I suggested that he use a for loop, then just use a delayed bukkit task, and caclulate the task via i * delay :0.
     
  12. Offline

    macguy8

    dillyg10
    Yeah I guess, but it's better to do a bit more math and have 1 scheduler running instead of 100s of them
     
  13. Offline

    dillyg10

    Same difference
    Repeating task just runs a scheduled task every x ticks.
     
  14. Offline

    macguy8

    dillyg10
    But, in your example you make one task for, say 5 ticks, then 10, then 15, etc. It's be better to just have a repeating task (which is pretty much what a BukkitRunnable is) than 100s of delayed tasks
     
  15. Offline

    dillyg10

    No difference between the 2...
     
  16. Offline

    macguy8

    dillyg10
    Picture it this way. I want to do 10 things, each 10 seconds apart.

    If I do it your way, I have one task waiting 10 seconds, one waiting 20, etc. so I have a total of 10 schedulers Bukkit has to keep track of.

    If I use a repeating task, or a BukkitRunnable, I have one task that loops, and I simply run cancel(); at the end. Bukkit now only has one task to run, making it more efficient.
     
  17. Offline

    Vincent1468

    Thanks for all the awnsers, but I had a for loop like this
    Code:
    for(Location loc : locs) {
    How would I add the locations again?
    locs is a list of Locations and I used loc now with thread.sleep.
     
  18. Offline

    macguy8

    Vincent1468
    What do you mean add again? I don't quite understand your post
     
  19. Offline

    Vincent1468

    Sorry I was a bit too fast with posting.
    But I've got it like this now:
    Code:
      for(final Location loc : locs) {
            
            Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
            public void run() {
                      try {      
     //Do Something
                            } catch (Exception exc) {
                         }
            }
           }, 20L, 20L);
     
            }
     
            List<Entity> entities = location.getWorld().getEntities();
                 Vector ownVector = player.getLocation().toVector();
                 for (Entity entity : entities) {
                 if(entity.getLocation().toVector().distance(ownVector) < 10) {
                 if(entity instanceof LivingEntity) {
                 if(entity instanceof Player) {                
                 } else {
                 world.strikeLightning(entity.getLocation());  
                 }
                 
                 }
                 }
     
            }
    But my problem is now that the lightning goes before the loop, how do I make it so that it comes after the loop?

    Thanks for your help by the way, I really appreciate it.
     
  20. Offline

    macguy8

    Vincent1468
    I'll explain a bit more how schedulers work.

    Thread.sleep (Don't use this in Bukkit) pauses the code, and then continues.

    Bukkit's Schedulers SCHEDULE it when you run that code, but doesn't wait for it to happen. Eg, You're just telling it "Hey, in 10 seconds do this", not "In 10 seconds do this, and THEN finish the rest of the code". If you want to code to happen after X seconds, you'll have to put it in the scheduled code. In this example, you'd just want to run the code where you strike lightning IN the scheduled code, not after you schedule it.
     
  21. Offline

    dillyg10

    ^I edited the code above, take a look @ what I did.
     
  22. Offline

    macguy8

    dillyg10
    That really didn't do anything... If he wanted the lightning after a delay, you have to put it INSIDE the delayed task, not after it.
     
  23. Offline

    Vincent1468

    macguy8
    dillyg10

    I've got it like this now, but now it's doing really weird.
    Code:
     for(int i =0; i < locs.size(); i++) {
    final Location lok = locs.get(i);
    Bukkit.getServer().getScheduler().runTaskLater(plugin, new Runnable() {
    public void run() {
    try {
    fplayer.playFirework(world, lok, FireworkEffect.builder().with(Type.BALL).withColor(Color.AQUA).build());
    } catch (Exception exc) {
    }
     
    }
    }, i * 20);
    if(i == 30) break; {
    List<Entity> entities = location.getWorld().getEntities();
    Vector ownVector = player.getLocation().toVector();
    for (Entity entity : entities) {
    if(entity.getLocation().toVector().distance(ownVector) < 10) {
    if(entity instanceof LivingEntity) {
    if(entity instanceof Player) {
    } else {
    world.strikeLightning(entity.getLocation());
    }
     
    }
    }
    }
    }
     
    }
    It first strikes the lightning, then very slow the fireworks.
    It's getting a bit confusing for me :(
    By the way macguy8, Thanks for the explanation on the schedulers, I now understand them :)
     
  24. Offline

    macguy8

    Vincent1468
    If you want the fireworks to happen at the same time as the lightning, just move the lightning code into the scheduler code
     
  25. Offline

    Vincent1468

    Thanks for your reply, but I want the lightning after the fireworks.
     
  26. Offline

    macguy8

    Vincent1468
    Oh! Then, you'll just want to schedule your fireworks, and then schedule one for (i + <Extra delay in seconds>) * 20 where you run the lightning
     
  27. Offline

    Vincent1468

    macguy8
    Thanks for your awnser, I now have this:
    Code:
            for(int i =0; i < locs.size(); i++) {
            final Location lok = locs.get(i);
            Bukkit.getServer().getScheduler().runTaskLater(plugin, new Runnable() {
            public void run() {
                      try {      
                        fplayer.playFirework(world, lok, FireworkEffect.builder().with(Type.BALL).withColor(Color.AQUA).build());
                            } catch (Exception exc) {
                         }
     
            }
            }, 50);
               Bukkit.getServer().getScheduler().runTaskLater(plugin, new Runnable() {
               public void run() {
                   List<Entity> entities = location.getWorld().getEntities();
                       Vector ownVector = p.getLocation().toVector();
                       for (Entity entity : entities) {
                       if(entity.getLocation().toVector().distance(ownVector) < 10) {
                       if(entity instanceof LivingEntity) {
                       if(entity instanceof Player) {                
                       } else {
                       world.strikeLightning(entity.getLocation());  
                       }
                       
                       }
                       }
                       } 
               }
               }, i + 2 * 20); 
            }
    It strikes the lightning, then the fireworks, is there any way to make the lightning go after the fireworks?
    Also, the fireworks all come at the same time, I don't want this, I want them to come after eachother. How would I do that?
     
  28. Offline

    dillyg10

    Edited your code
     
  29. Offline

    Vincent1468

    dillyg10
    Thanks, but when you activate it with that, the lightning comes, then fireworks and if you come close to a mob it keeps striking lightning.
    And am I correct that you only changed
    Code:
     }, i + 2 * 20);
    to
    Code:
     }, i + 2 * 20);
    which does basicly the same?
     
  30. Offline

    Omega Haxors

    Order of operation is pure linear within Java. The only exception is use of brackets.
    In your code you're adding I and 2 and then multiplying that by 20. His code he adds I and 40.

    Anyway, any word on how I would get a RepeatingSyncTask to stop repeating after some time? I tried cancel() like others have stated but I need to link it to a variable. I don't want to end the whole event, just the loop.
     
Thread Status:
Not open for further replies.

Share This Page