Navigator

[!INFO] Git Commit: 8c9087c | Updated: 2026-10-01

地图 API 库,modid navigator。为 JourneyMap / Xaero World Map / Xaero Minimap (VoxelMap 部分支持)提供统一的图层(layer)抽象层, 让第三方模组只写一份代码就能在多个地图模组上显示数据。

身份

属性 实测值
modid navigator(全小写,Navigator.java:20)
modName Navigator(:21)
资源域 navigator(与 modid 一致,无分裂)
Java 文件 73(5 251 行)
注册内容 0 方块 / 物品 / 实体(纯 API + Mixin)
配置项 5(2 个 general + 3 个 module 开关)
硬依赖 仅 gtnhlib(dependencies = "required-after:gtnhlib;",:17)

[!IMPORTANT] 定位:地图 API 库,不是导航 / 指南针 mod 仓库名「Navigator」有歧义,但源码 mcmod.info 的 description 明写 A map API providing integration for Journeymap & Xaeros maps, README.md 首句也是 Navigator is an api mod that allows for other mods to add integration for JourneyMap / Xaero World / Xaero Minimap / VoxelMap。

全文无任何「指南针 / 罗盘 / 朝向指示」相关实现。 本 mod 自己不显示任何 UI —— 它提供的是 「数据源 → 图层管理器 → 渲染步骤」的框架, 由消费方模组(本仓的 impl/ 4 个类)实例化后才产生可见效果。

依赖关系

dependencies.gradle 里只有 3 条真实依赖 + 4 条 compileOnly:

依赖 作用域 说明
GTNHLib api 唯一硬依赖;提供 @Config / ConfigurationManager / 事件总线
org.jetbrains:annotations compileOnlyApi @NotNull / @Nullable
NotEnoughItems devOnlyNonPublishable 仅开发期,不进产物
journeymap-api-forge compileOnly JourneyMap 官方 API 1.7.10-2.0.0
journeymap 5.2.20 compileOnlyApi(rfg.deobf) JourneyMap 5 本体进公开 API
xaeros-minimap / xaeros-world-map compileOnly 经 deobfCurse(...)
voxelmap compileOnly 经 deobfCurse(...)

⚠️ 4 个地图模组全部 compileOnly —— 运行期都不需要安装,README.md 明写 Map mods remain optional at runtime。 SupportedMods 用 Loader.isModLoaded 探测。

⚠️ VoxelMap 有 API 类但没有 mixin: api/voxelmap/VoxelMapWaypointManager.java(75 行)存在, 但 Mixins 的 6 个常量里没有 VoxelMap, SupportedMods 也没有 VoxelMap 枚举值。 这与 README.md 的 VoxelMap (Limited support) 一致 —— 只保留路点管理,不接入图层/渲染框架。

⚠️ JourneyMap 5 的本体是 compileOnlyApi(rfg.deobf), 即 JM5 的类型泄漏进了本 mod 的公开 API。 而 README.md 明确说 JM5 专用 API 已废弃: The JourneyMap-specific renderer and render-step APIs are deprecated because they support only JourneyMap 5。

gtnhlib 已登记未成文(前向引用)。 JourneyMap / Xaero World Map / Xaero Minimap / VoxelMap / NEI 均不在收录范围,故只以纯文本提及,不建分类、不加链接。

三个加载阶段

本 mod 同时扮演 coremod(early) 与 late mixin loader 两个角色:

角色 类 mixin 配置 阶段
coremod + early mixin NavigatorCore mixins.navigator.early.json EARLY
常规 early mixin 无独立加载器 mixins.navigator.json EARLY
late mixin NavigatorLateMixins mixins.navigator.late.json LATE

⚠️ 三个 mixin 配置的 package 各不相同:

配置 package minVersion
mixins.navigator.early.json com.gtnewhorizons.navigator.mixins.early 0.8.3-GTNH
mixins.navigator.json com.gtnewhorizons.navigator.mixins 0.8.3-GTNH
mixins.navigator.late.json com.gtnewhorizons.navigator.mixins.late 0.8.3-GTNH

三份配置共用同一个 refmap mixins.navigator.refmap.json, 且 compatibilityLevel 都是 JAVA_8。 late 配置独有 injectors.maxShiftBy = 3。

⚠️ mixins.navigator.json 的 package 是 ...mixins, 而 TargetedMod 与 Mixins 也在这个包下 —— 枚举类本身不是 mixin(无 @Mixin 注解), 但配置会扫描该包。靠 MixinBuilder 的 addClientMixins 精确点名实际类, 所以不会误注册枚举。

16 个 mixin 的归属

见 Mixins:

阶段 常量 目标模组 mixin 类数
EARLY TEXTURE_ATLAS_SPRITE_ACCESSOR 无(无限制) 1
EARLY ENABLE_STENCIL XaeroMiniMap 且 XaeroWorldMap 1
LATE JOURNEYMAP_V5 JourneyMap 7
LATE JOURNEYMAP_V6 JourneyMap 2
LATE XAEROS_GUI XaeroWorldMap 1
LATE XAEROS_MINIMAP_WAYPOINT XaeroMiniMap 1
LATE XAEROS_MINIMAP_RENDERER XaeroMiniMap 且 XaeroWorldMap 1

合计 14 个 @Mixin 类 + 2 个 @Accessor 接口 (TextureAtlasSpriteAccessor、DisplayVarsAccessor、 FullscreenAccessor —— 实际 3 个 accessor)= 16 个类。

⚠️ ENABLE_STENCIL 用 addRequiredMod 同时要求 XaeroMiniMap 与 XaeroWorldMap (两个 addRequiredMod 调用,:17-18), 所以只装其中一个时模板缓冲不会被强制开启。 这是有意的(stencil 主要给 world map 用),但对只装 minimap 的用户无效。

配置项(5 项)

两个 GTNHLib @Config 类:

GeneralConfig(无 category,2 项)

字段 类型 默认值
enableDebugLayers boolean false
rememberSearchText boolean true

ModuleConfig(category = modules,3 项)

字段 类型 默认值
enableJourneyMapModule boolean true
enableXaeroWorldMapModule boolean true
enableXaeroMinimapModule boolean true

⚠️ enableDebugLayers 默认 false,而 ClientProxy(:22-24)只在它为真时注册 DirtyChunkLayerManager —— 即本仓自带的唯一可见图层默认关闭。

⚠️ 3 个 module 开关全默认 true, 但 SupportedMods 会再与 「是否真的装了该模组」取逻辑与 —— 所以装了就自动生效,没装则枚举值为 false。

键位(1 个)

public static final KeyBinding ACTION_KEY = new KeyBinding(
    "navigator.key.action", Keyboard.KEY_DELETE, Navigator.MODNAME);   // NavigatorApi.java:34-37
属性 值
本地化 key navigator.key.action
默认键 DELETE(Keyboard.KEY_DELETE)
分类 Navigator(MODNAME,不是 modid)

⚠️ 键位分类用 Navigator.MODNAME("Navigator",首字母大写), 而 modid 是 navigator(全小写)——键位列表里显示为 Navigator > navigator.key.action。

⚠️ 默认占用 DELETE 键(与 TiC Tooltips 的「出厂未绑定」相反), 会与 BiomeMerger 之类的删除类键位冲突。

分层架构

ILocationProvider  ← 数据源(消费方实现)
        ↓
LayerManager       ← 图层管理器(缓存 + 生命周期 + 视口)
        ↓
LayerRenderer      ← 按地图模组分发的渲染器
        ↓
RenderStep / InteractableStep  ← 实际绘制/交互
层 抽象 地图中立实现
按钮 ButtonManager —
图层 LayerManager(623 行,全 mod 最大) —
渲染器 LayerRenderer UniversalLayerRenderer
渲染步骤 RenderStep UniversalRenderStep(280 行)
交互步骤 InteractableStep UniversalInteractableStep / UniversalLocationInteractableStep
标记 MapMarker(320 行) —
路点 Waypoint / WaypointManager —

地图中立(map-neutral)是官方推荐路径; JourneyMap 专用与 Xaero 专用渲染器作为备选: api/journeymap/render/(2 个)、api/xaero/renderers/(2 个)。

源码缺陷

  1. ModConfig 三个开关的求值时机在类初始化 —— SupportedMods 的构造参数 Util.isJourneyMapInstalled() && ModuleConfig.enableJourneyMapModule 在枚举常量初始化时求值,即 SupportedMods 类首次被加载的那一刻。 若该时刻早于 GTNHLib ConfigurationManager 读盘(见缺陷 2), 三个开关全是 Java 默认值 false → 枚举全部 false, 且 final 字段无法在配置加载后刷新(需重启游戏才生效)。

  2. 配置注册在 coremod 的 static 块里,早于 mod 加载 —— NavigatorCore(:20-27)的 static {} 调 ConfigurationManager.registerConfig(GeneralConfig.class)。 这是 GTNHLib 配置的推荐做法(早期读盘), 但与缺陷 1 叠加时,若 SupportedMods 被更早的类初始化, 就会读到未加载的配置。

  3. ClientProxy.onClientConnect 是 static 但注册在实例代理上 —— ClientProxy(:27-30)的方法是 public static void + @SubscribeEvent, 而类本身带 @EventBusSubscriber(side = Side.CLIENT)。 @EventBusSubscriber 扫描 static 方法,不需要实例, 所以 new ClientProxy()(由 @SidedProxy 创建)实际上没有任何用途 —— 它的 preInit 覆写(:19-25)才是唯一有效逻辑。 这不是 bug,但是冗余的实例化。

  4. @Mod 注解缺 acceptableRemoteVersions 之外的服务端声明 —— acceptableRemoteVersions = "*"(:16)允许不带本 mod 的客户端连服务端。 但本 mod 纯客户端(ClientProxy 才注册内容), 服务端装它没有任何作用(CommonProxy 三个方法全空)。不加限制是安全的。

  5. NavigatorApi.registerLayerManager 不去重 —— 源码注释明写 This method does not deduplicate registrations(:45-46)。 同一 LayerManager 注册两次会在 layerManagers 里出现两次, 导致该图层被渲染两次(getActiveRenderersFor 不去重, 见 NavigatorApi 的 :61-67)。 API 契约靠调用方自觉。

  6. VoxelMap 支持是死代码 —— api/voxelmap/VoxelMapWaypointManager.java(75 行)无任何调用点 (VoxelMap 既不在 SupportedMods, 也不在 Mixins)。 见本分类页「依赖关系」的说明。

  7. ENABLE_STENCIL 的双模组要求 —— 只装 Xaero Minimap(不装 World Map)时, ForgeHooksClientMixin 不会应用, 模板缓冲不被强制开启。见本分类页「16 个 mixin 的归属」。

分类索引

核心与入口

  • Navigator - @Mod 主类:3 个生命周期转发 + 唯一硬依赖声明
  • NavigatorCore - coremod + early mixin loader;配置注册的 static 块
  • NavigatorLateMixins - late mixin loader
  • ClientProxy - 注册 ACTION_KEY + 条件注册调试图层
  • CommonProxy - 三个空钩子(纯客户端 mod)
  • NavigatorApi - 公开 API 入口:图层注册、渲染器查询、排序

配置

模型层

工具

内部实现

参考实现

JourneyMap 专用 API(已废弃)

Xaero 专用 API

VoxelMap(部分支持)

Mixin

源码:/Users/evlos/a/mirror/Navigator/ API 文档:/Users/evlos/a/mirror/Navigator/docs/API.md 关系登记:见 data/relation.md(全局 Wiki 分类映射表)