配置界面

基本信息

属性 值
工厂类 com.github.lunatrius.core.client.gui.GuiFactory
配置页 com.github.lunatrius.core.client.gui.GuiModConfig
模组列表改写 com.github.lunatrius.core.handler.GuiHandler
触发开关 ConfigurationHandler.replaceInGameConfig(默认 true)

本条目覆盖 3 个类,共同实现 @Mod 注解上 guiFactory = Reference.GUI_FACTORY 指向的整套 FML 配置界面。

GuiFactory implements IModGuiFactory

方法 实现
public void initialize(Minecraft minecraftInstance) 空方法体
public Class<? extends GuiScreen> mainConfigGuiClass() return GuiModConfig.class;
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() return null;
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) return null;

[!NOTE] 因为 mainConfigGuiClass() 恒返回非 null 的 GuiModConfig.class,GuiFactory 自身不会被 GuiHandler 从模组列表中剔除。runtimeGuiCategories() 与 getHandlerFor() 返回 null 表示本 mod 不提供运行时配置项。

GuiModConfig extends GuiConfig

成员 值
构造函数 public GuiModConfig(GuiScreen guiScreen)
父类第 2 参 getConfigElements() — 静态方法动态生成
父类第 3 参 Reference.MODID — 配置 GUI 的标题字符串
父类第 4 参 false — parentChanged
父类第 5 参 false — worldGenEnabled
父类第 6 参 GuiConfig.getAbridgedConfigPath(ConfigurationHandler.configuration.toString()) — 底部显示的文件路径

分类页生成逻辑

private static List<IConfigElement> getConfigElements() 遍历 ConfigurationHandler.configuration.getCategoryNames(),对每个分类名构造一个 ConfigElement,并对分类对象调用 setLanguageKey(Names.Config.LANG_PREFIX + ".category." + name)。

因此分类页完全由配置文件内容决定:手动往 LunatriusCore.cfg 里加一个分类,刷新界面后就会多出一页。当前默认产生 2 页,即 versioncheck 与 tweaks。

GuiHandler

事件订阅

成员 值
订阅方法 @SubscribeEvent public void onGuiOpen(final GuiOpenEvent event)
事件类型 net.minecraftforge.client.event.GuiOpenEvent
注册总线 MinecraftForge.EVENT_BUS(在 ClientProxy.registerTickers() 中注册)

行为

条件判断为 ConfigurationHandler.replaceInGameConfig && event.gui instanceof GuiIngameModOptions,满足时执行 event.gui = new GuiModConfigList(Minecraft.getMinecraft().currentScreen)。

[!WARNING] 这里没有调用 event.setCanceled(true),而是直接改写 event.gui 字段。GuiOpenEvent 本身是可取消事件,改字段是绕过取消机制直接替换目标界面。

私有内部类 GuiModConfigList extends GuiModList

项目 值
可见性 private static class
构造函数 public GuiModConfigList(final GuiScreen screen),内部 super(screen)

构造函数用反射取出 FML 模组列表并做过滤:

步骤 源码
1. 反射取字段 ReflectionHelper.findField(GuiModList.class, "mods")
2. 强转为列表 (List<ModContainer>) fieldMods.get(this)
3. 遍历并剔除 若 guiFactory == null || guiFactory.mainConfigGuiClass() == null 则 iterator.remove()
4. 取工厂 FMLClientHandler.instance().getGuiFactoryFor(mod)
5. 异常处理 catch (Exception e) → Reference.logger.error("Failed to tweak mod list!", e)

[!IMPORTANT] 效果是:FML 原生的模组列表页中,所有没有实现配置界面的 mod 会被隐藏。这正是 replaceInGameConfig 描述里「Replace the FML test config GUI with a working GUI」的实际含义——不是替换本 mod 的配置页,而是清理整个模组列表页。

[!NOTE] ReflectionHelper.findField 依赖 GuiModList 的私有字段名 mods。若 FML 改名,该反射会失败,但已被 try-catch 兜住,只会打一条 Failed to tweak mod list! 日志而不崩溃。

相关条目