Calling a function every 2 minutes

折月煮酒 提交于 2021-01-28 05:56:59

问题


I'm working on a plugin for a Minecraft server which automatically breaks melons for melon farms. It loops through all the blocks in all players' current chunks, and breaks the blocks that are melons. At first, I attempted to continuously call this function with a while loop in the onEnable method, however that caused the server to time/lag out. Without the while loop (only calling the function once from the onEnable), the plugin worked fine. Every time I reloaded the server, the function would run and all melons would be broken; so I decided to make a timer that would call the function every two minutes. For some reason, the server still times out, even with the timer, which I don't understand

Here's my code:

package me.spigot.itiurray.main;

import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

public class Main extends JavaPlugin {
    private long goTime = 0;

    @Override
    public void onEnable() {
        getLogger().info("MelonDrop has been enabled.");
        startBreakWithInterval();
    }

    private void breakMelons() {
        for (Player player : Bukkit.getOnlinePlayers()) {
            Chunk chunk = player.getLocation().getChunk();

            int x = chunk.getX() << 4;
            int z = chunk.getZ() << 4;

            for (int xx = x; xx < x + 16; xx++) {
                for (int zz = z; zz < z + 16; zz++) {
                    for (int yy = 0; yy < 256; yy++) {

                        Block block = chunk.getBlock(xx, yy, zz);

                        if (block.getType().equals(Material.MELON_BLOCK))
                            block.breakNaturally();

                        goTime = System.currentTimeMillis() + 120000;
                    }
                }
            }
        }
    }

    private void startBreakWithInterval() {
        boolean running = true;

        while (running == true) {
            if (System.currentTimeMillis() >= getGoTime())
                breakMelons();
        }
    }

    private long getGoTime() {
        return goTime;
    }
}

Edit: Here's what it currently looks like...

    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

    @Override
    public void onEnable() {
        getLogger().info("MelonDrop has been enabled.");    

        scheduledExecutorService.scheduleWithFixedDelay(() -> breakMelons(), 
2, 2, TimeUnit.MINUTES);
    }

回答1:


Your code is stuck inside the while(running == true)

I suggest you to use a ScheduledExecutorService




回答2:


For your time logic you should do the following

if(System.currentTimeMillis() - getGoTime() >= 120000)
{
    breakMelons();
}

Then inside your break melons function just call it at the very end of your method outside your for loop and do the following

goTime = System.currentTimeMillis();

The goTime variable should really just be the time at which you last completed breaking all the melons. Then when you check that time against the current system time you check if the time difference between the current time and the last time you executed the melon function is greater than 120000ms.




回答3:


A much clearer solution would look like this:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run() {
        breakMelons()
    }
}, 2, 2, TimeUnit.MINUTES);

This will be calling your method each 2 minutes. Also if you support java 8 then you could use the following syntax:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

scheduledExecutorService.scheduleWithFixedDelay(() -> breakMelons(), 2, 2, TimeUnit.MINUTES);



回答4:


The correct solution for this is to use a BukkitRunnable. You can see more examples at bukkit's documentation

JavaPlugin plugin;    //Your plugin instance    
Long timeInSeconds = 10;
Long timeInTicks = 20 * timeInSeconds;
new BukkitRunnable() {

@Override
public void run() {
    //The code inside will be executed in {timeInTicks} ticks.
   //After that, it'll be re-executed every {timeInTicks} ticks;
  //Task can also cancel itself from running, if you want to.

   if (boolean) {
       this.cancel();
   }

}
}.runTaskTimer(plugin, timeInTicks, timeInTicks);   //Your plugin instance, 
                                                   //the time to wait until first execution,
                                                  //the time inbetween executions.



回答5:


Most other answers use BukkitRunnables and other native Java libraries. The best way to do this would be using a schedule task using a Runnable, not a BukkitRunnable.

Bukkit.getScheduler().scheduleSyncRepeatingTask(myPlugin, new Runnable() {

    @Override
    public void run() {
        breakMelons();
    }
}, 0, 2400);

The code below uses the recommended way of running a simple task repeatedly.

The reason you do not want to use BukkitRunnables the way that is recommended in another answer is because it creates a variable that is called and then left orphaned. This code uses an inline anonymous inner class in order to keep everything neat and tidy, while also giving you the same effect.

The only time you want to use a BukkitRunnable rather than just a normal Runnable, is when you have an intention of stopping the task in the future.



来源:https://stackoverflow.com/questions/44529987/calling-a-function-every-2-minutes

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