一个完全开源的1.20.1 Forge可注入式客户端Base
flowchart LR
Core --> IDEA["IDEA调试加载模式"]
Core --> DLL["DLL注入加载模式"]
IDEA -."通过Preloader.RegisterNatives".-> native["native方法直接获取jvm"]
DLL --> hook["Hook lwjgl.dll获取jvm"]
native --> judge["判断是否加载了Preloader.class"]
hook --> judge
judge --"已加载\n因为模组启动时会自动加载Preloader.class"--> loaded["判断为mod启动方式"]
judge --"没加载"--> inject["判为注入模式"]
loaded --> noop["无操作 开发人员调试模式"]
inject --> loadBuiltin["加载内置的Preloader.class并执行\nPreloader.run"]
loadBuiltin -."Preloader.class保存在dll里 需要独立打包".-> loadJar["加载jar里的所有class"]
loadJar --> main["执行Main主类"]
- 支持 MOD 启动模式与 DLL 注入模式双启动
- 注入基于jvmti无需java agent
- 基于Skia的2D屏幕绘制
- 支持外置Gui
- 内置完全开源的仿Mixin字节码修改框架
- 与
Core.dll紧密联系 方便操作jni - Module与Setting Base已全部完善 支持树形设置
**▶ 方式一:Forge mod启动
mod启动时默认依赖路径
C:\\Test\\lib默认dll名
Core.dll将
ext内文件复制到依赖路径修改
Preloader.javaMAIN_PATH与CORE_DLL字段
**▶ 方式二:DLL注入启动
运行
run.vbs
Important
改完Preloader.java后 如果要打包注入,请重新打包preloader_class.h
用 @Reflect 注解映射目标类的私有字段,方法声明为 native,框架会自动注入实现。
@ClassTransformer(Minecraft.class)
public class MinecraftTransformer implements ITransformer {
@Reflect("isLocalServer") // 对应 Minecraft 类中的字段名
public native static boolean isLocalServer(Minecraft instance); // getter
@Reflect("isLocalServer")
public native static void setLocalServer(Minecraft instance, boolean value); // setter
}2. 在 TransformerLoader 的构造函数中注册
public TransformerLoader() {
add(
MinecraftTransformer.class,
GameRendererTransformer.class,
// ...
YourTransformer.class // ← 在这里添加你的 Transformer
);
...
}通过 SettingAttribute 可以将 Setting 组织成树形结构,子节点只有在父节点满足条件时才会显示。
结构预览
TreeNode1 (a)
├── TreeNode2-1 (c)
└── TreeNode2-2 (b)
└── TreeNode3-1 (d)
代码示例
@SettingInfo(name = {
@Text(label = "TreeNode3-1", language = Language.English)
})
private final BooleanSetting d = new BooleanSetting(false);
// b 开启时,显示子节点 d
@SettingInfo(name = {
@Text(label = "TreeNode2-2", language = Language.English)
})
private final BooleanSetting b = new BooleanSetting(false,
new SettingAttribute<>(d, true) // d 在 b == true 时显示
);
@SettingInfo(name = {
@Text(label = "TreeNode2-1", language = Language.English)
})
private final BooleanSetting c = new BooleanSetting(false);
// 根节点,a 开启时显示子节点 b 和 c
@SettingInfo(name = {
@Text(label = "TreeNode1", language = Language.English)
})
private final BooleanSetting a = new BooleanSetting(false,
new SettingAttribute<>(b, true), // b 在 a == true 时显示
new SettingAttribute<>(c, true) // c 在 a == true 时显示
);
public TestModule1() {
registerSetting(a); // 只需注册根节点,子节点自动递归注册
}结构预览
Mode (ModeA / ModeB / ModeC)
├── Setting1 → 仅 ModeA 时显示
├── Setting2 → 仅 ModeB 时显示
└── Setting3 → ModeA / ModeB / ModeC 均显示
@SettingInfo(name = { @Text(label = "Setting1", language = Language.English) })
private final BooleanSetting setting1 = new BooleanSetting(false);
@SettingInfo(name = { @Text(label = "Setting2", language = Language.English) })
private final BooleanSetting setting2 = new BooleanSetting(false);
@SettingInfo(name = { @Text(label = "Setting3", language = Language.English) })
private final BooleanSetting setting3 = new BooleanSetting(false);
@SettingInfo(name = { @Text(label = "Mode", language = Language.English) })
private final ModeSetting mode = new ModeSetting(
"ModeA",
Arrays.asList("ModeA", "ModeB", "ModeC"),
new SettingAttribute<>(setting1, "ModeA"), // 仅 ModeA 显示
new SettingAttribute<>(setting2, "ModeB"), // 仅 ModeB 显示
new SettingAttribute<>(setting3, "ModeA", "ModeB", "ModeC") // 多个选项显示
);
public TestModule1() {
registerSetting(mode); // 只需注册根节点,子节点自动递归注册
}