VisualProspecting

GTNH 的矿脉勘探数据共享系统(作者 SinTh0r4s)。注册 1 个物品、0 个方块、0 个多方块、0 个实体、0 个维度。它本身不生成任何矿脉,而是把 GregTech 地震勘探仪(Seismic Prospector)扫描到的矿脉与地下流体存进一份可跨玩家共享的数据库,再在地图模组上画出来。

项目 值
modid visualprospecting(Tags.java 的 MODID 常量,与 gradle.properties 的 modId 一致)
源仓库 https://github.com/GTNewHorizons/VisualProspecting.git
源 commit 268e673(2026-09-17)
Minecraft 1.7.10 / Forge 10.13.4.1614
硬依赖 required-after:gregtech、required-after:NotEnoughItems、required-after:gtnhlib(VPMod.java:22-25)
软依赖 after:navigator(1.7.10 版 Navigator,与 1.20+ 的同名库不是一回事)
主类 com.sinthoras.visualprospecting.VPMod(@Mod 在 VPMod.java:20)
主源文件数 79
核心 ModLoader mixinplugin.VisualProspectingEarlyMixinLoader + 延迟 VisualProspectingLateMixinLoader
mixin 配置 3 份:mixins.visualprospecting.json、.early.json、.late.json
硬编码 MC 世界高度 256(VP.java:17,非 1.7.10 原生的 256 之下扩展)

物品(1)

物品 注册名 说明
勘探者日志 visualprospecting:visualprospecting.prospectorslog 团队数据载体,空/已填写两态

唯一的 registerItem 在 HooksShared.java:101。本 mod 没有任何配方:

$ grep -rn "addRecipe\|GameRegistry.add" src/main/java
(无输出)

日志物品只能从 GT 高级勘探器的右键结果获得(MTEAdvSeismicProspectorMixin 把勘探数据写进数据棒的 NBT),或从创造模式物品栏取。

方块 / 多方块 / 实体 / 维度

全部为零。 无 registerBlock,无 Block 子类,无 TileEntity,无 extends Entity,无 registerDimension,无 extends WorldProvider,无群系与世界生成。

⚠️ 勘探数据不存储在任何方块或 TileEntity 里,而是存在 ServerCache / ClientCache 的内存数据库中,并通过 SnapshotUploadTask / SnapshotDownloadTask 在玩家间传输——见 数据库与缓存。

游戏设定(3)

条目 内容
数据库与缓存 矿脉 / 地下流体数据存在内存而非方块,含 11 个数据库类与 5 个任务类
指令 /vp 与 /vp_admin 两棵 Brigadier 命令树 + 1 条客户端指令
配置 13 项配置,分 general / network / integration / caching 四类

勘探半径(来自 VP.java 常量)

常量 值 用途
oreVeinSizeChunkX / Z 3 / 3 区块 单条矿脉的存储粒度
undergroundFluidSizeChunkX / Z 8 / 8 区块 单个地下流体样本的存储粒度
undergroundFluidChunkProspectingBlockRadius 128 方块 由 8 × 16 算出,地震勘探器扫地下流体的固定半径
chunksPerRegionFileX / Z 32 / 32 对应原版 region 文件布局
gregTechSmallOreMinimumMeta 16000 GT 小矿 meta 下界,用于识别 ore 生成记录
uploadSizePerPacketInBytes 30,000 B 单封包上限,源码注释警告「超过 32 kB 会踢玩家」

键位(2 个)

HooksKey(HooksKey.java:18-29),默认键码全部 Keyboard.KEY_NONE(未绑定)。

键位 键名 作用
矿脉图层开关 visualprospecting.key.toggleore.name 切换矿脉覆盖层
地下流体图层开关 visualprospecting.key.togglefluid.name 切换地下流体覆盖层

分类名均为 visualprospecting.key.action.category。

指令(2 棵命令树)

用 GTNHLib 的 Brigadier API 注册(VPCommand.register() / VPAdminCommand.register()),非 1.7.10 原版 ICommand。

/vp(所有玩家)

子命令 作用
/vp 显示用法
/vp team 显示用法
/vp team info 查看本队勘探数据概况
/vp team info detailed 查看本队勘探数据详情

/vp_admin(权限等级 2)

子命令 权限 作用
/vp_admin team info <玩家> 2 查看指定玩家的数据
/vp_admin team info <玩家> detailed 2 查看指定玩家数据详情
/vp_admin team upload <玩家> 2 强制上传指定玩家数据
/vp_admin team clear <玩家> 2 清除指定玩家数据
/vp_admin servercache rebuild all 4 重建全服矿脉缓存
/vp_admin servercache rebuild spawn 4 只重建出生点半径缓存
/vp_admin debug vein 4 调试矿脉数据

另有客户端指令 vp_client_cache_reset(ResetClientCacheCommand,权限等级见该类 getRequiredPermissionLevel())。

配置(13 项,4 类)

Config.syncronizeConfiguration()(Config.java:51-158),category 分 general / network / integration / caching。

键 类 默认 作用
enableProspecting general true 客户端总开关,低配机器可关
enableTeamSharing general true 服务端:GTNHLib 队成员间自动共享勘探数据
keepProspectionOnTeamLeave general true 离队时把团队数据复制进个人队伍
cacheGenerationLogUpdateMinTime general 5 生成缓存时日志刷新的最小间隔(秒),只发生一次
minDelayBetweenVeinRequests network 2000 ms 玩家请求矿脉信息的最小间隔(防刷)
uploadBandwidth network 2,000,000 B/s 客户端上传带宽上限,超出会被踢
minZoomLevelForOreLabel general 1 显示矿脉标签的最小缩放级别
minZoomLevelForUndergroundFluidDetails general 2 显示地下流体详情的最小缩放级别
maxTransferCacheSizeMB general 50 MB 玩家同步地图数据的内存上限
recacheVeins general false 强制重做 GT 矿脉缓存
enableVoxelMapWaypointsByDefault integration false VoxelMap:勘探产生的路点是否默认启用
showOreLabelsOnJourneyMap6Minimap integration true JourneyMap 6:小地图上是否显示矿脉标签
maxRegionRowFileMBForInMemoryScan caching 10,000 MB 重建缓存时同时打开的 region 文件总大小上限

uploadPacketsPerSecond 是派生值,由 uploadBandwidthBytes / 30,000 算出,不是独立配置项。

整合的其它模组

模组 关系 说明
GregTech 硬依赖 提供地震勘探器(MTEAdvSeismicProspector),本 mod 用 @Overwrite 接管其 onRightclick
NotEnoughItems 硬依赖 勘探结果以数据棒形式展示
GTNHLib 硬依赖 提供 Brigadier 命令 API 与队伍系统
Navigator 软依赖 地图图层抽象(1.7.10 版)
VoxelMap 可选整合 VoxelMapEventHandler 写路点
JourneyMap 6 可选整合 在小地图显示矿脉标签

⚠️ VPMod.java 注释里写的是 after:navigator,指的是 1.7.10 的 Navigator 库(对应 wiki 分类 navigator),与 1.20+ 的 Navigator 是不同模组。VoxelMap / JourneyMap 6 均为代码存在但不声明依赖,缺它们时相关整合静默失效。

本 mod 没有的内容

以下经源码检索确认完全没有,故不建目录、不建条目:

  • 方块与多方块:grep -rn "registerBlock\|extends Block\b" src/main/java 无输出。无 TileEntity、无多方块、无控制器。
  • 实体:grep -rn "extends Entity\b\|registerModEntity" src/main/java 无输出。
  • 附魔 / 药水效果 / 成就:grep -rniE "Enchantment|Achievement|extends Potion" src/main/java 无输出。
  • 维度 / 群系 / 世界生成:grep -rn "registerDimension\|extends WorldProvider\|extends BiomeGenBase\|IWorldGenerator" src/main/java 无输出。它只读取已有维度的数据,不新增。
  • 任何配方:grep -rn "addRecipe" src/main/java 无输出。唯一的物品无法合成。
  • GUI / 容器 / 机器方块:grep -rn "IGuiHandler\|GuiScreen\|extends Gui" src/main/java 无输出。勘探结果通过地图模组或可编辑书展示,本 mod 自己不开界面。

源码缺陷

  1. Config.syncronizeConfiguration 拼写错误(Config.java:51)。方法名 syncronize(正确应为 synchronize)在整个仓库中一致沿用,属命名笔误,不影响功能。

  2. recacheVeins 是自毁式一次性开关(Config.java:121-129)。读取后若为 true,立刻 set(false) 写回配置:

    recacheVeins = recacheVeinsProperty.getBoolean();
    if (recacheVeins) { recacheVeinsProperty.set(false); }
    

    玩家的设置不会保存——这不是 bug 而是设计(配置项自己的描述也写了 “Will automatically be set back to False the next time the game is started”),但当 configuration.hasChanged() 为 false 时这个 set(false) 不会被写入磁盘,玩家下次启动仍会读到 true 并重复重建缓存。

  3. 两处未使用的字段。Config.java:20-23 的 Defaults 私有类中 cacheGenerationLogUpdateMinTime 有对应读取点,但 Config.uploadPacketsPerSecond 是每次 syncronizeConfiguration 重新计算的派生值,而 VP.randomGeneration(VP.java:13)在 ProspectorsLog 里被当作失败概率随机源使用(见 勘探者日志),命名极易误导——它不是「生成随机数」而是「判失败」。

  4. 地震勘探器被 @Overwrite 整体接管(MTEAdvSeismicProspectorMixin.java:50-118)。Mixin 完整重写了 MTEAdvSeismicProspector.onRightclick,因此任何对该机器的其它 mod 补丁都会被静默丢弃。同时该方法恒返回 true,吞掉了原版可能的返回值语义。

  5. ProspectorsLog 的失败率不对称。写入时是 nextInt(1000) 后判 < 5(0.5%);读取时判据是 TransferCache.instance.isClientDataAvailable(authorUuid) ? 1000 : 5——对方数据不在本地时用 5,即必定失败(ProspectorsLog.java:66-68)。这设计上是防止读取不存在的数据,但也意味着任何未同步到本地的队友数据都读不出来。

  6. 混入了另一个 mod 的语言键。en_US.lang 存在 item.visualprospecting.prospectorslog.creation.fail<random> 与 reading.fail<random> 这类带随机数后缀的键(:48、:69 把 random 直接拼进键名)。nextInt(1000) 可能返回 0–999,而语言文件不可能提供 1000 条 fail 消息,绝大多数失败分支会显示原始键名。