Вызов функции каждые 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, это когда у вас есть намерение остановить задачу в будущем.