编辑会话与历史

基本信息

属性 值
编辑会话类 com.sk89q.worldedit.EditSession(EditSession.java:130,implements Extent)
持有者 com.sk89q.worldedit.LocalSession(每玩家一个)
历史实现 LocalSession 内的 List<EditSession> + historyPointer 游标
历史上限 LocalSession.MAX_HISTORY_SIZE,字段初值 15(LocalSession.java:61)
历史包 com.sk89q.worldedit.history(UndoContext.java + change/ + changeset/)

历史栈机制

LocalSession 用双字段模型:列表 history 与倒序游标 historyPointer(LocalSession.java:71)。

写入一次新操作时,LocalSession.remember(EditSession)(LocalSession.java:188)执行:

195  while (historyPointer < history.size()) {   // 丢弃此撤销点之后的所有 redo 分支
196      history.remove(historyPointer);
197  }
198  history.add(editSession);
199  while (history.size() > MAX_HISTORY_SIZE) { // 超出上限时丢最老的
200      history.remove(0);
201  }
202  historyPointer = history.size();

因此先做新操作会清空 redo 分支(:195-197),历史超过上限时从头部淘汰(:199-201)。

undo 先把游标左移再取记录(LocalSession.java:225-227:--historyPointer; if (historyPointer >= 0) { EditSession editSession = history.get(historyPointer); …),越界时返回 null,命令层据此打印 “Undo successful.” 或不打印。

历史上限有硬下限 15

MAX_HISTORY_SIZE 由配置赋值(PropertiesConfiguration.java:111):

LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15));

Math.max(15, …) 意味着把 history-size 配成 5、0 或任何小于 15 的值都无效,实际仍为 15。这与 LocalConfiguration 字段初值 15(LocalSession.java:61)一致。

同仓 YAMLConfiguration.java:100 用的是 Math.max(0, config.getInt("history.size", 15)),下限不同。YAML 配置在 1.7.10 Forge 版未被使用(Forge 侧只构造 ForgeConfiguration),故不影响本条目所述行为——但这是上游两套配置实现的一处不一致,记录备查。

改动上限与 MaxChangedBlocksException

EditSession 逐次记录改动方块数(getBlockChangeCount(),EditSession.java:438)。写方块的核心入口有 3 个重载:

方法 行
setBlock(Vector, BaseBlock, Stage) EditSession.java:543
setBlock(Vector, BaseBlock) EditSession.java:587
setBlock(Vector, Pattern) EditSession.java:606
setBlockIfAir(Vector, BaseBlock) EditSession.java:654

超出 max-changed-blocks 时抛 MaxChangedBlocksException(配置默认 -1 = 不限)。会话级初始上限由 default-max-changed-blocks 决定,注入点为 SessionManager.java:159(session.setBlockChangeLimit(config.defaultChangeLimit))。

掩码

EditSession 持掩码,写入前逐方块判定。两个 setMask 重载(EditSession.java:338、:354)分别接受 com.sk89q.worldedit.masks.Mask 与另一套 Mask 接口。掩码可由单条命令设置(//gmask)或由刷子参数(/mask)设置,详见 工具与超级镐指令。

会话与玩家的绑定

  • 取会话:ForgeWorldEdit.getSession(EntityPlayerMP)(ForgeWorldEdit.java:312-317),内部 WorldEdit.getInstance().getSessionManager().get(wrap(player))
  • 每个玩家一个 LocalSession,选区、掩码、历史互不可见
  • 会话本体落盘见 会话与存档

交互

  • 一次 //undo 撤销一整个命令(含该命令产生的所有方块改动),而非单个方块
  • //undo 撤销他人会话需 worldedit.history.undo.other 权限(HistoryCommands.java:62)
  • 方块写入走队列模式:EditSession.enableQueue() 开启、disableQueue() 关闭;disableQueue() 在关闭前若队列仍启用则调用 flushQueue() 把待写方块落盘(EditSession.java:310-322)

相关条目