Custom Main Menu
[!INFO] Git Commit:
fed2e4b(tag1.14.1,2026-04-27)| MC 1.7.10 / Forge
用 JSON 完全重定义 Minecraft 主菜单的纯客户端 GUI 配置 mod。没有方块、没有物品、没有实体——它的全部"内容"就是一套 GUI 元素类型、8 种按钮动作、一套配置文件机制,外加给其他 mod 用的一个事件接口。
| 属性 | 值 |
|---|---|
| modid | ⚠️ custommainmenu(CustomMainMenu.java:25,gradle.properties:10)——与本 wiki 分类名 custom-main-menu 不一致 |
| 显示名 | Custom Main Menu(CustomMainMenu.java:26) |
@Mod 类 |
lumien.custommainmenu.CustomMainMenu(全客户端,无 @SideOnly 注解但只注册客户端事件) |
| 资源命名空间 | assets/custommainmenu/ |
| 配置文件目录 | <.minecraft>/config/CustomMainMenu/*.json |
| Java 源文件 | 52 个,全部在 src/main/java/lumien/custommainmenu/ |
| 随包资源 | 3 张贴图 + 1 份默认配置(无 lang 文件、无 mcmod 之外的资源包) |
核心设计
<mc>/config/CustomMainMenu/*.json
↓ ConfigurationLoader.load()(遍历所有 .json,文件名=界面名)
GuiConfig.load() ← 解析 images / buttons / texts / other 四段
↓ GuiCustom(每个界面一个实例)
CMMEventHandler.openGui ← 反射替换 GuiMainMenu
↓
GuiCustom.drawScreen ← Panorama → Background → Image → SplashText → Text → Button
三类可扩展点:
| 层 | 内容 | 数量 |
|---|---|---|
| 视觉元素 | GUI 元素 | 7 种 |
| 交互动作 | 按钮动作 | 8 种 |
| 配置机制 | 配置系统 | 8 项 |
GUI 元素
可放在 images / buttons / texts / other 四段里的全部可视元素类型。
- 按钮(Button) -
buttons段条目,7 种渲染/交互路径 - 文本(Text) -
texts段条目,支持多行与缩放 - 图片(Image) -
images段条目,静态图或轮播 - 背景(Background) -
other.background,4 种缩放模式 - 全景图(Panorama) -
other.panorama,6 面立方体 + 可选模糊 - 轮播(Slideshow) - 背景与图片共用的淡入淡出实现
- 飘字(SplashText) -
other.splash-text,逐行随机
按钮动作
action.type 的全部 8 个取值,由 GuiConfig.getWantedAction(GuiConfig.java:389-420)分发。
| 动作 | 效果 | 是否离开游戏进程 |
|---|---|---|
| 打开界面(openGui) | 跳转到原版 / FML / 其他 mod / 自定义界面 | 否 |
| 打开链接(openLink) | 三按钮确认框后用系统浏览器打开 | 是 |
| 加载世界(loadWorld) | 直连指定存档,跳过选关界面 | 否 |
| 连接服务器(connectToServer) | 直连指定 IP,跳过服务器列表 | 否 |
| 打开文件夹(openFolder) | 资源管理器打开 .minecraft 内的目录 |
是 |
| 退出游戏(quit) | Minecraft.shutdown() |
是 |
| 重载配置(refresh) | 重读全部 JSON,可选刷新游戏资源 | 否 |
| 发送 IMC(sendIMC) | 在 Forge 事件总线上抛 ActionIMCEvent |
否 |
配置系统
- 配置文件格式 - 目录、命名、四个顶层段、数组即随机
- GUI 缩放变体 -
_small/_normal/_large/_auto文件名后缀 - 锚点系统(Alignment) - 10 个内置锚点 + 自定义锚点
- 文本来源(IText) -
web:/file:/ 本地化键 / 字面量 - 贴图来源(ITexture) -
web:URL 贴图 /ResourceLocation - 占位符替换 - 7 个静态 + 2 个动态占位符
- 重载与错误处理 - 热重载、失败回滚、5 秒红字提示
- IMC 事件接口 - 唯一对外编程接口
热键
- 重载配置热键 - LWJGL 键码 29+19,裸轮询不经
KeyBinding系统
特殊机制
本 mod 没有的内容
以下维度经 grep 确认零命中,因此不建对应目录:
| 维度 | grep 证据(在 src/main/java/ 下) |
|---|---|
| 方块 / 物品 / TileEntity | registerBlock 0、registerItem 0、registerTileEntity 0、extends Block 0、extends Item 0 |
| 实体 | registerEntity 0、extends Entity 0 |
| 附魔 / 药水效果 | Enchantment 0、PotionEffect 0 |
| 维度 / 世界生成 | registerDimension 0、WorldProvider 0、WorldGenerator 0 |
| 群系 / 结构 | BiomeGen / Biome 0、世界生成 0 |
| 成就 | Achievement 0 |
| 指令 | addChatCommand 0 |
| 合成配方 | IRecipe / CraftingRecipe 0 |
| 多方块 | Multiblock / TileMultiblock 0 |
| 本地化 | 无 assets/*/lang/*.lang(src/main/resources 下仅 3 张贴图 + mainmenu_default.json + mcmod.info) |
本 mod 也没有
KeyBinding注册(grep -rn "KeyBinding" src/→ 0),唯一的键盘交互是 重载配置热键 的裸 LWJGL 键码轮询。
已知源码缺陷与矛盾
| # | 问题 | 位置 |
|---|---|---|
| 1 | schema 与代码的段名冲突:schema 写 labels,代码只认 texts,且 get("texts") 无判空 → 用 schema 的名字写文件必崩 |
mainmenu.schema.json:591 vs GuiConfig.java:220 |
| 2 | 主菜单自身 background 写 synced: true 必崩:addGui 在 load() 之后执行,此时 getGUI("mainmenu") 返回 null |
GuiConfig.java:184-186 + Config.java:29 + ConfigurationLoader.java:64,79 |
| 3 | 四个顶层段(images/buttons/texts/other)全部无判空硬读,缺任一即启动崩溃 |
GuiConfig.java:210,220,230,115 |
| 4 | TextURL 对可变 String 值加锁且字段无 volatile,跨线程可见性无保证 |
TextURL.java:30-36 + LoadStringURL.java:44-47 |
| 5 | openLink 用 equals(大小写敏感),其余 7 个动作用 equalsIgnoreCase |
GuiConfig.java:391 |
| 6 | getStringPlease 对任意数组字段随机取值(不只飘字),且每次调用 new Random() |
GuiConfig.java:368-379 |
| 7 | fadeDuration = 0 会在 getAlphaFade 除零 |
Slideshow.java:44 |
| 8 | 背景 image 字段无判空硬读,与 slideshow 分支不构成真正的二选一 |
GuiConfig.java:177 |
| 9 | #mcpversion# 依赖反射 Forge 私有字段 Loader.mcpversion,GTNH 改名即 NPE |
StringReplacer.java:35-41 |
| 10 | #mcversion# 硬编码字面量 "1.7.10",不读实际 MC 版本 |
StringReplacer.java:24 |
| 11 | schema 的 openGui 枚举漏 4 个代码支持的键(options.ressourcepacks/options.shaderpacks/options.broadcast/mainmenu),且未说明 custom. 前缀 |
mainmenu.schema.json vs ActionOpenGUI.java |
| 12 | schema 把 alignments 画在 other 段,代码从顶层读 |
mainmenu.schema.json vs GuiConfig.java:98 |
| 13 | schema 声明的 version 字段代码从不读取 |
mainmenu.schema.json vs GuiConfig.load |
| 14 | 快捷键热键无边沿检测,按住即每 tick 全量重载 JSON | GuiCustom.java:458-464 |
| 15 | 未识别的原版按钮只打 DEBUG 日志(控制台默认不可见) | CMMEventHandler.java:86-89 |
| 16 | ActionConnectToServer.serverName 声明后从不赋值也从不读取(死字段) |
ActionConnectToServer.java:11 |
| 17 | TextureURL.load() 无任何调用点(死代码),实际走 LoadTextureURL 线程 |
TextureURL.java:35-53 |
| 18 | Text.setLink() 无任何调用点(死代码) |
Text.java:54-56 |
| 19 | options.ressourcepacks 是拼写错误的兼容别名,与正确拼写并存 |
ActionOpenGUI.java:60-61 |
| 20 | 字段 ichBinEineSlideshow(德语"我是一个轮播")是作者个人命名混入公共配置模型 |
Background.java:15、Image.java:16 |