Вызов функции каждые 2 минуты

Я работаю над плагином для сервера Minecraft, который автоматически разбивает дыни для фермы дынь. Он проходит через все блоки в текущих чанках всех игроков и разбивает блоки, которые являются дынями. Сначала я пытался непрерывно вызывать эту функцию с помощью while петля в onEnable метод, однако это привело к задержке / отставанию сервера. Без while цикл (вызывая функцию только один раз из onEnable), плагин работал нормально. Каждый раз, когда я перезагружал сервер, функция запускалась, и все дыни ломались; поэтому я решил сделать таймер, который будет вызывать функцию каждые две минуты. По какой-то причине, сервер все еще не работает, даже с таймером, который я не понимаю

Вот мой код:

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;
    }
}

Редактировать: Вот как это выглядит в настоящее время...

    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

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

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

5 ответов

Ваш код застрял внутри while(running == true)

Я предлагаю вам использовать ScheduledExecutorService

Гораздо более понятное решение будет выглядеть так:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

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

Это будет вызывать ваш метод каждые 2 минуты. Также, если вы поддерживаете Java 8, то вы можете использовать следующий синтаксис:

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

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

Для вашей логики времени вы должны сделать следующее

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

Затем внутри вашей функции break melons просто вызовите ее в самом конце вашего метода вне цикла for и сделайте следующее

goTime = System.currentTimeMillis();

Переменная goTime действительно должна быть временем, когда вы в последний раз заканчивали ломать все дыни. Затем, когда вы сравниваете это время с текущим системным временем, вы проверяете, больше ли разница во времени между текущим временем и последним выполнением функции дыни, чем 120000 мс.

Правильным решением для этого является использование BukkitRunnable. Вы можете увидеть больше примеров в документации Bukkit

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.

Большинство других ответов используют BukkitRunnables и другие нативные библиотеки Java. Лучший способ сделать это - использовать задачу расписания с использованием Runnable, а не BukkitRunnable.

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

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

Приведенный ниже код использует рекомендуемый способ многократного выполнения простой задачи.

Причина, по которой вы не хотите использовать BukkitRunnables способом, рекомендованным в другом ответе, заключается в том, что он создает переменную, которая вызывается, а затем остается осиротевшей. Этот код использует встроенный анонимный внутренний класс, чтобы все было аккуратно и аккуратно, и в то же время дает вам тот же эффект.

Единственный раз, когда вы хотите использовать BukkitRunnable, а не просто обычный Runnable, это когда у вас есть намерение остановить задачу в будущем.

Другие вопросы по тегам