第三方模组集成
基本信息
| 属性 | 值 |
|---|---|
| 依赖声明文件 | dependencies.gradle、gradle.properties、@Mod(dependencies=...) |
| 硬依赖 | 1 个第三方模组(GTNHLib) |
| 软依赖 | 8 个第三方模组 |
| 运行期专有 | 1 个(Hodgepodge,反向读取其字段) |
| 明确不兼容 | 1 个(FTB Utilities) |
| 排除目标 | 1 个(Ultramine) |
| 编译期库 | 1 个非模组依赖(JourneyMap API) |
依赖分层
硬依赖(required-after,缺失则无法加载)
| 模组 | 版本 | 声明位置 |
|---|---|---|
| GTNHLib | 0.11.49 |
@Mod(dependencies = "required-after:gtnhlib;...")(ServerUtilities.java:33);dependencies.gradle:5 用 api(...);gradle.properties:172 required-project:gtnhlib;gradle.properties:191 requiredDependency:gtnhlib |
GTNHLib 提供配置系统(@Config)、Mixin 框架(IMixins、ILateMixinLoader、IEarlyMixinLoader)与 LateMixin 注解。本模组完全依赖它的配置反射机制。
此外,RetroFuturaGradle 会在 usesMixins = true(gradle.properties:101)时自动把 UniMixins 加为必需依赖(gradle.properties:168 注释明确说明),故 UniMixins 也是事实上的硬依赖。
软依赖(after 或 optional,缺失则功能降级)
| 模组 | 版本 | 依赖声明 | 缺失后果 |
|---|---|---|---|
| Navigator | 1.1.10 |
after:navigator(ServerUtilities.java:33);optional-project:navigator(:172);optionalDependency:navigator(:191) |
地图上不显示领地 |
| NotEnoughItems | 2.8.144-GTNH |
compileOnly(dependencies.gradle:6) |
创造物品栏识别与侧边栏按钮隐藏逻辑失效 |
| EnderIO | 2.10.45 |
compileOnly(:7) |
无法识别 EnderIO 的 FakeFarmPlayer |
| Random-Things | 2.7.10 |
compileOnly(:8) |
隐身玩家仍会被在线检测器看到 |
| Witchery | CurseMaven witchery-69673:2234410 |
compileOnly(rfg.deobf(...))(:18) |
无吸血鬼/棺材判定 |
| WAILA | 1.19.34 |
runtimeOnlyNonPublishable(:24) |
仅运行期需要,不随模组发布 |
| Hodgepodge | 未在 dependencies.gradle 声明 |
运行时 Loader.isModLoaded 探测 |
备份完成后不触发其世界数据刷新 |
[!NOTE] Hodgepodge 没有任何编译期依赖,却出现在
OtherMods的探测列表里。它是反向集成:BackupTask.drainQueuedWrites()(task/backup/BackupTask.java:190-205)用Class.forName("com.mitchej123.hodgepodge.config.TweaksConfig")反射读取其threadedWorldDataSaving字段,为真时再反射调com.mitchej123.hodgepodge.util.WorldDataSaver的刷新方法。方法注释写明「without requiring that mod, or its newer flush API」—— 对ClassNotFoundException与NoSuchFieldException都直接return,兼容 Hodgepodge 的新旧两版 API。
仅编译期(reference-only)
| 依赖 | 版本 | 用途 |
|---|---|---|
info.journeymap:journeymap-api-forge |
1.7.10-2.0.0(dependencies.gradle:10) |
只用其 API 编译,不产生运行期耦合 |
org.jetbrains:annotations |
26.1.0(:11) |
@NotNull / @Nullable / @ApiStatus |
invsee 背包专用(软依赖)
Baubles-Expanded、Battlegear2、Galacticraft、TinkersConstruct、AdventureBackpack2、Minecraft Backpack Mod —— 全部 compileOnly 且 transitive = false(dependencies.gradle:12-17)。详见 Invsee 背包查看。
集成实现细节
Navigator
NavigatorIntegration(integration/navigator/)是集成最深的软依赖,共 8 个类。
| 类 | 作用 |
|---|---|
NavigatorIntegration |
入口,init() 注册图层管理器;维护 CLAIMS 缓存 |
ClaimsLayerManager |
实现 Navigator 的图层管理器 |
ClaimsLayerManager.INSTANCE |
单例 |
ClaimsButtonManager |
侧边栏按钮集成 |
ClaimsRenderStep |
渲染步骤 |
ClaimsPolygonOverlay |
多边形覆盖层绘制 |
ClaimsLocation |
坐标转换 |
触发点 3 处:
| 位置 | 行 | 作用 |
|---|---|---|
client/ServerUtilitiesClient.java |
81 | postInit 时 NavigatorIntegration.init() |
net/MessageClaimedChunksUpdate.java |
150 | 收到领地更新后同步到 Navigator |
handlers/ServerUtilitiesClientEventHandler.java |
65 | 客户端事件时刷新 |
使用 Navigator 的 4 个封包(utilities_claim 通道):MessageNavigatorUpdate、MessageNavigatorRequest、MessageNavigatorUpdateKnown、MessageNavigatorValidateKnown。
NavigatorIntegration 静态字段 CLAIMS 是 Object2ObjectMap<ChunkDimPos, ClientClaimedChunks.ChunkData>(fastutil 映射,:24),另有 OWNTEAM 缓存与 mutablePos 复用对象。
Witchery
serverutils.compat.WitcheryCompat(compat/WitcheryCompat.java)只有 2 个方法:
| 方法 | 行 | 用途 |
|---|---|---|
isVampire(EntityPlayer) |
11 | ExtendedPlayer.get(player).isVampire() |
isSleepInCoffin(World, EntityPlayer) |
17 | 检查玩家所在方块是否 Witchery.Blocks.COFFIN |
配合 Mixins.CANCEL_VAMPIRE_WAKEUP_EVENT(LATE 阶段,需 world.enable_player_sleeping_percentage 为真)与 world.vampire_sleep_percent(默认 50)实现「棺材中达到一定比例的吸血鬼才能跳过夜晚」。
[!NOTE]
OtherMods.isWitcheryLoaded()被OtherMods.init()赋值(lib/OtherMods.java:19),但全仓没有任何地方调用它 —— Witchery 集成完全通过 Mixin 的addRequiredMod(TargetedMod.WITCHERY)与直接类引用判断,不走isWitcheryLoaded()标志。
NotEnoughItems
两处使用:
| 位置 | 行 | 作用 |
|---|---|---|
lib/client/ClientUtils.java |
66 | isCreativePlusGui():NEI 加载时把 GuiExtendedCreativeInv 识别为创造物品栏 |
client/gui/SidebarButton.java |
33 | NEI_NOT_LOADED 布尔供给器 |
SidebarButton.NEI_NOT_LOADED 驱动 sidebar_buttons.json 中 5 个 hide_with_nei: true 的作弊按钮(heal、toggle.gamemode、toggle.rain、toggle.day、toggle.night)。
EnderIO
唯一使用点 ServerUtils.isFakeFarmPlayer()(lib/util/ServerUtils.java:50-53):
private static boolean isFakeFarmPlayer(EntityPlayerMP player) {
if (!OtherMods.isEnderIOLoaded()) return false;
return player instanceof FakeFarmPlayer;
}
结果被 isFake()(:46-48)合并,后者控制 world.logging.include_fake_players 是否生效。
Random-Things
Mixins.HIDE_VANISHED_FROM_DETECTOR(mixin/Mixins.java)—— LATE 阶段,addRequiredMod(RANDOMTHINGS),条件 commands.vanish 为真,向 randomthings.MixinWorldUtils 注入。作用是把隐身玩家从 Random-Things 的在线检测器中隐藏。
TargetedMod.RANDOMTHINGS 定义为 RANDOMTHINGS("RandomThings")(mixin/TargetedMod.java:9),即按 modid RandomThings 匹配。
JourneyMap
只通过 journeymap-api-forge 编译依赖接入。功能上体现为两个权限节点(ServerUtilitiesPermissions.java:131-132):
| 节点 | 含义 |
|---|---|
serverutilities.journeymap.enable |
在 JourneyMap 覆盖层上看自己队伍的领地 |
serverutilities.journeymap.other |
看其他队伍的领地 |
明确不兼容:FTB Utilities
gradle.properties:191 声明 incompatible\:ftb-utilities-forge(仅 CurseForge 元数据)。
运行期强制在 client/ServerUtilitiesClient.java:90-92:
if (Loader.isModLoaded("FTBU") || Loader.isModLoaded("FTBL")) {
throw new IncompatibleModException();
}
检测的是 modid FTBU 或 FTBL(FTB Utilities / FTB Library),而非 CurseForge slug ftb-utilities-forge。
IncompatibleModException(lib/client/IncompatibleModException.java:12)继承 cpw.mods.fml.client.CustomModLoadingErrorDisplayException(该 FML 类在 :9 被 import),错误文案硬编码为 "FTBUtilities/FTBLibrary detected during load."(:13),并弹出一个只有「Close Game」按钮的错误界面(:25-33),点按后 Minecraft.getMinecraft().shutdown()。
[!IMPORTANT] 这是模组历史造成的冲突,不是功能依赖问题。
ja_JP.lang中仍保留 7 个ftbutilities_client.*语言键(resources/assets/serverutilities/lang/ja_JP.lang:66-72,含show_shutdown_timer、button_daytime、button_nighttime、shutdown_timer_start等),说明侧边栏按钮功能原本源自 FTB Utilities,本模组 fork 后接管了这部分功能,因此互斥。本条目只陈述代码与资源中的事实。
排除目标:Ultramine
TargetedMod.ULTRAMINE(null, null, "org.ultramine.server.UltraminePlugin")(mixin/TargetedMod.java:8)—— 按类 org.ultramine.server.UltraminePlugin 匹配(无 modid、无 coreModClass)。
Mixins 中有 2 个条目 addExcludedMod(TargetedMod.ULTRAMINE):
| 条目 | 说明 |
|---|---|
PAUSE_WHEN_EMPTY |
空服暂停 |
MAX_TICK_TIME |
单 tick 超时保护 |
Ultramine 自身实现了这两项服务器级功能,同时启用会冲突。
失败被静默吞掉的集成点
InvSeeRegistry.DefaultInventories 构造函数(invsee/inventories/InvSeeRegistry.java:36-48)在尝试实例化某个 mod 背包时:
try {
registerInventory(inventory.getDeclaredConstructor().newInstance());
} catch (Exception ignored) {}
空 catch,异常被完全吞掉(:46)。若某个可选 mod 加载了但其背包类结构不兼容,invsee 页签会静默消失,没有任何日志。同样的空 catch 模式还出现在:
| 位置 | 行 | 场景 |
|---|---|---|
task/ShutdownTask.java |
48 | 关机流程 |
lib/data/ForgePlayer.java |
126、137 | 玩家数据读写 |
lib/icon/PlayerHeadIcon.java |
98、109 | 玩家头颅图标渲染 |
aurora/AuroraServer.java |
98、107 | Web 服务器绑定/关闭(见 Aurora 配置) |
相关条目
- Invsee 背包查看 - 6 个可选模组的背包集成
- 客户端配置 -
hide_with_nei按钮的生效逻辑 - 服务端指令总表 -
/transfer与跨服切服 - 封包与同步 - Navigator 专用封包