You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Minecraft Spigot插件开发:为每位玩家设置独立15分钟重复消息任务

我来帮你解决这个每个玩家独立计时的消息推送问题!你之前的代码用了全局的重复任务遍历在线玩家,这会导致所有玩家同时收到消息,没法实现「从每个玩家加入服务器开始,每15分钟单独发消息」的需求。下面是正确的实现方案:

核心思路
  • 给每个玩家单独分配计时任务:玩家刚加入时启动专属的重复任务,计时从加入时刻开始算
  • 玩家离线时及时取消任务:避免内存泄漏,也不会给离线玩家无效发消息
具体代码实现

首先,我们需要一个Map来存储每个玩家对应的任务实例,方便后续取消:

import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class PlayerMessageListener implements Listener {
    private final JavaPlugin plugin;
    // 存储玩家UUID和对应的任务实例
    private final Map<UUID, BukkitRunnable> playerTasks = new HashMap<>();

    public PlayerMessageListener(JavaPlugin plugin) {
        this.plugin = plugin;
    }

    // 监听玩家加入事件,启动独立计时任务
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        UUID playerId = player.getUniqueId();

        // 创建专属的重复任务
        BukkitRunnable messageTask = new BukkitRunnable() {
            @Override
            public void run() {
                // 先检查玩家是否在线,避免给离线玩家发消息
                if (player.isOnline()) {
                    // 替换成你自己的消息发送逻辑
                    Utils.sendMessage(player, "这是你加入服务器后每15分钟收到的专属消息!");
                } else {
                    // 玩家离线了,取消任务并从Map移除
                    this.cancel();
                    playerTasks.remove(playerId);
                }
            }
        };

        // 调度任务:延迟0秒立即启动,之后每15分钟执行一次
        // 注意:Spigot的时间单位是游戏刻,1秒=20刻,15分钟=15*60*20=18000刻
        messageTask.runTaskTimer(plugin, 0L, 15 * 60 * 20L);

        // 将任务存入Map,方便玩家离线时取消
        playerTasks.put(playerId, messageTask);
    }

    // 监听玩家离开事件,取消对应任务
    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        UUID playerId = event.getPlayer().getUniqueId();
        BukkitRunnable task = playerTasks.remove(playerId);
        if (task != null) {
            task.cancel();
        }
    }
}
关键注意事项
  • 不要用异步任务发送玩家消息:和玩家交互的操作(比如发送消息)必须在主线程执行,所以用runTaskTimer而不是异步的scheduleAsyncRepeatingTask,避免线程安全问题
  • 务必清理任务:玩家离线时一定要取消任务并从Map中移除,不然会导致内存泄漏,还可能出现无效的任务执行
  • 任务内检查玩家状态:虽然我们会在玩家离开时取消任务,但保险起见,每次执行任务时还是检查一下玩家是否在线,防止极端情况(比如玩家突然断开连接但事件没触发)

最后,记得在你的插件主类里注册这个监听器:

@Override
public void onEnable() {
    getServer().getPluginManager().registerEvents(new PlayerMessageListener(this), this);
}

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:34:59