可撤销动作基类

基本信息

属性 值
包 modtweaker2.utils
文件数 10 个 Base*.java(共 620 行)
实现接口 minetweaker.IUndoableAction
根类 BaseUndoable(60 行)
提交入口 MineTweakerAPI.apply(IUndoableAction)

功能

ModTweaker 的每个 @ZenMethod 在参数校验通过后都不会直接改动游戏注册表,而是构造一个 IUndoableAction 并交给 MineTweakerAPI.apply(...) 提交。这让整包脚本可以被 MineTweaker 统一重载与回滚。modtweaker2/utils/ 下的 10 个抽象基类把「往 List / Map / 合成表里增删」这四种重复模式各抽了一层。

类族

类 行数 继承 用途
BaseUndoable 60 IUndoableAction 根类,持有 name 与 success
BaseListModification<T> 114 BaseUndoable 持有 list / recipes / successful 三个 LinkedList
BaseListAddition<T> 66 BaseListModification<T> 逐条 list.add(),成功项记入 successful
BaseListRemoval<T> 73 BaseListModification<T> 逐条 list.remove(),撤销时 list.add() 还原
BaseMapModification<K,V> 52 BaseUndoable 同上,容器换成 Map
BaseMapAddition<K,V> 83 BaseMapModification<K,V> map.put(),被覆盖的旧值存入 overwritten
BaseMapRemoval<K,V> 61 BaseMapModification<K,V> map.remove() 并在撤销时回填
BaseCraftingAddition 23 BaseListAddition<IRecipe> 固定为 IRecipe 列表
BaseCraftingRemoval 39 BaseListRemoval<IRecipe> 固定为 IRecipe 列表
BaseMultiModification 49 BaseUndoable 把多个 IUndoableAction 串成一个原子动作

撤销语义

BaseUndoable.canUndo() 直接返回 success 字段(BaseUndoable.java:23-26),而 BaseListModification.canUndo() 收紧为「recipes 与 successful 都非空」(BaseListModification.java:17-21)。也就是说只有真正改动了至少一条注册表记录、且该改动成功落地的动作才可回滚;纯失败的动作不占用回滚槽位。

BaseMapAddition 额外维护 overwritten(BaseMapAddition.java:14),在 apply() 里若 map.put() 返回了非空旧值,就记一条 logWarning 并把旧值存进 overwritten(BaseMapAddition.java:33-45),撤销时再写回——这使得「覆盖已有配方」也能被正确还原。

BaseMultiModification 是唯一的组合器:apply() / undo() 都只做一层 for 循环转发(BaseMultiModification.java:15-19、:42-46),canUndo() 要求每个子动作都可撤销(BaseMultiModification.java:21-28)。

失败不抛异常

apply() 遇到单条配方失败时走 LogHelper.logError(...) 而不中断循环。以 BaseListAddition.apply() 为例(BaseListAddition.java:24-40):list.add() 返回 false 就记一条 Error adding %s Recipe for %s;配方对象为 null 则记 Error adding %s Recipe: null object。undo() 侧对称(BaseListAddition.java:42-58)。因此一次 addRecipe 可以部分成功,脚本不会因个别配方冲突而整体回滚。

描述文本

所有基类的 describe() / describeUndo() 都用 String.format 产出以 [ModTweaker2] 开头的英文串(BaseUndoable.java:28-35、BaseListAddition.java:60-67)。这与 反射与日志助手 中 LogHelper.logError 统一追加的 [ModTweaker2] 前缀一致。

身份与去重

BaseUndoable.equals() 只比较 name 字段,hashCode() 返回 name.hashCode()(BaseUndoable.java:37-55)。getOverrideKey() 恒返回 null(BaseUndoable.java:57-60)。多数具体动作(如 Chisel 的 AddVariation)另行覆盖 getOverrideKey()。

一处非缺陷的命名

BaseListAddition 与 BaseListRemoval 的三参构造函数把参数拼写为 recipies(BaseListAddition.java:13),而方法体里往 recipes 字段 addAll。二者不是同一标识符:recipes 是 BaseListModification 声明的 protected final LinkedList<T> recipes(BaseListModification.java:9),recipies 是形参。方法体 recipes.addAll(recipies) 因此成立,行为正确——按代码原样记录,不作为缺陷。

相关条目