问题
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