Options Manager
基本信息
| 属性 | 值 |
|---|---|
| 界面类 | journeymap.client.ui.dialog.OptionsManager(OptionsManager.java),继承 JmUI |
| 控件工厂 | journeymap.client.ui.option.OptionSlotFactory(OptionSlotFactory.java) |
| 槽位描述 | journeymap.client.ui.option.SlotMetadata<T>(SlotMetadata.java:23),实现 Comparable<SlotMetadata> |
| 配置分类枚举 | journeymap.client.properties.config.Config.Category(Config.java:44) |
| 分类常量数 | 10 个声明,8 个实际建页 |
| 可调选项总数 | 95(等于全部 @Config 字段数) |
| 界面按钮数 | 约 24 |
| 打开方式 | UIManager.openOptionsManager()(UIManager.java:205) |
功能
Options Manager 是 95 个配置项的图形化编辑器。界面不硬编码任何选项——它用反射扫描所有 PropertiesBase 子类的 @Config 字段,按类型自动生成对应控件。
反射生成控件
OptionSlotFactory.buildSlots()(:136-207)是核心:
propertiesClass.getDeclaredFields()遍历当前类自己声明的字段(:144)- 跳过无
@Config注解的字段(:146) - 按字段类型分派控件(
:150-169):
| 字段类型 | 控件工厂方法 | 控件 |
|---|---|---|
AtomicBoolean |
getBooleanSlotMetadata() |
开关按钮 |
AtomicInteger |
getIntegerSlotMetadata() |
整数滑块 |
AtomicDouble |
getDoubleSlotMetadata() |
双精度滑块 |
AtomicReference + stringListProvider 非空 |
getStringSlotMetadata() |
下拉/循环列表 |
AtomicReference + 无 provider |
getEnumSlotMetadata() |
枚举循环按钮 |
- 未能识别的类型记 warn
Unable to create config gui for {}.{} using {}(:194-196) - 递归父类(
:200-206):若父类也是PropertiesBase子类,递归调用buildSlots()把父类的@Config字段并入同一张 map
第 5 步是 MapProperties(11 项)能被 FullMapProperties / MiniMapProperties / WebMapProperties 共享的原因——它们自身不重复声明这些字段,靠递归收集。
Inherit 的重映射
字段上的 category = Inherit 是占位符,两处被重写为实际分类:
| 位置 | 逻辑 |
|---|---|
buildSlots()(:180-184) |
读 config.category(),若为 Inherit 则换成传入的 inheritedCategory |
addSlots()(:115-118) |
同上,兜底处理 |
因此 MiniMapProperties 的 17 个 Inherit 字段,在 addSlots(mergedMap, Category.MiniMap1, miniMapProperties1) 时全部归入 MiniMap1 页签(OptionSlotFactory.java:43-48):
| 调用 | 配置实例 | 继承分类 |
|---|---|---|
addSlots(..., MiniMap1, ...) :43 |
getMiniMapProperties1() |
→ MiniMap1 页 |
addSlots(..., MiniMap2, ...) :44 |
getMiniMapProperties2() |
→ MiniMap2 页 |
addSlots(..., FullMap, ...) :45 |
getFullMapProperties() |
→ FullMap 页 |
addSlots(..., WebMap, ...) :46 |
getWebMapProperties() |
→ WebMap 页 |
addSlots(..., Waypoint, ...) :47 |
getWaypointProperties() |
→ Waypoint 页 |
addSlots(..., Advanced, ...) :48 |
getCoreProperties() |
→ Advanced 页 |
Cartography(18 项)与 WaypointBeacon(12 项)不走 addSlots 路径——它们由 CoreProperties / WaypointProperties 字段上显式标注的 category 决定,在 buildSlots() 内部分类。
8 个实际页签
| 页签 | 分类常量 | 选项数 | 语言键 |
|---|---|---|---|
| 小地图 1 | MiniMap1 |
17(继承 11 + 自身 6) | jm.config.category.minimap |
| 小地图 2 | MiniMap2 |
17(同上) | jm.config.category.minimap2 |
| 全屏地图 | FullMap |
20(继承)+ 1(themeName) |
jm.config.category.fullmap |
| Web 地图 | WebMap |
13(继承)+ 2 | jm.config.category.webmap |
| 路点 | Waypoint |
7 | jm.config.category.waypoint |
| 路点信标 | WaypointBeacon |
12 | jm.config.category.waypoint_beacons |
| 制图 | Cartography |
18 | jm.config.category.cartography |
| 高级 | Advanced |
19 | jm.config.category.advanced |
Config.Category 共声明 10 个常量(Config.java:46-55),其中 Inherit("") 是哨兵值(空语言键,不建页),Radar 无任何字段归属——因此实际建 8 页。详见 配置文件 的死代码说明。
排序与 master 标记
slotMetadata.setOrder(config.sortOrder())(:175)——注解的sortOrder决定页内顺序。CoreProperties的 4 个渲染距离显式设了sortOrder = 101–104(CoreProperties.java:92、:95、:98、:101)以保证连续排列SlotMetadata.isMasterPropertyForCategory()/setMasterPropertyForCategory()(SlotMetadata.java:96、:101)——对应注解的master = true。当前只有MiniMapProperties.enabled(jm.minimap.enable_minimap)与WebMapProperties.enabled(jm.webmap.enable)两项- 继承来的选项在下拉提示中标为"继承"(
OptionSlotFactory.java:99单独处理Category.MiniMap2)
本地化
两个静态辅助方法(OptionSlotFactory.java:209-224):
| 方法 | 逻辑 |
|---|---|
getName(Config) |
Constants.getString(annotation.key()) |
getTooltip(Config) |
读 key + ".tooltip";若读回仍等于 key 本身(说明语言文件没有该条目)则置 null 不显示提示 |
即语言文件缺少 .tooltip 条目时自动隐藏提示,不会显示裸 key。
界面结构
OptionsManager 的关键字段(:46-64):
| 字段 | 作用 |
|---|---|
openCategories |
静态 EnumSet<Config.Category>,记住上次打开的页签(:46) |
initialCategories |
本次要定位到的页签(可变参数) |
toolbars |
Map<Config.Category, List<SlotMetadata>> |
changedCategories |
记录被改动的页签,用于标记未保存 |
optionsListPane |
ScrollListPane<CategorySlot> 主体滚动区(:161) |
cartographyCategorySlot |
制图页签的引用,供特殊处理(:61、:218、:352) |
打开时可指定初始页签:UIManager.openOptionsManager(JmUI, Config.Category...)(UIManager.java:210)。界面加载时遍历 optionsListPane.getRootSlots() 定位并展开目标分类(:166-170)。
OptionsManager 还接管按键:previewMiniMap() 为真时把按键转发给 KeyEventHandler.onKeypress(true)(:590-594),使改小地图形状/位置时能实时预览。
数值
| 数值名 | 值 |
|---|---|
| 可调选项总数 | 95 |
| 实际页签数 | 8 |
| 声明的分类常量数 | 10(Inherit 为哨兵,Radar 无字段) |
| 控件工厂分支数 | 5(Boolean / Integer / Double / String / Enum) |
SlotMetadata 构造器数 |
6(:37、:42、:48、:53、:58、:63、:69 共 7 个重载) |
带 master = true 的选项 |
2(enable_minimap、webmap.enable) |
显式指定 sortOrder 的选项 |
4(渲染距离 min/max) |
| 界面按钮数 | 约 24 |
交互
| 触发 | 行为 |
|---|---|
| 点击选项按钮 | 立即写入对应 Atomic* 字段并 save() 落盘 |
| 打开界面 | 反射扫描 6 个配置实例生成控件;定位到 openCategories 记录的页签 |
| 改小地图形状/位置 | 实时预览(previewMiniMap() + onKeypress(true)) |
| 切换到 Cartography 页 | 触发 cartographyCategorySlot 特殊处理(:218、:352) |
| 编辑网格 | 进入 GridEditor(见 网格编辑器) |
| 关闭界面 | 保存全部改动配置 |
死代码
Config.Category.Radar:枚举常量声明于Config.java:51,但OptionSlotFactory.getSlots()只为 6 个分类调用addSlots(),且没有任何@Config字段标注Radar,因此该页签永不出现。雷达选项(maxMobsData等 4 项)实际在Advanced页。核验:grep -rn 'Category.Radar' src/main/java仅命中服务端Configuration.getRadar(),那是另一个同名内部类。AtomicDouble分支:buildSlots()与ConfigValidation都为AtomicDouble准备了控件与校验逻辑(OptionSlotFactory.java:157、:303;ConfigValidation.java:82),配套控件DoubleSliderButton也已实现(ui/component/DoubleSliderButton.java:17),但当前 95 个@Config字段中没有任何一个是AtomicDouble类型(全部为AtomicBoolean/AtomicInteger/AtomicReference)。这是一条为未来预留、当前不可达的分支。