java - 每 x 分钟为每个玩家重复一次任务

标签 java minecraft bukkit

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

相关文章:

c# - 如何将这个使用 XPath 的简单 C# 方法转换为 Java 方法?

java - 如何在java中检测我的程序是int的用户

minecraft - 尝试使用 MCP 反编译 Minecraft 1.12 时出现巨大错误

java - 掉落物已被清除,但仍在掉落

java - 检查 HashMap 中的列表是否包含 2 个值并且仅包含这 2 个值

Java 泛型的好奇心

java - 执行包含 Java 多行的 ".bat"文件

java - 如何使用noteblockapi bukkit?

mysql - SQLite/MySQL 大表与多个小表?

java - Process.getOutputStream() 不起作用?