主菜单 Credits 按钮

基本信息

属性 值
原版按钮类 net.noiraude.gtnhcredits.client.minecraft.gui.main_menu.CreditsButton(final,继承原版 GuiButton)
注入处理器 GuiMainMenuHandler(监听 GuiScreenEvent.InitGuiEvent.Post 与 GuiScreenEvent.ActionPerformedEvent.Post)
IMC 处理器 CmmActionHandler(监听 Custom Main Menu 的 ActionIMCEvent)
侧别限制 两者均 @SideOnly(Side.CLIENT)
注册时机 ClientProxy.init(ClientProxy.java:23-28)
按钮标签 lang 键 gui.main_menu.button.credits,英文值 Credits(en_US.lang:1)
注册的方块 / 物品 无 —— CreditsButton 是纯 GUI 控件,不是游戏内物品

功能

本 mod 提供两条互相独立的打开 Credits 界面的路径。

路径一:注入原版主菜单

GuiMainMenuHandler.onGuiInit 在每次 GuiMainMenu 完成初始化后,往 event.buttonList 追加一个 CreditsButton(GuiMainMenuHandler.java:22-27);点击后在 ActionPerformedEvent.Post 中比对按钮引用并打开界面(GuiMainMenuHandler.java:29-34)。

⚠️ 默认关闭。ClientProxy.init 只在 Config.getInstance().menuButtonEnabled 为 true 时才注册这个处理器(ClientProxy.java:24-26),而配置默认值是 false。原因是 GTNH 整合包由 Custom Main Menu 接管主菜单,原版按钮会与 CMM 按钮重复。

路径二:Custom Main Menu 的 sendIMC 动作

CmmActionHandler 无条件注册(ClientProxy.java:27),与 menuButtonEnabled 无关。它订阅 CMM 1.14.0+ 在按钮点击时抛出的 ActionIMCEvent,仅当 event.modId 等于 gtnhcredits 且 event.message 等于 openCredits 时打开界面(CmmActionHandler.java:18-25)。

该方法带 @Optional.Method(modid = "custommainmenu"):CMM 未安装时 FML 会在类加载前把它剥离,因此本 mod 不需要 CMM 就能运行。CMM 侧对 GTNH-Credits 无依赖(GTNH-Credits 对 CMM 是 compileOnly,dependencies.gradle:42)。

本 mod 不主动发送 IMC:全仓库 src/main/java 内对 FMLInterModComms / sendIMC 的 grep 结果为 0 匹配。IMC 事件由 CMM 抛出,本 mod 只是监听方。

CMM 侧配置

在 .minecraft/config/CustomMainMenu/mainmenu.json 的 buttons 对象中加入 credits 项(README.md 「Button configuration」节;仓库内的开发用样例见 src/dev/client/config/CustomMainMenu/mainmenu.json):

"credits": {
  "text": "Credits",
  "posX": 0,
  "posY": -160,
  "width": 150,
  "height": 20,
  "alignment": "column_bottom",
  "action": { "type": "sendIMC", "modid": "gtnhcredits", "message": "openCredits" }
}

text 也可直接写本 mod 的 lang 键 "gui.main_menu.button.credits" 复用翻译。

⚠️ CMM 会按当前 GUI 缩放在 mainmenu_auto.json / mainmenu_small.json / mainmenu_normal.json / mainmenu_large.json 中挑选实际生效的变体。只改 mainmenu.json 而当前缩放命中了某个变体文件,按钮不会出现 —— 需要把 credits 项加进每一个实际存在的变体(README.md 同节)。

数值

数值名 值 来源
按钮构造初始宽 / 高 200 × 20 px CreditsButton.java:38
实际最小宽度 200 px(max(计算值, 200)) CreditsButton.java:50-55
实际最小高度 20 px(max(图标高或字高 + 2×4, 20)) CreditsButton.java:56
默认 X / Y −18 / −18(负值 = 距右 / 距下边缘的边距) Config.java:40-53
内边距 水平 4 px、垂直 4 px CreditsButton.java:29-30
图标与文字间距 4 px(仅在有图标且文字非空时插入) CreditsButton.java:31,52
默认 X / Y 取值范围 −10000 – 10000 Config.java:40-53

按钮宽度按「4 + 图标宽 + (4)+ 文字宽 + 4」自适应,但不小于 200 px。当 menuButtonIcon 为空或贴图读取失败时宽度只由文字决定。按钮坐标不做屏幕边界钳制,配成绝对坐标时可能移出可视区(CreditsButton.java:57-60 仅按 >= 0 判断用哪种基准)。

按钮 ID 分配

CreditsButton.findFreeButtonId 从 event.buttonList 中挑一个未被占用的 id,永远不返回 0(0 被排除以避免哨兵值冲突),并按代价从低到高依次尝试三步(CreditsButton.java:84-107):

  1. 尾部空隙:若列表最大值 < Integer.MAX_VALUE,返回 max + 1(O(n),无分配,且不会溢出)。
  2. 首部空隙:否则若最小值 > 1,返回 min - 1。
  3. 内部空隙:否则复制 id 数组、排序、扫描相邻差值找第一个空洞(O(n log n),仅在 Integer.MAX_VALUE 确实被占用时才走到)。

三者皆失败则抛 IllegalStateException("No free button IDs available")。空列表返回 1。

交互

触发 行为
悬停按钮 文字变黄 0xFFFFA0;禁用态灰 0xA0A0A0;常态 0xE0E0E0;若按钮自带 packedFGColour 则以该色优先(CreditsButton.java:161-162)
左键 / 右键点击 打开 Credits 界面(GuiMainMenuHandler.java:29-34)
按钮图标 由 menu_button.icon 指定 domain:path,通过资源管理器 + ImageIO 读入;读取抛 IOException 时静默返回 null 并按无图标处理(CreditsButton.java:43-46,117-130)
图标纵向位置 按图标原始像素高度垂直居中于按钮(CreditsButton.java:141,155)

相关条目