主类入口与依赖注入
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。