包裹原版按钮

基本信息

属性 值
配置字段 按钮的 wrappedButton(int)
实现类 lumien.custommainmenu.gui.GuiCustomWrappedButton(继承 GuiCustomButton)
生效界面 仅 mainmenu(GuiCustom.java:505)
已知按钮 ID 666(OpenEye)、404(VersionChecker)

目的

让 CMM 自定义主菜单接管其他 mod 注入到原版 GuiMainMenu 上的按钮——外观、位置、贴图全由配置决定,但点击行为转交回原按钮对象。

提取流程

CMMEventHandler 用反射 + 事件优先级把原版按钮"偷"出来(CMMEventHandler.java:24-34):

initGuiPostEarly (EventPriority.HIGHEST)
  若当前界面是名为 "mainmenu" 的 GuiCustom:
    event.buttonList = new ArrayList<>()     // 清空所有按钮
    反射把 event.gui 换成 GuiFakeMain(一个空壳 GuiMainMenu)

initGuiPost (EventPriority.LOWEST)
  若当前界面是 GuiFakeMain:
    遍历 buttonList,把所有非 GuiCustomButton 的按钮移出并按 id 存进 removedButtons
    再遍历 actualGui.getButtonList(),对每个 GuiCustomWrappedButton:
      b.init(removedButtons.get(b.wrappedButtonID))

⚠️ GuiFakeMain 的 initGui() 被覆写为空(GuiFakeMain.java:15),所以原版 GuiMainMenu 不会真的重建按钮——按钮列表是 CMM 在 InitGuiEvent.Post 阶段塞进去的。

点击转交

GuiCustom.actionPerformed(GuiCustom.java:504-522):

若按钮是 GuiCustomWrappedButton 且本界面名 == "mainmenu":
    wrapped.wrappedButton 为 null → 什么都不做
    否则:
        构造 GuiScreenEvent.ActionPerformedEvent.Pre(new GuiFakeMain(), 原按钮, [])
        若 post() 返回 true(被取消)→ return
        原按钮.func_146113_a(soundHandler)        // 播原版点击音
        构造并 post GuiScreenEvent.ActionPerformedEvent.Post(...)

即完整重放原版按钮的点击流程(Pre 可被其他 mod 取消),而不是直接调按钮的点击逻辑。

可见性同步

GuiCustomWrappedButton.drawButton 每帧从被包裹按钮同步状态(GuiCustomWrappedButton.java:21-29):

条件 enabled / visible
wrappedButton != null = 原按钮的 visible && enabled
wrappedButton == null 两者都 false(按钮消失)

所以原按钮隐藏时包装按钮也隐藏,不会留下一个点不动的空壳。

已知的按钮 ID

CMMEventHandler.initGuiPost 逐一比对被移除的按钮(CMMEventHandler.java:74-85),常量定义在 Reference.java:

ID 常量 目标 mod 用途
666 Reference.OPEN_EYE_BUTTON OpenEye 动画播放器切换按钮
404 Reference.VERSION_CHECKER_BUTTON VersionChecker 更新检查按钮

两者都用 Loader.isModLoaded(...) 探测,未安装则不识别。

⚠️ 除 666 与 404 外,所有被移除的原版按钮一律走 else 分支,只打一条 DEBUG 日志 "Found unsupported button, use a wrapped button to config this. (id)"(CMMEventHandler.java:86-89)——默认 DEBUG 级,控制台默认看不到。这意味着集成包若有第三方 mod 往主菜单注入按钮,用户配了 wrappedButton 后表面上什么都不发生,且无从排查。

与普通按钮的 ID 分配差异

按钮种类 分配方式
普通自定义按钮 从 6000 起递增(GuiCustom.java:121-128)
包装按钮 buttonId = wrappedButtonID(直接用原按钮 ID,GuiCustom.java:125)

因此 actionPerformed 用 button.id >= 6000 区分两者(GuiCustom.java:523)。

使用场景

整合包主菜单保留其他 mod(OpenEye 动画、VersionChecker 更新提示)的功能按钮,但由 CMM 统一排版。

相关条目