Pisces_MZ
Minecraft 插件开发:ThePit 任务系统与 CPS 显示修复全记录

Minecraft 插件开发:ThePit 任务系统与 CPS 显示修复全记录

项目背景

ThePit 是一个 Minecraft 竞技 PvP 竞技场插件,运行在 1.20.1 Arclight(Forge+Bukkit 混合端)上。今天修复了三个核心问题:CPS 显示异常、任务系统无法触发、数据库访问权限错误。

技术栈

  • 语言: Java 17
  • 服务端: Arclight 1.20.1 (Forge + Bukkit)
  • 构建工具: Gradle 8.1.1
  • 数据库: SQLite / MySQL (HikariCP 连接池)
  • 依赖库: Paper API, ProtocolLib 5.2.0, PlaceholderAPI 2.11.5

问题一:CPS 显示为 0

玩家无论如何点击左键,计分板上的 CPS 始终显示为 0。

原始代码使用 Bukkit 的 PlayerInteractEvent 监听左键点击,但 Arclight 混合端上此事件触发不可靠。Forge 和 Bukkit 的事件系统存在兼容性问题。

解决方案:ProtocolLib 数据包监听

使用 ProtocolLib 直接监听客户端的手臂挥动数据包(ARM_ANIMATION),绕过 Bukkit 事件系统:

public class CPSListener implements Listener {
   public CPSListener(Plugin plugin) {
      ProtocolLibrary.getProtocolManager().addPacketListener(
         new PacketAdapter(plugin, ListenerPriority.NORMAL, 
                          PacketType.Play.Client.ARM_ANIMATION) {
            @Override
            public void onPacketReceiving(PacketEvent event) {
               Player player = event.getPlayer();
               if (player != null) {
                  CPSManager.recordClick(player);
               }
            }
         }
      );
   }
}

ARM_ANIMATION 对应 ServerboundSwingPacket,每次玩家挥动手臂都会发送,在所有服务端类型上都可靠。


问题二:任务系统无法触发

  • 任务界面只显示日常任务,周任务标题占用了错误的槽位
  • 没有事件监听器连接游戏事件到任务进度
  • 任务进度只存在内存中,重启丢失

解决方案

1. 事件监听器:创建 QuestListener,使用 MONITOR 优先级确保在金币发放和连杀更新之后执行。连杀任务延迟 1 tick 读取,避免数据竞争。

@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerKill(PlayerRespawnEvent event) {
    Player killer = event.getPlayer().getKiller();
    if (killer != null) {
        questManager.updateQuestProgress(killer, QuestType.KILL_PLAYERS, 1);
        Bukkit.getScheduler().runTaskLater(plugin, () -> {
            int streak = new PlayerStreak().getStreak(killer);
            questManager.setProgress(killer, "weekly_streak_5", streak);
        }, 1L);
    }
}

2. 数据库持久化:使用 PreparedStatement 和 UUID 关联存储任务进度。

CREATE TABLE ThePitQuests (
    Player varchar(30), UUID varchar(50), QuestID varchar(50),
    Progress INT(11), LastResetDay INT(11),
    LastResetWeek INT(11), LastResetYear INT(11)
);

3. 自动重置:每次读取进度时检查日期/周数,过期自动重置。日任务每天重置,周任务每周重置,无需定时任务。

事件优先级

  1. GlobalEventsHIGHEST:发放金币
  2. PlayerStreak默认:更新连杀数
  3. QuestListenerMONITOR:更新任务进度

问题三:数据库反射访问错误

java.lang.IllegalAccessException: class QuestManager cannot access 
a member of class SQLite with modifiers "private"

反射访问私有字段 connection 时缺少 setAccessible(true)。Java 安全机制默认禁止访问私有成员。

Field field = SQLite.getInstance().getClass()
    .getDeclaredField("connection");
field.setAccessible(true);  // 关键修复
return (Connection) field.get(SQLite.getInstance());

总结

  • CPS:ProtocolLib 数据包监听解决混合端兼容性
  • 任务系统:事件监听 + 数据库持久化 + 按需自动重置
  • 数据库:反射权限修复 setAccessible(true)

项目已可部署使用,后续可考虑 QuestManager 单例化和连接池优化。

本内容采用
CC BY-SA 4.0 协议授权 (可共享、改编,需署名并以相同方式共享)
作者: MoRan
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇