包裹原版按钮
基本信息
| 属性 | 值 |
|---|---|
| 配置字段 | 按钮的 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 统一排版。
相关条目
- 按钮(Button) -
wrappedButton字段的完整说明 - 打开界面(openGui) - VersionChecker 之外的更新检查路径