首先,这是与Minecraft/Bukkit相关的,但我相信我的问题不是Bukkit特有的,只是忽略了我认为(我希望)的一些小问题。
在我的代码的最底部是一个randomDelay
和randomPeriod
。run()
函数基于这两个变量以给定的间隔重复运行。我不知道如何在可运行程序启动后动态更改这些。我想让可运行的每个周期的长度不同,但问题是一旦run()
函数开始,它似乎就使用了分配的第一个值。
package code.malon;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
public final class RandomResponse extends JavaPlugin {
Random rand = new Random();
int min = 20;
int max = 200;
long randomDelay = rand.nextInt((max - min) + 1) + min;
long randomPeriod = rand.nextInt((max - min) + 1) + min;
public void onEnable() {
BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
@Override
public void run() {
randomDelay = rand.nextInt((max - min) + 1) + min;
randomPeriod = rand.nextInt((max - min) + 1) + min;
}
}, randomDelay, randomPeriod);
}
}
让我们递归!哦,是的!
您的代码不是动态的,因为当RandomResponse
由Bukkit的PluginClassLoader
构造时,您初始化felds。这将创建一个new Random()
,生成一次随机值,并为"randomDelay
"安排延迟。这不是动态的。让我们用一个小黑客来解决这个问题:
public final class RandomResponse extends JavaPlugin {
final Random rand = new Random();
final int min = 20;
final int max = 200;
// I made these final for arbitrary reasons.
private RandomResponse randomResponse;
@Override
public void onEnable() {
randomResponse = this; // To use in anonymous class.
// The delay should be random, so we compute it within onEnable() method.
// We do not leave it in the class because then it's initialized by constructing.
long randomDelay = rand.nextInt((max - min) + 1) + min;
getServer().getScheduler().runTaskLater(this, new Runnable() {
@Override
public void run() {
/*
* Stuff to do
*/
// Call itself again some time later.
long randomDelay = rand.nextInt((max - min) + 1) + min;
getServer().getScheduler().runTaskLater(randomResponse, this, randomDelay);
}
}, randomDelay);
}
}
请注意,scheduleSyncRepeatingTask
在开始运行后不能更改任务的周期长度。因此,您必须递归调用。要允许取消并重新运行任务,请使用以下命令:
BukkitTask task;
void runTask() {
cancelTask();
task = getServer().getScheduler().runTaskLater(this, new Runnable() {
@Override
public void run() {
/*
* Stuff to do
*/
// Call itself again some time later.
long randomDelay = rand.nextInt((max - min) + 1) + min;
task = getServer().getScheduler().runTaskLater(randomResponse, this, randomDelay);
}
}, randomDelay);
}
void cancelTask() {
if (task != null) try {
task.cancel();
} catch(Throwable ex) {
// Ignore.
}
}
您可能没有想到,您可能希望使用BukkitRunnable
,而不是java.lang
中的Runnable
类。
将周期设置为每个刻度。
Task task = new Task();
task.runTaskTimer(Plugin, 1L, 1L);
然后使用索引,并在每次达到随机延迟时将其重置。
public class Task extends BukkitRunnable() {
private Random random = new Random();
private int index;
public Task() {
setRandom();
}
@Override
public void run() {
if (index == delay) {
// Work goes here
setRandom();
} else {
index++;
}
}
private void setRandom() {
index = random.nextInt(201) + 20;
}
}
虽然使用Bukkit API无法做到这一点,但您可以在CraftBukkit和Reflection的帮助下动态更新任务的周期。
public class TaskUtil {
public static Field CRAFTTASK_PERIOD;
static {
try {
CRAFTTASK_PERIOD = CraftTask.class.getDeclaredField("period");
CRAFTTASK_PERIOD.setAccessible(true);
} catch (Exception e) {
e.printStackTrace()
}
}
public static void updateTaskPeriod(int id, long period) {
CraftScheduler scheduler = (CraftScheduler) Bukkit.getScheduler();
scheduler.getPendingTasks().forEach(task -> {
if (task.getTaskId() == id) {
try {
CRAFTTASK_PERIOD.setLong(task, period);
} catch (Exception e) {
e.printStackTrace()
}
}
});
}
}
您还可以更进一步,通过利用Reflection从调度器中获取排队任务,完全消除CraftBukkit依赖关系。