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
相关产品推荐
相关产品推荐

