跳到主要内容

随机传送实现

那么让我们基本构想这个随机传送的功能。

首先确定传送范围为500*500,在测试中这个大小已经足够捏。

对于高度,在这个例子中不做详细计算,统一设置为100,在实际的实现上你还需要给玩家寻找安全的高度。

然后是,当玩家执行指令后,随机生成一个目标位置,然后向玩家发送Title显示"3秒后传送",使用调度程序在三秒后执行调度任务完成传送。

在传统Spigot服务端中也许会这样写:

        Random random = new Random();
Location target = player.getLocation().set(random.nextInt(500),100,random.nextInt(500));
player.sendTitle("三秒后传送","...");
Bukkit.getScheduler().runTaskLater(this, new Runnable() {
@Override
public void run() {
player.teleport(target);
}
},60L);

Folia中应该改成什么样呢?

        Random random = new Random();
Location target = player.getLocation().set(random.nextInt(500),100,random.nextInt(500));
player.sendTitle("三秒后传送","...");
player.getScheduler().runDelayed(this, new Consumer<ScheduledTask>() {
@Override
public void accept(ScheduledTask scheduledTask) {
player.teleportAsync(target);
}
}, new Runnable() {
@Override
public void run() {
System.out.println("错误:玩家不存在!");
}
}, 60L);

如上的代码便是一个简单的实现!效果如下:

看! 传送后的坐标在463 100 154,实现了功能捏!

player.getScheduler()是什么

这是Folia提供的EntityScheduler ,与RegionScheduler的原理类似,只不过把加载区域换成了实体,它适用执行有关实体的传送、伤害等操作。我们注意到,样例中传入了一个Runnable对象,它有什么用呢? 如果你看过一些Bukkit教程,你是否还记得在那些教程中会提到,如果一个事件、一个调度程序执行的时候玩家实体不存在了应该怎么办?

这个Runnable就是用来解决这个问题的。当调度程序执行时,entity.getScheduler() 获得的entity实体如果消失了,也许会产生一些奇妙的后果。

例如当我执行命令后直接退出游戏, 后台会输出预设的信息。在设置妥当的情况下,这项功能能够解决在调度程序运行过程时玩家实体消失产生的问题。

[08:42:15 INFO]: 1badsobig joined the game
[08:42:15 INFO]: 1badsobig[/127.0.0.1:51943] logged in with entity id 304
[08:42:18 INFO]: 1badsobig issued server command: /tp
[08:42:19 INFO]: 1badsobig lost connection: Disconnected
[08:42:19 INFO]: [Folia-Test] [STDOUT] 错误:玩家不存在!
[08:42:19 INFO]: 1badsobig left the game

当然,你也可以直接传入null来忽视它!就像BukkitAPI中的那样!

对了,为什么不可以用上面的RegionScheduler 呢?

还记得吗?在这个服务端中,不同的区域之间就像一个个小的服务器,而传送难免会传送到其他的区域。显然,在传统Spigot服务端中也不能直接传送到另一个服务器的指定位置!

关于传送

这里我使用了player.teleportAsync();方法来传送玩家,这是Folia服务端提供的一个传送API。还记得吗,Spigot中不能异步调用实体传送方法,同时因为Folia服务器的多线程特点,传送需要独特实现方式,entity.teleport()在Folia服务端被禁用,应该用teleportAsync()来代替。

同时我们谈谈另一种传送,通过下界传送门。

当玩家进入下界传送门时,服务器需要对传送进行处理,首先会删除玩家实体,然后会在目的地搜索附近有没有对应的传送门,如果没有则会创建一个新的传送门,随后在目的地生成玩家实体。上文例子不同的是,这个传送过程插入了一个搜索传送门的过程,因此也许会有较为长的一段时间服务器内根本没有玩家的实体!所以,Bukkit中一些与传送门交互的事件在Folia中在一定程度上被"破坏"了,在使用对应事件时请稍加小心。