自定义建世界界面(GuiCreateCustomWorld)

基本信息

属性 值
所属 Default World Generator(modid defaultworldgenerator)
入口类 GuiCreateCustomWorld(继承原版 GuiCreateWorld)
源码 gui/GuiCreateCustomWorld.java:13
触发类 events/GuiEvents.java
注册时机 preInit,MinecraftForge.EVENT_BUS(DefaultWorldGenerator.java:28)

两处 GUI 拦截

GuiEvents 以 EventPriority.HIGHEST 监听 GuiScreenEvent.ActionPerformedEvent.Pre,做两件事:

# 界面 按钮 id 行为 行号
1 GuiSelectWorld(世界列表) 3 不走原版建世界流程,改为 new GuiCreateCustomWorld(currentScreen) 并 displayGuiScreen GuiEvents.java:20-27
2 GuiCreateWorld(建世界) 5 受 Lock World Generator 控制,可被吞掉 GuiEvents.java:29-36

拦截 #1 会先播按钮音效(行 24)再 setCanceled(true)(行 25), 因此与 #2 不同,锁定时没有音效。

构造函数做了什么

GuiCreateCustomWorld 继承原版 GuiCreateWorld,在构造阶段就把 默认世界生成器写死(GuiCreateCustomWorld.java:15-78):

  1. 反射取出父类的私有整型字段 field_146331_K 并 setAccessible(true) (行 19-20)。这是当前选中的世界类型索引。
  2. 先把 superflat 预设字段 field_146334_a 清空为 ""(行 22)。
  3. worldGenType 初值 0(行 24),遍历 WorldType.worldTypes:
    • 名字与 World Generator 配置匹配(忽略大小写) → 取 getWorldTypeID()(行 29-31)
    • 名字为 flat → 解析 Flat World Config 写入 field_146334_a(行 34-68)
  4. 用 field_146331_K.setInt(this, worldGenType) 回写,让 GUI 显示为已选中 (行 72)。

遍历对每个生成器都要求 getCanBeCreated() 为真(行 27)。

为什么必须用反射

field_146331_K 是原版 GuiCreateWorld 的私有字段, @SideOnly 且非 protected,子类无法直接访问。 mcmod.info 的 credits 写明 “Special thanks to amadornes for reflection help” ——反射方案即由此而来。field_146334_a 则是 protected, 子类可直接赋值,无需反射(行 22、67)。

已知源码问题

  • 字段名硬编码,映射变更即失效:"field_146331_K" 以字符串写死 (行 19)。1.7.10 的 MCP 映射一旦变化,getDeclaredField 抛 NoSuchFieldException,被最外层 catch (Exception ex) 吞掉(行 74-77), 只打两条 Log.fatal,整个默认生成器设置静默失效。 这是本 mod 最脆弱的耦合点。
  • 异常被完全吞掉:行 74-77 只 Log.fatal("Fatal Error:") + Log.fatal(ex),不重抛、不弹窗。玩家侧表现为「设置没生效」,无任何线索。
  • worldGenType 不 break:同名的多个 WorldType 会后者覆盖前者(行 29-32)。
  • GuiCreateCustomWorld 继承原版类,因此没有新增任何按钮; 本 mod 唯一的 UI 变化是世界列表里 id 3 的按钮被改道。 ⚠️ 该 id 在原版 GuiSelectWorld 中对应的按钮名无法从本仓库核实。
  • GuiEvents.java:38 有一行 // Log.error(event.button.id + ...) 处于注释状态,不参与运行;不能据此认为本 mod 会上报按钮 id。

相关条目