我正在为 Minecraft 开发一个 Java/Spigot 插件,每隔 15 分钟我就会向玩家发送一条消息。需要每 15 分钟进行一次,因为他们并不是每 15 分钟一起加入一次,因此每个玩家都会使用不同的计时器。
我尝试过的
@SuppressWarnings("deprecation")
public static void setup()
{
Bukkit.getScheduler().scheduleAsyncRepeatingTask(MyPlugin.getPlugin(), new BukkitRunnable()
{
public void run() {
for (final String string : online.keySet()) {
Utils.sendMessage(string, "It's been 15 minutes")
}
}
}, 1L, 1200L);
}
但自服务器启动以来,每 15 分钟就会执行一次。如果有 50 多个在线玩家,我无法找到一种方法来为每个玩家做到这一点,并且不会落后于服务器。
编辑:
第二次尝试
private static boolean taskStarted = false;
private static HashMap<UUID, Long> map = new HashMap<UUID, Long>();
@EventHandler
public void onJoin(PlayerJoinEvent event) {
map.put(event.getPlayer().getUniqueId(), Calendar.getInstance().getTime().getTime());
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
map.remove(event.getPlayer().getUniqueId());
}
@SuppressWarnings("deprecation")
public static void startPowerTask() {
if(taskStarted)
return;
taskStarted = true;
Bukkit.getScheduler().scheduleSyncRepeatingTask(ServerCore.getPlugin(), new BukkitRunnable() {
@Override
public void run() {
for(UUID uuid : map.keySet()) {
long time = map.get(uuid);
if(time == ???)
Utils.sendMessage(uuid, "It's been 15 minutes");
}
}
}, 20, 20);
}
我不知道如何检查是否已经过了 15 分钟
最佳答案
为每个玩家安排一个任务并不是一个好主意,为什么要使用异步任务?这些设置的成本特别高,并且可能会导致无意的行为,除非您知道自己在做什么。如果可能的话,始终致力于使用同步任务。
为了最小化延迟,我使用单个调度程序,称为全局调度程序。
听PlayerJoinEvent ,我们需要了解每个玩家以及他们何时加入。我使用 hashmap 来存储玩家 UUID 以及代表其加入日期的 long。
private HashMap<UUID, Long> map = new HashMap<UUID, Long>();
@EventHandler
public void onJoin(PlayerJoinEvent event) {
map.put(event.getPlayer().getUniqueID(), Calendar.getInstance().getTime().getTime());
}
您可以存储玩家名称甚至玩家对象,但 UUID 最可靠,因为它们是一致的。
现在我们需要检查 HashMap 是否为空,这可以在为映射设置值后立即完成:
- 如果 map 不为空且全局调度程序未运行,则启动 它。
- 如果 map 为空并且调度程序正在运行,请停止它。
这使得它只在必要时运行,从而减少延迟。
在调度程序中,我们想要循环遍历 map 中的所有玩家,并将他们的加入日期与当前日期进行比较,如果超过 15 分钟,则执行某些操作并将玩家加入日期设置为当前日期。 该调度程序最好尽可能少地运行,但为了获得最准确的结果,目标是大约一秒(20 个刻度)
关于java - 每 x 分钟为每个玩家重复一次任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50196462/