主菜单 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):
- 尾部空隙:若列表最大值
< Integer.MAX_VALUE,返回max + 1(O(n),无分配,且不会溢出)。 - 首部空隙:否则若最小值
> 1,返回min - 1。 - 内部空隙:否则复制 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) |
相关条目
- Credits 界面 - 按钮打开的目标界面
- GTNH Credits 配置 -
menu_button分区四项配置 - credits.json 数据文件 - 界面实际展示的数据来源