来点前戏:修改玩家脚下的方块
首先,我想设计一点特效。比如在随机传送前连续修改玩家脚下的方块三次,效果依次是钻石块、金块、铁块,间隔1秒。 在传统Spigot服务端中,可以写出如下的代码:
Block block = player.getLocation().add(0,-1,0).getBlock();
Material[] materials = {Material.DIAMOND_BLOCK,Material.GOLD_BLOCK,Material.IRON_BLOCK};
task = Bukkit.getScheduler().runTaskTimer(this, new Runnable() {
int i = 0;
@Override
public void run() {
block.setType(materials[i]);
i++;
if(i==3){
//取消任务
stop();
}
}
},0L,20L);
如果我直接在Folia服务端中测试这段调度程序,会发现它给我抛出了一个UnsupportedOperationException
,表示服务端不支持这样操作。那么我们应该怎么办呢?
这种情况下,我们可以使用Folia提供的RegionScheduler
!虽然没有主线程的概念,但是我们可以把这个区域的线程当作它自身的主线程!在传统的Spigot服务端中主线程管理了服务器内所有区块,而这个区域的线程大约只管理了附近九个区块,但是在实现的原理上是差不多的!同样的,通过这个方式获得的区域调度器只能操作它拥有区块内的方块,就像在传统Spigot中你无法直接操作别的服务器中某些方块,不是吗?
经过简单的修改我们得出了这样的代码
ScheduledTask task;
public void stop(){
task.cancel();
}
...
...
Block block = player.getLocation().add(0,-1,0).getBlock();
Material[] materials = {Material.DIAMOND_BLOCK,Material.GOLD_BLOCK,Material.IRON_BLOCK};
task = Bukkit.getRegionScheduler().runAtFixedRate(this, block.getLocation(), new Consumer<ScheduledTask>() {
int i = 0;
@Override
public void accept(ScheduledTask scheduledTask) {
block.setType(materials[i]);
i++;
if(i==3){
//取消任务
stop();
}
}
},1L,20L);
编译打包之后在Folia服务端测试,成功了! 脚下的方块实现了预期的变化。
ScheduledTask是什么东西啊?
由于不再使用BukkitAPI提供的调度程序,这是Folia添加的一个BukkitTask替代品。
ScheduledTask就像BukkitTask一样,同样作为调度管理器的返回值,你可以像BukkitTask一样调用它的cancel()
方法来中止调度程序的运行,就像例子中的那样。
为什么上面写的延迟为0L,下面却写1L?
FoliaAPI规定了有关区块、实体的调度的延迟都需要大于零,毕竟调度程序的运行时间是"下一tick"。
RegionScheduler()是什么?
Bukkit.getRegionScheduler()是Folia提供以获得RegionScheduler
的方法,这个调度需要传入一个Location,执行该Location所在区域相关的任务,其主要有三种主要方法:
run(Plugin plugin, Location location, Consumer<ScheduledTask> task)
runDelayed(Plugin plugin, Location location, Consumer<ScheduledTask> task,long delayTicks)
runAtFixedRate(Plugin plugin, Location location, Consumer<ScheduledTask> task, long initialDelayTicks, long periodTicks);
你可以把它们理解为Bukkit中的runTask、runTaskLater、runTaskTimer!
Consumer<ScheduledTask> task
是一个方法,需要传入以ScheduledTask类参数并无返回值的方法。
这里是不同的写法:
Bukkit.getRegionScheduler().run(instance, Location, new Consumer<ScheduledTask>() {
//some field
@Override
public void accept(ScheduledTask scheduledTask) {
//code
}
});
//lambda
Bukkit.getAsyncScheduler().runNow(instance,scheduledTask -> {
//code
});
Bukkit.getRegionScheduler().run(XgpLottery.instance, player.getLocation(), scheduledTask -> Class.methed()));