主类入口与依赖注入

WanionLib 的 mod 主类、常量类与运行期依赖容器。其它 mod 引用本库时,拿到实例与 logger 的唯一入口就是这里。

基本信息

属性 值
modid wanionlib
@Mod 类 wanion.lib.WanionLib(final)
根包 wanion.lib
Minecraft 1.7.10
Forge 10.13.4.1614
语言 / API 1.7.10 FML(cpw.mods.fml.*),非 1.12+
硬依赖 无(mcmod.info 的 "dependencies": [] 为空)
编译期依赖 CraftTweaker 3.4.6、ZenScript 1.0.1-GTNH(均 compileOnly + transitive = false)

wanion.lib.Reference 常量表

字段 类型 值
MOD_ID String wanionlib
MOD_NAME String WanionLib
MOD_VERSION String GRADLETOKEN_VERSION(构建期由 Gradle 替换,源码里是占位符)
ACCEPTED_MINECRAFT String [1.7.10]

类为 final,构造私有,纯常量持有者。

wanion.lib.WanionLib 公开成员

成员 签名 说明
实例 public static WanionLib instance 标注 @Mod.Instance(MOD_ID)
依赖容器 private Dependencies<IDependency> dependencies 初始值 new Dependencies<>()
Logger private Logger logger 由 preInit 赋值
取依赖 public static Dependencies<IDependency> getDependencies() 转发 instance.dependencies
取 Logger public static Logger getLogger() 转发 instance.logger
取客户端 tick public static ClientTickHandler getClientTickHandler() @SideOnly(Side.CLIENT),实为 instance.dependencies.get(ClientTickHandler.class)
版本匹配 public boolean matchModVersions(Map<String, String> remoteVersions, Side side) 客户端要求 remoteVersions.containsKey(MOD_ID);服务端要求不含 MOD_ID 或 其值等于 MOD_VERSION

FML 生命周期回调

回调 事件类型 实际行为
preInit(FMLPreInitializationEvent) FMLPreInitializationEvent 仅 logger = event.getModLog();
loadComplete(FMLLoadCompleteEvent) FMLLoadCompleteEvent 仅 dependencies = null;

⚠️ 源码级注意点:loadComplete 把 dependencies 字段置为 null。此后任何对 WanionLib.getDependencies() 的调用都会返回 null;getClientTickHandler() 内部走 instance.dependencies.get(...),因此在 FMLLoadCompleteEvent 之后调用会抛 NullPointerException。依赖容器的可用窗口是 preInit 之后到 loadComplete 之前。

主类没有 init(FMLInitializationEvent) 回调,也没有 @Mod.Instance 之外的任何注册动作。

wanion.lib.WanionLib.IDependency

public interface IDependency {
}

空标记接口。Dependencies<IDependency> 的类型参数即它,用途是把实现类(当前库内唯一实现是 ClientTickHandler)登记进依赖容器。

wanion.lib.common.Instantiator<I>

@FunctionalInterface
public interface Instantiator<I> {
    @Nonnull
    I instantiate(Class<? extends I> moduleThreadClass) throws InstantiationException, IllegalAccessException;
}

函数式接口,是 模块系统 里反射构造的替代方案:模块自带的 Instantiator 可以绕过 setAccessible,或注入带参构造。

wanion.lib.common.IRemovable

public interface IRemovable {
    boolean removed();
    void setRemoved(final boolean removed);
}

IAdvancedRecipe 继承它(见 高级配方注册表),供配方做「已移除」软删除标记。

wanion.lib.common.Dependencies<D>

按类身份(IdentityHashMap,非按 equals/hashCode)存放单例的懒加载容器。

成员 签名 行为
存储 Map<Class, D> dependencies IdentityHashMap
观察者 Map<Class, DependenceWatcher<? extends D>> dependenciesWatchers IdentityHashMap
按类注册 public final <I extends D> void add(Class<? extends I> typeClass) 已存在则直接返回;若有对应 DependenceWatcher 则 add(watcher.instantiate());否则反射 getDeclaredConstructor() + setAccessible(true) + newInstance(),四种反射异常各自 printStackTrace()
按实例注册 public final <I extends D> void add(I instance) 以 instance.getClass() 为键,已存在则返回
取 public final <I extends D> I get(Class<I> typeClass) 命中直接返回;未命中先 add(typeClass) 再返回(反射失败则返回 null)
判存在 public final boolean contains(Class<? extends D> typeClass) dependencies.containsKey(typeClass)
订阅 public final void subscribe(DependenceWatcher<? extends D> dependenceWatcher) 以 dependenceWatcher.dependenceClass 为键,已存在则不覆盖

内部类 Dependencies.DependenceWatcher<W extends D>

public abstract class,非静态内部类(隐式持有外部 Dependencies 引用)。

成员 签名 行为
键 private final Class<W> dependenceClass 构造时由 ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0] 反射取得
工厂 @Nonnull public abstract W instantiate() 抽象方法,由调用方提供带参构造路径

⚠️ 该类靠泛型实参反射推导键类型,必须是直接子类(如 new Dependencies.DependenceWatcher<Foo>() { ... })。再往下一层继承会使 getGenericSuperclass() 拿到非 ParameterizedType,抛 ClassCastException。

相关条目