简体   繁体   English

每位玩家每x分钟重复一次任务

[英]Repeating task every x minutes for every player

I am working on a Java/Spigot plugin for minecraft where every 15 minutes I'd like to send the player a message. 我正在为我的世界开发Java / Spigot插件,我希望每15分钟向播放器发送一条消息。 It needs to be every 15 minutes since they joined not every 15 minutes all together, so every player would be on a different timer. 需要每15分钟一次,因为他们并不是每15分钟才加入一次,因此每个玩家都将使用不同的计时器。

What I have tried 我尝试过的

@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);
}

but that is doing every 15 minutes since the server started. 但是自服务器启动以来,这每15分钟执行一次。 I can't find a way to do it for every player that won't lag the server if there are 50+ players online. 如果有50多个在线玩家,我无法找到一种方法来为每个不会落后于服务器的玩家做到这一点。

Edit: 编辑:

Second attempt 第二次尝试

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);
}

I don't know how to check if it's been 15 minutes 我不知道怎么检查了十五分钟

Scheduling a task per player is not a good idea, also why are you using an async task? 为每个玩家安排任务不是一个好主意,为什么还要使用异步任务? These are especially costly to setup and may led to unintentional behaviour unless you know what you're doing. 这些设置特别昂贵,除非您知道自己在做什么,否则可能会导致意外行为。 Always aim at using a sync task instead if possible. 如果可能,请始终以使用同步任务为目标。

For the least lag I'm using a single scheduler, called the global scheduler. 为了尽量减少延迟,我使用了一个称为全局调度程序的调度程序。

Listen for the PlayerJoinEvent , we need to know each player and when they joined. PlayerJoinEvent ,我们需要了解每个玩家以及他们何时加入。 I'm using a hashmap to store the player UUID as well as a long representing their join date. 我正在使用哈希图存储玩家UUID以及代表他们加入日期的长整数。

private HashMap<UUID, Long> map = new HashMap<UUID, Long>();

@EventHandler
public void onJoin(PlayerJoinEvent event) {
    map.put(event.getPlayer().getUniqueID(), Calendar.getInstance().getTime().getTime());
}

You can store the player name or even the player object instead, but UUIDs are most robust as they are consistent. 您可以存储播放器名称,甚至可以存储播放器对象,但是UUID最为稳定,因为它们是一致的。

Now we need to check if the hashmap is empty or not, this can be done right after setting values to the map: 现在我们需要检查哈希图是否为空,这可以在将值设置为映射后立即完成:

  • if the map isn't empty and the global scheduler isn't running, start it. 如果映射不为空并且全局调度程序未运行,请启动它。
  • if the map is empty and the scheduler is running, stop it. 如果映射为空并且调度程序正在运行,请停止它。

This makes it only run when necessary, reducing lag. 这使得它仅在必要时运行,从而减少了延迟。

In the scheduler we want to loop through all players in the map and compare their join date with the current date, if above 15 minutes, do something and set the player join date as the current date. 在排程器中,我们要遍历地图中的所有玩家,并将其加入日期与当前日期进行比较,如果超过15分钟,请执行一些操作并将玩家加入日期设置为当前日期。 This scheduler should preferably run as rarely as possible, but to achieve most accurate results, aim at around a second (20 ticks) 此调度程序最好应尽可能少地运行,但要获得最准确的结果,请瞄准大约一秒钟(20滴答)

I am not personally familiar with Bukkit, however, the documentation provides a getLastPlayed() method which should return the date when the user last was seen on the server. 我个人并不熟悉Bukkit,但是文档提供了getLastPlayed()方法 ,该方法应返回在服务器上看到用户的最后一次日期。 I believe you could use this date to calculate the delay in the BukkitScheduler , like this: 我相信您可以使用此日期来计算BukkitSchedulerdelay ,如下所示:

@SuppressWarnings("deprecation")
public static void setup()
{
    // calculate delay amount
    static long delay = somePlayer.getLastPlayed();
    // figure out remaining time post calculation
    delay = (System.currentTimeMillis() - delay) % 1200;
    // proceed with your code as before
    Bukkit.getScheduler().scheduleAsyncRepeatingTask(MyPlugin.getPlugin(), new BukkitRunnable()
    {
        public void run() {
            for (final String string : online.keySet()) {
                Utils.sendMessage(string, "It's been 15 minutes")
            }
        }
    }, delay, 1200L);
}

Note that I'm assuming 1200 ticks gives you the amount of time you want, but if not you can change that value after delay as well as in the modular arithmetic accordingly. 请注意,我假设1200滴答声会为您提供所需的时间,但是如果没有,您可以在delay后以及相应的模块化算术中更改该值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM