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)是核心:

  1. propertiesClass.getDeclaredFields() 遍历当前类自己声明的字段(:144)
  2. 跳过无 @Config 注解的字段(:146)
  3. 按字段类型分派控件(:150-169):
字段类型 控件工厂方法 控件
AtomicBoolean getBooleanSlotMetadata() 开关按钮
AtomicInteger getIntegerSlotMetadata() 整数滑块
AtomicDouble getDoubleSlotMetadata() 双精度滑块
AtomicReference + stringListProvider 非空 getStringSlotMetadata() 下拉/循环列表
AtomicReference + 无 provider getEnumSlotMetadata() 枚举循环按钮
  1. 未能识别的类型记 warn Unable to create config gui for {}.{} using {}(:194-196)
  2. 递归父类(: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)。这是一条为未来预留、当前不可达的分支。

相关条目