首页 > 解决方案 > 为每个玩家每 x 分钟重复一次任务

问题描述

我正在为 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 分钟

标签: javaminecraftbukkit

解决方案


为每个玩家安排一个任务不是一个好主意,为什么还要使用异步任务?这些设置成本特别高,除非您知道自己在做什么,否则可能会导致意外行为。如果可能,请始终以使用同步任务为目标。

为了最小的延迟,我使用了一个称为全局调度程序的调度程序。

监听PlayerJoinEvent,我们需要知道每个玩家以及他们何时加入。我正在使用哈希图来存储玩家 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 设置值后立即完成:

  • 如果地图不为空且全局调度程序未运行,请启动它。
  • 如果地图为空且调度程序正在运行,则停止它。

这使它仅在必要时运行,从而减少延迟。

在调度程序中,我们要循环遍历地图中的所有玩家并将他们的加入日期与当前日期进行比较,如果超过 15 分钟,请执行一些操作并将玩家加入日期设置为当前日期。此调度程序最好尽可能少地运行,但为了获得最准确的结果,目标是大约一秒(20 个滴答声)


推荐阅读