一键导入
base-module-register-all
为 SlimefunHelper 新模块补全 BaseModule 基础注册骨架。用于创建或改造模块时,统一完成模块名、ModulePath、Flag 绑定、不同类别 Ref、监听器、常用监听器、热键和命令注册。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
为 SlimefunHelper 新模块补全 BaseModule 基础注册骨架。用于创建或改造模块时,统一完成模块名、ModulePath、Flag 绑定、不同类别 Ref、监听器、常用监听器、热键和命令注册。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Analyze server-side block interaction flow around ServerPlayerInteractionManager.interactBlock, BlockState.onUseWithItem/onUse, ItemStack.useOnBlock, and BlockItem.useOnBlock in this merged Yarn Minecraft tree. Use when tracing whether right-clicking a block can fall through into item use or block placement, when classifying PASS vs PASS_TO_DEFAULT_BLOCK_ACTION behavior, or when summarizing special interactable block families.
理解并维护 SlimefunHelper 中 `ElytraExtra.applyAxisLimit2` 的 Elytra 烟花容错盒、两帧 look 叠加、目标逼近与爬升策略选择。用于分析 `currentMotion = currentRotation * 1.7` 一类上推方案,判断斜向追点、竖直拉升、前后折返等 rotation 序列的收益与约束。
Grim 中 Elytra 预测、烟花容错、offset 判定与 setback 回滚的结果逻辑。用于直接回答滑翔检测、fireworksBox、1.7 来源与拉回后高速原因。
在 SlimefunHelper 中兼容多个 Baritone 发行形态,尤其是“全混淆”版本。用于区分无混淆、仅方法混淆、类与方法全混淆三种形态,并决定 MixinPlugin、目标类定位、成员定位、反射桥接和 hooks 访问层该如何拆分。
在 SlimefunHelper 中新增或改造模块配置屏幕时,统一复用 `WidgetUtils` 的配置屏幕组装链,而不是在模块里重复手写 `DynamicListWidget + RefKeyValueInputWidget`。用于把 `BaseModule` 的 `editableConfig`、显示条件、模块标题、主题色和自定义 widget 接到同一条打开链路上。
理解并维护 SlimefunHelper 中 `NBTType`、`NBTParsable`、`NBTRef`、`AttrKeyValue` 的自动配置链。用于分析或新增 NBT 配置类型时,追踪它如何在字符串、原始对象、NBT、Ref、可编辑 GUI 之间自动转换,并据此实现新的 `NBTParsable` / 组合型配置结构。
| name | base-module-register-all |
| description | 为 SlimefunHelper 新模块补全 BaseModule 基础注册骨架。用于创建或改造模块时,统一完成模块名、ModulePath、Flag 绑定、不同类别 Ref、监听器、常用监听器、热键和命令注册。 |
| disable-model-invocation | true |
为一个 extends BaseModule 的模块一次性补齐基础注册结构,保持这几个面一致:
ModulePathFlagRef 与 bindFlag所有可注册对象都走 BaseModule 提供的方法,不要绕开。
必须遵守:
registerAll()registerAll()bindFlag(enable) 绑定onEnableModule()onDisableModule()public class MyModule extends BaseModule {
public static MyModule INSTANCE;
public final ModulePath module = makePath(Configs.EXTRA_CONFIG, "my-module");
public MyModule() {
INSTANCE = this;
bindFlag(enable);
}
public final FlagRef enable = flagBuilder(module.add("enable")).build();
@Override
public void registerAll() {
super.registerAll();
}
@Override
public void onEnableModule() {}
@Override
public void onDisableModule() {}
}
有显示名需求(默认没有)时用构造器:
super("Config");
super("Printer");
super("BeaconPlus");
否则直接默认类名。
ModulePath集成了Config和Path,指定了保存路径
优先先抽一个 ModulePath 根,再从根派生:
public final ModulePath attack = makePath(Configs.COMBAT_CONFIG, "attack");
public final ModulePath moveSafety = makePath(Configs.MOV_CONFIG, "move-safety");
子项统一通过根项追加生成:
attack.add("whitelist")
moveSafety.add("auto-resync-pos")
配置项使用的路径命名风格需要是类似上面的带- - 的, 不能使用java风格的命名
如果该模块希望可以在菜单中快捷启用/关闭, 则其需要指定一个 enable flag,并在构造器中绑定:
public final FlagRef enable = flagBuilder(module.add("enable")).build();
public MyModule() {
bindFlag(enable);
}
这类模型通常只有一个主要功能
// 默认值为false,不可修改
public final FlagRef enable = flagBuilder(module.add("enable")).build();
public final FlagRef log = builder(module.add("log"), Boolean.class)
.defaultValue(true)
.build();
public final IntRef delay = intBuilder(module.add("delay"))
.defaultValue(5)
.validator(Configs.INT_POSITIVE)
.build();
public final DoubleRef threshold = doubleBuilder(module.add("threshold"))
.defaultValue(0.5D)
.validator(Configs.doubleRange(0.0, 1.0))
.build();
public final StringRef regex = builder(module.add("regex"), StringRef.TYPE)
.defaultValue("^(.*)$")
.validator(Configs.REGEX_VALIDATOR)
.build();
ListRef 只存 String 列表。
public final ListRef friendList = builder(module.add("friend-list"), ListRef.TYPE)
.defaultValue(List.of())
.listValidator(Configs.REGEX_VALIDATOR)
.build();
public final EnumRef<Type> mode = builder(module.add("mode"), Type.class)
.defaultValue(Type.DEFAULT)
.build();
要求该枚举实现 ConfigEnum。
public final NBTRef<Vec2> pos = builder(module.add("pos"), Vec2.class)
.defaultValue(new Vec2(0.5D, 0.5D))
.validator(v -> v.x() >= 0.0D && v.y() >= 0.0D && v.x() <= 1.0D && v.y() <= 1.0D)
.build();
运行功能形快捷键:
public final KeyBindRef openMenu = hotkey(module.add("open-menu"))
.defaultValue(new MultiKeyBind(KeyCode.KEY_LEFT_CONTROL, KeyCode.KEY_G))
.registerHotkey(HotKeyUtils.wrapAsHandler(this::openMenu))
.build();
切换形快捷键在下章
我们有一些功能会注册到ModuleList中, 其中 ModuleEntry是我们注册的东西
一个ModuleEntry并不和一个BaseModule绑定, 一个BaseModule可以注册多个ModuleEntry
只要有一个FlagRef和配套的KeyBind用于切换该FlagRef即可注册ModuleEntry
public final FlagRef enable = flagBuilder(module.add("enable")).build();
// 通过调用moduleEntry方法将enable绑定到该快捷键并自动注册ModuleEntry
public final KeyBindRef hotkey = moduleEntry(module.add("hotkey"), new MultiKeyBind(), module.add("enable"))
.build();
// 可以通过该方法设置动态附加给ModuleEntry的metadata, 让其显示例如当前模式等
public final KeyBindRef hotkey = moduleEntry(module.add("hotkey"), new MultiKeyBind(), module.add("enable"), () -> Text.literal("当前的模式..."))
.build();
用于拦截非法值:
.validator(Configs.INT_POSITIVE)
.validator(Configs.doubleRange(0.0, 1.0))
.validator(Configs.REGEX_VALIDATOR)
用于配置变化后同步派生状态:
.updateListener(this::parseEntityTypes)
.updateListener(v -> compile = v.stream().map(Pattern::compile).toList())
.updateListener(v -> typesDebug = getDebugTypes(v))
仅 ListRef 使用:
.listValidator(Configs.REGEX_VALIDATOR)
用于配置界面显隐:
.show(() -> controlType.get().isIn(Type.MOV_VOID_2))
.hideConfig()
统一放在 registerAll()。
@Override
public void registerAll() {
super.registerAll();
registerListener(Listener.getPostGameTick(), this::onTick);
registerListener(Listener.getWorldSwitchPoint(), this::onWorldSwitch);
registerListener(Listener.getCustomListener().getChannel(ModulePreset.class), this::onModulePreset);
registerListener(Listener.getPacketPoint().getChannel(PlayerPositionLookS2CPacket.class), this::onSetBack);
}
监听channel定义在Listener和RenderListener两个类中
Listener.getPostGameTick() // post tickListener.getPreGameTick() // pre tick优先用 getChannel(Class) 精确收窄:
registerListener(Listener.getPacketPoint().getChannel(PlayerPositionLookS2CPacket.class), this::onSetBack);
如果包含了全部入站/出站包,可以使用
registerListener(Listener.getPacketPoint().getPacketSendChannel(), this::onSetBack);
registerListener(Listener.getPacketPoint().getPacketReceiveChannel(), this::onSetBack);
注: 常用的channel:
registerListener(Listener.getCustomListener().getChannel(ModulePreset.class), this::onModulePreset);
public final KeyBindRef actionKey = hotkey(module.add("action"))
.defaultValue(new MultiKeyBind(KeyCode.KEY_Z))
.registerHotkey(HotKeyUtils.asHandler(this::doAction))
.build();
用于让该快捷键在打开其他屏幕/玩家不在游戏中 的时候不起作用 如果该功能涉及游戏修改,那么最好需要使用
.registerHotkey(HotKeyUtils.wrapAsHandler(this::openConfigMenu))
(仅包含不需要注册为ModuleEntry的开关)
public final KeyBindRef toggleKey = toggleHotkey(
module.add("toggle-hotkey"),
new MultiKeyBind(KeyCode.KEY_X),
module.add("enable"))
.build();
在ModuleEntry处已经讲过了
统一放在 registerAll():
@Override
public void registerAll() {
super.registerAll();
registerCommandBootstrap(this::bootStrapTargetCommand);
}
命令包含若干类型节点:用来操纵参数流以及响应
我们的MainCommand构成:一个AbstractMain
向MainCommand的List节点中注册一个命令节点时,要先分清你要的是哪一层:
mainBuilder():直接把 Tree 节点塞进 MainCommand 的 List 根节点subMainBuilder():先用同名 Bridge 节点包一层,再把里面的 Tree 节点塞进 MainCommand 的 List 根节点这里有一个关键点:
mainBuilder() 返回的 Tree 节点名字本身不重要,因为它是被直接放进 List 根节点里按顺序尝试接收的subMainBuilder() 这种“先包一层 Bridge”的入口,Tree 的名字才会作为外部命令分发名真正生效直接注册 Tree 节点的例子:
public void bootStrapTargetCommand(MainCommand mainCommand) {
TreeSubCommand main = mainCommand.mainBuilder().name("target").build();
main.subBuilder(SubCommand.treeBuilder())
.name("calculate")
.post(m -> m.subBuilder(SubCommand.taskBuilder())
.name("pos")
.helper("<target> calculate")
.arg(SimpleCommandArgs.argumentBuilder(MyArgType::new).name("target").build())
.post(s -> s.executor(CommandContext.execute(this::onTarget)))
.complete())
.complete();
}
registerCommandBootstrap(this::bootStrapTargetCommand);
需要把整棵树作为一个具名子命令暴露时,用 subMainBuilder():
public void bootStrapConfigCommand(MainCommand mainCommand) {
TreeSubCommand main = mainCommand.subMainBuilder().name("config").build();
main.subBuilder(SubCommand.taskBuilder())
.name("open")
.post(e -> e.executor(CommandContext.run(this::onOpen)))
.complete();
}
可以注册一个SubCommand Factory 通过registerCommands和registerSubCommands注册入MainCommand
其中 两者的区别在于registerCommands直接将实例加入MainCommand的List节点中, 而registerSubCommands会先包装一个Bridge节点(用提供的name)再加入List节点
public void onTarget(CommandExecution exec, ArgumentInputStream args) {}
public boolean onTarget(CommandExecution exec, ArgumentInputStream args, ArgumentReader reader) { return true; }
public void onCancel() {}
只放这些:
INSTANCE = thissuper("Name")bindFlag(enable)不要在构造器里注册监听器和命令。
只放注册动作:
registerListener(...)registerCommandBootstrap(...)TargetSelectorAutoResyncConfigSystemTargetCommandWarpsonEnableModule() 里重复注册监听器BaseModule 自己向输入系统塞热键String[] 常量无需检查,用户会自行检查 无需编译,用户会自行编译 无需风格对齐,用户会自己spotless