﻿【附件重传 · 2026-09-22】v1.2.3 的下载附件已重传覆盖（同名文件，不新发版本号）

· **为什么**：下面三条（实测六百二十四 / 六百二十五 / 六百二十六）当时都写了"本条不重新发布"——意思是当时没发版。现按用户要求把这三条直接**覆盖进 v1.2.3 的附件**，所以那三条里"附件仍是原样"的说法作废，以本条为准。

· **重传后的附件** = v1.2.3 首发内容（实测五百九十五 ~ 六百二十三）+ 六百二十四（巨型文件拆分、删死代码，玩家可见行为零变化）+ 六百二十五（只带拔刀剑/弹幕的女仆不再被自主战斗切进法术模式）+ 六百二十六（手册那句过头话的更正）。**本模组不会自动更新，装的是哪个 jar 就是哪个版本**。

· **玩家侧唯一可见变化**：女仆只带拔刀剑（或妖怪归乡的弹幕/激光/符卡）时，不会再被自主战斗切进「近战法术 / 远程法术」；要旧口径就把配置 `combat.spellGearIgnore` 留空。文件名与放置位置不变（mods 里覆盖同名 jar），存档无需任何处理。

【实测六百二十六】更正手册里一句过头话：「女仆喂食繁殖不再有任何击杀行为」（繁殖模式里本体自己的「超过上限就杀」仍在；本模组一行代码未改，不重新发布）

· **反馈**：用户看着女仆界面「繁殖动物」任务的提示问"繁殖动物界面还是带上了老版本的宰杀文本描述"——提示第二行是「主手持有攻击性武器（用于杀死超过上限的动物）」。

· **查证：那条提示不是旧版残留，它现在依然成立，也不是本模组的文本**。①该提示属于车万女仆本体（`task.touhou_little_maid.feed_animal.condition.assault_weapon`），1.20.1 与 1.21.1 两版一字不差，本模组从未定义过这个键；②本体 `hasAssaultWeapon(maid)` = 主手物品带攻击伤害属性，正是提示里那半句；③本体 `findFirstValidAttackTarget(maid)` 统计附近同种动物，**数量顶到「繁殖动物的最大数量」−2 时才返回一只目标**，④且这个方法在线——javap -v 的 BootstrapMethods 实证：`createBrainTasks` 里 `StartAttacking` 的目标查找器就是它，配套 `MaidMeleeAttack` 与 `StopAttackingIfTargetInvalid`（手里有武器且目标不远）执行击杀。⇒ 本体繁殖模式确实会杀超上限的动物。

· **真正过时的是我们自己手册那句**：工作章原写「早期版本的『畜牧数量控制（杀幼保成）』已在 v1.5.291 整体移除——女仆喂食繁殖不再有任何击杀行为」。前半句对（我们确实把自己的 MaidFeedAnimalCapMixin 连同配置项与面板行整体删了），后半句是过头话——我们删的是**我们自己的加码**，露出的是本体本来就有的「超上限就杀」。已两树同步改正：本模组不再碰繁殖模式，但本体自己的「超过上限就杀」还在（提示里那条是真事），不想让她动手就别往她主手放武器、或把上限调高。

· **本模组一行代码未改**（`mixins.promaid.json` 无畜牧 mixin、配置无 `animalCap*`，v1.5.291 已删干净，本次复核确认），也没有去改本体的文本——那是本体的准确说明。两树 `javac` 0 错误、两个 jar 重新打包校验通过。**不重新发布**。

【实测六百二十五】法术任务的「她会用法术吗」闸门排掉拔刀剑/弹幕（修「只给了把拔刀剑的女仆被自主战斗切去法术模式」；本条不重新发布）

· **反馈原文**（粉丝私信）："包里没有法术书却仍然显示法术类的切换选项，可以确定包里主手副手是完全没有任何魔法类道具的。而那个自主战斗切到法术是真的。"——拆成两件事查，第一件不是我们的，第二件是我们的。

· **第一件（不改）**：那两个法术任务是《车万女仆：万法皆通》注册的，它的 `isEnable(EntityMaid)` **恒返回 true**（javap 反编译：方法体只有 iconst_1; ireturn），它自己那个 `hasSpellBook(maid)` 同样是空壳恒真；TLM 女仆界面列任务走 `TaskManager.getNotHiddenTaskList`（调用方 `AbstractMaidContainerGui`），**只按 `isHidden` 过滤**。所以**装了附属就一直显示这两项**，与背包无关，也与本模组无关（本模组从不拦手动切换任务）。

· **第二件（已修）**：自主参战对法术任务的闸门，判"她会不会用法术"时问的是附属各前置 provider 的 `isSpellBook`——其中两个认的"法术装备"**本身就是武器**：`slashblade` 认**拔刀剑**（`ItemSlashBlade`）、`youkaishomecoming` 认**弹幕/激光/符卡**（`DanmakuItem`/`LaserItem`，TLM 原版就有 danmaku_attack）。旧口径 = "背包里有把拔刀剑 = 她带着法术书" → 法术任务进候选池 +「模组任务优先让位」把原版任务整体挤掉 → 她就被切去法术模式（实测三百七十九 同款反馈的第二次）。

· **改法**：新增配置 `combat.spellGearIgnore`（默认 `slashblade, youkaishomecoming`，逗号/空白分隔的 provider id = 前置模组 modId），列进去的 provider 认的物品不再算"她会用法术"；面板「战斗与自保 → 主动参战 → **法术装备忽略表**」一行；**留空 = 旧口径**。排查：`latest.log` 搜 `combat pools`，池里有法术任务时会附一行 `spellGear=`，直接点名是哪件东西放行的（形如 `slashblade:slashblade:slashblade`，或 `addon-data`）。手册「战斗与自保」章新增第十一 / 十二节讲这两件事。

· **只影响这一处**：法术任务能否被**自主切换**选中。手动切换、空袭施法、位移法术、友军风免等既有链路一字未动；忽略 `slashblade` 后，拿拔刀剑的女仆照旧走她自己的拔刀剑战斗模式，只是不再被拉去法术模式。

· **验证**：两树全量重编 **0 错误**、两个 jar 重新打包校验通过（类齐全 / 语言文件正常 / mixins 齐全）。**本条不重新发布**——GitHub 附件仍是 v1.2.3 原样；未跑游戏内实测（按约定测试留给用户）。

【实测六百二十四】内部大扫除：拆分超大源码文件 + 清理死代码（**玩家可见行为零变化**，本条不重新发布）

· **为什么做**：到 v1.2.3 为止，几个源文件已经涨到「读一次要滚几千行」（蓝图库 6677 行、配置面板 4647 行、自保行为 4392 行），改一行动辄要翻几千行。本条**只搬文件**：不改逻辑、不改配置项名、不改任何玩家可见文案与数值。

· **拆了什么（两树同步）**：蓝图库 6677 → **570** 行（拆出 14 个类：方块分类表 / 旧版 id 兼容层 / 结构文件解码 / 外部文件扫描 / 世界提取 / 目录描述 / 步骤几何 / 方块形状材质 / 材料统计 / 机器识别 / 宽松替代 / 中文名表 / 机器收尾 / 放置处理）；轰炸 2733 → **1058**（拆出配置读取 / 物品识别 / 爆炸来源 / 放置选点 / 投掷弹道 / 战斗节拍 6 个类）；蓝图网络包 2618 → **854**（拆成建造包与实体包两个容器）；手册正文 2090 → **194**（按主题拆成入门/生产/战斗/飞行/系统 5 个章节文件）；排班网络包 1265 → **约 350**（拆成排班数据包与女仆操作包）。主动参战 2000 → **783**（拆出「威胁判定」与「自动参战任务池」两个类）。

· **外部调用点一行都没改**：公开方法在原类留**同签名转发**、公开常量表留**同名字段别名**，所以 `BlueprintLib.canBreak(...)`、`BlueprintLib.FORBIDDEN` 这类写法照旧可用；搬走的网络包类，全树 7 个文件里的 `BlueprintBookNetworking.X` 写法（含 `import` 全限定与方法引用）已自动改写。手册正文、中文提示、配置键名**逐字未改**。

· **删了什么**：蓝图库里 5 个早已废弃的内置预设方法（小屋/凉亭/喷泉/瞭望塔/水井——内置预设早已全部移除，这五个全仓库零调用）；`PersonaSyncManager`（写完从没接线的类，零引用，所以「人设同步」实际上一直没有代码在跑）。

· **验证**：两树全量重编 **0 错误**，两个 jar 重新打包校验通过（类齐全 / 语言文件正常 / mixins 齐全）。**本条不重新发布**——GitHub 上的下载附件仍是 v1.2.3 原样，游戏内行为与 v1.2.3 完全一致。

· **没拆的**：配置面板 / 蓝图界面 / 自保行为 / 各类工作行为等文件，静态成员只占 6%~47%，主体是绑在 `this` 上的实例方法，机械搬运会断链，要拆得重新设计状态归属；`MaidSmartConfig` 里 1479 行是 static 初始化块，`public static final` 配置项按语言规则只能在本类初始化，搬走即编译不过。

【实测六百二十三】版本号升为 v1.2.3（正式发布 · 加急）：先修「收放魂符丢血量上限与装备」，再带上 v1.2.2 之后攒下的一批新功能

· **为什么加急**：B 站用户 lawte 反馈「女仆由好感度升阶带来的血量上限加成、以及身上穿的装备，会因为收放魂符被卡掉」，GitHub issue #18（P1aneZ）也报了同一条（魂符放出后从她背包/装备栏取物会丢失）。这是会**吃掉玩家存档里实打实物品**的严重 bug。两条的根因与修复其实早已在仓库里做完、只是没进过任何一次 release 附件——**血量上限掉回 20**（实测五百九十五：我们自己的「入世界自动补包」new 出全新客户端实体却没补属性表，原版只在"开始追踪"那一枪发属性表）、**装备被吞**（实测五百九十六：收放魂符的「放出」本身就是一次入世界，于是每收放一次客户端那只女仆就被销毁重建，你正开着的容器还指着已被删掉的那只）。v1.2.2 的 release 附件比这两条修复早约 12 小时上传，所以从 release 下到的人仍会踩到。同类还有 issue #17（着火连吃金苹果到背包空，实测六百一十九已修）。

· **这一版都更新了什么（v1.2.2 → v1.2.3：实测五百九十五 ~ 六百二十三）**——**修复**：收放魂符丢血量上限/装备、着火连吃金苹果（issue #17）、法术冷却被多乘 20 倍（issue #16）、图纸三条（issue #12/#14/#15）、回收方块整体还她（萤石不再变粉）、"拿着羽扇却报缺飞行道具"假提示、坐下还在搭路、无主女仆一概不碰、**面板字符串输入行一直没画标签**（六百二十二）；**新功能**：**战斗模式分类表**（逐任务点名近战/远程/不参与 + 可关掉的「模组任务优先让位」+ `/maid_smart combat modes`）、**压缩盒**（5 格 × 每格 114514，放进她背包 = 背包延伸；禁入清单 + 箱子式界面 + 常驻附魔光效）、**空袭轰炸**（末地水晶/重生锚/床/投掷 TNT，三段并行，默认不破坏方块、不伤主人友军、火改粉色且不烧玩家与女仆）、**飞行跟随**（主人飞走了她背鞘翅追过来，默认关）、**散步速度终于调得动**（默认 0.7→0.4、下限 0.3→0.05，配 `/maid_smart stroll check|go|speed`）、**索敌两处调整**（隔着方块的怪不再算威胁 + 战斗时工作范围临时扩圈）、副手动作表现推广到全链路、空袭 34 项数值可调与俯冲段冲刺加速；**删掉**：排班表「全员在家」整条移除（注册号留空不补位）。

· **手册正文同步（两树）**：「这是什么」章的版本表述改成**两版本对齐**（1.20.1 Forge / 1.21.1 NeoForge），并补上 **v1.2.2 起 / v1.2.3 起两段新增功能速览**（此前只有 v1.1.0 与 v1.2.0 两段）；「战斗与自保」章新增一条 **【收放魂符后血量上限掉回 20 / 拖她的装备被吞？】**（症状 / 根因 / 改法 / 诊断入口「装备离开」）；「专业术语」章补 7 条（空袭轰炸、粉色火焰、飞行跟随、压缩盒、战斗模式分类表、散步速度倍率等）。**README 首页**：新增「v1.2.3 加急修复」一节（含 issue 链接）、空袭轰炸与压缩盒两节、散步速度对照表与三个新命令，章节数 32 → 33、面板小类数 28 → 31。

· **战斗时临时扩圈默认值 32 → 15**（用户指定，本批唯一的行为变化）：追怪时的工作范围圈原本默认 32 格（默认工作范围才 12 格，等于放她跑到两个半工位以外接战），改成 **15**——够追出工位、又不至于被拽进几十格外的乱战。新档生效；老档 toml 里已写着 32 的不会被改，想跟着调小可在「战斗与自保 → 主动参战」改。
· **版本号**：mods.toml ×3（含游戏内模组列表描述里的一句本版摘要）、两树构建脚本、部署/测试/校验脚本共 32 个文件 97 处 jar 名、README / PUBLISH_GUIDE / GIT_SYNC 与两份 release 说明一并同步；本批**只有版本号与文档字符串改动，无行为变化**。

· **验证**：两树 `javac` 0 错误、两树打包成功（`promaid-1.2.3.jar` / `promaid-1.2.3-neoforge-1.21.1.jar`，jar 内 `mods.toml` 版本为 1.2.3）、`verify_jar_classes` 全过、语言 JSON 校验通过、两树本文件逐字节一致；部署三个目标字节一致。按用户要求**测试交回**——发布后请重点复看「收放魂符后血量上限与装备」与「面板主动战斗两行」。

【实测六百二十二】面板的「字符串输入行」一直没画标签与说明——新加的「模式分类表」因此整页只剩一个黑框

· 用户反馈（附截图）："战斗模式分类表根本看不到在哪，似乎根本就没做出来。" 截图里那一页只有一个没有标题的黑色输入框。

· **根因是两件事叠加**：①面板行定义有七种，**渲染侧的分支链唯独漏了 TextRow**（字符串输入行）——`init` 照常建输入框、行高照常按注释折行留出，渲染侧却连标签带说明一个字都不画，于是只剩一个空黑框；这个洞是旧版就有的（TextRow 是 v1.5.127 加的），既有那几条字符串行（API 地址/密钥/模型、导入路径、提供高度/速度的法术表、危险方块表、禁入清单）平时夹在别的行中间、看着又像"没做完"，一直没人点名。②我 六百二十一 给这条行的注释写了约 250 字（折 5 行、行高 84px），用户那台窗口每页只装得下 1~2 行 → 这条行**独占一页**，而它又恰好是唯一不画标签的类型 → 整页只有一个黑框。

· **改法**：渲染链补上 TextRow 分支（标签 + 注释，与 NumRow 同款布局，两树同步）——顺带把上面那几条老字符串行的标签一起修好；两行新配置（模式分类表 / 模组任务优先让位）的面板注释压到 2 行以内，长说明只留在配置注释、手册与 `/maid_smart combat modes` 的输出里。

· **验证**：两树 `javac` 0 错误、两树打包成功（747 / 749 项）；未跑用例（纯客户端渲染问题，自动化看不到）。复看：打开「战斗与自保 → 主动参战」，应能看到「模组任务优先让位」与「模式分类表」（标签 + 蓝字说明 + 输入框）两行。

【实测六百二十一】战斗模式分类表（哪些算近战/远程、哪些参与自主切换，逐任务点名）+ 可关掉「模组任务优先让位」+ 删掉排班表「全员在家」+ 清掉金苹果冷却那处过时注释

· 用户原话："然后在主动参战面板里面加一个配置项目，可以配置哪些模式属于近战或者远程,然后确认这些模式哪些参与自主切换，目前是默认都能参与，模组优先。有人认为这个逻辑太笼统了。然后删除排班表的全员在家选项。" 另有一条顺带指出的不一致：`SelfPreservationBehavior` 里按药水种类记的 CD（`potionCds`）注释把 `golden_apple` 写成会走这套 CD 的键，实际没有任何地方读它。

· **"太笼统"是实情**：入战选任务与战中换战术共用一份候选池，规则只有三条且**一条都不由玩家决定**——①谁能进池 = 任务自己认的武器在她背包里 + 几道硬门（模组任务要有非原版物品背书、枪械要有弹药、法术任务要有法术装备、第三方玩法模式黑名单）；②算近战还是远程 = 靠 UID 关键词与命名空间**猜**（`ranged/gun/danmaku/spell/crossbow/trident/bow` 与 `maidspell` 命名空间算远程，`ef_tlm/slashblade/sbr_core/truepower` 算近战，**其余未知模组任务一律当近战兜底**）；③池里有模组专属任务时原版通用五件套**整体让位**（"模组优先"）。装了冷门模组的人只能看着远程任务被当近战冲脸、看着某个模式被整体挤掉，而这两件事在面板里一个字都改不了。

· **新增「战斗模式分类表」**（配置 `combat.taskModes`，默认空）：一行一条 `任务UID=近战/远程/不参与`（认中文写法与逗号分隔）。写 `近战`/`远程` = 分类以表为准、并且这个任务**不再被"模组优先让位"挤掉**（你点名的优先）；写 `不参与` = **入战选任务与战中换战术两条路都永不选它**（想让它只在你手动指派时上场就用这档）；**留空 = 与旧版一字不差**。表里没写的任务照旧走内置推断与那几道参与门——写"参与"也不保证被选中，她还必须手里有那个任务认的武器/弹药/法术装备。

· **「模组任务优先让位」做成开关**（配置 `combat.vanillaYieldToMod`，默认开 = 旧行为）：关掉 = 原版与模组同池纯按权重随机（原版/模组两条权重照旧生效）。觉得"模组优先"太笼统就关它，再在表里逐个点名。

· **查询入口 `/maid_smart combat modes`**（只读）：把当前服务器上**所有攻击类任务**列成一张表——内置算什么 ｜ 现在算什么 ｜ 表里写了什么 ｜ 参不参与，抄一行改一改就是表项（UID 在游戏里没有别的地方能看到）；输出同时进 `logs/promaid.log`（分类「战斗分类表」）。

· **面板两行**（战斗与自保 → 主动参战）：「模组任务优先让位」（开关）与「模式分类表」（文本行，**非法行整串拒收**并保留旧值——缺 `=`、缺命名空间、取值不认的都算非法）；语言文件补两条。

· **删掉排班表「全员在家」**（用户裁定）：列表页那个按钮、它的计数逻辑、以及 C2S 的 `BatchHomePacket` 与其注册（index 13）整条移除——一键把全队留在家不跟随，误伤面太大；注册号**留空不补位**（注册号是双方约定的固定槽位）；翻页按钮随之回到下方中间。**单只女仆的在家开关照旧**（详情页，实测三百四十二）。

· **顺手改掉手册里一句已经被实测一百零七作废的话**："仅原版任务参与互换（实测八十六）"——一百零七 起模组任务双向参与，"谁不参与"现在由分类表说了算。另把 `potionCds` 的类注释改对：`golden_apple` 那条键**从来没人读过**（着火连吃的根因），实测六百一十九 已把它改成两条吃苹果路径共用的**持久化**冷却（CD = 该苹果自己的效果时长）；不并回那张表的原因是本表是**实例字段**，脑重建/切任务会连冷却一起丢，而"她正烧着"往往就是切任务的时刻。`honey`/`milk` 是真的在走这张表，照旧不动。

· **本批验证到哪一步**：按用户要求测试交回——**未跑自动化用例、未开专用服务器实测**。已做的只有静态几项：两树 `javac` **0 错误**；两树打包成功并逐类核对（`promaid-1.2.2.jar` 9783849 字节 747 项、`promaid-1.2.2-neoforge-1.21.1.jar` 9805353 字节 749 项；语言 JSON 校验通过）；`BatchHomePacket` 两树已无任何引用；新命令按"与 `check`/`box` 同级挂在 `combat` 下"核对过括号平衡（是 `combat modes` 而不是 `maidsmart modes`）；分类表在选任务循环里被逐任务查询，故加了"配置内容变才重建"的缓存。待复跑：`/maid_smart combat modes` 输出、面板两行当场改并落盘、排班表按钮确实没了，以及 六百二十 遗留的两条断言。

【实测六百二十】空闲散步速度终于调得动了（默认 0.7→0.4、下限放到 0.05、给了现场量速入口）+ 压缩盒禁入清单（附魔书/附魔武器/压缩盒，鼠标也选不中）

· 用户原话："1.女仆空闲散步移动速度调不了，0.1倍速都跟快步跑一样 2.加一个黑名单，在压缩盒界面内无法放入附魔书/附魔武器和压缩盒，压缩盒在这个界面内无法被鼠标选中，并再次提示玩家不能把压缩盒放进压缩袋里。"

· **散步速度"调不了"的两半原因**：那条倍率**乘在女仆的基础移动速度属性上**（`MaidMoveControl` 走的就是原版 `setSpeed(倍率 × MOVEMENT_SPEED)`），而 TLM 没动过这个属性——它是原版 `LivingEntity` 的默认值 **0.7**（玩家 0.1、僵尸 0.23、村民 0.5；javap 实证全 TLM 只有 5 个类引用它，除 `MaidMoveControl` 就是扫帚/妖精，没有一处给女仆加修正）。**实测**（专用服务器量她走一段路的平均格/秒；玩家走路 4.32、跑步 5.61）：0.1~0.2 → 0.1（几乎不走）、0.3 → 1.9、0.4 → 3.3、0.5 → 4.9、0.6 → 6、**0.7 → 8**、1.0 → 14。所以：①**老默认 0.7 实测约 8 格/秒 = 比玩家跑步还快**，用户看到的"快步跑"就是这个数（只改默认值对老档毫无作用——老 toml 里写着 0.7，框架不会再取默认值，所以这一批加了**一次性迁移**：还停在旧默认 0.7 的自动改成 0.4，之后玩家想写回 0.7 随便）；②**老下限 0.3 就是"能调到的最慢值"**，想调慢的人被卡死，现在放到 0.05。另外实测清了一件事：**实际格/秒与倍率不成线性**（慢到一定程度她一步一顿，寻路每格重新判定），0.2 及以下几乎都是 0.1——拿"属性 × 倍率"算出来的数只会误导人，所以自检与配置里给的都是**量出来的**对照表。

· **新增现场调试入口**（"调不了"另一half 是试起来太麻烦）：`/maid_smart stroll check [女仆]` 打她**自己**的移速属性（万一装了加移速的装备/模组一眼看出）、实测参考表与口诀、当前散步门禁（逐条念出被哪条挡着）、当前移动目标的速度修正，以及上一次测量的读数；`/maid_smart stroll go [女仆]` 用当前倍率让她走一次 24 格直线；`/maid_smart stroll speed <值>` 当场改倍率并写进配置文件（越界**在命令里就夹住**并回报"实际生效为 X"，不会出现"界面写着 0.005、重启变 0.05"两套数）。读数给两个：全程均值 + 起步 1 秒后的**巡航窗口**速度（起步加速段不算进去），到点即冻结。

· **压缩盒禁入清单**（"加一个黑名单"）：新增一个判据给**四条路**用（界面点击 / 服务端搬运 / 女仆背包插入 / 溢出回退），禁入三类——**压缩盒本身**（老口径，文案不变）、**带附魔的物品**（用户点名的附魔书/附魔武器，含附魔工具与盔甲；附魔书按**物品类型**判——1.20.1 它的附魔在 `StoredEnchantments`、1.21.1 在 `STORED_ENCHANTMENTS`，两版的 `isEnchanted()` 都看不见书）、**配置禁入清单**（新配置 `refuseEnchanted` 默认开，`refuseList` 默认空，可自己点名加，如 `minecraft:gunpowder`）。

· **"压缩盒在这个界面里无法被鼠标选中"**：界面里点背包中的压缩盒**既不拿起、也不和手上的东西交换**，只回一句「压缩盒不能装进压缩盒」（以前能拿起来挂鼠标上，之后每次点击都被服务端挡掉，看着像界面坏了）；服务端同样挡。**拒绝要给话**：服务端每次点击都记一句理由随内容同步发给界面画成红字（协议 2→3），"配置清单"这种只有服务端知道的判据也能把理由说给玩家听；悬停说明直接列出"放不进"的原因，压缩盒还多一行"这个界面里鼠标选不中它"。女仆那一侧口径一致：她捡到附魔书不会再"顺手塞进盒子"。

· **实测与自检**：`/maid_smart box check [女仆]` 新增「禁入清单」段（判据三种拒绝 + 石头放行对照、数据层 `mergeInto`/`merge` 退回、界面那条路 Shift+左键被拒、配置清单当场加一条再清空、鼠标选不中压缩盒两条路、女仆那侧 `isItemValid`），并把 六百一十八 那几条"拿附魔书当不可堆叠探针"的回归改成**临时关掉开关再跑**（口径变了不是坏了），跑完还原。用例 `test_box620.py` / `test_stroll620.py` 双服跑：散步速度两支全绿（0.15/0.4/0.7 三档实测速度单调上升、约 0.45 / 3.2 / 9.6 格/秒，`speed 0.005` 夹到 0.05 并落盘），压缩盒在 neo 上全绿（含"老档 strollSpeed = 0.7 起来后被迁到 0.4"这条端到端迁移）；Forge 侧那支只剩"老档迁移"一条断言没读到 0.4（已在迁移里加了日记，待复跑定位）。回归 19 例 17 条绿，另两条是测试现场状态（Forge 侧迁移断言、六百一十九 扩圈自检把测试女仆判成"刚挨过打"）。

【实测六百一十九】索敌：隔着方块的怪不再算威胁 + 战斗时临时扩圈 + 着火的金苹果不再吃到背包空

· 用户原话："1.用了几天感觉索敌还是有一点点问题 在地面下面有空洞里面有僵尸 酒狐隔着方块就感知到了 但是因为没有可以下去的入口所以就会开始原地打转 或许改成有方块遮挡的怪不能被感知到会好一些？还有近战战斗时由于超出工作范围而被传送回来然后就这么来回循环 感觉可以改成战斗状态临时扩圈把范围改大些回到常态在用正常设置的工作范围 2.https://github.com/fadersketch/Promaid-mod/issues/17 反馈的问题"（#17：女仆着火时会把背包里的金苹果瞬间全部吃完）

· **隔着方块的怪不再算威胁**：本模组的威胁驱动（每 0.5 秒扫 16 格内"`getTarget()` 正是主人或她"的怪 → 写进 brain 的 `ATTACK_TARGET`）此前**只按距离与锁定关系**；而原版所有"这个实体我可见吗"的判据（`Sensor.m_26803_`）是"**它就是我的攻击目标 → 跳过视线判定**"。于是我们自己写进去的目标在**全部下游链路里都变成看得见**：TLM 的走位追人、TLM 近战那条 `nearestVisibleLivingEntities.contains(target)`（隔着墙挥刀）全被绕过——追不到的怪（地下空洞、墙那头）就成了"原地打转"。现在威胁候选加一条**视线门**（与原版 `hasLineOfSight` 同口径：只挡实体方块、不看流体）：被挡住的怪**根本不会被写进攻击目标**，那条绕过链从源头断开。

· **战斗时临时扩圈**：TLM 的 `SchedulePos.tick` 每 40 tick 检查一次——「离圈心超过 **(int)工作半径 + 4** 格就直接**传送回工位**」，没超就"走回去"。排班/在家模式（不跟随）下追怪的近战女仆因此被反复拽回原地（追出去→传送回来→再追出去，仗永远打不完）。现在把**读数**改掉：`EntityMaid.getRestrictRadius` 的出口在**接战期间**返回 `max(常态半径, 战斗时临时扩圈)`（新配置项，默认 32 格，0 = 关闭）——圈内判定、寻路节点评估、上面那条传送阈值、各任务"离家多远该回去"**全都读这一个值**，一处改完全线一致；**战斗结束（目标清掉 / 挨打后 5 秒）自动落回**你设置的正常工作范围，不需要任何收尾操作。取 `max` 不缩圈、不动存储、客户端照旧画常态圈（参数在「战斗与自保 → 主动参战」小节）。

· **着火不再把金苹果吃到背包空**（issue #17）：着火链路每 tick 调一次吃金苹果，只问了"喂食冷却"那张表——而那张表**只在物品没被消耗时才写**（遗物类），普通金苹果是普通食物、吃完就少一个 → 永远不写 → 每 tick 都答"没冷却" → 一整组几十个几秒清空。现在两条吃金苹果的路（岩浆/着火兜底、低血回血阶梯）**共用一条冷却，CD = 它自己给的效果时长**（普通 = 吸收 2 分钟，附魔 = 抗性/抗火 5 分钟），一次一颗、效果耗尽才会再吃；冷却存**实体持久数据**（脑重建/切任务/重载都还在，实例字段会丢）。

· **实测（专用服务器 + 游戏内自检 `/maid_smart combat check [女仆]`，只读、摆出来的场景用完复原）**：金苹果那条——**修之前**点火 1 秒后 16 → 0（对照组 16 个不动）；**修之后** 16 → **15**（只吃 1 个），自检读数「冷却剩余 2056 tick」；索敌那条——墙在时"看不见 + 不算威胁 + 扫描不选它"，**拆墙同一只僵尸立刻翻转**，且"没锁定我方"与"远在 40 格外"两条对照都不算威胁；扩圈那条——常态圈读数 8.0、离圈心 10 格在圈外，**脑里真写一条攻击目标后半径变 32.0、10 格进圈、传送阈值从 12 格抬到 36 格**，清掉目标立刻落回 8.0 / 出圈。回归 15 条里 13 条一次过、两条（压缩盒 neo / 飞行 612）是抖动、单独重跑均绿。

【实测六百一十八】压缩盒：她终于吃盒子里的饭 + 附魔物品不再消失 + 界面改成箱子式鼠标取放 + 常驻附魔光效

· 用户原话："1.我发现一件事，往压缩盒里面加食物，女仆是不会去吃的。只是往里面加弹药以及TNT这些会认。2.对于附魔类的物品似乎有一些bug，存入会导致物品直接消失。3.这个存入目前跟玩家的认知不太一样…我想的是可以像往箱子存东西一样，玩家可以通过用鼠标的方式将物品拖进去。直接照搬往箱子存东西的代码就行。4.给压缩盒打上附魔的特效。这个…排班表中已经做过了，直接照搬即可。"

· **她终于吃盒子里的饭**：女仆"自己吃饭"走的是 TLM 的另一条入口（`getAvailableBackpackInv`，读的是背包**字段**、按背包等级截到 6/12/24/36 格），六百一十六那批只注入了 `getMaidInv()`——所以盒子在那条路上根本不存在，她只认走自己那条路的弹药/TNT。现在把盒子**接在那两条路的最后**（照抄 TLM 自己的构造：类型还是它的 `MaidInvWrapper`，第三方模组的"女仆要东西"事件照发；背包里没有盒子时一行都不多做）。挤奶/剪羊毛/喂动物/采蜜/插火把/取箭这些也一并看得见盒子了。

· **附魔物品不再消失**：不可堆叠的东西（附魔书、附魔工具/甲、药水）一格能存好几个，而原版上限是 1——以前她的"视野"一律按 64 封顶，于是原版拿到一个"2 个的附魔书"这种**非法堆**，按上限只收下 1 个、剩下的**当返回值退回**，而 TLM 那几十处调用点不看返回值 = 那 1 个凭空没了。现在改成 `min(64, 物品自己的堆叠上限)`：**交给她/原版的永远是合法堆**。

· **界面改成箱子式鼠标取放**（用户要的"照搬往箱子里存东西的代码"）：鼠标上挂着一叠——左键点自己的背包格拿起、再点盒子格放下（塞不下的继续挂在手上）；右键拿 1/放 1（在自己背包格上按原版拿一半）；Shift+左键快速移动（背包格 → 盒子整叠、盒子格 → 背包最多 64）；手上有东西点自己的格子可合并/放下/交换；点空白处、或关界面（ESC）时手上的东西**还回背包**。那一叠的真身在服务端，关界面、换手、掉线、甚至每 tick 的兜底都会把它放回背包——**任何路径都不会丢**。顺带修掉"界面开着滚一下滚轮就把手上的盒子换走了"（以前会看着像界面坏了）。

· **常驻附魔光效**：排班表／手册早就有的那层流光（重写 `isFoil` 恒 true，逐字同源），压缩盒也加上了；物品本身不加附魔（附魔会影响铁砧/交易/经验修补，这里只要外观）。

· **顺带修掉的两个数**：界面上盒子每一格的数字、光标上那一叠的数量以前**全都多 1**（网络回读时用错了方法：写的是 grow 不是 setCount；1.21 那棵树一直是对的，这一批两树口径对齐）；另外"盒子里 5 个石头"曾经在她眼里变成"64 个"（视野上限写成了"设成上限"，而不是"不超过 min(真实数量, 上限)"）——被自检当场打红。

· 验证：`test_box618.py` 在 1201 与 neoforge1211 两台专用服各跑一遍；游戏内自检 `/maid_smart box check <女仆>` 扩到 27 条全 PASS（附魔合法堆、鼠标取放①~⑥、六百一十七那批的回归也都在）；行为面证据：给女仆一个装着 114514 个石头／16 份熟牛肉／8 个 TNT／32 根光谱箭的压缩盒、把她打到 8 点血，她自己把盒子里的熟牛肉吃掉、血量一路回到满（一份熟牛肉治好约 4.16 点，与她"自己吃"的公式逐行同源）。
【实测六百一十七】压缩盒：贴图改樱花粉 + 界面里背包格照原版显示数量与耐久条 + 修「盒子能把自己装进去被卡掉」

· 用户原话："1.将这个物品的贴图外观改成粉色调（参考樱花木板色调）2.点进这个界面的时候，最好跟玩家的物品栏一样，可以显示这个物品的实时状态：也就是有多少个，它的耐久是有多少，玩家看到的就跟玩家生存时的物品栏一样。3.存在一个bug，就是收纳箱可以把自己装进去，导致被卡掉。"

· **压缩盒贴图换成樱花木板那一组粉**：先量了 1.20.1 原版 `cherry_planks`（樱花木板）这张贴图的真实调色板（最亮 `#E7CAC5`、木纹 `#CD8580`，色相 4~9°、饱和 0.44~0.53），再**保住原图每个像素的明暗关系**、只把颜色映射过去——是"同一只箱子换了木料"，不是重画一张。**锁扣仍是金色**（用户没要求改；而且全粉的箱子太空，锁扣是图上唯一的对比点）。

· **界面里每个背包格现在和生存物品栏一模一样**：格子里**画数量、画耐久条**。数量与耐久条不是我们照猫画虎画的，是**直接调原版那两个绘制方法**（`renderItemDecorations`）——就是生存物品栏用的同一段代码，所以是逐像素一致（1 个的数量不写）。盒子里那 5 格的数量仍然是格子下面那行大字（原版右下角那种小字放不下六位数），但**耐久条照画**。**悬停提示**也跟着补齐：背包格现在也显示名字、数量、耐久；按住 Shift 会告诉你这一下会发生什么（「Shift+左键存入压缩盒」；指到盒子那一格则是红色的「压缩盒不能装进压缩盒」）。

· **修掉「压缩盒能把自己装进去、导致被卡掉」**：以前**把盒子 Shift 存进它自己**（界面里"打开的盒子"就是背包第 0 格那个盒子）是**能存进去**的，存完以后盒子里装着盒子——打开只看见一层、里面的东西再也取不出来。现在**三层一起拦**：数据层（所有写入都经过的那一个方法）开头就把它原样退回；服务端在**取出之前**就拒（不会出现"东西拿出去了又被拒"的一瞬间）；女仆那一侧（她能往盒子里放东西的那条路）同样拒；客户端界面**连包都不发**。

· **顺带查出并修掉两个真 bug（不是这一批要做的，是自检逼出来的）**：
  ① **盒子里所有东西的数量都多 1**——"设数量"那一句用错了方法（写成"加数量"了）。写 3 个石头读出来是 4 个；六百一十六那批的烟花写 114514 读出来是 114515。**上一批的用例为什么没发现**：它那条写的是"不少于 114514"（松断言），多的那 1 个正好被放行——本批把那条**收紧成相等**。
  ② 自检自己踩的坑：假玩家"把东西拿在手上"用的那个方法在 1.20.1 里是**空实现**（写了不动），所以整条点击路径第一次是全红的；换成真正的方法之后才真的在测。

· **怎么验证（新增 `/maid_smart box check <女仆>`，游戏内自检）**：把这一批修的那条路——"界面点击"——做成了一条能在游戏里跑的检查。**为什么要这么做**：专用服务器上没有客户端、点不了界面，六百一十六那批就是在这里栽过（改的是点击那条路，跑的却是"她看不看得见盒子"）。这条自检用假玩家在服务端**把界面点击真正调用的那个方法原样走一遍**，逐条打印 `[PASS]/[FAIL]`，其中包括**用户报的那一下**（Shift+点自己那一格 → 被拒、盒子还在手上、里面东西不变），并且配了两条**对照**（同一个动作存普通物品**必须成功**——不然"全被拒"也能骗过测试）和一条**对账**（两个盒子合计 15 个，没东西凭空消失）。1201 与 NeoForge 1.21.1 两台专用服实测**各 12/12 全过**。

【实测六百一十六】压缩盒（5 格 × 每格 114514，放进女仆背包 = 她背包的延伸）+ 面板里飞行跟随那一档的描述压短

· 用户原话："1.功能测试全部通过！现在在进行一个小调整。截图这一页对于飞行跟随的描述，字数太多了，直接撑满屏幕。需要精简化。2.加入一个新道具，压缩盒。建模如图。整体机制和潜影箱差不多。但不同的是，将这个箱子放进女仆的背包里面，女仆可以从这个里面拿东西，这个箱子里面的内容会被视为女仆背包的延伸。而且这个箱子里面物品堆叠上限大大增加，也就是说不再是只能堆64个，而是可以堆114514个。合成：要在中间放一个粉色染料。第2，4，6，8格放钻石，剩下格子放置粉色樱花木板在工作台内合成。虽然堆叠上限很高，但它的格子数量只有5个。"

· **面板那一页不再撑满屏幕**：飞行跟随的说明从 868 字压到 344 字（其余四条一起收短），保留"默认关、四个起飞条件、收手时消掉推进矢量、升版要重开一次开关"，把动作细节与来龙去脉挪进手册——那一行末尾现在写「完整判定、调试入口与细则见手册」（配置文件的注释与手册正文里的完整版**一字未删**）。

· **新道具「压缩盒」**：工作台里**中间放粉色染料、上下左右（第 2/4/6/8 格）放钻石、四个角放樱花木板**合成。**5 格**，默认**每格能堆 114514 个**（可在「系统与杂项 → 压缩盒 → 每格上限」里改，64~1000000）。**拿在手上右键**就打开它的界面（不用像潜影箱那样先放下）。

· **放进女仆背包 = 她背包的延伸**：盒子在她背包里时，她找材料、拿食物、取建材都会**先看盒子里有没有**（每个盒子各贡献 5 格）。**存进去不封顶**（她捡到的东西会并进那一堆，一直堆到每格上限），**拿出来一次最多 64**——这不是小气：1.20.1 的存档把物品数量写成 1 个字节，114514 整堆塞进她的背包格会被截断成 82（等于凭空蒸发），所以她的「视野」必须封顶 64。想知道她到底看得见什么：**`/maid_smart box <女仆>`** 会把每一格「看得见多少 / 实际多少」打出来（例如「看得见 ×64，实际 ×114514」）。开关在「系统与杂项 → 压缩盒 → 女仆背包延伸」（默认开）。

· **界面怎么点**（不是原版箱子界面，没有"光标上那一叠"，所以是点而不是拖）：**左键点盒子格 = 取 64 个**；**右键 = 取 1 个**；**Shift+左键 = 整格取**（背包塞不下就停，剩下的留在盒子里）；**Shift+左键点你自己的背包格 = 把那一叠存进盒子**（Shift+右键只存 1 个）。数量印在格子下面（六位数也放得下），**超过 64 的用金色**标出来；背包满了多出来的部分会掉在你脚边。

· **两条边界（写清楚，免得来回问）**：① 它**不接原版漏斗**——漏斗那套按"一格最多 64"算，碰到一格 11 万个的堆会把目标格改写成 64，等于销毁物品，宁可少一个接口也不丢东西；② 它**现在不能放置成方块**（手上右键就是开界面）——方块形态卡在一个编译限制上（方块实体类型的工厂接口在原版 jar 里是包内可见，没有 Forge 的 AT 环境过不去），留到以后做；"放下成箱子、拆掉连内容一起掉出来"这类潜影箱的方块侧行为暂时没有。

· **怎么验证**：拿到压缩盒 → ×右键打开 → 往里面塞点石头（Shift+点背包格），看数量印在格子下面；然后把盒子放进女仆背包（背包界面拖给她，或让她自己捡），`/maid_smart box <女仆>` 看一眼她"看得见多少"；再看她平时取材料、搭路、飞行跟随（烟花/鞘翅都可以放在盒子里）是否照用。把「女仆背包延伸」关掉，她那一侧就**完全看不见**盒子里面的东西（`/maid_smart box` 会显示"原版的 36 格"）。
【实测六百一十五】飞行跟随：起手 25 格 / 收手 5 格（两个球）+ 单独成一个板块；空袭俯冲的烟花力度 ×1.4

· 用户原话："1.现在女仆稍微走出去一点就开始飞（默认5格导致的），需要对判定进行一个收紧……但实际上开始跟结束两个半点的球大小应该不一样，默认值就是我说的那两个。依旧可以在手册内调试。2.然后把飞行跟随这个板块单独拎出来，不要放在搭路板块的里面，而是改成跟搭路平行的一个板块。3.近战空袭不是刚加了一个俯冲时使用烟花加速的功能吗？但是我发现加强力度太小，加速效果不明显。还耗了一颗烟花，没啥用。这边建议这个烟花加速力度效果乘以1.4倍"

· **起手与收手是两个不同的球**：起飞要等你离她超过 **25 格**（3~128 可调），收手只看你**进到 5 格**内（1~64 可调）。旧版只有一个判定球——收手半径是「起手距离减 1」推出来的，迟滞只有 1 格：她滑出去刚过线就起飞、飞回来刚进线就收手、走两步又滑出去再起飞，来回抖（用户："这样子带来的麻烦很多"）。两个数都在 **「移动与行为 → 飞行跟随」** 小节里调；**写反了也不会出事**（收手 ≥ 起手时自动压到「起手 − 1」，否则就是「起飞即收手」）。

· **飞行跟随搬到了自己的板块**：以前它挂在「搭路」里面（配置写在 `[bridge]` 小节、面板也在搭路那一页），现在与搭路**平级**——配置是新小节 `[flightFollow]`，面板是「移动与行为 → 飞行跟随」。**升级注意**：老配置文件里 `[bridge]` 下那四行 `flightFollow*` **不再生效**（值不会被自动搬过去），想要旧设置请手动搬一次、或者干脆重新打开开关一次；另外起手距离的默认值这批从 5 改成了 25（老配置里写着的 5 会照旧用 5）。

· **俯冲那一枚烟花 ×1.4**（用户原话："加强力度太小，加速效果不明显。还耗了一颗烟花，没啥用"）：原版挂载烟花的推力是**把速度往「1.7 倍视线」这个不动点上拉**——俯冲里那点力度只够勉强维持速度。现在**只有俯冲段**点的那一枚会额外补一份推力，把不动点抬到 **2.38 倍视线**（默认 ×1.4；可在「战斗与自保 → 空袭数值 → ⑥.5 俯冲段冲刺加速 → 烟花力度倍数」里调，**1.0 = 完全照原版**）。**不额外消耗烟花**（仍然一发一枚）、起飞/爬升/盘旋那几处的烟花一字未动；日志搜「空袭·俯冲」会写「俯冲加速（烟花×1.4，距敌 N 格）」。

· **怎么验证**：飞行跟随的两个球——日志搜「飞行跟随跳过」能看到「距离不够（N 格 ≤ 起手距离 25.0）」，起飞那行写「主人飞远了（N 格）」（N 刚过 25），收手那两行写「进到主人 N 格内」与「结束（主人 N 格…）」（N 刚进 5）；把「收手距离」改成 12 再试一次，她就会在 12 格左右收手——**收手球确实跟着配置走**。俯冲烟花——把倍数改成 3.0 飞一圈，肉眼就能看出俯冲比 1.0 时猛得多（收尾记得调回 1.4）。

【实测六百一十四】鞘翅赶路：只合并粉丝那份实现里的「精华」（坐标档 + 法术 id 诊断）

· 用户原话："关于那个粉丝issue鞘翅赶路的问题，我们就照你说的办，只合并一部分内容。取其精华，去其糟粕。"

· **她可以飞向指定坐标了**：`/maid_smart elytra_goto <x> <y> <z> [女仆]`（不写女仆就取离你最近的一只）——她会穿鞘翅飞向那个坐标，走的就是「飞行跟随」**同一条链路**（判定 / 起飞 / 补推 / 收手一模一样），只是把「目标」从主人换成一个坐标。到点 / 超时（60 秒）/ 出现威胁 / 燃料与鞘翅掉了 / 她换了维度 → **当场收手并忘掉这个坐标**（一次性；之后交回普通跟随，主人还远的话由原版瞬移接手）。命令会先把几条硬条件判一遍并**直接告诉你原因**（开关关着 / 目标太近 / 没有可用鞘翅 / 没有能飞的道具），其余情况看日志「飞行跟随跳过」。

· **为什么只取这一件**：粉丝 Roderick32 那份「鞘翅赶路」的主干（非战斗常态下主人跑远 → 穿鞘翅飞过去、空袭打完没敌人时跟随、赶路不消耗鞘翅耐久开关、法术冷却 ×20 修正）与**我们这边即将要更新的「飞行跟随」完全重叠**——而重叠的那几条我们不但已经有了，还更全（所有模式通用、烟花 / 羽扇 / 位移法术三种燃料、两个省料开关、与搭路 / 自保 / 传送的让位全套）。他那边唯一我们没有的能力就是「**目标可以是一个坐标**」，所以只合并这一件：**同一条链路多一个目标来源，不是第二套飞行逻辑**（坐标档同样吃那两个省料开关与法术口径）。

· **顺带收下的一条诊断**：两张法术表（提供高度 / 提供速度）里**认不出来**的 id，表现是「这张表里排第一的法术永远静默失效」；现在挑法术前都会校验一遍，认不出的在 `logs/promaid.log` 里报一条「法术兼容 … 配置里的法术 id 认不出来，已被跳过 …」（同一个 id 只报一次；最常见的原因是少写了复数 `irons_spellbooks:`）。

· **实机验收**：打开「飞行跟随」（`bridge.flightFollow`，默认关）→ 女仆背包放鞘翅 + 烟花（或羽扇 / 位移法术任一件）→ 站在她 5 格外执行 `/maid_smart elytra_goto <x> <y> <z>`（多女仆时末尾加一只点名）→ 日志搜「飞行跟随」，应看到「飞向指定坐标（N 格），背上鞘翅追过去（…）」，到点后「结束（目标点 N 格，…）」。

【实测六百一十三】飞行跟随的启动并入位移法术：能飞的道具两选一 → 三选一

· 用户原话："位移法术也可以加入到飞行跟随的启动中"。

· **能飞的道具由「烟花 / 羽扇」两选一扩成三选一**（加**能上天的位移法术**，也就是升腾 / 烈焰冲锋这类「提供高度」的法术）：只带一本法术书、一枚烟花都不带的女仆，现在**也会起飞**了。改动只有一条口径——门禁改调 `MaidFlightKit.hasFlightPropellant`，与空袭三件套的第三条**同一份定义**（这份"三选一"原先在空袭激活与缺件气泡里各写一遍，本批收进一个方法，三处共用）。

· **推进顺序 = 扇子优先 → 烟花 → 位移法术**，与空袭**起飞**那一套同序（"有烟花先走烟花链路、没有才用位移法术"）。所以**带烟花/羽扇的存档手感与烧料节奏一字不变**，法术是**第三条腿**：扇子不在、烟花也真拿不出来时接手（消耗档把最后一枚烧完之后的下一脚，就是它）。法术那一口**抬头瞄着主人放**（先清掉法术模组那份施法目标，否则它施法前会把朝向拧平、升腾就变成"向前扑"），按书里铭刻的等级放——与空袭"平地起飞/补高"完全同一套打法。

· **不新增配置项**：法术这一支归空袭的**「位移法术·起飞/补高」**管（默认开）——关掉它，空袭与飞行跟随**一起**退回只认烟花/羽扇。法术不消耗物资（按自己的冷却放），所以「消耗烟花」那个开关管不到它，两种档位下都一样。

· **三种道具都没有时**：跳过日志（搜「飞行跟随跳过」）写的是「背包里没有「可以飞行的道具」（烟花火箭 / 孔雀羽扇 / 能上天的位移法术，三选一）」；**起飞行**多一个字段「位移法术=开/关」，**法术补推**单独一行「放位移法术追主人（irons_spellbooks:ascension Lv3）」。进收手半径那一刻的"解除推进矢量"天然也把法术给的那一份解掉（法术是瞬发改速度，没有烟花那种"活着期间每 tick 都推"的残留）。

· 验证（1.20.1 专用服务器，同一轮两只女仆）：**只带鞘翅的女仆**——6 条跳过日志、**0 次起飞**，文案正是上面那句新文案；**鞘翅 + 64 烟花的女仆**——照常起飞两趟、照常烧烟花（起飞行写着「燃料=烟花火箭，烟花=消耗，位移法术=开，鞘翅耐久=照原版扣」，收手行「解除火箭推进矢量（水平速度 0.74 → 0）」）；四条标准回归（1.20.1 / 1.21.1 启动 × 女仆装载）全 PASS。

· 【这批验不到的那一层】"她真的放出了升腾 / 烈焰冲锋"必须装《车万女仆：万法皆通》+ 铁魔法两个模组才触发，测试服里装不了，所以自动用例只证到"门禁真的改了 + 烟花那条老链路没坏 + 新日志字段真的打出来了"。**实机怎么验**：背包放鞘翅 + 一本写着【升腾】的书（一枚烟花都不放）→ 打开「飞行跟随」→ 自己飞远 → 日志搜「飞行跟随」，应看到「燃料=位移法术（irons_spellbooks:ascension）」与「放位移法术追主人（… LvN）」；再把「位移法术·起飞/补高」关掉试一次，她应退回"不起飞"。

【实测六百一十二】飞行跟随：默认 5 格、进半径解除推进矢量、所有模式通用、威胁当场断链

· 用户反馈（四条）："1.飞行跟随配置默认距离从16改为5，同时加一个判定，在距离内检测到主人之后解除烟花带来的矢量（之前空袭状态下是不解除，在此模式下改为解除）2.2个空袭状态（未接敌），也可以触发飞行跟随，不做额外抑制。简单来说，就是目前飞行跟随触发判定推广到所有模式下。3.跟搭路有同款的判定，检测到威胁的时候会解除这个链路（又变成自然滑行）。4.我需要确认一点，在此类状态下，女仆在什么时候会使用烟花火箭这类推进呢？"

· **触发距离默认 16 → 5 格**（范围 6~128 → 3~128）：16 那档配上"收手半径 = min(15, 距离-1)"只剩 1 格迟滞，现实里几乎飞不起来。**升级注意**：老存档配置文件里若已经写着 flightFollowDist = 16，Forge/NeoForge **不会**替你改小——想用新默认就删掉那一行，或在面板/配置里手动改成 5。

· **进到收手半径 = 解除推进矢量**（收手半径 = 触发距离减 1，默认 **4 格**；触发距离调到 16 以上才回到 15 格上限）：你进这个范围，本趟就中断，而且**当场把烟花给的速度解掉**——收掉还挂在背上的那枚助推火箭 + 速度归零，之后零速滑翔自然下沉。为什么"收掉那枚火箭"是必需的一步：烟花不是"一次性给一份速度"，而是它活着的那十几 tick 里**每 tick** 都把骑手速度往"1.7 倍视线"拉（1.20.1 `FireworkRocketEntity.tick` 字节码实证：`v = v*0.5 + look*0.85`），只清零不收它，下一 tick 就被补回来。空袭那边**故意不解除**（她正需要这份动量贴脸、扑击）。

· **触发判定推广到所有模式**：旧版那句"她是空袭任务就不起飞（它自己有飞行作战链路）"已删除——两个空袭任务**未接敌**时照飞（未接敌 = 脑内没有存活攻击目标、也没在起跳/爬升/猛击/助推那几段出手里）。空闲 / 战斗 / 挖矿 / 烹饪 / 搭路一视同仁；**只有"真在打"与"真有活干"才让位**（后者是与搭路同一套的"任务实质占用"）。链飞到一半才接上敌的，也会**当场把控制权交回**给她自己的空袭链路。

· **威胁一出现就断链**（第 3 条）：与搭路**逐条同源**——同一个威胁半径配置（默认 8 格）、同一个"敌对生物"判据（史莱姆/岩浆怪这类只实现 Enemy 的也算）、起飞时挡 + 途中也中止（搭路同样是这两处）。空中就**保持动量自然滑翔**：这一支**不**解除矢量——威胁是"撤"，进距离才是"收"。

· **她什么时候烧烟花**（第 4 条的正面回答）：不是"每隔几秒烧一枚"，而是**掉了才补**——三个条件同时成立才补一口：① 本趟还没进到收手半径内；② 距上次补推满 1.5 秒；③ **她比主人低 ≥0.5 格**或**水平速度掉到 0.35 格/tick 以下**。最后一条就是"起飞那一下"：刚跳起来时水平速度是 0，所以**起飞后第一口推进几乎是立刻发生的**。背包里有孔雀羽扇时这一口走扇子（不烧烟花、扣扇子自己的耐久）；两样都没有就补不了，本趟会因燃料门禁收手。

· 验证（1.20.1 专用服务器；红 / 绿，同一套用例五轮）：**红**（旧 jar）——A 轮收手 **13.5 格**（旧 15 那一档）、**没有**解除矢量行、配置被旧 jar 写回 **16.0**；A2 轮同样没有解除行，而独立取证显示她那一刻仍在以 **1.601 格/tick** 飞（烟花推力的不动点那一档，人还在空中）；B 轮空袭任务被整类跳过。**绿**（本批 jar，同一套用例五轮，**全部通过**）：**A 轮**（把配置里 `flightFollowDist` 那一行删掉，验新默认）——替代主人只在约 **14.3 格**（10 平 + 8 高）外她就起飞（旧 jar 要等到 tp 到 64 格才飞），收手距离 **3.8 / 3.4 格**（= 触发 5 → 收手 4 那一档），配置被新默认写回 **5.0**；进半径时打了两行「解除火箭推进矢量（收掉还挂着的烟花，水平速度 1.46 → 0）」；**独立取证**：解除之后她还在空中（y=72.3，站立基线 69.0），水平速度只剩 **0.309 格/tick**（旧版是烟花推力的 1.7 那一档）；tp 到 64 格之后**又飞了一趟**；烟花 64 → 62（真扣）、鞘翅 1 件。**A2 轮**（触发距离 20 → 收手取上限 15）——收手距离 **14.7 格**、独立取证水平速度 **0.280**。**B 轮**（空袭任务、未接敌、无武器、周围无怪）——照样起飞并在 3.8 格收手（旧版整类跳过）。**C 轮**（替代主人 64 格外，她起飞后把 NoAI 无敌僵尸刷到她身边 3 格）——**第一趟在 54.0 格处当场断链**（远大于收手半径，且该趟没有解除矢量行），清掉僵尸后她又能飞（解除行只出现在收手那一趟 3.2 格）。**D 轮**（开关关着）——一行日志都没有。

· 【这批没做的】空袭那套"能上天的位移法术"仍未接进飞行跟随的燃料口径（原因同前：它绑在空袭状态机的朝向函数上，照搬会把"朝主人去"拧成"背对主人"）；视觉三样没动（六百一十一 已统一）；"解除矢量"那一瞬的观感是纯客户端，自动用例验不了（验到的是"速度确实归零 + 那枚火箭确实被收掉"）。

· 【这批自己踩到并修掉的两处（都是用例抓出来的）】① "在 tick 里解除矢量"**一次都跑不到**——Brain 先问 canContinue、为假就直接 stop，而"进半径"正是 canContinue 末尾那条（绿轮现场：日志里没有那一行）；改成由 stop() 执行。② forge 树把"收掉那枚火箭"写成了 `m_6075_`——javap 实证那是 **baseTick()**，火箭根本没被收掉、继续每 tick 推她（现场：日志说"1.35 → 0"、可她一秒后仍以 1.4~1.6 格/tick 飞出 140 格）；改成 `remove(RemovalReason.DISCARDED)`。镜像复核脚本里那条"想当然的映射"（`m_6075_` → `discard`）也改掉了——它正好把两树的差异抹平，这比 bug 本身更值得记。

【实测六百一十一】飞行跟随：15 格内就收手、自然滑翔、飞出去再飞一趟，动作也跟上空袭

· 用户反馈："飞行跟随的启动只认烟花，而且动作没有换成空袭飞行的动作……在飞行跟随期间自身周围 15 格内找到主人那么此链路就中断，不需要紧挨着主人。具体的表现就跟空袭女仆把怪打死一样。自然滑翔。反正飞出去了会再次启动链路。"

· 收手半径 4 格 → **15 格**：你进到她 15 格内这一趟就中断（**不需要贴到你身边**），她若还在空中就**什么都不做**——原版滑翔把她自然带下去、落地那一 tick 自动还回胸甲，与"空袭把怪打死之后"完全同一套（旧版要贴到 4 格、还得抬头泄速 60 tick 刹车，整段删掉）。你飞远了（又超过触发距离）她**再飞一趟**，一趟一趟地跟。起飞与结束两行日志现在**都带距离**（各自 5 秒限频，边界来回穿越不刷屏）。

· **动作与空袭同款**：展翅的游泳姿态 / 背上的鞘翅翅膀 / 跟着俯角的前倾——这三样原来都只认"飞行任务"判据，而跟着飞的她不是飞行任务，于是一样都跟不上（这就是"启动只认烟花"的现场：除了手上那发烟花，她身上没有半点"在飞"的样子）。现在判据统一成"飞行任务 **或** 正在滑翔"（取同步过的滑翔位，多人下客户端也认）。放宽游泳姿态是安全的：扫过 TLM 1.5.3 的 2344 个类，读 `isVisuallySwimming` 的只有 3 个（动画选择表 / 游泳动画本体 / 女仆自己的覆写），全是客户端动画，没有一个玩法判定读它。

· **燃料口径并入孔雀羽扇**：起飞与补推从"只认烟花"扩成"烟花火箭 **或** 孔雀羽扇"（与空袭口径一致；有羽扇先用羽扇），起飞行日志会写明这一趟按什么飞。缺件时的跳过日志也分得更清（「背包里既没有烟花火箭、也没有孔雀羽扇（能飞的道具）」）。

· 验证（1.20.1 专用服务器；红 / 绿；两树编译零错、两 jar 重建、三处部署 match=True、四条标准回归 PASS）：**红**——旧 jar 的结束行没有距离，红轮现场她**落在替代主人身边 3.3 格**才收手（等于"贴到 4 格才收手"），新用例第一条就判失败；**绿**——结束行带上距离且每一条都 ≥5 格、把替代主人 tp 到 64 格后又飞了一趟、烟花照扣、鞘翅没丢；另有省料档 / 开关关 / **只给鞘翅不给燃料（必须不起飞）** 三轮。视觉三样是纯客户端渲染，自动用例验不到"看起来像不像"，只验了判据口径与空袭同一处。

· 【这批没做的】空袭那套"能上天的位移法术"没接进飞行跟随的燃料口径（它与空袭的状态机绑在一起，照搬会把"朝主人去"的朝向拧成"背对主人"）；威力 / 地形 / 动力学一概没动。

【实测六百一十】她扔的模组 TNT 那一炸：主人/友军也被护住了（并更正六百〇七 那句交代）

· 六百〇七 收走模组 TNT 的「破不破方块」时留了一句交代："那一炸的伤害源是那枚 TNT 实体、不是女仆，所以现有的主人/友军免伤覆盖不到它。" 这批把它验了：那句话**只说对了一半**——伤害源里的**直接实体**确实是那枚 TNT，但**造成者**是她（原版拿引信 TNT 记的点火者当造成者，等价交换把点火者原样交给了它自己那一枚），而主人/友军免伤判的正是造成者。所以对**记了点火者的模组**，主人与友军本来就被护住了：同一队里的女仆在她连炸十几发新星期间 26 次采样恒为 1024 血、一格没掉，而**没入队的对照女仆被炸到 67 血**。

· 但六百〇七 指出的**边界是真的**：模组未必把点火者写进伤害源（那时造成者是空的，谁也认不出这一炸）。修法就是把"她扔的 TNT"这条归因接进主人/友军免伤：`MaidTntBlastGuard` 公开一条 `maidOfTnt`（引信 TNT 记的点火者 → 我们亲手登记过的那一枚，与六百〇七 为地形留的那张登记表同一份判据），主人/友军免伤改成三级归因"造成者 → 直接实体 → **直接实体是她放的 TNT**"。**「伤到主人/友军」开着时这一层让位**（那是玩家要的原版口径）；威力 / 带不带火 / 地形权限一概没动。

· 验证（1.20.1 + 等价交换，红 / 绿 + 阳性对照；两树编译零错、两 jar 重建、三处部署 match=True、四条标准回归 PASS）：**红**——把点火时的 igniter 临时传成 null（模拟不记点火者的模组），友军女仆 1024 → 110，与对照女仆（1024 → 48）一样惨；**绿**——修好后同一场景友军 26 次采样恒 1024、对照 984 → 32，日志里 `间系=空 伤害源{造成者=空}` 却照样护住友军（兜底真的在工作）；**真身**——去掉探针、走等价交换自己的点火者，同样友军不掉血、对照被炸。模组 TNT 那一炸的日志行现在会写**归因现场**（直系 / 间系 / 伤害源里的造成者与直接实体 / 类型 / 我方登记）。

· 【顺带更正两处旧记录】① 六百〇七 说的"伤害源是那枚 TNT"指的是**直接实体**，造成者是她；② `Health:2000f` + `max_health 2000` 这套 NBT 落到世界里的血量是 1024（僵尸与女仆都一样），所以旧记录里"木桩 2000 → 1024"其实是落地血量、不是被炸掉的（木桩还带抗性 5 = 免伤）；本用例的阳性对照改用没入队的对照女仆。

· 【这批没做的】不改威力 / 带不带火 / 消耗 / 飞行动力学；也不管玩家自己的 TNT 与别人的爆炸（只认她扔的那一枚）。

【实测六百〇九】"她说缺飞行道具"的假提示：本模组自己的副手动作把副手那件借走了

· 反馈原话："女仆受伤，明明拿着孔雀羽扇，但她却还是说缺少飞行道具。执行链路可以执行，但这个系统消息不停。"

· 现场定因（实机日志逐毫秒对上）：孔雀羽扇挂在女仆**副手**上，而本模组自己的"手上亮一下"（放置 / 充能 / 投掷那一刻把"她正在用的那件"放进副手举十几 tick，用完原样还回去）在空袭轰炸段每十几秒借一次副手——那十几 tick 里羽扇**不在任何槽位里**，于是就绪判定报「没有可以飞行的道具」并给主人发一条系统消息；借还之后判定又齐、把 15 秒播报冷却清零，下一轮再报一条，**每 10 秒一条、永远不停**。证据是日志里"副手 羽扇→重生锚"那一瞬间的下一条就是系统消息，而同一段里她挥扇起飞一直是好用的（反馈说的"执行链路可以执行"就是这个）。受伤与这条提示无关——真正的节拍是轰炸链路。

· 修法之一（就绪口径）：判定"她身上有没有这件东西"时，**把我们自己借走的副手那件也算上**（本模组自己的动作表现借走的，不是玩家拿走的）。"判定有没有"与"动手去用"因此不再互相打脸：借走的那十几 tick 里不再误报，而她真要挥扇 / 烧烟花时仍要求它老老实实待在槽位里。

· 修法之二（播报不再一抖就响）：缺件与齐备都必须**连续成立 2 秒**才算数——缺没站稳不播报，齐没站稳也不清冷却。所以"借出去又还回来"这种十几 tick 的抖动既报不出来、也解锁不了下一条；真把羽扇/烟花拿走时照报，只是晚 2 秒（她本来就在按普通战斗打，这条提示是补充说明）。

· 顺带补了一行诊断日志：缺「可以飞行的道具」时，运行日志里会写清主手 / 副手各是什么、背包里有没有烟花和羽扇、会不会位移法术（与"缺鞘翅"那行同一节流，最多 15 秒一行）。旧版这种情况日志里一片安静、气泡却照发，玩家报过来时没法复核——这批就是先补这一行才把现场读出来的。

· 验证（1.20.1 专用服务器，红 / 绿 + 阳性对照；两树编译零错、两 jar 重建、三处部署 match=True、四条标准回归 PASS）：场景是远程空袭女仆 + 背包 TNT/打火石/箭、**烟花只放副手 64 枚**（测试服没装暮色森林，用烟花顶替羽扇，机制完全相同）、面前一尊 2000 血木桩。**修之前**（先加诊断日志的中间件）：8 次投掷 TNT = 8 个"副手被借走"的窗口 → 6 条假提示，与粉丝现场同节拍；**修之后**：同样 8 次投掷 → **0 条**，且收尾时副手烟花 64 → 50（她真飞了、真烧了燃料）；**阳性对照**（副手也不给烟花）：5 条缺件提示 —— 证明这条播报通路确实会响，不是"没量到"。

· 【这批没做的】不改消耗 / 耐久 / 飞行动力学，只动"读"的路径与播报节流；也没把"借走的那件"算进**取用**（挥扇、烧烟花仍然要求它在槽位里）。

【实测六百〇八】飞行跟随：主人自己飞走了，她背上鞘翅追过来（默认关，手册内开启）

· 需求原话（粉丝留言）："女仆跟随能不能给她整个使用鞘翅一起飞呢，自己飞了后女仆只能搭着方块干着急了，两人一起飞想想还挺有意思的"。作者回复定为可选玩法：这种观赏类型的东西可以做，**默认关闭**，并在手册/面板里提供两个省料开关。做法与口径完全照作者给的："女仆在判定使用搭路时，发现主人离自己太远且自己跟主人之间没有方块阻拦，自己包里面还鞘翅和烟花的时候，target=主人，执行飞行（跟空袭模式的起飞是一样的，但是 target 等于主人）。"

· 触发点就是「搭路」那一档：新行为注册在 core 246，刚好压过搭路（245）——条件不满足时本行为不启动、搭路一字未动；条件满足时她直接起飞，搭路另加了一道"她正在飞行跟随就不搭"的让位。起飞要同时满足：开关打开、她不在空袭任务/守家/坐姿/骑乘/睡觉/自保、任务没有实质占用（与搭路同一套判据）、主人（或调试目标）活着且同维度、**3D 距离超过「飞行跟随距离」**（默认 16 格，6~128 可调）、**背包里同时有可用鞘翅和烟花火箭**、**你俩之间没有方块挡住视线**（raycast）、周围威胁半径内没有怪。

· 飞起来跟空袭的起飞一样：先跳一下离地、置滑翔位、抬头换高度，再放一发**挂载烟花**（只写飞行时长、不带爆炸星，到期不会炸到她自己）；推力沿她的视线方向生效，而她此刻正看着你——所以"看向主人"本身就是油门加方向盘，不用额外造速度。每 tick 把视线钉在你身上，比你低或速度掉了就补一发（最短 1.5 秒一次）；进 4 格收手，落地的就地结束，还在空中的先抬头泄速几秒，剩下的高度靠滑翔自然落下去（滑翔期间原版每 tick 清坠落距离，摔不伤）。

· 两个省料开关（都在「移动与行为 → 搭路」小节）：**消耗烟花**（默认开）关掉后每次补推不再从背包扣那一枚——但**照旧要求背包里有烟花**（它是她能飞的凭证）；**消耗鞘翅耐久**（默认开 = 照原版每 20 tick 扣 1 点）关掉后这一趟不啃耐久。后者是靠一笔 mixin 拦在原版 `ElytraItem.elytraFlightTick` 入口（那就是扣耐久的地方）：注意这一手**只能"跳过扣耐久"、不能"取消滑翔"**——那个方法的返回值是"这一 tick 滑翔还算不算数"，返回假她当场就掉出滑翔、20 血自由落体，所以拦法是照旧返回真。**边界**：只认原版鞘翅及其调用 super 的子类，模组那种自带滑翔钩子的护甲拦不到。

· 她不会抢别人的活：飞行期间**自动传送与同维度拉回一律让位**（否则她飞到 48 格会被直接拽走，"一起飞"当场结束）；搭路一见她在飞就让位；撞墙/摔落免疫也照飞行任务那两档一起管（女仆 20 血，撞一次墙就没了）。**装备两处硬约束**：起飞前把胸甲槽换成鞘翅（她自己本来就穿着可用鞘翅时一字不动）、换下的胸甲当场回背包；而**归还只在她站到地上时发生**——原版每 tick 都要看胸甲槽里那件鞘翅能不能飞，空中摘走等于清滑翔位（自由落体），所以收手时若她还在空中，鞘翅继续戴着让原版把她安全滑下去，落地那一 tick 再还。有界：一趟最多 60 秒，超时 / 烟花用完 / 威胁出现 / 自保 立刻收手。

· 怎么验证她真的会飞？（服务端）`/maid_smart flyfollow <实体> [女仆]` 给最近的一只女仆（或点名的那一只）指定一个"替代主人"，`/maid_smart flyfollow clear` 摘掉——它走的仍是这条链**同一套**判定与飞行链路，只把目标从"在线主人"换成你指定的实体（专用服务器上没有玩家，主人实体恒为 null，这条链结构上没法端到端触发，与 `/maid_smart feedtest` 同一类困境）。运行日志搜「飞行跟随」，能看到**起飞 / 补烟花 / 结束 / 已落地把胸甲还回去**四行；**不起飞**时搜「飞行跟随跳过」，她会说清是哪一条判据没过（睡觉/守家/空袭任务/自保/任务占用/没有目标/距离不够/缺鞘翅/缺烟花/视线被挡/附近有怪）——每只女仆 10 秒最多一条，且**只在开关开着时才记**，默认档一行都没有。替代目标请用**非敌对活体**（比如村民）：她自己的"附近有怪就不飞"会把敌对目标当威胁，拿僵尸当替身只会验出"起飞就收手"的假象。

· 验证（1.20.1 专用服务器实跑，三轮对照；两树编译零错、两 jar 重建、三处部署 match=True、四条标准回归 PASS、两树 608 段镜像复核一致）：**全默认档**——起飞 22 格、补推 1 次、4 秒追上并落地，背包烟花 **64 → 62**（真扣）、鞘翅耐久 **0 → 3**（照原版扣）、胸甲原样还回背包；**两个省料档**——起飞日志写「烟花=不消耗，鞘翅耐久=不消耗」，同样追得上，但烟花 **64 → 64**、鞘翅 **Damage 0**；**开关关着**——一行日志都没有、她原地不动。【要你进游戏验收】：把「飞行跟随」打开，自己背上鞘翅飞远一点，看她是不是也背上鞘翅追上来、贴到你身边才收翅落地；再回面板把「消耗烟花 / 消耗鞘翅耐久」两个开关关掉跑一轮，确认烟花不再少、鞘翅耐久不再掉。【实测踩过的三个坑，写在这里省得你排查】① 命令默认取"离你最近的女仆"，测试世界里若有别的女仆可能挂错人（现在可以 `/maid_smart flyfollow <目标> <女仆>` 点名）；② 沿途/附近有敌对生物（威胁半径内）她不会起飞——日志「飞行跟随跳过」会写明「附近有敌对生物」；③ 替代目标别用敌对生物（僵尸之类）：她自己的"附近有怪就不飞"会把目标当威胁，刚起飞就收手，请用村民这类非敌对活体。

· 【这批没做的】不做"跨维度飞过去"（她一见目标与自己不同维度就收手，跨维还是走原有跟随/传送链路）；也不做"她自己主动起飞兜风"——这条链只在"该搭路却够不着你"的那一刻被动触发。


【实测六百〇七】模组 TNT 那一炸也受「不破坏方块」管辖

· 需求原话："mod的TNT也受我们的不破坏方块管辖。" 收掉的是六百〇五 留下的边界：那一批让女仆扔出**模组自己的 TNT 实体**（等价交换的爆破新星），当时定的口径是「威力 / 破不破方块 / 带不带火全归它自己」——于是那一炸照样在地上留坑，本模组的「轰炸破坏方块」开关管不到它。现在把「破不破方块」收回来：开关关着（默认）时，她扔的模组 TNT 也一个方块都不拆；开着才照它自己那一炸炸坑。**威力与带不带火仍归它自己，伤害与击退一概没动**。

· 机制（javap 实证，两版一致）：Explosion 没有威力/交互模式的公开读取口（都是 private），所以「照原威力重炸一遍」走不通；但 Forge/Neo 都在 **Explosion.explode() 里**发布 ExplosionEvent.Detonate，而方块真正被拆发生在之后的 finalizeExplosion，且它读的就是 getToBlow() 那张表——而 Detonate.getAffectedBlocks() **直接返回活的 getToBlow() 表**（不是副本）。所以在事件里把这张表清空 = 这一炸不拆任何方块，伤害完全不受影响。对覆盖了 finalizeExplosion 的模组（等价交换）同样成立：它也是先 explode() 再 finalizeExplosion()，拷贝发生在事件之后；而我们自己的四类炸弹走 ExplosionInteraction.NONE，本来就不拆方块，这层对它是空转。

· 怎么认出「这是她扔的那一枚」（新增 com.maidsmart.combat.MaidTntBlastGuard，只认 TNT、绝不动别人的爆炸）：① 主人链——直系来源是引信 TNT、点火者（间系来源）是她（原版/加载器自己就是这么归因的，等价交换也把 owner 收下了）；② 兜底——primeTnt 在我们放出「模组自己的 TNT 实体」时把它登记进一张带 400 tick 过期的小表（惰性清理防死 id 堆积），个别模组不记 owner 时靠这条兜住。日志搜「空袭轰炸」可见「模组 TNT 那一炸按「不破坏方块」处理（清掉 N 个方块；威力与伤害照它自己的）」。

· 验证（1.20.1 + 等价交换实跑，开/关两轮对照）：场景是先立一尊不动不落的 Marker 盔甲架当锚点、以它为准铺 5x5 石头台并在台上放 2000 血木桩，女仆反复扔新星砸木桩。**关**（默认）：8 行守卫日志（每次清掉 9009~22630 个方块）、石头台采样格 **5/5 全在**、木桩 **2000 → 1024 血**（只收地形权限，伤害照旧）；**开**：守卫日志 0 行、石头台**全被拆掉**（证明是这道开关在管）。两树编译零错、两 jar 重建、三处部署 match=True、四条标准回归 PASS。【要你进游戏验收】：拿等价交换的爆破新星喂她，看新星炸开时**地面是不是不留坑**（默认档），再进面板把「破坏方块」打开跑一轮，确认那时才恢复拆坑。

· 【这批没做的】只挡地形、不挡伤害：那一炸的伤害源是**那枚 TNT 实体**（不是女仆），所以现有「主人/友军免伤」覆盖不到它——需要的话另开一批。若某个模组的爆炸不走 getToBlow() 而是自己另开一套循环拆方块，这层拦不住。

【实测六百〇六】俯冲段冲刺加速：朝着敌人俯冲那一段补一口推进，方向不变（烟花 / 法术 / 羽扇三路）

· 需求原话："近战空袭向下朝着敌人俯冲期间补一个链路：用烟花/法术加速（孔雀羽扇好像不行，行的话也加上），方向不变，这样可以大幅提高周期 dps。"

· 先说清"俯冲"是哪一段：一轮是「放烟花/挥扇爬升 → 朝目标压低机头一路滑翔扎下去 → 进 3.5 格收翅猛击」。中间那截下滑就是俯冲——它才是周期里最长、最影响周期 DPS 的一截。

· 为什么旧版这里没有加速、而烟花其实可行：javap 实证，原版挂载烟花的推力分支与暮色孔雀羽扇的滑翔分支，开头都是 `if (isFallFlying())`——都只在滑翔时给推力。俯冲这一段正是滑翔中，所以**点一枚烟花真的吃得到推力**（沿她的视线 = 朝着敌人，方向天然不变），旧版只是没在这一段调用它。而扇子那一式自带 +1.25 的竖直升力、还会把速度往视线×2 收敛，会把「往下扎」顶成「往前平飞」——这就是「孔雀羽扇好像不行」的由来：不是扇子坏了，是它的推力方向不对。

· 改法（面板新一段「⑥.5 俯冲段冲刺加速」，三路燃料按优先级）：① 位移法术（不消耗物资、最省，有就先用，旧版那处冲刺收进这里统一排序）；② 烟花（默认开）——俯冲途中真的点一枚，消耗 1 枚，推力由原版给、方向不变，副手照旧亮一下、有点火音效；③ 羽扇（默认关）——挥一次只借它的动作与消耗（挥臂 / 音效 / 扇风盒把贴脸怪扇开 / 原版扣耐久），不用它那一式推力，速度由本模组按「一口速度」（默认 0.55 格/tick）给。闸口：距敌 5~40 格才补、两次间隔默认 30 tick（1.5 秒）、激流突进期间让位。日志搜「空袭·俯冲」看「俯冲加速（烟花，距敌 12.3 格）」。

· 验证（1.20.1 实跑，开/关两轮对照）：开时本轮女仆 9 行「俯冲加速（烟花，距敌 39.6 格）」（全部落在闸口内）、背包烟花 63 → 31、照常起飞；把服务端配置的 `diveBoost` 改成 false 重启后 0 行、她照常飞。两树编译零错、两个 jar 重建、三处部署 match=True、四条标准回归 PASS。【要你进游戏验收】：看俯冲那一下是不是明显更快扎下去、烟花是不是每轮少一枚、以及**方向有没有被带偏**（这一条最关键——它应当始终朝着敌人扎，不会因为加速而平飞或偏航）；把「用羽扇」打开再看一轮，确认它只多了挥扇动作、方向同样不乱。

【实测六百〇五】认出来的 TNT 就放它自己那一枚（等价交换的爆破新星这类名字里没有 tnt 的模组 TNT 也认）+ 点火料按「类」认

· TNT 判据再加一条（需求原话："我们应该判断一下这个方块是否存在其对应 tnt 形式，如果有则确认，并释放其对应的 TNT（而不是原版tnt）。"）：六百〇四 只按注册名判，而模组 TNT 十有八九根本不含 tnt 这三个字母（等价交换的爆破新星注册名是 projecte:nova_catalyst）。现在两条取并集：① 注册名里带 tnt；② 这一件是方块物品、而**它的方块继承 TntBlock**——名字可以随便写，方块的血统骗不了人。

· 认出来的是哪一件，就放它自己那一枚：旧版不论手上拿的是哪一件，扔出去的都是自己 new 出来的**原版**引信 TNT（模组 TNT 的威力 / 破不破方块 / 带不带火全被抹掉）。现在投放前先问那一件自己：方块不是 TntBlock 本身（= 模组自己写的 TNT 方块）就走它自己的点火钩子 onCaughtFire（原版拿打火石点 TNT 走的正是这一步）——等价交换在这一步 new 出来的是它自己的 projecte:nova_catalyst_primed（威力 16、照它自己的 NovaExplosion 炸），**那一炸完全归它自己，本模组不接管**。它继承 PrimedTnt，所以追踪照旧生效、引信仍按配置（默认 40 tick）。**原版那一件一字没动**：还是自己造引信 TNT + 本模组「默认不破坏方块」的那一炸。日志那一行现在会点名放出来的是哪一枚（搜「投掷 TNT」）：「投掷 TNT ×1（projecte:nova_catalyst，引信 40 tick，它自己那一枚 projecte:nova_catalyst_primed）」。

· 点火料按「类」认（需求原话："类打火石/火焰弹识别"）：**类打火石**（FlintAndSteelItem 的子类）/ **类火焰弹**（FireChargeItem 的子类）都算，注册名兜底——模组自加的点火料不用再各自打补丁。打火石那一类仍然优先（手 → 背包）。

· 道具走耐久、消耗品走消耗（需求原话："点燃 tnt 的消耗品走消耗，道具走自己的耐久机制"）：走哪一条不看名字，看这一件**有没有耐久**——有耐久的是道具（打火石 64 点）→ 扣 1 点耐久、放回原槽（耐久耗尽才真的少一件）；没耐久的是消耗品（烈焰弹）→ 整件消耗。模组自加的点火料各按自己的性质落进对应那一档。

· 验证（1.20.1 装了等价交换那台，test_bomb605.py）：新星女仆 6 条「投掷 TNT」行、每条都点名物品与它自己那一枚；独立抽样「execute if entity @e[type=projecte:nova_catalyst_primed]」命中 3 次、data get 回读到「Primed Nova Catalyst … : 40s」（我们自己配的引信）——放出来的确实是等价交换自己的新星实体；另一台拿原版 TNT + 火焰弹的（4 条行、点名 minecraft:tnt、不带后缀）证明原版那条路没被改坏；负向对照（圆石 + 打火石）0 条行；打火石一件没少、耐久正好掉 6 点。两树编译零错、两个 jar 重建、三处部署 match=True、604 双服务器回归 + 四条标准回归 PASS。【要你进游戏验收】：1.21.1 那台测试服的 mods 里没有任何 TntBlock 子类（全部 jar 扫过 0 命中），所以模组 TNT 那条路只在 1.20.1 实测过——你在 1.21.1 上遇到模组 TNT 时照「投掷 TNT」那一行验收（它会写明放出来的是哪一枚）；另外**模组 TNT 自己那一炸不受本模组「不破坏方块」管**（那一炸归它自己），介意的话先说一声。

【实测六百〇四】TNT 边界放宽：注册名里带 tnt 的都算 TNT

· 判据放宽（需求原话："为 tnt 放宽界线，模组内含有 tnt 词条的都可被视作 tnt。"）：旧版把 minecraft:tnt 写死，别的模组自己加的 TNT（tntmod:tnt / xxx:tnt_block / yyy:super_tnt …）她一概看不见——玩家把那种 TNT 塞进背包，投掷链路照样按"缺料"跳过。现在改成**注册名（namespace:path）里出现 tnt 就算**，大小写不敏感：原版那一件天然还在里面，各模组的 TNT 一视同仁。看的是注册名、不看显示名（中文客户端里它根本不叫 tnt，按显示名判会随语言变）；边界只看名字、不看"这一件能不能放"，所以像 minecraft:tnt_minecart 这种名字里带 tnt 的也算数——她扔出去的本来就是一枚原版引信 TNT。真要不认这一类，说一声就加例外。

· 投掷日志点名物品：那一行原来是「投掷 TNT ×1（引信 40 tick）」，现在是「投掷 TNT ×1（minecraft:tnt_minecart，引信 40 tick）」——模组 TNT 认没认，翻日志（搜「投掷 TNT」）一眼就知道。

· 验证（专用服务器场景实测，两树各一轮 PASS）：探针物品用 minecraft:tnt_minecart（注册名里带 tnt、但绝不是原版那一件——两台测试服的 mods 全扫过，没有任何"注册名带 tnt 的模组物品"），旁边再放一台负向对照女仆（背包只有圆石 + 打火石）。探针那一台掷出「投掷 TNT ×1（minecraft:tnt_minecart，引信 40 tick）」、那一格回读为空（真消耗）、打火石掉 1 点耐久；对照那一台 0 条投掷行、圆石原封不动。两树编译零错、两个 jar 重建、三处部署 match=True、四条回归 PASS。【要你进游戏验收】：拿真正带 tnt 的模组物品（比如某个模组的大 TNT）喂她，看她照不照扔、扔完是不是少一个。

【实测六百〇三】远程空袭也放炸弹（重生锚 / 末地水晶 / 床）+「走后门」让悬空目标也放得下 + TNT 点火料多了烈焰弹

· 远程空袭加入放置链路：旧版按"她一直飞在天上，本来就放不了"把远程空袭排除在外，这道闸已整个删掉。现在盘旋期间每次开火之后先试放炸弹（重生锚 / 末地水晶 / 床），材料齐就交给相位、相位收尾自己投 TNT；没起手才就地投 TNT——与近战猛击那条路完全对称。放置是她自己的服务端动作，与她飞多高、离目标多远都无关。

· 「走后门」悬空也放得下（新面板项「空中悬空投弹」，默认开）：落点从三级扩到四级。难题是目标**自己悬空**（蝙蝠 / 恶魂 / 被击飞到半空 / 站在水里的怪）——它脚边那四格全是空气，前两级找不到支撑面。第四级直接把落点取在「目标头顶那一格 → 目标自己那一格」：不要求支撑面、也不要求那格没站着目标（原版以"那一格站着实体"为由拒绝时我们强制放下），于是底座可以悬在空中、贴在目标身上，0.5 秒后原地开花；那格若站着除目标以外的别人则跳过。日志里搜「走后门」能看到它有没有被用到。

· 投掷 TNT 的点火料多了烈焰弹 / 火焰弹：打火石优先（每发就地掉 1 点耐久），没有打火石时消耗 1 个烈焰弹（整颗消耗），两样都没有才跳过；副手动作跟着换——只有烈焰弹时举的就是那枚烈焰弹。

【实测六百〇二】粉火"不灭 / 又变橙"的真正根因 + 轰炸改判为附加链路

· 粉火被打回原版火（真凶）：原版火在任何邻居方块变化时都会按"原版火"重算一次状态（FireBlock.updateShape → 私有助手 → BaseFireBlock.getState 里写死 Blocks.FIRE），于是粉火旁边一动（爆炸、方块变化、水流、别的火…）就变回橙色火。橙色那些是"爆炸时又粉又橙"的来源；而原版火在石头/地面上是永不熄灭的——这就是"粉色的火又不会熄灭了"。现已补两处转发把状态翻回粉色，并保留它自己的 AGE（不会被反复更新续命）。
· 粉火一定会灭：粉火的自灭依赖方块 tick 链，而它所在的区块可能在它老化之前就停了 tick（远处战斗 / 玩家走开 / 区块卸载），冻住后还会被存进存档。新增 PinkFireSweep 两层兜底：① 每格粉火登记到期时间，服务端 tick 到点直接抹掉（不看方块 tick）；② 区块加载时把存档里带进来的粉火收进同一张表、下一 tick 抹掉——老版本残留的那 70 格会在下次进入那片区域时自动消失。
· 轰炸=附加链路（不占用行动与飞行）：旧版轰炸相位在飞的那十几 tick 里飞行行为整段让位，而起手正好是"收翅猛击打完、马上要再起飞"那一刻，等于把起飞压后 0.5~1 秒。现在删掉那道闸：放方块 / 挂水晶 / 充能都不需要她停手，该起飞起飞、该扑击扑击、该开火开火。
· 验证：专用服务器实测（放粉火 → 制造邻居更新后仍是粉 → 10 秒后变空气；存档 NBT 粉火 0 格）；两树编译零错、jar 重建、三处部署、四项回归 PASS。

## 实测六百〇一【粉火范围收回：只影响女仆那一炸点着的火】

- ① **收回越界的那一步**（反馈："你这样等于直接开挂了呀。你应该只影响女仆造成爆炸所产生的火焰，并且将它替换。而不是将所有的火焰全都开了。"）：实测六百 曾经做到"开关开着 → 世界里每一格新火都换成粉色"外加"每炸一次把爆炸范围里既有的原版火也扫成粉色"与一套 15 秒守护区；因为粉火不蔓延、约 8 秒自灭，那等于顺手把**全世界的火蔓延**关掉（含你自己点的火），已全部收回
- ② **现在的边界**：换的只有**她自己那一炸点着的火**（"边点边换"，一炸点着多少格就换多少格——实测 119 格全中，与距离无关）；打火石 / 闪电 / 岩浆 / 别的模组 / 早先留下的原版火**一概不碰**（该烧还是烧、该蔓延还是蔓延）；"不掉血也不着火"只对**那片粉色火**生效；别处的火按原版规则走，本模组不介入
- ③ 三个开关不变：`bombing.pinkFire`（爆炸火焰改粉色）/ `bombing.fireRender`（粉色火焰渲染）/ `bombing.fireProtect`（火焰伤害保护）
- ④ 验证：两树编译零错、两 jar 重建、三处部署 match=True、回归 4/4 PASS


## 实测六百【无主女仆全面降级；粉火"新火全变粉 + 不会被烧"；重生锚不再被末地水晶吞；空袭放锚照搬黑曜石那套】

- ① **无主女仆：promaid 一概不碰**（反馈："某些整合包对于无主的女仆会有一些额外的特殊效果，我们这个 mod 不能够阻碍他们……对于无主女仆 promai 所做的一切改动全都不生效"）：判据是**主人 UUID**（`getOwnerUUID() == null` = 野生/未认领）——**主人离线不算无主**，有主的离线女仆照旧干活。做法是卡在行为基类 `Behavior.tryStart`（final）上：`com.maidsmart.*` 的全部 AI 行为对无主女仆一律不许起手（以后新加的行为自动生效）；危险避让 / 恐慌门控 / 横扫加成 / 玩家伤害口径 / 农田踩踏 / 自动参战 / 危险减益那些改原版行为的入口也逐个让开。日志搜「无主女仆」（实测：1.20.1 服 41 条、1.21.1 服 15 条）
- ② **粉火：模式开着时"新点着的每一格火"都直接生成为粉色**（反馈："还有可能会出现橙火焰……玩家还是会被粉火烧到。这边建议改为……所有被生成的黄色火焰都会被替换成粉色火焰"）：实测日志证明旧版窗口那条路是好的（那一炸点着的 119 格火全部直接变粉），烧到人的是**窗口之外**的火。现在卡在原版唯一的放火入口上全局替换 + 每炸一次把爆炸范围内**既有的**原版火一并换掉 + **15 秒守护区**（区里你和女仆身上带火直接熄灭、踩进火里那一下取消 = "不会被烧"）。代价：开关开着时整个世界的新火都不再蔓延（含你自己点的），关掉即恢复原版橙色火
- ③ **重生锚不再被末地水晶吞掉**（反馈："此时女仆只会扔 TNT 和放末影水晶，压根不会去放重生锚。我认为它的优先级应和放末影水晶是一样的。两者可以同时启动"）：旧版三段是"取第一个材料齐的"，于是带着水晶就永远轮不到重生锚/床 → 现在 `PHASE` 改成"每段各一个相位"、最短间隔也每段各一条，**材料齐的几段同一次攻击里一起起手**（最多三段同时飞，落点互不抢：新增 `claimedByOtherPhase`），所有段放完才投 TNT
- ④ **近战空袭放重生锚"照搬黑曜石那套"**：三段放置本来就是同一套代码（`placeOnSupport`：原版放置 → 落点兜底强制放下 → 空中强制），"放不出重生锚"的真因就是 ③ 的"被水晶吞掉"；③ 落地后重生锚/床与黑曜石走同一条路
- ⑤ **验证**：两树编译零错、两 jar 重建、三处部署 match=True、回归 4/4 PASS；**要你进游戏验收**：空袭那一记是否同时放水晶+重生锚、打火石/岩浆的火是否也变粉且烧不到你、整合包给无主女仆的效果是否不再被挡


## 实测五百九十九【近战空袭不放重生锚；副手展示只亮 1 tick 的真凶；粉色火焰保护实测有效】

- ① **近战空袭不放重生锚**（反馈："近战空袭的时候不会放置重生锚"）：相位旧版一见"目标没了"就整段回滚，而收翅猛击**经常就是致命一击**——起手那一 tick 之后目标就死了，下一拍炸弹还没放下就被撤掉。现在 `Phase` 记住目标最后所在的那一格，**目标死了也把这一轮走完**（炸弹落在原地、0.5 秒后照炸）。上服实测：修复前 `目标死 → isBombing=false 附近重生锚=0`；修复后 `目标死 → isBombing=true 附近重生锚=1 → 副手=萤石（充能）→ 附近重生锚=0（炸掉）`。代价是每打死一个怪多花一份材料，手册里写了（把「轰炸最短间隔」调大或关掉「战斗模式轰炸」）。
- ② **副手展示只亮 1 tick 的真凶**（反馈："副手的物品没有换，哪怕只显示一下也行啊"）：`BombPose.show` 新建记录时**忘了写展示时长**（字段默认 0）→ 下一 tick 就还原，那件东西只在副手上存在 **1 tick（16 毫秒）**，屏幕上一帧都看不到——这就是"所有链路的副手都没换"。顺带修掉同源的第二处：`BombPose.tick` 每次被调用都扣 1，而 core 行为同一 tick 可能被评估多次（请求 40 tick、不到 20 tick 就还原）→ 改成按 gameTime 节流。实测：修复前 +2 tick 就变回盾牌；修复后 +1/+2/+8/+20/+40 tick 一直是重生锚。
- ③ **粉色火焰的伤害保护实测有效**：上服直接对女仆调 `entityInside`（原版会为 AABB 内每一格方块调它）——粉色火 + 保护开 → 血量 20.0、**没被点燃**；保护关（对照）→ 血量 19.0、点燃 160 tick。所以"被粉色火烧到"其实是**同一场爆炸里残留的原版橙色火**，那一半已在 实测五百九十八 根除（点火那一刻就换成粉色火）。**面板位置**：模组详细配置 → 战斗与自保 → 空袭数值 → 「副手动作表现」下面三条（`爆炸火焰改粉色` / `粉色火焰渲染` / `火焰伤害保护`），也可以直接改 `config/promaid-common.toml` 的 `[combat.bombing]` 段。
- ④ **验证**：两树编译零错、两个 jar 重建、四处回归全 PASS；上服实测（临时探针，验完即删）覆盖上面每一条，含"目标死后相位继续"的完整链路（起手 → 目标死 → 放锚 → 换萤石 → 起爆）。**要你进游戏验收**：那一记打死怪之后她有没有把重生锚放下、掏出萤石充能、副手三下都看得见；搭路/建造/酿造的副手是不是真的举起来了；站在粉色火里掉不掉血。


## 实测五百九十八【回收方块"整体还她"；粉色火焰三个真凶；issue #12 过滤追查；issue #14 判据统一】

- ① **回收改成"她放下去的那一件，原样还她"**（反馈："回收方块的时候是整体回到女仆的背包，但是发现在搭建萤石的时候会掉落萤石粉"）：旧版回收走 `Block.getDrops`（**挖掘口径**），可这些方块是她**从自己背包里拿出那件物品**去垫的（搭路 / 搭高 / 战斗垫脚 / 深井挖矿）。新公用方法 `PlacedBlockTracker.reclaimDrops`：方块有对应物品就还 1 个该物品本身，只有没有物品形式的方块（水 / 岩浆 / 火 / 红石线 / 耕地）才回退掉落表。**上服逐块实测**：萤石 `萤石粉×2 → 萤石×1`、草方块 `泥土 → 草方块`、石头 `圆石 → 石头`、树叶 `什么都不掉 → 树叶×1`、黏土 `黏土球×4 → 黏土×1`、钻石矿 `钻石 → 钻石矿`。
- ② **粉色火焰三个真凶**：**(a) 没中文名** → 两树 lang 补 `block.maid_smart.pink_fire`（粉色火焰 / Pink Fire）；**(b) 永远不熄灭** → `tick` 里那句"排下一拍"误用了 `m_6933_`（那是 `Level.setBlock` 的四参重载，**不是 `scheduleTick`**；真正排 tick 是 `m_186460_`），于是火只在原版 `onPlace` 那一拍动过一次（AGE 0→1）就再也不 tick——现在照原版口径改 AGE（flag 4）+ `scheduleTick`，上服实测 AGE 0 → 8 秒后 4（下一拍自灭）；**(c) 又粉又橙** → 旧版"爆炸后按盒子扫一遍再换"永远罩不住：原版点火位置来自 `Explosion` 的**射线**集，空气阻力 0、每步只花 0.09 能量，功率 5 的一炸能跑到**约 20 格开外**。改成**边点边换**：爆炸前后开/关"点火窗口"，新 mixin `BaseFireBlockPinkMixin` 在窗口内把 `BaseFireBlock.getState` 的返回值直接翻译成粉色火（上服实测：窗口关=`minecraft:fire`、窗口开=`maid_smart:pink_fire`），旧 `scanFire/pinkifyFire` 整段删除。窗口外（打火石 / 闪电 / 火焰弹）一概不动。
- ③ **issue #12 追查**：反馈者的推测成立——墙上方块的 `asItem()` **不是 air**，而是**前身物品**（`redstone_wall_torch → 红石火把`、`oak_wall_sign → 橡木告示牌`、`wall_torch → 火把`，上服实测），所以解析期那句 `asItem() == AIR → 跳过` **对它们从来没生效过**。现在解析期过滤改用与材料链同一个 `itemForBlock()`：真正没有物品形式的方块（火 / 传送门 / 活塞头）才跳过，**跳过的格数写进日志**（旧版静默）。用他的附件实测：`chuachuan-12w-cobblegen.litematic` 解析出 879 步，那两个墙上件都在计划里、归一成红石火把 / 橡木告示牌。
- ④ **issue #14 判据统一**：新增 `isMachineForMaterials(id)` = **文件名关键词 ∪ 图纸内容**，`缺料同类宽松 = machine` 改用它（不会再"水留下了、材料却不放宽"）；机器专属搭建顺序 / 活放置**仍按文件名判**（与 #15 那轮说好的边界一致）。内容判据补一类**结构件**（岩浆块 / 冰 / 蓝冰 / 灵魂沙 / 气泡柱 / 铁砧 / 石匠台 / 堆肥桶…）——纯物理结构型机器几乎没有红石件：判据为 `红石件 ≥3` 或 `红石件 ≥1 且 结构件 ≥1` 或 `结构件 ≥2`。**判成非机器因而没放宽时日志写明原因**（含"红石/物流件 N 种 / 结构件 M 种"），剥离日志也带上判据数字。
- ⑤ **issue #16 新回复（鞘翅赶路）**：口径 = **传送保底不动**（远距拉回 / 牵引绳 / 跨维度跟随照旧传送，省耐久、不误事），鞘翅赶路只作观赏；反馈者的分支要提 PR 时挂在**开关（默认关）**后面，不做默认行为。本批不动代码。
- ⑥ **验证**：两树编译零错、两个 jar 重建、三处部署 hash 一致、四个回归全 PASS；上服实测（临时探针，验完即删）覆盖上面每一条。**要你进游戏验收**：回收回来的萤石是不是整块、那一炸的火是不是一片全粉且不烧你、方块名是不是「粉色火焰」、非机器图纸不放宽时日志能不能读到原因。


## 实测五百九十七【副手持物推广到全链路；爆炸火焰改粉色 + 玩家女仆免伤；坐下不搭路；issue #16 法术冷却】

- ① **副手动作表现推广到所有"从背包掏出来就用"的链路**（反馈："放置重生锚的时候副手应该要拿对应的方块，使用荧石激活的时候也是……任何一个链路行动的时候副手都应该拿对应的物品，现版本只有动作"）：搭路（4 条腿）、插火把、建造（主循环 + 延后补建）、种植、酿造（9 处下料）、喂主人（药水/金苹果/牛奶/蜂蜜/饮品）、轰炸——每一处副手都举她**这一下真正在用的那一件**（总开关仍是 `combat.bombing.pose`）。**已在主手看得见的链路不动**（挖矿的镐、砍树的斧、耕地/骨粉）。顺带修掉两个坑：撞上"烟花姿势正在用副手"时旧版**直接丢弃**（那一记动作整个消失）→ 改成记待办、等它还原完再举；改完副手**主动补一包**装备同步包（展示只有 10 tick，不能靠"应该会同步"）。
- ② **爆炸火焰改粉色**（新方块 `maid_smart:pink_fire`）：javap 实证原版点火只看 `fire=true`、与我们"不破坏方块"无关（四类炸弹里只有重生锚与床带火）；火焰贴图蓝通道几乎为 0，**任何 tint 都乘不出粉色**，所以新增一个继承 `FireBlock` 的自定义方块 + 把原版 `fire_0/fire_1` 做**色相映射**到粉色的贴图（形状与 32 帧动画照旧）+ 照抄原版的 blockstate 与 10 份模型。三条行为收紧：**不蔓延**（原版传火逻辑整段替换）、**几秒后自灭**（约 3~5 秒）、**玩家与女仆免疫**（点燃与掉血都跳过；其它生物照烧）。只换"这一炸新点着的"火（爆炸前记一份快照），主人自己的火堆不受影响。三个开关：`bombing.pinkFire`（默认开）/ `bombing.fireRender`（默认开：关掉后火还在、只是不画）/ `bombing.fireProtect`（默认开：玩家与女仆免伤）。
- ③ **坐下不搭路**（反馈："女仆坐下的时候还是会触发搭路"）：`BridgeUpBehavior` 的 canUse / canStillUse 里一条坐姿判定都没有——坐在椅子上（passenger）或被叫坐下（sitting pose）时照旧启动。现在两处都拦，中止原因单独记 `sitting`。
- ④ **issue #16：法术自身冷却被多乘 20**：ISS 的 `AbstractSpell#getSpellCooldown()` 返回的**本来就是 tick**，旧版又乘了 20 → 烈焰冲锋（200 tick）被写成 4000 tick = 200 秒，"提供速度"第一次放过之后两百秒再也不放。现在原样返回。
- ⑤ **验证**：两树编译零错、两个 jar 重建、三处部署 hash 一致、四个回归全 PASS（两版本各跑 专用服务器启动 + 召唤女仆）；粉色火方块的上服实测（临时探针）确认 `fromVanillaFire` → `setBlock` 真的把那一格换成了粉色火、底面支撑判定为可存活。**要你进游戏验收**：副手拿的东西、粉色火与免伤、坐下不搭路、法术反复放。

## 实测五百九十六【第 2 个问题（收放魂符后装备被吞）没修好的真凶：我们自己的"入世界自动补包"每次魂符放出都把客户端那只女仆删了重建】

- ① **先把服务端拖拽逻辑洗清**（实测）：临时探针用假玩家在带【万法皆通】的测试服上真跑点击（头甲→物品栏、胸甲→物品栏、物品栏→头甲、原地四组），**东西都老老实实进了她背包**——槽位映射、`mayPlace`、背包黑名单都没问题（探针验完已删，不进包）。顺带实证：无背包女仆的容器是 49 槽，`addMainDefaultInv` 在 i==5 那轮加了两遍同一个物品栏槽（第 47、48 号都绑 `maidInv[5]`），两树一致、不是吞装备的原因。
- ② **真凶：我们自己的"入世界自动补包"**（实测五百六十五/五百六十六 加的那一枪）——**收放魂符的"放出"就是一次入世界**（TLM `spawnFromStore`：新建 → `load(快照)` → 加入世界），它却无条件发"删实体 + 重新生成"，等于**每收放一次就把客户端那只女仆销毁重建一次**（现场日志 21:09~21:11 十几轮「离场 → 重同步」）。两个后果：**a)** TLM 容器槽位绑的是"建容器那一刻那只实体"的背包/装备句柄，重建后容器还指着已销毁的那只 = 客户端对着尸体读写她的物品栏；**b)** TLM 在"开始追踪"时另发的**饰品全量同步 / YSM 模型数据**不在我们那四个包里，被一起抹掉（法术模组判"锚核"也读它）。另外法术模组的 `ClientMaidRemovalGuard` 会拦下删包，拦下后我们那发"生成"就成了幽灵副本。
- ③ **修法：补包按实体网络 id 分流**（`LAST_ENTITY_ID`，入世界/离世界各记一次）：**id 变了 = 新实体（魂符放出/重新召唤）→ 不补包**，原版追踪本来就会发全套；**id 没变 = 同一只离场又回来 → 照旧补包**（这才是当初要治的"客户端把她弄丢了"）；**本次进程第一次见到 → 不补**。补包那一支同时**补发 TLM 饰品全量同步**。五百九十五 的"界面开着就推迟"保留。
- ④ **新增「装备离开」诊断日志**（`ProMaidExtension.onMaidEquipmentLeave`）：女仆装备槽从有东西变空时记一行——**槽位 + 丢的物品 + 她背包实时快照 + 8 帧调用栈**（同只女仆 1.5 秒最多一条）。栈里是 `AbstractContainerMenu.clicked` 就是玩家拖拽；是别的类就是"谁把装备拿走了"。**再复现一次把 `promaid.log` 发我（搜「装备离开」）就能直接定位。**
- ⑤ 验证：两树编译 0 错；重打两个 jar 并部署 3 个目标 `match=True`；回归 `test_server.py` / `test_maid_load.py` 两版本 **4/4 PASS**；探针与临时世界已清理。

## 实测五百九十五【收放魂符后血量上限掉回 20 的根因（我们自己那一枪）、装备被吞的那个窗口、重生锚用萤石不是萤石粉、撤掉上一批气泡】

- ① **重生锚充能用【萤石】（方块）而不是萤石粉**（回答你的问题，反编译实证）：原版 `RespawnAnchorBlock.isRespawnFuel` 只有一句 `stack.is(Items.GLOWSTONE)`——`Items.GLOWSTONE` 就是 `minecraft:glowstone` **方块**的物品形式（字节码：`Items.f_42054_` 由 `Blocks.f_50141_` 生成，后者正是 `register("glowstone", …)`）；萤石粉是另一个字段（`glowstone_dust` = `Items.f_42525_`），**充不了能**。我们内部常量一直是 `minecraft:glowstone`，没错。
- ② **bug 2【收放魂符后血量上限掉回 20】的根因：我们自己那一枪漏了一包**（你的判断是对的，与别的模组无关）：原版只在"开始追踪"那一刻下发属性表（`ServerEntity.sendPairingData`），之后仅属性变脏才补发；而实测五百六十五/五百六十六 加的"入世界自动补包"（删实体 + 重新生成）旧版只补了"同步数据 + 装备"，**没补属性表** → 客户端那只新实体属性全是默认值（TLM 女仆 MAX_HEALTH 默认 20），于是收放魂符后客户端算出来的上限就是 20；服务端属性一变脏（好感度升阶 `setBaseValue`）原版又把 80 补回来——**这就是你看到的 80/20 反复横跳**。服务端那一侧本来就是无损的（原版 `LivingEntity` 读档先读 `Attributes` 再读 `Health`，属性连 `Base` 一起存）。修法：`resyncTo` 按原版口径补全 —— 同步数据 → **属性表** → 乘客 → 装备（两个 jar 的字节码已核对带上 `ClientboundUpdateAttributesPacket`）。
- ③ **bug 3【收放魂符后拖装备被吞】的根因与修法：同一个"删+生成"落在她界面开着的窗口里**：玩家正开着她的物品栏/装备栏时重建客户端实体，TLM 容器槽位抓的还是那只**已被删掉**的实体、背包/饰品句柄一起作废 → 客户端"哪一格有什么"与服务端错位，来回拖就会吞装备。自动补包是入世界后 20 tick 触发，而"魂符放出"正好是一次入世界，玩家顺手开界面整理装备就撞上。修法：见到 `maid.guiOpening`（TLM 公开字段）就**推迟 1 秒再看、最多 10 次**，她一直开着界面就不补（关掉界面后的下次入世界还会登记；日志搜「重同步推迟」）。
- ④ **"还东西"的路径全部改成损失免疫**（同一类隐患，新增 `com.maidsmart.tool.MaidGiveBack`）：`insertItemStacked` 堆叠插入、拿到塞不进去的那一份，有剩就掉在她脚下——最坏落地、绝不消失。`MaidBombing.giveBack` 与 `MaidFlightKit.giveBack`（空袭换鞘翅/换武器换下来的胸甲与武器）改走它：旧写法"找第一个空格 → insertItem → **不看返回值直接 return**"，那一格被女仆背包禁放规则或模组背包限制拒收时整栈被退回来、旧版拿到就丢。`BombPose` / `FlightFireworkPose` 的归还也不再覆盖玩家在展示窗口里刚放进副手的东西（原物进背包 / 落地）。
- ⑤ **撤掉上一批（实测五百九十四）加的气泡**：重生锚那一段没开成的**原因只写日志**了（搜「轰炸链路没开成」），60 秒限频不变；手册 ⑦ 段同步改口径。
- ⑥ **验证**：两树逐处同步（36 处改动各命中 1 次、neo 无 SRG 残留增加）、两树编译零错、两个 jar 重打（9,556,954 / 9,579,013 字节，新类 `MaidGiveBack` 已入包）、三实例部署 `match=True`、1.20.1 与 1.21.1 服务器回归 + 女仆实体加载均 PASS。请你实测：升到 80 血 → 收放魂符 → 上限应仍是 80；反复拖动装备不应再被吞。






## 实测五百九十四【"放不下来"的真相、投掷 TNT 举打火石、动作表现开关】

- ① **"重生锚放不下来"的真相**：翻本机 `latest.log`（1.21.1 实例），那条诊断写的是「重生锚：缺萤石」——她**带着重生锚**，只是背包里没有那 1 颗萤石（原版 0 级充能右键不炸），于是这一段被跳过、退到了床（"床都能放置"就是这个原因）。放置逻辑本身没有问题（与黑曜石同一条路径，javap 已证），卡的是材料。
- ② **把原因说到脸上**（新）：重生锚这一段被跳过时（不管后面是床顶上还是整条链都没开成）她会**冒气泡**：缺萤石 → 「主人，给我 1 颗萤石吧——重生锚要充能 1 级才会炸～」；维度闸拦下 → 「这个维度里重生锚不会炸，我换个办法（维度闸）～」；床被维度闸拦下（主世界用床）同样有气泡。60 秒一条、同一句话不重复，日志同步落「轰炸链路没开成：…」。
- ③ **投掷 TNT 时副手举打火石**（反馈："在扔 TNT 的时候，副手武器应该切换成打火石"）：旧版举的是刚扔出去的那枚 TNT，现在改成**点火那只手里的打火石**；耐久已在投掷时"就地扣 1 点"里处理过，这里只借模型做表现（数量与耐久不动，0.5 秒后原样奉还）。
- ④ **新开关「副手动作表现」**（新配置 `pose`，默认开）：三处副手临时换物（放置举方块 / 充能举萤石 / 投掷举打火石，起爆再举一次）可以整体关掉，关掉只剩挥臂 / 音效 / 爆炸；半路关掉也会原样还回去（还原逻辑独立于开关）。





## 实测五百九十三【回收落地成掉落物、爆炸特效对齐原版、落点兜底强制放置】

- ① **背包满 → 掉在地上**（反馈："应该变成掉落物"）：底座（黑曜石 / 基岩）仍然先塞回她背包，**塞不进的那一份掉在她脚下**——与挖矿 / 搭路的方块回收完全同一口径（面板与手册的口径说明已同步改掉）。
- ② **爆炸特效对齐原版**（反馈："爆炸的特效太小了，比正常生成的末地水晶和 TNT 要小很多"）：根因是"不破坏方块"这个模式——原版只在**会破坏方块的爆炸**里放那团大粒子，`ExplosionInteraction.NONE` 恒走小粒子分支（javap 实证：`Explosion.m_46075_` 的两个粒子分支 + `ParticleTypes` 注册名对照）。现在不破坏方块时会**补发一枚同样的大粒子**（只补视觉，伤害 / 击退 / 地形一概不动）；打开「轰炸破坏方块」时原版本来就有大粒子、不重复补。
- ③ **重生锚"放不下来"的兜底**：javap 全量方法表证明 `RespawnAnchorBlock` 的放置规则与黑曜石完全一样（没有覆写 canSurvive / getStateForPlacement），问题在原版放置判定本身（最典型：落点那一格正站着实体 → `isUnobstructed` 直接拒绝）。现在原版拒绝之后会**补一手强制放下**（仅当那一格确实可替换、且不是床）并写日志；"放不下"的日志会写明三段找法都没成，「轰炸跳过」会写明缺萤石或哪个维度被闸（带维度键）。




## 实测五百九十二【萤石回归（重生锚完整动作链）+ 轰炸推广到所有攻击模式】

- ① **萤石要回来**（反馈："不行啊，重生锚还是需要一个萤石进行充能的。所以正确的链路应该是攻击→副手换成重生锚，放置重生锚（摆臂）→副手换成萤石，拿一颗萤石充能（摆臂动画）→继续切换回飞行。0.5 秒后再挥一次手臂。正好对上重生锚自爆"）：上一版把"不需要这个机制"当成引信、把萤石去掉了——现在整段按原话重排：**攻击打完 → 副手换成重生锚 → 放下（挥臂）→ 副手换成萤石 → 消耗 1 颗萤石充能（挥臂）→ 交还链路**，**0.5 秒后她再挥一次手臂**、正好压上重生锚自己那一炸。1 颗就够的理由：0 级充能不炸，而充能等级只决定"炸不炸"、不决定"炸多狠"（那一炸写死 5.0F，反编译实证）。面板「重生锚需要萤石」（默认开）也回来了。
- ② **轰炸推广到所有攻击模式**（反馈："将末地水晶/重生锚/床的机制推广到所有的攻击模式下（除了远程空袭，因为一直飞在天上，本来就放不了）"）：相位机改由**服务端 tick 每 tick 统一驱动**（不再只由空袭行为推），所有战斗任务都在"刚打完一记"那一刻试起手——地面近战 / 弓弩 / 三叉戟 / 弹幕 / 枪械 / 近战空袭 / 第三方战斗任务都有，**远程空袭按 UID 排除**；材料齐则整段交给相位，相位收尾照旧接着投 TNT。
- ③ **轰炸最短间隔**（新配置 `bombInterval`，默认 200 tick = 10 秒）：轰炸仍挂在攻击链路里（打完一记才放），这条只是两次之间的下限——推广到所有攻击模式之后，不加下限一次挥砍放一枚会在几秒内烧光黑曜石 / 水晶；缺料那一下不占用间隔。
- ④ **硬清相位时回滚**：`forget` 现在会把已放下的方块撤掉并**原物还她**（旧版只 remove，那块黑曜石白留在世界里——空袭每次收尾都走 forget，漏点很常见）。
- ⑤ **面板 / 语言 / 手册**：「近战空袭轰炸」更名为「战斗模式轰炸」（含说明与四份语言文件），面板新增「轰炸最短间隔」、「重生锚需要萤石」回到「放置与材料」小节；手册 ⑦ 段同步改写并修掉上一版残留的一句重复文本。




## 实测五百九十一【重生锚去萤石、放置间隔、维度闸、追踪限时限转角、打火石耐久、动作表现、回收归属】

- ① **重生锚不再需要萤石**（反馈："重生锚还是放不了，放置逻辑改为跟放黑曜石一样"、"重生锚和床不需要有这个机制，因为它自己会炸"）：旧版这条链路要求「重生锚 + 萤石」，没萤石就**静默**跳过——这就是"放不了"的根因（那一炸固定 5.0F、与充能等级无关，引信本来就是我们自己点的）。现在它与黑曜石走**同一条放置口径**，放完照原版 `charge` 补 1 级（音效 + 等级变化 + 挥臂），不消耗任何引信材料；面板那条「重生锚需要萤石」已撤掉。另外补上**缺料日志**：带着材料却没开链路时写「轰炸跳过（没有可用链路）」并列出缺哪件 / 哪条被维度闸拦下（每 10 秒最多一条）。
- ② **看得见的放置间隔**（反馈："黑耀石和末影水晶几乎是同时放置的，根本看不出间隔"）：放底座与挂水晶 / 充能之间插入 **0.5 秒**间隔（新配置 `placeGap`，默认 10 tick，可调 0~40）。
- ③ **维度闸**（反馈："其他模组会添加其他的维度，在其他的维度不会爆炸，必须要检测当前维度有可以爆炸的代码才开放这条链路"）：判据就是原版自己判断要不要炸的那两句（重生锚 `respawnAnchorWorks`、床 `bedWorks`，false 才炸）；模组 / 数据包新增的维度写成"这个维度能用"就整段不开放；新开关 `dimensionGuard`（默认开）。
- ④ **TNT 追踪限时 + 限转角**（反馈："还是太鬼畜了，运动很不自然，追踪时间控制在 0.5 秒左右，0.5 秒之后不再追踪，时间可调"）：只在**离手后 0.5 秒**（新配置 `tntTrackTicks`，默认 10 tick，可调 0~200）内修正方向，且每 tick 最多转 **5 度**——一段平滑小弧线、只小幅修准，到点按当时方向直飞；仍然只改方向、速度不变。
- ⑤ **打火石就地扣耐久**（反馈："扔 TNT 的时候会直接把打火石吞掉，而不是消耗打火石的耐久"）：旧版把整件取出、只对取出的那份扣耐久；现在从**同一格**取出 → 扣 1 点 → 放回**同一格**，耐久见底才真的少一件。
- ⑥ **动作表现**（反馈："放置方块/给重生锚充能/扔 tnt 的时候要有一个动作，使用动作的时候替换一下副手上的物品；放置完重生锚/末地水晶后 0.5s 也会有一个挥臂的动作"）：新类 `BombPose`——那一刻副手短暂举起**她正在用的那件**（复制品、0.5 秒后原物奉还），**起爆那一刻再挥一记**（她还在 8 格内才做）；与烟花姿势互不打扰（免得两套快照互相覆盖弄丢盾牌 / 食物）。
- ⑦ **回收归属**（反馈："黑曜石的回收是回收到女仆的背包里" + 口径确认"回收一律不掉落，这条也套用到重生锚与床"）：底座**变成物品收进她背包**（背包满就就地消失、**不掉落地面**，所以不会白送黑曜石）；重生锚 / 床**自己那一炸就消耗掉了**（原版口径），起爆即撤、不回背包；相位失败回滚时**原物还她**。
- ⑧ **面板 / 手册 / 语言**：新增「放置间隔」「TNT 追踪时长」「维度闸（原版会炸才开）」三行，撤掉「重生锚需要萤石」；手册 ⑦ 段同步改写并新增"她带着材料却没放？搜「轰炸跳过」"一条。




## 实测五百九十【TNT 挂进攻击链路末段 + 小型追踪、傀儡模式（傀儡装配）黑名单】

- ① **TNT 改成"打完一记才扔"**（反馈："最好是跟末影水晶一样放在攻击链条的某个部分……适当的正常攻击链路走完之后加到最后。而不是一个固定的 Cd，CD 仅作为最小释放，间隔 10 秒左右"）：攻击链路收尾才登记一发待投放——近战空袭是「猛击命中 → 该段的炸弹 → TNT」，远程空袭是「开火之后」，其余战斗任务按「攻击冷却记忆刚写入」判定；投掷间隔默认 **40 → 200 tick（2 秒 → 10 秒）**，而且**只当最短间隔**（没到点就挂着、等下一记），不再是驱动本身；老配置自动迁移（120 → 40 → 200，自己调过的不动）；
- ② **TNT 小型追踪**（反馈："TNT 再加一个小型追踪功能，TNT 会朝着目标的方向飞行（只更改方向，速度不变）直到爆炸"）：引信期间每 tick 把速度**方向**掰向目标、**速度大小不变**，并按 −0.04/tick 重力做垂向补偿（只拐弯、不加速），直到爆炸；目标没了/换维度就按当前朝向直飞。新开关 **「TNT 追踪飞行」**（默认开）；
- ③ **傀儡模式自动列入黑名单**（反馈："如果检测到有傀儡模式，那么会自动将他列入黑名单。自主切换和主动作战不会切换到这个模式"）：对象 =《傀儡装配》Modular Golems（`modulargolems`）给女仆注册的**「傀儡师」**任务（javap 实证 `MaidSummonerTask implements IRangedAttackTask`，UID `modulargolems:summon_golems`，条件 = 主手持万能手杖）——**自主参战选任务 / 战中换战术**的任务池与 **LLM 自主切换**的可用任务列表里直接过滤掉（永不切进去）；**TLM 自带的 `switch_work_task` 工具也上了一道闸**（mixin 在工具调用入口按 UID 拒绝——`AutonomousTaskManager` 的自主决策驱动的就是它，那条路完全不经过本模组代码；`require = 0`，注入点对不上时只失效不崩服）；没装那个模组时它只是一句恒假判断；
- ④ **手动切进去之后，本模组战术全体让位**（反馈："原本这个 mod 安排的所有战术全都暂时无效，仅保留那个模组原汁原味的傀儡装配玩法"）：单兵走位/跳劈/举盾与威胁驱动、投弹与轰炸、自动换装、自主参战与还原、排班换段**全部停手**，切回来即自动恢复（存档数据未改动）；**保命动作不在让位之列**（自保/落地水/防火/宠物免疫）；新开关 **「傀儡模式黑名单」**（默认开，面板「战斗与自保 → 空袭数值 → 第三方玩法模式」）；
- ⑤ **面板 / 手册 / 语言**：面板新增两行（TNT 追踪飞行、傀儡模式黑名单）并改写"投掷间隔"说明；手册⑩段补上链路与追踪、新增 ⑪【第三方玩法模式：傀儡师】；四份语言文件同步；




## 实测五百八十九【TNT 准度/CD、空中强制放置、水晶外观与黑曜石保留、萤石判定、粉色标记】

- ① **TNT 准度**：旧版忽略了 0.98/tick 的水平阻尼（水平位移是等比级数、射程有限），目标一动就偏；现在改成**闭式弹道解**（每 tick 先 −0.04 重力、再位移、最后整体 ×0.98 → 先解飞行时间 n、再解竖直初速 vy0）并给目标加**提前量**，落点误差只剩地形阻挡；
- ② **TNT 冷却**：默认 120 → **40 tick（6 秒 → 2 秒）**；老配置里还是 120 的会在启动时自动迁移一次（自己调过的不动）；
- ③ **空中也能放**：落点三级找法——① 目标脚边四邻 → ② **她正下方**往下扫 16 格（「落点位于自己下方可放置方块的区域」）→ ③ 都没有支撑面就**直接悬空放下**（新开关「空中强制放置」，默认开；原版放置本身允许悬空，只是玩家手点不到空气）；关掉第 ③ 级则回到"找不到带支撑的落点就整段跳过"；
- ④ **重生锚与萤石**：**放置不需要萤石**，**要它炸**才需要 ≥1 级充能（原版规则：0 级不炸）；威力是写死的 5.0F、与等级无关，1 级足够。默认仍要 1 颗萤石点火（照原版 charge：音效 + 挥臂）；新增开关**「重生锚需要萤石」**（默认开），关掉就不消耗萤石、她直接补上那 1 级；
- ⑤ **水晶外观 + 黑曜石保留**：水晶改成 `setShowBottom(false)` = **原版物品放置的样子**（不是末地柱子上那种带底座的）；底座黑曜石**起爆后不再立刻消失**，新增**「炸弹底座回收延迟」**（秒，默认 10，0 = 起爆即回收）到期由她回收，**回收不掉落**、不会白送材料；
- ⑥ **粉色标记**：填充 0.16/0.20 → **0.34/0.38**，方块标记也加**亮粉棱线**，并在上方浮一行 **「友军炸弹」**（跟着 TNT 飞的那份会一起动）——之前太淡看不出是友方的。




## 实测五百八十八【TNT 投掷推广到所有战斗标签模式 + 防误伤 + 自爆风免】

- ① **TNT 投掷不再只属于远程空袭**：改成**所有有战斗标签的模式**都会扔（近战 / 弓弩 / 三叉戟 / 弹幕 / 枪械 / 近战空袭 / 远程空袭 / 第三方战斗任务）——判定用既有 `MaidWorkTags.isCombatTask`（`IAttackTask` 接口 + UID 兜底），服务端每 4 tick 扫一次，条件 = 战斗任务 + 有 TNT 与打火石 + 冷却到点 + 半径内有合法目标；投掷手法照《女仆生存》那套思路自己实现（身位 75% 高度朝目标中心抛、水平单位向量 × 初速 + 竖直补偿）；
- ② **参数对齐女仆生存**：索敌半径 **12 格**、冷却沿用本模组 6 秒、引信 2 秒、初速 0.9；**残血（≤ 七成血）连投最多 3 发**、横向散开（女仆生存的"低血量爆发"）；空中地面都能扔；
- ③ **防误伤（两道）**：主人 / 同主女仆 / 友军**绝不会成为投掷目标**（先过友军判定、再过任务自己的 `canAttack`）；炸弹的伤害与击飞对主人/友军一律不生效；
- ④ **自爆风免（与重锤不同）**：重锤风爆会把包括她在内的所有人掀飞；**这条链路做的炸弹，它的风对放炸弹的女仆本人也不生效**（爆炸期间挂窗口，风免的两条路径都查它）——她不会被自己的炸弹推飞，伤害本来就已经免疫；烟花推进 / 风弹自起跳 / 空袭弹开这些"她自己的机动"一字未改；
- ⑤ **新增 3 项配置**（「战斗与自保 → 空袭数值 → ⑦ 空袭轰炸」）：**投掷索敌半径**（默认 12）、**残血连投阈值**（默认 0.7）、**连投最多**（默认 3，填 1 = 关掉连投）；该小节改名为「所有战斗模式：TNT 投掷」；
- ⑥ **排查**：运行日志搜「空袭轰炸」——投掷会写「谁投掷 TNT ×N（引信 … tick）」。




## 实测五百八十七【空袭轰炸：末地水晶 / 重生锚 / 床 + 远程投掷 TNT】

- ① **近战空袭多了一段轰炸（默认开）**：猛击命中之后、再次起飞之前，按包里材料放一枚炸弹——**① 黑曜石/基岩 + 末地水晶（威力 6，优先）② 重生锚 + 萤石（威力 5，下界不生效）③ 床（威力 5，主世界不生效）**；三段按顺序取第一个材料齐的，**放不下就整段跳过**（悬空目标脚边没地面、位置被占等），直接接着起飞、不卡链路；落点选"离她最近的目标脚边那一格"（要有实心支撑、不把她自己埋了）；
- ② **重生锚只要 1 颗萤石**：反编译实证那一炸的威力是**写死的 5.0F**，与萤石充能等级**无关**（充能等级只决定"炸不炸"：0 级右键不炸），所以不需要"充到 4 级"那套功能——放下后用萤石充 1 级（照原版 `charge`，有音效 + 挥臂）；同一批数字：末地水晶 6.0F、床 5.0F、TNT 4.0F；床/重生锚的生效维度也是原版口径（床在主世界、重生锚在下界都不炸）；
- ③ **远程空袭多了一条附加链路（默认开）**：天上盘旋期间额外扔 TNT（默认 6 秒一发、引信 2 秒），需要**同时有 TNT + 打火石**（每发 1 个 TNT、打火石掉 1 耐久）；**缺料静默跳过**，不影响弓弩/枪械开火；
- ④ **爆炸口径默认全保护（四个开关都在「战斗与自保 → 空袭数值 → ⑦ 空袭轰炸」）**：**不伤主人/友军**（炸弹归因给女仆 → 伤害走友伤守卫、击退走重锤同款风免；她自己也不会被自己的炸弹炸伤，只被震开当起飞推力）、**不破坏方块**（只炸伤害与击退，地形一点不动）、**淡粉色标记**（默认开，纯客户端：她刚放的方块/水晶/扔出的 TNT 套一层很淡的粉框，TNT 那层框跟着飞）；打开「伤到主人/友军」= 完全原版（主人照掉血照被炸飞，她也吃自己那一发），打开「破坏方块」= 原版爆炸照原样炸坑；
- ⑤ **她放的方块一定回收**：无论开关如何，黑曜石/重生锚/床都在起爆时由她撤掉（不掉落）——不会在世界里留永久黑曜石、也就没有"白送材料"；
- ⑥ **排查**：日志搜「空袭轰炸」——会写"谁放下了什么、放在哪个坐标、多少 tick 后起爆、威力多少"；放不下时也会写明原因；想看全过程可把「起爆延迟」调大（默认 10 tick = 0.5 秒）。




## 实测五百八十六【缺料同类宽松：建筑严格 / 机器放宽（issue #14）】

- ① **新档位 `build.looseMaterials`（off / machine / always，默认 machine）**：机器蓝图里允许 **任意告示牌↔任意告示牌、任意树叶↔任意树叶、任意羊毛/地毯↔同类型、任意染色玻璃/玻璃板↔同类型** 互替（它们在机器里只是挡水/标记/遮光/观察窗的功能件），建筑图纸保持严格（配色/树种不会被动，樱花树不会被换成橡树）；off = 旧行为，always = 全都放宽；悬挂告示牌单独一桶（物品与放法都不同）；
- ② **分桶不写死名单**：按物品注册名后缀现场扫一次注册表并缓存（模组方块自动纳入），墙上版本先经五百八十三的归一变成前身物品（`oak_wall_sign → oak_sign`），所以立式/墙上天然同族；
- ③ **口径统一**：新增 `equivalentGroup()` 作为等价族唯一入口，材料统计 / 取料 / 主人背包转移 / 替代品验收 / 创造豁免 6 处全走它——面板与气泡里的数字跟实际会用到的材料一致；建造行为每 tick、建造入口、容器取料各登记一次"当前图纸"，machine 档据此生效；
- ④ 面板「模组详细配置 → 生产与工作 → 建造 → 缺料同类宽松」，手册建造章补【缺一个颜色就整台卡住？】；


## 实测五百八十五【流体保留判据可配置 + 剥离不再静默（issue #15）】

- ① **流体的保留/剥离不再只认文件名关键词**：`build.keepFluids` = auto（默认）/ always / never——auto 档除文件名里的机器关键词外，**还看图内容**（调色板里出现 ≥3 种红石机器件即判机器图纸；"一个拉杆+一盏灯"的装饰房不命中），`川川12w刷石机` 这类名字里不含关键词的机器不再被静默剥掉水/岩浆；
- ② **剥离不再静默**：解析时写运行日志（剥掉多少格 + 两种改成保留的办法：改文件名 / 把配置设成 always），「建造此图纸」的提示里也附一句——不再"机器一动不动、毫无线索"；
- ③ **内容判据只用于流体**，机器专属搭建顺序与活放置口径不变（仍按文件名家族）——避免"看起来像机器就改建造方式"的连带风险；
- ④ 面板新增「图纸流体保留」档位行，手册建造章补【图纸里的水/岩浆怎么办】；


## 实测五百八十四【指标石锁定死锁：进世界同步 + 无条件解锁出口（issue #13）】

- ① **根因**：客户端锁定状态是 static，只在收到 S2C 时更新，而服务端推状态只有 3 个调用点、**没有任何"进入世界时同步"**；单人档退出世界不重载客户端类 → "服务端早清了、客户端还以为锁着"，退出世界重进也没用；
- ② **补上进世界同步**：登录与切换维度各补一次 `syncTo`（会话为空自然推空状态 → 客户端解锁）；
- ③ **客户端断线/重连清镜像**：`ClientPlayerNetworkEvent.LoggingOut / LoggingIn` → 本地 static 归零；
- ④ **无条件解锁出口**：锁定期间 **潜行 + 右键 = 强制解锁**（原来只有"重新右击那一格"一条路，而那格可能已被水/地形挡住或超出 512 格长射线）；服务端仍按原规则校验（女仆搭建中会婉拒）；
- ⑤ 锁定提示与用法提示补上"瞄不到那格怎么办"，手册指标石章新增一节；


## 实测五百八十三【墙上告示牌 / 墙上火把永远报缺料（issue #12）】

- ① **方块→物品归一**：`wall_*`（墙上火把/墙上告示牌/墙上横幅/墙上悬挂告示牌）是**独立方块但没有同名物品**（物品是它的前身 `oak_sign` / `redstone_torch` / `white_banner` / `oak_hanging_sign`）——旧版按方块名搜物品永远搜不到 → 永久报缺料；现在统一做一次"去掉 `wall_` 再查注册表"的归一（模组方块同样适用）；
- ② **`itemForBlock` 对无物品方块返回 null**：物品注册表对查不到的 id 会给 air（不是 null），旧版据此认为"有对应物品"，于是 `MaidBuildBehavior` 里那条「没有对应物品 → 永久跳过并报告」**是死代码**——任何无物品方块都会以"材料不够"的名义永久卡死（实测 8 分钟不动、切创造才过关）；现在快速路径与延后轮询两处都会**跳过 + 播报 + 写 `build skip` 日志**；
- ③ **缺料气泡念物品名**：`redstone_wall_torch` 的中文规则会拼成"红石墙火把"（游戏里搜不到），现在报"红石火把"；
- ④ 入口提示：世界存档提取（.zip 蓝图）不过滤无物品方块，是最容易带进 `wall_*` 的链路；`.litematic/.nbt` 解析期会过滤掉 `asItem()==AIR` 的方块（若日志里确有这两个方块，欢迎把图纸发来核对）；


## 实测五百八十二【版本号升为 v1.2.2 / release 说明改写成「两版差异」】

- ① **版本号 1.2.1 → 1.2.2**：`mods.toml` ×3、构建 / 部署 / 测试脚本的 jar 名、README、发布指南、GIT_SYNC 一并同步；部署脚本的"旧包清理"过滤器改成通用 `promaid-*.jar`（除本次写入的那个以外全删）——换版本号不必再改脚本，也避免同 modId 双 jar 启动失败；
- ② **两份 release 说明重写成「v1.2.1 → v1.2.2 差异」**（Forge / NeoForge 各一份）：一句话总结 + 六节主题（法术兼容 / 空袭手感 / 喂食喂水 / 面板手册 / 兼容稳定 / 4 个新 AI 工具）+ 本版行为变化 + **致谢 @rodericksthescriptkid**（法术兼容由他写成，本人只做实战战术改良与 1.20.1 移植）+ 已知限制；
- ③ 本批**没有代码改动**——内容与实测五百八十一 完全一致，只是换版本号并把发布说明改写成两版差异；


## 实测五百八十一【空袭数值全部可调 / 新增「空袭数值」配置页】

- ① **34 项空袭数值全部可调**：`MaidFlightCombatBehavior` 里写死的飞行常量（起飞时长/仰角、收翅距离/命中判定/俯仰限幅、盘旋半径/期望高度/掉高容差/补推窗口、开火间隔/射程、弹开半径/速度/时长、冲刺距离）全部搬进配置的新分类 `airRaid`——**默认值与原常量一字未改**，行为不变，只是把原来只能改代码的旋钮交出来；调用点改成逐次读配置，改完立即生效；
- ② **面板新增小类页「战斗与自保 → 空袭数值」**：六个小节（起飞与爬升 / 收翅俯冲 / 盘旋与补高 / 远程开火 / 近身弹开 / 位移法术），每项都带说明（默认值、调大调小的后果），两处连带影响（起飞仰角、盘旋高度）在注释里点明；
- ③ **手册**：空袭章新增【空袭数值面板：所有数值都可调】一节，章末「⚙ 配置入口」现在直接跳到这一页；
- ④ **两版差异只有一项**：1.20.1 多「地面近战触及距离」（退路用）、1.21.1 多「猛击下落加成门槛」（重锤下落加成的写回下限）；


## 实测五百八十【喂水走物品自己的使用路径 / 勾选面板按剩余次数细分】

- ① **喂水改成对真栈结算**（旧版"喂副本 + 扣来源"）：多次使用的容器（水壶这类，用完还剩 3/4 次）不再被当一次性扣掉；交还的容器/残余塞回背包，**塞不下就掉在脚下**（旧版静默丢弃）；物品抛异常时来源一点不动；
- ② **勾选面板按「剩余次数」细分**：喂食勾选页与喂水白名单页里，耐久物品（能喂/喝好几档的）每一档剩余次数各占一行——「剩 4/4 次」和「剩 3/4 次」是两个独立条目，各自勾选互不影响，悬停写明「剩余 N/M 次」；名单条目支持手写 `注册名#剩余次数`，不写 # = 该物品任意次数（旧配置照旧生效）；


## 实测五百七十九【盘旋高度 +10 格 / 喂食改走物品自己的 finishUsingItem】

- ① **远程空袭期望盘旋高度 3.5 → 10 格**（按作者口径；3.5 格太薄，滑翔一转弯就低于敌人）——配合上一批修好的补推阈值（低 0.5 格就补）＝"低于期望高度就补"真正成立；射程不受影响（3D 24 格，盘旋 10 格时约 14 格）；
- ② **喂食改走物品自己的 finishUsingItem**（普通食物与旧版 eat() 完全等价，但重写过它的物品才按自己的语义生效）：奇异饰品的「永恒牛排」这类**吃完不消失**的遗物不再被手搓的 `shrink(1)`/`extractItem(1)` 扣掉，它自己的效果照常生效、并按自己的冷却节流（女仆身上读不到物品冷却，本地记 10 秒）；姐妹链 / 主人链 / 自救吃食物 / feedtest 共 7 处站点统一；TLM 的 HEAL_MEAL 回血只在**真吃掉一份**时补调。


## 实测五百七十八【位移法术照抄烟花 / 掉高补推修复 / 空袭续航 / 新增 4 个 AI 工具】

- ① **位移法术的朝向一律照抄烟花（A 方案）**：起飞/补高改走烟花起飞那套（地面目标＝背离敌人＋抬头，目标高出 10 格以上才朝目标爬；抬头角近战 62°/远战 45°），盘旋里用掉高窗口那 45° 抬头——不再自己发明角度（旧版"朝目标抬头 62°"等于往敌人脸上窜，"盘旋圈上冲一口"等于当面切进去）；
- ② **远程空袭"掉高补推"从来没生效过 → 已修**：期望盘旋高度 3.5 格 与 补推阈值 3.0 **相消**，实际触发点是"目标高度 +0.5 格"＝几乎贴地，所以对地面目标永远走不到（反馈"每次都是掉到地上再补"）。阈值改 0.5＝低于高度带半格就补；
- ③ **续航战术**：掉高窗口里按 **位移法术 → 羽扇 → 烟花** 的顺序补推，法术成功时**自己开那个抬头窗口**（"只带法术不带烟花"也能一直飞）；舰升腾/烈焰冲锋的两条口径（水平被放大 3 倍、"抬头 62°"实际约 45°、一次性冲量非持续推力、高速时可能削速）已写进手册与 README；
- ④ **新增 4 个 AI 工具**：`smart_switch_task`（换任务/模式，中文别名，认不出回可用列表）、`smart_air_raid`（起飞/停止空袭，含缺件回报）、`smart_work_area`（定工作区驻守/解除/查看）、`smart_readiness`（只读自检：三件套/弹药/驻守/排班/锚点/血量）。四个开关都在「AI 工具」区，默认开。


## 实测五百七十七【官方译名统一 + 手册空袭法术段致谢】

- ① **官方译名为《车万女仆：万法皆通》**：手册第七/八/十章、配置项注释、配置面板提示、中文语言文件、类注释与 README 里原先混用的旧名《车万女仆：魔法》全部统一（只改显示名，模组 id 与英文名 Touhou Little Maid: Spell 一字未动、行为零变化；历史 changelog 条目保持原样）；
- ② **手册「空袭状态下的法术怎么用」正文首行加致谢**：这套空袭法术兼容主要由 **Roderick32**（GitHub `rodericksthescriptkid`、B 站 `Roderick32`）写成——我对魔法方面并不是很了解，法术兼容这一块交给他接手；我在这里的作用只有在实战方面做了一定程度上的战术改良（法术该在空袭的哪一段放、怎么配合起飞与俯冲），以及把这份兼容移植到 1.20.1。


## 实测五百七十六【羽扇高度回调 / 冲刺法术方向 / 刚放出误报 / 喂水水质】

- ① **羽扇竖直冲量 0.85 → 1.05**（按反馈取"玩家体感的 1.25 倍"；水平分量不动）；
- ② **冲刺法术的旋转动画是法术自己的**（烈焰冲锋是冲刺类法术，法术模组会给施法者播动作；本模组的激流三叉戟链路只认主手三叉戟+激流，日志搜「激流突进」可证）；**方向已修**——盘旋相位她的视线沿切线，放冲刺前先摆正到"朝目标 + 略抬 12°"，不再横着飞出去；
- ③ **刚放出不再误报缺件**：入世界后 0.5 秒静默 + 法术书负缓存缩短到 5 tick + 入世界清缓存（法术数据要一拍才初始化）；
- ④ **喂水水质分级**：口渴模组分四档（肮脏/有点脏/可接受的/纯净），新增「喂水最低水质（0-3）」默认 2 = 可接受的（只对装水容器生效，果汁牛奶不受影响）；喂水白名单子页里每杯水会标出水质。


## 实测五百七十五【1.20.1 法术层修复 / 空袭传送说明纠错 / 排班表归位 / 面板溢出 / 羽扇】

- ① **【1.20.1 关键】法术兼容层被签名差异判死**：插件包 1.20.1 的 `stopAllCasting(女仆)` 与 `setCurrentCastingSpell(SpellData)` 与 1.21.1 不同，旧探针写死 1.21.1 签名 → 整层（顺带施法 + 位移法术）全关。现在两种签名都认、可选能力缺失不再拖垮整层——**带着烈焰冲锋的书（背包/饰品栏）就能平地起飞了**；
- ② **手册空袭传送说明纠错**：飞行期间让位的是"自动传送"（跟随/跨维/搭太高/自保归位），而且让位有界（滞空超 15 秒强制拉回）；**你手动的「一键集合」与主人死亡传送照常生效**（原手册写成"禁止被传送"是错的）；
- ③ **「排班表」配置项从「移动与行为」挪到「生产与工作」**（手册一直这么写，是面板挂错了）；
- ④ **喂食 / 喂水子页窄窗口文字溢出修复**：悬停信息按最宽行收进屏幕、标题与统计行缩短并居中钳制；
- ⑤ **羽扇**：竖直冲量夹到 0.85 格/tick（旧值低速挥扇时达 2.2，比玩家高太多），并补上挥扇动作。


## 实测五百七十四【空袭缺件文案 + 法术进起飞判定 + 手册法术实战指南】

- 缺件气泡从「缺烟花火箭/羽扇（或能上天的位移法术）」改为「**没有可以飞行的道具**」，并在缺这一项时尾注「（烟花火箭 / 孔雀羽扇 / 位移类法术任一）」；
- **可起飞判定**新增总口径：烟花/羽扇可用 **或** 她会"提供高度"的位移法术——与模式激活、缺件提示三处口径终于对齐（内部仍是有烟花先走烟花链路、没有才用位移法术，旧手感不变）；
- 手册「空袭」章新增 **⑨空袭状态下的法术怎么用（配装 + 节奏 + 排查）**：两类法术各司其职、三段施法节奏、她不会做的事、举例（只带升腾也能起飞）、日志怎么对；
- 同章三件套小节改为「③ 可以飞行的道具（三选一）」、常见问题与 README 同步措辞。


## 实测五百七十三【五个问题一起修：羽扇 / 重锤风爆 / 喂水面板 / 河童罗盘 / 魂符模型】

- ① **羽扇不认（放背包也报缺羽扇）**：注册名写成了 `twilightforest:peacock_fan`，真实是 `twilightforest:peacock_feather_fan`（少一个 feather，永远匹配不上）——已修正（两树），背包里放一把即算燃料；
- ② **主人被女仆重锤波及**：原版风爆附魔的爆炸没有来源实体（`wind_burst.json` 无 attribute_to_user），爆炸归因拿不到女仆 → 击退发给了主人的客户端（只震不伤、服务端都没变）。风免归因补第三条兜底（"这一下在谁的 tick 里创建就算谁放的"）；
- ③ **喂水面板照搬喂食**：入口行改为「喂水白名单 · 打开 →（可喂 N / 候选 M）」，子页与食物勾选页同款——搜索 + 图标网格（绿✔可喂 / 红✖不喂，点击切换）+ 翻页 + 手动填注册名 + 底名单「不喂了」一键移出；候选按口渴模组自己的口径扫描；
- ④ **中键工位标记 × 河童的罗盘**：两者写的是**同一份排班锚点**，谁后写谁生效（女仆不会挑）；现手持罗盘时中键自动让位，另加「移动与行为 → 中键工位标记」开关（默认开）；
- ⑤ **1.20.1 魂符放出后模型变灵梦**：客户端实体重同步误用了 packDirty（只发"变化过的值"，通常一个都不发）→ 复活出来的客户端实体保持默认模型；换回 getNonDefaultValues（与 1.21.1 树一致）。


## 实测五百七十二【位移类法术当推进器：平地起飞 + 空中补高 + 飞行加速】（PR #11，@rodericksthescriptkid 社区贡献）

- 需求（法术模组作者转达的玩家反馈）：位移类法术（如「烈焰冲锋」）用于①飞行加速、②平地起飞；
- 按"冲量方向"分两类：「提供高度」（默认升腾+烈焰冲锋）用于平地起飞与空中补高（施法前抬头 62°，并把法术模组的施法目标清空，免得它施法前把朝向掰平）；「提供速度」（默认烈焰冲锋）用于飞行加速（对着目标冲一口续速）；
- 推进剂口径放宽：没有烟花/羽扇时，带得起飞法术 = 三件套照常激活（否则"平地起飞"那条路永远走不到）；
- 指定法术瞬发施法（序列照抄法术模组自己的 /maidspell iron_cast），按她书里铭刻的等级放（等级影响冲量），并写回法术模组自己的冷却表；
- 冷却口径：「提供高度」不受法术自身冷却约束（激流三叉戟先例：位移手段让女仆比玩家宽松——不这样"没烟花也能持续飞"就不成立）；「提供速度」默认尊重法术自身冷却（取 max(间隔, 法术冷却)）；
- 配置六件：flightDashClimb / flightDashBoost / flightDashClimbSpells / flightDashBoostSpells / flightDashInterval（默认 40 tick）/ flightDashBoostRespectCooldown；两树同步（1.20.1 由作者按 SRG 移植）。


## 实测五百七十一【女仆喂水：软联动「口渴」Thirst Was Taken】

- 反馈原文："能让女仆喂水吗（软联动口渴mod）……把判定位点改为口渴值即可……触发效果和玩家自己喝水是一样的（也就是说会返还玻璃瓶这种）……同时给一个像喂食物一样的白名单。如果没有装这个模组，那么此配置项目不会出现。"；
- 贴身辅助新增分支：主人口渴值低于「投喂触发口渴度」（默认 15）时，从女仆背包/手持按口渴恢复量选优喂水；结构照搬喂食链；
- "跟玩家自己喝一样"：代喂走物品自己的 finishUsingItem——药水瓶口渴（TWT MixinPotionItem）、TWT 自家物品、可食用饮品、容器返还（玻璃瓶/陶碗/空桶）全走原版喝的路径，喝完的容器塞回女仆背包；其他 mod 的装水容器由 ThirstCompat 按 TWT 完成钩子同口径兜底调 PlayerThirst.drink（不双重计数）；
- 喂水白名单（aidDrinkWhitelist，默认=水瓶+陶碗水；potion 只认纯净水，其它药水永不喂；留空=不喂水）——其他 mod 的装水工具把注册名加进来即可；
- 两项喂水配置按模组在场条件注册：没装「口渴」时面板与 toml 里都不出现；
- 喂食的容器返还核查：蜂蜜玻璃瓶（v1.5.288 起）与牛奶空桶早已实现，喂水沿用同一口径。


## 实测五百七十【近战空袭起手挥臂 + 起飞前地面补跳】

- 反馈原文："近战空袭也没有攻击动作"、"触发起飞有点困难，触发烟花起飞之前先向上跳跃一下，然后再走原来的流程"；
- 近战空袭：挥臂提前到收翅俯冲起手那一刻（旧版唯一一挥在高速俯冲的最末尾，看不见）；命中结算那一挥保留；三叉戟自转不冲突；
- 起飞：跳起窗口内离地前的每一 tick 都补一跳（旧版重试只摆头不补跳，第一跳被走位吃掉就整轮点不着烟花）；离地后原流程不变。


## 实测五百六十九【攻击动画补全：重锤猛击命中挥臂 + 远程空袭弓/弩/弩烟花开火挥臂】

- 反馈原文："重锤+风弹下落攻击的时候没有攻击的动作，只有效果"、"远程空袭看不太清楚，不确定有没有"；
- 地面重锤猛击（1.21.1）确实没动画：全程直接 hurt 结算，粒子音效全播、唯独没挥臂——补在结算前（出手即挥）；
- 远程空袭缺的是弓/弩箭/弩烟花三分支：出手瞬间补挥臂；三叉戟（自转）、御币（本就挥）、TACZ 枪械（模组自己的开火动画）本来就有；
- 空袭近战猛击与地面普通近战的挥臂本来就有，未改动；1.20.1 树同步补远程三分支。


## 实测五百六十八【TACZ 弹药箱兼容：弹药箱也算「有子弹」】

- 反馈原文："远程空战模式不识别 TACZ 的弹药箱，会提示没有弹药按照普通模式来，但普通模式不会开枪（因为觉得没有弹药）"；
- 根因只有一道门：本模组的枪械弹药判定（空袭弹药门禁 + 自主战斗切枪械共用）只数散装 tacz:ammo，弹药箱（tacz:ammo_box）被当「没子弹」→ 空袭不激活退普通模式、gun_attack 也不进池；
- 消耗侧零改动：TACZ 自己的换弹本来就认弹药箱（isAmmoBoxOfGun 认箱、扣 AmmoCount、打空清 AmmoId，扫女仆护甲+双手+背包+饰品四合一背包）——判定门一开，装填即通；
- 判据与 TACZ canReload 同口径：箱内型号必须对得上枪（9mm 箱喂不了步枪）、创造弹药箱无限、打空的箱不算——比散装「任意 tacz:ammo 都算」更严，不会「判定有弹却装填不上」；
- 顺手补齐：挑枪评分（自动装备「有弹药优先」加成）同样认弹药箱；反射软兼容，没装 TACZ 时与旧版一致。


## 实测五百六十七【空袭·法术层：用飞行武器的同时顺手放法术（需装《车万女仆：魔法》）】（PR #8，@rodericksthescriptkid 社区贡献）

- 叠加层而非新任务：三件套口径不变（鞘翅+武器+烟花），法术书放**背包或饰品栏**即可（法术模组自己扫，不看主手、不占武器位）；没装《车万女仆：魔法》时零效果；
- 只在「本来就该面向目标」的两个相位发起：远战盘旋开火前、近战已爬到目标上方正要俯冲时——吟唱期间法术模组每 tick 把她朝向拧向目标，爬升段（要背离抬头吃烟花推力）与收翅俯冲那一击刻意不施法；
- 三个开关（「主动参战」小类）：空袭顺带施法（默认开）/ 施法间隔（默认 20 tick）/ 施法距离（默认 24 格，与法术模组 maxSpellRange 一致）；隔墙不施法；
- 放哪个法术由法术模组决定（随机挑不在冷却、不在黑名单的；女仆没法力条，只受冷却限制）；
- 确认方法：看效果/特效，或 promaid.log 搜「空袭·法术」（每只 30 秒最多一条）。

**已知限制**：烈焰冲锋（ISS 的 burning_dash）这类自身冲刺法术的「指定法术」受控使用——比如让她主动用冲刺给飞行加速——本版未做；当前只会随机向目标施放不在冷却的指向型法术，作者留待下一轮。

## 实测五百六十六【客户端实体丢失（服务端照打、客户端没有她）→ 重同步兜底】（PR #10，@rodericksthescriptkid 社区贡献）

- 新增 /maid_smart resync（OP）：诊断（每只女仆的维度/坐标 + Sable sub-level 追踪位置反射探查）+ 救急（对同维度主人强制重发"删+生成+数据+装备"四包，纯补包不改服务端状态）；
- 自动兜底：女仆重新入世界 / 离场时各登记一次延迟 20 tick 的自动补包（同维度且主人在线才真补）——把"法术模组对没带锚核女仆离场只删不补 + Sable 改追踪位置"的组合失配两头都盖住；
- 离场诊断日志：女仆离开世界时记录移除原因与维度，"她为什么消失"从此有第一现场。

## 实测五百六十五【空袭召回永久禁传 → 空中让位改为有界】（PR #10，@rodericksthescriptkid 社区贡献）

- 现场实例：空袭女仆在异维度打完 BOSS 后被困，45 分钟里每 60 秒一条「飞行作战进行中…不传」，客户端连实体都没有；
- 根因："重锤跃起/飞行作战进行中不传送"的让位没有上限，而空袭女仆整个作战期间都在空中——一旦她落在远处/别的维度，这道闸就是永久禁传；
- 修法：让位改为有界——跨维度需确认主人存活且确实异维度、同维度需距离/高度确实超线，才启动 15 秒计时；超时就清干净空袭状态（收翅 + 复位本轮）后强拉回来；近处的正常让位完全不计时。


## 实测五百六十四【Sable 同装时：全图扫描被拒查 → 一大片功能静默失效 + 日志刷爆】（PR #9，@rodericksthescriptkid 社区贡献）

**现象**：装了 Sable（Create Aeronautics 的物理引擎）后 latest.log 被
「Aborting entity get for abnormally large AABB」刷爆（实测 ~1 小时 19 万条 / 500MB+）。

**根因**（Sable 2.0.5 字节码实证）：SubLevelInclusiveLevelEntityGetter#get(AABB, Consumer)
开头即 if (box.getSize() > 100000.0) { logError(box); return; }——本模组用了多年的
"有限值全世界 AABB"（±131072/±4096，getSize≈3.7e5）一个实体都不会交付。

**影响面**（在 Sable 环境里等于彻底失效，不只是刷日志）：农场锄地/骨粉催熟、钓鱼座椅走位、
指标石找女仆（含客户端预览连线）、自主战斗还原扫描、仇恨清除、中立威胁驱动、宠物免疫、
home 巡逻/走动、险境脱离、危险减益、排班扫描、搭路状态清理、蓝图背包检查。

**改法**：全图扫描统一改 level.getAllEntities()（客户端那处改 entitiesForRendering()）——
不传 AABB，同时继续绕开早期两个老坑（EntityMaid.class 桶 bug、±∞ 经 blockToSection 溢出）；
另补上原 PR 漏掉的蓝图背包检查一处（并顺带修掉它的"原点高度盒扫不到远处女仆"老毛病）。

**验证**：本地无头服 + Sable 2.0.5 A/B——旧 jar 45 秒 406 条报错、农场女仆的 till diag
诊断 0 行；修复后同场景 0 条、4 行（扫描确实重新看到了女仆）。


## 实测五百六十三【空袭 × 暮色森林孔雀羽扇：扇子当飞行燃料（起飞/爬升/盘旋补推全链路），推进与扣耐久照搬扇子原版机制】

需求原文："空袭可以兼容一下暮色森林的孔雀羽扇，也和烟花火箭一样可以起飞（起飞力度及后续使用烟花的路段
都照搬孔雀羽扇自己），每使用一次都使用孔雀羽扇自己的扣耐久机制"。

- **三件套的"燃料件"扩为【烟花 或 羽扇】**：给女仆背包放一把暮色森林孔雀羽扇（不用拿在手上），空袭照常
  激活；**有扇先用扇**，没扇才烧烟花；缺件提示同步改为「缺烟花火箭/羽扇」；
- **推进全部照搬扇子自己**（反编译 1.20.1 / 1.21.1 两版 PeacockFanItem 实证）：滑翔中一挥 =
  速度 + 视线×0.1 + (视线×2 − 速度)×0.5 + 竖直 1.25（原版滑翔助推公式）；起飞、猛击后的再起飞、
  爬升补推、远程盘旋掉高补推，全部走这条链路；
- **每挥一次按原版口径扣耐久**：hurtAndBreak(扇飞数 + 1)——身前 3 格半径 2 盒内的可推生物/掉落物/
  弹射物会被 视线×2 扇飞（扇飞数计入耐久；扇到主人/同主女仆会被「友军风免」拦下）；耐久附魔照常生效；
- **使用节奏照搬原版 getUseDuration=20**：每秒最多挥一次（烟花那条 30 tick 冷却对羽扇换成 20 tick）；
- **纯软兼容**：扇子按注册名 twilightforest:peacock_fan 识别，音效/粒子用 TF 自己的 item.fan.whoosh
  与云朵粒子；不装暮色森林时零开销、行为与旧版完全一致。没有搬 TF 的方块扇风（吹蜡烛/吹散花）——
  那是玩家手持路径的彩蛋，女仆空中挥扇不涉及。


## 实测五百六十二【工作区域回归：不跟随女仆不再"越走越远" + 潜行+中键标记工位 + 修不跟随钓鱼】

反馈原文："在【不跟随】状态下女仆并不能精准的找到自己工作区域，总是会胡乱跑动脱离我想要让她工作的工作范围……
能否添加一个标记功能，用鼠标中键标记某个地方"；以及"女仆在【不跟随】状态下不会钓鱼"。

**根因（反编译对账 TLM 1.5.3）**：TLM 原版 home 模式有一套完整的"工作区域"——限制圈（工位/休闲锚点 ± 半径）
加三重保险：任务选点逐格过滤 isWithinRestriction、出圈走位目标被清、每 2 秒物理拉回。我们此前的历次
"呆立修复 / 干活不被打断"把它拆掉了：干活时整段关掉每 2 秒的拉回与圈刷新；挖矿/伐木/宰杀用直连导航绕过
走位圈；「排班活动半径」默认放大到 32 格（原版只有 12）——于是她顺着目标越走越远，收工后又因出圈被
传送回工位，观感就是"乱跑 + 闪回"。钓鱼同根：home 模式下原版只认"限制圈内"的椅子/坐垫，我们的自动
坐垫按"离女仆最近的水"找点（常在圈外）→ 原版拒收 + 走向目标被清 → 60 秒弃疗循环，所以"跟随才会钓鱼"。

**工作区域回归（两树同步）**：
- 挖矿/伐木/宰杀的任务选点（全量扫描、缓存轮、连锁队列、宰杀索敌、闲逛点）全部加"工作圈钳制"——
  home 模式下只认限制圈内的目标（与 TLM 原生任务同口径）；跟随/战斗模式不受影响；
- home 模式下挖矿/伐木的"锚点滑动迁移"停用（它正是"追出去半个地图"的源头）；女仆被推/打飞出圈时，
  重埋锚点落在圈心而不是脚下；
- 干活期间限制圈照常每 2 秒刷新（圈心跟随当前活动），只免掉出圈时的硬拽/传送——收工后由原版拉回兜底；
- 「排班活动半径」默认 32 → **12**（回归 TLM 原版量级；旧档一次性自动迁移，手动设过 32 的不动）——
  32 变成明确的大范围选项，随时调回；
- 巡逻/工作驱动的锚点兜底链去掉"当前位置"这层（旧兜底会让巡逻中心跟着人漂移）；
- **修：跟随模式下空闲散步整段失效**——"是否受限"的判定对 TLM 女仆实体不成立（半径恒为 8、圈心是零点），
  改为按 home 模式判定。

**新增：工位标记（潜行 + 鼠标中键）**：对着一个方块**潜行 + 中键**，即可把身边 32 格内所有自家"在家模式"
（不跟随/排班中）女仆的工作区域标到那里——工位/休闲锚点立刻生效，任务选点、散步、巡逻都会收进这个圈。
想让她们守农场：站在农场开排班，或潜行+中键农场中心。不潜行的中键照旧是原版取方块，不受影响。

**修：不跟随状态不会钓鱼**：自动坐垫在 home 模式下只在"工作区域内"找水坐；圈外不再生成走不到的远水坐垫
（旧行为是生成 → 走向被清 → 60 秒后"路走不通"弃疗，无限循环），改为提示主人"潜行+中键水边，把工作区域
标过去"；跟随模式照旧大范围找水。


## 实测五百六十一【修：点「保存并返回」卡死 / 下次进游戏卡在 mod 加载界面（配置自触发写盘风暴）】

反馈原文："promaid 配置书在最新版也开始不稳定，一旦点保存有大概率导致游戏崩溃，然后再次进入时
mc 卡在 mod 加载页面，触发了两次卡死，退回到 1.10 版本恢复正常。"

**根因（不是配置书本身，是配置的写盘时机）**：1.2.0 起 NeoForge 侧在收到配置事件后多做了一次
显式 `save()`（当时是为了让默认值迁移落盘）。而 NeoForge 用文件监听器盯着 `config/*.toml`：

```
我们事件里 save()  →  文件被写  →  监听器触发  →  又发一次 ModConfigEvent.Reloading
   ↑                                                                      │
   └──────────────────────  处理器再 save()  ←───────────────────────────┘
```

**实测复现**（NeoForge 专用服务器，外部把 `config/promaid-common.toml` 改一次）：
20 秒内该文件被重写 **38 次**（约 2 次/秒，停不下来），并留下**截断的**
`promaid-common.new.tmp.toml`（16 KB 半截文件，写盘被下一次写盘打断）。

两个症状由此完全对得上：

- **点「保存并返回」= 一次写盘 → 风暴起来 → 客户端卡死/崩**（"一保存就崩、大概率高"）；
- **下次进游戏时 NeoForge 发现旧键要修正**（日志里的
  `Configuration file ... is not correct. Correcting`——玩家 toml 里残留着 1.2.0 删掉的
  `build.realGhostBlocks / ghostBlockCap / placementRange`，这类修正本身也要写盘）
  → 同样踩进风暴 → **卡在 mod 加载界面**，且每次重开都会重演。

**修法**：配置事件处理里**一个字节都不写**（只记录 ModConfig 引用），并加了一道
`inConfigEvent` 闸——事件回调期间任何落盘请求一律拒绝，防止以后有人再加回来。
默认值迁移改由**服务端启动时**跑一次（本来就有这条兜底链路），且**只在真的改过值时才落盘一次**；
那一次在配置回调之外，监听器触发的 Reloading 进来只会记个引用，风暴断掉。

**验证**（同一套复现脚本、同一台机器）：

| | 修前 | 修后 |
| --- | --- | --- |
| 外部改一次配置后 20 秒内文件被重写次数 | **38** | **0** |
| 残留截断的 .new.tmp.toml | 有（16 KB） | 无 |

两树同步修改（Forge 侧原本没写盘，一并收紧到同一口径）；两个专用服务器回归照常 PASS。

## 实测五百六十【友军风免：女仆的法术 / 风弹不再震开主人与同主女仆】

反馈原文："玩家和其他女仆免疫女仆释放的风暴/风弹效果，不会被震开。当前版本免疫伤害，但是会被震风。
导致从高空攻击的时候会直接把主人也打到空中。"

**伤害早就免了，漏的是击退**：主人免伤有本模组的「主人/友军免伤总闸」，《万法皆通》自己也有
盟友判定——两条都在攻击 / 受伤 / 结算三层把"女仆→友军"的伤害取消掉了。但击退**不是伤害事件**：

- 原版 `Explosion.explode()` 在实体循环里先 `hurt()`（被上面两层拦掉），随后**无条件**执行
  `entity.setDeltaMovement(旧速度 + 击退向量)`——伤害结算返回 false 也照推不误。铁魔法的火球
  （`MagicFireball`）正是**用女仆本人当爆炸来源**构造的原版爆炸，所以"女仆在高空打、火球在主人
  脚边炸"就会把主人顶上天，与反馈完全吻合。
- 铁魔法「呼啸之风」（`GustCollider`）更彻底：一次伤害都不发，直接给对方
  `setDeltaMovement(旧速度 + 推力)`，所以三层免伤防护对它完全无效。

**做法**：不去逐个模组打补丁（写死第三方类名 = 无底洞），而是抓住所有外力位移的**唯一出口**
`Entity.setDeltaMovement(Vec3)`（各重载最终都汇到这里），再解决**归因**——"这一下是谁推的"：
新增"当前正在 tick 的实体"记录（`Entity.tick` 的 HEAD），而法术 / 风弹 / 火球推人时调用栈必定
围着效果实体自己的 tick（铁魔法在自己的 tick 里射线命中后推、火球在自己的 tick 里爆炸、瞬发范围
法术在女仆本人的 tick 里结算、风弹 collider 由法书在施法瞬间手动 tick 也在这条链上），
于是推人者 = 那个实体本身是女仆、或它的主人是女仆（投射物 / 召唤物 / 载具）。
爆炸另有一条独立归因（`Explosion` 的直系 / 间系来源），第三方模组的爆炸也照这条走。

**判据三条**：① 推人者是女仆方、且不是她自己（她自己的烟花推进 / 风弹自起跳一字不改）；
② 受害者是玩家或女仆、且与她友军（优先用《万法皆通》自己的盟友口径，保证与它对伤害的判定一致；
没装则用本模组口径）；③ 只拦**明显的外力位移**（速度变化 ≥ 0.2 格/tick，走路 / 重力 / 互相挤开
都远小于它）。

**对主人手感的额外一层**：爆炸对玩家有两条施加通道——服务端改速度，以及把击退向量塞进爆炸包让
**客户端自己推自己的玩家**。所以除了拦服务端那一下，还会在发包前把友军从"受击玩家击退表"里剔掉，
否则本地仍会被"推一下、再被服务器拉回"。两条通道都在服务端处理，客户端不掺和。

配置：`combat.friendlyWindImmune`（战斗与自保 → 单兵战术 → 友军风免，默认开）。

## 实测五百五十九【万法皆通（法术附属）：法术模式的自动换武器 / 自主参战收紧】

《车万女仆：万法皆通》（`touhou_little_maid_spell`，前置 铁魔法 与 新生魔艺）给女仆加了
「近战法术 / 远程法术」两个任务。查兼容时发现一件关键事实：

**这两个任务的 `isWeapon(maid, stack)` 恒返回 true**（javap 反汇编实证：方法体只有
`iconst_1; ireturn`）。而本模组所有"武器"判定都走"任务自带判据"，于是对这两个任务等于
**万物皆武器**：

- **自动换武器**：主手空/快坏时会把背包里**最高 DPS 的冷兵器**（剑/斧）塞进法术模式的主手；
- **自主参战**：法术任务只凭"背包里有任意一件非原版物品"就进候选池（实测三百七十九的兜底）——
  等于"带个模组食物也算会用魔法"。

### 收紧规则（本次改动）

1. 自动换武器遇到法术任务时：**她得真的带着法术装备**（法术书/法器在主手、副手、背包或饰品栏，
   或者附属数据里已经有她的法术书）才开放切换；没带 → **一次都不换**，绝不往法术模式塞冷兵器；
2. 换也**只换法术装备**（附属各 provider 认的法术书/法器）——mod 武器优先，按 附魔 > 耐久 择优；
   主手已经是法术装备则不换（尊重玩家搭配）；
3. 自主参战的法术任务改用同一道闸门（不再只看"有没有非原版物品"）：不会用法的女仆不会被切到
   法术任务上；
4. 其它模组战斗任务（拔刀剑/史诗战斗等）**口径完全不变**，照旧走任务自带的 isWeapon。

### 实现口径

新增软兼容层 `MaidSpellCompat`（与 `GunCompat` 同一套路）：**全反射 + 一次性缓存**，
附属没装 / 版本不符时所有判定恒 false、行为与旧版完全一致——本模组依旧只把 TLM 当硬前置，
不为任何第三方做编译期硬链接。"会用魔法"的判据用附属自己的公开 API：
`SpellBookManager.getLoadedMods/getProvider` + `ISpellBookProvider.isSpellBook` 认法术装备，
`MaidIronsSpellData/MaidArsNouveauSpellData.get(uuid).getSpellBooks()` 认附属数据里的法术书。

### 另外两处的兼容结论（本次未改动）

- **自主参战**：法术系任务已被识别为"远程"（按 namespace 判定），本次只补了上面那道闸门；
- **近战/远程空袭**：空袭的"武器位"仍是本模组自己的近战/远程武器判据，**不会**把法术装备算作武器——
  所以"只会法术"的女仆目前**不会**进入空袭模式（三件套永远差武器位）。要让空袭途中也能放法术，
  需要单独做一层"空袭法术"（把施法挂进飞行行为的节奏里），不属于本次收紧范围。

1.20.1 与 1.21.1 两树同步。

## 实测五百五十八【排班表和游戏时间差 6 小时：深夜在加班、白天在睡觉】

反馈：「排班表和游戏时间不一致，深夜在加班，白天在睡觉」。

### 根因：整张表的时钟比游戏挂钟早 6 小时

原版 Minecraft 的 `dayTime = 0` 是**日出 06:00**，不是午夜（`/time set midnight` = 18000 即证；
TLM 自己显示游戏时间用的也是 `dayTime/1000 + 6` 小时，反编译实证）。而排班表的换算
`分钟 = dayTime % 24000 × 3 ÷ 50` 直接把 dayTime 0 当成了 00:00 —— 于是**整张表比挂钟早 6 小时**：
你按挂钟填的「12:00~16:00 农场」实际跑在傍晚 18:00~22:00，「06:00~14:00 睡觉」实际睡到晚上——
观感就是"深夜在加班、白天在睡觉"。

### 修法

- **时钟补 6 小时偏移**（6000 tick）：现在 00:00 = 游戏午夜、06:00 = 日出、12:00 = 正午、
  18:00 = 日落——与 TLM 显示的游戏时间、F3 的时钟完全一致；
- **班次窗口跟着重锚**（旧窗口也是按"日出=0 点"排的）：早班 = **06:00~18:00**、
  晚班 = **18:00~06:00**（跨午夜，6 个槽的下半段落在 0:00~6:00）、全天 = 00:00~24:00；
  这样早班/晚班与 TLM 自家的 DAY（夜里睡觉）/ NIGHT（白天睡觉）作息正好重合；
- **服务端与客户端共用一份实现**：手册里的"当前时段高亮"、槽位标签、调度器决策全部走
  `ScheduleData`（旧版客户端自己抄了一份 dayTime 换算——两份实现不一致正是这类问题的温床）；
- 已存的日程**不做换算**：同一张表在新口径下就是"挂在挂钟上的那个时段"，正是修复的目的。

1.20.1 与 1.21.1 两树同步；时钟锚点、三个班次的槽窗口、跨午夜命中与"休息时段不排段"
都用公式镜像逐一验过。

## 实测五百五十七【建造默认速度改回 ×1；建完进度 HUD 不消失；进度到不了 100%】

三条都是实测反馈：「建造的默认速度应该改为 ×1，现在是极速」「建造完成之后，左上角的 GUI 不会
消失」（截图停在 80,445 / 80,446 = 99%）。

### 一、默认速度回到 ×1（不再一上来就是极速）

- `build.speedTier` 默认 **x1.5 → x1**；`build.turbo`（极速模式，放置冷却归零、吃满服务器上限）
  默认 **开 → 关**。旧默认下新装的档一开建就是上千块/秒，既看不出建造过程也白烧性能。
**旧档一次性迁移**：用一条**内部标记**（`build.speedMigrated`，跑一次就置位）来判定"只做一次"，
  而不是"值 == 旧默认"——实测玩家 toml 里的真实组合是 `speedTier = "x1" + turbo = true`
  （档位早就被切到 x1、只剩极速还开着），只凭值分不出"旧默认留下的 true"和"玩家自己打开的 true"。
  第一次进游戏后极速会被关掉（档位若是 x1.5 则一并归到 ×1），**之后你想开极速随时开、不会再被改回去**。

### 二、建造完成后左上角进度 HUD 不消失（根因：服务端不再推送，客户端就一直留着最后一帧）

- 进度 HUD 是**客户端拿服务端每秒推送的快照画的**；而服务端在"没有进行中计划"时旧版是**直接
  return、一个包都不发**——计划一完成/取消，客户端永远收不到"清空"，最后那一帧（实测卡在 99%）
  就挂在左上角直到退出游戏。
- 修法两道：① **计划清空时补发一次空快照**（客户端据此立刻清屏）；② 客户端加 **5 秒看门狗**
  ——超过 5 秒没收到任何快照（丢包 / 服务端广播异常 / 切世界重连）就本地清屏，HUD 不允许永久挂着。

### 三、进度卡在 99%（最后那一格）

- 蓝图盖在**已有地形**上时，"开工那一刻就已经是目标方块"的格子旧版**只前进游标、不计数**，
  于是她把该放的都放完了，进度仍差最后几格（截图里的 99% 就是这一格）。
- 现在这类格子**单独计数**（`prebuiltCount`）并计入 HUD 与手册进度条；为防一个格子算两遍，
  真放上去时把它从 prebuilt 里摘掉（两套计数互斥）。**完成判定（缺口扫描那套）口径不变**
  ——仍然只按"她真放的"算，所以"缺口补建"行为一个字节没动。

1.20.1 与 1.21.1 两树同步。

## 实测五百五十六【建造：预览/落点回退旧版（只留"区块内箱子取料"）+ 建造瞬移限频减半】

反馈：「建造功能回退旧版本，关于新版本的改造只保留一个可以从箱子里拿的功能，我发现在用新的
方式以后反而渲染不出方块了。而且 bug 也很多。」另外「将代码里建造女仆传送到要搭建的方块
旁边的间隔减半，移动区块方面的全部都按照旧版本」。

### 一、回退：投影与落点全部回到旧版

- 投影回到**彩色填充盒**（旧的填充盒 + 棱线：近处实心、远处线框那一套），服务端点云也回到
  「只发坐标」格式（去掉调色板段）——真方块渲染这条路整段撤销；
- 金色预览框回到**跟着玩家走**：点「建造此图纸」开预览 → 退出手册走位选点 → 再打开手册点
  第二下弹确认框（旧的两次点击流程），落点 = 你确认那一刻站的位置；「就地建」的快捷手感因此
  自动回归；
- 删掉「落点微调」界面（`BuildPlacementScreen`）、G 键位、方向键操控、`SelectBlueprintPacket`
  里的落点字段与服务端那套「离玩家 ≤ 32 格 / 区块已加载」校验，以及配套的三个配置项
  （投影真方块 / 投影每帧上限 / 落点微调范围）。

### 二、保留：从建造区块内的箱子取料

缺料 → 女仆去**建造区块内（外扩 4 格）**的箱子 / 木桶 / 潜影箱取那种材料：走过去 → 开箱
（盖子会动）→ 取一部分（背包塞不下的还回原槽）→ 关箱 → 回工地继续盖；末影箱不翻、区块外的
箱子不去。开建前算材料也把箱子里的算进去。配置项与手册里那一段都保留。

### 三、建造瞬移限频减半

「放置前把女仆瞬移到目标格旁」的限频 **4 tick → 2 tick**（`MaidBuildBehavior.TELEPORT_MIN_INTERVAL`）：
摆放连着出时瞬移跟得上每一次落块；瞬移前的判据（安全站立格、已在该格 2 格内不瞬移）与
「找不到安全站姿就隔空放置」的兜底都不变。

### 四、空袭：鞘翅取用优先级 + 飞坏自动补装（承五百五十五）

- 背包里**同时**有普通鞘翅与"鞘翅胸甲"这类装备时，**优先穿带护甲的那件**（既滑翔又当护甲）；
  没有护甲型才退回普通鞘翅；胸甲槽已经穿着其中任意一件时**不换**；
- 鞘翅飞坏/耗尽（原版每 20 tick 掉一点耐久，耗尽即消失）后**自动从背包再拿一件穿上**——
  「补齐三件套」那条链路在空袭任务下每 tick 都在跑，胸甲槽一空就补位；
  背包没有备用鞘翅时她**不会**凭空续航（原版滑翔闸门要求胸甲槽里有可滑翔物品），会滑翔落地；
- 每次换装写一行运行日志「空袭装备 · 胸甲槽换装：<新>（原 <旧>）」（40 tick 节流），
  想确认"到底换没换"看日志即可。

## 实测五百五十五【空袭：模组里"内置鞘翅的装备"（鞘翅胸甲这类）现在也认了】

反馈：「在我的整合包里女仆不会把内置了鞘翅的装备视为有鞘翅（如鞘翅胸甲）」。

**原因**：三件套的"鞘翅位"旧判据写死成 `stack.getItem() instanceof ElytraItem`——只认原版鞘翅
物品。而模组里这类装备基本都不是 `ElytraItem` 的子类，而是**护甲物品 + 重写滑翔钩子**，
于是被当成"没有鞘翅" → 三件套永远不齐 → 空袭模式不激活，还会一直播报"缺鞘翅"；
更糟的是"补齐三件套"那一步会去找背包里的原版鞘翅、把玩家给她穿的这件胸甲**换下来塞回背包**
（等于把护甲扒了）。

**改法**：判据换成 `ItemStack.canElytraFly(实体)`（Forge/NeoForge 扩展方法）。选它是因为
**口径完全同源**——原版滑翔的唯一闸门 `LivingEntity.updateFallFlying`（aiStep 内、travel 之前）
在 Forge/NeoForge 里读的就是这个方法（反编译实证：字节码里依次调用
`ItemStack.canElytraFly` 与 `ItemStack.elytraFlightTick`，**没有任何原版物品判定**；
原版 `ElytraItem` 自己实现的 `canElytraFly` 恰好就是 `ElytraItem.isFlyEnabled`，与旧判据等价）。
所以"她能不能滑翔"与"我们认不认这件装备"从此是同一个判据：
凡是**对玩家能滑翔**的物品，女仆一律认得，不会出现"我们认了但原版每 tick 把滑翔位清掉"。

- 受影响的三处判定全部走新口径：`hasElytra`（三件套检查 / 缺件播报）、`equip`（穿脱，
  **胸甲槽已有这类装备时原地不动**）、以及 `isModeActive`；
- **渲染层保持严格口径**（只认原版鞘翅）——鞘翅胸甲自带模型，再叠一层我们的翅膀只会穿模；
  原版自己的 `ElytraLayer` 同样只认 `Items.ELYTRA`；
- **新增诊断**：缺鞘翅时往运行日志写一行「空袭装备 · 缺鞘翅（鞘翅判定: 胸甲=<物品id>
  (原版鞘翅=false，canElytraFly=true/false) 主手=… 副手=…）」（与气泡同一节流，最多 15 秒一行）。
  看这一行就能分清是"我们没认"还是"那个物品压根没实现滑翔钩子"——后者对玩家同样滑不起来，
  该找的是那个模组（`canElytraFly` 与 `elytraFlightTick` 两个钩子都得有，Forge 给
  `elytraFlightTick` 的默认实现是 `false`，只重写一个滑不起来）；
- **取用优先级**（同一条的补充）：背包里同时有普通鞘翅和"鞘翅胸甲"这类装备时优先穿带护甲的
  那件；胸甲槽已穿着任意一件时不换。**鞘翅飞坏/耗尽后会自动从背包再拿一件穿上**（空袭任务下
  「补齐三件套」每 tick 都在跑），包里没有备用鞘翅才会落地；每次换装写一行运行日志
  「空袭装备 · 胸甲槽换装：<新>（原 <旧>）」（40 tick 节流）；
- 手册「空袭与飞行作战 → 三件套」的鞘翅那一条补了这句兼容说明。

1.20.1 与 1.21.1 两树同步。

## 实测五百五十四【落点微调改版：点「建造此图纸」直接弹界面，方向键搬区块】
> **本条已整体回退（实测五百五十六）**：落点微调界面、方向键操控、G 键位全部删除，落点回到
> 「点建造此图纸时以玩家为中心、跟着人走」的旧做法。下面这段仅作记录。


玩家反馈「微调界面按 G 键触发感觉不是很好」，要的是：点建造该建筑就跳出界面、区块就地产生，
然后直接按 ←↑→↓ 移动建筑——这四个键此时不接管移动，而是接管区块的移动。按这个改完了。

- **入口改了**：手册里点「建造此图纸」不再要点两次、也不再需要 G 键——一下就把「落点微调」
  界面顶出来，金色框同时定在你点那一下的脚下格（青色幽灵 / 真方块投影同帧就位）；
- **键盘驱动**：`←→` 走 X、`↑↓` 走 Z、`PgUp/PgDn` 调高度 Y，按住 `Shift` 一次 8 格；
  `Q`/`E` 转向（界面外照旧用 Z 键）、`R` 回到脚下、`回车` 确认建造、`Esc` 取消；
  按住可以连发（原版屏幕本来就收 GLFW 的重复按键事件）；
- **这四个键不会挪你**：原版 `KeyboardHandler` 在屏幕打开时**直接跳过**按键绑定更新
  （字节码实证：`screen != null` 时整段 `KeyMapping.set/click` 被跳过），所以 ←↑→↓ 只挪区块；
  顺带也挡住了误点方块 / 误攻击——这也是用界面而不是纯 HUD 的原因；
- **看得见才算能用**：面板只占**屏幕顶部一条**（98 px：图纸名 / 落点 / 占地 / 朝向 + 键位提示
  + 两排备用按钮），并**覆盖掉原版的全屏暗底**（`renderBackground` 置空）——挪的时候能一直看清
  世界里的金色框与投影跟着动。按钮仍在（鼠标党可用），键位都写在按钮上，不用背；
- **挪远了也知道在哪**：顶栏实时显示落点**离你多少格**，超过 32 格直接标红提醒（服务端会拒绝这种落点）。
- **确认仍是两步**：「确认建造」先弹一次原版确认框（落点 / 占地 / 朝向 / 离你多少格 + 会摧毁
  区块内障碍物），确认才发包；反悔点「再挪挪」直接回微调界面，落点与朝向不丢；
- **删掉 G 键位**：原来那条 `key.promaid.build_placement` 从原版按键设置里消失
  （`options.txt` 里可能残留一行失效配置，无害；`key.promaid.build_rotate` = Z 不变）。

服务端协议与校验（落点离玩家 ≤ `build.placementRange` 默认 32 格、区块已加载、重叠检查）
原样不动；实测五百五十三的真方块投影预览与「区块内容器取料」不受影响。

## 实测五百五十三【建造三件套：预览改真方块 / 落点固定 + 微调界面 / 从区块内的箱子取材料】
> **本条的第一、二部分已在实测五百五十六整体回退**（真方块投影渲染不出来、落点微调那一套 bug 多）：
> 投影回到彩色填充盒、金色框回到跟着玩家走、微调界面与 G 键位删除。**第三部分「区块内箱子取料」保留**。
> 下面第一、二节保留原样，作为当时的记录。


参照 [车万重工] TLM-Builder 的三处做法（只借思路，代码自己写）。三件事都做完并已部署。

### 一、投影预览改成"真方块"（不再是彩色填充盒）

以前幽灵投影是**轴对齐填充盒**（服务端只发坐标，客户端用 DebugRenderer 画盒子），
只能看出体量看不出材质。现在：

- 服务端点云格式改成 `<点>|<调色板>` 两段：点里带**调色板下标**（base36，1~2 字符），
  调色板按方块种类去重（`i~方块id~方块状态`）——同带宽只多 1~2 字符/点；
- 客户端按调色板还原 `BlockState`（走原版 `BlockStateParser`，**楼梯朝向/半砖/含水都还原**），
  用**原版烘焙模型**半透明绘制（alpha×0.6、RGB 略压暗，同参照的 GhostVertexConsumer 做法），
  已经建好的格子不再重复画；
- 渲染层挪到半透明层之后（AFTER_TRANSLUCENT_BLOCKS），每帧上限 `build.ghostBlockCap`（默认 1500）。
- 旧格式点云仍兼容（无调色板 → 回退填充盒）；开关 `build.realGhostBlocks`（默认开）。

### 二、落点固定 + G 键微调界面（不再"框跟着人走"）
> **本条的微调界面入口已在实测五百五十四改版**：不再按 G、也不再点两次——点「建造此图纸」
> 直接弹出界面，用 ←↑→↓（Shift=8 格）/ PgUp·PgDn / Q·E 搬动区块，回车确认、Esc 取消。
> 下面这段描述的 G 键入口与「X-1 / Y+1 按钮」操作方式已作废；落点固定与服务端校验不变。


以前金色框**每帧取玩家位置**，落点 = 你确认那一刻站的地方，想挪半格只能自己走位。现在：

- 打开预览时**定住落点**（= 点那一下的脚下格），之后不再跟着你动；
- 按 **G**（原版按键设置可改）打开**「落点微调」**界面：`X-1/X+1/Y-1/Y+1/Z-1/Z+1`
  （按住 Shift 步进 8 格）、`左转/右转`（每次 90°，Z 键照旧可用）、`回到脚下`、
  `确认建造`、`取消`——界面不暂停游戏，挪的时候能直接看世界里的金框与真方块投影；
- 点两次"建造此图纸"的**就地建快捷方式保留**（只是落点改为那一下的脚下格，不再漂移）；
- 协议带上落点：服务端校验「离玩家 ≤ `build.placementRange`（默认 32 格）」「区块已加载」
  后才建（重叠检查沿用原有逻辑）。

### 三、从**建造区块内**的箱子 / 潜影箱取材料（女仆会走过去并开箱）

以前材料只认"女仆背包 + 主人背包"，箱子里的东西不算也不去拿。现在：

- 新增取料行为（注册在建筑任务，优先级高于建造）：**计划里缺某种料**、且**建造区块
  （外扩 `build.chestSearchMargin`，默认 4 格）里的容器装着这种料**时，女仆会：
  解除"建造中静止" → 走到容器旁 → **开箱动画**（原版 `blockEvent`，箱子/桶/潜影箱的盖子都会动）
  → 取 `build.chestFetchPerTake`（默认 8）个（背包塞不下的**还回原槽**）→ 关箱 → 回工地继续盖；
- 容器识别用 `BlockEntity instanceof Container`：箱子、陷阱箱、桶、潜影箱、各类模组容器
  全覆盖；**末影箱天然不含 Container**，不会被翻；
- 找不到容器时行为不介入——缺料提示与延后重试仍是原逻辑（`build.fetchFromChests` 默认开，
  两趟取料之间有 `build.chestFetchCooldown`（默认 60 tick）冷却，防"箱子锁着/取不到"来回跑）；
- **开建预检也算上箱子**：材料全放在区块内的箱子里也能正常开建，不再误报"材料不足"。

### 验证

两树编译零错；jar 重建（1.20.1 = 9354824，1.21.1 = 9384700，新类已入包核对）；
Forge 1.20.1 与 NeoForge 1.21.1 专用服务器回归均 PASS；已部署两个客户端实例与 pack1201 服务器。
行为面（预览观感、微调手感、女仆走去开箱取料）待实测确认。

## 实测五百五十二【回血资源判定太窄：包里有食物（金胡萝卜/模组料理）却判成"没有"】

### 先纠错：五百五十一改错了地方

五百五十一 把搭高的门槛从"必须有回血资源"改成了"有方块就搭"——**这个改法是错的，已回退**。
没得回血爬上去确实没有意义，门槛就该是回血资源。也就是说：门槛是对的，错的是**回血资源的判定**。

### 决定性证据（五百五十一 新加的「自保诊断」日志）

```
血 16%  距威胁 1.7 格（贴身线 4.0 格） | 回血资源=无  可搭方块=有
血 65%  距威胁 3.7 格                 | 回血资源=无  可搭方块=有
血 65%  距威胁 4.8 格                 | 回血资源=无  可搭方块=有
```

威胁一直在贴身范围内（搭高分支进得去）、背包里有方块，但"回血资源=无"——而实际包里有食物。
原因：旧判定只认 **药水 / 金苹果 / 一小撮硬编码原版食物**（熟肉、面包、苹果…），
**金胡萝卜、各类模组料理一律不认**（而玩家喂给女仆的正是金胡萝卜）。

### 改法

- 回血资源判定改成与投喂系统**同一个口径**：`EmotionalActionExecutor.isFeedableFood`
  = TLM 自己的 `DefaultMaidHealSelfMeal.isHealMeal` 口径（**有食物属性且不在投喂黑名单里**）——
  任何"能吃的东西"都算回血资源；金苹果保留单独判定（它在投喂黑名单里刻意让给"低血即时增益"路径，
  但作为回血资源必须算）；
- **门槛、上限、塔顶处理全部回退**到五百五十一 之前（无回血资源不搭高；垫到 pillarMax；
  塔顶围困只清计数不主动下塔）；
- 「自保诊断」日志升级：写出**认到的那个物品名**（`回血资源=minecraft:golden_carrot`），
  以后判定再出问题一眼就能看出来。

### 验证

两树编译零错；重建 jar 并部署到两个客户端实例与 pack1201 服务器；双服务器回归均 PASS。

## 实测五百五十一【搭高的门槛压在"有没有带药"上——包里一堆方块也一块不搭】

> **本条的门槛改法已在实测五百五十二推翻并回退**：门槛（必须有回血资源）本身是对的，
> 真正的问题是"回血资源的判定太窄"（金胡萝卜/模组料理都认不出来），已改为通用食物判定。
> 下面这段保留原样，作为当时的排查记录。

### 现象

五百五十那道取料闸口修好、部署进游戏后，实测**仍然一块方块都不搭**，也不播报
"背包里没有搭方块的材料"。日志把范围缩小到一句话：整场自保只有一句
「情况不妙，我小心周旋！」，运行日志里**一行「自保搭高」都没有**——
说明搭高分支根本没进去，问题不在取料闸口，而在它前面的门槛。

### 根因：实测三百六十五那条"没回血资源就不搭"的口径

原口径是：包里没有药水/金苹果/治疗食物 → **搭高不再作为可选项**，被近身只做小幅走位。
理由（当时的反馈）是"塔的唯一意义是安全回血，没得回血垫塔纯属干耗"。

问题在于它把两件事绑在了一起：
- **能不能搭** 取决于包里有没有方块；
- **上去以后干什么** 才取决于有没有回血资源。

于是一个背着几组方块、只带武器（或只带金胡萝卜这类不在"治疗食物"名单里的食物）
的女仆，被怪按在地上打时，一块都不搭——正是"宁愿被打到死"。

顺带查出一条死链：塔顶无回血资源时，那条"围困满 10 秒"的处理在实测三百九十把
围困传送停用之后**只剩 `heallessSiegeTicks = 0` 这个空壳**——什么也不做。所以
"上去也是干耗"确实成立，只不过当初的解决办法是"干脆别上去"，这次改成"上去、
待不住就下来"。

### 改法

1. **搭高门槛改成材料**：`hasBuildBlock(maid)`（背包里有可搭方块）取代
   `hasHealResource(maid)` 作为搭高的前置——branch 2（连续被近身后的爆发搭高）
   与 branch 4（被近身垫到安全高度）都改。
2. **上限分流**：有回血资源 → 照旧垫到 `pillarMax`（塔顶守势安心回血）；
   没有回血资源 → 只垫到 `safePillarHeight`（默认 5 格，够不着就行），
   不再一路垫到 30 格站桩。
3. **塔顶不再干耗**：塔顶 + 威胁仍在 + 包里没有回血资源，围困满 10 秒 → 置位
   `towerDescendRequest`，branch 4 消费它清掉塔位状态下塔，回地面继续打；
   再被近身会重新垫上去（"打不过就上去躲、躲不成就下来打"）。
4. **决策快照日志**（本轮新增，为了不再靠猜）：每场自保第一次锁定威胁时写一行
   「自保诊断」——血 20% 距威胁 3.2 格（贴身线 4.0 格）| 回血资源=无 可搭方块=有。
   运行日志搜「自保诊断」。以后再出现"她怎么不搭方块"，一行就能看出卡在哪道门槛。

### 验证

两树编译零错；重建 jar 并部署到两个客户端实例与 pack1201 服务器；
Forge 1.20.1 与 NeoForge 1.21.1 专用服务器回归均 PASS。
行为面（她真的开始搭方块）待实测确认——若仍不搭，把「自保诊断」那一行发回即可定位。

## 实测五百五十【悬空禁搭把"她自己一跳"也判成了悬空——被围殴时不再搭方块自保】

### 现象

被怪围住时她不再往脚下垫方块自保，也不吭声，原地被磨死。连"背包里没有搭方块的材料"
那个气泡都没有——因为那个气泡在"悬空"时是**特意静默**的，于是整条搭高链路堵死时
一个字都留不下（实测四百四十三当时的设计本意是防误报，副作用就是这种静默失败）。

### 根因：四百九十八那次收紧的又一处误伤

四百九十八把"悬空禁搭"的口径从"坠落 ≥ 落地水触发高度"收紧成了"只要 `fallDistance > 0`"。
当时想拦的是滑翔与真正的高空悬空，但这一条把**她自己在战斗里的小跳**也算进去了：
战术跳劈、走位跨台阶、被击退，都会让她离地一格再落回来，落地前那几 tick
`fallDistance` 是正数 → 判定为悬空 → `takeBuildBlock` 返回 `null` → 搭高一块都放不下。
搭高自己的"放块 → 被顶起 → 落回"也是同一类 tick，等于她一边被围殴、
一边每次想搭方块都被自己的动作否决。

同一处收紧此前已经撞出一例（实测五百零九：岩浆里垫方块自救被禁搭误伤），
这次是它的第二类误伤——根都在"把下落当悬空"这个口径上。

### 改法

"悬空"回到它的字面意思：**脚下没有地**。判据从"是否正在下落"换成
"脚下 3 格内有没有可站立面"（用 `isFaceSturdy(level, pos, UP)`，台阶/楼梯/栅栏这类
"顶面能站人、但不是整块实心"的方块也算落点，免得站在台阶边跳一下就被误判）。
四百九十八要拦的一件没丢：

| 情形 | 判据 | 结果 |
| --- | --- | --- |
| 滑翔 / 飞行作战空中 | `MaidFlightKit.isFlightAirborne` | 禁（原样保留，这是四百九十八的主漏口） |
| 1.21.1 重锤跃起中 | `MaidMaceSmashBehavior.isAirborne` | 禁（原样保留） |
| 从高处掉下来 | `fallDistance ≥ 落地水触发高度` | 禁（恢复四百四十三的原始阈值） |
| 3~5 格浅坠、站在崖边往下跳 | 脚下 3 格内无地 | 禁（新判据天然覆盖） |
| 战斗里的小跳、被击退、搭高自身顶起 | 脚下 1 格就是地面 | **放行** |

三处照旧放行：水里、岩浆里（实测五百零九）、骑乘中。四个搭方块模块
（自保搭高 · 搭路 · 挖矿垫脚 · 伐木垫脚）共用这一道闸口，一起恢复正常。

### 附带的观测修复

自保搭高每次被拒都会往运行日志写一行原因（限频 5 秒/女仆，搜「自保搭高」）：
`悬空禁搭（脚下无地 / 滑翔飞行中）` / `目标格被主人碰撞箱占着` /
`放置格/头顶 2 格不是空气（防窒息拦下）` / `实际头顶被堵` / `背包里没有能搭的方块`。
以后再遇到"她怎么不搭方块"，一眼就能看出卡在哪一道闸口，不必再从行为链倒推。

### 验证

两树编译零错；重建 jar 并部署到两个客户端实例与测试服务器；
两个专用服务器回归均 PASS（Forge 1.20.1 / NeoForge 1.21.1，`Done` 后再盯 30 秒无延迟崩溃）。
行为面（她真的开始搭方块了）以待实测确认——本次另加了「自保搭高」被拒原因日志，
若仍有拦阻，运行日志里会直接写出是哪一道闸口。

## 实测五百四十九【1.21.1 上四个配方全都加载不了（数据包目录名与字段名漏改）；指标石在手册里找不到】

### 一、配方（只在 1.21.1 上坏）

**现象**：1.21.1 生存里合成不了指标石。顺带查出来蓝图书、药剂手册、排班表也都合不出来。

**根因**：1.21（数据包格式 48）把数据包目录名统一改成了单数——`recipes`→`recipe`、
`advancements`→`advancement`、`loot_tables`→`loot_table`、`tags/items`→`tags/item`。
移植 1.21.1 树时只改了后三者，`recipes/` 与 `tags/items/` 漏了，于是**整个目录在 1.21.1 上
根本不会被读取**：四个配方一个都不存在。另外三个老配方还留着 1.20.1 的字段名：

| 文件 | 旧写法（1.20.1） | 1.21 的正确写法 |
| --- | --- | --- |
| blueprint_book / brew_manual / schedule_book | `result.item` | `result.id` |
| schedule_book | `result.nbt` | `result.components` |

（`index_stone.json` 是后加的，字段当时就按新格式写了——但目录名一错，它同样加载不了，
所以玩家最先撞上的正是"指标石合不出来"。）

**改法**：neo 树 `data/maid_smart/recipes/` → `recipe/`、`tags/items/` → `tags/item/`；
三个老配方按 1.21 规范改字段（排班表那枚作标记用的附魔改成
`components` → `minecraft:enchantments` → `levels` → `minecraft:mending = 0`）。
**1.20.1 树不动**——复数目录 + `result.item` + `result.nbt` 才是 1.20.1 的正确写法。

**核验口径**：拿同版本的真实数据包当基准——1.21.1 侧 TLM 自己 49 个配方、灾变 210 个、
tacz 183 个、森罗物语 548 个，清一色 `recipe/` + `tags/item/` + `result.id`，而我们改前是
里面唯一的例外（`recipe`=0、`recipes`=4）；1.20.1 侧区块加载器 / 拔刀剑 / tacz / ProjectE
清一色 `recipes/` + `result.item`，与我们 1.20.1 的写法一致。

### 二、手册里找不到指标石

**现象**：手册目录和「功能总览」里都没有指标石，顺着手册读根本发现不了这个物品。

**根因**：用法文案写在「建造系统教程」章节的最末尾（那一章两页多），既没有独立标题、
也不在「功能总览」的跳转清单里——文案是有的，但等于藏起来了。

**改法**：
- 提为**独立章节**「指标石（即兴临时搭建）」，排在「建造系统教程」之后（全手册 31 → 32 章）：
  合成（9 块平滑石头 3×3 摆满）、三步用法（绿框 → 右键锁成红框 → 右击女仆绑定）、
  材料从哪来（先从她背包、不够从你背包，选数量最多且有碰撞的方块）、几条规矩
  （先锁再绑 / 同时只有一个锁定 + 一个绑定 / 换目标必须先解除 / 中断会报数收尾）、总开关位置；
- 「功能总览 · 一键跳转配置」的「生产与工作」一行加上**指标石**跳转链接，点一下直达它的配置行；
- 建造章节末尾只留一行指向该专章，不再重复正文。


## 实测五百四十八【装了「是，史蒂夫模型」(YSM) 时黑屏进不去游戏：鞘翅图层的泛型参数写死导致 ClassCastException】

### 现象

同时装本模组与「是，史蒂夫模型」(Yes Steve Model, YSM) 时，游戏能启动、能加载资源，
然后**卡在黑屏**进不去（日志里是 `Minecraft.abortResourcePackRecovery`）。

### 根因（一个 checkcast）

TLM 自带 YSM 联动：装了 YSM 时它把女仆交给 YSM 的渲染器
（`EntityMaidRenderer.initYsmModelRenderer`，字段 `ysmMaidRenderer` 的类型是
`IGeoEntityRenderer<Mob>`），并把已有 geo 图层逐个 `copy` 到那个渲染器上。

TLM 的基类是 `GeoLayerRenderer<T, R extends IGeoEntityRenderer<T>>`，`copy(R)` 的形参
就是 `R`。我们那两个图层（`LayerMaidElytraGecko` / `LayerMaidSpinAttackGecko`）把 `R`
写死成 `GeckoEntityMaidRenderer<Mob>`，泛型擦除后 javac 会生成桥接方法，里面
`checkcast GeckoEntityMaidRenderer`。而 YSM 的渲染器（`com.elfmcys.yesstevemodel.*`）
只实现了 `IGeoEntityRenderer`、继承的是 YSM 自己的类，**不是 `GeckoEntityMaidRenderer`
的子类**。于是：

```
ClassCastException: com.elfmcys.yesstevemodel.ooOoooo0o000Oo0OoOooo0oo
  cannot be cast to GeckoEntityMaidRenderer
  at com.maidsmart.client.LayerMaidElytraGecko.copy
  at TLM EntityMaidRenderer.initYsmModelRenderer
→ EntityRenderers.createEntityRenderers 整体中断（实体渲染器整批没建起来）
→ Minecraft.abortResourcePackRecovery → 黑屏
```

### 改法

1. 两个图层的 `R` 从 `GeckoEntityMaidRenderer<Mob>` **放宽为公共上界
   `IGeoEntityRenderer<Mob>`**——`copy` 的形参类型随之与擦除后的签名一致，桥接方法里的
   checkcast 直接消失；构造参数放宽为 `IGeoEntityRenderer<?>`，两个调用点（mixin）不用改。
2. `render()` 开头加 `getRenderer() instanceof GeckoEntityMaidRenderer` 守卫：走 YSM 时
   **不画**我们的鞘翅与旋转特效。本层的挂点逻辑依赖 Gecko 骨骼表
   （`AnimatedGeoModel.bones()` 里的 ElytraLocator/Elytra/UpperBody/Root），YSM 模型没有
   那套骨骼，硬画只会把翅膀堆在原点——那比不画更糟。女仆的背部物品/鞘翅在 YSM 那条链上
   由 TLM 自己的图层负责。
3. **两树同步**：1.20.1 的 TLM 1.5.3 同样带 `initYsmModelRenderer` + `ysmMaidRenderer`，
   装了 YSM 一样会崩，所以这不是 1.21.1 独有的问题。

### 验证

- 两树编译零错；重新打包后 javap 确认两个图层的类声明与 `copy` 形参都已是
  `IGeoEntityRenderer`，桥接 checkcast 消失；
- 没装 YSM 时 `getRenderer()` 必然是 Gecko 渲染器，守卫不生效，原有行为不变。

### 顺带说明（另一个"黑屏"传闻无关的坑）

把 jar 换进 `mods` 目录**必须在游戏完全退出后做**。运行中替换文件会让 ModLauncher
按旧偏移去读新文件，表现为"某个类明明在包里却 ClassNotFoundException"，同样会死在
加载阶段（实测五百四十六 那次的崩溃日志就是这种）。


## 实测五百四十七【空袭牵引绳：空袭期间离主人超出半径（默认 100 格）就立刻传送回主人身边】

### 一、"自己回不来"是怎么来的（三道路闸全对她关着）

她会飞高是机制决定的：两种空袭都是「放烟花给初速 → 爬升 → 收翅俯冲 / 空中盘旋」，一轮打完
人已经挂在几十上百格高空，而主人早就不在脚下。此前有三条"远距拉回"链路，它们**全都主动
放行空袭**：

| 链路 | 平时怎么触发 | 遇到空袭时 |
| --- | --- | --- |
| 同维度远距拉回 | 同维度、距离超过 48 格 | **不拉**（实测四百八十七 加的：怕打断扑击） |
| 跨维度跟随 | 主人换了维度 | **不传**（滑翔中不传，猛击落地后自然恢复） |
| TLM 原版 teleportToOwner | 离主人过远自动瞬移 | **被拦**（MaidTeleportPreserveMixin 在滑翔 / 飞行作战空中时直接返回 false） |

于是"飞太高、把目标打死后自己回不来"这条路径上谁都不拉她——她只能一路滑翔到落地，落点
可能在几百格外的山头上。这不是哪一处写错了，而是三条豁免叠起来的必然结果。

### 二、这一版加了什么

一句话：**空袭期间，以她为圆心、半径 N 格（默认 100）的球内找不到主人 → 立刻把她传送回
主人身边**，走的是排班表那次人工传送同一条链路（即实测五百四十六 的「强制 + 无视地块 +
可以空中传送」）。

- 新配置 **「空袭牵引绳（格）」**，默认 **100**，**填 0 = 关闭**。位置：配置面板 →
  「生存与复活 → 落地缓冲」小类（和「免疫鞘翅撞击 / 空袭免疫摔落 / 远程空袭近身弹开」放一起）。
- 距离按 **3D 距离**算（水平 + 竖直一起算）——所以"飞太高"本身就会触发：她爬到主人头顶
  100 格以上就出了球，那正是"飞太高回不来"的字面含义。
- 落点：先在主人身边 16 格内找可站立格；找不到就直接落在**主人当前所在格**（与排班表人工
  传送完全同一口径：主人飞在高空 / 悬在虚空边也照传）。
- 触发时主人会收到一条系统消息，并落一条 `[空袭牵引绳]` 运行日志（距主人多少格、半径多大）。

### 三、只在"她确实在空中"时生效

面板文案里那句"只在空中生效"不是偷懒，是刻意划的边界：

- **地面上的距离问题不归它管**——落回地面后交给"同维度拉回"那套更保守的规则（48 格，且
  守家 / 坐姿 / 骑乘 / 干活都有豁免）。否则"主人出门 100 格、空袭女仆守家站着不动"会被
  无条件拽走；
- 空中 = 空袭正在进行，这正是本条要管的窗口；
- 正因为已经有"空中"这道门，本入口**不查 home（在家）模式**：停放的语义已经被"她飞起来了"
  这件事本身打破；而我们的排班表**会自动给女仆锚定 home**，如果照抄 home 那道门，结果
  恰恰是"用了排班的那批女仆永远召不回"——正是报上来的场景；
- **主人跨维度时不抢**：那一路由跨维度跟随在本轮攻击结束后处理，在这里立刻抢会重演
  实测四百八十七「猛击被传送打断」的老问题。

### 四、实现（给日后排查用）

- 新增 `com.maidsmart.combat.MaidFlightRecall`：每 tick 的判定全在这里（是不是空袭任务 /
  她是否在空中 / 主人是否已加载且存活 / 是否同维度 / 3D 距离是否出球）。
- 新增 `MaidChunkLoadManager.recallFromFlight(女仆, 主人)`：复用现成的
  `teleportCore(女仆, 主人, force = true)`，与「一键集合 / 传送到我身边」同一条真传送链路
  （原版 teleportTo + 摔落距离归零 + 停导航 + 清速度 + 末影人音效）。
- 调用点挂在 `MaidToolAutoEquipBehavior.checkExtraStartConditions` 的飞行任务分支——
  core 行为，任何 activity、每 tick 一次。挂那里有个额外好处：本模组给所有有主活动女仆挂了
  2 级强制加载票（= 实体正常 ticking），所以哪怕她离主人几百格、区块早已出了模拟距离，
  她的 brain 照样在跑，这条牵引绳才真的"立即"。
- 反过来说：空袭行为本身要"有攻击目标"才 tick，而本条要管的恰恰是**目标已经死了之后**
  她还挂在几百格高空的那一段，所以这条判定不能写在空袭行为里。
- 失败保护：传送失败（主人实体不在已加载世界等）后 60 tick 内不重试；系统消息 10 秒最多
  一条（成功召回后她人已经在身边，不会连发）。
- 手册"飞行作战"章节与配置面板文案同步更新；那句"飞行期间禁止被传送（包括跟随拉回、一键
  集合）"现在补了一句"**唯一的例外就是空袭牵引绳**"——飞出 100 格早已超出任何扑击的有效
  范围，那一步是把她捞回来、不是打断她。



## 实测五百四十六【自动复活：去掉内置 CD、重生点不可用就强制落在主人身边；排班表传送同样强制 + 无视地块】

### 一、"卡住无法复活"是怎么来的

三样东西叠在一起：

1. 复活落点原本是「主人重生点（床/重生锚）→ **无则主世界出生点**」。出生点往往是另一个坐标
   （甚至另一个维度）的荒郊——女仆落在那儿可能立刻又死；
2. 她"复活后很快又死"会踩到 实测四百一十六 加的**死亡循环断路器**：把下次复活**推迟**
   60 秒，连续则 120 / 240 / 480 / 600 秒封顶；
3. 那个断路器的提示语写的是「已把下次复活推迟 60 秒」——而实际退避是**翻倍**的，
   玩家看到的就是"说要等 60 秒，然后一直不来"。

### 二、改法

| 位置 | 旧 | 新 |
| --- | --- | --- |
| 复活落点（重生点不可用） | 退回主世界出生点 | **强制落在主人当前所在位置**（不看地块，主人在高空/岩浆边/水底也照落） |
| 死亡循环断路器 | 硬编码退避 60→600 秒 + 那条"推迟 N 秒"的提示 | **整段删除**（不再有任何内置 CD） |
| 复活提示语 | 无论落在哪都说"正在主人重生点等你" | 按实际落点分流：落在重生点 → 原话；重生点不可用 → "重生点不可用（床被拆/重生锚没电/维度不允许），**已直接在你所在的位置复活**" |

理由：主人站的地方就是玩家自己站的地方，是这颗星球上最不会让她"一放出来又死一次"的落点；
这也是"复活到她该在的人身边"这个功能的本意。断路器删掉之后，"复活点不安全"不再被掩盖成
"等一会就好"，而是从根上不再发生。

**注意**：`复活延迟（秒）` / `复活时机（次日黎明）` 这两个**配置项保留不动**——去掉的是那个
硬编码的退避 CD，不是玩家自己设的复活延迟。（复活延迟正是"墓碑存在多久"的时长。）

### 三、排班表传送：强制 + 无视地块

`MaidChunkLoadManager.teleportCore` 原本在「主人身边 16 格内找不到可站立格」时直接**拒绝**，
于是主人飞在天上、悬在虚空/海面上时，点「传送到我身边」只会收到一句"落地后再点"。
现在给传送加了 `force` 口径：

- **人工传送走强制**（「传送到我身边」/「一键集合」以及未加载区块的自动补召回）：
  找不到可站立格就直接落在**主人当前所在格**——主人飞着她就落到空中，这正是
  "无视地块、可以空中传送"。（空袭女仆悬停/滑翔时也能被叫回来。）
- **自动路径保持非强制**（受困救援 / 同维度远距拉回）：这两条是系统自己发起的，
  仍然"宁可她走路归队，也不冒半空坠落的风险"，不受本次改动影响。
- 「**把自己传到女仆身边**」的跨维度分支原本也会因为"她脚下没找到可站立的位置"而**取消传送**
  （同维度分支早就有"退到她那一格"的兜底，跨维度漏了）——现补上同一个兜底。

顺带把几条不再成立的提示语改掉（"你身边 16 格内无可站立点（高空/虚空）——落地后再点"、
"N 名因身边无可站立点未动" → 改为状态异常的通用失败说明）。

### 验证

两树编译零错，jar 已重建并部署三个目标。本轮**没有跑行为测试**，留待进游戏实测。


## 实测五百四十五【投喂效果与"女仆自己吃"对齐：补上 TLM 那一记吃食物回血】

### 根因：TLM 的"吃食物回血"不在 eat() 里，而在**餐食系统**里

女仆自己吃食物时，回血发生在 TLM 的 `MaidHealSelfTask` → `DefaultMaidHealSelfMeal.onMaidEat`
（反编译两版同构）：

```java
// 1.20.1：total = 营养 + 营养 × 饱和度系数 × 2
// 1.21.1：total = 营养 + saturation()（那边的 saturation() 已含 ×2，两版等价）
float total = ...;
if (random.nextInt(5) < total) {          // MAX_PROBABILITY = 5
    maid.heal(Math.max(total / 5.0f, 1.0f));
}
```

**一根胡萝卜**：`nutrition=3`、`saturationModifier=0.6` → `total = 3 + 3×0.6×2 = 6.6`
→ `6.6/5 > 1` 即 **100% 触发** → 回 `6.6/5 = 1.32` 点血。

而本模组的投喂走的是**原版 `LivingEntity.eat`**（`feedSisterFood` / 蜂蜜分支都一样）——
那条路只做"食物自带效果 + 音效 + 饱食度"，**完全不经过 TLM 的餐食系统**。
也就是说：TLM 那一记回血在投喂时**整段缺失**，于是"喂胡萝卜只回了原版那点效果 /
喂蜂蜜只解了毒"，观感就是"喂食比她自己吃弱"。

### 修法：喂食后补调一次 TLM 的 HEAL_MEAL（不自己实现公式）

新增 `com.maidsmart.combat.MaidMealBridge`：走 TLM 自己的接口
（`MaidMealManager.getMaidMeals(HEAL_MEAL)` → `canMaidEat` → `onMaidEat`），于是

- 回血**公式、概率、上限、粒子、饰品（bauble）联动**全部与她自己吃**逐行同源**
  ——TLM 以后改公式我们也自动跟着变，不会再出现"两套回血口径"；
- **黑名单也自动一致**：`MaidHealMealsBlockList` / `HEAL_MEAL_REGEX` 里被禁的食物，
  喂食同样不给回血（与"她自己不吃这个"完全同一个判据）。

接入点三处：姐妹喂普通食物（`feedSisterFood`）、姐妹喂蜂蜜（蜂蜜也是食物、nutrition=6）、
即所有"喂给**女仆**"的入口。**主人链不动**——玩家走原版饥饿系统，
TLM 那记回血是女仆专属的餐食系统，套到玩家身上没有语义。

### 三个必须踩对的细节

1. **必须传快照**。反编译 `LivingEntity.eat`：末尾 `stack.shrink(1)`（`m_41774_`）。
   如果直接把 `toGive` 传给 Bridge，eat 之后它已经是**空栈** → Bridge 判空直接返回 →
   修复静默失效。所以先 `copy()` 出"喂进去的那一份"再调 eat。
2. **金苹果刻意不补**。TLM 自己吃金苹果也只走 `eat()`（`ApplyGoldenAppleEvent`，
   玩家喂她时触发），同样没有那记回血——所以投喂金苹果若补上 HEAL_MEAL 反而会
   **强于**她自己吃。现在的口径是"与她自己吃完全一致"，金苹果维持原样。
3. **失败要留痕**。若 TLM 未来改了 API（拿不到任何 HEAL_MEAL 实现），会退化成
   "只有原版 eat"的旧行为——这正是最难发现的那类静默缺失，所以加了**一次性**告警日志。

### 为什么还加了一条调试命令

"女仆喂女仆"发生在两个实体之间、不产生任何原版事件，而且互助链要求
"被喂的那只有主人、且主人在线"——**专用服务器上没有玩家，这条链结构上无法端到端触发**。
所以本次同时留了一个控制台可用的验证入口：

```
/maid_smart feedtest <itemId>        # OP；对最近一只未满血的女仆结算一次投喂并打印血量变化
```

它走的是与 `feedSisterFood` **完全相同的调用序列**（eat 快照 → eat → Bridge）；
**不消耗任何物品**（用新造的物品栈），所以它不是玩法入口，纯验证。

### 验证：新增行为级回归 `test_feed_heal.py`（两版 PASS）

```
verdict: PASS
note: Bridge 命中 HEAL_MEAL=True
note: 血量 12.00 → 13.32（+1.32）
note: 回血幅度 = 1.32（胡萝卜 total=6.6 → heal(1.32) 的 TLM 口径）
[promaid/投喂回血] FeedTestMaid 按 TLM 餐食口径结算 Carrot（DefaultMaidHealSelfMeal）：血量 12.00 → 13.32
```

`+1.32` 正是"她自己吃一根胡萝卜"的回血量——**数字对上了**，这才是"效果等同"的实证。
加上原有六项（`test_maid_load` / `test_spin_air` / `test_server` × 两版）共八项全绿。

**脚手架又踩到四个坑（都已修，留档）**：
①先造"满血女仆"再喂 → `heal()` 被原版上限吃掉 → `20.00 → 20.00` 假失败，必须先造成伤害；
②测试世界是持久化的，残留的**满血**女仆会被选成目标 → 命令改为"取存活中血量最低的那只"；
③按血量升序又选中了 **0 血的残留尸体** → 追加"只取存活"过滤；
④Brigadier 的字符串参数：`word()` 不接受冒号（`minecraft:carrot` 断在冒号）、
   `string()` 要求带引号 —— 只有 `greedyString()` 能吃下裸的物品 id。


## 实测五百四十四【激流：把空袭"收翅俯冲"那一记也换成旋转冲击（空中放行）】

### 改了什么：只开**一个**空中窗口

起手入口从两个变成三个，前两个的护栏**一条都没动**：

| 入口 | 位置 | 起手条件 |
| --- | --- | --- |
| TLM 原生近战 `MaidMeleeRiptideMixin` | 攻击模式 | 仍要求**站在地上** |
| 空袭地面近战 `groundMelee` | 空袭落地后 | 仍要求**站在地上** |
| 空袭**收翅俯冲** `smashHit` | 空袭扑击 | **允许空中**（本次新增） |

"收翅俯冲"本来就是她主动朝敌人砸下去的那一瞬，所以放行它不会碰 实测五百四十一 的护栏
（那道护栏防的是"在起跳/爬升途中横插一次突进"）。`airborne` 取的是 `!onGround()`，
所以她落地之后这一记自动退回地面规则。

### 空中与地面的三条差异（都有理由）

1. **不提前刹住**。地面那版一旦离目标 1.5 格内就把速度归零（免得"顶着怪推"）；空中照用会
   停在半空自由落体，而且 1.5 格根本够不到怪的碰撞箱 → 转一整套也不结算。空中改成只判
   "越过目标所在的那条线"，一路扫过它的碰撞箱——原版 `checkAutoSpinAttack` 的判定是
   **上一帧到本帧的包围盒并集**（扫掠），扫过去就必定结算一次，这正是玩家那记"撞上去"。
2. **重力照常**。反编译实证原版对旋转突进**没有任何**改重力/改速度的处理
   （`LivingEntity` 里 `f_20938_`/`autoSpinAttackTicks` 只出现在 `aiStep` 的递减与
   `checkAutoSpinAttack` 两处），所以空中旋转 = 一次朝敌人的冲量 + 正常抛物线。刻意不造悬停。
3. **坠落伤害由本链路兜掉**。既然重力照常、旋转又有 16 tick，她是边转边掉的；
   突进期间每 tick 把坠落距离清零（与收翅猛击同款口径），落地不自我摔伤。

### 空袭让位（这次是"收窄过"的让位）

突进那 16 tick 里，空袭**只让掉状态机**（`isDashing` 为真时提前 return，顺带收翅、压住原生近战）。
**必须让**：空袭同一 tick 会放烟花（推力沿视线）+ 开滑翔（`travel` 的滑翔分支把水平速度往视线
方向拽并限速），三套速度互相覆盖的结果是"刚起手就被冲掉，只闪一下"。
**这次不会重演 五百四十一 的"不会起飞"**：①起手时机 = 她的攻击时机（有攻击冷却 + 收招硬直，
不是按距离自主触发）；②让位有硬上限（一次旋转的时长 + 陈旧自愈）；③让位放在三件套维护与
"缺件提示"**之后**——装备照穿、缺件照报，被让掉的只有状态机本身。
配套把 `isEngaged`（"空中禁传送"的豁免）并入突进状态，免得主人一远、自动传送把她当场拽走，
白转一场。

### 顺带修的两件事

1. **1.21.1 树的常量漂移**：那份 `MaidTridentSpinBehavior` 的 `DASH_RANGE/SPIN_TICKS/RECOVER`
   还停在 实测五百三十八 那版（10/20/10），而 五百四十一 的定稿表格写的是 4/16/20——
   即 1.21.1 上仍是"从十格开外一路冲过去"的诡异口径。两树现已一致。
2. **突进状态的漏清**：`MaidTridentSpinBehavior.forget()` 定义了两版却从未接线。它现在会让
   空袭让位 + 豁免传送，残留的代价比之前大得多，已接进既有的两处统一清理点
   （登录清理 / 退图清理）——与 实测四百八十三 修滑翔位残留是同一类问题。

### 验证：新增一条**行为级**回归 `test_spin_air.py`

原有两条检查**结构上**覆盖不到本次改动（`test_maid_load.py` 只证明"女仆能被召唤出来、
mixin 没炸"；`test_server.py` 只等 `Done (`），而本次动的恰恰是 五百四十一 出过事的链路。
所以新增：`summon` 一个空袭女仆（NBT 指定任务 + 主手**激流**三叉戟 + 背包鞘翅/烟花）
+ 一只打不死的木桩，观察日志里是否**既起飞、又能空中旋转**。

```
verdict: PASS
note: 起飞=True 空中旋转=True
note: 武器上读到 riptide=True
[promaid/激流突进] SpinTestMaid 旋转冲击（空中起手，激流 3 级，力度 3.00，距离 2.9，目标 SpinTestTarget）
[promaid/飞行作战] SpinTestMaid 放烟花起飞
[promaid/激流突进] SpinTestMaid 旋转冲击（空中起手，激流 3 级，力度 1.8，目标 SpinTestTarget）
```

两版都是"起飞 ↔ 空中旋转"交替（不是卡在某一态），另加 `test_maid_load.py` /
`test_server.py` 两版 PASS，共六项全绿。

**脚手架上的三个坑（都已修，留档以免重踩）**：
①两版服务端日志编码不同（1.20.1 UTF-8 / neo GBK），且 neo 那份是 GBK 夹非法字节，
   必须 `errors='replace'` 解码——否则中文判据全部假失败，现象是"没起飞"而日志里明明有；
②两版附魔 NBT 完全不同：1.20.1 是 `tag.Enchantments`，1.21.1 是
   `components.minecraft:enchantments.levels`（`ItemEnchantments.CODEC` 优先认带 `levels` 层的形式）。
   写错时**不报错、只是没有附魔**，看起来就像"功能没生效"——已加 `data get` 回读自检；
③测试世界是持久化的，`@e[...,limit=1]` 会选中**上一轮**的女仆，选择器一律按名字限定。

### 一个待确认的点

空中旋转期间她**会掉**（这是原版语义：不抵消重力）。按现在的参数，一次 16 tick 的旋转从
起手高度掉约 6~13 格，随后空袭自己切回滑翔接住。若认为"掉得太快、看不全那几圈"，
两个可调量：`MaidTridentSpinBehavior.SPIN_TICKS`（缩短旋转）或 `MIN_UP/MAX_UP`（起手更朝上）。

## 实测五百四十三【那圈"激流特效"：扒出来是官方的一个独立图层，已照抄给女仆】

### 扒出来的结果：方向对了，但它既不是粒子、也不是玩家建模/动作

它是原版挂在 `PlayerRenderer` 上的一个**独立渲染图层** `SpinAttackEffectLayer`。两版源码同构：

```java
if (!entity.isAutoSpinAttack()) return;                       // 唯一门槛：LivingEntity 的方法
VertexConsumer vc = buffers.getBuffer(RenderType.entityCutoutNoCull(
        new ResourceLocation("textures/entity/trident_riptide.png")));
for (int i = 0; i < 3; ++i) {
    poseStack.pushPose();
    poseStack.mulPose(Axis.YP.rotationDegrees(ageInTicks * -(45 + i * 5))); // 45/50/55 度每 tick 三个反向自转
    float s = 0.75f * i;                                    // i=0 时 s=0（退化不可见），实际两层
    poseStack.scale(s, s, s);
    poseStack.translate(0.0f, -0.2f + 0.6f * i, 0.0f);      // 上下错开 0.6 格
    box.render(poseStack, vc, light, OverlayTexture.NO_OVERLAY);
    poseStack.popPose();
}
// box = CubeListBuilder.addBox(-8,-16,-8, 16,32,16)  ← 一个 16×32×16 的大方块
```

**所以那圈东西 ＝ 一个贴着"白色斜纹、透明底"贴图（`trident_riptide.png`）的大方块，
以三种速度反向自转。** 它不在玩家模型里、也不是玩家的动作，门槛只是
`LivingEntity.isAutoSpinAttack()` —— 这反而是好消息：**可以直接照抄给女仆**。
（贴图在原版资源包里就有，两版都确认存在，我们不需要打包任何素材。）

### 复刻做了什么

新增 `MaidSpinAttackEffect`（几何/贴图/三层方块的角度·缩放·位移**逐行照抄**原版），
再按两套模型体系各挂一个图层：

| 模型体系 | 图层 | 挂载点 | 坐标处理 |
| --- | --- | --- | --- |
| Bedrock（TLM 内置模型） | `LayerMaidSpinAttack` | `EntityMaidRenderer` 构造末尾（与鞘翅图层同一入口） | 与原版**同一个空间**，原样照抄 |
| Gecko（酒狐家族等） | `LayerMaidSpinAttackGecko` | `GeckoEntityMaidRenderer` 构造末尾 | 先 `scale(-1,-1,1)` 翻进原版模型空间（反编译实证：Gecko 图层跑在"格、Y 朝上、原点在脚下"的空间） |

判据用**原版那个已同步的旋转标志位**（`isAutoSpinAttack`）：它随实体数据同步到客户端，
而本模组那份"是否正在突进"的状态在服务端、客户端读不到；突进结束时我们会显式清标志位，
所以不会出现"没转却一直冒特效"。

### 与实测五百四十二 的关系

542 把旋转的**枢轴**抬高了 0.6 格（平躺后不再有一半埋在地面以下）；这圈特效是画在
"已经施加过旋转的坐标系"里的，所以两者叠加后观感才对：身体离地一段高度、斜纹方块绕着她转。

### 验证

两树编译零错；包内确认三个新类与 mixin 注册都在；`test_maid_load.py` / `test_server.py`
两版 PASS。**注意**：这是纯客户端渲染，服务端那几条检查覆盖不到，最终观感要在游戏里看。

## 实测五百四十二【激流旋转：把枢轴抬高，别像嵌进地里】

### 为什么偏低（几何上算得出来）

原版施加激流姿态是**绕实体原点（脚底）**转的——`LivingEntityRenderer.setupRotations` 里只有
两次 `mulPose`（`XP(-90 - 俯仰)` + `YP(-75 × tick)`），**没有任何平移**。女仆的模型是从脚下往上
建模的（身体占 y ∈ [0, ~1.8]），平躺之后这段"高度"变成了身体的"前后厚度"（约 ±0.3），于是整个
身体成了一块**以脚底高度为中心的薄片**：下半沉进地面、上半露在外面。平地勉强能看，**斜坡 / 台阶
上一转就像嵌进方块里**。玩家没有这个观感，因为玩家的激流只在水里 / 雨里、身体本来就不贴着地面。

### 修法（纯客户端渲染，机制零改动）

在旋转**之前**（矩阵还是"Y 朝上、原点在脚下"的时候）先把模型整体抬起 **0.6 格** —— 抬的是
**枢轴**，平躺的身体就以"离地 0.6 格"为中心了。新增 `MaidSpinLiftMixin`，注入**原版**
`LivingEntityRenderer.setupRotations` 的 HEAD：Gecko 与 Bedrock 两套模型最终都走这一层，
一处覆盖两边；判据与数值在 `com.maidsmart.client.SpinLift`（只对**正在旋转的女仆**生效，
其余实体 / 状态原样返回）。0.6 是唯一调节量：嫌"像在飘"调到 0.3 左右，嫌"还是压地"就调大。

### 顺带回答："空袭状态下可以触发激流吗？"

当前口径：**只有站在地上时才会**（攻击模式与空袭任务都一样）。空袭的空中链路（起跳滑翔 →
烟花助推 → 收翅俯冲）刻意完全不碰 —— 那正是上一版"不会起飞"的来源；空袭里她**落地之后的
近身战**才会用旋转冲击。想让她在空中（例如收翅俯冲那一下）也能转，说一声，我按那个窗口单独放行。

### 验证

两树编译零错；包内确认新 mixin 与注册都在；`test_maid_load.py` / `test_server.py` 两版 PASS。
**注意**：这条是**纯客户端渲染**，服务端那两条检查跑不到它（`LivingEntityRenderer` 是客户端类），
实际观感要在游戏里看。

## 实测五百四十一【激流改成"替代普通挥砍"；修"不会起飞"与"行动诡异"；去掉旋风特效】

### 一、为什么"不会起飞"（实测五百三十八 引入的回归，两条都是我这边的）

日志实证：13:44–13:45 那一串"旋转冲击（距离 1.5～9.9）"说明当时的版本**在空中也会发起突进**
（只排除了滑翔），加上触发距离 10 格、一轮只要 30 tick —— 她**大部分时间都在突进**；与此同时
`MaidFlightCombatBehavior.tick` 开头有一条"突进期间整段让位"的早退，于是"起跳滑翔 → 放烟花助推"
被反复打断，表现就是**不会起飞**。更糟的是：那个"正在突进"的状态**只要泄漏一次**（任务切换 /
大脑重建 / 被收回时行为没跑到收招），她就永久被判定成"正在突进"，**换什么武器都一直卡着** ——
这正是"换成别的武器也一样"。

### 二、修法（都是"把不该由突进插手的地方还回去"）

1. **突进只在站在地上时发起**（不在地面直接拒绝）→ 空中的空袭链路完全不受影响；
2. **删掉空袭里那条"让位"早退**，空袭状态机永远自己跑；
3. **突进状态自愈**：起手后超过一次旋转的时长还没结束（＝起手了但行为没能跑起来），
   下一次判据里直接丢弃它 —— 再也留不下"永久卡住"的状态。

### 三、触发判定改成"就是她的普通攻击"（回应"判定很奇怪"）

旧版是"目标进 N 格就自主起手"，所以会出现"什么时候触发说不清、还被跳劈等别的行为抢先"。
现在**起手只有两个入口，都是"本来要挥砍的那一记"被替换掉**：

| 入口 | 说明 |
| --- | --- |
| `MaidMeleeRiptideMixin` → TLM 原生近战那一记 `doHurtTarget` | 起手成功 = 这一记算打出去了（TLM 照常吃攻击冷却）；起不了手就**原样调回普通挥砍** |
| 空袭的地面近战 `groundMelee` | 同上，站在地上时才替换 |

共同前提：开关开 ＋ 攻击模式 / 空袭任务 ＋ 主手**激流**三叉戟 ＋ **站在地上** ＋ 目标不超
4 格 ＋ 不在突进中 ＋ 收招硬直已过。**起手时机 = 她的攻击时机**，其余时间这个行为什么都不做
（不再自己找目标）。同时把上一版放大的参数收回来：

| 参数 | 538 那版 | 现在 |
| --- | --- | --- |
| 触发距离 | 10 格 | **4 格** |
| 单次旋转 | 20 tick | **16 tick** |
| 收招硬直 | 10 tick | **20 tick** |

### 四、去掉旋风特效（实测五百三十九 回退）

参考图放大看过：主体是"**横躺自转的本体 + 被甩起来画圆的手持三叉戟 + 白色斜向拖尾**"，
主角其实是被甩起来的武器与它的拖尾 —— 靠粒子拼很难忠实还原。既然直接还原做不到，
就把 539 加的那圈粒子（`sweep_attack` / `electric_spark` / `small_gust`）**整段删掉**
（方法、常量、两处调用，两树都删干净）。现在旋转只剩"与玩家同款的本体自转 + 平躺"
（实测五百三十七 的渲染修复），不再有自造粒子。

### 验证

两树编译零错；`test_maid_load.py` 两版 PASS（女仆真的召唤出来、无 mixin 报错）；
`test_server.py` 两版回归 PASS。桌面那份 v1.2.0 更新文案草稿同步到最新。

## 实测五百四十【修：持激流三叉戟切攻击模式 → 女仆 AI 直接死、收回魂符再放下会消失】

### 根因（是我的锅，日志铁证）

实测五百三十八 新增的 `MaidMeleeRiptideMixin` 注入 TLM 近战任务时，**回调方法写成了非静态**，
而它的注入目标 `MaidMeleeAttack.lambda$create$0` 是 **static** 方法。Mixin 的规则是
"静态目标方法只接受静态回调"，于是在 `MaidMeleeAttack` **首次被加载**（＝女仆生成、
TLM 构建大脑的那一刻）直接 FATAL：

```
[Server thread/FATAL] [mixin/]: Mixin apply for mod promaid failed mixins.promaid.json:MaidMeleeRiptideMixin
    -> com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task.MaidMeleeAttack
org.spongepowered.asm.mixin.injection.throwables.InvalidInjectionException:
    non-static callback method ...MaidMeleeAttack::promaid$riptideReplacesMelee
    targets a static method which is not supported
```

`MaidMeleeAttack` 变形失败 → 女仆的大脑构建不出来 → 表现就是"AI 直接死、一动不动"；
从魂符再放下来会在同一处再炸一次，于是**女仆当场消失**。

注意：这里 `require = 0` 救不了 —— 它只容忍"没匹配到"，不容忍"回调签名非法"。

### 修法

两树的回调都改成 `private static`（静态回调仍然照常把 receiver 作为第一个参数收下）。
`javap` 已确认两个包里的方法都带 `static` 修饰。

### 为什么上一轮的服务端回归没抓到（重要教训）

`test_server.py` 只等 `Done (`，而 `MaidMeleeAttack` 这个脑任务类**只有在女仆实体生成、
TLM 构建大脑时才会被加载** —— 所以那次回归"全绿"却根本没碰到这条注入路径。

新增 `test_maid_load.py` 补上这个盲区：起服 → 等 Done → 控制台 `summon touhou_little_maid:maid`
→ 盯日志 → 判据 = **真的召唤成功** ＋ **没有任何 mixin 应用失败 / `MaidMeleeAttack` 报错**。
两版现在都 PASS（都有 `Summoned new ...` 且无 FATAL）。以后凡是要动 TLM 大脑行为类的注入，
都得先过这条检查。

### 顺带清掉的隐患

两个测试服的 mods 目录里还躺着旧包（`promaid-1.1.1` / `promaid-test` / `promaid-1.1.0`，
同 modId 双包会让"测试到底加载了哪一份"失去意义），已移到
`patched/backup_old/stale_server_jars/`（是移走不是删除）。

### 关于已经消失的那台女仆

那次消失是实体被移除导致的：如果魂符里还留着她的数据，用修好的包再放下来应当正常；
如果魂符已经空了，那台女仆的存档数据我这边找不回来 —— 这是我的 bug 造成的，很抱歉。

## 实测五百三十九【激流旋转补上"周身旋风"特效】

### 之前为什么没有

实测五百三十七 让**本体**的旋转回来了（TLM 把原版那对旋转反号抵消掉，已修），实测五百三十八 让这 20 tick
放得完、看得清。但玩家的观感其实由两部分组成：**① 横躺高速自转的本体**、**② 被甩起来绕体画圆的手持物
与粒子拖尾**。女仆这边 ① 有了；② 里的手持物由 TLM 的模型图层负责、也会随模型一起转，**但粒子拖尾我们
一颗都没生成** —— 所以看上去还是"只有音效"。

### 补了什么

旋转期间（起手 + 每 tick）在服务端就地把"绕着她转的旋风"画出来，附近玩家都看得到：

| 粒子 | 用途 |
| --- | --- |
| `sweep_attack`（白色弧刃） | 两条对置、每 5 tick 转一圈 —— 旋风的主体观感 |
| `electric_spark`（青白火花） | 反向、半径更小的第二环，呼应原版激流的青蓝色 |
| `small_gust`（小风旋，1.21.1）/ `cloud`（白雾，1.20.1） | 贴着她本体的那一圈"风"（1.20.1 没有 gust 系粒子，那是 1.20.5+ 才加的） |
| `crit` + `gust_emitter_small` | 起手与每 6 tick 一圈爆点，让"发动"这一下看得见 |

粒子只是观感，全部包在 `try/catch` 里：任何异常都不影响攻击结算。两树的粒子字段名都经过字节码核对
（1.20.1 是从 `ParticleTypes` 静态初始化的"注册名字符串 → 字段"配对里读出来的，1.21.1 按官方名并核对了
声明类型），不是猜的。

### 验证方式

两树 `javac` 编译零错；进游戏看到"旋转 + 绕体旋风"同时出现即算通过。

## 实测五百三十八【激流三叉戟：独立攻击链路（旋转冲击），并让旋转真的看得见】

### 先查清"为什么上一个版本还是看不清"

实测五百三十七 修的是**渲染被抵消**（TLM 的 `GeoReplacedEntityRenderer.setupRotations` 把原版那对
反号重复旋转消成了单位矩阵），那条修复本身是对的、也确实生效了 —— 客户端 `debug.log` 有实证：

```
[12:46:21] [Render thread/DEBUG] [mixin/]: Mixing MaidGeckoSpinDedupMixin from mixins.promaid.json
    into com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.GeoReplacedEntityRenderer
```

但实测记录（`promaid.log`，12:47–12:49）每次都写着"激流 3 级，力度 3.00"，而**触发距离只有 5 格**：
3 格/tick → **约 2 tick 就撞上目标**；而"撞到实体"按原版 `checkAutoSpinAttack` 会**立刻收招**
（旋转计数清零 + 速度乘 −0.2）。20 tick 的旋转实际只放了 2 tick ≈ 0.1 秒，所以"动作也不明显"。

顺带取证：**原版玩家的旋转没有任何粒子特效**（`LivingEntity` 与 `ItemInHandRenderer` 里
`isAutoSpinAttack` 附近都没有 `addParticle`；后者那条只是第一人称手里三叉戟的翻转）。玩家看到的
"特效"就是**身体高速自转 + 平躺**本身 —— 所以这次要解决的是"让它放得完、看得清"。

### 改了什么（两树各一份）

**① 触发距离 5 → 10 格**（`DASH_RANGE`）。攻击既然就是"冲过去撞"，就得留出冲刺距离。

**② 突进期间每 tick 顶住标志位与速度**（`MaidTridentSpinBehavior.tick`）。原版"撞人即收招"是给
"玩家自己瞄着飞"设计的；女仆每次都朝怪撞，照搬就永远看不到旋转。现在：

- 每 tick 把剩余 tick 与标志位 4 重新写回 → **20 tick 的旋转画面完整放完**；
- 每 tick 按剩余比例重新给推力，**越过目标横线后停住**（不是一路滑出去几十格）→ 冲上去撞，
  然后贴着怪把这一圈转完；
- 撞到横向方块仍照原版提前收招。

**③ 同一目标每次突进只打一下**。标志位被顶住后，原版"撞击即收招"那条天然的一次性保护就没了，
所以 `onSpinTouch` 按本次突进记 hit 集合去重（最终效果与原版一致：一冲一伤）。

**④ 攻击环节被替换**（即"替换原本的攻击环节"）。持激流三叉戟且在攻击模式 / 空袭下时，
普通挥砍不再出手：

| 原本的攻击步骤 | 现在 |
| --- | --- |
| TLM 原生近战 `MaidMeleeAttack`（`swing` + `doHurtTarget`） | 新增 `MaidMeleeRiptideMixin`：把它的"近战可达"判据（1.20.1 `m_217066_` / 1.21.1 `isWithinMeleeAttackRange`，两版都是 **public**）判成 false → 整段不发生（不挥砍、不结算、不吃冷却） |
| 空袭的俯冲猛击 `smashHit` | 换成 `tryStartDash`：起手成功就按"这次出手了"收尾俯冲 |
| 空袭的地面近战 `groundMelee` | 同上（吃同样的攻击冷却） |

`MaidMeleeAttack` 这个任务**只负责"打成"**，走路 / 面向 / 索敌 / 冷却记忆都在别的任务里 —— 需求要的
"其他的如索敌等不变"因此天然成立。种田、伐木等其它任务里拿激流三叉戟**照旧正常挥砍**
（`replacesMelee` 带了任务口径，不会把女仆变成不会还手的沙包）。

**⑤ 空袭的移动权交接**。`MaidFlightCombatBehavior.tick` 在突进期间直接返回（这一秒归突进：不抢速度、
不点烟花、不改滑翔位）；另外**滑翔中不发起突进**（鞘翅物理会与突进互相抢速度，空袭那边本来就是
收翅俯冲时才出手）。

### 现在的表现

拿激流三叉戟 → 切成攻击模式或近战空袭 → 怪进 10 格：她朝怪冲过去，**平躺 + 高速自转 20 tick（1 秒）**，
撞到结算一次（攻击力 + 附魔，含击退 / 火焰附加 / 荆棘），撞完停在怪身边把这一圈转完，10 tick 硬直后
再来一次。走路、索敌、排班、其它任务一律不变。总开关仍是 `combat.riptideDash`
（面板「激流三叉戟旋转冲击」，默认开）。

### 验证方式

- 两树 `javac` 编译零错；
- 新增注入点经 `javap` 实证：TLM `MaidMeleeAttack.lambda$create$0` 内的
  `EntityMaid.m_217066_(LivingEntity)Z`（1.21.1 为 `isWithinMeleeAttackRange(LivingEntity)Z`），
  两版同名同签名、目标方法 public 可直接回指；
- "渲染被抵消"的完整推导见 实测五百三十七 那一段（CFR 反编译 + `javap` 字节码，非推测）。

## 实测五百三十七【激流旋转终于转起来了；弩用普通烟花默认改关】

### 一、Gecko 模型女仆的激流：只有音效和伤害，没有旋转与俯卧（bug 修复）

**症状**：只有音效和伤害，没有玩家那样的旋转特效与动作。

**根因：TLM 自己那对旋转把原版的那对正好抵消了。**

原版 `LivingEntityRenderer.setupRotations` 早就实现了激流姿态，而且**不是 Player 专属**
（1.20.1 字节码 197-199 行、1.21.1 202-204 行）：

```java
} else if (entity.isAutoSpinAttack()) {
    poseStack.mulPose(Axis.XP.rotationDegrees(-90.0f - entity.getXRot()));
    poseStack.mulPose(Axis.YP.rotationDegrees((entity.tickCount + partialTicks) * -75.0f));
}
```

TLM 1.5.3 的 `GeoReplacedEntityRenderer.setupRotations` 在 `super`（＝上面这段）之后
**又叠了同轴反号的一对**（javap 实证：`invokespecial LivingEntityRenderer.setupRotations`
→ `invokevirtual LivingEntity.isAutoSpinAttack` → 两次 `mulPose`，常量 `75.0f`）：

```java
if (deathTime <= 0 && entity.isAutoSpinAttack()) {
    poseStack.mulPose(Axis.YP.rotationDegrees((entity.tickCount + partialTicks) * 75.0f));
    poseStack.mulPose(Axis.XP.rotationDegrees(90.0f + entity.getXRot()));
}
```

`mulPose` 是**右乘**，于是合成矩阵为

```
M = M0 · XP(a) · YP(b) · YP(-b) · XP(-a) = M0      a = -90 - xRot，b = -75·(tick + partial)
```

中间那对同轴 YP 相邻、直接消成单位矩阵，剩下的一对同轴 XP 也消成单位矩阵 →
**净旋转恒等于什么都不做**。所以走这个渲染器的模型（Gecko 系：酒狐家族等）突进时永远不转、
也不俯卧。存档实体 NBT 核实：这边的女仆正是 Gecko 模型（`geckolib:winefox` 系列、
`geckolib:kluonoa`）；TLM 内置基岩模型（`touhou_little_maid:*`，走 `EntityMaidRenderer`）
不经这里，本来就有原版那一份，不受影响。

**修法（两树）**：新增客户端 mixin `MaidGeckoSpinDedupMixin`，把 TLM 那次
`isAutoSpinAttack()`（1.20.1 `m_21209_`）读取重定向为 `false` —— 只让它那对重复旋转整段
跳过、把**原版那一份留下**，于是效果与玩家**完全同款**（不自己写角度、不重复叠加）。该 `if`
块里除这两次 `mulPose` 没有别的语句，且标志位只在突进中为真，所以不突进的女仆一个字都不
受影响。取 `require = 0`：万一 TLM 以后自己删掉这对（＝它修好了），我们自动不再干预；写成
`require = 1` 会把"TLM 修好了"变成启动崩溃，反而有害。

覆盖范围如实说明：只覆盖走 `GeoReplacedEntityRenderer` 的 **Gecko 模型**；YSM 模型由 YSM
自己的 `IGeoEntityRenderer` 渲染、不经这个类（TLM 只给它 `is_riptide` molang 变量），那条路
的旋转取决于 YSM 本体，本 mixin 管不到也不该乱管。总开关仍是 `combat.riptideDash`（默认开）。

### 二、烟花火箭"一点伤害都没有"：不是 bug，是原版机制；开关默认改关

**结论：不是你哪里出错，也不是版本差异 —— 原版任何版本里，没放烟火之星的普通烟花火箭
伤害恒为 0。** 两版字节码完全一致：爆炸结算先看 `Fireworks.Explosions`，**为空则整段早退**。

```java
// 1.20.1 FireworkRocketEntity.m_37087_（就是爆炸伤害的结算）
float dmg = 0.0f;
ListTag ex = "Fireworks" -> "Explosions";
if (ex != null && !ex.isEmpty()) dmg = 5.0f + (float)(ex.size() * 2);
if (dmg > 0.0f) { /* 才结算伤害 */ }

// 1.21.1 同名逻辑 dealExplosionDamage()
float dmg = 0.0f;
List<FireworkExplosion> ex = this.getExplosions();
if (!ex.isEmpty()) dmg = 5.0f + (float)(ex.size() * 2);
if (dmg > 0.0f) { ... }
```

顺带：`m_37086_`／`hasExplosion()` 用的是同一个判据，所以普通烟花**连撞到方块的爆炸都不
触发**，只冒烟（客户端 `m_7822_`／`handleEntityEvent` 那条分支）。

- 想要伤害就**放烟火之星**（星越多伤害越高：`5 + 2×星数`）；`/give minecraft:firework_rocket`
  给的是无爆炸的那种，永远 0 伤害。
- **女仆这条链路本身没问题**：`shootCrossbowFirework` 把取到的弹药栈**原样**塞进
  `new FireworkRocketEntity(level, ammo, shooter, …, true)`（内部 `stack.copy()`，NBT／组件
  完整保留），带星的烟花在她手里照样打出 `5 + 2×星数`。

**配置默认值改关**：`combat.crossbowPlainFirework`（面板「弩用普通烟花当弹药」）
`true → false`。理由就是上面这条：普通烟花当弹药＝白烧一枚飞行燃料（0 伤害）。默认改成
"只有带烟火之星的**攻击性烟花**才当弩弹药，普通烟花全留给飞行推进"；想退回原版玩家口径
（任意烟花都能当弹药）随时可打开。配置面板说明与游戏内指南同步改写（指南里补上
"普通烟花打出去本来就是 0 伤害"的依据）。

> **已存在的配置文件不会被新默认值覆盖**（Forge 只补缺失的键、不覆盖已有值）：1.21.1 实例
> 的 `config/promaid-common.toml` 里这一项原本是 `true`，已一并改成 `false`；1.20.1 实例与
> 两个测试服务器的同名文件也核对过（1.20.1 客户端那份当时还没有这个键，下次启动写入新默认）。

### 验证方式

- 两树 `javac` 编译零错（1.20.1 239 源 / 1.21.1 241 源）；
- 注入点描述符经 `javap -p -c` 核对（1.20.1 `m_7523_` 内 `LivingEntity.m_21209_()Z`、
  1.21.1 `setupRotations` 内 `LivingEntity.isAutoSpinAttack()Z`），并确认编译用的 TLM jar
  与运行期 jar 逐字节相同（1.20.1 `maidmods\original_tlm.jar`、1.21.1 `libs_neo` 副本）；
- 本文所有"原版／TLM 行为"结论均来自 CFR 反编译 + `javap` 字节码，非推测。

## 实测五百三十六【不得把方块搭在主人身上（尤其是头部）】

### 判据

目标格与主人碰撞箱**真正交叠**才算被占（`AABB(BlockPos).intersects(owner 碰撞箱)`，
用严格不等式）。两个后果：

- 你**站在方块上**时，脚下那格与碰撞箱只是相切 → 不算被占 → 该在你身下垫的
  照垫，正常搭路/垫高不受影响；
- 碰撞箱真正探进去的格（身体格、**头部格**）才算 → 正是要防的"塞进身体/盖住头"。

女仆自己所在格不受影响（垫高就是往自己脚下垫）。

### 开关

`misc.noPlaceOnOwner`（默认开）——面板：**系统与杂项 → 交互与杂项 → 不得搭在主人身上**。

### 覆盖范围

自保搭高、搭路、挖矿垫脚、伐木垫脚、插火把、AI 工具「把这里填上」、蓝图建造、
碑石建造，全部 52 处落点。闸口都在**取料之前**（被拦不扣方块）。

### 蓝图/碑石是"延后"而非"跳过"

它们要"把图纸填满"，跳过会永久留洞——所以是延后：**你让开后她下一轮自动回来补上**。
不会因为你站了一下就在建筑里留个洞。

### 副作用

无。默认 = 修复方向；关掉开关恢复旧行为。

## 实测五百三十五【弩用普通烟花当弹药：加开关（默认开 = 原版行为）】

### 开关

`combat.crossbowPlainFirework`（配置面板：生存与复活 → 落地缓冲 → **弩用普通烟花当弹药**）

- **默认开** = 任意烟花火箭都能当弩的弹药（原版 `CrossbowItem` 的弹药谓词只看
  是不是烟花火箭，不看有没有爆炸组件；玩家拿弩装普通烟花照样能射）；
- **关** = 只有带烟火之星的【攻击性烟花】才当弹药，普通烟花一律留给飞行推进。

### 两处判据读同一个开关

`hasAmmoFirework`（判"有没有弹药"）与 `takeBestCrossbowFirework`（实际取用）
都读这一项——只改一边会出现"判定有弹药、起飞后一发打不出来"的死角。

### 优先威力大的不受开关影响

开关只管"普通烟花算不算弹药"；"先打哪一个"一律按爆炸条目数降序
（见 实测五百三十三），有带烟火之星的先打带烟火之星的。

### 本次事故说明

这条开关的第一次实现中途丢失：修复被写坏的 `PromaidConfigScreen.java` 时误用
`git checkout --` 回退了带未提交改动的文件，连带 10 条界面行与"投喂食物勾选"
功能一并丢失。已从事故前构建产物反编译比对后全部补回（1.20.1 448/448 方法、
54/54 字段；1.21.1 454/454、54/54），配置字段与语言条目当时未受影响。
本次补的正是那次丢失的配置面板行。

### 副作用

无。默认值 = 加入这条开关之前的行为。

## 实测五百三十四【激流三叉戟：把玩家的"旋转突进"套到女仆身上】

### 关键结论：标志位是通用的，动画不用自己写

反编译两版后有三个决定性发现：

1. **旋转突进的整套机制都在 `LivingEntity` 上，不是 Player 专属**：
   `autoSpinAttackTicks`（1.20.1 为 `f_20938_`）与"标志位 4"都在 LivingEntity，
   `LivingEntity.tick` 里就会递减 tick、扫掠这次位移的包围盒、撞墙收招。
   置位之后女仆**自动获得原版整套行为**。
2. **动画 TLM 早就做好了**——它读的就是这个标志位：
   ```
   GeoReplacedEntityRenderer.setupRotations（两版都有，字节码实证）：
       if (deathTime <= 0 && isAutoSpinAttack()) {
           mulPose(Axis.YP.rotationDegrees((tickCount + partialTicks) * 75.0f));  // 高速自转
           mulPose(Axis.XP.rotationDegrees(90.0f + getXRot()));                    // 平躺突进
       }
   ```
   而且 `YSMBinding` 还把它暴露成 molang 变量 **`is_riptide`**
   （1.20.1 读 `m_21209_()`、1.21.1 读 `isAutoSpinAttack()`——同一个标志位）。
   所以"动画这一块"根本不用我写：**标志位一置，Gecko 模型女仆就自动转起来**，
   模型作者还能用 `is_riptide` 写专属动画。Bedrock 模型那条路 TLM 自己没做
   （`EntityMaidRenderer` 无此分支），与 TLM 原版一致，本模组不额外补。

### 唯一缺的一环：伤害

`checkAutoSpinAttack` 撞到实体时回调的 `doAutoAttackOnTouch`，在 **LivingEntity 上是空实现**
（1.20.1 字节码就一条 `return`），**只有 Player 覆写成 `attack()`**。所以女仆必须自己补。
新增 `MaidSpinAttackTouchMixin` 注入基类（不改 TLM 源码），回调到
`MaidTridentSpinBehavior.onSpinTouch` 结算：攻击力 + 附魔加成 → 击退 → 火焰附加 → 荆棘 →
命中音；主人/友方与非法目标一律跳过。

### 实现（两树）

- **`MaidTridentSpinBehavior`**：触发条件 = 攻击模式（`touhou_little_maid:attack`）或
  **近战空袭** + 主手是**激流**三叉戟 + 有存活敌对目标且在其 5 格内 + 冷却好；
  触发时照原版：`push(方向 × 3.0×(1+等级)/4)` → 置 tick 数 20 → 置标志位 4 →
  按等级放 `TRIDENT_RIPTIDE_1/2/3` → 耐久扣 1。行为优先级 235（低于落地水 240、高于战术 230）。
- **`LivingEntitySpinAccessor`**：新开的 mixin。**不能复用** `EntityFlagInvoker`——
  滑翔位走的是 `Entity.DATA_SHARED_FLAGS_ID`，而旋转突进读的是
  `LivingEntity.DATA_LIVING_ENTITY_FLAGS`，**是两个不同的 SynchedEntityData**（字节码实证）。
- 配置项 `combat.riptideDash`（默认开）+ 面板一行「激流三叉戟突进」+ 四份 lang。

### 与玩家版本的刻意差异（三处）

| 差异 | 理由 |
| --- | --- |
| **不要求在水里/雨中** | 原版那道闸门是为"游泳突进"设计的，女仆在陆战/空袭时根本不在水里；照搬等于永远触发不了。水外可用是本次需求的核心。 |
| **方向取"她→目标"而非视线** | 玩家自己瞄，女仆得自动瞄准；竖直分量夹在 `[-0.15, 0.35]`，避免目标在脚下时一头扎进地面。 |
| **伤害 = 攻击力 + 附魔** | 1.20.1 玩家激流走普通 `attack()`（随攻击冷却缩放）、1.21.1 是固定 8.0 + 附魔；女仆统一成一种口径（同 `hitOne`，不吃暴击倍率），两树一致。 |

## 实测五百三十三【弩认烟花火箭当弹药 + 优先用威力大的（烟火之星多的）】

### 为什么原来不认

旧版弩的弹药判据是**只认带 `Explosions`（爆炸组件）的烟花**——那是 实测四百九十九 定的，
理由是"不带爆炸的烟花打出去是 0 伤害，拿它当子弹等于白烧一份飞行燃料"。

这个理由**只说明它弱，不说明它不能用**：原版 `CrossbowItem` 的弹药谓词认的就是
**任意烟花火箭**，不看有没有爆炸组件；玩家拿弩装普通烟花照样能射。而本模组却因此
把玩家那叠普通烟花判成"不是弹药"→ 报"缺弹药"→ 一发不开。

### 改了什么（两树）

1. **弹药口径放宽**：`hasAmmoForRanged` 的弩分支改为直接复用 `hasFirework`
   （任意烟花火箭都算），不再要求带爆炸组件。原来的 `hasExplosiveFirework` 随之删除。
2. **按威力挑弹药**：新增 `MaidFlightKit.fireworkPower(stack)` = **爆炸条目数**
   （= 合成时用掉的烟火之星个数，普通烟花 = 0），取用改用
   `takeBestCrossbowFirework`——**威力降序**挑，同威力时按"副手 → 主手 → 背包"的稳定次序。
   于是：有带烟火之星的先打带烟火之星的，没有才用普通烟花兜底。
3. `isExplosiveFirework` 保留但改为 `fireworkPower(stack) > 0`（语义不变，去重复实现）。

### 为什么"烟火之星多"就等于"威力大"（不是拍脑袋）

原版伤害只有这一个数在决定——`FireworkRocketEntity.m_37087_` 字节码：

```
伤害 = 5.0f + 2 * Explosions.size()     // 每多一枚烟火之星 +2
不带爆炸 → 整段早退                       // 0 伤害
```

（同一方法里还可见：对 5 格内实体做 `(5 - 距离)/5` 的开方衰减、对发射者本人不结算。）
所以"烟火之星多"与"打出去更疼"是同一件事，排序依据直接取自原版公式。

### 副作用（如实说明）

普通烟花现在**可能被当弹药打出去**（没有更好的时候兜底）。这是原版玩家行为
（拿弩装普通烟花就能射），不再是需要规避的意外；代价是极少数情况下会烧掉一枚
本可当飞行燃料的普通烟花。弹药耗尽后仍回落到射箭。

## 实测五百三十二【激流三叉戟按"近战武器"归类（原版里它投不出去）】

### 提问与结论

问："TLM 是怎么处理三叉戟的激流附魔的？我觉得我们的空袭也需要注意一下这个，
理论上激流三叉戟应被判定为近战武器。"

答：**TLM 完全没处理**——两个版本的 jar 全文搜 `m_44932_` /
`getTridentSpinAttackStrength` / `startAutoSpinAttack` 全部 **0 命中**
（只剩 geckolib 一个客户端动画绑定读 `isAutoSpinAttack`）。TLM 的
`TaskTridentAttack` 只做了"剥忠诚"一件事，**投掷时不看激流**。

而原版 `TridentItem` 两版字节码都证明：**带激流的三叉戟根本投不出去**——
`use`/`releaseUsing` 里第一道闸门就是"激流 > 0 且不在水中/雨中 → 直接 return"，
而**造 `ThrownTrident` 那一支只在激流 = 0 时走**（1.20.1 是 `iload 7; ifne` 跳过），
激流 > 0 走的是 `startAutoSpinAttack` + `push` 的旋转突进分支。

所以"TLM 能投"这件事本身就是个不一致：玩家拿着它投不出去，女仆却能投。
这条判断是对的，本轮按该口径改。

### 改了什么（两树）

1. 新增 `MaidFlightKit.isRiptide(stack)`——1.20.1 走 `EnchantmentHelper.m_44932_`
   （方法体就读 `Enchantments.f_44957_` = RIPTIDE，字节码实证）；
   1.21.1 走 `stack.getEnchantments().keySet()` + `Holder.is(Enchantments.RIPTIDE)`
   （那个重载不需要 `RegistryAccess`，单参判据也能用）。
2. `isRangedWeapon` 里把激流三叉戟**排除** → 远程空袭的三件套不齐
   （会照常提示"缺远程武器"，不会静默不动）；近战空袭里它照旧算近战武器
   （`isMeleeWeapon` 不看激流，三叉戟带 8.0 攻击力属性，两版一致），
   由俯冲猛击那一记结算。
3. `MaidFlightRangedTask.throwTrident` 补上原版闸门：带激流就不投
   （正常路径不会走到——第 2 条已挡住；这条是防任务切换竞态的兜底）。

### 手册同步

远程空袭的"武器位"说明补了"带激流的三叉戟除外"；弹药那段补了一句说明
（想用投掷三叉戟请放在近战空袭/攻击任务里）。

### 没动的部分

TLM 式的"剥忠诚"保留（防副本飞回来被捡走刷三叉戟）；穿刺/引雷/火焰附加照旧由
`ThrownTrident` 自己结算；御币、弩、弓的通道一律不变。

## 实测五百三十一【飞行远战的手持武器附魔：弩（多重射击/穿透）+ 快速装填】

### 现象

"飞行没有办法触发手持武器的附魔。比如弓和弩，还有三叉戟。"

### 核查结论（逐个反编译实证，不是猜）

| 武器 | 结论 |
| --- | --- |
| **弓** | **本来就是通的**：1.20.1 侧的 `shootArrow` 已逐条照抄 `BowItem.releaseUsing` 的
Power/Punch/Flame/Infinity（SRG 名与常量逐字节一致）；1.21.1 侧箭矢带武器（`firedFromWeapon`），
命中时由 `EnchantmentHelper.modifyDamage` / `doPostAttackEffectsWithItemSource` 自行结算。 |
| **弩** | **真缺**：多重射击、穿透此前**一次都没有**触发过（旧版把弩当弓、自己造一支箭就完事）。 |
| **三叉戟** | 穿刺/引雷/火焰附加由 `ThrownTrident` 自己读物品结算（本来就通）；
**忠诚**是 TLM 两个版本都刻意剥掉的（防"副本飞回来被捡走"刷三叉戟），本模组照搬，故保持不动。 |

### 弩的修法（两树）

照原版 `CrossbowItem.createProjectile` + `performShooting` 的装配与发射：

- **多重射击**（`MULTISHOT`）：1 发 → **3 发**，偏角按原版字节码里的 **0° / -10° / +10°**；
  弹药仍只扣 **1** 份（原版第 2、3 发用的是副本，"1 支箭变 3 支"正是这个附魔的价值）；
- **穿透**（`PIERCING`）：1.20.1 侧显式 `setPierceLevel`（原版 `m_36767_`）；
  1.21.1 侧**不用手动设**——那边 `AbstractArrow` 带武器的构造器里就
  `EnchantmentHelper.getPiercingCount(...)` → `setPierceLevel`，且该方法是 **private**，
  原版就是要它自动生效；
- **命中音**改成 `CROSSBOW_HIT`（原版 `createProjectile` 的唯一额外动作）；
- 耐久仍是**每次射击扣 1**（原版 `onCrossbowShot` 口径），不是每支箭扣 1。

### 快速装填（`QUICK_CHARGE`）

原版弩的蓄力时长 = `25 - 5 × 等级`（1.20.1 `m_40939_` 字节码：`25; iconst_5; imul; isub`）。
飞行时没有"蓄力"这个动作，所以把**同一相对幅度**搬到开火间隔上：
`间隔 = 基础 20 tick × (25 - 5L) / 25`——III 级 20 → **8 tick**，与原版"25 → 10 tick"
同为 2.5 倍提速；下限 4 tick，避免叠出荒谬射速。弓没有射速类附魔，一律走基础间隔。

### 没动的部分

弓的附魔结算通道、三叉戟的忠诚剥离（TLM 同款）、御币弹幕的三个专属附魔、枪械通道，
全部照旧。

## 实测五百三十【垂直占位的高度容差 0 → 10：差 10 格以内一律走原链路】

### 改了什么

`ALTITUDE_TOLERANCE`（实测五百二十七 引入的"已占位"容差）**0.0 → 10.0**，两树同改：

```java
/** 判据：她比目标低 ALTITUDE_TOLERANCE 格以内即视为"已占位" */
private static boolean onTargetAltitude(EntityMaid maid, LivingEntity target) {
    return maid.getY() >= target.getY() - ALTITUDE_TOLERANCE;   // 10.0
}
```

- 目标高出她 **10 格以上** → 进垂直占位相位：朝目标爬升，并且把当前这枚烟花的推力吃完
  才交棒（实测五百二十八）；
- 差 **10 格以内**（含等高、含她更高）→ 原链路直接应付：近战俯冲猛击 / 远战盘旋开火。

### 连带影响（同一个判据）

`faceLaunchDirection` 用的就是这条判据，所以"10 格以内"连**起飞朝向**也回到老口径
"背离 + 向上"（那是为地面目标设计的：爬升时别站在对方近战/爆炸包线里）；只有
"高出 10 格以上"才会切成"朝目标 + 抬头"顺着他爬——正是"用原链路应付"的字面意思。

### 没动的部分

地面起飞门槛（水平 ≤ 20 格）、近战 62° / 远战 45° 的爬升仰角、烟花内置 CD、
以及实测五百二十九 的朝向修正，全部照旧。

## 实测五百二十九【1.21.1 起飞/爬升方向歪掉：两个朝向方法漏了"喂 LookControl"】

### 现象

"起飞方向有问题。不是在向着敌人的方向起飞。"

### 根因（反编译实证 · 1.21.1 客户端 jar）

朝向有两条通道，**两条都得走**，1.21.1 侧只走了一条：

1. `applyRotation(...)` 直接写 `yRot` / `xRot`（含 `yRotO` / `xRotO`，渲染插值要用）；
2. `getLookControl().setLookAt(x, y, z, 360, 360)` 把"期望角度"交给 `LookControl`。

为什么第 2 条不能省：`Mob.serverAiStep()` 里 `customServerAiStep()`（脑活动 → 本行为）在
**字节码偏移 189**，`LookControl.tick()` 在**偏移 236**——**后手执行**。而 `LookControl.tick()`
第一件事就是 `if (resetXRotOnTick()) mob.setXRot(0)`（对女仆恒真），**同一 tick 内就把我们
刚写进去的抬头角归零**；若它手上还留着"期望点"（`lookAtCooldown > 0`，主人 / 游荡 /
上一次瞄准留下的），还会拿**那一份残留**把俯仰和头朝向重新压过去。烟花推力是沿
`getLookAngle()` 给的，于是她既爬不起来、方向也被带偏。

实测四百八十一（1.20.1）当时就是靠"两手都上"解决的；问题出在 1.21.1 移植时只把那一套
搬给了 `faceAwayAndUp` / `faceTarget`，**`faceUpForward` 与 `faceOrbit` 一直漏着**——
这是两棵树唯一的口径差，也正是"不朝着敌人起飞"的根（`faceUpForward` 恰好是起飞、垂直
占位爬升、远战俯冲助推三处的朝向来源）。

### 修法

把 1.20.1 的写法原样补到 1.21.1 的这两个方法。期望点取"朝目标 1 格 + 抬高 tan(仰角)"，
`LookControl` 据此反解出的俯仰角与传入的 `pitch` 同口径；`faceOrbit` 额外按 1.20.1 取
`h = |o|` 再乘进 Y 分量：

```java
applyRotation(maid, yaw, pitch);
try {
    double tan = Math.tan(Math.toRadians(-pitch));
    maid.getLookControl().setLookAt(
            maid.getX() + dx / dh, maid.getEyeY() + tan, maid.getZ() + dz / dh,
            360.0f, 360.0f);
} catch (Throwable ignored) {
}
```

### 影响面

- 1.21.1：起飞方向、垂直占位爬升、远战"俯冲助推"朝向（同用 `faceUpForward`）、
  远战盘旋的高度保持（`faceOrbit`）四处一起纠正；
- 1.20.1：本来就是齐的（四个朝向方法都喂了 `LookControl`），**本轮未改动**。

## 实测五百二十八【空袭垂直占位：够高之后不立刻撤推力，等这枚火箭烧完再交棒】

### 上一版（实测五百二十七）漏掉了什么

"高于或等于就落回原链路"这个判据本身没错，错在**落回得太干脆**：挂载型烟花的推力方向
是**每 tick 跟着她当时的视线走**的，而"抬头朝目标爬"这个朝向只有垂直占位相位在给。
她一到目标高度就切走 → 朝向立刻被后一段"瞄准敌人"改成基本水平 → 同一枚烟花剩下的
20~30 tick 推力全被摊到水平方向。结果是：她刚爬到的那点高度又还回去，敌人只要还在升，
她就在目标高度上下来回蹭，**永远攒不出"在它头上"这个占位**。

### 现在的口径

进相位的判据从一条变成两条（或）：

```
进垂直占位相位 = 还在目标身下（onTargetAltitude 为假）
              或 本相位点着的这枚烟花推力还没烧完（CLIMB_BOOST 且 LAUNCH_LEFT > 0）
```

- `LAUNCH_LEFT` 在本相位里的含义改写为"**当前这枚烟花的推力还剩多少 tick**"
  （近战 30 / 远战 20）。烟花实际寿命是 20~31 tick、`FIREWORK_COOLDOWN = 30`，
  所以"推力刚烧完"基本就是"下一枚可以点了"，不引进新的计时器。
- **够高之后不再补烟花**：只有"还差高度"时才调 `tryLaunch`。否则冷却一好又点一枚、
  本相位被自己无限续命，她会一路烧到世界顶端。
- 够高 + 推力烧完 → 下一 tick 自然交棒给原链路（近战俯冲猛击 / 远战盘旋开火）。
- 新增 `CLIMB_BOOST`（本相位标记）：同时纳入 `isEngaged`，爬升途中也算"正在打这一轮"，
  不会被"主人太远自动传送"拽走（与实测四百八十七同款豁免）；`forget` / `pauseRound` /
  `clearAll` 三处同步清理，不会残留。

### 效果

对着比自己高的敌人：她一路爬、把每一枚烟花的推力吃满，**越过目标高度之后还会继续升一段**，
在它头上攒出高度差，然后才转俯冲（近战）/ 盘旋（远战）。敌人若一直在升，追得上就追；
追不上那是火箭抬升速率本身的极限，不再是"自己把推力扔掉"。

## 实测五百二十七【空袭垂直逻辑改为"垂直占位"：爬到目标头上再谈出手】

### 换掉了什么

上一轮（实测五百二十五）用的是"目标高过 **8 格**就朝它爬"的启发式。本轮按需求换成
**唯一的垂直判据**，8 格那个值连同 `AIR_TARGET_ABOVE` 常量一起删掉：

```java
/** 是否已"占位"——高度是否已经高于或等于目标 */
private static boolean onTargetAltitude(EntityMaid maid, LivingEntity target) {
    return maid.getY() >= target.getY() - ALTITUDE_TOLERANCE;   // 容差默认 0
}
```

新增 `ALTITUDE_TOLERANCE`（默认 **0**，严格按"高于或等于就走正常路径"）。留这个常量是为了
日后一句话就能给 1~2 格的台阶/土坡留余量——**默认值不改**，现在就是严格判据。

### 新的空中链路

`tick` 里在"猛击段"之后、阶段一之前插了一道**垂直占位**闸门：

```
目标没了 / 三件不齐  → 收尾（原样）
起跳等待（JUMP_LEFT） → 原样（3 tick）
猛击段（SMASH）       → 原样（已经收翅砸下去了，让它砸完）
── 垂直占位 ──        ← 新增
   空中 且 高度 < 目标高度 → 只做一件事：爬（tickClimbToAltitude）
   否则（高于或等于）      → 落回原链路：近战俯冲猛击 / 远战盘旋开火
阶段一（LAUNCH_LEFT） → 原样
地面支点             → 原样（水平 ≤ 20 格起跳 / 太远先走过去）
阶段二               → 原样
```

**爬升相位做四件事**（`tickClimbToAltitude`）：

1. **朝向**：朝目标水平方向 + 抬头——角度与起飞同口径（近战 62° / 远战 45°，抽成 `climbPitch()`）；
2. **烟花**：走 `canLaunch` 那套**内建 CD**（`FIREWORK_READY` 30 tick + 有烟花），
   与地面起飞、远战补烟花同一道闸门，**没有新开计时器**；
3. **保持滑翔位**：挂载型烟花只推"正在滑翔"的实体；
4. **远战额外开火**：近战爬升途中没有可打的（要贴到 3.5 格才收翅猛击），远战则不然——
   所以爬升途中照常调 `fireRanged`，不白白浪费输出窗口。

**为什么这一支要"吃掉"阶段一与等待再放**：本相位自管烟花与朝向，所以进相位就把
`LAUNCH_LEFT`（阶段一倒计时）与 `WAIT_LAUNCH`（等猛击后再放）清掉。否则她爬到目标高度
之后会先走完 30 tick 的"背离 + 向上"（那是给地面目标设计的躲闪爬升），白等半秒多才俯冲。

**起飞朝向**（`faceLaunchDirection`）也统一成同一条判据：还在目标身下 → 朝它爬；
已在目标头上（含等高）→ 老口径"背离 + 向上"。四个起飞调用点（起跳 / 阶段一 /
`jumpForLaunch` / `tryLaunch`）一个都没增删。

### 出手看方块阻隔：补上两处漏网的视线门

需求里那句"是否出手肯定还是要看有没有受到方块阻隔的"——查了一遍，**有五条出手链路，
其中三条本来就有视线门**（新锁定 `scan`、地面近战 `groundMelee`、猛击的范围补刀），
另两条没有，本轮补齐：

| 链路 | 之前 | 现在 |
|---|---|---|
| 猛击**主目标**那一记（`smashHit` → `hitOne`） | 无条件结算——隔着一层方块也能凭空打中 | 加 `hasSight`；**放在冷却检查之后、消费冷却之前**：看不见 = 这次没出手、不吃攻击冷却，`tickSmash` 会继续俯冲压着打，视线一通就打出去 |
| 远战弓弩开火（`fireRanged` 的箭矢那一路） | 不看视线（箭自己撞墙是另一回事：先扣冷却、白放一箭） | 加 `hasSight`；枪械那一路本来就有 `canSeeGunTarget`，现在两条枪口口径一致 |

这与 TLM 原生近战"出手前必过 `hasLineOfSight`"、以及本模组实测五百零五给自保链路补
视线的口径完全一致。

### 验证

- 两树编译零错（1.20.1 `EXITCODE=0`；1.21.1 `exit=0`）；
- `javap` 逐项核对（两树各自）：
  - `AIR_TARGET_ABOVE` **已无残留**；`ALTITUDE_TOLERANCE` 常量 = `0.0d`；
  - `tickClimbToAltitude` 已定义且被 `tick` **调用 1 次**，相位内 `faceUpForward` /
    `canLaunch` / `tryLaunch` / `fireRanged` 四件齐全；
  - `onTargetAltitude` 已定义、被调用 **2 次**（`tick` 的闸门 + `faceLaunchDirection`）；
  - `faceLaunchDirection` 仍被调用 **4 次**（四个起飞点，没增删）；
  - `SelfPreservationBehavior.hasSight` 调用点由 **2 → 4**（`smashHit` 主目标 + `fireRanged`
    各一处，原有 2 处未动）；
- `build_promaid.py` / `build_promaid_neo.py` 均 `verify_jar_classes: OK` + lang json OK；
- `deploy_all.py` 三端 `match=True`；
- `test_server.py 1201` 与 `test_server.py neoforge1211` 均 PASS。

### 边界（如实交代）

- **地面那一段一行没动**：还是"水平 ≤ 20 格起跳 / 太远先走过去"。垂直判据只拦**空中**那一段——
  否则她站在地上、目标在半空时会跟着往天上跳（她还没起飞，没有滑翔位，烟花推力吃不到）。
  她一离地就进爬升相位，所以观感仍是"起飞即朝目标爬"。
- **地面等高的敌人行为完全不变**（`getY()` 相等 → 判据为真 → 走原链路：起跳 → 阶段一
  "背离 + 向上" → 阶段二俯冲）；1 格台阶上的目标现在会让她起飞（差值 > 0 = 未占位）——
  这是需求的严格口径，想要余量就调 `ALTITUDE_TOLERANCE`。
- **近战爬升途中不出手**（要贴到 3.5 格才收翅猛击），只有远战会边爬边打；
- 索敌口径（50 格发现 / 128 格维持 / 新锁定要视线）**未动**——垂直占位只管"往哪飞"，
  不管"锁谁"；
- 摔落免疫仍是上一轮改成的**默认开**；落地水"接住即收"、重锤落地帧的内置 CD 也都保持；
- 未改任何配置键名、网络协议号、用户可见文案。

### 已部署待实测

1. **高目标（飞在半空/崖上）**：她应持续放烟花往上爬，高度一够就转俯冲猛击，不再原地仰头看；
2. **等高目标（平地怪）**：行为应与以前一致（起跳 → 背离爬升 → 俯冲）；
3. **1 格台阶上的怪**：按严格口径她会起飞打（差值 > 0）；若认为"为一格台阶就烧烟花"
   不值当，我可以把 `ALTITUDE_TOLERANCE` 调到 1.0~2.0；
4. **隔墙**：目标躲在方块后时不应打中（猛击主目标 / 箭矢都不会结算），
   视线一开立刻打——日志里 `[promaid/飞行撞击免疫]`、`[promaid/空袭免摔]` 不受影响。



## 实测五百二十六【空袭免疫摔落伤害：默认关 → 默认开】

### 改法

默认值一个字的位置改动，但配套的**五处文案**必须跟着改，否则面板写着"默认关"、实际默认开：

| 位置 | 改动 |
|---|---|
| `MaidSmartConfig`（两树） | `COMBAT_FLIGHT_NO_FALL_DAMAGE` 的 `define("flightNoFallDamage", false)` → `true`，config comment `（默认关）` → `（默认开）` |
| `PromaidConfigScreen`（两树） | 该行 tooltip 的 `（默认关）` → `（默认开）` |
| `MaidFlightWallGuard`（两树） | 代码注释里的"（默认关）"同步 |
| 游戏内手册「空袭与飞行作战」章（两树） | 「空袭免疫摔落伤害（§c默认关§r）」→「（§a默认开§r）」，并把"开启即彻底免摔"改写成"默认彻底免摔；关掉才按落地水/雪保护" |
| 桌面发布文案草稿 | 那句"另有默认关的…开关"→ 改成默认开并说明原因 |

### 为什么"默认开"更合理（写进注释里了）

空袭整条链路本身就是"**高空盘旋 + 收翅俯冲**"，落地缓冲（水/雪）只是**兜底**；而兜底失败的
情形都在这条链路的常态里——背包没桶、落点被占、被打断，以及 `实测五百二十五` 修掉的那类
"水还在、滑翔分支被顶掉"。她只有 20 血，这些都属于"机制没接住"，不该由玩家承担。
想按原版吃摔伤，随时可在「生存与复活 → 落地缓冲」里关掉（关掉后行为与以前完全一致）。

### 一个必须交代的坑：改默认值**不会**改动已有存档的配置文件

Forge/NeoForge 的 COMMON 配置一旦生成就会把值写进 `config/promaid-common.toml`，
之后**代码默认值不再生效**（读的是文件里的值）。所以本次顺带核对了你本机的三个配置：

```
D:\.minecraft\versions\1.20.1-Forge_47.4.21\config\promaid-common.toml      flightNoFallDamage = true
D:\.minecraft\versions\1.21.1-NeoForge_21.1.250\config\promaid-common.toml  flightNoFallDamage = true
```

**两边都已经是 true**（此前已手动打开过），所以本机不需要改配置文件、行为立刻一致；
对**新装/新档**的玩家，这次改的默认值才会体现出来。这一点写在这里免得日后被当成"改了没生效"。

### 验证

- 两树编译零错（1.20.1 `EXITCODE=0`；1.21.1 `exit=0`）；
- `javap -c` 反汇编 `MaidSmartConfig` 的 `<clinit>`，`flightNoFallDamage` 后面紧跟的
  是 **`iconst_1`**（= true）——两树都确认；对照组 `flightNoWallDamage` 同为 `iconst_1`，
  `ominous_bottle` 仍在 `List.of` 的实参里（实测五百二十五 那条没被碰掉）；
- `build_promaid.py` / `build_promaid_neo.py` 均 `verify_jar_classes: OK` + lang json OK；
- `deploy_all.py` 三端 `match=True`；
- `test_server.py 1201` 与 `test_server.py neoforge1211` 均 PASS。

### 边界

- **只改默认值与文案**：`MaidFlightWallGuard` 的拦截逻辑（`FALL` 伤害取消 + 日志
  「空袭免摔」）一行未动，`实测四百九十四` 引入的行为完全保留，只是默认值反过来。
- 免疫仍**只作用于两个空袭任务**（`MaidFlightKit.isFlightTask` 门控）——普通近战/生产任务的
  女仆照常吃摔落伤害。
- 免疫的是**摔落伤害**（`fall`），不是"免疫所有伤害"：被怪打照样掉血、照样可能被击落，
  与 `实测四百九十四` 的口径一致。
- 未改任何配置项键名、网络协议号；`config.promaid.combat.flightNoFallDamage` 的翻译键与
  中英文名都没动（面板行的标题仍是「空袭免疫摔落伤害」）。



## 实测五百二十五【排班表分类说明补齐 + 空袭"敌人更高"方案 + 落地水不再挡飞行 + 不祥之瓶默认不喂】

## 一、排班表挪了分类，两处"文字说明"漏改（两树）

`实测五百一十八` 把排班表从「移动与行为」挪到「生产与工作」，但那次**只改了 `Section`
枚举的归属**，两处写给玩家看的说明漏改：

| 位置 | 旧文（错的） | 现在 |
|---|---|---|
| 配置面板大类页一句话（`groupHint`）· 生产与工作 | `建造 / 挖矿 / 伐木 / 烧制酿造 / 农场宰杀` | 末尾补 ` / 排班表` |
| 同上 · 移动与行为 | `跟随 / 空闲流畅 / 排班表 / 搭路` | 排班表已不在这个大类 → 去掉 |
| 手册「功能总览 · 一键跳转配置」① 生产与工作 | 只有建造/挖矿/伐木/烹饪与酿造/农场与宰杀五个链接 | 补 `[[@WORK:SCHEDULE|排班表]]` 链接 |
| 同上 ⑤ 移动与行为 | 还挂着 `[[@WORK:SCHEDULE|排班表]]`（跳得到，但列错了大类） | 去掉（已在 ① 列出） |

判据就是 `Section` 枚举里的实际归属（`SCHEDULE("排班表", Group.WORK)`），不再靠人工记忆。
手册那一章是「一键跳转」的性质，现在 ①②③④⑤⑥⑦ 七行与配置面板首页**逐项对齐**。

## 二、空袭面对"比自己高的敌人"没有方案（两树）

两个原因叠在一起，都在 `MaidFlightCombatBehavior`：

**① 起飞门槛用的是 3D 距离——她根本进不了起飞分支。**

```java
double dist = maid.distanceTo(target);           // 旧：3D 距离
if (maid.onGround()) {
    if (dist <= LAUNCH_RANGE && canLaunch(...)) { jumpForLaunch(...); }   // LAUNCH_RANGE = 20
    ...
}
```

敌人比她高 50 格时，**光是垂直分量就 ≥50 > 20**：她就算站在敌人正下方也永远进不了这个
分支——不跳、不放烟花，只会原地仰头看（反馈原文："只会对着比自己高 50 格的敌人看着"）。

现在改判**水平距离**：

```java
double dxh = maid.getX() - target.getX();
double dzh = maid.getZ() - target.getZ();
double distH = Math.sqrt(dxh * dxh + dzh * dzh);
if (distH <= LAUNCH_RANGE && canLaunch(...)) { jumpForLaunch(...); }
```

`LAUNCH_RANGE` 那句话的原意（常量注释）本就是"太远先跑过去，避免越炸越远"——这是个
**水平**概念；空袭是立体作战，垂直方向不该设限。爬升量由起飞仰角（近战 62°/远战 45°）承担。

**② 起飞朝向是给地面敌人设计的——目标是空中目标时会越飞越远。**

原口径是"背离敌人 + 抬头 62°"，目的是爬升时不站在对方的近战/爆炸包线里。可目标在头顶
50 格时她本来就不在对方包线内，"背离"只会让她**越飞越远再掉头飞回来**，全程烧烟花。

新增 `faceLaunchDirection(maid, target)`（起飞阶段四处调用点统一走它）：

```java
if (target.getY() - maid.getY() > AIR_TARGET_ABOVE) {   // 8 格
    faceUpForward(maid, target, -62°);   // 空中目标：朝它爬（复用远战补烟花那套）
} else {
    faceAwayAndUp(maid, target);         // 地面目标：保持原口径，一行没动
}
```

门槛取 8 格的理由：对方在 8 格以上高度时她的近战包线本来就够不着，"躲开"没有收益；
而地面怪站在 1~7 格台阶/土坡上时仍走旧口径，避免刚起飞就贴脸。

## 三、落地水会阻拦女仆飞行（两树；1.21.1 重锤落地帧另补 CD）

### 真根因不是"缺 CD"

水是**流体**。`LivingEntity.travel` 的第一个分支就是
`isInWater() → travelInWater(...)`——只要她还在水里，**滑翔分支整个被顶掉**：

- 烟花推力被水阻尼几乎吃光（`FireworkRocketEntity` 只是往速度里加，真正结算的是 `travel`）；
- 而且在水里 `onGround()` 恒为 false → 空袭"落脚再起飞"的支点判定也进不去。

所以她站在自己刚放的那格水里"看着敌人不动"。**细雪不是流体、没有这一层**，所以过去
只有落地水挡飞行——这正是"落地雪没事、落地水有事"的来源。

`实测五百一十二` 已经给空袭分支加过 2 秒内置 CD（`FLIGHT_CLUTCH_CD = 40`，这次核对
**两树都在、值没变**）。但 CD 拦的是"不要连着再放一次"，拦不住"这一格水还在那儿"。

### 改法：这类缓冲只负责"接住这一下"

新增 `flightPlaced` 标记（`placeFluid` 增加一个带来源的重载），空袭/重锤落地帧置位；
主循环里对这类**水**加一条"接住了就收"：

```java
if (this.flightPlaced && !this.placedSnow
        && maid.getDeltaMovement().y >= 0.0) {   // 不再下坠 = 已落进水里被阻尼停住 / 已踩到地
    this.recoverFluid(level, maid);
    return;
}
```

- 只用**竖直速度 ≥ 0** 做判据，不用 `onGround()`——因为在水里 `onGround()` 恰恰是 false，
  用它就永远收不掉（这正是上面那条连锁的机关）；
- **细雪不走这一支**（它不是流体，不挡滑翔分支）；
- **通用（高塔坠落）那条路不置位**：它的保持时长仍由配置 `waterHold` 决定，
  "收水后再放一次接住极高塔"的既有语义完全没动。

### 按要求：1.21.1 重锤落地帧也吃同一个 2 秒闸门

`maceLanding` 分支原先没有任何冷却（只靠 `FORCED_CLUTCH` 一次性消费）。重锤 3 秒一发、
落地水只保持 5 tick 时，"跃起 → 落地 → 立刻再跃起"的连击会让水连着放、每次都要从水里
重新起飞。现在这一帧同样过 `gameTime >= flightClutchCd` 并写回 `+FLIGHT_CLUTCH_CD`，
与空袭分支同口径（1.20.1 树没有重锤落地帧，无此改动）。

## 四、不祥之瓶默认不能喂（两树）

1.21 的**不祥之瓶**带食物组件、能"喝"，于是被投喂的通用判定（"有食物属性且不在黑名单"
= 能喂）当成普通食物。喂下去等于顺手给女仆挂**不祥之兆**（袭击/试炼的触发条件）——
玩家喂她是为了回饱食度，不该捎带这个。已加入 `aidFoodBlacklist` 默认值：

```java
"minecraft:enchanted_golden_apple",
"minecraft:ominous_bottle"), o -> o instanceof String s && !s.isEmpty());
```

1.20.1 注册表里没有这个物品，那张表在那边是空操作——**两端默认值保持一致**（配置面板的
勾选页本来就只列注册表里真实存在的食物，多一个未知 id 不会显示、也不影响计数）。
手册「贴身辅助」章那句"默认黑名单…"同步写明不祥之瓶与原因。

## 验证

- 两树编译零错（1.20.1 `EXITCODE=0`；1.21.1 `exit=0`）；
- `javap` 逐项核对：
  - `AIR_TARGET_ABOVE` = `double 8.0d`、`LAUNCH_RANGE` = `double 20.0d`（两树）；
  - **`faceLaunchDirection` 的调用点恰好 4 处**（起跳分支 / 阶段一 / `jumpForLaunch` /
    `tryLaunch`）、**`faceAwayAndUp` 只剩 2 处**（`faceLaunchDirection` 内部 + 远程近身弹开）
    ——即起飞阶段已全部改走新朝向；
  - `tick` 里出现新的 `Math.sqrt`（水平距离）且两个 `jumpForLaunch` 都在它之后；
  - `WaterClutchBehavior`：`FLIGHT_CLUTCH_CD` = `long 40l`、
    `placeFluid(...,boolean,boolean)` 重载存在、`flightPlaced` 读写齐全、竖直速度判据在位；
  - `MaidSmartConfig`：`ominous_bottle` 两端都在；
  - **自查（又一次踩同一个坑）**：第一版校验脚本把 `LAUNCH_RANGE` 判成"0 次比较"、
    重载方法体切不出来——原因是 `static final double` 常量被 javac **内联**（字段名在方法体里
    消失，这正是 实测五百二十一 记录过的坑），以及我的方法体切片正则失手。改用
    `javap -c` 原样 grep 调用点后结论如上表，**是脚本错、不是代码错**；
- `build_promaid.py` / `build_promaid_neo.py` 均 `verify_jar_classes: OK` + lang json OK；
- `deploy_all.py` 三端 `match=True`；
- `test_server.py 1201` PASS（Done 2.614s）、`test_server.py neoforge1211` PASS（Done 0.852s）。

## 边界（如实交代）

- 飞行链路的**数值**一个没动：起飞仰角（近战 62° / 远战 45°）、阶段一时长（30 / 20 tick）、
  收翅距离 3.5、盘旋半径 10、盘旋高度 3.5、弹开 3 格 / 1.5 秒、重锤下落加成算法全部原样；
  本轮只改了"进不进得了起飞分支"（水平距离）与"往哪个方向爬"（有高空目标时朝它爬）。
- `实测五百一十二` 的 2 秒 CD **没有被删除或改值**——落地水的"挡飞行"不是它没生效，
  是它管不到"水还在"；两者是互补的（CD 防连放、接住即收防挡飞）。
- 通用落地水的"收水后再放一次"语义、细雪的全部语义（含追补雪垫）**一行未动**。
- **没有改**投喂判定的通用口径（"有食物属性且不在黑名单 = 能喂"），只调默认黑名单一项；
  玩家仍可在「投喂食物勾选」页里把不祥之瓶重新勾成"能喂"。
- 未改任何网络协议号、配置项键名、用户可见文案的既有措辞（新增的说明文字除外）。

## 已部署待实测

1. 配置面板首页进「生产与工作」，上方的说明应含"排班表"；进「移动与行为」应不含；
   手册「功能总览」① 里的"排班表"链接能跳到排班表小类；
2. **空中敌人**：找一个高处的敌人（或凋灵/幻翼），她应能起飞并**朝它爬**，而不是原地仰头看；
   地面敌人（1~7 格高差）行为与以前一致；
3. **落地水**：空袭/重锤落地后她应能立刻重新起飞——水在她落地停稳的那一刻就被收回，
   不再有"泡在自己放的水里不动"；
4. 往女仆背包塞不祥之瓶：饿到阈值以下她**不应**喂它（顶多去拿别的食物）。



## 实测五百二十四【空袭"飞太高就丢目标、飘走"根治：索敌三处修正（16 格上限 / 起飞丢锁 / 停止清瞄准）】

### 先用实测日志定位，不靠猜

日志就在本机，直接读现场（1.21.1 客户端 `logs/promaid.log`，2026-09-16 22:19~22:20，
打的是监守者）：

```
22:19:32 [空袭索敌] task=flight_combat 候选=1 → 存活=0 → 可攻击=0 → … → 选中=-
22:20:25 [空袭索敌] cands=4 → 存活=3 → 可攻击=1 → 活动范围内=1 → 有视线=1 → 选中=minecraft:warden@7.1
22:20:25 [飞行作战] 放烟花起飞          ← 锁上了，起飞
22:20:27 [空袭索敌] 候选=4 → 存活=3 → 可攻击=1 → 活动范围内=1 → 有视线=0 → 选中=-   ← 2 秒后目标没了
22:20:25~22:20:39 [重锤门] 主手=minecraft:mace 目标=无 地面=false                          ← 悬在空中、没有目标
```

三条硬结论：**候选都在（有敌人）、可攻击也在，却锁不上**；**起飞 2 秒后就丢锁**；
**长时间"在空中 + 无目标"**——没有目标 = 行为停止 = 没有任何朝向指令，于是顺惯性飘走。
这就是"飞得特别高就失去方向"。

### 三个真根因（逐个字节码实证）

**① 视线门误用了 `Sensor.isEntityAttackable`——它内含 16 格上限，我们的"50 格索敌"根本没生效。**

这是本轮最关键的一条。旧版 `FlightTargeting.scan` 里那一关写的是
`Sensor.isEntityAttackable(maid, e)`，注释还写着"与 TLM 原版逐环一致"。反编译实证：

1.20.1（CFR，`Sensor.m_26803_`）：

```java
f_26793_ = TargetingConditions.m_148353_().m_26883_(16.0);                       // forNonCombat().range(16.0)
f_26794_ = TargetingConditions.m_148353_().m_26883_(16.0).m_26893_();            // … + ignoreLineOfSight
m_26803_(a, b) { return brain 已把 b 记为 ATTACK_TARGET ? f_26794_.test(a,b) : f_26793_.test(a,b); }
```

1.21.1（`javap` 客户端 jar，`Sensor.isEntityAttackable`）：

```
static { TARGET_CONDITIONS = TargetingConditions.forCombat().range(16.0);
         ATTACK_TARGET_CONDITIONS_IGNORE_INVISIBILITY_TESTING =
                 forCombat().range(16.0).ignoreInvisibilityTesting(); }
isEntityAttackable(a, b) { return brain.isMemoryValue(ATTACK_TARGET, b)
                                    ? …IGNORE_INVISIBILITY_TESTING.test(a, b)
                                    : TARGET_CONDITIONS.test(a, b); }
```

而 `TargetingConditions.test` 里就是那句
`d = a.distanceToSqr(b); if (d > (range * visibility)²) return false;`。

**两个变体都带 `range(16.0)`。** 也就是说这一环真正卡的是"**16 格以内**"，视线只是顺带。
后果：我们扫的是 50 格球（日志 `盒尺寸=100.6/101.5/100.6`，候选确实捞进来了），却**在 16 格这一关
被全数否决**（日志 `有视线=0 → 选中=-`）。她一旦被起飞弧线推到 16 格外，**再也拿不回目标**。

`实测五百二十一` 之所以"反而更严重"，根因就在这里：旧版（521 之前）根本没有"按距离丢锁"这回事
（它直接读 brain，TLM 什么时候擦才什么时候丢），所以锁能一直挂到打完；521 引入了"距离超限就丢锁"，
而她一旦丢锁，**重新索敌又被这个 16 格上限掐死**——于是从"偶尔丢"变成"丢了就再也回不来"。

**② 维持锁定与新锁定共用 50 格上限——起飞那口气就把她推出 50 格。**

起飞动作是**主动背离敌人 + 抬头 62°** 去吃烟花推力（`faceAwayAndUp` + `LAUNCH_CLIMB_TAN_MELEE=1.88`
+ `LAUNCH_TICKS_MELEE=30`），实测日志正好是这条线的证据：**锁定时距离 7.1 格，放烟花起飞 2 秒后
目标就没了**。旧口径下每一轮起飞都在半路自我解除瞄准，行为随即停止、状态被整清，她在高空
保持滑翔却没有任何朝向指令。

**③ 行为一停止就用 `forget()` 整清，把"瞄准"和"烟花冷却"一起清掉了。**

空袭一轮里行为本来就会短暂停（三件不齐那两拍、`canStillUse` 与 `tick` 的边界），而这些地方
旧版都走 `forget()`。它连带清掉：

- `FlightTargeting` 的锁定 → 她得重新过"限频扫描 + 视线门"，而此刻她多半在高空（① 的 16 格上限
  在这里再次致命）→ **有敌人却拿不到目标**，正是日志里那片 `选中=-` 的状态；
- `FIREWORK_READY` 烟花冷却 → 停一下就能重开一次，实测日志里出现了**同一秒两次"放烟花起飞"**。

### 改法（两树同步）

| 位置 | 改动 |
|---|---|
| `FlightTargeting.scan` | 视线门改用本模组自有的 **`SelfPreservationBehavior.hasSight`**（纯 raycast：`ClipContext.Block.COLLIDER`、中心点上抬 1.2 格、**没有距离上限**）。"隔墙不出手"照旧成立，但"能不能发现"重新交回用户指定的 50 格球。与实测五百零五给自保近战补视线用的是同一个方法，口径统一 |
| `FlightTargeting` 常数 | 拆成两个：`RANGE = 50.0`（**只管发现**，新锁定）+ 新增 `HOLD_RANGE = 128.0`（**维持锁定**）。起飞弧线最坏约 60 格，128 有约两倍余量，同时仍能防住"追着跑出战场" |
| `FlightTargeting.resolve` | 维持/接管锁定这两条分支顺手把扫描冷却推到"下个 tick 即可扫"——限频只为"没敌人时别空扫"，不该在交战中拖延重新锁定 |
| 新增 `FlightTargeting.pause(uuid)` | **轻量清理：保留锁定**，只清每 tick 的缓存。给"行为中途停止"用 |
| 新增 `MaidFlightCombatBehavior.pauseRound(uuid)` | 停止时只清"本轮动作"（`LAUNCH/JUMP/SMASH/WAIT/RANGED_*/ATTACK_READY/MAX_Y`），**刻意保留 `FIREWORK_READY` 与索敌锁定** |
| `endFlightSafely` | `forget(id)` → **`pauseRound(id)`**；硬清仍走 `forget`（女仆移除、清空换任务） |

净效果：**打起来之后，瞄准不会再因为"飞远了 / 视线被挡 / 行为停一拍"而断**——她会一直朝那个方向
飞回去；空中重启也直接进阶段二扑击，不会又补一轮背离爬升。

### 顺带修掉诊断日志的误导标签

`FlightTargetProbe`（实测五百一十五 加的一次性排查工具，本轮正是靠它锁定根因）原来把
`Sensor.isEntityAttackable` 的通过数标成 **"有视线"**——可那个方法含 16 格上限，
"有视线=0"常常根本不是视线问题、而是目标在 16 格外，排查时被它带偏过。现在：

- 逐环计数**改照我方索敌链**：可攻击 → 活动范围内 → **50 格内** → **我方有视线**，
  末端的 `我方选中` 就等于 `scan` 真正会锁的那个；
- 原版那一关单独列出并**标明含 16 格上限**。

新格式：

```
[空袭索敌] maid=… task=… activity=work 盒尺寸=100.6/101.5/100.6 候选=4 → 存活=3 → 可攻击=1
  → 活动范围内=1 → 50格内=1 → 我方有视线=1 → 我方选中=minecraft:warden@7.1（原版可判(含16格上限)=1）
```

### 验证

- 两树编译零错（1.20.1 `EXITCODE=0`；1.21.1 `exit=0`）；
  中途我自己出过一次错：给 neo 的 `pauseRound` 抄了 1.20.1 才有的 `GROUND_READY` 字段，
  javac 报"找不到符号"，删掉后重编通过——如实记录；
- `javap` 逐项核对（两树各自）：`RANGE` 常量 = `50.0d`、`HOLD_RANGE` = `128.0d`、
  **`keepable` 体内是 `16384.0`（=128²）而不再是 `2500.0`（=50²）**、
  `scan` 调 `hasSight` 且**不再出现 `isEntityAttackable`/`m_26803_`**、
  `pause` 存在且**不碰 `LOCKED`**、`endFlightSafely` 调 `pauseRound` 而非 `forget`、
  `pauseRound` 内**不出现 `FIREWORK_READY`**；
- 1.21.1 侧那条"16 格上限"是用**客户端 jar 的 `javap` 字节码**确认的，不是从 1.20.1 推断；
- `build_promaid.py` / `build_promaid_neo.py` 均 `verify_jar_classes: OK` + lang json OK；
- `deploy_all.py` 三端 `match=True`；
- `test_server.py 1201` PASS（Done 2.658s）、`test_server.py neoforge1211` PASS（Done 0.863s）。

### 边界（如实交代）

- **只改了索敌与收尾口径**，没动飞行链路本身：起飞仰角/时长（近战 62°×30t）、收翅距离 3.5 格、
  盘旋半径 10 格、盘旋高度 3.5 格、弹开 3 格/1.5 秒、重锤下落加成的算法**全部原样**。
  她起飞还是会爬很高——那是"吃满烟花推力"的设计，不是 bug；本轮修的是"爬高之后丢掉瞄准"。
- `HOLD_RANGE=128` 是**有界**的：目标跑出 128 格、或死了/打不着/越出活动范围，仍然会正常收尾。
- 未改任何用户可见文案、配置项与网络协议号。

### 已部署待实测

1. 近战空袭（1.20.1 暴击 / 1.21.1 重锤）能否**完整走完一轮**：起飞 → 朝敌飞 → 收翅猛击 → 再起飞；
2. 飞得再高也不丢目标，不再"飘出战场"；落地后若目标还在，是否立刻重新起飞；
3. 隔墙的怪**仍然不会被新锁定**（这条要专门验一下，是本轮唯一"放宽"的地方的对立面）；
4. 日志里 `我方有视线` 与 `原版可判(含16格上限)` 两列的差别，能直观看出旧口径卡在哪一环。



## 实测五百二十三【版本号统一为 1.2.0（两端一致）】

### 改法

把**未发布批次**的版本号统一为 **1.2.0**，1.20.1 Forge 与 1.21.1 NeoForge **两端一致**。

落地范围（共 **657 处**）：

| 位置 | 改动 |
|---|---|
| `promaid_src/META-INF/mods.toml` | `1.1.1` → `1.2.0` |
| `promaid_src_neo/META-INF/neoforge.mods.toml` | `1.1.0` → `1.2.0`（实际被打包的那个） |
| `promaid_src_neo/META-INF/mods.toml` | 同步（该文件不参与打包，仅避免日后混淆） |
| 构建脚本 | jar 名 → `promaid-1.2.0.jar` / `promaid-1.2.0-neoforge-1.21.1.jar` |
| 部署 / 测试 / 校验脚本 | 源与目标路径改名 |
| `deploy_all.py` | 新增：部署时**自动删除目标目录里旧的 `promaid-1.1*.jar`**——jar 改名后旧包若残留，同 modId 共存会导致启动失败 |
| 游戏内手册 | 玩家可见版本标注（"v1.2.0 起新增功能速览"等） |
| 内置变更日志 | 两树 `changelog.txt` |
| README | 两平台版本标注 |

### 顺带归一的历史口径

这批未发布改动原先在源码注释里**混用了 `v1.1.3` 与 `v1.1.4`**（同一批功能前后写下的两个号），
另有一处 `v1.1.2`——现在**全部归一为 `v1.2.0`**。

**安全性依据**：远端 tag 当时只到 `v1.1.1`（`git ls-remote` 确认），所以 `v1.1.2/3/4` 从未发布，
归一不影响任何已发布记录；已发布标号（`v1.0.x` / `v1.1.0` / `v1.1.1`）**原样保留、未触碰**。

### 我自己踩的坑（如实记录）

批量替换是用脚本做的，中途把两树 `changelog.txt` 写成了**双 BOM**——读用 `utf-8-sig`
（吃掉 BOM）、写又用 `utf-8-sig`（再补一个），文件头变成 `EF BB BF EF BB BF`，
游戏里首行会显示成一个方框。已修正为单 BOM 并复核（首行仍是【版本号说明】、第 2 行仍是最新条目）。

### 验证

两树编译零错；jar 内 `version=1.2.0`（两平台）、手册含 `v1.2.0` 且无 `v1.1.2/3/4` 残留、
内置日志单 BOM 且首行正常、`pack_format` 分别 15 / 34；
`deploy_all.py` 三端 `match=True`，且两个客户端目录里的旧 `promaid-1.1.x` 包已确认清除
（只剩 1.2.0）；`test_server.py 1201` 与 `neoforge1211` 均 PASS。

### 升级提示

两个 jar 的 `modId` 相同，**安装前请删除 mods 目录里的旧 `promaid-1.1.x` 包**，
否则同时加载会启动失败。

## 实测五百二十二【手册「详细介绍」全面重写：补上空袭专章 + 补齐缺失功能 + 修失效跳转】

### 先做体检：手册到底漏了什么

没有凭印象改，先把两边的**实际内容**都盘出来对账：

- 手册侧：`GuideContent` 共 30 章、1108 行（两树内容基本同源），逐章读完；
- 模组侧：`MaidSmartConfig` 共 **326 个配置项 / 12 个配置组**，配置面板另有独立的
  **7 大类 / 28 小类**层级——这才是"模组实际有什么"的权威清单。

然后拿功能关键词去手册里检索，得到硬结论：**手册完全没提的功能有一整片**，
其中最大的一块是——

### 最大的缺口：整个「空袭 / 飞行作战」系统手册只字未提

全篇检索「飞行作战 / 空袭 / 鞘翅 / 烟花火箭」= **0 次**。

而这是模组里体量最大的一套系统：两树合计 4 个任务类 + 1 个行为类（1300+ 行）
+ 装备/弹药/姿势 3 个工具类 + 若干 mixin；配置项还**散在三个小类里**
（总开关在「主动参战」/ 1.21.1 在「单兵战术」，落地保护三项在「落地缓冲」）。
玩家切到这两个任务后，完全不知道三件套是什么、为什么不起飞、为什么她贴地不飞。

**新增整章「空袭与飞行作战（会飞的女仆）」**（约 5 页，与最长的既有章节持平），
七节写全：两个任务的区别 / 三件套（鞘翅+武器+烟花，远程空袭另需弹药）/
保姆式首飞举例 / 近战空袭完整链路 / 远程空袭完整链路 / 索敌机制 / 开关位置与常见问题。

口径全部照当前字节码与配置 comment，不凭印象：
- 激活判据 = `MaidFlightKit.isModeActive/hasElytra/hasWeapon/hasFirework`（远程另需 `hasAmmoForRanged`）；
- 链路常量实测值：收翅距离 3.5 格、范围补刀 2.5 格、盘旋半径 10 格、
  盘旋高度目标上方 3.5 格、开火距离 24 格、近身弹开 3 格 / 1.5 秒、地面重新起飞限 20 格；
- 两树差异**分开写**：1.20.1 无重锤 → 收翅下落按原版暴击 ×1.5；
  1.21.1 手持重锤 → 吃**下落加成 + 风爆**，且按「本轮最高点」结算（`forcedFallDistance` 后门）。

特别把 521 那次索敌重写的**用户可感知结论**写进手册：索敌是以自身为圆心、
半径 50 格的球，且**一旦锁定就持续瞄准**（不再飞高丢目标、飘出战场）。

### 顺手修掉一个真实的失效链接

体检时发现：`MOVE:SCHEDULE` 这个跳转目标**不存在**——排班表在实测五百一十八
已从「移动与行为」挪到「生产与工作」，但手册里两处引用漏改：
① 功能总览章的 `[[@MOVE:SCHEDULE|排班表]]`；② `CFG_LINK_RULES` 里的同名规则。
点了跳不过去。现在两处都改为 `WORK:SCHEDULE`，并给新的空袭章补了两条跳转规则。

### 其余补齐（手册原来一个字都没有的功能）

- **投喂食物勾选**（实测五百一十九/五百二十的新功能）：写清"现在认模组食物
  （带食物属性就算能喂）、勾选面板在哪、点图标切换能不能吃、默认黑名单有哪些"，
  附"让女仆喂三明治"的保姆式举例；
- **AI 记忆**补「人格种子」（人设与聊天记忆分离）与「双 agent 提取」（摘要/事实分两次调用）；
- **农场与杂项**补：蛋糕可食用、悬空禁搭方块、手持光源发实光、TNT 点火保护期、红石机器专属搭建；
- **伐木**补「树冠清理」、**挖矿**补「穿透预算」；
- 「模组详细配置面板导航」补空袭相关的分类指引（说明它为什么横跨两个小类）；
- 「这是什么？」补 v1.2.0 功能速览（空袭 / 投喂认模组食物 / 三叉戟按任务分类 / 排班表分类调整）。

### 还修了一处会误导读者的编号引用

章内多处写「（见第 3 章）」指"配置 LLM"，但按实际章节顺序它是**第 4 章**
（序言与功能总览各占一位）——读者按图索骥会找错。统一改成按章节名指路
（「准备篇：配置 LLM」），不再依赖会漂移的编号。

### 验证

两树编译零错；内容校验全绿——**章节总数 31**（原 30 + 新增空袭章，
`javap` 确认字节码里 `chapters()` 调用数也是 31）、
**全部 30 个跳转链接与 CFG_LINK_RULES 目标都是配置面板里的合法目标**（不再有 `MOVE:SCHEDULE`）、
本次新增/补齐的关键词全部出现在正文；
排版估算：新章约 5 页（与最长既有章持平）、全手册约 70 页，无异常巨章；
打包 → `deploy_all.py` 三端 `match=True`；`test_server.py 1201` 与 `neoforge1211` 均 PASS。

### 边界

只改了 `GuideContent`（手册正文）与其跳转规则。**没动**任何功能代码、
**没动**配置项本身、**没动**用户可见的语义文本（AI 记忆角色标签、对话翻译提示等保持原样）。
两树内容保持同步，差异只在预期处（版本号措辞、重锤 vs 暴击、空袭总开关所在小类、
`DataComponents.FOOD` vs `FoodProperties`）。

## 实测五百二十一【空袭索敌改为"以自身为圆心、半径 50 格的球"，每 tick 持续瞄准】

### 根因（反编译实证，不是推测）

TLM 的索敌是"传感器扫盒子 → 写可见列表 → 任务从列表里选"三段，
而**扫描盒的大小是按排班活动分流的**：

```
EntityMaid.searchDimension() {
    if (getScheduleDetail() == Activity.WORK) return getTask().searchDimension(this);
    return TaskManager.getIdleTask().searchDimension(this);   // ← 非 WORK 一律走这里
}
```

我们两个空袭任务覆写的 50 格盒子**只在活动恰为 WORK 时参与**；其余时段走 idle 任务的默认口径
（`IMaidTask.searchDimension` 默认 = `inflate(searchRadius, 4.0, searchRadius)`）——
**垂直半径只有 4 格**。空袭是立体作战，她一爬高十几格，敌人就直接掉出那个 4 格高的盒子。

目标掉出可见列表之后：`StartAttacking` 再也选不到它（它的目标来源就是那个列表）；
而空袭行为的 canStillUse 又要求"当前有目标"，目标一丢行为立刻停止、状态被 `forget()` 整清——
她在高空保持滑翔却**没有任何朝向指令**，于是顺着惯性飘出战场。这就是"飞太高 → 丢目标 → 往别处飞"。

### 改法：空袭索敌从 TLM 链路上整个摘出来

新增 `com.maidsmart.combat.FlightTargeting`（两树同源），每 tick 自己维持三件事：

1. **自己扫**以自身碰撞箱为中心、半径 **50 格的球**——AABB 膨胀 50 格做粗筛、距离平方
   （`2500.0`）精筛成球。**完全不看排班活动**，所以她爬多高都算。
2. 目标选定后**每 tick 回写** `ATTACK_TARGET` + `LOOK_TARGET`。TLM 那边什么时候擦、
   按什么判据擦都不再影响空袭：下一 tick 就补回来。

   **还有第二条丢目标的通路，一并被这一条堵住**：TLM 注册在空袭任务 brain 里的
   `StopAttackingIfTargetInvalid` 除了"目标死了/换了维度/不可攻击"之外，还有一条
   **200 tick「寻路到不了就放弃」**的擦除判据——反编译实证它读的是
   `CANT_REACH_WALK_TARGET_SINCE`（1.20.1 `f_26326_`，官方 mappings 名 =
   `cant_reach_walk_target_since`），而那个记忆由 `MoveToTargetSink` 在"路径算不出来"
   时写入。她在高空盘旋时寻路本来就经常算不到地面目标，于是这条判据会把目标判成
   "追不到"而擦掉。现在因为每 tick 都回写，擦掉与否对空袭都不再有影响。
3. 已锁定的目标只要"还活着 + 同维度 + 能攻击（`canAttack`）+ 在活动范围内
   （`isWithinRestriction`）+ 仍在 50 格内"就**继续用它，不再要求视线**。
   这一条正是"持续瞄准"的实质——她飞高时与地面敌人之间的视线经常被地形/树叶/怪物身体挡住，
   旧口径下这会让她把目标判成"不可见"而放弃；现在视线只作为**新锁定**的门槛。

**与 TLM "隔墙不出手"没有任何冲突**：新锁定仍然要过 `Sensor.isEntityAttackable`
（内含 `TargetingConditions` → `Sensing.hasLineOfSight`，与 TLM 原版逐环一致），
墙后的怪不会被新锁定；改变的只是"已经打起来的目标不会因为她飞高、视线被挡一下就被丢掉"。

### 实现细节（两处必须交代）

- **同 tick 去重**：空袭行为同一 tick 会调三次索敌（`checkExtraStartConditions` /
  `canStillUse` / `tick`）。加了 `RESOLVED_TICK` 表按 gameTime 去重，保证三次给出**同一个答案**——
  否则会出现"启动判定看到一个目标、运行中维持的是另一个"的分裂，同时省掉两遍重复扫描与 brain 写入。
- **扫描限频**：行为未运行时 Brain 每 tick 仍会评估 `checkExtraStartConditions`。
  若不加限制，没有敌人的空袭女仆会每 tick 扫一次 50 格 AABB 盒。加了 `SCAN_INTERVAL = 10`
  （0.5 秒），只在"没有锁定"时生效；一旦锁定成功，维持分支短路，扫描根本不参与。

状态表用 `WeakReference` 存目标、并由 `MaidFlightCombatBehavior.forget/clearAll` 在
行为收尾、女仆移除、服务器停止时清空（与既有的状态表同一套回收路径）。

### 验证

两树编译零错；字节码核对（javap）：`FlightTargeting` 成员/字段齐全、
`RANGE` 常量值 = `50.0`、`RANGE_SQR` = `2500.0`、
**视线门只在 `scan`（新锁定）里、不在 `keepable`（维持锁定）里**、
`keepable` 含活动范围与 50 格距离判据、空袭行为已调 `FlightTargeting.resolve/forget/clearAll`
且**不再直读** `ATTACK_TARGET`/`f_26372_`（调用数 0）；
打包 → `deploy_all.py` 三端 `match=True`；`test_server.py 1201` 与 `neoforge1211` 均 PASS。

### 一点自查

我这轮校验脚本自己写错了三次判据（double 的字节序、1.20.1 视线门方法名多打了个下划线、
编译期常量被内联后不该再找字段名），一度报出 4 条假 FAIL。三处都核对过字节码原样后才改判据，
最终 `ALL PASS`——**是脚本错，不是代码错**，记在这里免得下次再踩。

v1.2.0 投喂食物改为「勾选面板」（像矿表那样点图标切换能不能吃）（两树同步）：①【反馈】"那如何进行配置呢？我预想的是就跟设置挖矿种类的面板这种一样，先将所有含标签的食物列出来。然后通过勾选的方式确认能不能吃"②【改法】原来那个逗号分隔输入框换成与矿物名单/替代品名单完全同款的勾选子页。入口在「战斗与自保 → 贴身辅助 → 投喂食物勾选」（按钮显示"可喂 X / 不能吃 Y"）。网格里列出全部带食物属性的物品——包括所有模组食物（三明治等），数据源是新建的 ensureFoodCache()：遍历全部注册物品取 getFoodProperties() != null（1.21.1 是 DataComponents.FOOD）的，不套黑名单（黑名单就是本页勾选的结果）。点图标切换：绿框+✔ = 能喂；红框+✖ = 不能吃；悬停右侧显示中文名/英文 id + "当前：能吃（点击改成不能吃）"。搜索框（中英文皆可）、翻页、下方"不能吃"名单（每行带「允许吃」按钮可一键恢复）、输入框（直接输入注册名列为不能吃，回车生效）——全部与矿表子页同交互；底部提示实时显示"共 X 种食物，当前可喂 Y 种"。③【语义】打勾 = 女仆可以喂（默认全勾），取消勾选 = 列为「不能吃」= 写进 aidFoodBlacklist，与反馈的直觉一致——"打勾的就能吃"。配置项本身仍是同一个 aidFoodBlacklist，只是编辑界面从文本框换成了勾选面板，之前设的值照旧生效。④【一个必须交代的坑·我自己踩了】移植到 1.21.1 时直接复制了 1.20.1 的列表类，neo 侧编译报了一串「需要分号」。根因是 ObjectSelectionList 的构造签名两树不同：1.20.1 是 6 参（top, bottom, itemHeight），1.21.1 是 5 参（top 与 height 合并）+ 没有 setRenderBackground/setRenderTopAndBottom、滚动条覆盖方法是 renderItem 不是 renderScrollbar；另外注册表取值 1.21.1 是 BuiltInRegistries.ITEM.get(...)（无 getValue）。全部照 neo 既有的 AltList 写法改齐后编译通过——这是我引入的错误，已修。⑤【验证】两树编译零错；字节码核对 foodTable 字段、ensureFoodCache、isFoodChecked、toggleFoodChecked、countFeedableFoods、AID_FOOD_BLACKLIST 引用、食物属性读取、$FoodList 内部类——两树全部 YES 且一致；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 投喂判定：21 项原版白名单 → 通用判定 + 可配置黑名单（两树同步）：①【反馈】"女仆的喂食功能可以喂其他mod的食物吗？检测背包中是否有能够喂食的食物的时候有没有跳过模组食物？这个提醒是只判定原版食物吗，往女仆背包里塞一堆三明治疯狂跳没食物"②【根因】EmotionalActionExecutor 里有个 Set<ItemStack> FOODS，内容是手工列出的 21 个原版物品（熟牛排/猪排/羊肉/鲑鱼/鸡肉/兔肉/鳕鱼、兔肉煲/甜菜汤/蘑菇煲/南瓜派、金胡萝卜/烤马铃薯/面包/胡萝卜/苹果/西瓜片/甜浆果/发光浆果/曲奇/海带干 + 蜂蜜瓶），所有投喂判定都是"遍历该集合按物品身份比对"——任何模组食物（三明治等）都不在内 → 背包塞满也判"没有食物" → 疯狂播报"我背包里没有吃的了"。而 TLM 自己"女仆饿了吃"那条链（DefaultMaidHealSelfMeal.isHealMeal，javap 实证）判据是"有 FoodProperties && 不在黑名单"，从不看是不是原版——一个模组里两套食物哲学，正是本问题根源。③【改法·用户选定】新增 EmotionalActionExecutor.isFeedableFood(ItemStack)，与 TLM 完全同口径：有食物属性（1.20.1 Item.getFoodProperties() / 1.21.1 DataComponents.FOOD）&& 不在 AID_FOOD_BLACKLIST 里。FOODS 白名单整体删除（不是留壳——两树字节码核对确认该字段引用已彻底消失）；任何注册了食物属性的物品（模组三明治/蛋糕/其他模组食物）现在都能喂。新增配置项 aidFoodBlacklist（面板「战斗与自保 → 贴身辅助 → 投喂食物黑名单」，TextRow 逗号分隔编辑，与「危险方块表」同款交互）；留空 = 不排除任何食物。默认黑名单：腐肉/蜘蛛眼/毒马铃薯/河豚/紫颂果/可疑炖菜 + 全部生食（beef/porkchop/chicken/mutton/rabbit/cod/salmon/tropical_fish）+ 金苹果/附魔金苹果。④【一个必须说明的取舍·金苹果】旧白名单注释明确写着"金苹果/附魔金苹果【不在内】——走即时增益道具路径（MaidAidOwnerBehavior.useGoldenApple）"。改成通用判定后金苹果天然满足"有食物属性"，若不排除，低血时会被当普通食物喂掉（浪费——金苹果的价值在吸收+再生，不是那 4 点饱食度）。故把这两种也放进默认黑名单保住原行为——这是新口径引入的回归风险，已堵。⑤【改动 6 处调用点（两树）】MaidAidOwnerBehavior 里六处"遍历 FOODS"逐处换成 isFeedableFood(...)：主人链背包/手持选优、feedHealingFood 背包/手持选优、姐妹互助链背包/手持选优、countFoods 诊断、isAidItem 预检。判定逻辑一字未改，只换了"什么算食物"。⑥【验证】两树编译零错；字节码核对 FOODS 字段引用两树两文件均为 False（白名单确实删除）、isFeedableFood 调用数（本类 3 + 行为类 6，正是改动的 6 处）、判定链正确（Item.m_41473_ / DataComponents.FOOD → 取注册名 → 遍历黑名单比对）、MaidSmartConfig 与 PromaidConfigScreen 均含 AID_FOOD_BLACKLIST；四个 lang 文件（两树 × zh_cn/en_us）插入翻译键后 JSON 仍合法、BOM 保留；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 配置面板：排班表从「移动与行为」挪到「生产与工作」（两树同步）：①【反馈】"模组详细配置里面把日程表相关的内容移动到生产与工作中。"②【改法】PromaidConfigScreen.Section 里 SCHEDULE 的所属大类：SCHEDULE("排班表", Group.MOVE) → SCHEDULE("排班表", Group.WORK)。只改所属大类这一个参数——排班表小节的参数行（总开关、战斗还原宽限、可用性检测、反向切换窗口/阈值/冷却、最短持有期、切段后大脑自省、排班活动半径）一行未动，MaidSmartConfig 里的配置项更没动（改分组不影响存档/配置键）。理由：排班表的本质是"给女仆安排各时段干什么活"（种地/挖矿/伐木/烹饪…），属于生产调度而不是移动行为，放生产与工作下更符合直觉。③【顺带同步手册旧路径文案】GuideContent 里 6 处硬编码的旧面板路径一并改掉（两树）：(a)「移动与行为 → 排班表」的「排班活动半径」→「生产与工作 → 排班表」…；(b)总开关：「模组详细配置 → 移动与行为 → 排班表」→「… → 生产与工作 → 排班表」；(c)七个大类清单 ①生产与工作：…/农场与宰杀；→ 末尾加 /排班表；；(d)同一清单 ⑤移动与行为：移动与跟随/空闲与流畅/排班表/搭路；→ 去掉「排班表/」；(e)「怎么找某个开关」·干活（…/宰杀）→生产与工作；→ 末尾加 /排班；(f)同一段 ·跟随/拉回/散步/排班/搭路 → 移动与行为；→ 去掉「排班/」。全库扫描确认：除上述改动说明注释外，再没有"排班表+移动与行为"的残留路径文案。④【验证】两树编译零错；字节码逐常量核对所属大类——SCHEDULE→Group.WORK（原 MOVE）、FOLLOW/IDLE/BRIDGE 仍为 MOVE（确认没误伤）、BUILD/FARM 仍为 WORK，两树一致；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 三叉戟在攻击模式下走近战、不再原地转圈（两树同步）：①【反馈】"三叉戟现在没法作为近战武器用在攻击模式里面了。虽说在各判定里面，它被判定为远程武器。但是我希望保留它被女仆拿在手上开攻击模式的时候不是像个傻子一样在那边转圈。核心问题就在于三叉戟目前只认远程武器，那个模式，调整为攻击模式时候，根本就不认这个武器。明明这个武器也有近战的方式的。"②【根因·不是 TLM 不认三叉戟，是我们自己的走位分类按物品一刀切】javap 钉死两树事实：TridentItem 不是 ProjectileWeaponItem（1.20.1 extends Item implements Vanishable；1.21.1 extends Item implements ProjectileItem）；近战 ATTACK_DAMAGE=8.0（构造器 AttributeModifier(...,8.0d,ADDITION) 实证）；TLM 侧完全认它——TaskAttack.isWeapon="主手装备槽带攻击力属性"（三叉戟满足），MaidMeleeAttack 只在 isHoldingUsableProjectileWeapon（只认 ProjectileWeaponItem）时才不出手→近战任务是愿意挥三叉戟的。真正的问题在 MaidCombatTacticsBehavior：它把 main instanceof TridentItem 写进了"物品即远程"的判定里，于是拿三叉戟走攻击模式时(a) engageRange 被撑到任务搜索半径（十几格就接管走位）、(b) tick 主分支落进 rangedTick → 保持理想射程≥7格+横移绕圈——正是反馈里的"像个傻子一样在那边转圈"：她按远程风筝逻辑跑，而三叉戟既投不出去（投掷要走 trident_attack 任务）、又不肯走近战。另：findBestMeleeWeapon 也把三叉戟排除在"近战武器"外，导致远程任务被贴身时的近战反击手里握着 8 点攻击力的三叉戟却按"无近战武器 1 点"结算。③【改法·分类看当前任务，不看物品类型】三叉戟是双用武器，该按她当前在做什么来分：主分支改成 if (ProjectileWeaponItem || GunCompat.isGun || isRangedTaskActive) → rangedTick 风筝；else → meleeTick 走近战（取代原来的 instanceof TridentItem）。于是：attack（近战任务）持三叉戟 → meleeTick 蛇形逼近/跳劈暴击/贴脸绕圈，8 点攻击力的近战形态这才用得上；trident_attack（投掷任务）→ isRangedTaskActive 为真 → rangedTick 风筝照旧（远程机制一点没动）。判定口径与 AutoCombatSwitch.isRangedTask（同样按任务 UID 分类）对齐，两层不再打架。engageRange 同步去掉 TridentItem（否则近战任务持三叉戟仍会被撑到搜索半径、从十几格就被接管走位）；findBestMeleeWeapon 去掉 TridentItem 排除项（现为合格近战武器参与评分），仍排除的是纯投射武器（弓/弩 ProjectileWeaponItem、枪械——没有可用的近战形态）。④【保留未动】isRangedAttacker（判敌人手里拿什么）里的 TridentItem 照旧——敌人拿三叉戟确实会投掷，那里判定是对的。全类现在只剩这一处 TridentItem 引用（字节码实证）。⑤【验证】两树编译零错；字节码核对全类仅剩 1 处 TridentItem（在 isRangedAttacker）、主分支与 engageRange/findBestMeleeWeapon 均已改走 isRangedTaskActive，两树一致；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 严格门控：中立威胁驱动的"写目标/挥砍"也归"主动参战"管（两树同步）：①【反馈】"是默认会自动清敌对怪吗？把主动参战关了好像也会自己打怪，工作模式甚至都没变，似乎是空手攻击。创造模式下检测不出来，一旦切回生存模式，就会主动攻击敌对生物。"②【根因】NeutralThreatDriver（实测三百四十四为"发狂的狼女仆没反应"加的兜底驱动）做三件事，只有①触发参战在 AutoCombatSwitch 内部查了 COMBAT_AUTO_SWITCH；②往 brain 写 ATTACK_TARGET/LOOK_TARGET 与 ③直接 doHurtTarget 挥砍+导航追人，旧版【一个配置项都没读】（两树全量扫描实证：该类此前引用配置为空），且它在 ProMaidExtension 里无条件注册。于是关掉总开关后：任务不切（①被挡），但②③照跑——任务 UID 不变、人却自己走上去挥刀，正是反馈里的"工作模式没变却在打怪"。③【为何像"空手攻击"】isArmed 只查主手有没有 ATTACK_DAMAGE 属性，而 DiggerItem 构造器会给主手挂 Attributes.ATTACK_DAMAGE（"Tool modifier"，字节码实证）——镐/斧/锹/锄这些干活工具都算"有武器"，工作模式手里正拿着工具 → 判定通过直接挥砍，伤害却只有工具那点加成，观感就是"空手在打"。④【为何创造模式测不出】威胁判据是行为化的 mob.getTarget()==主人/女仆，而原版 TargetingConditions.test 会经 canBeSeenAsEnemy() 过滤目标，创造模式玩家的 Abilities(invulnerable) 为 true → 该判定 false → 怪物根本不会把创造模式的玩家当敌人，getTarget 恒 null → 本驱动静默；切回生存（invulnerable=false）→ 怪物立刻锁定主人 → getTarget 就位 → 当轮即出手。（1.21.1 侧同环是 Player.canBeSeenAsEnemy() 读 Abilities.invulnerable，两树均实证。）⑤【改法·用户选定严格口径】在 drive() 里①之后、②之前插入 COMBAT_AUTO_SWITCH 门控：关了就 return，②写目标与③挥砍一律不做。三点设计说明：(a) 放在①之后——威胁扫描与"威胁解除清理"（threat==null 时那两个 remove）照常运行，Map 不积压，只是不再主动出手；(b) 顺手收回自己写过的目标——关开关时若她脑里还留着"我们写的" ATTACK_TARGET，TLM 攻击行为仍会照着打，故用 ASSIGNED_TARGETS（只登记我们写过的）精确判断，命中才清 ATTACK_TARGET/LOOK_TARGET，不碰 TLM 自己写的目标（战斗任务女仆由 TLM 传感器写，本表无记录）；(c) 两树同步。⑥【行为后果·取舍不是缺陷】按严格口径，关掉「主动参战」后女仆被怪咬只挨打、不还手——除非另外开「单兵战术」（COMBAT_TACTICS，默认开，有自己的开关与战术行为，不受本门控影响）。这正是用户选定的语义。⑦【范围】重锤猛击（1.21.1 专属）有独立 COMBAT_MACE_SMASH 开关、且只在战斗任务下激活，不属本次漏网范围，未改动。⑧【验证】两树编译零错；字节码核对 getstatic COMBAT_AUTO_SWITCH 紧跟 tryEngagePublic(①)之后、eraseMemory/doHurtTarget(②③)均在其后（门控位置正确）；ASSIGNED_TARGETS 仅本类与 assignedTargetOf(无人调用)引用；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 空袭索敌诊断日志【数值不动·只加取证手段】（两树同步）：①【反馈】"锁敌范围仍然很奇怪。建议加到半径为 200 格。然后加个日志来判定一下，我看看为什么锁不到。"→ 随后"如果确认了不是因为索敌范围太小的问题，那就先保持原样。加个日志，然后等我测试。"②【排查结论·已用 javap 证实】不是"范围太小"，是我们的半径在大多数时段根本不参与——EntityMaid.searchDimension() 的实现是：if (getScheduleDetail() == Activity.WORK) return getTask().searchDimension(this); return TaskManager.getIdleTask().searchDimension(this); 而 getScheduleDetail() 按当前时间(getDayTime()%24000)查排班表返回活动。所以只有排班活动恰为 WORK 时，传感器拿到的才是我们覆写的 inflate(50,50,50)；其余时段（夜间 REST 等）盒子来自空闲任务默认实现（水平=限制半径，垂直硬编码 4.0）——实测五百零八/五百一十三 两次调半径在非 WORK 时段等于没改。这本身就足以解释"范围仍然很奇怪"，而不是"50 还不够大"。另：Level.getEntitiesOfClass 一链没有任何 AABB 体积上限（EntityGetter 默认实现只在 getSize()<1.0E-7 时早退），200 格扫描本身可行，不存在"盒子太大静默失效"。③【改法】按用户指示数值保持原样（FLIGHT_SEARCH_RADIUS 两树仍 50.0，没改成 200），新增只读诊断探针 FlightTargetProbe（两树同步），按 TLM 原版那条链逐环计数：候选(复扫 searchDimension 盒子的活体数) → 存活(isAlive && != maid) → 可攻击(EntityMaid.canAttack→IAttackTask.canAttack→DefaultMonsterType，动物/村民/玩家/盔甲架在此出局) → 活动范围内(isWithinRestriction) → 有视线(Sensor.isEntityAttackable，含视线判定=隔墙不出手的来源) → 选中(最近的那个)。日志同时打印 activity=(当前排班活动) 与 盒尺寸=x/y/z——这两个字段是本次关键，一眼看出"此刻盒子多大、是不是走了空闲口径"。④【挂载点】MaidToolAutoEquipBehavior.checkExtraStartConditions（core 行为、任何 activity 都跑、每 tick 一次）——挂这里是为拿到真实排班活动字段（搜索盒子按它分流）。⑤【频率】每女仆每 40 tick(2 秒)最多一条，且只在空袭任务+当前无攻击目标时打印（正是锁不到的现场）；有目标或非空袭任务一律静默，零刷屏。走 PromaidLog，受「运行日志」总开关控制，同时写 logs/promaid.log 与 latest.log；搜关键词【空袭索敌】。纯只读：不写 brain 记忆、不改状态、不参与战斗决策。⑥【边界】本次没有"修复"任何东西，只加观测手段；WORK 门控是已证实的事实，但"用户实际遇到的正是它"要等日志说话——探针的 activity= 字段就是用来验这一点的。探针是一次性排查工具，验证完可直接删（类注释已写明）。⑦【验证】两树编译零错；字节码逐项核对五环判据/盒尺寸三访问器/activity 名/实体类型名/挂载点；打包→deploy_all.py 三端 match=True；test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 副手展示改用"实际消耗的那枚火箭"【修正五百一十一的错误判断】（两树同步）：①【反馈】"应该用使用的那个火箭的那个贴图吧。"（针对实测五百一十一里我写的"展示用的固定是朴素火箭"）②【我上一轮错在哪】实测五百一十一我让副手展示一枚朴素火箭（new ItemStack(Items.FIREWORK_ROCKET)、不写 Explosions），理由写的是"避免被当弩弹药吃掉"。这次核实发现这个理由【方向反了】：(a) 烟花火箭的物品模型是静态的——models/item/firework_rocket.json 全文只有 {"parent":"item/generated","textures":{"layer0":"minecraft:item/firework_rocket"}}，【没有任何 overrides、不读 NBT/组件】（1.20.1 与 1.21.1 的 extra jar 都实证过），所以"带不带爆炸组件"在手部看上去完全一样——我那句"观感一致"是对的，但"必须换掉真实那枚"就没有依据了；(b) 而所谓"被当弹药吃掉"的风险【根本不存在】：展示窗口内若正好开弩，takeExplosiveFirework（副手优先）读到的是真实的爆炸烟花、它本来就是合格弹药；反倒是朴素火箭万一被当弹药打出去才是 0 伤害（FireworkRocketEntity.dealExplosionDamage 开头 if (!this.hasExplosion()) return;）——也就是说我为了"避险"引入了一个更糟的假想风险。用户一句"应该用使用的那个火箭的那个贴图吧"点破了这层：既然模型一样，就该用她真正消耗掉的那一枚显示——语义也对（"掏出的就是刚才那枚"）。③【改法】FlightFireworkPose.show(EntityMaid) → show(EntityMaid, ItemStack consumedFw)：display = (consumedFw != null && !consumedFw.isEmpty()) ? consumedFw.copy() : new ItemStack(Items.FIREWORK_ROCKET)（兜底）；display.setCount(1)；再 setItemInHand(OFFHAND, display)。四个调用点（两树 × 近战起飞 / 远程补推）都改成把 takeFirework 取出的 fw 传进去。其余部分（10 tick 保持、原物快照与还原、core 行为里的归还入口、clearAll）完全不动。④【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；javap -p -c 反汇编构建产物：FlightFireworkPose.show 签名已是 (EntityMaid, ItemStack) 两参，方法体里能看到"参数非空且非空栈 → consumedFw.copy()，否则 new ItemStack(Items.FIREWORK_ROCKET)"的分支（字节码 ifnull / isEmpty / 两条 copy() 路径清晰可见）；两树调用点的 show 调用均为 2 参形式；build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.833s）与 neoforge1211 PASS（Done 0.994s）。已部署待实测：空袭放烟花那一瞬副手显示的就是你包里被消耗掉的那枚烟花（外观与它一致），约 0.5 秒后自动换回原副手物品（盾牌/食物）；其余行为与五百一十一相同。
v1.2.0 空袭索敌：三轴统一 50 格（以自身为圆心）【隔墙不出手由原版保证】调整（两树同步）：①【反馈】"索敌范围还是太小，改为以自身为圆心，半径为 50 索敌，但就和 tlm 原版一样，有隔墙阻挡不出手。"②【演进】实测五百零八先把垂直半径从 TLM 默认的 4 格提到 50 格、水平仍沿用 maid.searchRadius()（默认 16）——当时"只动垂直"是保守取舍，但实测水平 16 格仍太小：空袭是立体作战，敌人在斜上方 20~40 格时水平距离早就出界。本条按需求三轴统一。③【改法】FLIGHT_SEARCH_RADIUS=50.0，两个分支都 AABB.inflate(50,50,50)（有 home/工作点限制时以限制中心为基准、与 TLM 同款）。AABB.inflate 是三轴独立膨胀，等价于"以自身碰撞箱为中心、半径 50 的立方盒"（边长 100）；水平/垂直一视同仁，且【已彻底不再引用 searchRadius】（字节码可见 m_21535_/searchRadius 在这两个方法里归零）——水平不再受 TLM 默认 16 格限制。④【隔墙不出手：由 TLM 原版机制保证，我们没动这条链路】这是本条最需要说清的一点——"放大扫描范围"与"能不能打"是两件事、分属两层：扫描范围由本方法 searchDimension 决定（MaidNearestLivingEntitySensor 用它做 AABB 扫描，结果写进 NEAREST_VISIBLE_LIVING_ENTITIES）；能否出手由 TLM 原版 IAttackTask.findFirstValidAttackTarget 决定（从该记忆里 findClosest(predicate) 选目标）。而 NearestVisibleLivingEntities 【自带视线过滤】：构造器把 Sensor.isEntityAttackable 作为可见性谓词（字节码实证），后者一路走到 TargetingConditions.test、其 ignoreLineOfSight 字段默认 false → 最终查 Sensing.hasLineOfSight。所以墙后的怪能进候选列表、但会在可见性那一关被滤掉——放大范围不会让女仆隔墙出手，这正是"和 TLM 原版一样、有隔墙阻挡不出手"的要求。（另：实测五百零五给自造的那几条近战链路补过 hasSight，那是另一层保险，针对我们绕过 TLM 索敌直调 doHurtTarget 的路径，与原版这条链路互不冲突。）⑤【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；javap -p -c 反汇编构建产物、四处逐一确认（按方法边界切出 searchDimension 全文）：每个 inflate/m_82377_ 调用的三个参数都是 ldc2_w 50.0d × 3（常量序列 [50.0×6]——两个分支各三个）；searchRadius（m_21535_/searchRadius）在方法体内出现 0 次（已不再依赖）；两分支都保留。build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.816s）与 neoforge1211 PASS（Done 0.888s）——本条是服务端行为（索敌传感器跑在服务端），回归有参考价值。已部署待实测：空袭时 50 格内（含斜上方/正上方）的敌人都能被锁定；隔墙的目标仍不出手（与原版一致）；守家/工作点受限的女仆索敌盒以限制中心为基准。
v1.2.0 空袭落地雪/水无限重放 → 女仆无法起飞【内置 2 秒冷却】根因修复（两树同步）：①【反馈】"落地雪在空战状态下有 bug，女仆落地后会一直释放导致无法起飞。解决方法也简单，给此空袭状态的落地雪/水内置一个 2 秒 cd 就好了"②【根因：空袭分支复用了 clutchedThisFall，而它在回收时被清零】WaterClutchBehavior.recoverFluid() 结尾有一行this.clutchedThisFall = false（注释写明 v1.5.25e：收水后允许再放一次——极高塔坠落时 1 秒水可能提前收、落地前最后一段若速度仍达标则再放一次接住）。这行对【通用落地水】是合理的，但空袭分支 isFlightAirborne 复用了同一个标志，于是变成无限循环：①空袭落地缓冲触发 → clutchedThisFall=true → 放出雪垫；②保持时长（雪默认 100 tick / 水按配置）到期 → recoverFluid() → 标志被清零；③下一 tick 条件再次满足 → 又放一次 → 再清零……无限循环。【为什么"落地了还在触发"】细雪不是实心方块——实体是沉进雪里的，onGround() 一直不成立，所以那行"落地即重置"在雪里永远不执行；而 recoverFluid 又会清零，两条路径叠加就让她反复重放。表现即"落地后一直释放、雪花不停铺、行为槽一直被占 → 无法起飞"。③【改法（按用户说的：内置 2 秒 CD）】新增独立字段 flightClutchCd（下一允许触发的 tick）与常量 FLIGHT_CLUTCH_CD=40L（2 秒），【只作用于空袭分支】：条件里加 gameTime >= this.flightClutchCd，触发时记 this.flightClutchCd = gameTime + FLIGHT_CLUTCH_CD。刻意与通用分支解耦：recoverFluid() 里那行"收水后再放一次"原样保留、不动它的语义（那是为通用落地水的极高塔场景服务的），CD 是独立字段、recoverFluid 不碰它，所以空袭分支的循环被彻底切断，普通坠落的落地水行为完全不受影响。④【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；改动过程中我自己出过一次错：第一次编辑误删了 boolean flightWater = ... 那一行，靠括号平衡核对（{/} 各 61/69、diff=0）与"boolean flightWater = 出现次数 = 1"发现并补回——这类结构性错误编译不一定第一时间报，所以每次改完都会核对；javap -p -c 反汇编构建产物，两树 tick 方法体内确认：getfield flightClutchCd + lcmp（比较 gameTime >= cd）、ldc2_w 40l + putfield flightClutchCd（触发时写入 2 秒冷却）——两树完全一致；build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.748s）与 neoforge1211 PASS（Done 1.059s）——本条是服务端行为（放块/回收都在服务端 tick 里），回归有参考价值。已部署待实测：空袭落地放一次雪/水后 2 秒内不再重复释放；落地后能正常起飞；普通（非空袭）坠落的落地水"收水后再补一次"语义不变。
v1.2.0 放烟花的瞬间副手"亮一下"烟花模型【纯表现，零逻辑改动】新增（两树同步）：①【需求】"我还是希望女仆放烟花的瞬间副手拿一下烟花（只加了个动作和烟花模型在副手，不改运行逻辑，用完恢复）"②【背景】实测五百一十 已把副手永久让出给盾牌/食物（烟花改为从背包按需取用、发射路径自己造弹体），功能上正确但"她在放烟花"这件事完全看不到了——本条只补动作表现：发射那一刻把烟花放进副手 0.5 秒，然后原样还回去。③【实现：新增 FlightFireworkPose（两树各一份，约 130 行）】不碰任何运行逻辑：不改弹药判定/推力/冷却/三件套就绪判定，只是 show() 里 setItemInSlot(OFFHAND, 烟花)、tick() 到点还原，烟花在手上【不参与任何计算】；原物必还：放置前先 getOffhandItem().copy() 快照整栈（含 NBT/组件/数量），到点整体写回——盾牌/食物绝不会丢；有界：每女仆至多一条倒计时记录（HOLD_TICKS=10，0.5 秒），到点自清；同步：setItemSlot/setItemInHand 走 LivingEntity 的装备槽同步（EntityMaid 覆写了 m_8061_），服务端一改客户端立刻看得到手里的烟花——【不需要新网络包】。④【固定展示一枚朴素火箭（new ItemStack(Items.FIREWORK_ROCKET)、不写 Explosions）】烟花火箭在手部的物品模型与有没有爆炸组件无关（颜色只在飞行轨迹里体现），观感一致；而这样能避开一个交互风险——展示窗口内若正好开弩，TLM 的 getProjectile（副手是烟花就交出来）与我们的 takeExplosiveFirework（副手优先）都会先读副手，展示"带爆炸的那枚"就可能被当弹药吃掉。⑤【归还点选在 core 行为，这是本条最关键的设计】第一版把归还在 forget() 里做，但 forget(UUID) 拿不到实体引用，清表会把"原副手物品"快照一起丢掉 → 若行为在 10 tick 窗口内被强杀（切任务/目标丢失/死亡），盾牌/食物会【永久】留在烟花状态，这不可接受。所以改成：归还挂在 MaidToolAutoEquipBehavior.canUse——那个 core 行为任何 activity 都跑、每 tick 一次（正是本项目自己注释里写的），且空袭分支里本来就调了 MaidFlightKit.equip；FlightFireworkPose.tick(maid) 放那里 = 无论飞行行为是否在跑，最迟 10 tick 后一定还原。forget() 因此刻意不清表（注释里写明了原因），由 clearAll() 在服务器停机时收尾。⑥【接线（两树各 4 处）】MaidFlightCombatBehavior 近战空袭起飞 tryLaunch → show(maid)；MaidFlightCombatBehavior 远程空袭掉高补推 tickRangedAir → show(maid)；MaidToolAutoEquipBehavior（core、每 tick）→ tick(maid)【归还入口】；MaidFlightCombatBehavior.clearAll() → clearAll()。⑦【验证】两树编译零错（新文件已重跑 gen_compile.py / gen_compile_neo.py 进 argfile）；javap -p -c 反汇编构建产物：FlightFireworkPose（两树）六个方法齐全（show/tick/restoreNow/forget/clearAll/restore），且含副手写入（m_21008_/setItemInHand）、副手快照读取（m_21206_/getOffhandItem）、快照用 copy()（m_41777_/copy）、以及 Items 常量（朴素火箭）；调用点逐一计数：MaidFlightCombatBehavior 里 show=2、clearAll=1，MaidToolAutoEquipBehavior 里 tick=1——两树完全一致、与接线表相符；build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.532s）与 neoforge1211 PASS（Done 0.986s）——本条虽是表现层，但槽位操作与还原都在服务端执行，回归能覆盖"新增类不崩服"。已部署待实测：空袭放烟花（起飞/掉高补推）那一瞬副手会短暂显示一枚烟花火箭（约 0.5 秒），随后自动换回你放在副手的盾牌/食物；期间盾牌/食物只是被暂时盖住、不会丢失；飞行机制、弹药消耗、三件套判定全部不变。
v1.2.0 空袭锁死副手 → 无法进食回血【副手让出，烟花改为按需取用】根因修复（两树同步）：①【反馈】"女仆没办法在空战状态下吃东西回血"；用户补充诊断（方向准确）："空袭状态下锁定了主副手物品，女仆无法在副手装盾牌和食物，我认为这是原因。应该为，不把烟花绑在主副手，检测但只有用的时后放手上"②【根因：equip() 把烟花常驻副手，且写进了"就绪"判定】MaidFlightKit.equip 旧版做三件事：胸甲穿鞘翅、主手换武器、【副手放烟花】——最后一步是长驻占用，而且就绪判定也要求副手必须是烟花（return ok && ... && isFirework(hands.getStackInSlot(1))）。后果：空袭期间副手被烟花锁死，盾牌/食物都装不进去，于是 TLM 的回血吃 MaidHealSelfTask（扫"主手/副手/背包"、换手时要把旧物腾出来）拿不到东西 → "空战无法进食回血"。用户的判断是对的。③【关键事实：烟花根本不需要拿在手上】发射走的是 MaidFlightCombatBehavior.launchFirework，它自己造弹体：new ItemStack(Items.FIREWORK_ROCKET) + 只写 Fireworks.Flight（不写 Explosions）+ new FireworkRocketEntity(level, rocketStack, maid) 直接入世界——【全程不读女仆手里的物品】，方法签名里那个 ItemStack consumedIgnored 参数就是证据（收了却不用）。所以"常驻副手"纯属多余占用。④【改法（按用户选的方案）】(1) 副手完全让出：equip() 删掉副手放烟花那一段，【不再写副手任何槽位】——盾牌/食物可正常装在副手；(2) 起飞门槛改为"烟花在任意位置"：就绪判定由 isFirework(副手槽) 改为 hasFirework(maid)，而 hasFirework 本来就是"主手/副手/背包"三处覆盖（实测五百零二已对齐），所以烟花放背包、放主手、放副手都认。⑤【同步修正 5 处已不适用的注释/文案（代码本就正确、描述已过时）】MaidFlightKit.equip 与类头"副手拿烟花"→"不再占用副手"；MaidToolAutoEquipBehavior（两树）幂等性说明从"副手已有烟花"改为"烟花在身上任意位置"；MaidFlightRangedTask（两树）"两种身份抢同一个副手槽"→说明已不抢槽，但【"只认带爆炸的烟花"这条规则必须保留】（0 伤害烟花当子弹打等于白烧燃料）；neo 用户可见配置文案（MaidSmartConfig + PromaidConfigScreen）"主手换重锤、副手拿烟花"→"主手换重锤（烟花不必拿在手上，副手留给玩家放盾牌/食物）"。⑥【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；javap -p -c 反汇编构建产物、按方法声明边界精确切出 equip 方法体（不靠字符串搜索）：1.20.1 为 117 行、1.21.1 为 129 行，两者的 setStackInSlot 都【只剩 1 次且槽位常量是 iconst_0（主手）】——副手槽（iconst_1）零写入；就绪链为 isUsableElytra(胸甲) → isWeaponForTask(主手) → hasFirework(整个女仆)。另全库复查"副手 + 烟花"的所有提及，剩下都已是正确表述（描述 TLM 原版弩口径或其它功能的副手用途）、无残留误导。build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.777s）与 neoforge1211 PASS（Done 0.835s）——本条是服务端行为（装备槽操作在服务端 tick 里跑），回归有参考价值。已部署待实测：空袭时把盾牌/食物放副手不再被顶掉；缺血≥2 点时能正常进食回血；飞行动力照常（烟花从背包按需取、发射推力不变）；三件套判定不受影响。
v1.2.0 岩浆垫方块自救被禁搭误伤【四百九十八收紧引入的回归】根因修复（两树同步）：①【反馈】"女仆在没有持有火焰保护饰品和抗火效果的情况下，在岩浆里面垫方块自救是一个很正常的行为。需要将它改回来。"②【根因：1.20.1 的放行名单从来没有岩浆这一条（SRG 名注反了）】MaidPlaceGuard.blocked 的放行名单本意是"落地 / 在水里 / 在岩浆里 / 骑乘 → 不拦"，但 1.20.1 侧 SRG 注释写的是 m_20096_=onGround m_20071_=isInWater m_20069_=isInLava——最后这个注反了。javap 复核 Entity 字节码：m_20069_ 是 return f_19798_（触水标志位）＝isInWater；m_20071_ 是 m_20069_||下雨||气泡柱＝isInWaterRainOrBubble；真 isInLava 是 m_20077_（!f_19803_ && f_19799_.getDouble(FluidTags.f_13132_=LAVA) > 0）。三个全是"水"，真 isInLava 的 m_20077_ 一次都没出现——所以岩浆从来就没被放行过。③【为什么以前没暴露、四百九十八之后才炸】岩浆不会像水那样把 fallDistance 清零（水有两条清零路径、都只认水 tag），岩浆只有 Entity.baseTick 里一句 f_19789_ *= 0.5f（每 tick 减半），所以泡岩浆下沉时 fallDistance 稳定停在一个小正数（稳态≈每 tick 下沉量）。四百四十三那版阈值是"≥ 落地水高度 6 格"，岩浆的小正数远小于 6 → 放行，垫方块自救正常；四百九十八收紧成"只要在下落就禁（>0）"后，岩浆下沉必然满足 → 禁搭 → lavaStepUp 里 takeBuildBlock 返回 null→ 岩浆垫方块自救整条失效。所以这是那次收紧顺带引入的回归，不是老问题。④【失效表现很隐蔽】她背包只有方块（没水桶/没末影珍珠/没抗火药）时会一路走到"自救手段都用尽了，我没招了！"；而且 announceNoMaterial 自己也调 blocked() 来抑制误报，连"背包里没有搭方块的材料"这个气泡都不会出——属于静默失败。另：1.21.1 侧一直是对的（用 Mojmap 的 isInLava()，不存在注反问题），所以这本来是两树行为不一致。⑤【改法】1.20.1 放行名单补上真 m_20077_()（isInLava），并把那行错误的 SRG 注释改对：if (maid.m_20096_() || maid.m_20071_() || maid.m_20069_() || maid.m_20077_() || maid.m_20159_()) return false;保留 m_20069_/m_20071_（水与雨/气泡柱放行本身是对的），只加岩浆这一条；1.21.1 代码无需改动、仅补注说明这条为何必须留——两树现在同款。⑥【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；javap -p -c 反汇编构建产物：1.20.1 MaidPlaceGuard.blocked 的放行段现在是 m_20096_ → m_20071_ → m_20069_ → m_20077_ → m_20159_ 一路 ifne 到同一个"返回 false"，与 1.21.1 的 onGround → isInWater → isInLava → isPassenger 结构完全对齐；build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 3.007s）与 neoforge1211 PASS（Done 0.848s）。⑦【这条回归有参考价值】放行名单在服务端 tick 里求值，是服务端行为判定、不是纯客户端渲染。已部署待实测：泡岩浆时女仆照常垫方块脱离液面（无抗火/无火焰保护饰品也一样）；水/雨/气泡柱里的放行不变；正常悬空/滑翔/坠落仍按四百九十八的口径禁搭（不受影响）。
v1.2.0 空袭的垂直索敌提到 50 格【修"凋灵飞高了就锁不上"】根因修复（两树同步，两个空袭任务）：①【反馈】"女仆对高度上的索敌判定太小，在空袭状态应该要增大索敌范围。在进入两个空袭状态下的时候，高度的锁敌应提高为 50 格左右。测试中发现，女仆跟凋灵打的时候，可能会因为凋灵飞得太高而无法锁敌到。"②【根因：TLM 的索敌盒把垂直方向硬编码成了 4 格】女仆索敌范围由 IMaidTask.searchDimension(maid) 决定，MaidNearestLivingEntitySensor 每 tick 用其返回值做 AABB 扫描、结果写进 NEAREST_VISIBLE_LIVING_ENTITIES，而 IAttackTask.findFirstValidAttackTarget（我们两个空袭任务注册的索敌行为）正是从这个记忆里挑目标（反编译实证：读 f_148205_）。TLM 的默认实现（IMaidTask，两树同构）是 AABB.inflate(searchRadius, 4.0, searchRadius)——【中间那个 4.0 就是垂直方向，被写死了】，水平才是 searchRadius（默认 16）。所以空袭模式下女仆的垂直索敌只有 4 格：凋灵稍微飞高一点就出了这个盒，传感器扫不到它 → 记忆里没有 → findFirstValidAttackTarget 选不出目标 → 失去锁定。空袭本来就是打空中目标的模式，4 格垂直盲区完全不合理，与实测现象完全吻合。另已核对：MaidFlightCombatTask / MaidFlightRangedTask 原文里都【没有】覆写 searchDimension，所以一直吃 TLM 默认值。③【改法】在两个空袭任务（近战空袭 MaidFlightCombatTask + 远程空袭 MaidFlightRangedTask）各覆写 searchDimension：【只把垂直半径提到 50 格】（按需求"提高到 50 格左右"），水平仍沿用 maid.searchRadius()——保持与其它任务一致的接战半径、不改索敌广度，避免"顺带把水平拉大"引入未要求的行为变化。两分支写法与 TLM 保持一致：有活动范围限制（home/工作点）时以限制中心为基准，否则以自身碰撞箱为基准——这样守家中的空袭女仆不会因为索敌盒变大而跨出活动范围。④【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0）；javap -p -c 反汇编构建产物、四处逐一确认：都声明了 searchDimension(EntityMaid)（覆写生效）；方法体里能看到 searchRadius() 取值 + AABB.m_82377_(dx,dy,dz)/inflate(...) 调用，且中间那个参数是 ldc2_w 50.0d（垂直位）、两侧是同一个水平值（dload_3）——即 inflate(horizontal, 50.0, horizontal)，正是预期形态；两个分支（m_21536_()/hasRestriction() 为真/假）都在。build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.603s）与 neoforge1211 PASS（Done 0.959s）。⑤【这条回归比前几条有意义】索敌跑在服务端（传感器 + brain 记忆），不是纯客户端渲染，所以服务端能正常加载并启动对本次改动是有参考价值的。已部署待实测：空袭时凋灵飞高（50 格内）仍能被锁定并追击；地面目标行为不变；守家/工作点受限的女仆索敌盒以限制中心为准、不会因此跑出活动范围。
v1.2.0 鞘翅光泽改回"只有真附魔才亮"【撤掉五百零四的常亮】根因修复（两树同步，四处）：①【反馈】"现在对于鞘翅附魔的渲染不分对象。不管附没附魔都渲染出了附魔的样子。"②【根因：这是五百零四自己改出来的】那次把光泽参数固定成 true（常亮）：ItemRenderer.m_115184_(buffer, RenderType.m_110431_(WINGS), false, true)。当时的理由是"本模组手册/排班表/协议源石都是常亮光泽的口径，顺手统一"——但鞘翅跟那几件物品不是一回事：手册是我们自己的物品（常亮是我们的设计选择），而鞘翅是玩家自己附魔的装备，光泽应当如实反映它有没有附魔。注释里甚至留了"想改回只有附魔才亮就把 true 换回去"的话，但默认值本身选错了，等于把"有没有附魔"这条信息抹掉了。③【改法】四处（两树 × Bedrock/Gecko）全部改回与原版 ElytraLayer 完全同款的判定：1.20.1 传 chest.m_41790_()（= ItemStack.hasFoil）；1.21.1 传 chest.hasFoil()。四处差异说明：1.20.1 Gecko 层原本就是对的（五百零四之前一直传 chest.m_41790_()）；1.21.1 那两处改前是硬编码 false（从来不亮），被五百零四一并改成 true，现在一并改为按附魔判定。④【确认判定不会被本模组污染】MaidFlightKit.equip() 只是把鞘翅从背包原样搬进 CHEST 槽（m_8061_/setItemSlot），全程不改写 NBT、不加附魔、不动 Enchantments——所以 hasFoil 读到的就是玩家自己那件鞘翅的真实附魔状态。⑤【验证】两树编译零错；过程中修掉一个自己引入的错误：1.21.1 的 LayerMaidElytra 里原本没有 chest 局部变量（那是内联调用 maid.getItemBySlot(...) 的写法），我直接写了 chest.hasFoil() → "找不到符号: 变量 chest"，已补上局部变量与 ItemStack 导入（该类原本没引这个 import）；javap -p -c 反汇编构建产物，四处逐一确认光泽位已从常量变为真实调用：1.20.1 为 invokevirtual ItemStack.m_41790_:()Z 出现在 foil 调用点前的常量序列末位（序列 iconst_1, iconst_0, iconst_0, m_41790_——前两参是 noEntity/useTranslucent，末位才是光泽位）；1.21.1 为 invokevirtual ItemStack.hasFoil:()Z 同位置（序列 iconst_1, iconst_0, hasFoil）；四处都含取胸甲槽的调用且判定存在。build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.770s）与 neoforge1211 PASS（Done 0.905s）。⑥【证据边界】本条同样是纯客户端渲染改动，服务端回归只证明"新 jar 没让服务器启动失败"，不对渲染效果构成证据——实际观感仍以客户端目视为准。⑦【待部署】与上一条相同，deploy_all.py 检测到游戏实例在运行时会拒绝写入；退出游戏后执行 python deploy_all.py 即可。已部署待实测：普通鞘翅（未附魔）不再有流光；给鞘翅附上任意附魔（如耐久/经验修补）后正常出现附魔光泽；其余外观（尺寸/上移/展翅/前倾）不受影响。
v1.2.0 飞行作战"跟随俯角"前倾【让滑翔姿态向玩家鞘翅靠拢】（Gecko 链，两树同步）：①【需求】"近战空袭飞向敌人时身体建模可能还要向前方向翻一下，大致 35 度左右，这样更接近玩家的鞘翅飞行动作，现在的游泳动作让女仆在俯冲时更类似全身体正对敌人。仅修改建模，机制不变。"②【"游泳动作"确实是我们在播】本项目自己的 MaidSwimGlideMixin 让女仆滑翔时 isVisuallySwimming() 返回 true，而 TLM 的 Gecko 动画选择表 AnimationRegister（两树反编译实证）里游泳动画的触发谓词正是它：AnimationRegister.register("swim", 0, (maid,event) -> maid.asEntity().m_6067_())（1.20.1）/ isVisuallySwimming()（1.21.1）；酒狐（winefox）模型里确实带 swim / swim_stand 两段动画（winefox.animation.json 实测有条目），于是滑翔期间播放游泳动画——身体水平俯卧、中轴直指目标，就是反馈的观感来源。③【玩家鞘翅的权威配方】PlayerRenderer.setupRotations（字节码实证）：ramp = clamp(t*t/100, 0, 1)（t=连续滑翔 tick），然后 mulPose(Axis.XP.rotationDegrees(ramp * (-90.0F - player.getXRot())))——即"基础 -90° 之外【再减掉俯仰角】"。女仆这边的基础 -90° 由模型动画承担，所以本次只补 -getXRot() 这一项：俯冲时（低头为正角）身体继续前翻，平飞/盘旋（俯角≈0）几乎无变化、无需再分阶段。这也说明"大约 35 度"的准确含义是【35° 是俯冲角本身、不是固定要加的角度】，故本条实现的是"跟随俯角"而非硬编码 35°。④【只改 Gecko 这条链（按用户选择）】Gecko（酒狐家族等）走 EntityMaidRenderer.render 的 isGeckoModel() 分支 → GeckoEntityMaidRenderer（继承 GeoReplacedEntityRenderer），本次已改；Bedrock（原版风格）走 BedrockModel.setupAnim，本轮未动。【为什么用 mixin 而不是 TLM 官方扩展点】ICustomAnimation 确实同时提供 setupRotations(Bedrock) 与 setupGeckoRotations(Gecko) 两个回调，但 TLM 自己的 SwimAnimation 【只覆写了 setupRotations、没覆写 setupGeckoRotations】——说明 Gecko 路径的姿态根本不经过扩展点分发，扩展点够不到，必须注入 GeoReplacedEntityRenderer.setupRotations 本身。注入位置选 RETURN：该方法先调 LivingEntityRenderer.setupRotations 摆好朝向，此刻矩阵仍在"Y 朝上、原点在脚下"的世界式空间（scale(-1,-1,1) 与 translate(0,-1.501,0) 尚未施加，即模型渲染之前），原版所有飞行/俯卧姿态都在这一层用 Axis.XP 施加——轴向与枢轴因此与游戏一致，叠加而非覆盖模型动画。⑤【触发口径】MaidFlightKit.isFlightTask(maid) && !onGround()——与鞘翅图层展翅口径一致；刻意不认 isFallFlying()：收翅猛击那段 tickSmash 会主动 setGliding(false)（收翅才吃得到猛击判定），只认滑翔位的话"飞向敌人"最需要前倾的那一段恰好不生效。⑥【可调】唯一调节量 FlightDiveTilt.TILT_FACTOR（默认 1.0 = 与玩家鞘翅同款）；方向若相反把 apply 里的取负去掉即可（一行）。纯客户端渲染，不动任何飞行机制、不加网络包、服务端无感。⑦【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0 仅既有警告），新文件已重跑 gen_compile.py / gen_compile_neo.py 进 argfile；javap 反汇编构建产物确认 FlightDiveTilt 含 isFlightTask + onGround + getXRot/m_146909_ + Axis.XP/f_252529_ + rotationDegrees/m_252977_ + mulPose/m_252781_，MaidFlightDiveTiltMixin 调 FlightDiveTilt.apply 且注解值经 javap -v 提取为 method="m_7523_"（1.20.1）/ method="setupRotations"（1.21.1）、at=RETURN；注入点离线核对：TLM 目标类 GeoReplacedEntityRenderer 里对应方法确实存在且描述符逐一匹配——1.20.1 是 5 参 m_7523_(T,PoseStack,float,float,float)（与原版 LivingEntityRenderer 一致），1.21.1 是 6 参 setupRotations(T,PoseStack,float,float,float,float)，两树签名不同故 mixin 各写一份；build 脚本 verify_jar_classes OK + lang json OK；test_server.py 1201 PASS（Done 2.723s）与 neoforge1211 PASS（Done 0.855s/0.815s，首次跑出现一次 TIMEOUT、重跑两次均 PASS——与上一轮同样的启动偶发超时，如实记录）。【⚠️ 证据边界，必须说清】本条 mixin 的目标 GeoReplacedEntityRenderer 是纯客户端渲染类、且 mixin 注册在 client 列表里，专用服务器根本不加载这个类也不加载这段 client mixin 配置——所以 test_server 结果对本次改动不构成任何有效性证据，只证明"新 jar 没让服务器启动失败"。本条真正依据是：编译零错 + 字节码断言 + 注入点离线核对（目标类里方法存在且描述符与 mixin 签名逐一匹配）。实际渲染效果只能由你在客户端目视确认。⑧【待部署】部署时检测到用户正在游玩（Minecraft NeoForge 1.21.1 窗口运行中），deploy_all.py 按设计拒绝写入（防覆盖运行中的 jar），故本轮尚未部署到游戏实例；退出游戏后执行 python deploy_all.py 即可。已部署待实测：近战空袭俯冲时酒狐身体随俯角继续前翻（更接近玩家鞘翅），抬头爬升自然回正；平飞盘旋几乎无变化；落地恢复站立；飞行机制（索敌/伤害/烟花推进/收翅猛击）完全不变。
v1.2.0 隔墙疯狂挥空【四条自造攻击链路都绕过了"视线"这道门】根因修复（两树同步）：①【反馈】"可以优化一下攻击逻辑吗，我发现装了这个之后墙壁后有怪物酒狐就会疯狂的攻击墙壁。"②【根因：TLM 原生近战本来就有视线门控，我们自己造的链路全绕过了】TLM MaidMeleeAttack 出手条件三条（两树反编译实证）：!isHoldingUsableProjectileWeapon(maid) && maid.isWithinMeleeAttackRange(target) && nearestVisibleLivingEntities.contains(target)——最后那条 contains 走 Sensor.isEntityAttackable → TargetingConditions.test（ignoreLineOfSight 字段默认 false）→ Sensing.hasLineOfSight。也就是说【原版女仆隔墙本来打不到怪】。而本模组为了补 TLM 的结构性盲区（中立/魔改生物索敌、近身反击、空袭命中率）自己实现的攻击链路直接调 m_7327_/doHurtTarget，全都没带上这道门，共四处：(a) NeutralThreatDriver 第③步兜底挥砍只判"距离≤3.1 + getTarget() 锁定我方"——主犯，墙后怪持续锁定主人/女仆 → 每 12 tick 对着墙挥一刀；(b) MaidCombatTacticsBehavior.meleeCounterAttack 按目标周围 2 格 AABB 横扫、只查友伤 → 隔墙能把墙后怪一起真打到（比空挥更糟）；(c) SelfPreservationBehavior.counterAttack 上游 findThreat 查了视线，但"着火兜底"走 findNearestThreatNearby（只有类型+距离、没有视线）→ 墙后怪也能让她隔墙挥刀/放箭/射弹幕；(d) MaidFlightCombatBehavior 的 smashHit 范围命中 + groundMelee 按 AABB 直接结算 → 空袭/落地近战隔墙也打得到。③【改法：统一往项目现有的那条视线工具里收，不新造轮子】项目里本来就有 SelfPreservationBehavior.hasSight(from,other)（public static、两树同名，raycast 到眼睛高度 +1.2 的 ClipContext.Block.COLLIDER），findThreat 与举盾判定都在用它，缺的只是没贯穿到"直接出手"的路径上——六处出手点统一补上（两树同改）。④【隔墙不罚站，这是本次最关键的取舍】NeutralThreatDriver 只在"挥砍"那一步拦、导航照常执行：她仍会朝怪走过去、绕到能看见的位置再打，追击欲望不受影响；因此原第③步末尾那段内联导航提成了 navigateTo(maid,threat) 供"看不见所以不出手"复用（否则会在墙这边原地罚站）。空袭 groundMelee 同理：看不见就 moveTo(target) 继续走近而不是干等。⑤【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0 仅 16 条既有警告）；过程中修掉一个自己引入的语法错误——NeutralThreatDriver 首次编辑多留了一个右大括号（drive 的收尾括号被替换带了过来），报错是"-source 21 中不支持隐式声明的类"，指向的是结果不是原因，靠括号平衡核对定位；javap -p -c 反汇编构建产物按【方法边界】逐一统计 hasSight 出现次数（避免把常量池引用误判成方法体命中）：NeutralThreatDriver.drive=1（两树）、MaidCombatTacticsBehavior.meleeCounterAttack=2（主目标+逐受害者各一次）、SelfPreservationBehavior.counterAttack=1（收口处覆盖三个分支）、MaidFlightCombatBehavior 的 groundMelee/smashHit 各 1——全部与源码意图一致；build 脚本 verify_jar_classes OK + lang json OK；deploy_all.py 三处 match=True；test_server.py 1201 PASS（Done 3.005s）与 neoforge1211 PASS（Done 0.882s）。⑥【附：本次是纯服务端行为判定，不开新包、不动渲染；hasSight 是 raycast，只在真正要出手时（贴脸/范围内）才调用，不进入每 tick 的扫描热路径】。已部署待实测：墙后站怪时女仆不再对墙挥刀而是绕过去（走位照旧），绕到有视线的那一刻立刻开打；近身横扫/自保反击/空袭范围命中同样不再穿墙；开阔地带正常战斗观感不变。
v1.2.0 鞘翅渲染附魔光泽 + 绑定 TLM「显示背部物品」根因修复（两树同步）：①【需求】"可以让鞘翅渲染出附魔光泽吗？同时绑定 tlm 的显示背部物品来决定是否渲染出鞘翅。"②【附魔光泽：原版本来就有通道，只是传的是"有没有真附魔"】原版 ElytraLayer 调 ItemRenderer.m_115184_(buffer, type, false, stack.m_41790_())（1.21.1 是 getArmorFoilBuffer(..., stack.hasFoil())）——第 4 / 第 3 个参数就是 hasFoil：字节码实证为 true 时额外复合一层 glint 渲染类型（1.20.1 armor_entity_glint / 1.21.1 RenderType.armorEntityGlint），为 false 时直接返回原 buffer。③【改前两树还不一致，且都不亮】1.20.1 两处图层传 chest.m_41790_()（只有真附魔过的鞘翅才亮，普通鞘翅全无光泽）；1.21.1 两处图层硬编码 false（永远不亮）。现在四个图层统一固定传 true = 常亮，与本模组手册/排班表/协议源石的"常亮光泽"口径一致；想改回"只有附魔鞘翅才亮"就把 true 换回 chest.m_41790_()（1.20.1）/ chest.hasFoil()（1.21.1），四个文件里都就地留了注释。④【绑定「显示背部物品」】TLM 女仆配置页那一项 = lang 键 gui.touhou_little_maid.maid_config.show_back_item（两树同名）= 显示背部物品，落点 EntityMaid.getConfigManager().isShowBackItem()；字节码实证它读同步实体数据 EntityMaid.BACK_ITEM_SHOW，在 defineSynchedData 里默认值 iconst_1 = true，所以绑定后默认行为与旧版完全一致，只有玩家主动关掉那一项才会消失（两树 API 同名同签名，javap 实证 MaidConfigManager.isShowBackItem():boolean 均 public）。鞘翅画在女仆背上本就属于"背部物品"——TLM 自己的 LayerMaidBackItem / GeckoLayerMaidBackItem 正是在 isShowBackItem() 这个条件下绘制的，跟着走才是同一口径；四个图层（两树 × Bedrock/Gecko）都在"任务为飞行作战 + 胸甲槽是可用鞘翅"之后追加了这道判定。⑤【验证】两树编译零错（1.20.1 EXITCODE=0；1.21.1 exit=0 仅 16 条既有警告）；javap -p -c 反汇编构建产物，四个 class 逐一确认：含 getConfigManager + isShowBackItem 调用、含 m_115184_/getArmorFoilBuffer 调用且其光泽参数位为 iconst_1、m_41790_/hasFoil 残留为 False（证明是把旧参数换掉而非只加不改）；build 脚本 verify_jar_classes OK + lang json OK；deploy_all.py 三处 match=True；test_server.py 1201 PASS（Done 2.815s）与 neoforge1211 PASS（Done 1.030s）。⑥【注意：附魔光泽是纯客户端渲染，服务端看不到也无需同步；「显示背部物品」是 TLM 已有的同步实体数据，多人下由 TLM 自己同步——本模组不新增任何网络包】。已部署待实测：穿鞘翅/空袭激活后翅膀带附魔流光；女仆配置页关掉「显示背部物品」→ 翅膀消失、重新打开恢复；尺寸/上移 0.7 格/展翅等既有外观不受影响。
v1.2.0 远程空袭新增"近身弹开"【3 格内有怪就给她一个远离怪物的速度矢量】新机制（两树同步）：①【需求】"远程空袭激活后需要再加一个机制：周围三格内出现怪物时女仆被弹开（或强制增加一个远离怪物的速度矢量），防止她在远程攻击时还采用向敌人飞的策略、下落时被直接打死。女仆自己被弹开更加平衡，弹开敌人太超模（也保证狭小空间内敌人仍有命中的可能）。"②【为什么需要】远程空袭的盘旋 faceOrbit 只做"绕半径10格的圈 + 按高度偏差调俯仰"，切向分量天然带"向敌"横向速度，怪物贴过来（或她被地形/烟花推力挤过去）时盘旋会让她贴着怪物转，而她只有20血；起飞那次"背离+向上"的推力只在起飞有效。③【最关键实现点：必须同时改速度+改朝向】滑翔物理在 LivingEntity.travel 的 isFallFlying 分支（反编译实证，1.20.1 在 :1946 起）：每 tick 做一次 `速度 += (视线水平单位向量 × 当前速率 - 速度水平分量) × 0.1`——持续把水平速度往"视线方向"拽。所以只压速度不改朝向：视线仍指敌人，一两 tick 就被这份转向力拉回"朝敌人"，等于没弹；只改朝向不压速度则起步太慢（10%/tick）。两者一起给才是"立刻离开+持续保持"；也正因这份转向力，朝向与推力必须引用同一个威胁，否则自相拉扯（朝A飞被B推）——实现上让 pushAwayFromThreat 把"该背离的威胁"作为返回值交给调用方摆朝向。④【参数取舍】触发半径3格（需求原话）；水平速度0.55格/tick、【覆盖式非叠加】（鞘翅水平巡航约0.4~0.8，0.55 可在一两 tick 内把向敌压反向且仍是连续弧线；叠加会让反复触发时越滚越大变成"被弹飞"）；向上+0.25（抬离近战竖直包线，竖直保留原值再抬不往地面压）；持续30 tick=1.5秒（盘旋向敌分量每 tick 都在拉，只弹一 tick 立刻被拉回）；只在 isFallFlying() 时生效（落地/骑乘不叠加速度）。⑤【只弹女仆不弹怪物】需求明确否定后者：弹开敌人等于远程角色获得持续、无需操作的群体击退，太超模；弹开自己是"用机动换安全"——离开的同时也脱离输出位，且在狭小空间（墙角/洞穴）跑不掉，敌人仍有机会命中。⑥【威胁判据对齐既有口径】只认真威胁：Enemy → 已记仇中立生物（NeutralMob.m_21660_() / neo isAngry()，走 AutoCombatSwitch.neutralAngry 同款防御封装，模组 getter 抛异常不炸 tick）→ 正在锁定她或她主人的任意 Mob（魔改生物靠这条兜住）；并用 FriendlyFireGuard.isFriendly 先排除主人/同主女仆/友军，绝不弹开自己人。⑦【开关与文档】新增配置 combat.flightRangedPush（默认开）+ 配置面板"远程空袭近身弹开"一行 + 四个 lang/*.json 补 config.promaid.combat.flightRangedPush（中英两树）；弹开是高频事件，日志按5秒/女仆限频。⑧【验证】两树编译零错（过程中修掉两处真实问题：NeutralMob 记仇 getter 我一开始误用 m_21672_()、实为 m_21660_()；滑翔判定一开始误用 m_20161_()，反编译证实它是 m_6144_()、与滑翔无关，正确名是 m_21255_()——本项目 MaidFlightKit/EntityFlagInvoker/MaidSwimGlideMixin 全用这个名）；javap -p -c 反汇编构建产物按"真正的声明行"校验：tickRangedAir 同时含 pushAwayFromThreat/faceAwayAndUp/faceOrbit/faceUpForward（弹开分支在、原盘旋分支也在，是二选一而非替换）；pushAwayFromThreat 含 COMBAT_FLIGHT_RANGED_PUSH、m_21255_/isFallFlying、findNearestThreat、applyAwayVelocity、logPushThrottled；applyAwayVelocity 含 set/getDeltaMovement；isThreat 含 Enemy/NeutralMob/记仇方法/目标锁定方法——两树全部命中；deploy_all.py 三处 match=true；test_server.py 1201 与 neoforge1211 均 PASS。已部署待实测：远程空袭盘旋时怪物进3格内女仆立刻往反方向飘1.5秒（日志 [远程空袭] xxx 近身弹开（2.4 格：zombie），5秒限频），脱离后自动恢复盘旋；关掉配置项即完全回到旧行为。
v1.2.0 烟花检测的副手覆盖核查【副手本来就查了；顺带补上"攻击性烟花"漏查的主手】根因修复（两树同步）：①【反馈】"检测烟花火箭的时候似乎没有检测副手。"②【逐条核查：副手确实查了】前提已用字节码钉死——LivingEntity.m_21206_() 反编译 = return this.m_6844_(EquipmentSlot.OFFHAND)，即 m_21206_ 就是副手；EquipmentSlot.values() 的 <clinit> 常量创建顺序 = MAINHAND,OFFHAND,FEET,LEGS,CHEST,HEAD，而 EntityHandsInvWrapper 只保留 Type.HAND 的槽并照该顺序装进 slots 列表 → getHandsInvWrapper() 的 slot 0 = 主手、slot 1 = 副手。四处烟花函数的覆盖面（改动前）：hasFirework 主手✓(m_21205_)/副手✓(m_21206_)/背包✓；takeFirework 主手✓(slot0)/副手✓(slot1)/背包✓；hasExplosiveFirework 主手✗缺/副手✓/背包✓；takeExplosiveFirework 主手✗缺/副手✓/背包✓——即"副手没被检测"在代码里不成立，反倒是四百九十九新增的那对"攻击性烟花"函数漏了主手（方向相反）。另确认消耗路径两次调用（起跳/远战补烟花各一处）走的都是 takeFirework，副手在 slot 1 是第一优先，所以"副手放烟花却不生效"也不是这条链路的问题。③【顺手修掉的真实不一致】hasExplosiveFirework/takeExplosiveFirework 只查"副手+背包"，而 hasFirework/takeFirework 是"主手+副手+背包"三处都认——同一口径两套覆盖面是隐患，具体场景：主手拿着带爆炸的烟花、弩放背包里时，resolveRangedWeapon 会返回背包那把弩（规则是"主手已是本任务合法武器才用主手"，而烟花不是武器），那一刻弹药就在主手上，旧代码只扫副手 → 判成"缺弹药" → 远程空袭不激活、气泡报"缺弹药"。修法：补齐为与 hasFirework/takeFirework 完全一致的三处覆盖面，取用顺序也照抄（副手→主手→背包），"副手优先"这条原版口径保留不变。④【验证】两树编译零错；javap -p -c 反汇编构建产物确认四个函数主手/副手/背包三处全部为 True，takeExplosiveFirework 字节码里可见 iconst_1→getStackInSlot(1)（副手）紧跟 iconst_0→getStackInSlot(0)（主手）最后 takeOneFromBackpack；out/ 的 MaidFlightKit.class 与 jar 内该类 SHA-1 逐一比对相同（防"改源码却打旧字节码"）；deploy_all.py 三处 match=true；test_server.py 1201 与 neoforge1211 均 PASS。⑤【待补充】"检测烟花没查副手"在代码里找不到对应路径（四处都查了副手，见上表）——若现象仍在，请给一句话复现步骤（什么任务、烟花放哪只手、看到什么）：是切任务时气泡报"缺烟花火箭"？是副手那枚没被消耗？是 1.21.1 重锤猛击链路（那查的是风弹不是烟花）？还是别的界面在判断烟花？
v1.2.0 御币被误判"缺弹药"【它是 ProjectileWeaponItem 的子类，被"数箭"那一路吃掉了】根因修复（两树同步）：①【反馈】"检测远程武器御币的时候会显示没有弹药。明明这个武器不需要弹药来驱动的。"②【根因·判据顺序】MaidFlightKit.hasAmmoForRanged 的注释本就把御币归在"不消耗弹药"那一类（弹幕用武器本体），最后也写了 `// 御币 / 三叉戟 / 其它：不消耗弹药 → 放行`，但那条兜底排在 ProjectileWeaponItem 分支之后，而御币恰恰是这个类的子类（ItemHakureiGohei extends ProjectileWeaponItem，两版 TLM 字节码实证）——所以它走不到兜底，落到"数箭"分支 hasArrowFor：副手不是箭→背包按 supportedProjectiles 找箭→再兜底找任意箭→都没有就返回 false→ 判定"缺弹药"→ 远程空袭不激活（missingParts 于是报出"弹药"那一项）。③【三条旁证把路径钉死】(a) 御币自己的弹药谓词 m_6437_()/getAllSupportedProjectiles() 是 Predicates.alwaysTrue()（反编译逐字）——它压根没有"专用弹药"这个概念；(b) 御币 1.20.1 没有覆写 shootProjectile/m_6394_（空实现），说明它不走原版箭矢通道，硬塞箭进去也没意义；(c) TLM 自己的 TaskDanmakuAttack 全部成员里没有任何 hasArrow 之类的弹药判据（javap 实证），只有 hasGohei（查的是"有没有御币"）。即原版/TLM 都没有"御币要箭"这个前提，是我们自己那条门禁的判定顺序把它卷进去了。④【改法】判据顺序改为（两树同步）：枪械 → 御币 → 三叉戟 → 弩 → 其它弹射武器 → 放行。御币新增判定用 TLM 自带的 ItemHakureiGohei.isGohei(stack)，与开火路径 MaidFlightRangedTask#isGohei 同一口径（门禁与开火必须一致，否则会出现"判定有弹药却没按弹幕打"或"能打弹幕却不起飞"）；三叉戟本来就不是 ProjectileWeaponItem、走不到那条分支，但显式写出来，让门禁与开火路径三条"无需弹药"通道逐条对齐、以后改动不漏；MaidFlightKit 新增 public 助手 isGohei(ItemStack)。只动判定顺序，不动伤害/弹幕/激活条件——御币该走 shootDanmaku 照样走（那条分流本来就在 shootArrow 之前，顺序是对的），这次修的是门禁那一侧。⑤【验证】两树编译零错；javap -p -c 反汇编构建产物按常量池判定调用序列校正：21:GunCompat.isGun、33:isGohei、45:instanceof TridentItem、57:instanceof CrossbowItem、82:instanceof ProjectileWeaponItem(→hasArrowFor)，两树都实测 isGohei 与 TridentItem 都排在 ProjectileWeaponItem 之前（三项顺序断言全部 True），isGohei 方法已就位；deploy_all.py 三处 match=true；test_server.py 1201 与 neoforge1211 均 PASS。已部署待实测：远程空袭持御币时不再报"缺弹药"、能正常起飞并按弹幕开火（与她自己用弹幕任务时一致）；弓/弩仍照旧要求箭（弩还认攻击性烟花）；不带御币的配置不受影响。
v1.2.0 空袭适配拔刀剑【TLM 的拔刀斩门控在她的"地面攻击任务"上，空袭任务永远进不去】根因修复（两树同步）：①【反馈】"空袭技能目前不适配拔刀剑"。②【根因一·门控】TLM 对拔刀剑的支持只有一处：EntityMaid.swing()（1.20.1 m_6674_）开头调用 SlashBladeCompat.swingSlashBlade(maid,主手)，而那个方法体第一步就是 if (isSlashBladeItem(stack) && maid.getTask().getUid().equals(TaskAttack.UID)) —— TaskAttack.UID 的静态初始化字节码是 new ResourceLocation("touhou_little_maid","attack")；我们的飞行任务 UID 是 maid_smart:flight_combat / flight_ranged，这个 equals 恒 false → 女仆在空袭里挥刀，拔刀斩一次都不会触发（不是"触发得少"，是根本不进那段代码）；同一个女仆换成地面攻击任务却能触发。③【根因二·缺倍率】MaidFlightCombatBehavior#hitOne 的伤害是 ATTACK_DAMAGE×暴击1.5+附魔，而拔刀剑自己的口径（AttackHelper.calculateTotalDamage 反编译）是 (ATTACK_DAMAGE+横扫加成+段位加成+附魔加成)×comboRatio×getSlashBladeDamageScale(攻击者)×SLASHBLADE_DAMAGE_MULTIPLIER，getSlashBladeDamageScale 读的就是拔刀剑注册的 SLASHBLADE_DAMAGE 属性（默认1.0、随练度/段位成长）——我们那条通道整段没有这个乘数。④【改法】新增 com.maidsmart.combat.SlashBladeCompat（全反射），在我们自己的挥刀点复刻 TLM 同一段调用：roll=random.nextInt(60)-30；AttackManager.doSlash(maid, roll, Vec3.ZERO, mute=false, critical=false, comboRatio=1.0, KnockBacks.smash)；再记一次 BLADESTATE.setLastActionTime(level.getGameTime())。doSlash 生成的 EntitySlashEffect 自己按拔刀剑完整公式结算伤害（EntitySlashEffect.tick→AttackManager.areaAttack→AttackHelper.attack），所以根因二那条缺口被同一调用一并补上；刻意不再往 hitOne 里乘倍率（否则变成"原版伤害+拔刀斩伤害"叠乘，比玩家与 TLM 女仆都强）。挂载点两处：smashHit（收翅俯冲，空袭主体）与 groundMelee（落地后贴身近战退路——只补俯冲会留下"落地就变哑巴"的半截体验）；全反射的原因：compile_promaid.txt / compile_neo.txt 的 classpath 里都没有 slashblade（已核对），模组也不保证装，直接 import 会编译不过；符号在 ModList.isLoaded("slashblade") 之后一次性缓存，缺模组时一次布尔判断即返回。doSlash 在 AttackManager 里有 7 个重载，按参数名盲选会静默失败（IllegalArgumentException），故按精确签名 (LivingEntity, float, Vec3, boolean, boolean, double, KnockBacks) 定位。⑤【1.21.1 侧额外实情】1.21.1 的 TLM 1.5.3 完全没有拔刀剑兼容代码（jar 内常量池扫 slashblade 零命中，1.20.1 那份 SlashBladeCompat/SlashBladeRender 在 neo 版不存在）——即 1.21.1 上"女仆持拔刀剑"本来就没有官方联动、连地面攻击任务都不触发拔刀斩；本兼容层挂在我们自己的挥刀点上、不依赖 TLM 门控，所以在 1.21.1 上是"同时补上地面与空袭"的净新增。另：1.21.1 的拔刀剑 2.0.7 已无 CapabilitySlashBlade 类（capability 包改成 BladeStateAccess/SlashBladeDataComponents），故状态入口走 BladeStateAccess.of(ItemStack) 静态方法。⑥【主人免伤】doSlash 的伤害来源是 damageSources().mobAttack(女仆)（AttackHelper.attack 非玩家分支，反编译实证 attacker.m_269291_().m_269333_(attacker)，m_269333_=mobAttack）→ 加害者就是女仆 → 已有的 FriendlyFireGuard 会拦掉主人/友方，无需新增免伤代码；另有两层天然保险：拔刀剑默认 pvp_enable=false、friendly_enable=false，其目标筛选器 TargetSelector$AttackablePredicate 只打 Enemy。⑦【验证】两树编译零错（新增类需重跑 gen_compile.py/gen_compile_neo.py 才进编译清单，首次报"找不到符号"即此因，已处理）；对真实 jar 起 JVM 逐个校验反射符号（initialize=false 不触发 mod 静态初始化）：1.20.1 11/11、1.21.1 5/5 全通过，含 doSlash 重载数=7 且精确命中 7 参那条、ItemSlashBlade 父类=SwordItem、状态入口两版各自正确；javap -p -c 反汇编构建产物确认 SlashBladeCompat 三方法就位、MaidFlightCombatBehavior 的 smashHit 与 groundMelee 各含一次 invokestatic swingSlash（两树 2 处）；1.20.1 测试服装着拔刀剑（启动日志实证 slashblade 1.9.65 + mrqxs_Slashblade_Core-1.4.1），回归 PASS 且启动无异常；deploy_all.py 三处 match=true；test_server.py 1201 与 neoforge1211 均 PASS。已部署待实测（1.20.1）：空袭持拔刀剑时俯冲那一记与落地近战都会带出拔刀斩（有伤害、有刀光）；持其它武器不受影响；没装拔刀剑的实例零开销、行为与之前一致。注：1.21.1 侧客户端实例里拔刀剑本体是 .disabled 状态（玩法层面无法在客户端实测），但 NeoForge 测试服是启用状态（mods 下两个拔刀剑 jar 均无 .disabled），本模组 SlashBladeCompat 在该服上随模组加载、启动与回归全程无异常——即"装了拔刀剑的 1.21.1 服务端"这条路径实测过；反射符号另按 2.0.7 真实 jar 逐个校验。
v1.2.0 弩无法发射攻击性烟花火箭【飞行远战任务的武器分流里压根没有"弩"这一路】根因修复（两树同步）：①【反馈】"在使用弩的时候没有办法发射攻击性烟花火箭"。②【根因】MaidFlightRangedTask.performRangedAttack 的分流是 枪械→三叉戟→ProjectileWeaponItem→御币→shootArrow，弩属于 ProjectileWeaponItem 因此必然落到 shootArrow，而 shootArrow 只认 ArrowItem：1.21.1 的 findAmmo 第一站是 maid.getProjectile(主手)，TLM 的 EntityMaid.getProjectile 在副手是烟花时就把副手那叠烟花交出来（TLM 给女仆做弩的官方口径，字节码实证），拿回来却被 instanceof ArrowItem 判掉→退化成一支普通箭，最后 arrowStack.shrink(1) 还把这枚烟花消耗掉了（表现为"烟花少一枚、飞出去一支箭"）；1.20.1 的 findArrow 第一站是副手，同样只认 ArrowItem，副手烟花判不过、背包再没箭就返回空→shootArrow 直接 return，一枪都放不出来。原版（CrossbowItem.createProjectile 有专门的烟花分支）和 TLM（TaskCrossBowAttack.hasAmmunition 把副手烟花算弹药，1.21.1 还有 MixinCrossbowItem 给女仆做弩的瞄准）本来都支持，唯独我们自己那条飞行远战通道漏了。③【必须处理的撞车】副手烟花既是"原版口径的弩弹药"又是"本模组的飞行燃料"（MaidFlightKit.equip 副手槽 + MaidFlightCombatBehavior#launchFirework 优先消耗副手），而【不带爆炸（Explosions）的烟花打出去是 0 伤害】（FireworkRocketEntity.dealExplosionDamage 开头就是 if (!this.hasExplosion()) return，字节码实证），拿它开火等于白烧一份飞行燃料+空中掉高风险——所以弩的弹药只认"攻击性"烟花。④【改法】MaidFlightKit 新增 isExplosiveFirework（1.20.1 读 NBT Fireworks.Explosions，与 FireworkRocketEntity 自己的读法一致；1.21.1 读组件 DataComponents.FIREWORKS.explosions()）、hasExplosiveFirework（只查不取）、takeExplosiveFirework（取1枚：副手优先=原版口径，背包路径只抽1枚绝不整叠拿走）；弹药门禁 hasAmmoForRanged 的弩分支同步改为"有攻击性烟花 或 有箭"（门禁与开火路径必须同口径，否则会出现"判定有弹药、起飞后一发打不出来"的死角）；MaidFlightRangedTask 新增弩分支并排在 shootArrow 之前，shootCrossbowFirework 逐点对齐原版+TLM：弹体 = new FireworkRocketEntity(level, 弹药, 女仆, x, 眼高-0.15, z, true)（原版 createProjectile 烟花分支逐字一致，末位 true = shotAtAngle → 命中即爆、不给射手推力，不是给滑翔加速的挂载烟花）、瞄准取双方眼高差 + setNoGravity(true) 直线飞、速度 clamp(距离/10,1.6,3.2)、散布 1-clamp(距离/100,0,0.9)（TLM 女仆弩口径）、耐久扣 3（原版烟花分支，射箭是 1）、音效 CROSSBOW_SHOOT（音高带±0.4随机）、顺序=先取弹药→立即建弹体入世界→再扣耐久（取弹与入世界之间只有算术、没有任何可能失败的分支，不存在"烟花扣了却打不出去"的窗口）。⑤【主人免伤】烟花是爆炸伤害、DamageSources.fireworks(烟花, 女仆) 的造成者就是女仆，会被已有的 FriendlyFireGuard 拦下，无需新增免伤代码。⑥【验证】两树编译零错；javap -p -c 反汇编构建产物确认 MaidFlightRangedTask 有 instanceof CrossbowItem + shootCrossbowFirework 且排在 shootArrow 之前、MaidFlightKit 三个新接口就位且 isExplosiveFirework 被三处引用（3/3）、烟花判定路径分别引用 Explosions/FIREWORKS；deploy_all.py 三处 match=true；test_server.py 1201 与 neoforge1211 回归均 PASS。已部署待实测：飞行远战下弩+攻击性烟花→打真烟花（命中即爆、有伤害）；弩+只有箭→照旧射箭；弩+只有普通烟花（无爆炸）且没箭→判为缺弹药不开火，不会烧掉飞行燃料。
v1.2.0 悬空/滑翔禁搭方块【收紧：滑翔被放行、普通悬空只拦深坠落】根因修复（两树同步）：①【反馈】"女仆似乎还是会在悬空和滑翔状态下搭方块"。②【根因·两处漏口，都在 MaidPlaceGuard.blocked 的口径里】四百四十三的判定是"未落地 &&（重锤跃起 || 坠落距离 ≥ 落地水触发高度）"：(a) isFallFlying() 与"站在地面/水里/骑乘"并列在【放行名单】里——空袭期间她本来就在滑翔，所以"滑翔中搭方块"被整条放行；(b) 普通悬空只拦"坠落距离 ≥ combat.waterFallDistance（默认 6 格）"，3~5 格的悬空下落照样放行；而滑翔中 LivingEntity.travel 每 tick 调 Entity.m_245125_() 把 fallDistance 钳在最多 1.0，所以就算把滑翔从放行名单拿掉、只留那条阈值，滑翔期也永远不会触发——必须单独判滑翔位。③【为什么空袭期真的会搭】搭路行为 BridgeUpBehavior 是 core 245（任何 activity 都跑），自保虽在飞行任务下被硬闸关掉，搭路却没有；空袭期间只要脑内暂无攻击目标，搭路就会启动并朝主人/前方缺口铺块——正是玩家看到的"悬空搭方块"。④【改法】MaidPlaceGuard.blocked 重写：未落地且不在水/岩浆/骑乘时，(a) 滑翔或飞行作战空中（MaidFlightKit.isFlightAirborne，含收翅猛击/被击落盘旋）→ 禁；(b) 【1.21.1】重锤跃起中（MaidMaceSmashBehavior.isAirborne）→ 禁；(c) 正在下落（fallDistance > 0）→ 禁（旧版要坠够 6 格才禁）。上升段 fallDistance == 0 不受影响，所以站在地面/浅跳垫脚、搭路把自己顶上去这些正常链路照常工作。⑤【覆盖面】四个搭方块模块（自保搭高·搭路·挖矿垫脚·伐木垫脚）的 takeBuildBlock 全部先问闸口（逐条核对：两树各 4/4 就位），被禁即返回 null → 不消耗方块、不改世界；取料失败气泡同样静默。⑥【不拦】落地水/细雪（WaterClutchBehavior 直接放水，是本模组防摔死的保命机制）、照明光块、农耕播种、插火把（要求目标格脚下有实心支撑面且贴着主人）、AI 工具 smart_place（玩家显式指令）。⑦【验证】两树编译零错；javap -c 反汇编构建产物确认 MaidPlaceGuard 里已是 isFlightAirborne + isAirborne + fallDistance>0 三段，且 isFallFlying/m_20161_ 已彻底消失；deploy_all.py 三处 match=True；test_server.py 1201 与 neoforge1211 回归均 PASS。已部署待实测：空袭（近战/远战）飞行期间不再搭方块；正常挖矿/伐木垫脚、搭路、浅跳垫高不受影响。
v1.2.0 1.21.1 女仆模型【同 domain 的模型包只活一个，其余整包模型从选择界面消失】根因修复（两树同步）：①【反馈】"1.21.1 版本女仆选择模型里面出现了问题……有很多模型被隐藏了"。②【根因·TLM 字节码 + 磁盘双实证】模型包 id 就是 assets/ 下的域名目录名（CustomPackLoader.loadMaidModelPack → pack.decorate(domain)）；MaidModels.sortPackList() 先对 DefaultPackConstant.MAID_SORT = [touhou_little_maid, touhou_little_maid_old, touhou_little_maid_seihou, geckolib, authors_and_credits, minecraft_15th] 的每个 id 用 findFirst() 只收第一个包，再用 !MAID_SORT.contains(id) 过滤后半段——同 id 的第二个包两头都不在，直接从 packList 里消失；而 GUI 是按包遍历 getModelList() 的（搜索模式的全量表也按包拼），于是整包模型一起"被隐藏"。③【为什么只有 1.21.1】磁盘实测：1.21.1 实例 tlm_custom_pack 里有【两个】domain=geckolib 的女仆包（maidspell_geckolib_models-1.0.0 的 3 个 + touhou_little_maid-1.0.0 的 27 个），客户端日志实测 maidspell 那个先加载 → 内置 geckolib 包（声明 27 个 / 注册 41 个 id：winefox 全家族 + zhiban 系列 + hailuo_new_year + kluonoa + foxmaid + rice_cake_fox）整包从界面消失；1.20.1 实例只有内置那一个 geckolib 包，实测丢包 0（对照组成立）。④【改法】新增客户端 mixin MaidModelPackSortMixin（两树同源，登记在 mixins.promaid.json 的 client 段）：@Inject(sortPackList, HEAD, cancellable) 用"先按 MAID_SORT 名单顺序收齐同 id 的全部包（保持加载顺序）、其余包按 id 排序跟在后面"替换原实现，唯一语义变化是"不再丢弃"。⑤【实测证据】SortDemo 直接加载 TLM jar 里的 DefaultPackConstant / CustomModelPack 跑两套算法：1.21.1 输入 7 包 → 原版 6 包存活（丢掉内置 geckolib 的 27 个声明模型），本模组算法 7/7、丢包 0；1.20.1 输入 6 包 → 两套算法都是 6/6。⑥【未动】椅子模型（ChairModels.sortPackList + CHAIR_SORT）是同一份逻辑、同样的坑，但用户包内没有第二份椅子域名（磁盘实测），本次不改以免扩大改动面。⑦【验证】两树编译零错（229 / 231 个源文件）；jar 重建并逐项核对（新类已入包 + client 段已登记 + javap 确认 getPackList / MAID_SORT / getId / ci.cancel 字节码）；deploy_all.py 三处 match=True；test_server.py 1201 PASS（Done 3.199s）、neoforge1211 PASS（Done 0.937s）；把本条 changelog 打进 jar（重新打包）后复测仍 PASS（Done 2.847s / 0.976s）。已部署待实测：打开女仆模型选择界面，geckolib 页应能看到 27 个内置模型（winefox 全家族等）。
v1.2.0 空袭鞘翅【一穿上就渲染，不再需要先起飞一次】：①【反馈】1.20.1 版本女仆必须起飞一次才会把鞘翅渲染出来，应该一穿上就渲染。②【渲染层本身没问题】两树 LayerMaidElytra / LayerMaidElytraGecko 的显示条件只有三件：isInvisible==false && MaidFlightKit.isFlightTask(maid) && isUsableElytra(胸甲槽)——没有任何"必须离地/必须滑翔"的额外条件，故"穿上即渲染"在渲染侧本来成立，问题在于有没有被穿上。③【根因·代码路径实证】全局搜索确认胸甲槽的唯一写入者是 MaidFlightKit.equip()（两树各一处 m_8061_(EquipmentSlot.CHEST,ely) / setItemSlot(EquipmentSlot.CHEST,ely)），而它此前只在飞行作战行为里调用，那个 tick 开头是 currentTarget(maid)==null 就 endFlightSafely+return——没敌人时永远走不到 equip。因果链：切到空袭任务→还没遇敌→tick 在 target==null 处返回→equip 从未执行→胸甲槽无鞘翅→渲染层看不到→直到第一次接敌起飞（equip 终于跑一次）才出现。MaidToolAutoEquipBehavior（core 行为，每 tick 都跑）虽会进入飞行任务分支，但源码注释明写"本分支只提示、不擅自换装（换装仍由 MaidFlightKit.equip 在行为里做）"，故没兜住。④【改法】两树 MaidToolAutoEquipBehavior 的飞行任务分支里，先调一次 MaidFlightKit.equip(maid) 再 notifyNotReady。安全性（已核对源码）：equip 幂等——三段都先判是否已就位（胸甲已可用鞘翅/主手已是本任务合法武器/副手已是烟花），就位即整段跳过零开销，故每 tick 调用不会反复换装；换下的旧装备走 giveBack 塞回背包空格、无空格才落地(m_5552_)，不丢物品；与战斗行为里那次调用互不冲突（同一份幂等逻辑），战斗行为保留原调用（它还要用返回值判三件是否齐备）。⑤验证：两树编译零错；字节码校验两树 MaidToolAutoEquipBehavior 的 checkExtraStartConditions 依次出现 isFlightTask → equip → notifyNotReady；deploy_all.py 三处 match=True；test_server.py 1201 PASS(2.734s)、neoforge1211 PASS(0.930s)。⑥待实测：把女仆切成空袭任务（附近无敌人）鞘翅应立刻出现在背上、不再需要先起飞一次；切回其它任务鞘翅应随任务切换脱下（equip 只在飞行分支调）；接敌后滑翔/收翅的展翅表现不受影响（渲染层展翅逻辑本次未改）。
v1.2.0 远程空袭【激活时检测弹药，没弹药就不起飞】：①【反馈】远程空袭激活时还需要检测一下有没有对应的弹药，否则没必要起飞。②【现状】isModeActive 原来只判鞘翅+武器+烟花三件，远程空袭会在背包一支箭/一颗子弹都没有时照常起飞、升空盘旋却一发都打不出来——白烧烟花、白暴露在敌方火力下。③【关键·不能一刀切，TLM 反编译实证】远程武器里只有一部分消耗弹药：弓 TaskBowAttack 有 hasArrow（ItemsUtil.findStackSlot(inv, bow.m_6437_())）、弩 TaskCrossBowAttack 有 hasAmmunition（箭 或 烟花火箭）、而御币 TaskDanmakuAttack 与三叉戟 TaskTridentAttack 都【没有】弹药门禁（弹幕不耗弹药、投出去的是武器自身副本）；枪械另有既有判据 GunCompat.hasGunAndAmmo（已正确豁免卓越前线能量武器的内部充能）。故本模组门禁只对真吃弹药的武器生效：弓/弩认箭、枪认子弹，御币/三叉戟/能量枪一律放行——若对它们也强加门禁会造出更糟的新 bug（持御币/三叉戟的女仆永远判定缺弹药、永远不起飞）。④【改法】新增 MaidFlightKit.hasAmmoForRanged（两树），箭的判据与开火路径 MaidFlightRangedTask#findArrow/findAmmo 的三层一一对齐（副手箭 → 武器 supportedProjectiles 认可的弹药 → 背包任意箭），保证激活检测与能否打出去同口径；isModeActive 近战不变、远程追加弹药要求；missingParts 远程缺弹药时额外报出「弹药」，否则玩家只看到三件齐了却没起飞、不知为何。⑤【实现时规避的陷阱】isModeActive 在 equip() 之前调用，那一刻主手可能还是空的（弓和箭都在背包），直接用主手判弹药会把这配置误判成缺弹药→永远不激活；故新增 resolveRangedWeapon 逐字照抄 equip() 的选武器规则（主手已是本任务合法武器就不换，否则取背包第一把合法的）再判。⑥验证：新用符号逐个 javap 核对编译期真实 jar 存在（m_6437_/getAllSupportedProjectiles/CrossbowItem/FireworkRocketItem/ArrowItem）；两树编译零错；字节码校验两树 MaidFlightKit 均含 hasAmmoForRanged/resolveRangedWeapon/hasArrowFor 且常量池含 ProjectileWeaponItem/CrossbowItem/FireworkRocketItem/GunCompat.hasGunAndAmmo 引用与缺件文案「弹药」；deploy_all.py 三处 match=True；test_server.py 1201 PASS(2.735s)、neoforge1211 PASS(0.783s)。⑦待实测：远程空袭空手或无箭时不起飞并报「缺弹药」，放箭后正常起飞开火；御币/三叉戟/枪械（含能量武器）无箭也照常激活；弩+副手烟花算有弹药；近战空袭不查弹药不受影响。
v1.2.0 空袭落地水/雪【改成重锤同款特殊落地缓冲】+ 新增空袭免摔开关：①【反馈】女仆空袭时的落地水/雪需要改正为和重锤状态下一样的特殊落地水，一直防止女仆摔死；同时加一个配置开关可直接关掉空袭状态下的摔落伤害（默认关闭）。②【先说清重锤那套】重锤跃起落地时行为置位 FORCED_CLUTCH，由 WaterClutchBehavior（core 240，在重锤 235 之后 tick）同 tick 在落点强制放一格水/细雪——不看 fallDistance 阈值、不看抑制条件（猛击加成此刻已结算完，放水只负责不摔）。③【空袭根因·两树不同】(a) 1.21.1：MaidMaceSmashBehavior.isAirborne = isLeaping || MaidFlightKit.isFlightAirborne 把飞行也并进"空中"，于是落地水把它当"重锤跃起中"直接 return（让位保住 fallDistance），但飞行侧从不置位 FORCED_CLUTCH → 空袭落地完全没有落地水/雪、纯硬摔；(b) 1.20.1：该树无重锤类、通用落地水仍在跑，但通用逻辑按 fallDistance>=阈值 触发，而滑翔中 LivingEntity.travel 每 tick 把 fallDistance 钳在 ~1.0（本模组多处已实证）、远低于默认阈值 3 → 空袭里几乎不触发。④【改法一·两树】把"重锤跃起让位"与"空袭落地缓冲"拆开判，不再共用一个 isAirborne：跃起中（isLeaping）仍完全让位（保住 fallDistance 给猛击）；重锤落地帧（consumeForcedClutch）先判（落地那 tick 两标志同时为真，顺序不能反）原语义不变；空袭（新增）的落点帧改由落地水自己判——未落地+正在下坠+脚下 1~2 格内有地面（照抄重锤 isNearGround 同款判据），不看 fallDistance 阈值（滑翔钳在 ~1.0，按阈值判永不触发，这正是 1.20.1 旧版接不住的原因），有水桶（非下界）/细雪桶即强制放一格，与重锤落地帧完全一致。⑤【改法二·新开关】combat.flightNoFallDamage（默认关，用户明确要求）：复用 MaidFlightWallGuard（原负责飞行免疫鞘翅撞击伤害），同套 message_id 手法新增 fall 分支；fall.json 的 message_id 两版都是 "fall"（1.20.1 与 1.21.1 版本目录 jar 逐个开包核对 68/79 个 damage_type json，与既有 flyIntoWall 同样跨版本稳定）；只作用于飞行任务、不影响普通坠落；触发有日志（搜「空袭免摔」）。面板在"生存与复活"分区紧跟"免疫鞘翅撞击伤害"一行；四个语言文件同步（空袭免疫摔落伤害 / Air Raid: Immune to Fall Damage）。⑥验证：两树编译零错；字节码校验（javap -c 反汇编构建产物）两树 Guard 均含 String "fall" 比较 + COMBAT_FLIGHT_NO_FALL_DAMAGE 字段 + setCanceled（与 flyIntoWall 分支并列）、两树 WaterClutchBehavior 均含空袭分支与 flight clutch trigger 日志；四个 lang JSON 合法；deploy_all.py 三处 match=True；test_server.py 1201 PASS(2.990s)；NeoForge 首跑 TIMEOUT 已定位为新增配置项触发的一次性配置迁移（日志尾部 promaid-common.toml is not correct. Correcting、目录出现 promaid-common.new.tmp.toml），核对迁移后文件确认 flightNoFallDamage=false 已写入且旧键保留，重跑即 PASS(0.996s)，残留 .new.tmp.toml 已清理。⑦待实测：两种空袭高空落地有水桶/细雪桶时应自动放一格接住不摔伤（搜 flight clutch trigger）；收翅猛击伤害加成不应因放水丢失（放水在猛击结算之后）；开关打开后空袭高空摔下完全不掉血（搜空袭免摔）；普通坠落不受该开关影响。
v1.2.0 1.21.1【pack_format 写成了 1.20.1 的值】修复（15 → 34）：①【背景】这是此前主动标出但当时未获授权修改的瑕疵。②【现状】四处 pack.mcmeta（两树各一 + 对应 staging_* 构建产物）原本全部写着 15；构建真源是 promaid_src(/_neo)/pack.mcmeta（build_promaid*.py 第 71/76 行 copy2），staging_* 每次构建会被覆盖。③【1.21.1 正确值 34，三条独立证据一致】(a) 最权威：javap -v 读 vanilla net.minecraft.SharedConstants 的 ConstantValue —— RESOURCE_PACK_FORMAT ConstantValue: int 34、DATA_PACK_FORMAT ConstantValue: int 48（1.20.1 侧字段名被混淆读不到符号名，但同一常量表资源/数据格式均为 15）；(b) TLM 官方 pack.mcmeta：1.20.1 版=15、1.21.1 版=34；(c) 同目录其它 1.21.1 mod：TACZ=48，而写 15 的 Neat(标 1.21)、IMBlocker(标 1.20.6-1.21.8) 都是跨多版本打包、用旧值兼容更宽区间，不能作 1.21.1 单版本目标值。④【修法】只改 promaid_src_neo/pack.mcmeta 的 15→34；1.20.1 那棵本来就是对的、不动。⑤【影响】pack_format 只参与资源包版本匹配校验（不匹配时给"为旧/新版本制作"警告、影响默认启用），不参与任何代码逻辑，不影响玩法/存档/本次其它修复。⑥验证：构建后逐个开包核对 8 个副本（构建产物、三处部署点、两处 staging、两处源码）全部符合预期（1.20.1 系=15、1.21.1 系=34）；首次核验发现"已部署的 1.21.1 仍是 15"（改源码并重建后尚未重新部署），部署后复验通过；deploy_all.py 三处 match=True；test_server.py 1201 与 neoforge1211 均 PASS。⑦待实测：1.21.1 客户端加载时不应再对本模组资源包报"为其它版本制作"警告；Gecko 皮肤列表应与修复前一致（本改动不涉及皮肤资源）。
v1.2.0 飞行攻击【附魔效果核查与补齐】+ 两模式改名：①【反馈】看飞行时攻击能不能触发附魔，不能就做；顺带把两个模式改名为 近战空袭 / 远程空袭。②【近战核查】两树已用 m_44833_（锋利/亡灵/节肢伤害加成）、m_44914_（火焰附加）、m_44823_（荆棘等 doPostAttack），1.21.1 更已走现代 API（modifyDamage/modifyKnockback/doPostAttackEffects）；唯一缺口是 1.20.1 击退量被写死 1.0、没读击退附魔与 ATTACK_KNOCKBACK 属性——已按原版 Mob.m_7327_ 算式补为 (属性+m_44894_)*0.5。③【远战·弓弩 1.20.1 全缺、1.21.1 本就生效】根因（反编译实证）：1.20.1 ArrowItem.m_6394_(level,stack,shooter) 只有三参、不收武器，给箭上附魔是原版 BowItem.releaseUsing 手工写的：Power→m_36781_(m_36789_()+lv*0.5+0.5)、Punch→m_36735_(lv)、Flame→m_20254_(100)，我们旧版造完箭直接射出、这三条从未被调用；1.21.1 则因 createArrow(level,stack,shooter,weapon) 多一个武器参数、存进 firedFromWeapon，命中时由 modifyDamage/modifyKnockback 读取（onHitEntity 374 行 / doKnockback 457 行，数据驱动且无 instanceof Player 门控），我们早已传入 weapon 故一直生效。修法：1.20.1 shootArrow 照抄原版 BowItem 三行（算式逐字一致），两树再补无限附魔（f_44952_/INFINITY，有则不吃箭）。④【远战·御币三个专属附魔两树都缺】TLM 阻碍/神速/末影杀手注册在 GOHEI 类别上（InitEnchantments：EnchantmentCategory.create("gohei", item->item instanceof ItemHakureiGohei)），自身无行为，作用全靠 TaskDanmakuAttack 读等级后传给弹幕 API：speed*=(speedyLevel+1)、setImpedingLevel(impedingLevel)、setHurtEnderman(endersEnderLevel>0)；旧版整段跳过（注释原写"保持与旧版一致：不吃这三个"），本次按用户要求补齐，算式与 TLM 一致（1.20.1 用 EnchantmentHelper.m_44843_，1.21.1 用 EnchantmentKeys.getEnchantmentLevel）。⑤【改名】flight_combat：飞行近战/Flight Melee（1.21.1 英文原为 Flight Combat）→ 近战空袭/Melee Air Raid；flight_ranged：飞行远战/Flight Ranged → 远程空袭/Ranged Air Raid。改了四个 lang 的名称值+desc 首句称呼、两个任务的 getMaidActionSummary()（TLM 任务列表 UI）、运行时日志标签；刻意不改任务 UID（maid_smart:flight_combat / flight_ranged，写进存档的内部标识，改了会让已存档女仆任务失效）；配置里的"飞行作战"是伞形总开关覆盖两模式，不是模式名，保持原样；历史 changelog 按旧名的记录不改写。⑥验证：新用符号全部先以 javap 对着编译期真实 jar 逐个核对存在（f_44988_/f_44989_/f_44990_/f_44952_、m_36781_/m_36789_/m_36735_、m_44894_、f_22282_、InitEnchantments.IMPEDING/SPEEDY/ENDERS_ENDER、EnchantmentKeys.*、setImpedingLevel）；两树编译零错；字节级校验 17 项全 OK（直接读 jar 内 .class 引用）+ 四个 lang 均为新名无旧名残留；deploy_all.py 三处 match=True；test_server.py 1201 与 neoforge1211 均 PASS。⑦待实测：1.20.1 附魔弓（力量/冲击/火矢/无限）箭伤更高/命中击退/点燃/不掉箭；附魔御币（阻碍/神速/末影杀手）弹幕更快/有减速/能打末影人；附魔剑（击退）命中打退怪；任务列表显示近战空袭/远程空袭。
v1.2.0 鞘翅渲染【尺寸改为与玩家等大 + 整体下移 0.3 格对齐肩线】：①【反馈】鞘翅改成跟玩家同样大小；顶端要对准 winefox 建模的肩膀，目前视觉上需再降低约 0.3 格。②【落点】两树各两个图层文件（LayerMaidElytra=Bedrock 模型女仆、LayerMaidElytraGecko=GeckoLib 模型女仆），四文件常量原本一致。③【改动】SIZE_FACTOR 0.85f→1.0f（尺寸回到与玩家等大，即 0.9375=原版 PlayerRenderer 缩放系数）；LIFT_BLOCKS 1.0f→0.7f（上移量由 1.0 格减到 0.7 格，净降 0.3 格）。④【为什么减在上移量】实测四百八十记着当时要求是「整体上移 1 格」，用户现在说「再降低 0.3 格」，方向无歧义。⑤【为什么顶端由 LIFT_BLOCKS 单独决定·数据实证】扫全部 18 个 winefox 族模型 JSON：ElytraLocator 枢轴 y=30.9644px，肩线 LeftArm 枢轴 29.1 / 手臂方块顶 30.436px，换算成格后同高——挂点本身就落在肩线上，故顶端高度只由上移量决定。⑥【为什么改尺寸不挪顶端】反编译原版 ElytraModel.m_170539_：左右翅 PartPose 枢轴为 (±5,0,0)，枢轴就在 y=0，scale(k) 只缩放翅膀不移动枢轴 → 尺寸与顶端位置解耦，两个常量可独立调。⑦【变换链坐实（本次新证）】RenderUtils.prepMatrixForLocator 全部按 /16 换算 → 锚点后单位是格、Y 朝上；IGeoRenderer.renderEarly 直接 scale(width,height,width) 且 GeckoEntityMaidRenderer 覆写 getWidthScale/getHeightScale 返回 renderEntityScale，而 renderEarly(render 第82行) 与图层调用(第246行)之间没有 push/pop 包住该 scale → 图层矩阵带实体缩放，「除以 modelScale 才是世界格」成立；winefox 的 render_entity_scale=0.65，不除缩放 0.3 格会被放大成约 0.46 格。⑧验证：两树编译零错；两 jar 构建成功；字节级校验四个 .class 常量池均为 1.0f+0.7f+0.9375f 且旧 0.85f 完全消失；deploy_all.py 三处 match=True；test_server.py 1201 与 neoforge1211 均 PASS。⑨待实测：飞行作战穿鞘翅看翅膀大小是否与玩家一致、顶端是否落在 winefox 肩线；若仍偏，只调 LIFT_BLOCKS，每 0.1 格即 ±0.1。
v1.2.0 飞行远战【御币扇形范围攻击丢失】修复（两树同步）：①【反馈】御币的攻击本是扇形范围攻击，但飞行远战期间失去该功能。②【根因·CFR 反编译实证】DanmakuShoot 有两条不同形态的发射路径：aimedShot 只造 1 发直线瞄向目标；fanShapedShot 按 setFanNum(n)+setYawTotal(弧度) 张开扇形（内部：以目标方向为轴，yaw 从 -yawTotal/2 起每发递进 yawTotal/(fanNum-1)，逐发 Vec3.yRot(yaw)）。而我们的飞行远战御币分支是无条件 aimedShot 单发，整段扇形规则从未被调用。③【TLM 原始规则——不是永远扇形】TLM TaskDanmakuAttack.performRangedAttack 按周围同种敌人数分档：≤1 且无多重射击→aimedShot 单发；≤1 且有多重射击→3 发/0.2618 rad(15°)；≤5→8 发/1.0472 rad(60°)；>5→32 发/2.0944 rad(120°)。单挑单发、群战撒开是有意设计，旧实现把整张表丢了。同种敌人判据=可攻击+同 EntityType+有视线（同 TLM enemyEntityTest）。④【修法】shootDanmaku 按上表重写并对齐 TLM 原式的伤害/速度/散布：speed=0.3*(df+1)*(急速+1)+clamp(dist/40-0.4,0,2.4)；inaccuracy=1-clamp(dist/100,0,0.8)（扇形再/5）；damage=攻击力×(df+1.0/1.2/1.5) 按档。⑤【仅两处有意偏离原版并在注释写明】速度基线 0.3f→1.6f（空中交战距离更远，沿用原速弹幕追不上，这也是旧版写死 1.6 的原因）；不吃 TLM 独有的阻碍/神速/末影杀手三个自定义附魔（与旧版一致），只保留多重射击。⑥数敌人记忆按各版 TLM 原文口径：1.20.1 用 NEAREST_VISIBLE_LIVING_ENTITIES(f_148204_) stream 计数；1.21.1 用 NEAREST_LIVING_ENTITIES(List) stream 计数 + hasLineOfSight。⑦开火节流由本模组 RANGED_SHOT_COOLDOWN 控制，distanceFactor 恒传 1.0f（满蓄力，与 TLM 蓄力完成才开火一致）。⑧验证：本次新用到的每个 SRG/Mojmap 名均以 javap 逐个核对存在（不凭记忆）；两树编译零错、deploy_all.py 三处 match=True、test_server.py 1201 与 neoforge1211 均 PASS。⑨待实测：飞行远战持御币，单只怪→单发；3~5 只同种怪→8 发扇形；超 5 只→32 发大扇形。
v1.2.0 床铺互通【核对两端落地 + 修 Neo 编译 classpath 顺序隐患】：①【核对结论】提示"config 开关/面板条目/语言键全都没有"——逐项核对后这些其实都已在后续提交里补齐（配置 2026-09-15 08:22 落地），故本次不新增功能代码，改为验证其确实可用：MaidBedInteropBehavior（女仆睡原版床）、MaidBedBlockInteropMixin（玩家睡女仆床）、mixin 登记、MISC_BED_INTEROP 开关（默认开）、面板「杂项→床铺互通」一行、lang 中英条目、手册 bedInteropGuide() 章节、getRestBehaviors() 注册（优先级 6）、changelog 记录——两树全部在。注入签名逐字对照 TLM 字节码：1.20.1 isBed(...,Entity) + m_6227_→InteractionResult；1.21.1 isBed(...,LivingEntity) + useItemOn→ItemInteractionResult，均匹配。计划里两个"需实测确认"点也已验证：ServerPlayer$RespawnPosAngle.of(Vec3,BlockPos) 确为 public static 可直接调用；NeoForge IBlockExtension.getRespawnPosition 默认恒空，故显式实现是必要的。②【修掉真实隐患】gen_compile_neo.py 的 cp=[neo,mc,neou,tlm] 把未修补 vanilla srg jar 排在 NeoForge 修补 jar 之前，与本文件注释要求相反。javap 实测 RespawnPosAngle 在 vanilla srg 里是 final class（包私有）、在 neoforge client jar 里是 public final class、在 universal jar 里不存在；而 MaidBedBlockInteropMixin 要实现 getRespawnPosition，返回类型正是它——用包私有类型作 public 方法返回类型按 JLS 就是编译错误，旧顺序能过只是靠先命中 neo(client) 的 public 版本（偶然命中）。修为 cp=[neo,neou,mc,tlm]（与运行期一致，修补版在前）并写明依据。③验证：对照实验证实顺序决定可见性（mc 在前→final class 包私有；neo 在前→public）；两树编译零错、deploy_all.py 三处 match=True、test_server.py 1201 与 neoforge1211 均 PASS。④待实测：女仆睡原版 16 色床；玩家睡女仆床并可设为重生点；关掉开关后两者恢复 TLM 原版。
v1.2.0 空战缺装备提示【只在遇敌时才触发】修复（两树同步）：①【反馈】汇报缺乏装备的语音包没有触发，且文本触发条件很奇怪——应该一进入这个模式就发现缺乏然后发系统消息，而不是仅遇到敌人才发。②【排查结论：语音链路全部正常】flight_not_ready.ogg 存在且有效（30981 字节 OggS）、两树 jar（构建版与已部署版）都已打进、manifest 条目为 {"text":"空战装备不齐","file":"flight_not_ready.ogg","mode":"contains"}、按真实 manifest 模拟 matchKey 命中且排 122 条最前、TTS_JAR_PACK_ENABLED 默认 true、speakable() 放行汉字——所以"没触发"是根本没走到那句气泡（语音挂在气泡上）。③【根因】notifyNotReady 只被 MaidFlightCombatBehavior.tick() 里两处"三件不齐"分支调用，而 tick() 前面还有 canUse：currentTarget(maid)==null 时行为根本不启动——没敌人时缺装备永远走不到提示分支，只有真遇到怪行为开始跑才顺带报一句，正是反馈的"只在遇到敌人才发"。④【修法】notifyNotReady 改 public，挪到 MaidToolAutoEquipBehavior.checkExtraStartConditions 调用（core 行为、优先级 200、任何 activity 每 tick 都评估，与有没有敌人无关）——切到空战任务立刻检查、缺件立刻报；三件齐备时清冷却（NOTIFY_READY.remove），"补齐→又缺"能立刻再报；该分支只提示不擅自换装（补齐仍由 MaidFlightKit.equip 负责）。⑤验证：两树编译零错、deploy_all.py 三处 match=True、test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 飞行近战【飞向敌人贴近地面时被自动传送、卡掉本轮攻击】修复（两树同步）：①【根因】负责"空中禁传送"的 MaidFlightKit.isFlightAirborne 只认滑翔标志位 isGliding；而收翅猛击那一段【主动】清滑翔位（tickSmash 里 setGliding(false)——原版猛击判定要求 !isFallFlying，不收翅打不出猛击），于是"飞向敌人、贴近地面"那一刻恰好不满足 isGliding → 禁传送豁免失效，主人一超阈值就被任意自动传送链路拽走，本轮扑击作废。②【另查出两处漏接线】TLM 原生 teleportToOwner 拦截：1.20.1 有飞行豁免、1.21.1 完全没有（这棵树定义了 isFlightAirborne 却从未调用）；同维度远距拉回 trySameDimPull 与跨维度跟随 followIfCrossDimension：两树都没有飞行豁免。③【修法】MaidFlightCombatBehavior 新增 isEngaged(maid/UUID)——起跳 JUMP_LEFT / 烟花爬升 LAUNCH_LEFT / 收翅猛击 SMASH / 等待再放烟花 WAIT_LAUNCH / 远程俯冲助推 RANGED_BOOST_LEFT 任一为真即算"本轮攻击进行中"；isFlightAirborne 改为"滑翔中 或 isEngaged"，覆盖收翅扑敌那段滑翔位为空的窗口；并接到全部自动传送入口（同维度拉回、跨维度跟随、TLM 原生 teleportToOwner，含补上 1.21.1 缺失的那道）。④【豁免有界】状态表由行为收尾 forget() 整清：一轮打完/目标消失/行为停止立刻恢复正常传送，不会永久禁传。⑤验证：两树编译零错、deploy_all.py 三处 match=True、test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 指标石【女仆搭建中被收回 → 建造不停 / 放出来建模卡住】根因修复（两树同步）：①【根因·CFR 反编译实证】TLM 的 ItemSmartSlab.storeMaidData / AbstractStoreMaidItem.storeMaidData 是【先给女仆拍 NBT 快照、再 post ToItem 事件】——我们的钩子执行时魂符里已经躺着一份"临时建造中"快照（任务=maid_smart:index_build + ForgeData/NeoForgeData 里建造标记=true），旧实现只清女仆活体 persistentData 改不到它。放出来时 TLM maid.load(快照)：读 MaidTask → setTask(index_build) 让隐藏临时建造任务当场复活（而会话早在收回时结算 = 建造不停）；读回建造标记 → 行为 canUse 通过 → 只能靠 selfHealStale 自愈，而自愈是在【行为 tick 内部】直接调 setTask → TLM refreshBrain 重建整个 Brain = 行为列表被换掉（未定义行为，项目在 IndexStoneBuildBehavior.finish 注释里已记录过该风险）→ 女仆僵住（建模卡住）。②【修法一·清洗快照】IndexStoneService.onMaidRecalled 新增 snapshot 参数，收符时把 TLM 即将存进物品的那份 event.getData()（同一对象引用）一起修：MaidTask 写回【原任务】（从快照自己的 persistentData 读 prev_task），建造/站桩标记整段删除；自守护——只有快照里任务确实是我们那个隐藏任务时才动一个字段，相机/胶卷等其他"存女仆物品"路径只洗快照不结束会话（玩家拍照不该把正在进行的搭建判死刑）。③【修法二·自愈延后】selfHealStale 调用改为与 finish 同款 server.execute（1.20.1 为 m_18707_）延后一 tick 执行 + healing 锁防重复排程，杜绝行为 tick 内重建 Brain。④站桩标记 maid_smart_work_still 一并从快照清除。⑤验证：两树编译零错、deploy_all.py 三处 match=True、test_server.py 1201 与 neoforge1211 均 PASS。
v1.2.0 指标石【锁定期间完全不能改选其它方块】：对四百八十四的补充/纠正——要求是锁定期间没有任何办法再去选定其他方块（右击别的方块一律无效）；四百八十四只做到“右击别处不解锁”，但仍把那次右击当成换锁定点，等于照样能改选，没达到要求。【修法（两树同步）】锁定期间只认两种结果、没有第三种：①右击【同一个锁定方块】= 解除锁定（唯一途径）；②右击别的方块/空气/超出距离 = 一律无效，保持原锁定、吞掉这次右键并提示怎么解锁。三处改动：①客户端钩子 IndexStonePreviewClient.onInteraction：已锁定时先 pickAnyBlock 取瞄准方块，只有命中格 == 锁定格才发解锁请求，其余情况【不再发任何锁定请求】（旧版会发“换锁定点”），改 hintLocked() 提示 + cancel 事件；②服务端兜底 IndexStoneService.toggleLock：把“已锁定+不同格”从“换锁定点”改为【拒绝并保持原锁定】，提示“锁定中——要先右击那个锁定方块解除锁定，才能选别的方块”（客户端已拦截，这层防伪造包/其它入口绕过）；③近处方块路径误报修复 IndexStoneItem.useOn：锁定期间右击别的近处方块会被 toggleLock 拒绝并保持原锁定，旧文案却把【被拒的那一格】播报成“已锁定 X,Y,Z”，现在按“操作前是否已锁定在别处”分流，只在【真正锁上新格】时报告坐标。新增 IndexStoneItem.lockedHint()（锁定期间专属提示，纯字符串无客户端依赖）；hintLocked 与 hintUsage 共用 hintCooldown 限频，同一 tick 不会刷两条。顺带改掉“右击别的方块=换锁定点”等过期文案。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 指标石【解除锁定必须右击那个锁定方块】：反馈——锁定之后再右击别的地方就自动解锁了，跟“锁定”词义不符；要求必须再次右击那个锁定的方块才解除。【根因】服务端 toggleLock 本来就是对的（只在“右键位置与已锁格相同”时解锁，右键别的方块是换锁定点），问题在【客户端输入钩子】IndexStonePreviewClient.onInteraction：已锁定时它【无条件】发 LockRequestPacket(unlock=true, 0,0,0)，服务端收到 unlock=true 就走 toggleLock(player,null)（pos==null 语义=直接解锁）——于是只要右击任何地方（别的方块、甚至空气）都会解锁。【修法（两树同步）】已锁定时先做长射线取瞄准的方块，再分流：①同一个锁定方块 → 发解锁请求；②别的方块 → 发锁定请求（服务端按“换锁定点”处理，不是解锁）；③空气/超出距离 → 什么都不做，锁定保持不变，只提示用法。新增 pickAnyBlock(mc)：与 farPick 的区别是【不做距离过滤】——已锁定的方块常常就在眼前（触及距离内），而 farPick 会把 ≤ 触及距离的命中过滤成 null，用它判断会漏掉近处锁定格，导致“对着锁定方块右键却解不掉”。顺带更新误导文案与注释（原“再右键→取消锁定”已明确为“右击同一个锁定方块才解除；右击别的方块=换锁定点”）。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 两版本代码交叉审查【1 处真实 bug + 4 处移植不一致 + 死代码清理】。【真实 bug（两树都有）】getTagType 冒充 getByte 读布尔值 → 三个开关“关不掉”：注释写“getBoolean 等价实现 = getByte != 0”，实际调的是 getTagType；官方 mappings + 字节码双重实证 getTagType 返回 Tag.getId()，而 ByteTag.getId() 是 iconst_1/ireturn（常量 1），故 `!= 0` 恒真——等于上一版声称修好的“关了又自己打开”原样复发；getByte（1.20.1 m_128445_）才返回真实值。三处已改：AiMemoryManager（per-maid 记忆开关）、LlmEnableManager（per-maid LLM 开关）、BuildArchive（legacy 计划 paused）。【移植不一致】①1.20.1 缺飞行作战 static 表清理接线（唯一有“卡死”后果的）：MaidFlightCombatBehavior.forget/clearAll 早已写好却零调用——滑翔/俯冲是 static 表，崩溃/强杀/卸载时行为没走到 stop() 就残留，该女仆永久“俯冲中”（再进不了飞行作战 + 空中禁传送/落地缓冲全线卡死）；已按 1.21.1 补两处接线（ProMaidExtension.onServerStarted 逐女仆 forget+清滑翔位+全清兜底、AiMemoryManager.onEntityLeaveLevel 卸载路径）。②鞘翅“上移 1 格”方向与缩放（我上一轮引入的回归）：1.20.1 Gecko 图层写成 +LIFT_BLOCKS（翻转后该空间 Y 朝下，向上应为 -Y，方向相反），且两处图层漏除 modelScale（图层矩阵已被实体缩放乘过，不除则位移随模型缩放漂移）；已与 1.21.1 对齐为 -LIFT_BLOCKS/modelScale。③1.21.1 Bedrock 鞘翅图层缺 try/finally：中途抛异常会漏 popPose、污染后续渲染矩阵（Gecko 图层两树都有），已补。④1.20.1 sweepWithin 缺 xo/yo/zo 全 0（刚生成/刚传送）守卫：线段会从世界原点拉过来 → 扫掠判定被放大成超大命中范围（等于放宽猛击命中），已按 1.21.1 补。【死代码】删 1.21.1 的 SMASH_SWEEP_SQR 与 MELEE_REACH（均已被新实现取代）。【撤回】审查发现 1.20.1 jumpForLaunch 无 1.21.1 的 hurtMarked=true，但无法在合理成本内确证该字段 SRG 名（官方 mappings 给的 f_19864_ 在真实 jar 里不存在，映射表与 jar 版本不一致），故撤回改动、不留凭记忆写的字段名，仅作已知差异记录。【覆盖说明】文件集/mixin/网络包/配置项/坐标朝向/防摔死/防误伤/防刷物品 两树逐条对齐；try/catch 差异仅来自删掉的诊断代码与上述③；36 处下标访问两树对称且都有守卫。已知合理例外：重锤(1.21.1 独有)、药水组件、数据包目录单复数。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 生存搭建【搭一个扣一个】：需求——生存搭建要搭一个扣一个，不能搭完再一起扣，否则可刷方块。【排查结论】①蓝图建造主流程本来就正确：MaidBuildBehavior 在 doPlace 之前先 consumeBlock（内部 extractItem(...,1)）；②不存在“搭完统一结算”机制——placedCount/placedSet 只用于进度显示与缺口检查（BuildHudTracker/BuildPlan.getProgress），不参与扣料，完工路径（激活红石/水、TNT 结算、清理掉落物）都不扣方块；③索引石搭路 place 的目标格由 resolveMaterial 先取（takeBuildBlock 先扣 1），下方支撑也走 takeOneFor（先 extractItem）再 setBlock，顺序同样正确——（我先前把它判成“先放后扣”是扫描器启发式误报，此处更正）。【本次修掉的真口子】①蓝图建造“自动补支撑”白送方块（3 处）：doPlace 里附着方块（火把/按钮/拉杆/甘蔗/雪层等）支撑面缺失时会 setBlock 补一块支撑却完全不扣料，每补一次凭空多一块，生存可刷；现在三处补支撑（主支撑/掉落验证后的附着类补支撑/漏网类型补下方格）统一改为先扣后放：新增 consumeExtraBlock(maid,support)，走与主放置同一套 consumeBlock + tryTakeFromOwner 补料链，扣不到就不补支撑、延后（等有料再建），绝不“放了但没扣”。②种树苗先种后扣、且不检查扣除结果：MaidPlanting 原本先 setBlock 再 extractItem 且完全没看返回值——扣除失败（槽位被并发改动）时树苗已种下，等于白得一棵苗；现改为先扣后种：新增 takeOneSapling（手部栏优先、其次背包，槽位失效退化为按物品搜），返回非空才算成功，扣不到放弃本轮不放置。【顺带】tryTakeFromOwner 改 static。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 1.20.1 飞行作战与 1.21.1 未同步【只水平飞 + 漏的优化】。反馈：1.20.1 能跑，但烟花给了初速度后全是水平飞、不向上爬，索敌很差；而且 1.21.1 的飞行优化很多没落到 1.20.1。【只水平飞的根因，字节码双重确证】LookControl 每 tick 在 resetXRotOnTick() 为真时会把俯仰角清零——1.21.1 LookControl.tick() 偏移 12 是 setXRot(0)；1.20.1 m_8128_ 偏移 12 是 m_146926_(0)，而它判定的 m_8106_ 字节码是 iconst_1/ireturn【恒真】。lookAt(m_7618_) 写的抬头角正在被清零的字段上，下一 tick 即被抹掉，烟花推力只剩水平分量 → 永远平飞。1.21.1 靠 applyRotation() 每 tick 重写角度 + getLookControl().setLookAt(...) 交期望角度来对抗，这套当时【没同步到 1.20.1】（那边四个朝向函数全只有 m_7618_）。【修法】①1.20.1 新增 applyRotation(maid,yaw,pitch)：m_146922_(yaw) + m_146926_(pitch) + f_19859_/f_19860_（yRotO/xRotO，渲染插值要用）+ m_5616_/m_5618_（yHeadRot/yBodyRot），与 1.21.1 对齐；②faceAwayAndUp / faceTarget / faceUpForward / faceOrbit 改为直接算 yaw/pitch 立即写入，并保留 LookControl 期望角度（m_24950_(x,y,z,360,360)）让每 tick 归零被重新覆盖。【顺带补齐另一处漏同步】suppressVanillaMelee（飞行中给 Brain 写 40t ATTACK_COOLING_DOWN，避免 TLM 自带近战在滑翔时插手挥砍、与“视线当操纵杆”打架）只有 1.21.1 有，1.20.1 完全缺失，3 个调用点（阶段一爬升/阶段二盘旋/猛击段）一并补上；SRG 名以官方 mappings 实证：ATTACK_COOLING_DOWN = f_26373_（同表 ATTACK_TARGET = f_26372_，与项目既有用法交叉验证）、Brain.setMemoryWithExpiry = m_21882_。【逐项核对】endFlightSafely、notifyNotReady、sweepWithin、isCriticalHit、isNearGround、tickGunFire/stopGunAim、takeFirework、LAUNCH_TICKS/CLIMB_TAN 分模式、RANGED_BOOST、throwTrident/御币弹幕两树均齐；applyRotation 与 suppressVanillaMelee 本次补上；重锤后门(MAX_Y/forcedFall)仅 1.21.1 属正常——重锤是 1.21.1 独有物品，1.20.1 无 Items.MACE，不是漏同步。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 鞘翅渲染【尺寸 0.85× + 上移 1 格 + 修「只有 winefox 能渲染」】：反馈三条——①仍然太小、②位置偏下、③除 winefox 外都渲染不出。第③条根因已查清（与①②不是一回事）：扫描全部 28 个 Gecko 女仆模型骨骼 JSON——Elytra 17/28（全是 winefox 家族）、ElytraLocator 17/28、UpperBody 26/28、Root 28/28。旧代码只找 ElytraLocator/Elytra，于是【没有这两根骨骼的 7 个模型】（foxmaid、hailuo_new_year、sta、winefox_hanfu、winefox_mini、zhiban_hanfu、zhiban_new_year）全掉进硬编码兜底，而兜底是从【原版】ElytraLayer 抄的 scale(-1,-1,1)+translate(0,-1.501,0)——那是【原版模型空间】的补偿；Gecko 图层栈单位=格、Y 朝上、原点在脚下，根本不是那个空间，于是翅膀被顶到脚下/身体里 → 看不见。也就是说，【只有 winefox 显示，是因为只有 winefox 家族恰好带那根骨骼、绕过了坏兜底】。【修法：永不掉进兜底】按优先级找骨骼，找不到专用挂点就锚到一定有的躯干/根骨骼，并补一段从真实模型统计出的平均偏移（17 样本，Elytra.pivot−bone.pivot 均值/16）：ElytraLocator/Elytra→(0,0,0)、UpperBody→(0,+0.4310,+0.2011)、Root→(0,+1.8596,+0.2022) 格。28/28 模型现在都有锚点，兜底实际到不了；万一全都没有会打一条「鞘翅挂点」日志便于定位（只报一次），不再静默失败。【尺寸与位置】尺寸 k = 0.85×0.9375/modelScale（0.9375 是原版 PlayerRenderer.scale，即原先的"与玩家等大"，再乘 0.85）；上移 1 格：Gecko 侧锚定后先 scale(-1,-1,1) 转成 ElytraModel 的 Y 朝下空间，故向上 = -Y，写作 translate(0, -1.0/modelScale, 0)，Bedrock 侧同为 -Y；两者都放在 scale(k) 之前（不受鞘翅尺寸缩放影响），除以 modelScale 是因为图层矩阵已被 renderEarly 的 scale(widthScale,heightScale,widthScale) 乘过（字节码实证），不除就变成 1/modelScale 格。编译零错（两树）、字节码校验入包、两个 server 回归 PASS、部署三目标。
v1.2.0 重锤后门【取消 40 格封顶，改回无限增伤】：反馈「不要上限，要的就是无限增伤」。旧版（实测四百七十七）我给 `MAX_FORCED_FALL = 40` 做了个务实天花板，理由只是「连放多枚烟花爬上天怕算出离谱数字」——但那条是我自己加的，不是原版行为，也不是你要的。现按原版口径去掉上限：`forcedFallDistance` 只保留下限（`SMASH_MIN_FALL + 0.01`，为绕开原版严格的 `fallDistance > 1.5`，恰好等于 1.5 时加成仍为 0，那不是封顶），不再有上界——爬多高就吃多高的加成，与原版三段式末段 `22 + (fd-8)` 的无上限特性一致。实测：落差 50 格 = +64、100 格 = +114。仅 Neo 树（重锤是 1.21.1 独有物品）。
v1.2.0 飞行远战「三叉戟单独一路（ThrownTrident）」【含一处更正】：上一轮我说「三叉戟也是 ProjectileWeaponItem，现在会落到造箭那支」——【这个说法是错的，此处更正】。反编译实证：1.20.1 是 `TridentItem extends Item implements Vanishable`、1.21.1 是 `TridentItem extends Item implements ProjectileItem`（ProjectileItem 与 ProjectileWeaponItem 是两个不同接口）——两版都【不是】ProjectileWeaponItem。所以旧版女仆拿三叉戟时：①「武器位」判否 → 飞行远战根本激活不了；②自动装备也认不出它。【为什么不能走原版那条路】`TridentItem.releaseUsing`(`m_5551_`) 第一件事就是 `if (!(entityLiving instanceof Player)) return;`（字节码 instanceof Player; ifne）——女仆不是 Player，调用它等于空转。【修复：照搬 TLM 自己的 TaskTridentAttack.performRangedAttack（字节码实证）】①`MaidFlightKit.isRangedWeapon` 增加 instanceof TridentItem（与 TLM TaskTridentAttack.isWeapon 同口径）→ 激活与自动装备都认它；②新增 isTrident / throwTrident：自建 ThrownTrident，投【副本】（主手只掉 1 点耐久）；③【剥掉忠诚附魔】（1.20.1 Enchantments.f_44955_，已用官方 mappings「LOYALTY -> E」交叉验证即忠诚；1.21.1 Enchantments.LOYALTY）——留着它 isAcceptibleReturnOwner() 对活着的女仆返回 true，副本会飞回来、还可能被玩家捡走，等于凭空多出一把三叉戟（刷取漏洞）；④setNoGravity(true) 直线飞行（配 TLM 的 ThrownTridentMixin：命中实体后才恢复重力）；⑤pickup=CREATIVE_ONLY——副本不落地可捡、到期由 tickDespawn 自行回收；⑥速度/散布照 TLM：clamp(距离/10, 1.6, 3.2) 与 1-clamp(距离/100, 0, 0.9)，音效 TRIDENT_THROW。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 飞行近战「重锤增伤按最大上升高度强制结算」（后门）：走的是"强制按最大上升高度结算增伤"这条捷径。【结论：可以，而且比改飞行 AI 更对路】反编译实证：`MaceItem.getAttackDamageBonus` 只读 `fallDistance` 一个字段，`canSmashAttack` = `fallDistance > 1.5 && !isFallFlying()`；风爆的 wind_burst.json 谓词也只是 `is_flying=false` + `fall_distance.min=1.5`。而 `fallDistance` 是普通浮点字段，且这两处结算都是本模组自己发起的（我们自己调 getAttackDamageBonus 与 doPostAttackEffects）——所以在调用前后临时改写它即可，不必真的让她爬到某个高度（滑翔物理每 tick 把 fallDistance 钳回 1.0，靠飞行动作永远攒不出高数值，这正是吃不到加成的根）。【实现】①新增 MAX_Y：每 tick 记录本轮最高 Y，每放一枚烟花（=新一轮爬升）重置为当前高度；②forcedFallDistance = clamp(本轮最高点 − 当前高度, 1.51, 40)，即"她实际砸下来的这段距离"；③hitOne 里持重锤时写入该值 → 结算 → **finally 必还原**（绝不把假值留给原版摔落判定）；④因为不再依赖真实累计，把四百七十三那版"必须等攒过 1.5 才出手"的门撤掉，恢复"够近就打"，顺带解决玩家反馈的「空中时间太长掉 DPS」。【数值】落差 8 格=+22、10 格=+24、15 格=+29、30 格=+44——**并按原版口径无上限，爬多高就吃多高**（实测四百七十九已取消 40 格封顶；floor 取 1.51 是为满足原版【严格大于】1.5）。⑤附诊断日志（latest.log 搜「重锤后门」）如实打印"落差X格 → 写入Y（真实值Z）"，便于实测核验。仅 Neo 树（重锤是 1.21.1 独有物品；1.20.1 无 Items.MACE，且其暴击只要 fallDistance>0，滑翔中天然满足）。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 飞行远战「手持武器不参与开火」修根：反馈「远战正常，但只会发射箭；换了武器（如御币）也没用，依旧发射弓箭」。【根因】`performRangedAttack` 里只判了武器是不是 `ProjectileWeaponItem`，之后就【无条件自己造箭】（旧代码：取箭 → ArrowItem.createArrow → shoot → 扣耐久扣箭）——武器本身是什么、该怎么发射，完全没被调用过。所以拿御币/三叉戟/模组弹射武器都变成射出一支普通箭。【实证】反编译 TLM 的御币：`ItemHakureiGohei` 虽 extends ProjectileWeaponItem，但它的 `shootProjectile` 是【空实现】、`getAllSupportedProjectiles` 返回 alwaysTrue（谓词恒真）——说明御币压根不走原版箭矢通道；TLM 自己是用 `DanmakuShoot`（弹幕 API）开火的（`TaskDanmakuAttack` 实证）。硬造箭必然变成「射箭」。【修复】按武器分流（与玩家手持该武器时的表现对齐）：①枪械（TACZ/卓越前线）→ 直接返回，仍由 tickGunFire 走 TLM 枪械通道（换弹+瞄准+开火）；②御币 → 走 TLM 弹幕通道 `DanmakuShoot.create().setWorld/setThrower/setTarget/setRandomColor/setVelocity(1.6)/setInaccuracy(1.0)/setDamage(女仆攻击力).aimedShot()`（与 TLM 弹幕任务同一套 API，反编译确认各字段均有默认值，只需补世界/投掷者/目标/速度伤害）；③其它弹射武器（弓/弩/模组弹射物）→ 造箭，且【弹药优先按武器自己的 supportedProjectiles 判据找】（弓弩认箭、模组武器认自己的弹药），拿不到才退回背包里的普通箭。两树同步（1.20.1 用 SRG 名：`m_6437_`=getAllSupportedProjectiles、`m_6394_`=createArrow 三参版）。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 支援语音包核查 + 语音间隔 8→5 秒：反馈「女仆支援语音似乎没有语音包」。【实证结论：支援语音包其实一直都在】逐条转写核对（whisper）——aid_sister_help「しまいっ頑張って今助けるからね」、aid_food「ご主人様お腹空いたでしょ 食べ物持ってきたよ」、aid_potion_given「ポーション、カバンに入れたよ」、aid_bag_full、aid_eat_something 等 10 条 aid_* 全部是正常日语人声，响度也已按全包统一归一（max≈-1.5dB，与其它 112 条同档）；两树 + 三个已部署实例的 jar 里都是 10 条齐全、manifest 命中正确（姐妹气泡 → aid_sister_help.ogg 实测命中）。所以「像没做」的真正原因是【被播报间隔吞掉了】：内置语音包最小间隔默认 8 秒，而支援/互助类台词与系统消息共用同一道门——一场战斗里系统消息频繁触发，支援语音轮到播放时大概率还在冷却窗口内，听感上就等于没有。【修复】jarPackMinIntervalS 默认 8 → 5 秒（配置面板「语音与 TTS → 内置语音最小间隔（秒）」可调，范围 0~60，0 = 不限制）。同时把三个已部署实例的现有配置文件一并从 8 改成 5（旧配置文件不会自动跟随新默认值，已在改前逐个备份 .bak_interval_*）。【顺带更正】配置面板内置语音包说明里的条数从旧的「115 条」改成实际「122 条」，并把支援/投喂台词与新增的空战提示计入分类说明。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 空战未激活提示 + 语音：需求"两种空战未进入激活状态时加一条气泡对话 + 系统消息"。做法：新增 MaidFlightKit.missingParts(maid)——按 isModeActive 的同一口径列出缺哪几件（鞘翅 / 近战或远程武器【按任务分流】/ 烟花火箭，缺多件一起报），行为里两处未激活分支（烟花用完或鞘翅损坏 / equip 后仍不齐）调用 notifyNotReady 发气泡。台词：「空战装备不齐，缺鞘翅、烟花火箭，先按普通战斗来」。【一个入口同时满足两个需求】走 addTextChatBubble：ChatBubbleLimitMixin 会把它①同步成主人系统消息（青色 [女仆名] 前缀）②按 misc.bubbleLimitMs 限频③汇入 SystemTTSManager 朗读——所以气泡 + 系统消息 + 语音三者共用同一句文本，不需要各写一遍。【限频】气泡自身 5 秒限频由 mixin 兜底；另加 15 秒冷却（WeakHashMap 按女仆记，防强引用泄漏），因为"三件不齐"是持续状态（站在怪堆里没烟花会每 tick 命中该分支），不拦会刷屏；clearAll 一并清 NOTIFY_READY。【语音】新增 flight_not_ready.ogg（日语「空戦の装備が足りないの、普通に戦うね」，小酒狐 v2Pro e15 音色，battle 档 speed 1.08，峰值归一 -1.5dB / libvorbis q4，3.64s 单声道）。manifest 条目用 contains 探针「空战装备不齐」——【必须排在 fallback_missing 的「缺」之前】：manifest 是自上而下顺序匹配，旧的通用「缺」条会把这句吞掉（已实测验证命中自己）。条目 122 条 / ogg 122 个两树一致，jar 内 manifest 与音频已复验可命中。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 飞行近战命中率 + 重锤下落加成/风爆 修根：①【本轮重点·重锤】原版 `MaceItem.canSmashAttack` = `fallDistance > 1.5 && !isFallFlying()`（字节码实证：`ifle` 严格大于），而 `MaceItem.getAttackDamageBonus`（下落三段加成 4 / 12+2(f-3) / 22+(f-8)）与「风爆」附魔【都以该判定为门】——风爆的 data/minecraft/enchantment/wind_burst.json 明写 requirements：`entity=direct_attacker`、`flags.is_flying=false`、`movement.fall_distance.min=1.5`，且经反编译确认 is_flying 走的就是 `LivingEntity.isFallFlying()`（滑翔位）。旧版在 t>=2 就出手，而那一刻 fallDistance 还被滑翔钳在 ~1.0（`Entity.m_245125_`：滑翔中 y 速度 > -0.5 时把 fallDistance 压回 1.0），于是重锤打出来等同白板、风爆一次都不触发——正是反馈的"触发不了风爆且伤害低"。修复：持重锤时【等 fallDistance 真正攒过 1.5 再出手】（收翅即自由落体，两三 tick 达标，远早于贴地）；贴地/落地时不再等待、照打（没加成也要打出去）；门槛用【严格大于】1.5 与 `ifle` 对齐（恰好等于 1.5 时加成仍为 0）。非重锤武器不吃这道门（暴击只要 fallDistance > 0）。顺序也已核对：命中结算里 `doPostAttackEffects`（风爆入口）在 `resetFallDistance()` 之前，收翅时滑翔位已清→ is_flying=false 成立，两个条件都满足。②【命中率】俯冲约 1~2 格/tick，旧版只比较"当帧中心距"，整段可能从目标侧上方掠过、每帧都不在半径内→ 整套俯冲白打。新增 sweepWithin：把"上一帧位置→本帧位置"连成线段，取目标到线段最短距离，擦身而过的这一帧也算够得着（与弹射物扫掠判定同思路）。两树一致（1.20.1 用 SRG 的 f_19854_/m_20182_ 等）。③【白打修复】smashHit 改为返回 boolean：攻击冷却未好时返回 false，调用方【不再收尾】，下一 tick 继续压着打——旧版无论打没打中都 endSmash，等于每次俯冲白送。④【安全】收尾分支改到命中分支之外，保证"未命中"时也一定走到落地清零（旧版冷却中命中分支 return，贴地时既没清零也没收尾，她会带着满坠落距离撞地）。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 飞行近战回退 + 摔死根治：①【回归根因】上一版为飞行远战「飞太高够不到地面敌人」把 LAUNCH_TICKS 30→20、LAUNCH_CLIMB_TAN 1.88(62°)→1.0(45°)，但这两个是【近战远战共用】的常量——近战链路是「起飞→扑击→收翅猛击→再起飞」的循环，每次重新起飞都要先把高度拉起来，仰角被压到 45° 后她一放烟花就往目标方向压头，几 tick 内贴地、滑翔位被原版 updateFallFlying 清掉 → 立刻变自由落体摔死。现按需求【回退】：近战恢复 62°/30t（LAUNCH_CLIMB_TAN_MELEE / LAUNCH_TICKS_MELEE），远战保留 45°/20t（..._RANGED），faceAwayAndUp 与 tryLaunch 按任务分流取值。②【实证】整合包实机日志（latest.log）里飞行期的死亡【全部是 类型=fall 伤害=21~23】（她 20 血必死），位置清一色在地面高度，全程没有一条 flyIntoWall——「很容易摔死」成立，与撞墙无关。③【附带根治】目标丢失 / 三件不齐（烟花用完或鞘翅损坏）/ 行为结束这三处旧版都【无条件清滑翔位】——若此刻正在高空（烟花推进的必然结果），清位即自由落体。新增 endFlightSafely：空中一律【保留滑翔自然下降】、落地再收翅（与玩家同款：没推力就滑下来），落地的清理由原版 updateFallFlying 自然完成。④【鞘翅撞击免疫可核验】MaidFlightWallGuard 判定本身正确（getMsgId=="flyIntoWall"，1.20.1/1.21.1 的 fly_into_wall.json 实证一致；已确认 Forge 的 ForgeHooks.onLivingAttack 挂在 LivingEntity.hurt 头部、NeoForge 的 LivingIncomingDamageEvent 同样在 hurt 内 post 且可取消），但此前日志里一条 flyIntoWall 都没有，「没生效」无从分辨是没触发还是没拦住——现在拦下时记一条「[promaid/飞行撞击免疫] XX 拦下鞘翅撞击伤害」，再复现即可确认。经核实注解自动注册【是生效的】（FriendlyFireGuard 同为注解注册且日志持续有输出），故【不】额外显式注册以免重复登记。
v1.2.0 指标石修 bug：建造完成后不自动清绑定与幽灵方块。根因是我上一轮引入的分支顺序错误——行为 tick 顶部先判 "s==null || s.cells.isEmpty()" 走 selfHealStale，而 selfHealStale 出于"魂符放回来"的安全考虑【绝不触碰玩家会话】，于是最后一格放完后 cells 变空时被它吃掉：绑定/锁定框/任务标记全清不掉、女仆永远卡在临时搭建任务上。修法：把【完成判定提到最前】——"她的会话还在（s.maidId==她）且 cells 已空" = 成功完成 → 走 finish（server.execute延后一 tick 调 onMaidFinished：清幽灵格 cells + 解绑 + 取消锁定框 + 释放强制加载票 + 还原原任务/作息 + 播报 + 立即 S2C 推空状态让客户端红框橙影当场消失）；另加 finishing 闸防延后期间重复排程/重复播报；onMaidFinished 改为【无论会话是否还在都解除她的临时建造任务】（防会话先消失时她永久卡住）。编译零错、两 server 回归 PASS、部署三目标。
v1.2.0 指标石细节：搭建中途失败/中断一律"视作结束和初始化"。①女仆被收回/死亡 → 清橙色幽灵格 + 解绑 + 取消锁定框 + 释放强制加载票，结束本次（消息如实报"已搭 X/Y 块"）；②搭建中途发现缺材料也视作失败——连续 3 秒拿不到任何材料即烂尾（留宽限防"刚消费完一叠、主人正在补"误判）；③新增失败收尾 failSession（幂等，多处触发只结算一次）：清幽灵格/解绑/取消锁定框/释放票/还原她原任务与作息/系统提示/立即 S2C 推空状态让红框橙影当场消失；④中断检测三入口：EntityLeaveLevelEvent（按 RemovalReason 精确区分——KILLED死亡/DISCARDED收回=结束，UNLOADED_*区块卸载与CHANGED_DIMENSION换维度=不结束，否则她走远被卸载会误判成烂尾）、LivingDeathEvent（死亡兜底）、魂符收回 MaidAndItemTransformEvent.ToItem（手动空魂符/自动回魂符唯一汇聚点，字节码实证 storeMaidData 先存 NBT 再 post，故此处只结束会话）；⑤魂符把女仆 NBT 一起存进魂符，放回来后残留标记由行为顶部 selfHealStale 兜底：只还原任务、不播报"搭好了"，且【绝不触碰主人的会话】——那可能已属于另一只女仆（failSession/selfHeal 都有会话归属校验，防"放回来一个旧女仆把正在干活的新任务清掉"）；⑥完成路径也一并取消锁定框、可立刻开下一个；⑦长时无进展（20秒）也按烂尾收尾。编译零错、两 server 回归 PASS（Neo 有一次 90s 内未到 Done 系该重模组包启动慢，放宽到 240s 后 Done(0.871s) PASS，非崩溃）、部署三目标。
v1.2.0 指标石贴图替换：物品图标换成玩家提供的「带指针的平滑石头」成品图（64x64，指针红/白、石头面带明暗过渡），替换两树 assets/maid_smart/textures/item/index_stone.png；模型 item/generated 引用同一路径无需改动，物品栏与手持渲染自动生效（item/generated 把整张图铺在物品面上，分辨率提高只增加细节、不改变尺寸）。
v1.2.0 飞行作战（近战/远战）下不触发自保（需求逐条落地）：SelfPreservationBehavior.tick 最顶端加飞行硬闸——MaidFlightKit.isFlightTask 为真时既不进自保会话、也把已在会话里的立刻安静中止（sessionActive=false + 清 PRESERVE_TAG + 清垫高/塔顶状态 + MOVING_SURVIVE 摘除），只保留与保命无关的常驻轻量逻辑（蜂蜜/牛奶解负面）后 return；两个易踩点都已避开：①豁免不能放 canUse——那会让行为在飞行任务下根本不启动（setTask→refreshBrain 后新实例永不 tick），而清残留 PRESERVE_TAG 的代码藏在 tick 里，结果从飞行切回时标记残留、排班/参战/搭方块对该女仆永久让位，故豁免统一放 tick；②清标记必须无条件（判 sessionActive || PRESERVE_TAG）——区块卸载/崩溃/魂符收放会把标记写进存档而内存态归零，只看内存态时该残留正好落在飞行任务上会被本闸提前 return 挡掉、再也清不掉；顺带把闸放在岩浆感知扫描之前（空中不需要避让，省掉每 10 tick 一次的全量方块扫描）。口径：只拦"自保接管"、不放宽真实伤害——飞行中照样掉血/可能被击落，只是不再由自保把她从空中拽下来（传送/垫高/放水/逃跑会打断滑翔与烟花推进），与 AutoCombatSwitch 里飞行任务"自主战斗不介入"一致。编译零错（两树）、两个 server 回归 PASS、部署三目标。
v1.2.0 指标石：临时蓝图制作器（需求逐条落地）——物品 maid_smart:index_stone（9 平滑石头 3×3 合成，创造栏建材页+工具页）；手持时视线指向的方块渲染为绿色（跟随指针）、右键锁定为红色不再移动、再右键取消，客户端 512 格长射线可锁极远、不可锁空气；右击自己的女仆绑定（再右击解绑/点其它女仆换绑），必须先锁方块再绑女仆（先绑会提示）；两件事齐备后女仆所在格到锁定格之间的空气方块渲染为橙色幽灵方块，女仆立即进入一次性临时建造、由近及远逐格填充，材料先从她背包取不够从主人背包拉（选材复用搭路规则：数量最多者优先/必须有碰撞/排除下落方块与TNT与危险方块，创造主人视为无限）；表现与建造任务一致（站桩+瞬移工地旁+挥臂+放置音效）；一个玩家同时只允许一个锁定+绑定，完成前不能开下一个；完成或取消均还原原任务/原作息并播报。实现：IndexStonePlan（体素连线几何，服务端开建与客户端幽灵共用，保证逐格一致）/IndexStoneService（会话内存态+女仆 persistentData 双写、隐藏任务 index_build 强制指派与还原、会话级 FORCED 票据给起点到锁定点之间区块强制加载并在完成/取消/下线/停服全路径释放）/IndexStoneItem/IndexStoneInteractHandler/IndexStoneNetworking（C2S 锁定+S2C 状态）/IndexStonePreviewClient（渲染+长射线锁定）；config BUILD_INDEX_STONE（默认开，面板建造区）+四份 lang。审查拦下并修复四个坑：①已锁定时取消 use 键会把右键女仆一并吞掉（绑定永远收不到包）——改为视线命中 EntityHitResult 时不拦截；②在行为 tick 里 setTask 会refreshBrain 重建 Brain=未定义行为——收尾改 server.execute 延后到本 tick 之后；③未加载区块的格被永久丢弃留洞——改为退避等加载就绪；④强制加载票在解绑/取消/下线/停服路径泄漏——补全路径释放。编译零错、lang json OK、新类与资源入包、两个 server 回归 PASS、部署三目标。
[05:40:00] v1.2.0 全盘修复五条：①任务栏 mod 任务全变英文——根因是 promaid_src_neo/assets/maid_smart/lang/{zh_cn,en_us}.json 末尾多了尾逗号，整份语言文件被 ClientLanguage 跳过（日志实证 Skipped language file），而 TLM 任务名走 task.<ns>.<path> 翻译键，键丢失就显示键名；删逗号并 json.load 复验四份 lang 合法（1.20.1 本来合法，只有 1.21.1 中招）；②飞行远战飞太高——LAUNCH_CLIMB_TAN 1.88(62°)→1.0(45°)、LAUNCH_TICKS 30→20、补烟花抬头角 55°→45°、抬头窗口 20→10tick、期望盘旋高度 6→3.5 格，远战图标弓→鞘翅；③免疫鞘翅撞击伤害（后门，默认开）——新增 MaidFlightWallGuard + config COMBAT_FLIGHT_NO_WALL_DAMAGE（生存与复活→落地缓冲），用 getMsgId()=="flyIntoWall" 判定（跨版本稳定），NeoForge 用 LivingIncomingDamageEvent、1.20.1 用 LivingAttackEvent；④鞘翅渲染——用的就是玩家 ElytraModel，前几版错在硬编 1.501 且未抵消模型 render_entity_scale(0.65)：鞘翅只有玩家 69% 大、挂点被顶到腰背埋在长发里（LongHair z 0.34~0.64）、只在 isGliding 展翅会露折叠态；改为锚定模型自带 Elytra 骨骼(pivot y30.9644 z3 → 世界 y≈1.258 z≈+0.122，在头发之前，16/27 模型有) + scale(-1,-1,1) + scale(0.9375/0.65)，Bedrock 分支同步补缩放抵消，展翅条件放宽为飞行任务且离地；⑤两模式落地水/雪恢复照常——撤掉 WaterClutch 对飞行任务的屏蔽。编译零错、四份 lang 合法、两个 server 回归 PASS、jar 重建部署三目标。
[05:30:00] v1.2.0 飞行远战·兼容枪械（TACZ / 卓越前线）（需求：把枪械接进飞行模式，接在"武器位判据 + 开火路径"两处）：①判据——MaidFlightKit.isRangedWeapon 放开为 ProjectileWeaponItem || GunCompat.isGun，因 isWeaponForTask/hasWeapon/isModeActive/任务 isWeapon 全复用该判据，故一处放开全线生效（飞行远战认枪；飞行近战仍只认近战武器），equip 远战分支也会从背包掏枪到主手；②开火——新增 fireRanged/tickGunFire，持枪走 TLM 枪械通道（照搬 GunShootTargetTask.tick：每 tick 换弹→冷却好且 canSee 时 performGunAttack→冷却按 MAID_GUN_ATTACK_SPEED 缩放），射程用 GunCompat.gunMaxRange，弓弩仍走箭矢通道 24 格，performRangedAttack 对枪械直接返回；③坑：performGunAttack 会自己算朝向把身体拧向目标，而滑翔方向=视线方向，故开火必须放在朝向之前、开完立刻盖回盘旋朝向，否则会被拉向目标；④退出模式在 stop() 调 GunCommonUtil.onStop 收枪（复位 ADS/手雷冷却，用一次性 GunShootTargetTask 实例，已确认无静态初始化块）。编译零错、两个 server 回归 PASS、jar 重建部署三目标。
[05:20:00] v1.2.0 飞行远战·盘旋高度保持（反馈：盘旋时高度会慢慢降低，像玩家滑翔那样；每 5 秒补一次烟花既费烟花又顶不住）：①盘旋俯仰改为按高度偏差的反馈控制——期望高度=目标上方 6 格，偏差按 5°/格 换算并留 1 格向上偏置（平衡点≈原 -6°），低了抬头把速度换成升力、高了低头把高度换成速度，限幅 +45°/-35°；②烟花由定时改为按需——只有掉出高度带（低于期望 3 格）才补，5 秒间隔仅为下限，补时仍抬头 55° 放；③其余不变（开火走 TLM performRangedAttack、24 格内每 2 秒一发；烟花耗尽或鞘翅损坏→模式自然未激活→退回地面）。说明：能绕圈（切向+半径修正）但飞行模型是鞘翅滑翔而非幻翼悬停，半径随速度变化，加高度保持后表现为稳定高度带绕圈。参数：RANGED_HOLD_HEIGHT/GAIN/BIAS、RANGED_BOOST_DROP、ORBIT_RADIUS、RANGED_BOOST_INTERVAL。编译零错、两个 server 回归 PASS、jar 重建部署三目标。
[05:10:00] v1.2.0 飞行作战·模式内两条强制限制（需求：该模式下女仆不会自主切换武器、自主战斗也不会被触发）：①不自动换武器——MaidToolAutoEquipBehavior.m_6114_ 对飞行任务直接返回 false，ensureForTask（主手择优换装）与 ensureShieldForCombat（副手换盾）都不再执行；模式内装备只由 MaidFlightKit.equip 补齐三件套（鞘翅/武器/烟花），主手已有合格武器时绝不替换；②自主战斗不介入——AutoCombatSwitch.tryEngageMaid 对飞行任务直接返回 2（已是战斗任务跳过），叠加已有三处 UID 排除（入战不进池/战中不换战术/还原视为玩家接管），参战评估→选任务→换战术→还原全链路都不碰。注：限制按任务生效——即使因没烟花/鞘翅损坏而模式未激活，只要任务还是飞行作战就不换武器、不被切走。另附兼容性结论：飞行近战与 TLM 攻击模式同判据（主手槽带 ATTACK_DAMAGE 修饰符，镐/弓/弩/御币排除）→ 多数模组近战武器天然兼容；飞行远战与 TLM 弓弩任务同判据（ProjectileWeaponItem）→ 原版弓弩/御币/多数模组弓弩兼容；TACZ 等枪械不属于以上两类，暂不参与（要接 GunCompat 另开一轮）。编译零错、两个 server 回归 PASS、jar 重建部署三目标。
[04:00:00] v1.2.0 回退「落地贴身就地近战」+ 强制受击绑定攻击频率（反馈：担心女仆只顾地面近战不再起飞；既然已有后门强制触发攻击事件就不需要这个改动；并强调强制受击的间隔要取决于女仆的攻击频率）：①回退——删掉 GROUND_FIGHT_RANGE 与「落地时目标仍在 5 格内 → 就地近战收尾」的分支，恢复原逻辑（落地只要在 LAUNCH_RANGE(20) 格内且能放烟花就立刻起跳重新进入飞行链路，够不到才退回地面近战），飞行近战循环恢复为「一直在飞」；②smashHit（含主目标与范围补命中）新增攻击冷却闸 ATTACK_READY——冷却没好就不出手，出手后按女仆自己的攻击间隔 20/ATTACK_SPEED（与 TLM MaidMeleeAttack 同口径）记冷却，所以强制受击是「每次能攻击时最多一次」而不是无条件每 tick 触发；③保留命中率另两项：攻击判定距离 4.0 格 / 收翅后 2 tick 即可出手、被无敌帧吃掉时清零 f_19802_ 再打一次。飞行远战不受影响。编译零错、两个 server 回归 PASS、jar 重建部署三目标。
[03:20:00] v1.2.0 飞行作战拆分为「飞行近战 / 飞行远战」（需求：手持远程武器时近战链路不适用——起飞不变，其后改为持续在天上盘旋、每 5 秒补一次烟花，攻击改为用手持远程武器在锁敌范围内开火，击败敌人后同样降落）：①原 maid_smart:flight_combat 显示名改为「飞行近战」（UID 保持不变，老存档不受影响）；②新增 maid_smart:flight_ranged「飞行远战」（图标=弓，不响应自主切换），三件套=鞘翅+任意远程武器（ProjectileWeaponItem：弓/弩/御币/模组弹射武器）+烟花火箭；起飞方式与近战完全相同（起跳滑翔+放烟花背离+向上）；起飞后不再扑击，改为绕目标约 10 格持续盘旋（切向视线+半径自动拉回），每 5 秒（100 tick）补一枚烟花——补的那一下先开 20 tick 的「抬头 55° 窗口」，让推力全部用在爬升、抵消滑翔下沉；开火走 TLM 自己的通道 EntityMaid.m_6504_(performRangedAttack)：本任务实现 IRangedAttackTask，在 performRangedAttack 里自己找箭（副手优先、其次女仆背包——原版 getProjectile 找不到女仆背包）、造箭、朝目标射出、耗 1 箭+耗耐久+射击音效；刻意不注册 TLM 的 MaidShootTargetTask（它每 tick 拽视线，与盘旋转向打架）；击败敌人后行为结束→清滑翔落地（与近战一致），落地后还有目标就重新起飞恢复盘旋。③MaidFlightKit.isFlightTask 现在覆盖两个 UID，所以鞘翅渲染/滑翔禁传送/飞行作战期间不收落地水雪/自主切换三处排除自动对两个模式同时生效；武器位判据按任务分流（近战认近战武器、远战认远程武器）。编译零错（218 源文件）、两个 server 回归 PASS、jar 重建部署三目标。
[02:00:00] v1.2.0 飞行作战·命中率与展翅修复（同 1.21.1 同步）：①命中率——攻击判定距离 2.5→4.0 格、收翅后 t≥2 tick 即可出手；以女仆为中心 2.5 格内的其他合法敌对目标强制补结算一次攻击（只认 IAttackTask.canAttack，女仆一律跳过 = 女仆免疫重锤友伤）；被无敌帧吃掉时清零 f_19802_(invulnerableTime) 再打一次。②落地时目标仍在 5 格内 → 就地近战收尾，不再立刻起飞（修"落地以后打不到怪"）。③飞行作战期间不收落地水/雪。④滑翔中强制完全展翅（原版会按下落速度部分收拢）：新增 ElytraModelAccessor（SRG 字段 f_102533_/f_102532_）+ ElytraSpread（ModelPart f_104203_/f_104204_/f_104205_ = xRot/yRot/zRot）。编译零错（217 源文件）、两个 server 回归 PASS、jar 重建部署三目标。
[00:30:00] v1.2.0 新增"飞行作战"任务（1.20.1 版，武器无关 + 暴击）：三件套 = 鞘翅 + 任意近战武器 + 烟花火箭，齐备才激活（缺任一件则与普通攻击模式一致）。链路：遇到敌人先【起跳滑翔】（跳一下离地——挂载烟花只对正在滑翔的实体给推力，而站在地上置位会被 LivingEntity.updateFallFlying 清掉）→放烟花给"背离敌人 + 向上 62°"的初速→1.5 秒后转入飞行、朝敌人飞（滑翔的唯一操纵杆就是视线方向）→进入 3.5 格【取消滑翔】收翅自由落体→触底前一次近战命中（1.20.1 无重锤，结算原版暴击 ×1.5：伤害 = 攻击力 × 1.5 + 附魔加成；依据是滑翔中 fallDistance 被 Entity.m_245125_() 钳在 ≤1.0，收翅后再掉 2~3 tick 就满足暴击的 fallDistance>0）→命中后【切回滑翔】→再放烟花，如此反复直至怪物死亡或模式退出；烟花用完或鞘翅损坏（滑翔每 20 tick 扣 1 点耐久）则模式自然失效、退回普通攻击模式。实现：新增 MaidFlightKit / MaidFlightCombatTask / MaidFlightCombatBehavior（SRG 化）、双路径鞘翅图层 LayerMaidElytra（Bedrock，照抄原版 ElytraLayer 配方）+ LayerMaidElytraGecko（GeckoLib，补 scale(-1,-1,1) + translate(0,-1.501,0) 的空间换算）、mixin EntityFlagInvoker（暴露 setSharedFlag/getSharedFlag 第 7 位滑翔标志）/ MaidSwimGlideMixin（滑翔时套游泳展翅动画）/ LivingEntityRendererAddLayerInvoker + MaidElytraLayerMixin + MaidElytraLayerGeckoMixin（客户端注册图层，不用 ILittleMaid.addAdditionMaidLayer 以免专用服务器 RuntimeDistCleaner 崩溃）；接入 mixins.promaid.json、addMaidTask、配置项 combat.flightMode、配置面板、lang；AutoCombatSwitch 三处按 UID 排除（入池/换战术/还原），MaidTeleportPreserveMixin 增加"滑翔途中禁传送"。踩过的 1.20.1 坑：RenderLayer 抽象方法在 SRG 里是 m_6494_(…,Mob,…)；Behavior 的钩子是 m_6114_/m_6737_/m_6725_/m_6732_；烟花是 NBT 结构（只写 Fireworks.Flight、不写 Explosions → 挂载烟花到期不炸自己）；EntityAnchorArgument 在 net.minecraft.commands.arguments 包；ItemStack.isEmpty()/EMPTY = m_41619_()/f_41583_。编译零错（215 源文件）、两个 server 回归 PASS、jar 重建部署（neo 客户端/1.20.1 客户端/pack1201）。
[11:00:00] v1.2.0 落地雪补齐独立配置 + 落地水/落地雪默认触发高度改为 4 格（需求：落地雪没有像落地水那样的下探填写面板，配置只能调落地水；同时两者默认释放高度改为 4 格）：①问题——落地雪此前只借用落地水的三个数值（触发高度 / 保持时长 / 下探格数），配置面板里只有"落地水"的那三项，落地雪的调不了。②改动——落地雪新增三项独立配置：触发高度（snowFallDistance，默认 4）、保持时长（snowHold，默认 5 tick）、下探格数（snowLandingScan，默认 2），面板在「战斗与自保 → 落地水/落地雪」区补齐四行（开关 + 三项数值），水/雪两条路径各读各的值，互不影响（两者都有桶时仍优先用水）。③默认值——落地水触发高度 6 → 4 格、落地雪同样 4 格（旧档里存着旧默认 6 的会自动迁移到 4，手动改过的值不动）。④顺带修复一个沉默很久的 bug（实测才发现）——旧版把配置事件 ModConfigEvent 注册在了 Forge 主事件总线上，而它其实是【MOD 总线】事件（implements IModBusEvent，javap 实证），因此该回调从未被调用过：此前累积的所有"旧默认自动迁移"（穿透预算 22→6、看门狗 30/45→8、搭路 8→5 等）其实一直静默失效。现在改为注册到 MOD 总线，并在服务端启动时兜底再跑一次；Neo 侧另发现迁移结果不回写磁盘（运行时值已变但文件仍旧），改为在配置事件里拿到官方 ModConfig 显式 save。⑤验证——实测两树都会把故意写回的旧默认 6.0 迁成 4.0、22 迁成 6，且磁盘文件与运行时一致；两树编译零错、jar 重建部署 6 处、server 回归 PASS。
[10:10:00] v1.2.0 开局赠礼改为原版进度系统：①现象与实证——实机日志显示同一存档 10:55 登录发一次、10:59 又登录又发一次（每次登录都发），背包里确实多出书。旧版是在玩家的 persistentData 里手写一个 maid_smart_blueprints_given 标记来判断"已发过"，这个手搓标记拦不住跨会话重发。②正解（参照 TLM《记忆中的幻想乡》）——那本手册就是用【原版进度系统】发的一次性赠礼：自定义触发器 + 进度 json + 奖励掉落表，「只发一次」由原版进度数据保证（服务端强制持久化、随玩家存档走）。本模组照做：新增 data/maid_smart/advancements/first_join_gift.json（用原版 minecraft:impossible 触发器——它永远不会自己触发，只由本模组显式授予，正好当"已领取"记录）+ 奖励掉落表 gift/first_join.json（两本书）。发奖励只在"从未完成 → 完成"那一刻触发（PlayerAdvancements.award 字节码实证：仅 !wasDone && isDone 才调 AdvancementRewards.grant），重复授予同一个已完成的进度是空操作。③老存档迁移——已用旧标记拿过书的人：静默把进度置为已完成但【不触发奖励】，不会多给一份；没拿过的照常首次发放。④兜底——万一数据包缺失或进度系统异常，退回旧的标记+直接塞背包，至少保证功能不消失。⑤验证——两树编译零错；差分测试证明进度真的加载（旧 jar 2081 条 → 新 jar 2082 条，正好 +1，且无 maid_smart 解析错误）；jar 重建部署 6 处；server 回归 PASS。1.20.1 与 1.21.1 的数据包目录名不同（advancements/loot_tables vs advancement/loot_table），两树已分别适配。
[09:40:00] v1.2.0 复活后反复摔死：实机日志确认 + 死亡循环断路器（整合包实测反馈）：「女仆摔死后自动复活，复活瞬间又摔死，反复循环」。①日志实证（整合包 latest.log）——受击类型明确是 fall（摔落）而不是战斗伤害：`[maidhurt] 类型=fall 伤害=91.4 位置=(28.2,294.0,101.9)`，另有 88.7/87.9/86.1/113.1 等共 9 次，落点高度 y=282~294（空岛平台）与 y=112~115（地面），与「从 y≈386 天上掉下来」完全吻合；女仆只有 20 血，摔伤 86~113 必死。②根因同实测四百五十——安全落点函数把 getHeight（384，维度总高度）与 getMinBuildHeight（-64）写反，两个扫描循环全空 → 兜底落点算到 y≈386 天空，一放出来就自由落体。该修复已在此前完成（上下界归位 + 改走原版 findStandUpPosition）。③新增【死亡循环断路器】——光修落点是治因，但只要任何因素让复活点不安全（地形被改/床被拆/跨维传送），「复活即死」仍会复发，且延迟设得越小转得越快（该整合包把复活延迟调成了 1 秒，所以变成 4 秒一轮的高频循环）。现在：同一只女仆在【上次复活后 30 秒内】又死亡 → 判定复活点不安全，把下次复活退避推迟（1 分钟起、翻倍、上限 10 分钟）并给主人一条明确告警（提示检查重生点或先关自动复活）；正常间隔的死亡不受影响，关掉自动复活时断路器状态一并清空。④顺带说明——TLM 原版右键墓碑只做「归还物品 + 删除墓碑」（字节码实证：全程无 EntityMaid/load/addFreshEntity），并不复活女仆；「自动复活」是本模组新增能力，因此不存在可照抄的原版复活实现，本模组已按原版口径复用玩家复活的 findStandUpPosition 求落点。两树编译零错、断路器退避数学单测通过、jar 重建部署 6 处、server 回归 PASS。
[09:20:00] v1.2.0 排班表血量百分比公式修正：女仆名字后面那个百分比此前取反了——写的是最大/当前（满血恰好 100% 所以一直没被发现），掉血后数字反而往上涨（15/20 显示 133%、10/20 显示 200%、1/20 显示 2000%，完全没法看）。现改为当前/最大，与该功能其余 8 处同类计算口径一致：掉血就显示 75%、50%、5%。两树编译零错、jar 重建部署、server 回归 PASS。
[08:00:00] v1.2.0 复活后原地反复摔死修复 + 清理失效配置项：①根因——「安全落点」函数把两个高度取值写反了：m_141928_ 是 getHeight（主世界 384，维度总高度），m_141937_ 是 getMinBuildHeight（-64），代码却写成「最低建筑高度 = getHeight+1 = 385」「上限 = getMinBuildHeight-3 = -67」，两个扫描循环全成空循环 → 落到兜底分支「原坐标上方 1 格」→ 实际复活点在 y≈386 的天空，女仆一放出来就自由落体摔死；摔死又触发自动收符、放出再摔，形成死循环。1.21.1 侧同名函数同样写反。②修复——上下界各自归位（minY = getMinBuildHeight+1、limitUp = getMaxBuildHeight-3）；复活/死亡传送的落点新增「原版等效站位」：床与重生锚走原版 BedBlock/RespawnAnchorBlock 的 findStandUpPosition（就是玩家复活时站的那一格），床是两格宽方块，之前自己柱状扫描会把她放到床边地面、与原版位置差半张床。③复活清洗（用户建议的兜底）——死亡快照先清 FallDistance/Motion/Fire/DeathTime/HurtTime 再 load（否则她带着「还在下坠」的状态出现，落地首 tick 再吃一次摔落伤害）；复活后清死亡/受击计时、清着火、清全部负面效果，并给抗性提升 V + 抗火各 2 秒作为保护窗口；魂符释放（TLM 释放逻辑读的就是同一份 NBT，已反编译确认）同样先清洗再 load，放出即摔死的死循环一并堵掉。④清理失效配置——「释放血量比（0.35）」从写入之日就没有任何读取方（TLM 释放走的是自己存档里的血量），现整体移除该配置项与相关 NBT 写入。两树编译零错、落点算法单测通过（修复前 y≈386 天空 → 修复后贴地）、jar 重建部署、server 回归 PASS。
[06:40:00] v1.1.1 蛋糕可食用——新增配置开关：①定位——本模组把 minecraft:cake 设为可食用物品（"女仆爱吃蛋糕"的设定），这会让"按食物判定识别投喂目标"的第三方模组（如 solmaiddream）把蛋糕也算作投喂物，并在不检查女仆是否已有主人的情况下抢走这次右键交互；而 Forge 的 Player.interactOn 在事件被取消后【不会再调用 mobInteract】，TLM 的 tameMaid（消耗驯服物+认主）因此不执行；②实测确认——未加装该第三方模组时，喂蛋糕驯服野生女仆完全正常、成就照常触发，说明这是模组间的交互冲突，不是本模组的功能缺陷；③改动——新增 misc.cakeEdible 开关（默认开）：关闭后蛋糕恢复原版行为（只能放置、女仆不再当食物），「女仆吃蛋糕／喂蛋糕加好感」相关功能整体停用，遇到上述冲突可直接关掉；④未做其它改动：不加事件拦截、不改变驯服逻辑。
[06:10:00] v1.1.1 正式发布（1.20.1 Forge 从 v1.1.0 升版）：本版把 v1.1.0 发布之后的全部改进合并发布——内置日语语音包（121 条，含情绪分档与规则气泡补漏）、冷却 HUD（复活倒计时 / 回魂符冷却）在 1.20.1 的渲染根因修复、悬空禁搭方块、床铺互通、女仆自动复活、重锤猛击（1.21.1）、收符期间冷却条保留、睡觉静默气泡与语音、配置面板重组（两级菜单 7 大类 28 小类）、手册详细介绍重写与一键跳转配置等；mods.toml 版本号 1.1.0→1.1.1，附件更名 promaid-1.1.1.jar（升级时请删除旧的 promaid-1.1.0.jar，避免两个同 modId 的 jar 同时加载）。
[05:40:00] v1.1.0 规则气泡语音补漏 6 条：①根因——WorkStatusReporter 的"卡住原因"气泡是以变量传入的（addTextChatBubble(reason)），"附近没有值得挖的矿石 / 我没有镐，没法挖矿——给我一把镐吧 / 附近没有需要打理的农田了 / 被骑乘着，动不了"四条文本从来没有进内置语音包 manifest，JarVoicePack.matchKey 落空 → 回落 TLM TTS 人机语音（不是没触发，是没登记）；②全盘扫描——site-aware 提取两棵树所有 addTextChatBubble 调用（含拼接与三元）并追到变量间接来源（WorkStatusReporter/PerceptionManager/EmotionNetworking/ScheduleBubbleBehavior/SmartDesignTool/MaidAidOwnerBehavior），逐条与 manifest 比对，除上述 4 条外还发现 MaidAidOwnerBehavior 金苹果投喂的"主人，金苹果给你！/主人，附魔金苹果给你！"也未覆盖，共 6 条；③新增 6 条日语配音（附魔金苹果条目排在普通金苹果之前，防 contains 遮蔽），manifest 115→121 条，ASR 客观校验通过（如「近くに掘る価値のある鉱石が無いの」整句转写正确）；④校验——121 条逐条用自身 text 反查，零遮蔽；语音随 jar 分发，重建两 jar + 部署 6 处。
[05:00:00] v1.1.0 冷却 HUD 在 1.20.1 不渲染的【真正根因】：窗口高度取错了 SRG 字段（顺带修建造 HUD 同款）。①证据链——从玩家上一轮会话（已轮转的 debug-1.log.gz）里看到：服务端每秒下发（revive/soul 都有）、客户端有「first snapshot received」和「first render event」，却【没有 first draw】——回调进来了、数据也在，是进到函数里被某个守卫提前 return 了。②根因（对照 srg1201_to_moj1211.json）：Window 的 SRG 名是 m_85445_=getGuiScaledWidth / m_85446_=getGuiScaledHeight / **m_85447_=getX（窗口位置！）**；433/444 两版都误把 m_85447_ 当高度 → h 拿到的是窗口 X 坐标，窗口贴左（最大化/全屏 x=0）时 h-12=-12，而 y=4 永远大于它 → 每帧提前 return，HUD 恒不显示；只有窗口恰好在 x≥16 的位置时才偶然画得出来（这就是"我自己拉个窗口测试就正常、你那边一直没有"的原因）。③修复——冷却 HUD 改用 m_85446_；**建造 HUD 同款错误一并修**（w 应为 m_85445_、h 应为 m_85446_，旧版 w/h 双双取错，折行宽度与"超出屏幕不画"判定一起失真）；另外加一道保险：h≤32 视为取值异常时不拦（宁可画出来也不要因为取值错误整块消失）。④诊断——新增 cooldown hud: SKIP[原因] 一行（按原因各记一次，最多 5 行），以后再出问题能直接看到是 screen / f3 / stale / noRoom / fontNull 哪一个拦的。⑤实测验证——把存档复制成一次性世界、用玩家本人 UUID 启动 1.20.1 客户端、并把窗口贴到屏幕左上角（复现 x=0 的失败条件），杀掉一只女仆触发待复活后：latest.log 依次出现 first snapshot received (3 entries) → **first draw at y=44**，HUD 实际画出来了；测试世界与临时脚本已清理，原存档未改动。1.20.1 编译零错、jar 重建部署、server 回归 PASS。1.21.1 侧本来就用 getGuiScaledHeight（Mojmap），不受影响。
[04:40:00] v1.1.0 语音包情绪化重制 + 落地水语音/颜色两个 bug：①情绪分档——manifest 只存中文 key、旧日语台词没落盘，本次按中文语义【重写 115 条日语台词】，并按情境分五档情绪：战斗 20（郑重参考+语速1.08）/关心 11（放慢0.95）/俏皮 60（含 49 条排班闲聊+钓鱼+天气+拥抱摸头，换用同一位女仆的另一条俏皮参考音频+1.05）/干活 17（1.03）/请求 7（俏皮参考）。两条参考音频都是小酒狐本人，不会变声，只是把"郑重 vs 俏皮"的语气底色换开。②采样参数是 ASR 对照试出来的：temperature 1.15 / top_k 20 / top_p 0.95 这组会把短句合成糊掉（「敵が来たよ、気をつけて！」被转写成「てちがちだよ 塩つけて」），而语速 1.08 + 默认采样（temp 1.0 / k15 / p1.0）清清楚楚——所以情绪靠【参考音频 + 语速】做，采样一律用验证过的默认值；五档各抽一条 ASR 复核（enemy_near/aid_food/hug_02/build_done/no_food_left）全部清晰。③落地水"没语音、还是人机语音"的根因——SystemTTSManager 旧版把「内置包最小间隔（默认 8 秒）」的判断放在命中判定【之前】：命中但被间隔挡下时会继续往下走，最终落到 ④ TLM TTS 合成。现在命中即由内置包负责，被间隔挡下就【静默】（绝不换人机语音），并让落地水/落地雪/敌人靠近三句豁免该间隔。④[警示]红字——落地水/落地雪是女仆自己的动作播报，不再按"敌袭警示"染红（聊天框前缀与世界气泡颜色都改回常规青色）。两树编译零错、jar 重建部署、server 回归 PASS。
[04:05:00] v1.1.0 冷却 HUD 在 1.20.1 恒不渲染根因修复：①证据——1.20.1 客户端 latest.log 有「cooldown hud: first snapshot received」却【没有】「first draw」：数据（服务端每秒下发、含 soul:名字:秒）正常，是客户端渲染回调从未进入。②根因（1.20.1 侧独有，1.21.1 的 NeoForge RenderGuiLayerEvent 同款写法是好的）——旧版用 @Mod.EventBusSubscriber 注解自动注册 + RenderGuiOverlayEvent.Post 只认 HOTBAR 层；1.20.1 上该注解自动注册对客户端 FORGE 总线这类没生效（同类里只有 MOD 总线/懒注册的先例），于是事件永远到不了本类。③修复——改用 RenderGuiEvent.Post（反编译 ForgeGui 实证：render 末尾每帧必然 post 一次，不再依赖"逐层 overlay 事件 + 比对 minecraft:hotbar"），并改为【显式注册】：客户端 Mod 构造期由 PromaidClientSetup.registerHudHooks() 调 CooldownHudRenderer.ensureRegistered()，onSnapshot 里再兜一次（registered 闸防重复）。④诊断加强：新增「cooldown hud: first render event」一行，和 first snapshot / first draw 三点连成一条链，一眼区分"没注册/没事件/没绘制"。⑤本次用客户端烟测验证：把存档复制成一次性世界 _hudtest 后用测试账号启动 1.20.1 客户端，latest.log 依次出现 first snapshot received (2 entries) → first render event → first draw at y=4，HUD 实际画出来了；测试世界与测试账号条目已清理，原存档未改动。1.20.1 编译零错、jar 重建部署、server 回归 PASS。
[03:35:00] v1.1.0 悬空禁搭方块：①统一闸口——四个搭方块模块（自保搭高/搭路/挖矿垫脚/伐木垫脚）都在各自 takeBuildBlock 取料前问 MaidPlaceGuard.blocked：悬空即返回 null → 各模块自然放弃本次放置（不消耗方块、不动世界）；取料失败的四条"没有搭方块的材料"气泡同样静默（否则悬空时会误报）。②判定口径——开关 misc.noPlaceInAir（默认开）；站在地面/水里/岩浆里、骑乘、鞘翅滑翔一律放行；其余情况坠落距离 ≥「落地水触发高度」(combat.waterFallDistance，默认 6) 才算悬空禁搭（这个高度落地水本来就会接管——搭方块既救不了她，又会把落点的水/结构改掉挡住落地水）。③不影响正常垫高——本模组的垫脚都是站在地面/浅跳时往前方脚下垫（fallDistance≈0），照常工作。两树编译零错、jar 重建部署、server 回归 PASS。
[02:35:00] v1.1.0 收符期间冷却条消失修复：①根因——HUD 的"女仆在符里"分支只认【自动标记】的魂符（AUTO_SAVED_TAG + 冷却戳）；玩家手动用空魂符收女仆时魂符是 TLM 自己 new 的、不带任何标记 → 扫背包查不到 → 冷却条消失（冷却其实记在女仆数据里继续计时）。②修复——TLM 的 storeMaidData 会发 MaidAndItemTransformEvent.ToItem（反编译实证：1.21.1 在 AbstractStoreMaidItem、1.20.1 在 ItemSmartSlab），新增 onSoulSpellToItem 钩子：女仆仍在冷却时把冷却戳+名字盖到魂符物品上，自动/手动两条收符路径全覆盖；charmCooldownUntil 放宽为只认冷却戳（AUTO_SAVED_TAG 仍只用于"释放时是否重算冷却"）；自动路径改为先写女仆数据再 storeMaidData，确保钩子拿得到本次冷却。③顺带修魂符落位 bug：主手恒写 items[0]（选中槽≠0 时顶掉 0 号槽物品）、副手误写 armor[0]（顶掉靴子）→ 改为 items[selected] 与 offhand[0]。④冷却HUD 日志补条目详情（kind:名字:剩余/总），便于下次一眼区分"没数据"还是"名字丢了"。两树编译零错、jar 重建部署、server 回归 PASS。
[02:05:00] v1.1.0 敌袭/感知系统消息日语语音 6 条：根因——PerceptionManager 的 7 条感知气泡（敌袭出现/靠近、敌人清空、主人受伤、主人低血、主人注视、天气变化）从未进内置包 manifest，故回落到 TLM TTS 合成（即"人机语音"）；且文案带动态距离/血量数字，exact 模式本就无法命中。修复：新增 6 条 contains 前缀映射 + 日语语音（enemy_near/enemy_clear/owner_hurt/owner_low_hp/owner_looking/weather_change.ogg，GPT-SoVITS 小酒狐合成、峰值归一化 -1.5dB、libvorbis q4）；"有敌人靠近"一条同时命中"…了！离我 X 格"与"…离我 X 格了"，"天气变成"一条覆盖下雨/雷雨/放晴；气泡照旧显示精确数字，语音说固定台词（不念数字）。条数 109→115（60+49+6），面板/手册同步。两树编译零错、jar 重建部署、server 回归 PASS。
[01:40:00] v1.1.0 回魂符冷却放出后消失根因修复：javap 实证 1.21.1 NeoForge 实体持久化键是 NeoForgeData（不是 Forge 1.20.1 的 ForgeData），neo 树把释放时的冷却写进 ForgeData 子标签 → getPersistentData() 读不到 → 冷却失效+HUD 不显示；修复：neo 的 FORGE_DATA_TAG 改 "NeoForgeData"（含 MaidInfo 子 NBT 路径），两树再加「直接写实体 persistentData」双保险（防 TLM 事件后才 apply data）；冷却仍从释放时刻重新起算。两树编译零错、jar 重建部署、server 回归 PASS。
[01:05:00] v1.1.0 右键墓碑不再当场复活：新增 MaidAutoResurrect.cancelPendingOnTombstoneClick（服务端+主手+本人待复活登记时移除该登记），mixin 由 MaidTombstoneReviveMixin（立即复活）重写为 MaidTombstoneClickMixin（不取消事件→右键走 TLM 原版归还物品，同时取消本次自动复活）；删除废弃 reviveFromTombstone/pendingOwnerOfTombstone；mixins.promaid.json 同步改名；手册「女仆自动复活」章对应改写。两树 gen_compile 重建源清单 + 编译零错、jar 重建部署、server 回归 PASS。
[23:45:00] v1.1.0 拥抱/摸头亲昵语音 6 条：EmotionNetworking 的 say() 里拥抱 3 条（抱抱！好温暖～/主人的怀抱最安心了～/嘿嘿，被抱着都不想动啦～）+ 摸头 3 条（嘿嘿，好舒服～/摸摸头就又有精神了！/最喜欢主人摸头了～）用 GPT-SoVITS 小酒狐合成日语并峰值归一化 -1.5dB，产物 hug_01~03/pat_01~03.ogg 打进 jar（两树），manifest 追加 6 条 exact → 共 109 条（54+49+6），已脚本校验 6/6 命中；括号旁白叙述不进语音（按要求排除）；无需改代码（say→addTextChatBubble→ChatBubbleLimitMixin→SystemTTSManager 本就会命中内置包）；面板/手册条数 103→109。两树编译零错、jar 重建部署、server 回归 PASS。
[23:00:00] v1.1.0 冷却 HUD 照搬 HeartPact 显示机制 + 收符窗口缺口：①证据——1.20.1 实例 promaid.log 显示 22:30~22:31 服务端每秒确有「[冷却HUD] 下发 1 条」但屏幕无 HUD → 数据正常、渲染通路坏；②改为 @EventBusSubscriber 注解常驻注册（去掉懒注册），绘制事件只认 HOTBAR 层（1.20.1 RenderGuiOverlayEvent.Post+VanillaGuiOverlay.HOTBAR；1.21.1 RenderGuiLayerEvent.Post+VanillaGuiLayers.HOTBAR），带阴影/升序/M:SS；③补收符窗口缺口——MaidSoulSpellGuard 收符时把女仆名写进魂符（AUTO_SAVED_NAME_TAG）并新增 charmCooldownUntil/charmMaidName，CooldownHudTracker 扫描玩家背包冷却中的魂符，女仆在符里也显示「回魂符 · 名字 M:SS」；④客户端加两条诊断日志（first snapshot / first draw）与服务端「冷却HUD」配对。两树编译零错、jar 重建部署、server 回归 PASS。
[22:25:00] v1.1.0 搭路默认开启 + 配置迁到「移动与行为」大类：①bridge.enabled 默认 false→true（两树），注释/面板说明「默认关」→「默认开」；已有实例 toml 里写死的 enabled=false 也一并改为 true（6 个本地实例），否则旧值会盖过新默认；②Section.BRIDGE 大类 SURVIVAL→MOVE，groupHint 两处同步；③手册同步：可点链接改 [[@MOVE:BRIDGE|搭路]]、大类小类清单与「怎么找开关」迁移、被动技能章两处大类别名改写、搭路「默认关」→「默认开」；④BridgeUpBehavior 类注释同步。两树编译零错、jar 重建部署、server 回归 PASS。
[22:10:00] v1.1.0 冷却 HUD 恒不渲染根因修复：①根因——四个 HUD 渲染器（两树×冷却/建造）的 F3 门禁都误写成 options.useNativeTransport（该值默认 true，玩家 options.txt 亦为 true）→ 条件恒真 → onGui 一进来就 return，HUD 永远不画；正确字段 1.20.1 为 Options.renderDebug（f_92063_，Gui 字节码实证）/1.21.1 为 getDebugOverlay().showDebugScreen()（javap 实证）；②连带修 1.21.1 建造 HUD 的 w/h 颠倒与折行误用 drawCenteredString（x=4 为中心画到屏幕外）；③显示对齐 HeartPact 分娩倒计时——带阴影、按剩余秒升序、时间 M:SS；1.20.1 改用 RenderGuiEvent.Post 整帧只画一次；④CooldownHudTracker 加限频「冷却HUD」日志便于区分没数据/没渲染。两树编译零错、jar 重建部署、server 回归 PASS。
[21:55:00] v1.1.0 睡觉中静默系统气泡与语音：改动用 LivingEntity.isSleeping()（1.20.1 SRG m_5803_，字节码实证=getSleepingPos().isPresent()，与 startSleeping 同源）判定——①ChatBubbleLimitMixin.addTextChatBubble HEAD 睡着直接 -1，拦住所有系统气泡 + 主人聊天框同步 + 汇入的 TTS/内置语音包朗读；②SystemTTSManager.speak 入口兜底 return，拦住排班气泡等直接调用者；③ScheduleBubbleBehavior 显式判睡（原为"简化不判"注释）；④MaidCakeEatHandler 直发 addChatBubble 路径睡着不弹蓝气泡/消息，回血与好感照常。两树编译零错、server 回归 PASS、已部署。
[21:40:00] v1.1.0 排班气泡日语语音包：①ScheduleBubbleBehavior 的 49 条排班贴身气泡全部翻成日语，用 GPT-SoVITS 小酒狐合成（同四百二十流程），每条峰值归一化到 -1.5 dB；②sched_01~49.ogg 打进 jar（两树），manifest 追加 49 条 exact 映射（追加在 54 条系统消息之后，脚本校验无截胡）；③冒泡后调用 SystemTTSManager.speak 接入语音链（命中内置包即播并压制原生）；内置包总条数 54→103，面板与手册同步；④两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[21:20:00] v1.1.0 内置语音包响度修复：①根因——ffmpeg 实测内置 ogg 平均 -32 dB / 峰值 -12 dB（GPT-SoVITS 直出未做响度处理），是素材太轻而非播放链路问题；②修复——两树各 54 条 ogg 峰值归一化到 -1.5 dB（volume+alimiter，libvorbis q4），平均响度提升约 11 dB（-32→-21 dB）；音量上限 5.0→20.0（jarPackVolume，默认仍 1.0）；③配置面板与手册（含条数 53→54）同步；④两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端（含整合包实例）与 pack1201
[21:00:00] v1.1.0 女仆复活机制修复：①根因——到期登记用 getGameTime、检查用 getTickCount，老存档 now>=due 永不成立（不触发）；且开启时清空墓碑容器导致右键墓碑拿不到东西（看起来像点击复活没了）；②修复——统一 getGameTime 口径（HUD 同步）；不再清空墓碑，新增 mixin MaidTombstoneReviveMixin 注入 EntityTombstone 右键：开启时主人右键墓碑=立即复活并在主人重生点落地，关闭时完全不介入=纯 TLM 原版（右键归还物品），并在关闭时丢弃待复活表防重复复活；③新增配置 autoResurrectTiming（0=延迟 N 秒 / 1=次日黎明，照驯养革新宠物床），面板「生存与复活→死亡与复活」加「复活时机」循环按钮，中英翻译与手册同步；④两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[20:50:00] v1.1.0 主人踩踏刷新扩展到挖矿/伐木/自保垫脚方块：PlacedBlockTracker 的 refreshOnOwnerStand 由仅搭路扩展到四套实例全部开启——挖矿/伐木（4.0/6.0/true）、自保战斗方块（0.5/12.0/true）与搭路一致：绑定女仆的主人在同维度踩在其方块上即补满回收寿命，玩家跟在女仆后面挖矿/伐木/爬塔不会踩到即将到期消失的垫脚方块而坠落；手册说明同步泛化；两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[20:40:00] v1.1.0 手册详细介绍重写 + 一键跳转配置：①手册正文新增链接语法 [[@大类:小类:行标签|文字]]——GuideScreen 换行把链接当原子 token（按标签宽度计量、不拆行），渲染成青色下划线并记录命中区，点击经 PromaidConfigScreen.openAt 直达配置对应页（大类/小类/具体参数行三级定位，跳转后目标行金色高亮，配置面板以手册为父界面、保存并返回回到手册）；②新增首章「功能总览·一键跳转配置」（7 大类 28 小类的可点击清单）；每章正文末尾由 configLinkFor(标题) 自动附加「配置入口」链接；手册使用指南补充用法说明；③两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[20:30:00] v1.1.0 配置面板重组：①两级菜单——新增 Group（7 大类），重写 Section 为 28 小类（各自带所属大类），首页列大类、大类页列小类、小类页才是参数；原 passiveRows/combatRows/miscRows 三大页约 230 条参数按配置键拆成 19 个细化小类方法（生产与工作/AI 与对话/战斗与自保/生存与复活/移动与行为/语音与显示/系统与杂项）；两级菜单共用自适应 menuGrid，小类页返回分类、大类页返回大类；②开关集中化——移除手册内「自动复活设置」「日语语音包设置」两个设置页入口（相关代码标 @Deprecated 保留不可达），所有开关只在配置面板；手册导航章重写并同步全部交叉引用路径；③完整性脚本校验行数/配置键与重组前一致（Bool112/Num175/Btn6/Cycle3/Text5/Info1，无丢失重复）；④两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[20:20:00] v1.1.0 搭路方块 CD·主人踩踏也重置：PlacedBlockTracker 新增 refreshOnOwnerStand 构造开关（默认 false，挖矿/伐木/自保方块不变），expirePlaced 在原「女仆踩着/女仆在附近」刷新之外，新增 masterOnBlock——搭路实例开启后，绑定女仆的主人也踩在该方块上同样补满寿命；BridgeUpBehavior 两树搭路追踪器改传 true。两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201
[20:10:00] v1.1.0 冷却可视化 HUD：①服务端——MaidAutoResurrect 的 Pending 增记女仆显示名并提供 hudReviveEntries（复活倒计时与到期判定同源），MaidSoulSpellGuard 新增 hudCooldownSeconds（读 persistentData 的回魂符冷却），新增 CooldownHudTracker 每秒按主人打包两类倒计时；②网络/客户端——新增 S2C CooldownHudPacket 与客户端 CooldownHudRenderer（屏幕左上角「冷却」列表：复活倒计时 + 回魂符冷却，排在建造进度下方不重叠，开界面/F3 不画，2.5 秒无新快照自动清空），BuildHudRenderer 两树新增 bottomY() 供避让；③配置——杂项新增「冷却可视化 HUD」（misc.cooldownHud，默认开）+ 中英翻译 + 配置面板行，手册「女仆自动复活」章补充说明；④两树编译零错、test_server 1201/neoforge1211 均 PASS，已部署客户端与 pack1201（rename-swap）
[04:40:00] v1.1.0 内置日语语音包：①语音素材——用本机 GPT-SoVITS（小酒狐权重 e15/e8_s184 + 该角色日语参考音）合成 53 条系统消息日语台词（覆盖建造/投喂治疗/自保/落地水雪/钓鱼/不死图腾/排班/搭路/酿造/挖矿伐木/攻击等 49 个系统消息点 + 4 条兜底），ffmpeg 转 vorbis ogg 打进 jar（assets/promaid/voice/ + manifest.json）；②播放链路——新增 JarVoicePack（jar 内资源包，classloader 读取，最高优先级：先于磁盘语音包/TTS 缓存/TTS 合成），SystemTTSManager 命中后经新 S2C 包 PlayJarVoicePacket 只下发【女仆实体 id + 文件名】，客户端从自己 jar 取字节播放（省流量、两端一致）；内置包有独立门禁（开关 + 自带最小间隔），不要求配置 TTS 站点——开箱即用；③自管播放——新增 PromaidVoiceSoundInstance 继承 TLM MaidAISoundInstance（复用其 OGG/Opus/MP3 解码），构造后覆盖音量字段 = TTS 倍率 × 内置包倍率（要求的"可调音量"）；④压制原生语音包——新增 ClientVoicePlayback：播放前按音频字节估算时长开启压制窗口，窗口内 PlaySoundEvent 里把TLM 原生 MaidSoundInstance（1.20.1/1.21.1）与 MaidSoundInstanceAtPos（1.21.1）setSound(null)，窗口到期自动解除（要求的"播放时卡掉原生、播完解除、优先级更高"）；试听音不受压制；⑤手册——目录页新增「日语语音包设置」整页（开关 + 音量 + 最小间隔，与自动复活设置并排），配置面板「语音 → 内置日语语音包」四行（开关/音量/最小间隔/播放时暂压原生），四份 lang 补条目；⑥两树同步（1.20.1 SRG / 1.21.1 Mojmap），编译零错。
[04:35:00] v1.1.0 排班表快捷调整引入整页任务选择：①第 1 页「快捷设置」的任务行，点中间任务名 → 打开整页任务选择（与第 2 页排班槽共用同一页实现）——整页列出全部任务、分页点选，不再"点一下只换下一个"（任务多时要循环点十几下）；②两种来源靠 pickQuick 区分去向：快捷页进来=选中即立即生效（走既有 QuickApply 包，服务端校验排班锁定）并回快捷页；排班页进来=填入时段槽 + 未保存脏标记（原行为不变）；③左边「空闲」按钮快捷页=切到 TLM 空闲任务（touhou_little_maid:idle），排班页=清空槽；左上返回按钮按来源显示「返回快捷设置 / 返回排班」；④两侧 ◀▶ 箭头保留（旧习惯不变）；⑤标题与提示随来源切换（"点击任务立即切换她的当前任务" / "点击任务填入第 N 时段"）；两树同步，编译零错。
[04:30:00] v1.1.0 床铺互通·女仆床↔玩家床：①方向一【女仆睡原版床】——新增 MaidBedInteropBehavior 挂 REST 活动（经 TLM 扩展点 getRestBehaviors 注册，优先级 6 排在 TLM 自带 MaidBedTask=5 之后：女仆床优先），用原版 PoiTypes.HOME 找最近的原版床（16 色床 HEAD 都注册在 HOME），校验 is(BlockTags.BEDS)+PART==HEAD+未占用+在活动范围内，走到 2 格内调 startSleeping+setPos（占床/回血/好感度全走 TLM 既有逻辑）；TLM 原版 MaidBedTask 只查 InitPoi.MAID_BED 且硬判 state.is(女仆床)，所以原版床原本对女仆完全不可用；②方向二【玩家睡女仆床】——新增 MaidBedBlockInteropMixin（@Mixin BlockMaidBed）：isBed 对玩家与 null（重生点解析）返回 true（女仆仍走 TLM 原分支）、use/useItemOn 非染料时服务端调 startSleepInBed（染料仍优先走 TLM 染色；潜行右键不躺下）、neo 版并显式实现 getRespawnPosition（NeoForge 默认恒空，不实现则死亡复活会报"重生方块缺失"）；女仆床 OCCUPIED/PART 与 BedBlock 是同一 Property 实例、FACING 来自 HorizontalDirectionalBlock，占床/床朝向用平台默认实现即可；③两方向共用开关「模组详细配置→杂项→床铺互通」（默认开，关掉恢复 TLM 原版）；④两树同步（1.20.1 SRG / 1.21.1 Mojmap）；neo 编译 classpath 把 NeoForge 修补 jar 排到 vanilla 前（RespawnPosAngle 在未修补 vanilla 里是包私有，顺位反了编译不过——实测）；手册新增「床铺互通」章节；两树编译零错。
[04:25:00] v1.1.0 手册内自动复活设置页：①《详细介绍》章节目录页右下角新增「自动复活设置」按钮——一页直接改【总开关 + 复活延迟（秒）+ 复活血量比】三项，「保存并返回目录」即时生效，不用再跳「模组详细配置」面板；②输入交互照搬配置面板既有管线（点击显式聚焦 + 自跟踪 activeBox + charTyped/keyPressed 直接转发，1.20.1 走 m_5534_/m_7933_），避开焦点链差异导致"点得进打不了字"；数字文本延迟提交（输入时只校验红/白字，离开本页或关界面时统一写入 + SPEC.save()），不在输入路径写配置；③越界钳制到声明范围（延迟 1~86400 秒、血量比 0.05~1.0），非法/空文本跳过保留原值；④《详细介绍》新增「女仆自动复活（v1.1.0）」章节：运作链路、话语提示、血量比、保姆式测试步骤与"在哪里调开关和 CD"；顺手把手册一处过期"详见第 20 章"改为按章节标题引用（插入新章节不再编号漂移）；⑤设置页布局 = 控件与渲染共用一套坐标（行高随窗口自适应、说明按可用高度取舍），小窗口不重叠；⑥两树同步（1.20.1 SRG / 1.21.1 Mojmap），两树编译零错 + 服务器回归 PASS。
[04:20:00] v1.1.0 女仆自动复活（新功能）：①死亡瞬间抓取女仆完整存档 NBT（死亡事件早于背包搬走），墓碑创建时配对墓碑 UUID，写入持久化待复活表（SavedData 存主世界，跨维度共享、重启不丢）；②延迟到期（默认 60 秒）自动让墓碑消失（discard，同步清理 TLM 墓碑记录）并在主人重生点复活女仆（床/重生锚；无重生点则主世界出生点，安全落点）+ 气泡"主人……我回来了。"；③复活与 TLM 魂符释放同构（new+load+复用原 UUID+设落点血量+addFreshEntity），背包/饰品/任务/模型原样恢复；④复活时女仆用话语提示玩家（气泡"主人，我回来啦！让你担心了～" + 主人系统消息"你的女仆 XX 已复活"）；⑤抓取快照后清空墓碑容器（墓碑转纯标记，物品只存快照、复活归还）——防 60 秒窗口内拾取墓碑导致物品复制；⑥复活血量默认满血可调、deathTime/摔落/速度清零；主人不在线墓碑保留等她上线、无主女仆不复活；⑦开关/延迟/血量比三项在「战斗自保 → 女仆自动复活」小节，关掉恢复原版死亡流程。
[04:10:00] v1.1.0 彻底移除第三方专属软联动(问题：保留按攻击力属性识别的通用武器联动不动，只把对特定第三方模组的专属联动删干净)：①精妙储存/超越维度——删除 com.maidsmart.storage 整包(BoundStorageInteractHandler/StorageBindingStore)与 storage_bind_card/storage_unbind_card 两个绑定卡物品，含模型/贴图/配方/语言，并移除全部调用点(建造材料统计与取物回退、酿药取物回退、创造栏、主类注册)；②爱憎分明——删除饥饿门控 mixin、4 个联动配置项与配置面板「爱憎分明模组调试」整页(含版本反射/接口探测)、自保极端饥饿反射保命、相关语言键；③心契誓约(maidmarriage/Heartfelt)——删除拥抱/子女交互与调试面板 mixin、关系标签反射(MaidConfigMemoryMixin 的 RelationshipExemption)、纪念日情绪脉冲(AffectManager.onAnniversaryDay/onAnniversaryApproaching)、建造心契交互锁、Heartfelt 纪念日联动配置；④配置项清理——MEMORY_RELATIONSHIP_ADAPTER / MEMORY_RELATION_SCAN / MEMORY_TRUST_DELTA / MEMORY_HEARTFELT_ANNIVERSARY 及界面行、callresponse 语言键全部移除；⑤手册/README/CHANGELOG/mods.toml 描述同步为纯独立版。保留：按攻击力属性的通用武器判定/自动装备(tacz/卓越前线/拔刀剑/万法皆通等模组武器天然参与，无需专属代码)。两树同步，1.20.1 与 1.21.1 服务器回归均 PASS。
[03:00:00] v1.1.0 手册补写：战斗与自保——宠物免伤用法（命名牌改「玩家宠物/主人的宠物」、主人驯服的动物自动识别、模组宠物标记；女仆不锁定不攻击、溅射不误伤、仇恨自动清除）、带保命道具（绀珠之药/不死图腾）低血不逃跑、背包有模组武器必定切专属战斗模式（拔刀剑→拔刀剑模式）；被动技能——搭路新启动规则（只要水平距离+朝主人前方脚下悬空就铺方块踩上去，平地跟踪距离无上限；平桥启动距离默认 6 格 3~64 可调；挖矿/伐木垫块同款踩上）；农场与杂项——回家与传送（跨维度跟随/同维度 48 格拉回/Y 轴垂直 16 格拉回，主人旁安全落点才传，排班与守家不响应）；排班表——活动半径默认 32 格（杂项可调 8~512）、空闲散步（默认 10 秒一次/16 格半径/0.7 倍速，参数在杂项）、排班锁定下原版界面改任务当场弹回；烧制——什么能烧就烧什么（矿石/沙子/圆石/原木/模组食材，cookSmeltAny 默认开）、多女仆各占一炉（占用表+不抢炉+日志限频）；武器与工具——剪刀任务自动装备剪刀（forge:shears 标签模组剪刀同认）；对话——击杀邀功气泡默认关（想听在「对话提示」打开）；建造——走出红色区块橙色幽灵方块仍可见（越远越淡，不再整片消失）。同步项目根 CHANGELOG.md 实测二百零三。
[02:45:00] v1.1.0 合集·战斗与搭路（一百七十三~一百八十二，对照 v1.0.4 的新功能/修复摘编；完整逐条见项目根 CHANGELOG.md）：①自主战斗还原根治——还原扫描用无限 AABB 查询永远命中空（section 溢出坍塌，日志 active=0 但标记在），改有限 AABB（±131072/±4096）后战斗还原/排班扫描真正生效；②模组武器专属模式确定性选择——拔刀剑等被原版 attack 认作武器时同池加权随机 1/3 落原版，现同池有模组任务则原版让位；③熔炉多女仆分配+通用烧制——FURNACE_USERS 占用表、抢炉竞争校验、喂料全熔炉配方非装备类回退（cookSmeltAny）；④搭路新触发口径——水平距离+朝主人脚前方缺口即铺桥踩上（不看主人高低、缺口分支无距离上限），平桥冷却永锁修复（只在垂直腿递减=只搭一块），新增 walkOn 持续推送踩块（旧版一次脉冲半格就停在沟对面）。
[02:47:00] v1.1.0 合集·排班/散步/传送/防护（一百八十三~一百九十五）：①排班活动范围与散步——排班/home 模式活动半径增幅（scheduleActivityRange 默认 32，原 TLM 8~16）、空闲散步替代 TLM 原生（原生 0.3 倍速 5 格概率两小时一次；现在间隔 200tick/半径 16/速度 0.7）；②排班三连修——段软失败日志 5 分钟限频、散步全速鬼畜降速、TLM 面板换任务客户端脱钩修复（守卫拒绝即同步真实任务回客户端）；③跨维度跟随 home/排班拦截（同维度拉回早就有，跨维补上）；④Y 轴拉回——3D 48 格门槛按水平标定，竖直搭高 30 格不触发；新增 maidSameDimVertical 默认 16 格+主人旁安全落点判定；⑤宠物免疫——名字含「玩家宠物/主人的宠物」/MaidNoAttack 前缀/主人可驯服宠物：仇恨不进（canAttack 拦截+自清）、AOE 伤害全免（LivingHurtEvent 总闸）；⑥挖矿/伐木垫块走不上方块死循环修复（BlockWalkOn 持续推送踩块）；⑦击杀邀功气泡默认关（proactiveKill=false）；⑧建造投影 96 格剔除移除（走出区块幽灵方块可见）、Z 键旋转朝向提示每次点击都弹出；⑨排班表/手册贴图更换。
[05:50:00] v1.1.0 实测一百二十三：搭路启动距离门槛放宽。核查结论：已空中的女仆会（airMaxDist 开大到 ≥50 即逐块搭过去）；落地女仆旧版不会——canUse 距离上限只在女仆【自己已空中】时才用 airMaxDist，落地恒用 maxDist（7 格）：主人悬空/飞高时她走不到（导航无路）、传送可能找不到落点（无落脚方块），搭方块是唯一通路却被 7 格门槛挡在门外原地干站。修复：距离上限判定增加两个放宽条件——主人【空中】（onGround=false，创造飞行/下落）或主人【高于女仆】（dy≥1）时，落地女仆同样用 airMaxDist。安全论证：落地平地上平桥只在"前方脚下悬空"时才垫块（tryAirBridgeStep 要求 fill 为空气），实心地面走导航零副作用，不会在地上搭一串方块；跨空/爬高才真正搭方块。注意边界：airMaxDist 设 50 且主人恰在 50.0 格时因 `>=` 判定被拒，开大一点（60/64）更稳。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:43:00] v1.1.0 实测一百二十二：搭路速度对齐玩家 + 方块滞留时间联动。原版无放置冷却，玩家持续搭块约 4~6 块/秒（人手点击上限）。取值：搭路节奏 BRIDGE_STEP_COOLDOWN 默认 8 → 5 tick/块（≈4 块/秒，玩家区间中值——与玩家基本持平略偏快）；方块滞留 BRIDGE_PLACED_LIFETIME 默认 10 → 2 秒（配置下限 3 → 1），纯数学联动：2 秒 × 4 块/秒 = 稳态最多 ≈8 块同时存在（实测一百二十一的"≤8 块"目标，站立格自动延后不影响移动中的稳态），不再堆成片。存量配置迁移（onConfigLoad）：stepCooldown 旧默认 8 与玩家手调的激进值 2 → 5；placedLifetime 旧默认 10 → 2。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:39:00] v1.1.0 实测一百二十一：搭路启动门槛落地水平远距放宽。根因：BridgeUpBehavior.canUse 的启动门槛是【纯高度差】——dy >= minDy（默认 2）才允许行为启动；两人各自向上搭时主人与女仆高度长期接近（dy 只有 0~1，主人未达门槛高差），水平距离却越拉越大 → 搭路行为永远不启动，而 tick 里明明为 dy<minDy 场景准备了平桥分支（tryAirBridgeStep——主人高度附近铺平桥横向逼近，实测一百零六注释也写明"水平距离远（>3格）时也允许启动"），但那个水平放宽当时只写在注释里、代码从未落地，平桥分支被启动门槛挡在门外形同虚设。修复：canUse 落地水平远距放宽——水平距离 >3 格且主人【不低于】女仆（dy >= 0）即允许启动，铺平桥朝主人横向逼近（站在自己垫的方块上算空中，24 格内有效；地面时同门槛只导航不搭块，无副作用）；高度门槛（dy >= minDy）只在近距离垂直搭高场景严格生效。垂直垫块/斜上台阶分支本就要求 dy >= 1，不会在平路误触发。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:34:00] v1.1.0 实测一百二十：自主战斗与模组武器联动三修（玩家确认上轮审计的三个边界逐一修复）。①【枪械弹药闸】AutoCombatSwitch.buildPools 新增闸门：gun_attack 任务进池必须弹药可用——TLM TaskGunAttack.isWeapon 只查 isGun（javap 实证），旧版有枪没子弹也会被切到 gun_attack → TLM 换弹失败干等；hasGunAndAmmo（背包有枪+任意弹药；卓越前线能量武器免弹药）不满足 → 枪械任务不进任何池，参战选任务/距离切换都不会把她切到打不出伤害的模式。②【远程分类任务走远程走位】MaidCombatTacticsBehavior 新增 isRangedTaskActive（当前任务为 isRangedTask 判远程的攻击任务）并接入三处：主走位分支 m_6725_（法术书/法杖等非投射远程武器不再落进 meleeTick 跳劈贴脸，改走 rangedTick 拉开距离风筝）、接战范围 engageRange（远程任务按任务搜索半径而非近战 8 格）、举盾判定 shouldUseShield（远程任务自己放风筝不举盾）——与距离切换的远程分类彻底对齐，消除"切换层认她远程、走位层当她近战"的矛盾。③【过时注释更正】retuneCombatTactics 的"模组隔离（模组任务永不被换出）"注释是实测八十六的旧语义，实测一百零七已改为任意 IAttackTask 双向参与——注释更新为实际行为，避免后续维护误解。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:27:00] v1.1.0 实测一百一十九：伐木发呆根因修复。日志实证：latest.log 显示女仆沿树干一截截砍到第 4 节后冻结在树基（wood stuck-reset idle=208t），看门狗确实触发但重置后几何不变照样冻死。根因一【伸手判定取方块中心】：砍伐距离判定是女仆脚底到【目标方块中心】的距离（m_20275_(pos+0.5)），站进树洞/树基时下一根木头的中心恰好压在 4.5 格伸手边界上——女仆实体只要水平偏移 0.1 格（走进树洞/寻路抖动）distSq 就超过 reachSq → 永远进搭路分支 → 搭方块被防窒息检查/没材料挡住 → 原地发呆（看门狗重置、收魂符重放都救不了，因为几何没变）。修复：伸手判定改为【目标方块 AABB 最近点】距离（玩家手长的正确语义——方块任一点够得着就能挖）——正上方木头的底面离女仆只有 dy=4 格，稳定够得着，逐节往上啃；够不着的（dy≥5）才走搭方块爬树。根因二【firstWoodAbove 从 dy=2 起跳】：树基的木头被砍掉后女仆站进树洞，下一根木头在她头平齐的 dy=1 处，旧版从 dy=2 起跳会漏掉它。挖矿行为同款中心点边界问题一并修复（站坑里挖正上方矿石同样会冻结）。修复后看门狗/魂符重放不再是救火手段——几何冻结从源头消失。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:16:00] v1.1.0 实测一百一十八：死亡传送重生点方块校验。上一轮（实测一百一十）已把死亡传送目标从"死亡地点"改为"玩家重生点访问器"（m_8961_/m_8963_），但还有个边界没盖：respawnPosition 字段在【床被拆/被占/重生锚空充能】时仍存旧坐标（原版只在复活流程才把它清空，死亡瞬间读到的是旧值）——直接传送会把女仆送到"床原来的位置"，而玩家实际复活在世界出生点，两处分离（此前仅靠复活保险纠偏，且旧床位置离实际复活点 64 格内时保险还会跳过）。修复：doDeathTeleport 加【原版同款校验】（镜像 Player.findRespawnPositionAndUseSpawnBlock，m_36130_ javap 实证）：重生点方块必须是【床】（维度允许睡觉 BedBlock.m_49488_=canSetSpawn + 床边能站起 BedBlock.m_260958_=findStandUpPosition 非空）或【充能重生锚】（RespawnAnchorBlock.f_55833_=CHARGES>0 + RespawnAnchorBlock.m_55850_ 维度允许，下界 true）；两者都不是（/spawnpoint 空地、床没了、锚空电）→ 直接主世界出生点兜底——第一次传送就瞄准正确位置，不依赖保险纠偏，与玩家实际复活点严格一致。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:11:00] v1.1.0 实测一百一十七：危险方块避让改用【原版寻路 malus 机制】。反馈"女仆仍会走岩浆块这种威胁方块——留一格站中心、周边围岩浆块、拿蛋糕吸引，女仆还是往上走；能不能套用原版生物的一些寻路逻辑"——核查证实这正是原版层面的根因：javap 字节码实证原版寻路对危险格子的通行裁决是 Mob.getPathfindingMalus（m_21439_，没设覆盖时回落 BlockPathTypes 枚举默认值 m_77124_）——LAVA=-1（不可通行，原版生物自动躲岩浆）、DAMAGE_OTHER=-1（仙人掌/浆果丛自动躲）、而 **DAMAGE_FIRE=+16（正数=可通行只是代价高）→ 原版生物踩岩浆块/火/营火**。TLM 女仆寻路全链路（MaidPathNavigation → MaidWrappedPathFinder → MaidNodeEvaluator，全部 javap 实证 extends 原版 WalkNodeEvaluator 体系，节点类型评估 m_77567_ → 缓存 m_264026_ → m_7209_）对岩浆本体格和岩浆上方的空气格都返回 DAMAGE_FIRE，16 的 malus 不拦路 → 女仆跟着蛋糕踩上去。修复：新增 MaidDangerMalusHandler——用原版决策点本身，把女仆的 DAMAGE_FIRE/DAMAGE_OTHER/LAVA/POWDER_SNOW 按配置危险表覆盖为 -1（m_21441_=setPathfindingMalus，与 LAVA 完全同款不可通行语义）：原版 WalkNodeEvaluator 生成邻居节点时 malus<0 节点直接跳过（m_164725_）、m_7209_ 对 malus<0 类型直接短路，对所有寻路路径（跟随/巡逻/干活/战斗）统一生效，不依赖任何注入点。应用时机：女仆入场（EntityJoinLevelEvent）+ 每 5 秒全服刷新（覆盖配置热改，Map.put 开销可忽略）；危险表→类型的映射按原版 raw 口径（岩浆块/火/灵魂火/营火/灵魂营火→DAMAGE_FIRE，岩浆→LAVA，仙人掌/浆果丛/凋零玫瑰/石笋→DAMAGE_OTHER，细雪→POWDER_SNOW），表外/开关关时恢复枚举默认值；DANGER_* 邻接型不管理（允许在危险旁正常走位绕行）。与 MaidDangerPathMixin 双保险：mixin 在节点层按配置方块 ID 拦截（覆盖模组危险方块、头顶灼烧型），本处理器按原版类型覆盖 malus（独立于注入点）——岩浆/火/营火两路都拦。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:51:00] v1.1.0 实测一百一十六：远程风筝距离管理重做。反馈"女仆拿弓箭时没有与怪物拉开明显的距离"——根因：rangedTick 旧版只在敌人贴进 ideal×0.55（弓≈4.95 格）才后退、退到 ideal-dist+2（≈6 格）就开始绕圈（半径 0.45×射程≈6.75）——怪物几乎全程贴在 5~7 格内，弓手看不出在放风筝。修复：①后退阈值提前到 ideal×0.75（弓≈6.75 格——怪物刚进近战威胁区就拉开）；②后退目标 = ideal+2（弓≈11 格——干净拉出一整段射程差）；③后退速度 1.15 → 1.3（肉眼可见甩开追兵）；④绕圈半径 = ideal（弓≈9 格）——在理想射程圆周上横移放风筝，保持清晰距离；⑤太远阈值 1.4 → 1.5（逼近节奏不变）。远程距离管理（m_20270_ 已 javap 实证返回线性距离，阈值比较无误）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:47:00] v1.1.0 实测一百一十五：距离切换武器设计落实。反馈"不会根据距离远近切换武器，之前的设计未落实"——根因：按距离切近/远程的 retuneCombatTactics 只在 hasThreatNearby（**8 格威胁圈**）为真时每秒评估，而距离切换本身覆盖 6~16 格——**8~16 格范围内的远处敌人**（不主动攻击/动态威胁圈过期）进不了切换分支，女仆不是切弓而是直接走还原退出战斗（设计在 8~16 格出现空洞）。修复：还原扫描新增远处敌人兜底分支——威胁圈外但最近敌人在近战够不着、远程够得着的 6~16 格时，先尝试按距离切远程：切成功（近战→远程）或已是远程任务 → 刷新威胁计时维持战斗继续射（此时 CORE 自动装备行为会把弓/弩/枪装到主手，任务切换即武器切换）；背包没有远程武器切不动 → 落回正常还原（10 秒安全期后退出）。切换时写 promaid.log（"距离切换：x -> y（远处威胁 N 格）"）便于验证。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:43:00] v1.1.0 实测一百一十四：自主战斗还原失效根因修复。玩家复测"威胁解除后仍还原不到之前的状态"——日志实证：promaid.log 15 次参战（每次"idle -> 战斗任务"）零还原。根因：isOnAssignedCombatTask 用 maid.getTask()（TLM 字节码实证读同步数据 DATA_TASK，且 findTask(uid).orElse(getIdleTask())——uid 解析失败/同步抖动直接回落 idle）与 ASSIGNED 比对，战中 retune 换战术/同步抖动/第三方模组换任务后 getTask() 与 ASSIGNED 不一致 → 误判"玩家接管"→ 静默清标记 → 战斗任务永不还原。修复：①isOnAssignedCombatTask 放宽——当前任务只要仍是【攻击类任务】（IAttackTask，与 buildPools 同口径）一律视为本系统战斗，还原扫描照常推进；只有任务真被换成非攻击任务才按接管处理；②还原分支 stillOnCombat 同步放宽（换过战术的战斗任务也还原到战斗前任务）；③tryEngageMaid 的静默"接管退出"路径补运行日志（下次复测可直接从 promaid.log 定位是哪种情况）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:34:00] v1.1.0 实测一百一十三：Home 模式呆立根治（守卫巡逻）。玩家澄清"即使 TLM 原版 GUI 手动 home 也呆立，原因未知"——javap 反编译 TLM 实证 home 女仆移动驱动只有三个：①SchedulePos.tick 每 2 秒回家走位（仅出圈才给目标，站 home 中心直接早退）；②IDLE/WORK 活动 MaidRunOne 随机散步；③follow 任务启动占位（home 下空转）。断点叠加：排班路径不设锚点（一百一十二已修）、isNonCombatWork 漏排跟随 → SchedulePosTickMixin 把 tick 整段 cancel（跟随任务命中"干活不打断"闸门，home 下 TLM 跟随本就空转，唯一移动驱动被掐）、站中心时 tick 不给走位 → 原地呆站。修复三层：①MaidWorkTags.isNonCombatWork 补排 follow（与文档契约"idle/跟随/战斗类不命中"一致）；②新增 HomePatrolHandler：对非干活 home 女仆每 4 秒在 home 锚点（restrictCenter→schedulePos 最近点→当前位置）附近随机选点给 WALK_TARGET（Brain.m_21879_，MoveToTargetSink 每 tick 消费与活动无关），女仆在家范围内持续巡逻走动；干活（挖矿/农活/建造任务驱动）、战斗/自保/战术/站桩/坐姿/骑乘一律不干扰。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:26:00] v1.1.0 实测一百一十二：Home 模式呆立根因修复。反馈"Home 模式下女仆还是傻站着一动不动"——根因：排班开启只调 maid.setHomeModeEnable(true)，反编译 TLM 证实该 setter 仅置 DATA_HOME_MODE 标志（MaidConfigManager 字节码 = entityData.set 单行），**从不设置女仆 home 坐标**；TLM 的 home 行为全靠 SchedulePos.tick（每 2 秒）→ restrictTo 用 workPos（null）调 setRestriction → hasRestriction=false → isWithinRestriction 恒 true → tick 早退：无回家走位、无越界拉回，整个 home 机制空转，无任务女仆原地呆站。修复：ScheduleManager.applyNow 开启 home 模式时同步用 TLM 自家 SchedulePos API 锚定 home 坐标（setHomeModeEnable(maid, 当前位置) + setConfigured(true)，与 TLM GUI 点 home 同款路径；玩家在 TLM GUI 配过 home 的保留原锚点不动）。锚定后每 2 秒的 home tick 恢复工作：范围内给回家走位目标（BehaviorUtils 0.7 速度）、越界拉回传送，女仆在 home 附近活动/干活，不再呆立。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:18:00] v1.1.0 实测一百一十一：建筑转向机制根因修复。玩家质疑"建筑区块转向机制真的生效了吗"——核查 rotateSteps（BlueprintLib）发现**双重 bug**：①外部结构蓝图步骤是全格式 {Name,Properties} 状态，重建步骤时漏加 '|' 分隔符，状态串紧跟方块名且含逗号，parseStep 按逗号切分长度不对 → 所有带状态步骤（楼梯/门/告示牌等）整块被静默丢弃；②内置/JSON 蓝图是 state-only SNBT（{facing:"south"} 无 Name），m_247651_（readBlockState）对无 Name 标签直接返回空气（javap 字节码实证），旋转后写回 {Name:"minecraft:air"} → 状态全毁。修复：重建步骤时统一补 '|' 分隔符，并把两种状态格式统一重建为 {Name,Properties} 全格式（有 Name/Properties 直接用，state-only 则补方块名+把顶层属性收进 Properties 子标签）再旋转——与 parseStructure/parseStepState/resolveBlockState 口径完全一致。修复后旋转 = 坐标矩阵 + 占地 W/D 互换 + 方块状态真实转向，橙影投影与实建逐块重合。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:12:00] v1.1.0 实测一百一十：死亡传送根因修复。反馈"死亡传送还是没有长进，女仆回到死亡地点而非玩家设定的重生点"——根因：doDeathTeleport 用 player.m_219759_() 解析传送目标，javap 反编译证实该 SRG 方法实为 getLastDeathLocation()（字节码 = getfield f_238176_ 死亡位置字段），注释"m_219759_ = getRespawnPosition"是错的——女仆一直**被传去主人上一次死亡的地点**！1.20.1 重生点字段在 ServerPlayer：m_8961_()=getRespawnPosition(BlockPos)、m_8963_()=getRespawnDimension(ResourceKey<Level>)（均 javap 字节码验证）。修复：①主路径 doDeathTeleport 改用 m_8961_/m_8963_ 解析目标（无重生点→主世界出生点兜底）；②保险路径 onPlayerRespawn 同样改用重生点访问器，不再依赖重生事件触发时玩家当前坐标（时机不可靠），传送目标维度改为解析出的重生维度。随 promaid-1.1.0.jar 部署，重启游戏生效。
[14:00:00] v1.1.0 实测一百零九：Litematica 风格幽灵方块渲染（重做）。此前实测一百零一尝试 renderSingleBlock 时方块完全不可见，原因已定位：TransparentVertexConsumer 的 builder 方法返回 delegate 而非 this——链式调用 vertex().color().uv() 直接在底层 consumer 上执行，alpha 缩减从未生效且渲染链中断。本次修复：①所有 builder 方法（m_5483_/m_6122_/m_7421_/m_7122_/m_7120_/m_5601_）返回 this，保证链式调用始终走包装器；②renderType 用 RenderType.m_110466_()（字节码实证 = translucent，引用 f_110375_ + TransparencyStateShard），translucent 管线开启 alpha 混合；③服务端 BlueprintProjectionSampler.sampleCloud 输出含方块注册名+状态 SNBT 的新格式，客户端解析重建 BlockState 后渲染真实方块模型。随 promaid-1.1.0.jar 部署，重启游戏生效。
[13:30:00] v1.1.0 实测一百零八：死亡传送根因修复。反馈"死亡传送还是不生效，女仆回到死亡地点"——根因：onPlayerRespawn 保险传送只搜索同一维度（level.m_45976_），跨维度女仆永远不会被拉。修复：改用 MAID_TRACK 遍历所有维度的女仆（与 doDeathTeleport 同口径），已加载的直接传送，未加载的强制加载后传送。同时保留原有的 doDeathTeleport 路径（真死校验后立即传送）作为主路径，onPlayerRespawn 作为保险兜底。随 promaid-1.1.0.jar 部署，重启游戏生效。
[13:00:00] v1.1.0 实测一百零七：近远战切换修复。反馈"女仆不会自己的近远战切换，模组武器也被屏蔽"——①retuneCombatTactics 旧版硬性要求 cur.getUid().getNamespace().equals("touhou_little_maid")，模组任务（拔刀剑/弹幕/御币等）永远被排除在切换之外；修复：改为 instanceof IAttackTask 即可参与切换（与 pickCombatTask 同口径）。②isRangedTask 旧版只认五个原版远程 UID，模组远程任务全部误判为近战；修复：新增 UID 关键词匹配（ranged/gun/danmaku/spell/crossbow/trident/bow）+ 命名空间匹配（maidspell/spellbook），模组远程任务也能正确分类。随 promaid-1.1.0.jar 部署，重启游戏生效。
[12:30:00] v1.1.0 实测一百零六：搭路欲望增强。反馈"搭路向主人方向搭方块的欲望太低了"——①放宽 canUse 启动门槛：旧版要求主人至少高 minDy（默认2格）才启动搭路，改为至少高1格即可（水平距离远时1格差也搭）；②tryAirBridgeStep/tryDiagStep 三方向尝试：正前方 → 左前45° → 右前45°，主方向被挡时自动尝试偏移方向继续搭路（向主人方向倾斜），不再一次被挡就放弃。仅影响 BridgeUpBehavior（普通搭路），自保/伐木/挖矿的搭路逻辑不变。随 promaid-1.1.0.jar 部署，重启游戏生效。
[12:00:00] v1.1.0 实测一百零五：回退幽灵方块渲染。反馈"建造模式下连幽灵方块都看不到了"——实测一百零一的 renderSingleBlock + TransparentVertexConsumer 方案中，VertexConsumer 接口的实际调用路径与 m_6122_ 不匹配（renderSingleBlock 内部可能走 m_7404_ 或其他路径），导致顶点数据全部丢失→方块完全不可见。紧急回退到 DebugRenderer 色块方案（0.4 格半透明方块），保证幽灵投影可见。Litematica 风格渲染需更深入研究 VertexConsumer 调用链后重做。随 promaid-1.1.0.jar 部署，重启游戏生效。
[11:30:00] v1.1.0 实测一百零四：自主战斗还原根因修复。反馈"威胁解除后不会切回原来的模式"——AutoCombatSwitch 的参战判定和还原扫描均用 getBoolean(PREV_TASK_TAG)，但 PREV_TASK_TAG 存的是字符串（前任务 UID），getBoolean 对字符串标签永远返回 false → 恢复逻辑永远不触发、排班调度器也误判为"不在战斗"。修复：新增独立布尔标记 COMBAT_ACTIVE_TAG（maid_smart_combat_active），参战时写 true、clearMarkers 时写 false、isAutoCombatActive 读此标记——与 PREV_TASK_TAG（字符串）职责分离，不再混淆类型。随 promaid-1.1.0.jar 部署，重启游戏生效。
[11:00:00] v1.1.0 实测一百零三：模组武器自动装备。反馈"拔刀剑模式不会自己装到主手上"——MaidToolAutoEquip.ensureForTask 只处理 touhou_little_maid 命名空间任务（attack/ranged_attack 等），模组任务（slashblade/ef_tlm/truepower/sbr_core 等）全部 return false → 自动装备从未生效。修复：else 分支检测任务是否实现 IAttackTask，若是则用任务自带的 isWeapon 方法匹配武器 + weaponScore 评分，实现与原版攻击模式相同的自动装配逻辑。随 promaid-1.1.0.jar 部署，重启游戏生效。
[10:30:00] v1.1.0 实测一百零二b：搭路跳跃动画恢复自然。反馈"搭路状态下往上跳看着不自然，能不能维持老版本的样子"——BridgeUpBehavior.stepOnto 每次放完方块都给0.42垂直速度（标准跳速），水平搭路时女仆明显跳一下；修复：水平搭路（d>0）去掉垂直跳速只给水平速度，视觉上是"走过去"而非"跳过去"；垂直垫块（d≈0）保持原地起跳不变。随 promaid-1.1.0.jar 部署，重启游戏生效。
[10:15:00] v1.1.0 实测一百零二：五项致命 bug 修复（实测反馈）。①【排班完全失效根因】ScheduleBookScreen.saveSchedule 发送 SchedSavePacket 时 loadedOn 默认 false → ON_TAG 写 false → 调度器每秒扫描跳过该女仆 → 排班/Home 模式/跨维跟随全部连锁失效；修复：有非空任务槽时自动将 loadedOn 置 true。②【死亡传送被 Home 模式阻断】MasterDeathTeleportHandler.shouldStayPut 将 isHomeModeEnable() 纳入豁免 → 排班女仆（被强制 Home 模式）死亡传送全部失效；修复：死亡传送豁免仅保留坐姿和骑乘，Home 模式不再阻断。③【自主战斗还原卡死】prevTask 为 null（原任务被卸载/删除）时 maid 永久留在战斗任务；修复：兜底还原到排班当前段或 TLM idle 任务。④【危险方块回避静默失效】MaidDangerPathMixin 的 catch(Exception) 吞掉所有异常 → 若 DangerBlocks.cellDangerous 抛异常则回避系统静默失效；修复：改为 warn 日志。⑤【伐木看门狗】WOOD_STUCK_RESET_SECONDS 默认 8→5 秒，更快速重置发呆状态。随 promaid-1.1.0.jar 部署，重启游戏生效。
[08:30:00] v1.1.0 实测一百零一：Litematica 风格幽灵方块渲染。反馈"当前幽灵方块颜色一样、大小不是标准方块，根本看不清建筑形态"——旧版 drawGhost 用 DebugRenderer 画 0.4 格均匀色块，玩家无法辨识方块种类与朝向。改造为真实方块模型半透明渲染：①服务端 BlueprintProjectionSampler.sampleCloud 输出格式从 "x,y,z;…" 升级为 "x,y,z,id|state;…"（附加方块注册名 + 状态 SNBT）；②客户端 BlueprintAreaPreview 投影缓存从 int[] 改为 Object[]{x,y,z,BlockState}——新增 parseCloudWithState 解析新格式，resolveBlockState 从 SNBT 重建 BlockState（支持默认态/属性补全/Name 包装兜底）；③drawGhost 改用 BlockRenderDispatcher.renderSingleBlock 渲染实际方块模型（全亮 0xF000F0、无覆盖 OverlayTexture）；④TransparentBufferSource + TransparentVertexConsumer 双层包装器：拦截 VertexConsumer.m_6122_（RGBA 颜色写入）缩减 alpha 分量，实现半透明幽灵效果；⑤BlueprintBookNetworking 无需改动——cloud 作为不透明字符串透传。随 promaid-1.1.0.jar 部署，重启游戏生效。
[19:49:08] v1.1.0 实测一百：转向键默认 P→Z。字节码实证原版「社交互动」默认键同为 P（Options 构造 bipush 80）——金色预览按 P 转向会同时弹出社交界面，每次都要多按一次 Esc。新默认 Z：原版零占用，且避开主流模组默认键（JEI 查看配方 R / OptiFine 缩放 C / 背包类 B / 语音类 V / Xaero 地图 M）；左手小拇指从 Shift 邻位自然够到，走动选位中无需腾手。手册教程第 3 步与建造确认提示语同步改为 Z；已存 options.txt 的玩家不受影响（改键随时经详情页「转向键位」按钮或原版按键设置调整）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[15:11:22] v1.1.0 实测九十九：实测前终审，一修一证。①【修】同点位换朝向重建改为原位替换——此前续建判定忽略朝向（按 P 选的旋转对旧计划完全不起作用）；初版修复走“取消旧区块+新建”会生成新 planId，导致已绑定女仆的持久化绑定全部失效被迫手动重绑。现新增 BuildPlan.replacePlanSteps：保留 planId 与工头/绑定关系，仅替换步骤与朝向并重置进度（已建方块由 filterBuilt 已建感知自然跳过，不白费材料也不重搭；包围盒与存档条目同步更新）。②【证】按键冲突实证：原版「社交互动」默认键同为 P（字节码 bipush 80 确认）——金色预览按 P 转向的同时会弹出社交界面；默认键位遵要求保持 P，可在原版按键设置里把社交互动改键、或经详情页「转向键位」按钮把转向键改到其他键位。随 promaid-1.1.0.jar 部署，重启游戏生效。
[14:52:45] v1.1.0 实测九十九：朝向系统实测前终审，三处修复。①【换朝向重建】建造执行器的“续建识别”此前只比对蓝图+原点、不比对朝向——同一位置先建 0° 取消后再按 P 转向重建会走续建分支沿用旧步骤，玩家选的旋转完全不起作用；现在朝向不一致视为重建：自动取消旧计划后按新朝号新建（已建的方块由已建感知自然跳过，进度不白费）。②【按键计数排空】转向键的 consumeClick 计数器改为无条件排空——旧版非预览态直接跳过轮询，平时误按的 P 会攒在计数里，下次开启金色预览瞬间一次性爆转多次；现在始终清空、仅预览态生效。③【常驻注册】BlueprintAreaPreview 原为首次预览才挂事件总线（懒注册），开机即由 BuildKeysClient 的 ClientSetup 挂载，保证计数器从进世界起就有人排空；渲染入口自带空态短路，常驻零开销。随 promaid-1.1.0.jar 部署，重启游戏生效。
[14:39:33] v1.1.0 实测九十八：手册补充说明（要求）。①建造教程「第 3 步」改写为“确认范围与朝向”——补入按 P 键整体旋转建筑（默认键位、「转向键位」按钮直达原版按键设置、占地宽深互换与楼梯/门跟随转向）、新增「建造期间的工地投影」段落（红色区块框+橙色幽灵关手册走近可见/96 格剔除/取消或完工自动消失/蓝图投影开关只管幽灵）；②杂项功能章补两条：「女仆安全与区块保载」（全区块持续加载语义+寻路避让+险境脱离+搭方块排除+受困救援，入口指向配置小节）与「运行日志」（logs/promaid.log 用途、4MB 轮换、镜像 latest.log、反馈问题附文件对账）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[05:35:33] v1.1.0 实测九十七：建造朝向系统——金色预览按 P 整体旋转建筑（每次顺时针 90°），手册内可跳原版按键设置改键。(1)【整体旋转】按判定口径“切换的应该是整个区块，而不仅仅是其中的方块”：新增 rotateSteps 通用步骤旋转器——坐标矩阵变换 + 占地 W/D 自动互换（金色框/红色区块框随之换向）+ 楼梯/门/原木轴向等方块状态跟随转向；内置蓝图此前完全不可旋转，现与外部文件统一走“先解析后旋转”。(2)【按键】注册原版 KeyMapping「建造预览·旋转朝向」（默认 P，分类 Promaid 建造）：金色预览激活期间按一次转 90°，青色幽灵实时刷新、悬浮文字显示当前角度与换算后的占地尺寸；建筑详情页新增「转向键位」按钮——直接打开原版按键绑定界面（与调整原版按键操作完全一致），改完点完成返回手册。(3)【贯通】朝向随 SelectBlueprintPacket 下发 → 建造执行器以同变换落地 → PlanState.quarters 存档持久化（BuildArchive 第 10 字段，旧档默认 0 兼容）→ 重启恢复仍按该朝向重建 → 每秒区块同步追加 r[14] 朝向字段（15 字段，三包同步扩位）→ 红色态橙影按 id#quarters 取旋转版点云，与实建逐块重合。(4) SRG 实证：KeyMapping.m_90859_=consumeClick（字节码级确认计数递减语义）、Minecraft.f_91066_=options。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:52:33] v1.1.0 实测九十六：金色预览回归——「建造此图纸」未确认阶段的金色框（随玩家移动）+ 青色幽灵投影。(1)【回归】实测九十五误将建造确认流程里的两步选位一并简化——玩家澄清：未确认时金色区域随玩家移动的功能很重要；现恢复两步流程：首次点击「建造此图纸」开启金色框+青色幽灵方块并提示退手册选位，再次点击弹确认框。(2)【增强】每次点击都会把金色预览刷新到当前脚下（取消弹窗重新选位后再点也一样），且金色状态下同步显示青色幽灵方块投影——未确认阶段即可看建筑形态与朝向；确认创建后金色框关闭、红色区块框+橙色幽灵投影由每秒同步接管，两种状态都有投影。(3) 独立「区块显示」按钮保持删除（其功能已被流程内金色预览覆盖）；“看过预览”标记沿用 v1.5.204 口径（重开手册不重置、确认创建后才复位）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:44:41] v1.1.0 实测九十五：删除「区块显示」金色预览，建造投影并入「建造此图纸」全程显示。(1)【根因】此前携带建造区块行的网络包只在打开手册/创建计划/控制操作时一次性下发——真正开始建造后玩家关掉手册走到工地，客户端没有任何区块数据，橙色幽灵方块从不渲染（“建造此建筑里面没有显示”的根因）；金色预览因为是纯客户端逻辑所以一直好用，形成“只有区块显示里能看到投影”的落差。(2)【删除】建筑详情页「区块显示」按钮与金色玩家中心预览（含青色幽灵方块、两步确认流程、“看过预览”标记）整体下线；建造此图纸改为一步确认弹窗（以玩家脚下为中心，保留摧毁障碍物警告）。(3)【新增】RegionSyncPacket：服务端每秒向全体玩家广播建造区块行（14 字段，复用 collectBuildRegions），驱动红色区块框 + 橙色幽灵方块在建造期间持续显示——玩家走近工地即见建筑最终形态与朝向，随移动自由观察（96 格距离剔除），计划取消/完成后自动清除；投影点云仍按蓝图 id 请求缓存。(4)【顺带】底部按钮改自适应均分布局（区块内 4 键/区块外 2 键），不再有出屏风险。随 promaid-1.1.0.jar 部署，重启游戏生效。
[04:32:46] v1.1.0 实测九十四：新增运行日志系统 + 新版内容复查收尾。(1)【运行日志】新增 游戏目录/logs/promaid.log（UTF-8 追加写，满 4MB 自动轮换为 promaid.log.old，同时镜像一行到 latest.log）：排班段应用（时段/模式/任务）、战斗参战/还原/僵局逃逸阀触发/战中任务被接管/原任务丢失、险境脱离挪格与应急灭火、跨维跟随传送、自保残留标记自愈等状态迁移事件全部带真实时间戳落盘——以后反馈“XX 没生效”可直接按时间线对账；巡检类每秒扫描的空转路径不落盘防日志爆炸；配置面板杂项页新增「运行日志」小节（总开关 + 文件位置说明），关闭后完全静默。(2)【新版复查】伐木等五个自定义任务确认经 addMaidTask 注册进 TLM 任务管理器（排班 UI 六槽可选）；mixin 注册表增量核对一致（仅新增 MaidDangerPathMixin）；旧 MaidDimensionFollow 类零代码引用（仅存历史注释）；静态容器清理核查通过（钓鱼坐垫三表 sweep 中 removeIf、关系记忆方法缓存有界、僵局日志节流表按女仆数有界）。随 promaid-1.1.0.jar 部署，重启游戏生效。
[03:30:55] v1.1.0 实测九十三：排班联动与打断处理审计，双修。①战斗还原直通排班的路径绕过了排班系统总开关——全局关闭排班系统后，女仆打完一架仍会被战斗还原代码强制进入在家模式并按旧日程换任务（跟随女仆打完架就不再跟人）；现在 applyNow 入口统一设总开关闸，三个调用方（每秒调度扫描/保存日程立即应用/战斗还原直通）口径一致。②自保标记残留自愈：女仆在自保会话进行中遭遇区块卸载/服务器崩溃/魂符收放时，自保标记随存档保留而会话内存态归零，重载后健康安全的她不会再进会话、标记永无人清→排班调度、主动战斗参战、搭方块、险境脱离对这只女仆永久让位；现在会话外检测到“带着标记但血量健康且环境安全”即自动清除。其余联动链路逐条核验通过：手动切任务/批量应用的去抖保护、战中换战术同步指派标记、还原宽限时间基一致、跨维跟随与一键集合对排班自动 home 女仆的豁免、快捷设置对排班中手改任务/模式的硬拦截均正确。
[16:40:0] v1.1.0 实测九十二（玩家质疑：“这个功能似乎并没有相关的开关和配置表吧”——属实）：①自绘配置面板补齐 5 个缺失条目（杂项页新增“女仆安全与区块保载”小节）：区块持续保载/受困救援/寻路危险避让/险境脱离四个开关 + 危险方块表文本行（逗号分隔注册名，缺命名空间拒绝提交）——此前这些只有 spec 键，游戏内面板看不到也改不了，只能手改 toml；②接线跨维度跟随：MISC_DIMENSION_FOLLOW 开关+面板条目早已存在，followIfCrossDimension 函数也早已写好，但两者从未连接（开关是摆设、函数是死代码）——现在每 5 秒扫描全服女仆，开关开启时异维度跟随者自动传送到主人身边；home/坐姿/骑乘/主人非存活豁免在函数内自判。
[16:00:0] v1.1.0 实测九十一（要求：搭方块时这些危险的方块也不应该在名单里面，无论如何都不会搭）：MaidBuildBlockFilter（挖矿/伐木/自保/搭路四模块统一选材入口）新增危险表排除——dangerBlocks 配置表中的方块无条件从垫脚选材中消失（与寻路避让/险境脱离共享同一张表），且不受 dangerAvoid 开关影响；反馈往表里加模组危险方块即自动从选材名单同步排除。原硬编码黑名单（仙人掌/岩浆块/浆果丛/营火等）保留双保险。
[15:10:0] v1.1.0 实测九十（追问：女仆已经处于这些危险方块上时会怎么办）：新增险境脱离——每 0.5 秒巡检，站立柱（脚格/头顶/脚下）命中危险表的女仆立即挪到最近安全格（环形半径 4 由近及远）+应急灭火（m_7311_(-1) 清剩余着火时间），不再等血量跌破自保线白挨伤害。语义边界：home 模式也救（只挪几格脱离险境，非传送到主人身边）；坐姿/骑乘跳过（椅子/载具系统管理位移）；自保中让位（有专属珍珠/放水/垫高链路）；四面皆险记冷却交给自保兜底。配置 dangerEscape 可关。同时把危险表逻辑抽取为 DangerBlocks 工具类供寻路 mixin 与本处理器共用。
[14:30:0] v1.1.0 实测八十九（需求：优化女仆寻路机制，让她可以自己避开一些危险的方块）：新增寻路层危险方块避让——注入原版 WalkNodeEvaluator 的逐节点路径类型评估（仅女仆生效，其余生物零影响），站立格/脚下方块命中危险表、或头顶一格为灼烧型方块时，把该节点强制改判为不可通行：女仆规划路径会主动绕开岩浆湖岸边、火焰地面、仙人掌丛等，宁可停下等过远传送兜底也不往里走。三处细节防误伤：①起点格不拦（已身处险境时保留逃出路径）；②危险表可配置（杂项 dangerBlocks，默认 9 种：岩浆/火/灵魂火/岩浆块/仙人掌/甜浆果丛/凋零玫瑰/细雪/石笋），总开关 dangerAvoid 可关；③配置列表按实例同一性缓存，改表即时生效不重复解析。
[12:40:0] v1.1.0 实测八十八b（玩家纠正：home/坐姿/骑乘只豁免传送，不豁免区块加载——他们的区块也要加载）：撤销八十八刚加的三态保载豁免。现在所有有主女仆一律持续加载所在区块：停放的女仆只是不走动，但周边农场/熔炉照常运转，也随时可被集合/召回/救援找到；三态豁免语义回归其本源——只作用于传送路径。
[12:00:0] v1.1.0 实测八十八：区块保载范围从“仅异维度”扩大到全部有主活动女仆。旧规则只给跨维度女仆挂加载票——同维度跟随的女仆一旦落后主人超过模拟距离，所在区块卸载、AI 冻结，TLM 的“离主人过远自动传送”永远无法触发，只能等主人走回去。现在除三态豁免（home/坐姿/骑乘=玩家明确停放）外全部持续加载：跟随、挖矿、伐木、建造中的女仆所在区块永久保持 实体 ticking 级别（与玩家同级），随时可以被传送/召回/救援。资源代价=每只活动女仆一张单区块票。无主野女仆不保载。
[11:00:0] v1.1.0 实测八十七d（/goal 女仆传送逻辑全量审查）：清点全部 9 类传送路径逐条核对守卫一致性。发现并修复 1 处：一键集合的“待召回队列”不豁免 home/坐姿/骑乘女仆——未加载区块里的女仆只能靠最后出现位置快照召回，旧快照没记录她的状态，导致 home 女仆的区块被白白强载、载出来才发现要豁免然后静默收队（玩家视角：点了集合看到待召回却石沉大海）。修复：①登记时快照三态豁免；②建队前先过滤并计入“保持原位”；③强载后才发现豁免的静默分支补上聊天播报。另确认：跨维度自动跟随函数为死代码（从未接线）——现役跨维手段=一键集合/死亡传送/受困救援三项，是否接线自动跟随留待玩家决策。其余路径守卫齐全：死亡传送与复活保险三态豁免、自保双闸、TLM teleportToOwner 双 mixin 拦截、救援绕过 home 属设计（基岩顶不是家）。
[10:10:0] v1.1.0 实测八十七b（/goal 逻辑链路审查——覆盖实测八十六隔离门与八十七中立口径增量）：全链路复审结论=无功能性 bug，一处健壮性隐患已修。①还原扫描每秒对参战女仆执行的中立生物记仇判定（isAngry）此前直接调用实体方法且无异常防护——NeutralMob 实现类是玩家可安装的第三方内容，模组实现若在 getter 里抛异常会顺着 ServerTickEvent 炸穿服务端 tick；现在统一走防御封装 neutralAngry（动态圈来源判定同步），异常按“不记仇”处理。②逐项复核确认无虞：八十六隔离门为纯提前返回零状态写入；四触点标记读写对称；动态圈查找跨维度安全（同维检索失败即回落固定圆）；僵局阀与圈互斥成立；被动生物任何链路不参与。
[09:30:0] v1.1.0 实测八十七（玩家提问："主动战斗在面对中立生物的情形怎么处理"）：确立【激怒即通行证】口径。中立生物分两层：实现 Enemy 的（末影人/僵尸猪灵/猪灵/蜘蛛）本来全链路算数；只实现 NeutralMob 的（蜜蜂/北极熊/狼/山羊/羊驼/海豚）此前三不管——蛰了女仆不触发参战、不进威胁圈、不挡还原，主人挨蛰拉女仆进来又 10 秒后撤走，状态机断裂。现在按字节码实证的 isAngry/isAngryAt 接口接入四触点：①女仆被记仇她的中立动物打了→参战；②该动物登记进动态威胁圈（圈内口径同步放宽）；③还原扫描把记仇状态（isAngry）的中立动物算作现役威胁——它们还在圈里转就保持战斗态，气消/打死/走远后正常还原；④主人开火目标是记仇主人的中立动物也算开战（帮打合理），平静态的照样不触发（驯养/管教不受影响）。被动生物（牛羊鸡）任何链路都不算，八十四b 口径不变。手册主动切换战斗条目同步。
[21:00:0] v1.1.0 实测八十六（要求：战中近远程互换对模组武器隔离——"原版有可能切到模组武器里，但是模组武器切不到原版里"；并审查该切换对主动战斗触发链的影响）：①战中动态换战术仅限【当前任务是原版五件套】的女仆参与——按命名空间判定（touhou_little_maid），模组任务（万法皆通/史诗战斗等）被切到后保持硬打、永不被换出；方向约定=原版可切入模组池（火力不浪费）、模组不可切回原版。理由：模组武器普遍更强且常带专属机制（姿态/施法循环），isRangedTask 的远近二分法对它们是瞎猜。②触发链审查结论：换战术只发生在还原扫描内部（参战评估从不调用它），且每次切换同步 ASSIGNED_TAG、不碰 PREV_TASK/LAST_THREAT——参战/续杯/还原/僵局阀/动态圈五条链路均不受切换次数影响；隔离门为纯提前返回、零状态写入，对全链路无副作用。③边界留档：模组远程任务被近身时不再自动切近战（信任模组武器自身近身机制如反击击退）；初始参战选池仍含模组候选（加权随机不变），隔离只约束战中互换。手册主动切换战斗条目同步。
[20:00:0] v1.1.0 实测八十五（玩家设计："动态威胁范围——出现那种情况时威胁圈自然放大，直至包含检索到伤害来源的那个生物"）：还原判定的固定 8 格圆与参战触发口径不对称——骷髅站在 10 多格外放风筝时固定圆扫不到它，还原计时照走，"还原 10 秒→又中一箭→再参战"反复横跳。实现动态威胁圈：①女仆挨打时登记【伤害来源生物】（uuid + 时刻）；②还原扫描时该生物若仍存活、距离 ≤32 格（硬上限）、且在扩展窗口（默认 10 秒）内有过接触 → 威胁圈自动放大把它包含进来，被远程压着打期间保持战斗态还击；怪死/走远/超窗后圈回落到固定半径。时长可调（combat.autoSwitchThreatExpandSeconds，0=关闭）。配套修挨打判定口径：骷髅放箭时伤害的直接实体是箭矢、造成者才是骷髅，旧版只查直接实体 → 远程怪放风筝女仆永不参战；现在造成者/直接实体任一是 Enemy 即算参战与登记。手册主动切换战斗条目同步。
[19:10:0] v1.1.0 实测八十四b：上轮只核查了还原扫描端（确实只认 Enemy），漏了参战触发端——主人"主动开火"触发不看目标是谁，打牛羊也算开战，且每次命中都经参战评估无条件续杯安全计时。两处口径修正：①主人主动开火的目标必须是敌对生物（Enemy）才触发参战——宰牛杀鸡/剪羊毛等被动生物交互不再让全员拔刀，无威胁战斗从源头消失；②已参战女仆的"续杯安全计时"只在真实存在敌对威胁（8 格内有 Enemy）时进行——任何其他路径的重复评估不再把还原时钟往后推。被动生物挨打侧不变：女仆被怪打才参战的口径本来就只认 Enemy。手册主动切换战斗条目同步（打被动生物不算开战）。注：主人打玩家（PVP）现在同样不算开战——此前任意受害者都会触发，属同一口径的边界收敛。
[18:30:0] v1.1.0 实测八十四（玩家两条）：①搭方块新效果——"女仆自己搭下一个方块以后，立刻移动到那个方块上"。旧版空中铺桥/斜台阶只挂导航目标（半空寻路永远失败=目标形同虚设，人留在原地等下一轮），垂直垫块则等方块卡身后被防窒息逻辑顶起（有半嵌瞬间）。现在三条放置路径（空中平桥/斜台阶/垂直垫高）放完块都给一拍朝目标格的物理跳跃速度（水平朝目标、垂直一拍标准跳速），落地即站上刚垫的方块；地面能寻路时导航照常接管。②自主战斗"打完了切不回来"根治——还原判定要求 8 格内无敌对生物才算威胁消失，怪卡在墙后/玻璃后/传送门里/飞行绕圈等杀不掉也够不着的死局会让安全计时永远续杯。新增僵局逃逸：女仆与敌对生物超过 60 秒没有任何伤害往来（挨打/打到都算接触，远程放风筝全程无伤也不会误判）→ 不再干等，按正常安全计时切回原任务；latest.log 搜 auto-combat stale 可查是哪种怪卡住的；时长可调（combat.autoSwitchStaleSeconds，0=关闭）。另确认玩家疑问：被动生物判定没有问题——参战触发与还原判定的威胁口径都只认 Enemy 接口（敌对生物），牛羊鸡等被动动物从来不算威胁、也不会触发参战。
[17:20:0] v1.1.0 实测八十三c：回退实测八十三在 TLM 跟随任务上加的 home 门。字节码取证：TLM 对 home 女仆本就是「跟随任务每 tick 正常启动 → start() 内部判 home 后全分支空转」，这个"启动即空转"占据着它的优先级组、是大脑正常运转的一环；从外部拦掉启动后同组行为接管异常，home 女仆站桩。home 的传送防护不受影响——自保两处、死亡传送三态（home/坐姿/骑乘）、一键集合与跨维度跟随的豁免都仍在各自传送点生效；跟随任务只保留"主人已死亡不启动"一道闸（原版只查 isRemoved 不查存活，尸体期会放行瞬移到死亡地点）。
[16:40:0] v1.1.0 实测八十三b：根因在传输层——投影点云整条打包成【一个字符串】下发，而网络层单字符串上限 32767 字符；大建筑点云（≤3000 点 × 每点 12~16 字符 ≈ 最高 4.8 万字符）在服务端编码阶段就超限抛异常、包静默发不出去，客户端的防重发标记又让后续点击不再补发 → 投影永远不出现。修复：①点云分块传输（每块 ≤16000 字符、客户端拼接还原，尺寸上限彻底解除）；②服务端采样与发送全程 try/catch 并写日志，异常不再静默；③客户端请求/接收各加一条诊断日志——latest.log 搜「projection」即可确认链路是否打通（request → size/chars sent → received N points）；④渲染距离剔除改用已验证的符号组合，消除一处潜在运行时风险。
[16:10:0] v1.1.0 实测八十三（实测三条反馈）：①到下界提示"一名女仆因为无站立点未动"——集合/跟随的找落脚点逻辑只从主人脚下一路向下扫 16 格，下界桥面、熔岩海高架、悬崖地形正下方悬空几十格就直接判失败；现在单柱向下 16 格 + 向上 12 格、水平由近及远扫半径 3 圈（沿桥面横走一格就能落脚），一键集合与跨维度跟同一并受益。②死亡后女仆出现在死亡地点而不是重生点——元凶是自保行为的两处"传回主人身边"传送（血恢复退出自保 / 自保中确认安全）都没有死亡主人防护：主人尸体停在死亡点等待重生，自保结束的女仆被直接拽到尸体旁；顺带堵死 TLM 内置跟随的同类路径（离主人过远自动瞬移——主人已死亡或 home 模式时跟随行为直接不启动）。③home 看家女仆仍被死亡传送拽走——死亡传送处理器此前声明"不受任何女仆状态判定影响"，漏掉了实测七十八确立的看家语义；现在「home/坐姿/骑乘」三态豁免与一键集合同口径，死亡传送和复活保险拉取都遵守，战斗类女仆照常无条件赶往重生点。手册被动技能章与自动在家模式条目同步。
[15:20:0] v1.1.0 实测八十二：建造范围预览升级为「区块框 + 蓝图投影」。①「区块显示」与建造流程第 1 步的金色框预览时，框内叠加青色半透明幽灵方块轮廓随玩家移动——选位阶段就能看到建筑的形状、长边朝向和门洞位置；②建造中/暂停中的红色区块标记按计划原点叠加橙色幽灵方块，与女仆实际搭建位置逐块重合（同一居中坐标变换），建到一半也能看到最终形态；③投影数据由服务端抽壳降采样生成（只保留六邻有开口的外壳块，实心大建筑内部全部丢弃；超 3000 点等距抽稀），经新增的请求/下发网络包传给客户端并按蓝图 id 缓存，55 万块级蓝图也只解析一次；④配置面板建造页新增「projection」开关（默认开），关闭后回到纯区块框。手册建造教程第 3 步与小知识页同步。
[14:40:0] v1.1.0 实测八十一（玩家提醒："结合 1.20.1 特性确认基岩层位置；之前把 -60 误判过——超平坦世界地表恰好在 y=-60"）：受困救援的虚空判定从硬编码 y<-60 改为按维度真实边界 getMinBuildHeight 判定（1.20.1：主世界 -64~319、下界 0~255 且 y=127 整层基岩天花板、末地 0~255）。修复站在超平坦地表（y=-60）的女仆被误判成"掉出世界"而反复触发救援传送的问题；下界基岩顶阈值 ≥126 与落点上限 124 经核对维持不变（顶层方块占 127、站面 128，中间留一格缓冲）。
[14:00:0] v1.1.0 实测八十（纠正实测七十八的误诊，真正根因修复）：反馈"主人下界死亡后女仆被传到基岩层上面"的元凶不是跟随链路，而是主人死亡强制传送的落点函数 findSafeLanding——下界 y=127 是整层基岩天花板，旧版从重生点向上扫第一处两格净空，重生点柱子上方被实体方块封到天花板时（封闭基地/埋地重生锚），第一处露天空间就是基岩层上方，随后的向下贴地又被基岩挡住 → 女仆稳落基岩顶。修复：下界落点搜索上限压到 y≤124、向上找不到改为向下继续扫（地下空腔/基地内部）、都无果才退回原坐标上方一格。跨区块（追踪表+区块强载）与跨维度（teleportTo）能力不变。
[13:10:0] v1.1.0 实测七十九：死亡传送策略成型为三层。①死亡瞬间：主人非存活一律不追（实测七十八），任何女仆都不会被拉去死亡点这类坏落点；②复活之后：跨维度跟随与"最后出现位置强载召回"两条既有链路照常工作，跟随女仆自动归队到复活的主人身边；③兜底救援（新增）：女仆被困下界基岩顶层（高度≥126）或掉出世界底部（y<-60）时，每 5 秒扫描自动把她安全传回存活主人身边（跨维度通用；在家模式的女仆也救——基岩顶不是家；已在主人 8 格内不触发防循环救援）。开关在配置面板杂项「maidRescue」，默认开。手册小知识补「受困救援」条目。
[12:30:0] v1.1.0 实测七十八（bug 报告：主人在下界死亡且未关死亡传送，主世界看家女仆被传到下界基岩层上面）：根因一——主人死亡期间实体仍留在原位置（血量 0 但未移除），跨维度跟随照常触发，女仆被传到死亡点附近，死亡点在高位时向下找站立格就直接落在下界基岩顶层上：修复为主人非存活状态一律不追。根因二——实测七十曾放开"home 模式女仆也响应一键集合"，现按玩家裁定的语义回滚：home=看家钉死，不响应任何传送（跨维度跟随本就豁免；一键集合在场/待召回两条路径均恢复豁免并在气泡注明；所有传送的咽喉点统一拒绝 home 女仆与已死亡主人）。想召回看家的女仆，先关闭她的排班/解除在家模式。手册同步。
[11:50:0] v1.1.0 实测七十七（新功能二次自查）：复核实测七十六锁定链路的最终形态——包处理顺序语义、批量跳过计数、按钮/提示渲染均无接缝问题；唯一调整：快捷页排班提示行措辞压缩到 30 字内，最小窗口宽度（320）下不再出屏。另留档两处边界：配置热重载事件里迁移矿表后，运行中的矿表缓存要等下次打开面板或重启才刷新（主流程不受影响）；跨维度集合召回 home 模式女仆后，她的"家"仍在原维度（守家行为自然退化为跟随主人附近活动，无害）。
[11:20:0] v1.1.0 实测七十六：实测七十只拦了"任务"，工作模式（早/晚/全天）仍可被一键更改、下个时段边界又被日程翻回去。本次锁全：①单女仆快捷页的「工作模式」按钮对排班中的女仆直接锁定（红色提示），服务端同步拦截并说明；②列表页「全员模式」和「应用任务」对排班中的女仆【整体】跳过（模式与任务都不动），汇总消息注明"先关闭她们的排班才能一键更改"；③先处理排班开关再判定，"关排班+立即改状态"的合并操作语义正确；④手册「排班锁定」条目同步。
[10:40:0] v1.1.0 实测七十五：①看门狗判定时长默认 伐木 30 秒/挖矿 45 秒统一降为 8 秒（范围下限放宽到 4），旧档存的旧默认自动迁移；②配套修时序坑——看门狗窗口小于目标超时（15 秒）后，若重置清掉"当前目标的等待时钟"，够不着的目标永远等不满超时去被弃置，反而无限循环；现在重置把当前目标与等待时钟一并保留（对超时弃置机制透明，失效检查逐 tick 照常复核）。配合七十四的"弃置即进展"，舞蹈期间每 15 秒必有进展标记，快速重置与慢速弃置两条链互不打断。
[10:00:0] v1.1.0 实测七十四（新功能逻辑自查）：修复实测六十九看门狗与"目标超时弃置"机制的相互干扰——够不着的目标每个要站桩等 15 秒超时才被弃置，两个以上就超过看门狗 30 秒窗口；而旧版重置会把 30 秒短排表一并清空，刚学到的"这些够不着"归零，从同一个目标重新开始等 → 形成"每 30 秒重置一次"的新死循环。修复：①看门狗重置保留短排表（600 tick 自过期的学习成果）；②超时弃置/视线弃置/走路卡死判不可达弃置统一视为真实进展喂狗——弃置是消耗工作清单的前进动作，真死循环（选中→拒绝同一块）不产生弃置仍会被抓住。另经审查确认无碍并留档的权衡：穿透预算迁移会把"故意保持 22"的配置一次性改为 6；空矿表的"故意全禁"会被一次性播种默认全家桶（均为一次性，之后不再干预）。
[08:20:0] v1.1.0 实测七十二：根因是穿透预算的挡路计数跳过了石头/泥土这些"可开路方块"——地下到处是石头=零阻挡，预算形同虚设，隔地板/隔墙的矿全部入选，而脚下的矿距离分最低，于是女仆在洞里对着地板连凿竖井。修复：①挡路计数重新计入实心可开路方块，预算真正约束"最多隔着几层实心方块选矿"；②默认 22→6，更远的矿先走近再评估（想要旧版全穿行为调回 20+）；③旧档配置里存的旧默认 22 在加载时自动迁移成 6，手动改过的值不动。
[07:30:0] v1.1.0 实测七十一：猜对了。四套搭方块表（挖矿/伐木/搭路/自保）各自独立登记，而各任务的防误挖检查只查自己那套表——搭路垫的原木桥不在伐木的保护名单里，而搭路选材恰是背包最多的可放置方块（刚砍下的原木），正好命中木材目标，女仆把脚下桥当树砍掉摔落。修复：放置登记器新增跨系统统一查询，四个系统的防误挖判定全部改走统一口径——伐木/挖矿的扫描与连锁不再把任何系统垫的方块当目标，挡路判定也一律放行自己人垫的方块。
[06:40:0] v1.1.0 实测七十（反馈两条）：①日程表与主人主动切任务的冲突改硬规则——排班开着的女仆在第 1 页的任务按钮直接锁定（红色提示），服务端同步拦截单发与批量应用（聊天栏说明原因），想手动切任务必须先把她的排班关掉；同时排班开启期间她自动进入在家模式（守家按日程干活、不跟着主人乱跑，旧档已开排班的女仆自动迁移，建造行为临时占用后会被重新扶正），关闭排班即解除。②一键集合跨维度修复——根因是未加载区块里的女仆根本不在实体列表里（票务只救还加载着的）：现在每 5 秒登记全部有主女仆的最后出现位置，一键集合时对不在场者按最后位置强载区块并进待召回队列，实体一出现自动传回身边并聊天栏回报（15 秒兜底放弃）；在家模式的女仆也响应一键集合（主人明确指令优先于守家豁免），坐着/骑乘仍保持原位。手册排班章同步更新。
[05:30:0] v1.1.0 实测六十九：伐木/挖矿新增「发呆看门狗」——连续 N 秒（wood 默认 30/mine 默认 45，配置面板可调）既没挖掉任何方块、位置也没挪动时，自动整体重置该女仆的全部行为状态（锚点/扫描缓存/弃置排除表/目标/连锁队列/走路记忆），等效收回魂符再放下去，不再需要玩家手动救；走路赶路与垫方块都算进展不会误触发，重置时气泡说一声（限频）。顺带修复两处会喂出「发呆」的漏洞：关闭透视时被挡目标从「丢弃但不记录」改为进 30 秒短排（不再无限「选中→看不见→丢弃」循环）；伐木抬头兜底不再回选已被硬挡路弃置的木材。开关与时长都在配置面板挖矿/伐木小节。
promaid V1.1.0 实测四十九：种树苗间隔减半（100→50 tick，5 秒→2.5 秒）——砍完树补种树苗的限频冷却减半，连续砍多棵树时补种更跟手。
[05:00:0] v1.1.0 实测六十八（反馈两症状同根修复）：武器匹配的异常兜底从方法级改为逐物品——修复拿斧子的女仆被切到三叉戟模式无法攻击；威胁判定 Monster 改 Enemy 接口与参战同口径（史莱姆等也算威胁/可测距）——修掉打不死怪导致永远不还原的连锁。
[04:30:0] v1.1.0 实测六十七：主手和背包都没有任何攻击任务认可的武器（剑/弓/枪械/模组武器等）的女仆，不再触发自主战斗——维持原任务继续干活（含女仆被打触发与主人被打触发两条路径）；新增「空手不参战」开关（默认开，配置面板主动切换战斗小节，关闭恢复空手近战兜底的旧行为）。
[04:00:0] v1.1.0 实测六十六：搭路台阶始终朝主人——水平没对齐时朝主人方向斜着垫台阶（地形实心也会在地面上再垫一级踩上来），不再原地直上搭出够不着主人的柱子。挖矿/伐木/自保的搭方块维持原逻辑。
[03:30:0] v1.1.0 实测六十五（实际运用审查修复 4 处）：分帧扫描进行中不再被 5 tick 节流（实际吞吐曾只有设计值 1/5，默认预算找一框从 0.85 秒变 20 秒）；主人摔落/岩浆/火烧等环境伤害不再误触发全队参战（要求伤害有来源实体）；女仆被打参战的判定 Monster 改 Enemy 接口（史莱姆/岩浆怪打她也参战了）；一键集合跳过在家模式女仆（跨维度集合后回不了家）。
[03:00:0] v1.1.0 实测六十四（重大修复）：排班表界面重写时遗漏了保存方法，导致五十一起每次编译都静默失败、打包的一直是旧界面字节码——五十一至六十三的全部界面/战斗/伐木挖矿改动实际未进过 jar。已补回方法并修复 7 个积累编译错误（改名 getValue SRG、5 处消息调用括号、MaidFireGuard 编译清单），构建脚本新增「源比 class 新拒打包」硬校验。本次为五十一以来全部新功能的首次真正部署。
[02:30:0] v1.1.0 实测六十三（代码自查修复 4 处）：列表搜索框击键重建后光标回 0 导致输入倒序乱码（光标移到末尾）；批量应用跳过自保中/主动战斗中的女仆（不再打断保命与战斗还原链）；一键集合跳过坐着的女仆（建造强制坐下不再被拽走）；伐木/挖矿分帧扫描进行中不再触发锚点滑动/播报（低预算下扫描永远完不成的死循环）。
[02:10:0] v1.1.0 实测六十二：女仆着火不传主人——燃烧女仆对主人的伤害直接取消；贴身接触传火每半秒检查一次自动给主人灭火（主人自己站火里/岩浆里不干预）；开关在配置面板「贴身辅助」小节。
[01:50:0] v1.1.0 实测六十一（借鉴 TLM-Sincerely 防抖与预算制探测）：战中换战术新增最短持有/反向切换窗口/反向冷却三重防抖；主动战斗还原后新增排班宽限期（防威胁闪烁拉扯，手动保存日程立即生效）；伐木/挖矿全量扫描改为分帧游标续扫（每 tick 预算可调，消除单 tick 扫描尖峰）。全部参数进手册配置面板。
[01:20:0] v1.1.0 实测六十（借鉴 Maid_Roster 军队管理，不学绑定点名册）：排班表列表页新增——搜索框按名字过滤、每行血量+维度状态（列表改为跨维度扫描）、全员模式一键应用（早/晚/全天）、批量任务选择+应用、一键集合（全部在场女仆含跨维度传送到身边，复用真传送链路）、详情快捷页改名（等同命名牌）。
[00:50:0] v1.1.0 实测五十九：排班表详情页拆回两页（页签切换）——第 1 页快捷设置（工作模式/任务点击立即生效，恢复实测五十一移除的遥控能力），第 2 页排班（班次+6 任务槽+保存）；排班开关两页共用右上角；排班页纵向压缩（班次行下移+槽行距 22）适配 240 高最小窗口。
[00:30:0] v1.1.0 实测五十八：女仆被怪物攻击也触发自主战斗（本人立即参战+周围同主人姐妹响应，只认怪物来源防女仆混战）；新增近战/远程偏好权重配置（两者皆可用且近身时按权重选池，默认 3:1 偏近战；设 0 永不选/切向该类，战中换战术同步受限）。
[23:59:59] v1.1.0 实测五十七：主动战斗战中动态换战术——远程被敌人近身（≤5 格）且背包有近战类武器（含模组）立即切近战；近战敌人远到大跳都跳不过去（>6 格）但仍在索敌范围（≤16 格）切远程放风筝；5~6 格滞回带防横跳；切换同步指派标记，还原链路零影响（威胁消失照常回原任务）。
[23:59:0] v1.1.0 实测五十六：排班表 UI 像素级自查修复 5 处缺陷——班次按钮与排班开关重叠（默认宽 427 下压 38px）、保存按钮与第 6 时段按钮角部重叠、底部提示被返回按钮遮挡前 17 字、页码两端被翻页按钮压 10px、时段标签与按钮 0px 贴边；列表页副标题文案同步新 UI。
[23:23:0] v1.1.0 实测五十三～五十五：排班表任务名中文化（翻译组件误用字面量的老 bug）；排班表图标改为原版旗帜图案物品贴图、附魔光效改手册同款（isFoil，0 级经验修补方案证实无效已移除）；伐木修复——站树洞里对头顶木材视而不见（空闲抬头兜底+站立点空中格兜底删除+头顶目标等待重试），垫块节奏 4→2 减顿挫。
[22:22:0] v1.1.0 实测五十二：修复被动插火把严重浪费——亮度判定旧版只读方块光（白天地表恒 0，跟着走路一路狂插），改为原版合并口径 max(方块光, 天光-天空变暗度)：白天/雨天不插，夜晚地表与地下照常。
[20:20:0] v1.1.0 实测五十一：排班表 UI 重做——选班次（早/晚/全天）+ 6 个任务按钮排一天，不再手填时间；工作时间均分 6 份（相邻同任务自动合并），休息时间不排段由作息睡觉；手册排班章节同步更新。
[16:16:0] v1.1.0 实测五十：排班表物品图标改为游戏内旗帜（banner）图案样式（悬挂红旗，旗帜图案风）；附魔流光特效沿用实测十一的 0 级经验修补方案，确认仍生效。
promaid V1.1.0 实测四十八：伐木移动速度减半（反馈至少快一倍像狂奔）——基础速度 wood.moveSpeed 默认 0.6→0.3；远处（>8 格）赶路加成 1.5×→1.25×（基础变慢后远处不必再猛加速，衔接更自然）；锚点迁移赶路原本硬编码 0.6（正是过快的一处来源）改为随 wood.moveSpeed 配置走。已有存档的配置文件若残留 0.6，需在配置面板伐木页手动调低或改配置文件。
promaid V1.1.0 实测四十七：伐木站树洞发呆修复 + 站方块刷新寿命落实到挖矿/伐木——(1)【站树洞发呆】女仆砍掉树干下 3 节后走进树洞，头顶就是树干本体：垫方块（pillarUpStep）的防窒息检查拒绝在树洞里往上垫（头顶被树干堵死）→ 旧版不垫也不走也不挖，站桩发呆。现垫块失败时改为把目标切成头顶正上方第一块木材（同柱最多上探 8 格），下一 tick 从正常挖掘入口直接挖掉（伸手范围内），逐节往上啃完整棵树，全程不需要垫方块；(2)【站方块刷新寿命】站上垫脚方块刷新满寿命的机制原先只在搭路/战斗落实，挖矿/伐木没落实：旧判定只认『正在挖矿』标记，而该标记在空闲扫描期会短暂移除（女仆仍站在方块上）→ 方块在她脚下照常到期消失。现 PlacedBlockTracker 到期扫描加第一道判定：绑定女仆本人站在方块上（脚下或脚下下一格）恒刷新寿命；第二道谓词（同任务姐妹借踩）保持不变。魂符收回暂停计时、跨维度强制回包均不受影响。
promaid V1.1.0 实测四十六：女仆放方块音效修复（反馈放方块变成咆哮声）——旧实现用 levelEvent 3001+方块id 附加数据，该事件的附加参数在客户端按注册表 id 解析，mod 环境下 id 错位被当成无关音效播放（咆哮）。现改为服务端 playSound 直接广播方块自身 SoundType 的放置音效，音量/音调按原版 BlockItem 公式（(vol+1)/2、pitch×0.8），与玩家亲手放方块完全一致；挖矿垫脚/斜坡/搭桥、伐木同款、搭路 9 处放置点全部切换。
promaid V1.1.0 实测四十五：配置手册第2页起排版错乱根治——旧版行坐标是【从第0行开始全表累加】的绝对 y，渲染/实例化侧却只取当前页的 start..end 行去查这张表：第1页恰好正确，第2页第一行拿到的还是它在第1页时的 y（起点整体偏低、行高分布随页错位）→ 文本与输入框/注释互相重叠。现改为按【页】布局：init 侧先算每页行数，再把【当前页】各行从 CONTENT_TOP 重新起算的 y 存入 pageRowY，渲染与控件实例化同用一份字段，任何页/任何分辨率下行位置一致；渲染侧不再重算（旧重算逻辑同款错误）。
promaid V1.1.0 实测四十四：女仆区块强制加载（约等于玩家）+ 跨维度跟随真传送——(1)【区块强制加载】与主人不同维度的女仆，其所在区块自动挂强制加载票（2 秴=实体正常 ticking，玩家同等待遇）：主人走远/下维度后女仆区块不再卸载，跨维度跟随与死亡传送永远能找到她（旧版：主人远离后区块卸载→扫描找不到女仆→传送静默失效『女仆全部消失』）；同维度时不占票（区块由玩家自然加载）；女仆传送走/收回魂符/死亡自动撤票，服务器关闭全量撤票；杂项页新增开关（默认开）；(2)【跨维度跟随改真传送】旧版手动 setRemoved+addFreshEntity 搬家不走 Forge 维度事件链、实体不重新注册到新维度存储（假传送）；现改用原版传送（完整跨维度流程+客户端维度同步），并补传送后清残留速度。
promaid V1.1.0 实测四十二：垫脚方块回收机制重做——新统一追踪器 PlacedBlockTracker（挖矿/伐木/搭路/战斗四方块共用）：(1)方块登记时绑定搭建女仆（UUID），到期不再按位置找附近女仆，而是跨维度定位该女仆本人，把方块以物品形式强制送回她的背包（含下界之星等），背包满才落地掉落物；(2)女仆被收回魂符/不在世界期间，她名下所有方块计时暂停（找回后继续倒计时）；(3)方块被任意女仆踩着时刷新时长（不立即回收），离脚后继续计时；行为内与 ServerTickEvent 双通道到期兜底（旧版行为停止后靠 8 格找女仆、找不到就原地掉落是缺陷根源）；实测四十三：挖矿间歇性停歇修复——接近够不着的矿期间若女仆位置连续 40 tick（2 秒）未变（导航被地形卡住、有路径走不动，即玩家观察的『挖一会儿停一下，收回重放立刻恢复』的停歇状态），自动执行软复位：清移动目标记忆+停导航强制重寻路（与收回重放清空导航状态等效）；同一目标 3 次重寻路仍原地不动即判不可达，弃置该矿并 30 秒短时排除，不再原地磨蹭等待 15 秒目标超时。
promaid V1.1.0：六大新功能——伐木 / 枪械战术 / 主动切换战斗 / 排班表 / 搭路——(1)【伐木任务】全新任务 maid_smart:woodcut（架构克隆挖矿）：女仆自动找树、持斧渐进砍伐、连锁砍完相连树干（默认开）；树叶不挡视线不计阻挡（树冠里的树干照常可见）；木材表默认含全部原版原木/菌柄/竹/去皮变体，配置面板独立「伐木」板块，木材名单创造网格只列木质类产品（原版木质 tag 并集，模组木材自动纳入）；障碍物名单与挖矿共享一处配置；带原版 #minecraft:logs 标签的模组原木自动识别为可砍木材（默认开，价值 300——「自动识别模组原木（标签）」开关在伐木板块，关闭则只认名单；与挖矿要手动加模组矿不同，伐木对模组原木零配置）；手册详细介绍新增「伐木系统教程」章节；(2)【枪械战术（TACZ/卓越前线）】TLM 内置枪械任务接入 promaid 战术体系：持枪女仆自动装枪（弹药充足的枪优先），走位复用弓弩三叉戟同款风筝逻辑（理想射程 = TLM 枪械中距离配置 × 60%，远近自动调整、绕圈横移），接战范围/举盾豁免/远程攻击者识别全部覆盖枪械；切到枪械任务模式即自动换枪；(3)【主动切换战斗模式（默认开）】主人被敌对生物攻击时，附近（默认 16 格）的女仆无论在干什么（挖矿/伐木/烹饪/建造/跟随…）立即切战斗模式保护主人——装了 TACZ/卓越前线且背包有枪+弹药优先切枪械模式，否则从近战/弓/弩/三叉戟/弹幕按背包武器随机选；威胁消失 20 秒自动还原原任务（可配置；判定威胁消失用独立小威胁半径默认 8 格，战斗中玩家手动安排的任务不会被自动还原翻回去，有排班表的女仆还原时直接交给排班当前段）；优先级：自保 > 排班表 > 主动战斗 > 玩家手动；(4)【排班表】新物品（纸+墨囊合成，旗帜风图标+附魔流光）右键打开：女仆列表 → 快捷设置（工作模式早班/晚班/全天 + 任务切换 + 排班开关，点击即生效）/ 日程设置（00:00~24:00 游戏内时间分段编排一天干什么，每段 = H:MM~H:MM + 工作模式 + 该时段任务；保存自动去缝隙补满 24:00；跨段时间点自动切换，一天 20 分钟）；排班数据随女仆存档（魂符收放不丢）；杂项页有「排班表系统」总开关（关闭=排班调度停摆、日程数据保留，重开即恢复）；(5)【搭路（默认关）】主人在女仆上方 ≥2 格且距离 <7 格（传送判定距离）、周围无威胁、背包有方块时，女仆走到主人下方垫方块逐格搭高靠近（借鉴僵尸搭方块追人；真实消耗背包方块，搭的方块 10 秒自动回收）；搭路期间禁止瞬移防止白搭；被动技能页「搭路」开关默认关闭；(6)【落地雪（默认开）】落地水的细雪桶版：高空坠落时自动在【落点平面】铺 3×3 细雪垫接住她并收回（桶不消耗，与落地水共用触发高度/保持时长/下探格数，两者都有桶时优先用水）——细雪不流动、落点必须正好是雪，与水的放法有本质区别：水可提前放稍高处靠流动铺开（碰到的任何水都重置摔落），雪只铺在落点平面且坠落途中逐 tick 跟着落点补垫（防击退/横移漂移错过），绝不在高处拦她减速（出雪后剩下的路是自由落体照样摔）；下界也能用（水会瞬间蒸发、细雪不会）；细雪接触 7 秒（140 tick）才开始冻伤、保持时长上限 100 tick（5 秒）在安全线内；注意：落地雪天生比落地水难、有小概率失败（细雪不流动、落点被漂移出雪垫或落点格非空气铺不进雪等）——机制固有上限，追求稳定请优先给水桶；开关在被动技能页；(7)【修复】配置面板排版修复——①标签偏移：宽屏时行标签固定 x=20、控件居中，改用 panelLeft+10 对齐；②第2页起控件全堆到屏幕顶部 y=0：rowY 数组是全局累加，第2页 start 行的 rowY[start] 未赋值默认 0，布局侧和渲染侧都从 CONTENT_TOP 重新累加当前页行位置（实测二十四）；(7)【修复】挖矿/伐木中自己搭的方块不再被自己当障碍物/目标挖掉（10 秒标记内跳过——根治"拆了再搭"死循环；伐木搭路材料几乎必是原木，此前必触发该循环）；建造强制坐下被玩家"解除坐下"后坐着走动——建造坐下状态现全程启用移动源头锁（MoveToTargetSink 取消 + 实体层水平速度清零，保留垂直下落不溺水；直连导航/直接速度矢量等一切通道都无法再让坐着的建造女仆挪动，此前只在建造行为激活期间有锁，缺料/找区块等间隙漏锁）；发布前终审再修多处——主动切换战斗（①标记判定改 getBoolean：旧 contains 判定遇 putBoolean(false) 不删键永远为真——女仆打完一仗后永不再响应主动参战、排班调度器也会因她"看似在战斗中"而永久让位；②还原前先校验任务未被玩家换过，不再覆盖玩家手动安排的任务；③还原扫描改按持久化标记遍历——存档重读/换维度不再卡死在战斗任务，单只找不到战斗任务不再 return 跳过同半径其他女仆）；搭路（①canUse 探测改无副作用判定——旧版每轮启动尝试都凭空消耗背包一枚方块；②头顶被挡/材料耗尽 20 秒垫不出方块自动放弃并播报，不再原地僵站；③中途因威胁中止时脚下已垫方块延后到走开才回收，不再瞬间消失让女仆从半空掉进威胁堆）；home 模式（在家模式）的女仆不搭路——守家不出门，与跨维度跟随同款豁免；搭路新增「垫脚方块回收进背包」开关（默认开，全局开关——搭路/挖矿/伐木一切女仆搭的垫脚方块都适用；v1.1.0 实测十从搭路专属升级并默认开启）——开启后到期/被摧毁的垫脚方块不掉落地面，直接塞回附近女仆（8 格内最近者）背包，背包满/附近没人才落地；实测十二修复——排班表界面三连修（①崩溃：删掉唯一一行分段/数据未到时 schedTab 对空 rows 取 get(0) 越界直接崩游戏——空表现在只显示「+ 添加分段」按钮不再建行，冒号/波浪线渲染同口径；②日程 tab 切换：每次进入都无条件重新拉最新数据（旧版只在特定状态补发请求，切回快捷再切日程会显示旧数据或空白）；③时间格式固定 □□：□□～□□：□□ 六框形状——小时十位空也显示框（9:00 显示成 _9:00 而不是挤掉一个框），形状不随数值变形，每个框仍只填一个数字）；实测十一修复——排班表物品常驻附魔光效（附魔书同款紫色流光——ScheduleBookItem override isFoil 恒 true，与 UI 红色调+紫红斜体标题的排班主题呼应）+ 物品图标改为红色调书本贴图（原先是借用原版 writable_book 的棕白贴图，与排班界面的红色主题不搭）；实测九新增——伐木冲破树叶（伐木状态下女仆身边 3×3×3 立方体内的树叶每秒直接摧毁并产生掉落物【autoCollect 开着直接进背包】——走路被树冠卡住不再绕路/站桩，直接穿过去；开关跟随树冠清理 wood.leavesClear，不想清叶一起关；立方体内的原木不碰——那是正常挖掘目标，走挖掘流程有工具加成）；实测八扩展——女仆互助链对齐主人支援链（把套给主人的方案复刻给姐妹女仆：①着火丢抗火药水；②负面效果喂牛奶全解【空桶返还；女仆版不做有增益不喂牛奶的保守检查——战场实用主义】或蜂蜜【解中毒+回饱食+玻璃瓶返还】；③低血走完整治疗链——喷溅治疗→金苹果/附魔金苹果【吸收+再生，附魔加抗性抗火】→再生药水→按饱和度择优喂食【手持也认】；主人优先级永远更高——同一 tick 主人链先跑完，主人有需求时互助轮空）；实测七修复——搭方块选材全局统一安全过滤（新建公共过滤器：火把等【无碰撞体积】方块绝不能垫脚——旧版四个模块【自保搭高/挖矿/伐木/搭路】的选材只拦下落方块，火把成了背包里数量最多的方块就会被选中，垫了个寂寞还白消耗；统一过滤 = 非下落方块 + 非 TNT + 伤害黑名单【仙人掌/岩浆块/甜浆果/营火/细雪等】+ 碰撞形状非空 + 非可替换方块【#minecraft:replaceable——火把/草/雪片第二道闸】+ 完整碰撞形状，战斗/挖矿/伐木/搭路一切垫脚场景同口径）；实测六新增——女仆互助战斗支援（①不死图腾共享范围扩大：女仆自己手里/饰品栏/背包的图腾全用完仍是致命伤时，16 格内同一主人的其他女公会共享图腾救她——与救主人同机制（背包优先再饰品栏、真实消耗、原版特效），双向气泡播报；②女仆给女仆丢药水：同主人 16 格内的姐妹低血（低于治疗阈值）或着火时，有富余药水的女仆会给她丢喷溅治疗/再生/抗火药水（同款追踪弹+择优+同种 CD 记账；主人不在身边时互助照常运作——两女仆外出战斗场景；主人优先级永远最高）；③投掷药水命中率优化（追踪弹速度 1.6→1.05 格/tick——旧速度单 tick 位移超过目标碰撞箱半径会整个穿过去、方向修正永远慢一拍；近距离直接命中阈值 1.2→2.5 格——喷溅半径内贴脸必中））；实测五新增——伐木树苗补种（树砍完后在树干原址向下找泥土/草地面，从背包拿任意树苗【#minecraft:saplings 标签，模组树苗自动兼容】种下消耗一个，限频 5 秒防连种；运作逻辑与插火把同款被动式——手中有树苗才会种，没有就跳过）；插火把兼容更多火把（灵魂火把/红石火把等——普通火把绝对优先，背包有普通火把绝不用灵魂火把【亮度 14>10】，只有普通火把用完/没有时才退而求其次；放置按火把自己的方块不再是写死的普通火把）；实测四修复——搭路区分地面/空中两套距离阈值（地面维持 7 格传送判定距离——平地上太远该走路/传送不铺桥；空中【脚下悬空或站在垫的方块上】放宽到独立配置 airMaxDist 默认 24 格——空中没有走路选项，远远看见主人就直接空中铺桥走过去，canUse/canContinue 双口径同步）；伐木新增「树冠清理」开关（默认开，伐木板块）——树干砍完后顺手把上方树冠的树叶也清掉（半径 3 格 BFS 相连树叶，掉落物/树苗/苹果直接进背包），不再挂着挡视线慢慢掉东西；实测三修复——伐木中距离站桩（斜坡/搭桥距离门槛 4.5→8 格——树干下半部常在 4.5~8 格，旧版这段距离不垫也不走干等；找不到站立点时直接朝树干走不再原地站桩；站立点搜索圈扩到 2 格——树冠内 1 格圈常被树叶占满）；搭路空中水平铺桥（参照僵尸追人：主人高度接近但水平还远时，朝主人方向前方一格脚下直接垫方块走过去——旧版只垂直叠柱/傻站，导航在半空永远失败）；搭路威胁半径默认 12→8（刷怪频繁的整合包里 12 格内几乎永远有怪，搭路会永不触发；主动切换战斗的还原判定同样新增独立的 8 格威胁半径配置，响应半径 16 不变）；排班表界面（两个设置 tab 旧版建在同一坐标完全重叠——看得见的是「日程设置」、点中的却是先注册的「快捷设置」；已改左右并排，整页窄屏自适应——排班开关不再与 tab 同行、分段行宽度/行数按窗口尺寸收敛，六档分辨率像素审计 0 重叠 0 出屏）；搭路方块耗尽改立即中止播报（不等 20 秒；选材保持「背包数量最多的可放置方块」不变，canUse 无料不触发原本就有）；终审二实测反馈修复——伐木空手傻站（找树前/够得着树后主手没斧都不会主动从背包装备，改 findWood 前 ensureAnyAxe + 挖掘前补换斧，完全没斧时限频播报）；搭路向前搭（水平未对齐时朝主人方向前方一格脚下垫台阶斜上逼近，不再只垂直叠柱等导航绕路）；排班表界面重做（红色调+附魔书风紫红斜体标题+顶部红色饰条；列表只显示名字不再拼任务串；任务名翻译缺失时回退显示 path 段而非 task.touhou_little_maid.xxx 整串；时间改 6 个单数字输入框「时时:分分～时时:分分」默认空、只收数字；末段到 24:00 后「+ 添加分段」按钮隐藏）；钓鱼任务自动换钓鱼竿（主手非钓竿即从背包装备，优先级与武器一致——TLM 钓鱼任务条件就是主手持钓竿）；建造强制坐下改走 setOrderedToSit 指令位（与玩家 shift+右键坐下完全同状态，根治坐姿位与指令位不一致导致的坐着小幅挪动）；卓越前线能量武器（二次灾变/超级星星炮）不吃常规弹药（内部充能）——枪械可用判定与装枪评分对它们跳过弹药检查（旧版「枪+弹药」硬要求导致拿二次灾变判定无子弹不切枪械模式）；(8)【手册】玩家可操作原则补齐——杂项页新增「排班表系统」总开关；战斗与自保/被动技能/单兵战术/武器切换章节补主动切换战斗、搭路、枪械战术的使用说明与开关位置；新增「排班表（全女仆日程调度）」教程章节（合成/两设置页/让位规则/举例）；配置面板导航补 v1.1.0 各开关入口；伐木/搭路/主动战斗章节同步补模组原木自动识别、还原威胁半径与玩家手动接管语义。；实测十五修复——搭路追主人加任务空闲门禁：挖矿/伐木已锁定目标（MINING/WOODING 标记）、建造任务且未暂停、烹饪/酿造站桩中都不再启动搭路；搭路途中任务重新占用（排班切班/矿刷新被重新锁定）立即中止让位、脚下方块 10 秒自回收——手上的活没干完不撂挑子，挖完矿的空闲间隙（框内无矿、标记已摘）照常追主人；实测十六修复——发布前全面审查（P1×5 + P2×8）：①主动切换战斗标记判定 contains→getBoolean（旧版 putBoolean(false) 不删键致 contains 永真——女仆打一仗后排班永久失效+每秒无效 NBT 写）②空手砍树双 return 死锁（没斧的女仆锁树后永久发呆——没斧照砍承诺落地：换不上斧播报后继续走挖掘公式）③树冠清理 BFS 起点失效（旧版从树干正上方一格起扫、非叶即终止——常规自底向上砍树几乎触发不了；改为沿树干向上爬最多 8 格找第一片真树叶起步）④金苹果/喂食链无 CD 连喂（旧版只有增益链记 3 秒间隔——主人低血+治疗药水在种类 CD 内时每 tick fallback 金苹果，几十个几秒蒸发；互助链每 tick 全量扫描+双重调用无节流——统一 CD 记账+互助链复用同一间隔让位）⑤排班 taskUid 直接 parse 脏数据崩服（改 m_135830_ isValid 预检+try/catch 双保险——1.20.1 无 tryParse）⑥落地水/雪 doStop 回收兜底（保持期内魂符收回/死亡→水/雪永久残留——加 doStop 兑底+回收改女仆当前维度感知）⑦树苗/火把消耗改 extractItem（旧版直缩 getStackInSlot 返回栈——handler 返副本时扣不掉=无限刷方块）⑧purge 存活联合补 SAPLING_PLANT_SINCE（旧版漏加→活女仆补种限频被每 30 秒误删→多耗树苗）⑨图腾 mixin 致命伤路径加整体 try/catch（旧版异常抛穿 hurt/die 链最坏崩服）⑩图腾特效改 levelEvent 2007（旧版 levelEvent 35 要求双手持图腾——从背包/饰品/同伴消耗时客户端什么都不渲染，四个分支全中招）⑪红石火把移出自动插火把清单（亮度仅 7 且会发红石信号——黑暗中自动放可能意外激活附近红石机关）⑫排班表 S2C 包加方向校验（恶意客户端发 S2C 包 ID 到服务端→加载客户端类→专用服崩）+Screen 空任务列表 IOOBE 守卫+副手食物哨兵值 -1 冲突修复；实测十六续二修复——P3清理项：①蜂蜜喂姐妹返还玻璃瓶（旧版吃完蜂蜜不返还瓶子——主人链有返还逻辑姐妹链漏了，物品凭空消失）②树冠清理掉落尊重 WOOD_AUTO_COLLECT 开关（旧版无条件进背包，与 burstNearbyLeaves 口径不一致——开关关着时该落地由拾取任务处理）③树苗补种可种地面改用 #minecraft:dirt 标签（旧版只认 dirt/grass_block——雨林/红树/繁茂洞穴等长在灰化土/苔藓/泥巴/缠根土上的树不补种；标签涵盖全部泥土变体+模组泥土）；实测十六续修复——P2/P3 深度加固：①药水 CD 改按女仆 UUID 分桶（旧版按效果种类全局共享——A 女仆给主人投治疗 B 女仆的治疗链跟着进 CD，投给姐妹的治疗也占主人的 CD；改为 (maidUUID, potionKey) 二元 key 每女仆独立）②跨维度排班请求回空数据包（旧版女仆不在当前维度时服务端静默 return→客户端 waiting 永不清除、日程 tab 永远卡请求中…；改为回空数据包客户端正常显示空表）③伐木危险方块判定改 static 缓存（旧版每次调用对 6 个 ID 各做一次 ResourceLocation.parse+注册表查询——fullScanWoods 每 5 秒数百候选×6=数千次注册表查询，改类加载时解析一次）④APPLIED_TAG 类型混写统一（AutoCombatSwitch 用 putBoolean 清、ScheduleManager 写 String——getString 对类型不符安全返回空串恰好等效但类型不一致是隐患，统一 putString 空串）；实测十七新增——战斗搭方块改为 60 秒自清 + 女仆可拆（自保行为的搭高/翻墙/搭桥/封头盖帽/岩浆垫高方块原本【永久留下】——玩家当初选择不清理；现改为与挖矿/伐木/搭路同款的标签追踪机制：①60 秒后自然消失——战斗节奏多变女仆可能还要在塔上待一阵，比挖矿的 10 秒长；女仆还站在上面的方块延后回收（搭高塔上打持久战不会脚下被抽走）②女仆可以直接破坏挡路的战斗方块——逃跑方向前方 1~2 格（脚部+头部高度）有自己搭的方块直接拆掉再导航，实际战斗多变，防止女仆自己搭了个死路还逃不出去；只拆自己登记过的战斗方块（自然地形/玩家建筑绝不碰）③bridge.reclaimToMaid 开关（垫脚方块回收进背包）从仅控制挖矿/伐木/搭路扩展为也控制战斗方块——开启时到期/被拆的战斗方块直接塞回附近女仆背包，关闭则正常掉落落地④玩家替换过的方块不误破坏（blockId 比对同口径）；服务器停止时残留战斗方块立即回收清场）；实测十八修复——搭方块站上面时刷新计时：旧版挖矿/伐木/搭路/战斗方块对正被女仆踩着的到期块只做【无限延后】（tick 不变、走开即清）——挖矿女仆在高柱上连续作业几分钟，脚下块早已过期但被一直延后，她一挖完走开整根柱子【瞬间全部到期】（含下落途中可能踩到的下段）→ 高空坠落。改为女仆踩着时【重置该块寿命】（从最后一次被踩起算满寿），走开后每块还有完整的 10 秒（挖矿/伐木/搭路）/ 60 秒（战斗方块）缓冲逐块到期，不会整塔瞬间塌——四张追踪表（MINE/WOOD/BRIDGE/COMBAT_PLACED）统一口径）；实测十九新增——战斗搭方块清理时间可配置（combat.placedLifetime，默认 60 秒，范围 3~600——与其他搭方块清理项同款玩家可调；搭路配置页新增「战斗搭方块清理（秒）」输入行；挖矿/伐木/搭路的清理时间原本就可在各自配置页调整）；实测二十重构——主动切换战斗触发与选模式双双升级：①触发条件扩展——主人被【任意来源】攻击（敌对生物/玩家 PVP/弹射物都算，仅自伤排除）或主人【攻击了别的生物】（主动开火也算开战；打自己女仆的误伤不触发）都让附近女仆参战②选模式重构——删除「枪械优先」开关，改为扫描 TaskManager 全部 IAttackTask 攻击类任务（自动含万法皆通/史诗战斗/真正的力量等模组任务与 TLM 枪械），按各任务自己的 isWeapon 匹配背包武器过滤候选，候选池加权随机：模组任务权重 2.0、原版五件套（近战/弓/弩/三叉戟/弹幕）权重 1.0（模组武器普遍更强降半权但不绝对排除）；任务对所有物品都不认（不限武器型模组任务）照样入池；全都匹配不上空手近战兜底③配置面板「枪械优先」行删除（旧配置文件残留键无害），手册/面板说明同步更新；实测二十一半——武器权重可配置（选战斗任务的加权随机权重拆成两条配置项：模组武器权重 combat.autoSwitchModWeight 默认 2.0、原版武器权重 combat.autoSwitchVanillaWeight 默认 1.0——例：背包法书+铁剑时法术:近战≈2:1=67%:33%；想五五开把两条都设 1、想模组绝对优先把原版设 0.1；面板「主动切换战斗」小节新增两行输入框，范围 0.1~10）；实测二十一半附——战斗还原延迟默认 20 秒改 10 秒（autoSwitchRestoreDelay 默认 400→200 tick——威胁解除后更快回岗；该配置项原本就有 UI：面板「主动切换战斗 → 还原延迟（tick）」输入框，范围 60~3600，手册说明同步）；实测二十二新增——配置面板像素级重叠防御：旧版行高固定 44px，注释折成 3 行以上时（长说明+窄窗口+GUI 缩放大）尾部与下一行标签/输入框像素重叠。新架构三层防护：①wrapComment 像素切割——注释按面板实际像素宽逐字符累积测量（font.width）超宽即折行，成为高度计算的统一口径②rowHeight 动态行高——每行高度=控件 22px+间隔 3px+注释行数×10px+底留白 9px（SectionRow 紧凑 18px），注释长行自动加高③布局与渲染同口径——perPage 按动态行高从 CONTENT_TOP 逐行累加计算（超出内容区换页），行位置两侧共用同一份累加结果，彻底消除两套计算脱节的根源；任何分辨率/GUI 缩放下注释与下一行永不重叠，长注释页自动少排几行；实测四十一调整——伐木两项默认开启：①透视感知（隔墙找木材）默认值 false→true——树木天然被树冠/地形遮挡，关着容错率太低；②连锁砍伐代码默认本就是 true，但现存档配置文件里是 false（历史遗留），已同步改回 true——与挖矿连锁默认开对齐。两项仍可在配置面板伐木页随时关闭；实测四十新增——远程被贴身近战反击：远程走位（rangedTick）新增贴身判定——敌人贴进 2 格内触发一次近战反击（冷却 2 秒防连拍）：摆臂动画 + 横扫粒子（levelEvent 2004，玩家横扫同款）+ 对贴身目标及 2 格内其他敌人造成近战伤害 + 原版击退（0.5 力度，玩家普攻级）；伤害 = 背包 DPH（攻击力属性修饰和）最高的非远程武器（枪械/弓/弩/三叉戟按判定口径不算近战），无近战武器 1 点空手伤害；反击不换主手（远程武器保持在手，反击是瞬发动作）；实测三十九修复——主动战斗威胁消除后无法还原原任务：根因是还原流程【先清标记再还原】——还原链路任何一环失败（战斗前任务找不到/排班重应用异常/任务 UID 非法），标记已被清掉：下次触发时她被当成「玩家手动安排的战斗任务」跳过、还原扫描也因无标记跳过 → 永久卡死在战斗任务；且还原全程零日志无从观测。修复：①改为【先解析战斗前任务、全部就绪才清标记执行还原】——解析失败保留标记下轮重试，不再一失足成千古恨；②还原全程加日志（latest.log 搜 auto-combat restore：成功记 原任务←战斗任务+威胁消失时长、失败记原因 FAIL/任务被换）；实测三十八新增——主动战斗选武器加距离判定：候选攻击任务先按武器类型分近战/远程两池（原版近战 attack 与 ef_tlm 史诗战斗/slashblade 拔刀剑/sbr_core/truepower 系=近战；原版弓/弩/三叉戟/弹幕/枪械与万法皆通法术系=远程；未知模组任务按近战兜底），只有一类有武器时该类内仍按原版/模组权重随机；两类都有时看女仆与最近敌对生物的距离——≤5 格用近战池、>5 格用远程池（池内仍加权随机，不退化成固定顺序），找不到敌人按远程兜底（安全距离输出）；选择结果记日志（auto-combat pick: both-pools dist=x -> melee/ranged）；实测三十七新增——女仆搭方块播放动作：挖矿/伐木/搭路三大行为里全部 9 处放方块点（垫高 pillarUpStep / 斜坡台阶 slopeStep / 搭桥 bridgeToOre·Wood / 搭路的垂直·斜坡·空中铺桥）统一补上摆臂动画（swing 主手，与挖方块/插火把同款）+ 放置音效粒子（blockEvent 3001，玩家放方块同款反馈）——旧版方块凭空出现没有任何动作，观感突兀；实测三十六修复——主动切换战斗「主人被打仍不触发」：LivingHurtEvent 不是唯一受伤信号——枪械模组（卓越前线等）伤害走自定义管线（自管伤害计算/减伤），事件可能【不发】或被其他模组（EF/SBW 自带减伤）【取消】。兜底：触发事件从单 LivingHurtEvent 扩为三事件全监听——LivingAttackEvent（受伤链最上游，任何模组 cancel 之前必经）+ LivingHurtEvent + LivingDamageEvent（结算层），三事件任一先到即触发、后到的被 20 tick 节流去重（同一次攻击只切一次）；主人开火侧同样补 LivingDamageEvent 兜底；触发时记日志（auto-combat trigger: owner 名字 hp——下次再不生效可直接看有没有这行）。；实测三十五调整——插火把检索再提速：①检索冷却 15 tick（0.75 秒）→ 10 tick（0.5 秒）；②亮度扫描范围主人脚下 3×3 → 5×5——旧版只有一格宽的跟随带，走路时边缘暗格轮不到检索就走出去了；5×5 覆盖正常走路节奏，每轮仍只插最暗的一格（节奏由冷却控制，不连插一片）；实测三十四修复——喂姐妹蜂蜜瓶不解中毒：姐妹链走 LivingEntity.eat 进食——只加饱食/食物效果，原版「喝蜂蜜解中毒」的 removeEffect(poison) 发生在 HoneyBottleItem.finishUsingItem（玩家喝完才触发），eat() 不经过它；主人链之所以有效是因为 feedFoodDirect 里手搓了 removeEffect。姐妹链补同款解中毒 + 喝蜂蜜音效；实测三十三重做——排班表 UI 整体重写：旧界面多轮补丁后布局参数多处复制粘贴口径不一（tab 与排班开关重叠、6 个单字符数字框焦点链脆弱易丢字、渲染与按钮两套坐标各算各的）。重写原则：①所有控件坐标集中在唯一布局函数、渲染层静态文字复用同一组常量——消灭「改一处漏一处」；②固定栏式分区：顶部标题/tab/内容区/底部按钮区互不重叠，行数按窗口高度自动收敛；③时间段改单输入框（形如 9:00~17:00 直接打字，保存时校验）替代 6 数字框——多行输入焦点稳定不丢字；④任务按钮文字截断防溢出，超可视行数给「还有 N 段未显示」提示；⑤工作模式改普通循环按钮（旧 CycleButton 在部分场景不刷新）。功能与网络协议不变，已保存的排班数据不受影响；实测三十二修复——女仆支援系统四项：①姐妹支援气泡固定文案「药水来了」改为「姐妹挺住，我来帮你」，并新增绿色系统字幕记录具体支援内容（[maid_smart] 某某 支援了 某某：扔了治疗药水/喂了金苹果/喂了牛奶（负面全解）/喂了蜂蜜瓶（解中毒+回饱食）/喂了某食物——与喂主人字幕同款显示）；②喂主人蜂蜜瓶修复：手持分支旧版先把蜂蜜消耗成空瓶再喂（空瓶无食物属性喂不进→蜂蜜凭空消失且无效果），改为复制一份喂、成功才消耗；③普通饮用型药水传递补绿色系统字幕（传递功能一直在但只有气泡提示，观感像没给——现在「女仆给了你一瓶治疗药水（在背包里，快喝）」）；④音效补齐：喂金苹果（主/姐妹链）、喂姐妹牛奶旧版静默无声，现在都有对应吃/喝音效；实测三十一调整——插火把间隔减半：插火把冷却 30 tick（1.5 秒）→ 15 tick（0.75 秒），照明跟上走路节奏；实测三十调整——伐木树叶清理口径改小：删除砍完树干后整冠 BFS 清除树叶的 clearTreeTop，树叶清理只保留【以女仆为中心 3×3×3】的随行破坏——女仆走动经过树冠逐层清叶，每块树叶破坏时各自播破坏音效+粒子特效（levelEvent 2001，同玩家挖方块）+ 摆臂动画，不再是静默瞬清；树苗补种补齐反馈与诊断：种下时播种下音效/粒子，跳过原因（背包没树苗/找不到可种地面）和种下成功都记日志（latest.log 搜 wood sapling）；实测二十九修复——搭路/方块回收间歇性失效根治：搭方块追踪表（内存 PLACED）只在正常退出时清场（ServerStopping），崩溃/任务管理器强杀进程后残留进新会话——①回收失效：残留的放置 tick 是旧会话 gameTime，新会话时间更小，「放置时间+寿命」判定永不过期，垫脚方块从此不回收；②搭路失效：残留位置命中脚下时 isAirborne 误判为空中，行为状态混乱；③BRIDGING 标记持久化在存档里，崩溃时没走到清理代码 → 重进后女仆永久背着「搭路中」（禁瞬移）。现兜底：每次服务端启动（ServerStartedEvent）清空全部搭方块追踪表 + 全量清除女仆 BRIDGING 标记（此刻任何女仆都不可能在搭路，清理零误伤）；另加诊断日志（latest.log 搜 bridge-up：启动记 owner-dy，中止记原因 reached/threat/no-block/head-blocked/task-occupied/owner-too-far 等，间歇性失效可精确定位）；实测二十八修复——主动切换战斗「主人主动开火」触发从未生效：旧版判定把受害者当成攻击者（getEntity=被打的人 instanceof ServerPlayer、又要求来源也是同一玩家——主人打怪时受害者是怪物，条件永远不成立，只有玩家互打才触发）；现改为【来源】是玩家即触发（受害者不限、打自己女仆除外）。被动挨打分支（主人被打→女仆参战）逻辑本来就正确。另加限频诊断日志（latest.log 搜 auto-combat：记录每次切换 女仆名 原任务→战斗任务，触发但零切换也记一笔）；实测二十七修复——挖矿「软方块不耗耐久」默认值改回开启（代码默认本就是 true，但注释与面板描述写着"默认关"系历史遗留；现存档配置文件里已是 false 的会被本次部署同步改回 true——与伐木行为一致，软方块开路不磨损工具）；实测二十六新增——排班表物品进创造物品栏「工具与实用品」标签页（与蓝图卷轴同页，可直接拿取；拿出的即带附魔流光）；实测二十五修复——全部界面翻页按钮改 20 像素宽纯箭头 ◀/▶（旧版 80~100 像素宽的"上一页/下一页"按钮在五个界面里都存在遮挡正文/图标的问题：排班表盖女仆行、手册盖正文末行、配置面板盖注释末行、矿表/替代品表盖网格底部图标、蓝图手册盖建筑名/材料行/女仆行/区块行/记忆行/调试行、文件选择器盖底行文件名；现在按钮只保留箭头符号、去掉了"上一页/下一页"文字，页码文字统一画在左右两枚箭头的正中间同一行——像素级计算：箭头各占 20px 分布在中心线两侧 ±20~±40px，页码居中不与箭头矩形相交，任何分辨率/GUI 缩放下不再遮挡文本）；实测二十三修复——岩浆格视作硬阻挡；实测十四新增——攻击任务接口化统一判定（主动切换战斗的让位检测升级：不再只按固定 UID 名单认战斗任务，改为直接问当前任务【是否实现 TLM 的 IAttackTask 接口】——万法皆通/史诗战斗等第三方模组给女仆注册的攻击任务一并识别：①主人被攻击时她们本来就在攻击任务上，绝不会被强切回原版近战/弓模式（尊重玩家手动安排的第三方攻击任务）；②副手盾牌自动装备、干活不被打断闸门（吃饭/偷吃/恐慌/切班拉回）全系列同口径覆盖第三方攻击任务；UID 名单保留为兜底）随 promaid-1.1.0.jar 部署，重启游戏生效。
promaid V1.0.4：挖矿体验大改 + 透视感知开关 + 矿表 UI 重构——(1)【透视感知（默认关）】女仆不再隔墙透视挖矿：关闭时像玩家一样只能发现视线无阻的矿物——除水/岩浆外任何方块（泥土/石头/玻璃/半砖等）都挡视线，被挡的矿不可见、不报点，也不会隔墙挖穿（已锁定目标同样持续检查视线）；开启后恢复隔墙找矿并挖穿开路（等同旧版逻辑）；(2)【矿表赋值交互重构】点方块图标锁定（黄框固定，鼠标移开不消失）→ 输入框出现 → 输优先级数值点「添加」/回车即赋值/加入（留空直接点添加/回车 = 默认价值 300）；悬停图标显示中文名/英文 id/绿色当前优先级；已加入矿物右上角 × 取消添加；列表条目显示中文名 + 价值输入框 + 标准删除按钮；(3)【UI 修复】矿表/替代品列表滚动条不再是一根突兀的亮色竖线（低调样式）；悬停提示移到网格右侧空白不再与图标重叠；障碍物输入校验方块真实存在；矿表网格每页 24→48 个（翻页数减半）；(4)【死 UI 清理】删除 4 个无效果配置项（主动会话记忆话题/防窒息传送冷却/恢复缓存保留/沉默阈值）；播报间隔、女仆管理上限两个原本硬编码的配置恢复生效；(5)【建造加固】建造中女仆每 tick 锁定移动——玩家解除坐下后也不会"坐着走动"；(6)【手册】挖矿章节更新为新交互说明，修正首页板块等过时描述；(7)【内置蓝图】移除授权不明的内置预制建筑（大型 snbt），内置蓝图仅保留 81 套授权玩家蓝图包，旧版自动复制的预制残留一并清理。随 promaid-1.0.4.jar 部署，重启游戏生效。
promaid 1.5.385：材料经济链审计修复——自动转交材料不再吞物品——(1)【物品丢失修复】transferFromPlayer（玩家背包→女仆背包的蓝图材料转交）：女仆背包放不下时，旧版把未插入的 left 部分计入 back 公式，但 whole.split(back) 最多只能分出 whole 剩余数量——放不下的物品凭空消失（注释声称"放不下的留在玩家原处"实际没有）。改为：剩余放回玩家原槽，放不下的还回玩家背包（PlayerMainInvWrapper），背包也满则掉落身侧；(2)【复核通过】consumeBlock 精确/等价族/自定义替代三级消耗逻辑与创造性模式豁免正确，water=无限/岩浆=消耗桶+空桶归还闭环；extractExact/returnEmptyBucket/deliverToMaid 计数正确；等价族计数（countMaterial/combinedHaveAll）一致。随 Promaid-1.0.12.jar 部署（备份 .bak_v1384），重启游戏生效。
promaid 1.5.384：深审补漏——导入文件名清洗——(1)【纵深防御】importBuildFile/importWorldFile 的目标文件名来自客户端可控路径，旧版直接 new File(blueprints目录, 原名)——含路径分隔符/.. 的恶意文件名可逃逸 blueprints 目录（服务器端已有 OP 门槛，此处再加一层：拒绝含 / \ .. 或纯 . 的文件名）；(2)【复核通过】SRG NBT 方法名全库扫描（m_128441_=containsKey 事故模式无复发，6 处全部正确）；语音包导入目录遍历与 zip 分支均有 startsWith 归一化防穿越+扩展名过滤；BlueprintLib 缓存失效全覆盖（文件变化按条目清除/扫描清残留/重启全清）；parseStep/parseJson/validate 边界完整；双 agent 提取（v1.1.0）完成结算正确（remaining 防双重递减、水位线双完成后推进、EXTRACTING 超时自愈）。随 Promaid-1.0.12.jar 部署（备份 .bak_v1383），重启游戏生效。
promaid 1.5.383：全面审计修复（安全/稳定性/泄漏/性能）——(1)【安全S1】语音包/世界地图/建筑三个导入包在联机服务器上改为仅 OP 可用：旧版任意玩家可发任意绝对路径让服务端读文件（单机同机无感，服务器是文件读取漏洞）；蓝图删除包同样加 OP 门槛（防任意玩家删他人蓝图）；记忆状态查询包补主人/OP 校验；(2)【稳定性S2】记忆日记生成的 LLM 响应解析异常（偶发坏 JSON）不再静默丢边界——挂入 pending 自动重试；(3)【M1孤儿票据】无绑定女仆超 10 分钟的建造计划自动取消（已建方块保留可续建）——防女仆全消失后 FORCED 区块票据与区块冻结永久驻留拖垮服务器；每 5 分钟自检一次；(4)【M3数据安全】女仆实体卸载/换维度时立即落盘记忆（旧版 WeakHashMap 键被 GC 时最多丢 20 秒窗口内的写入）；(5)【M4泄漏】实体卸载时清理挖矿行为 10 张状态表与感知危险缓存（长会话泄漏）；(6)【性能】归档器状态内存缓存（消除每 20 秒/女仆的磁盘读）；日记覆盖判定（登出部分天被完整天覆盖不再重复生成）；判空轻量化（不再拼整块事件字符串）；文件对话框线程改 daemon。随 Promaid-1.0.12.jar 部署（备份 .bak_v1382），重启游戏生效。
promaid 1.5.382：手册与配置界面跟进记忆系统——(1)【配置面板】AI 记忆段新增「多级记忆索引」配置组：多级记忆索引 / 睡一觉自动处理 / 登出会话收尾 / 月索引保留事件数 / 单次索引事件上限 / 短期→长期阈值（游戏日）六项，带说明悬浮提示；(2)【手册·女仆记忆页】新增「记忆日记」段（日/3日/周/月日记式摘要，显示篇数与最新 6 篇的级别/天数跨度/内容预览；暂无时提示"睡一觉后自动整理生成"）；记忆条目新增【长期】标记（long_term 沉淀记忆，与【永久】并列显示）；(3)【手册·AI 记忆系统章】新增"记忆日记"与"睡一觉自动整理"两段说明（含熬夜不整理、服务器登出收尾的语义）；AI 工具清单新增 query_memory_index；(4)【TLM 女仆配置面板】记忆区新增"记忆日记：N 篇（最新X记 第A~B天）"状态行，记忆条目前缀【长期】标记。随 Promaid-1.0.12.jar 部署（备份 .bak_v1381），重启游戏生效。
promaid 1.5.381：会话收尾按服务器/单机区分——(1)【单机集成服】玩家退出即关服、剧情时间停滞，登出收尾无意义（记忆原地不动，下次游戏内睡眠收尾会以"完整一天"的日级索引自然覆盖），登出处理器直接跳过，也不再写 pending——避免在关服竞态里抢跑；(2)【服务器】剧情时间持续推进，玩家登出后世界照常运转——保留登出收尾（当日日记先持久化 pending 再生成，下次进游戏由周期 tick 自愈补完成）。判定方式：MinecraftServer instanceof DedicatedServer。随 Promaid-1.0.12.jar 部署（备份 .bak_v1380），重启游戏生效。
promaid 1.5.380：会话收尾归档——补齐 Sphantosis 睡眠语义的【真人玩家】维度——(1)【背景】原项目是面向真人玩家的 AI 聊天记忆系统，wrap-up 收尾同时覆盖"角色入睡"与"真人玩家结束一天下线睡觉"（WorldManager 有状态机 active/sleeping/offline、角色作息表）；v1.5.379 只映射了游戏内睡眠维度，漏掉了真人维度。(2)【登出收尾】玩家登出（PlayerLoggedOutEvent，周围128格女仆）= 真人睡觉/结束一天：当日（部分天）「日」级日记边界【先持久化进 pending 再尝试生成】——单人模式关服后异步 LLM 响应可能丢失，pending 已落盘，下次进游戏由周期 tick 自动补生成（"女仆在你睡觉时整理好了昨天的记忆"），并复用睡眠收尾的边界检查与短期→长期提升；(3)【pending 语义加固】出队条件从"异步请求已发出"改为"has() 确认已归档（或跨度无事件）"——在途丢失自愈，不再静默丢边界；(4)【配置】新增 memory.indexOnLogout（默认开）。随 Promaid-1.0.12.jar 部署（备份 .bak_v1379），重启游戏生效。
promaid 1.5.379：记忆移植架构修订——熬夜排除 + 移除伪图聚簇 + 索引上下文长度管理——(1)【熬夜排除】归档触发从 PlayerWakeUpEvent 改为 SleepFinishedTimeEvent（全员真实睡过夜、时间跳到清晨才触发的服务端事件），并移除周期调度的跨日生成兜底（周期 tick 退化为纯 pending 重试）——白天躺床即起/入睡失败不误触发，熬夜过夜不再归档，「睡一觉自动处理」名副其实；多日未睡的日级空档不回填，由 3日/周/月 粗粒度层级自然覆盖；(2)【移除伪图聚簇】v1.5.378 的短期→长期转移用 ngram-Jaccard≥0.42 并查集伪聚类近似 Sphantosis 的图连通分量——但 promaid 段落是扁平线性列表（无 LLM 建立的语义边、单一存储），连通性检查无对应物，且 O(n²) 每 20 秒常驻是负优化。改为线性架构匹配的 O(n) 单遍规则：short_context 段落年龄≥shortTermDays 游戏日 且 重要度≥decaySalience → 打 long_term 标记（豁免衰减遗忘），仅在睡眠收尾时执行；(3)【上下文长度管理】新增配置 memory.indexMaxEvents（默认40）：所有级别索引的事件块超限按重要度裁剪后再按时间排序（月级另受 indexMonthTopN≈20 更紧约束），忙日不会撑爆摘要 prompt；prompt 同步注明事件可能已截取。随 Promaid-1.0.12.jar 部署（备份 .bak_v1378），重启游戏生效。
promaid 1.5.378：移植 Sphantosis 记忆系统——快速记忆索引 + 睡一觉自动归档（experimental/memory-port 分支）——(1)【跳表时间索引】自研跳表（游戏tick→段落hash，O(log n) 范围查询）取代全量线性扫描，索引生成/按时间检索记忆提速；(2)【多级记忆索引】日/3日/周/月四级日记式摘要（LLM 第一人称日记，跨度越大压缩越高，月级仅保留重要度 top20），跨游戏日/周(7日)/月(30日)边界自动生成，永久归档 memory_index.jsonl，失败不静默挂 pending 队列下个 tick 重试；(3)【睡一觉自动处理】玩家睡醒(PlayerWakeUpEvent)→周围128格内女仆强制归档：生成当日「日」级日记 + 短期→长期簇转移（对齐 Sphantosis start_role_sleep→wrap-up→tick(force_day_index=True) 链路）；周期调度兜底跨日（不睡过夜也归档）；(4)【短期→长期转移】short_context 层段落按 ngram-Jaccard≥0.42 聚簇，簇内全部段落年龄超过 shortTermDays(默认3)游戏日才整簇打 long_term 标记（豁免衰减遗忘，不拆散关联事件簇）；(5)【检索接入】query_memory 召回新增第5路（索引日记命中整段召回）；新工具 query_memory_index（先列可用跨度再查日记+关键事件原文，前缀和式缩小范围）；对话投影新增「记忆日记」段（最近2条日级日记）。配置新增 memory.indexEnable/indexOnSleep/indexMonthTopN/shortTermDays。随 Promaid-1.0.12.jar 部署（备份 .bak_v1377），重启游戏生效。
promaid 1.5.377：全面审计修复——死亡传送图腾校验时序 + 女仆追踪表清理——(1)【图腾校验时序】MasterDeathTeleportHandler 的死亡登记后校验(v1.5.329 加的图腾防误判)注释说延迟 1 tick,实际在【同一服务端 tick 的 END】就执行——死亡发生在 tick T 的实体阶段,同 tick 末立刻查血量,modded 图腾(charmofundying 等)若在 T+1 才复活仍会误传(女仆被传去重生点)。改为记录登记 tick,严格满 ≥1 tick 才校验执行(与 heartfelt 死亡调侃真死核验同款时序);(2)【追踪表清理】女仆追踪表(死亡传送对未加载女仆定位用)对【永久移除】(死亡/解雇/魂符收纳)的女仆条目永不清理——主人每次死亡都要白白强制加载一次死亡女仆遗照坐标的区块。现在实体永久移除时删条目(区块卸载仍保留坐标待用),强制加载后找不到实体也删。随 Promaid-1.0.12.jar 部署,重启游戏生效。
promaid 1.5.376：建造目录搜索框套用原版物品搜索栏样式——搜索框默认是"带边框+深色字"，在深色面板上几乎看不清，输入看起来"没反应/延迟"；改为原版 CreativeModeInventoryScreen 物品搜索栏同款：无边框（setBordered(false)）+ 白字（setTextColor(白)），提示语保留。字节码实证方法名 m_94182_=setBordered、m_94202_=setTextColor。随 Promaid-1.0.12.jar 部署（备份 .bak_v1376），重启游戏生效。
promaid 1.5.375：手册打开卡死修复——启动预热缓存全覆盖——(1)【根因】旧版 warmupNeedsCache 只在服务端启动预热了材料需求（countNeeds），但手册打开时 buildCatalogEntries 对每个外部蓝图调 describe（摘要）、openFor/目录请求对每个调 blueprintSize（占地尺寸）——这两项【没预热、没缓存】，8000+ 蓝图 × 各自遍历全部步骤（一次约 6400 万次坐标解析）= 首次打开手册主线程卡死几十秒；(2)【修复】①新增 SIZE_CACHE（id → 占地尺寸）+ blueprintSizeCached 缓存方法；②warmupNeedsCache 扩展为预热 describe + blueprintSizeCached（外部 + 内置全量）——把"手册打开时的遍历"提前到服务端启动（读世界阶段，玩家看不到）；③openFor / 目录请求改用 blueprintSizeCached；(3)【缓存失效】文件变化/删除/重启时同步清 SIZE_CACHE（与 DESCRIBE_CACHE/NEEDS_CACHE 一致）。效果：服务端启动多花十几~几十秒做一次性预热（读世界阶段），之后手册打开纯读缓存、秒开。随 Promaid-1.0.12.jar 部署（备份 .bak_v1375），重启游戏生效。
promaid 1.5.374：建造目录改革——搜索框 + 网格多列分页——(1)【搜索框】目录页顶部加搜索框，按建筑名/蓝图 id 实时过滤（大小写不敏感），搜索时不重建按钮、不打断中文输入法（条目改为渲染 + 坐标点击，搜索框只建一次）；(2)【每页数量】目录从"一列通栏按钮"改为【网格多列】（宽窗口 3 列、窄窗口 2 列，行高 16），每页显示数量约为原来的 3~6 倍；(3)【页码】目录底部显示"第 X/Y 页"；(4) 删除按钮（外部蓝图 ）保留在网格格内右侧。随 Promaid-1.0.12.jar 部署（备份 .bak_v1374），重启游戏生效。
promaid 1.5.373：玩家导入的地图放建造目录第 1 页 + 清理超限导入文件——(1)【目录顺序】buildCatalogEntries 调换顺序：外部/玩家导入的蓝图（maid_smart_ext:*）先入目录（按名排序），内置预设后入——玩家自己导入的地图在第 1 页就能看到，不再被 25 套内置小屋/农场挤到最后一页；(2)【清理】删除 33 个超方块上限的导入文件（3 个超绝对上限 419 万：星系城堡/春天城堡/法国马赛市体育场 + 30 个超默认 100 万上限，如罗马斗兽场/足球场1/迪拜金字塔等）——原文件仍在桌面「投影文件完整版(8511文件)」，需要可随时重导。随 Promaid-1.0.12.jar 部署（备份 .bak_v1373），重启游戏生效。
promaid 1.5.372：养鸡场重排——发射器不再压在漏斗下面——旧版把承接漏斗叠在发射器正上方往下灌，发射器被压在最底、且顶部平台偏高；重排为视频同款：投蛋发射器嵌在鸡舍南墙，进料漏斗在发射器【正后方、同层】横向指进发射器后背（"放一个指向它的漏斗"），上方再一个漏斗承接、9 漏斗平台架在 y=2 石砖基座上（平台更矮一层）。鸡蛋流向：平台→中心漏斗→上层漏斗→进料漏斗→发射器→射进鸡舍。随 Promaid-1.0.12.jar 部署（备份 .bak_v1372），重启游戏生效。
promaid 1.5.371：修复方块/物品朝向全部丢失——机器都用不了的根因——(1)【根因】doPlace 走 BlueprintLib.parseStepState 把步骤里的状态串（如 {facing:"south",lit:"false"}）转成 BlockState：旧版用 NbtUtils.snbtToTag 解析后只补了 Name，却没把 facing/half/shape 等属性包进 Properties 子标签——NbtUtils.readBlockState(m_247651_) 只读 Properties（javap 实证），顶层属性全被无视 → 所有带状态的方块一律回落默认态（朝向全朝北/朝下）：漏斗指向错误→熔炉组不投料不输出、发射器朝错方向→作物/树/鸡场全废、活塞/比较器/拉杆朝错→机器不动作；(2)【修复】parseStepState 在无 Name 时把 Name 之外的全部属性收集进 Properties 子标签再交给 readBlockState——所有内置（门/床/楼梯/火把/熔炉/农场机器）与 JSON/LLM 生成的带朝向方块现在正确落位朝向；(3) 附带：门此前"落地朝外"只修了位置，朝向同样受此 bug 影响，一并修复。随 Promaid-1.0.12.jar 部署（备份 .bak_v1371），重启游戏生效。
promaid 1.5.370：6 座农场正式接入"机器专属搭建顺序" + 完工使用说明 + 导入小蛋挞01（已授权）——(1)【搭建顺序】machineFamily() 为 6 座内置农场（farm_cactus/farm_superfurnace/farm_lavafountain/farm_crop/farm_tree/farm_chicken）+ 自动熔炉组（machine_furnace_array）登记机器家族 → 自动走 sortMachinePlan 六层相位（结构→惰性机构→活动件→传感件→动力源），动力源（红石粉/火把/拉杆）最后落地，避免半网通电误触（活塞乱推/发射器乱喷），v1.5.369 已建的农场从此建得更稳；(2)【完工说明】machineFinishTip 新增 7 条中文使用说明（仙人掌塔/超级熔炉/岩浆泉/作物/伐木场/养鸡场/自动熔炉组），建造完成的系统消息自动附带对应用法；(3)【手册】「红石机器」段落改为「机械类蓝图搭建顺序 + 各机械用法」七条（v1.5.300 旧文"只剩自动熔炉组"已过时同步替换）；(4)【导入】外部蓝图 小蛋挞01.litematic（82×96×34、约 2.2 万方块，体积 26.7 万，均在限内）已导入并重命名 小蛋挞01（已授权）.litematic。随 Promaid-1.0.12.jar 部署（备份 .bak_v1370），重启游戏生效。
promaid 1.5.369：新增 6 座生存农场蓝图——实现：语音转写 + 视觉逐帧还原视频方块布局后，全新设计 6 座农场并入内置目录（总数 19 → 25）：①仙人掌塔农场（farm_cactus）——11×11 石砖围墙两层塔，沙环+仙人掌+断顶环(离地 3 格碰碎第 3 格)+四角水流冲进正中 3×3 收集井(漏斗→箱,梯子下井)，无红石全自动；②超级熔炉组（farm_superfurnace）——6 熔炉一字排开，纯漏斗定向(输入箱→熔炉顶/燃料箱→熔炉背面/熔炉底→输出箱)，无红石 100% 可靠（原视频用漏斗矿车——实体女仆无法放置，改纯漏斗）；③无限岩浆泉（farm_lavafountain）——5 口炼药锅+滴水石锥悬锅上+石砖平台盛岩浆+台阶封顶防刷怪，随时间自动满锅；④高效作物农场（farm_crop）——中央耕地+水坑+前/右/后 3 发射器贴耕地+拉杆→红石粉网→三发射器骨粉齐射（半自动，比原视频 0-tick 观察者时钟在女仆建造环境下可靠；边按住种子右键边拨拉杆即可持续催熟）；⑤自动伐木场（farm_tree）——骨粉发射器朝树苗+拉杆开关+7 粘性活塞塔(朝南)+红石楼梯(zigzag 同时激活)+比较器脉冲+原木收集漏斗（仿视频布局，红石细节以视频为准）；⑥全自动养鸡场（farm_chicken）——鸡在顶部 3×3 九漏斗平台下蛋→漏斗链进发射器→拉杆向 3×2 鸡舍投蛋→小鸡孵出长大→玩家透过半砖缝隙击杀取肉+经验，鸡舍地板 5 漏斗收进中央箱。材料均 1.20.1 生存可得（滴水石锥/炼药锅 1.17+、无铜傀儡等超版本物品）。随 Promaid-1.0.12.jar 部署（备份 .bak_v1369），重启游戏生效。
promaid 1.5.368：内置建筑大改版——删雷同 + 修门 + 新增 12 种不同结构——(1)【门摆放根因修复】door() 辅助的调用方传参 bug：smallHouse/villa 里 `door(doorX, y0, 0, ...)` 把门中心当墙原点传，door() 内部再 `x + doorX` → 门被放到 x=2×doorX = 屋外一格（渲染实证：前视图门洞在 x=10、屋子只有 0..9）——全部内置小屋/别墅的门一直"不在正面墙上"；修复：改传墙原点 0（`door(0, y0, 0, ...)`）；(2)【删雷同】旧 15 小屋全是 smallHouse 同款盒（10×12×3 仅材质不同）、旧 10 别墅全是 villa 同款盒（14×16 三层仅材质不同）——删 12 小屋 + 7 别墅，保留材质风明显的 3 小屋（原木/雪原/沙漠）+ 3 别墅（石质山景/现代玻璃/陶瓦地中海）；(3)【新增 12 种不同结构建筑】A字架小屋（三角截面斜墙）、瞭望塔（空心塔+垛口+梯子）、灯塔（圆塔红白条纹+海晶灯灯室）、庭院屋（外墙环抱露天中庭）、谷仓（高双坡大空间+双开大门）、高脚小屋（柱上架空+梯子）、风车（圆塔锥顶+十字木翼+磨坊附间）、半地堡屋（厚墙+下沉坡道+天窗）、树屋（粗树干+平台小屋）、坡地阶梯屋（三级阶梯平台）、双子屋（两屋+连廊+前院）、城堡门楼（双塔夹门楼+垛口）——全部方块 500~5000（独立编译验证：各 531~2139 块），生存易得材料、家具齐备、无红石无液体；(4) 内置总数 26 → 19（指南/注释同步），手册目录即见新建筑。随 Promaid-1.0.12.jar 部署（备份 .bak_v1368），重启游戏生效。
promaid 1.5.367：heartfelt_connection 软联动——promaid 手册/配置面板新增「heartfelt 联动」页——实现：PromaidConfigScreen 新增 Section.HEARTFELT（左列按钮，ModList.isLoaded("heartfelt_connection") 门控——未安装不显示，与爱憎分明页同款）；页面分三组实时读写该模组配置（反射 HeartfeltConfig 字段，改完即生效、重启不丢）：①告白——玩家告白方向修正/女仆告白前摇开关、尝试间隔、所需好感、基础概率、失败心情惩罚、前摇最短等待/超时/走向速度；②女儿/成长——成长事件、父女互动；③伤心窗口——窗口时长、心情惩罚。随 Promaid-1.0.12.jar 重新部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.366：女儿对话选项专属文本池——实现：①新客户端 mixin HugDialogueDaughterFrameMixin 拦截 HugDialogueRuntimeBridge.currentFrame()（对话帧唯一出口,反编译实证其内部调 HugDialogueStageFlavorComposer.apply;帧含 nodeId/speaker/text）——当前交互女仆是女儿(ClientOnlyState 从成人 HugClientState/儿童 ChildInteractionClientState 双查 UUID)时,按 阶段×选项分类 替换【女仆台词】(speaker=女仆名,旁白/玩家提示/选项标题不动,不破坏界面):成年女儿(hug_menu 4 选项)聊天/讨好/讲笑话/摇曲柄/摸头;幼儿/少女(儿童场景)摸头/举高高/让妈妈抱抱/陪她说话;原版普通女仆文本在女儿身上永不触发。②PromptTexts.daughterOptionText 新增 3 阶段专属文本池（幼儿/少女/成年 各选项 4 条,按天轮换,扩充文本量）。随 heartfelt_connection-1.5.94.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.365：告白失败(缓一缓)对记忆/情绪零影响——根因(剧本实证)：maidmarriage 告白剧本的接受选项("我也喜欢你"=confession_accept)带服务端事件 story_confession_accept(完成告白),而拒绝选项("……先让我缓缓"=confession_reject)【没有任何服务端动作】——heartfelt 的永久记忆(CONFESSION_FAILED/CONFESSION_FAILED_AT)只有调整器手动标记才会写,真实拒绝路径完全没接。修复：①新 C2S ConfessionRejectPacket——客户端 PlayerConfessionEntryMixin 拦截 choose("confession_reject") 时发送；②服务端 MaidConfessionManager.handleConfessionRejected：写永久记忆 CONFESSION_FAILED+时间戳(她之后不再主动告白——isEligible 门；AI 记忆 MEMORY_CONFESSION_FAILED 与后果文本 AftermathPrompt 生效)+ 心情惩罚(CONFESSION_FAIL_MOOD)+ 系统消息(confessionRejected)。随 heartfelt_connection-1.5.93.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.365：村民机水闸活板门无法放置→机器不工作——(1)【根因】村民繁殖与交易一体机蓝图（BY：黑山大叔）把【顶部活板门直接设计在水上方】（探针实证：y=5 的 6 个活板门 half=top、上方 y=6 就是水；原版 TrapDoorBlock.canSurvive 要求上方实心，水不合法 → 正常手段放不上，蓝图作者用工具强放）；建造支撑逻辑要么【无限延后】等"水支撑建好"（水永远不会是合法支撑），要么 3 次后 force【把水换成石头】再放——水闸的水被替换/活板门缺失 → 机器水运/水闸机制毁掉 → "无法工作"；(2)【修复】新增 BlueprintLib.isFluidStepAt（蓝图指定位置是否为水/岩浆步骤，仅在支撑格已是流体且计划含该格时调用，O(N) 可接受）；doPlace 支撑检查：支撑格是流体且蓝图该格就是流体步骤 → 【直接放置附着块，不替换流体、不延后】（javap 实证 TrapDoorBlock.neighborChanged 只切换开合状态不自毁——强放后即使上方是水也稳定存在；水保持原位，机器水闸完整）；bad 校验对流体支撑块跳过 canSurvive 判定（粘住即成功，没粘住延后不替换流体）；(3) 注：矿车自动放置为【轰炸机家族专属】（v1.5.320 设计，完工提示已说明）——天机屠龙炮（never4get）手动触发、村民机（villager）无需矿车，均不自动放矿车，属预期行为。随 Promaid-1.0.12.jar 部署（备份 .bak_v1365），重启游戏生效。
promaid 1.5.364：女仆主动告白"准备文本→走向主人"衔接不稳定——根因：工作任务（建造/烹饪/酿造）每 tick 清 WALK_TARGET，且 promaid 站桩锁（isStill = WORK_STILL_TAG + 工作任务）会取消 MoveToTargetSink——正在干活的女仆（如建造中的妻子）告白前摇的走向目标被稳定打断，有时走、有时不走。修复：ConfessionApproachManager.startApproach 启动前摇时【切到待机任务】（TLM TaskManager.getIdleTask，记录原任务）——WALK_TARGET 独占、站桩锁自动失效（isStill 需工作任务）；会话结束（到达跳转告白/取消：死亡/离线/超时/威胁）时【恢复原任务】。随 heartfelt_connection-1.5.92.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.363：女仆主动告白跳过前文直接到选项——根因：jumpToMaidMarriageConfession 的断点续播用 HugStoryResumeState.remember(... "confession_accept_choice") 直达【选项节点】，整段告白前文（confession_intro 女仆的告白台词"那个……主人……我有话要对你说！"）被跳过——老代码设计如此。修复：续播节点改为 confession_intro——女仆主动告白从告白前文开始，完整流程（前文 → 开口选项 → 分支 → 接受）正常播放。附带修正：1.5.362 加的 jumpToNode 拦截过宽（会误劫女仆主动告白的 confession_* 续播，把合法流程换成玩家告白屏）——已移除，玩家告白拦截保留 choose + 女仆名兜底。随 heartfelt_connection-1.5.91.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.362：玩家告白拦截加固——根因：PlayerConfessionEntryMixin （玩家告白方向修正）在运行时可能落空——HugClientState.tick() 在女仆实体瞬时不在客户端世界时（hasEntityWithUuid false）会【清空交互状态】，getLocalInteractionMaidUuid() 返回 null → 拦截失败 → maidmarriage 原版 confession_intro 剧本照播（女仆向玩家告白，方向反了——"为什么是这样的文本"），且它的对话渲染偏左（"显示偏左，超出屏幕应移至中央"）。加固：①choose 拦截时 UUID 找不到 → 按女仆名兜底（bridge.maidNameSupplier，64 格内同名女仆）；②新增第二道防线——jumpToNode 跳入 confession_* 节点时同样拦截打开 heartfelt 告白屏（choose 拦截失败的剧本推进也被拦下，女仆告白文本永不触发）。随 heartfelt_connection-1.5.90.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.361：AI 调用心契工具 hug 仍然失败——定位（debug 日志实证）：LLM 已成功调用 smart_intimate({"action":"hug"})，但拥抱没发生。反编译 MaidHugManager 找到根因：工具调用的 handleHugPoseToggle(player, maidId) 转发到 3 参版，而 3 参版【第一行 PLAYER_TO_SESSION.get(player)】——玩家不在交互会话（没开 Alt+J 面板）时【静默 return】，拥抱什么都不做。kiss/lap/pet 各有独立流程不依赖 HugManager 会话（反编译确认），唯独 hug 需要。修复：①MaidMarriageCompat.ensureInteraction(player, maid)——女仆不在会话时先用 handleInteractionToggle 开启交互（内部全套校验：主人/儿童/坐姿/骑乘/距离，坐姿由 MixinInteractionSittingAllow 预站起； 已在会话则不动——handleInteractionToggle 是开关，再调会变停止）；②SmartIntimateTool hug(start) 执行前 先 ensureInteraction。随 heartfelt_connection-1.5.89.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.360：穿婚纱自动变 TLM 花嫁酒狐模型——实现：新增 WeddingDressModelManager，每 10 tick 扫描主人 48 格内女仆的胸甲槽（判定与 maidmarriage 自己的对话变量一致——反编译实证 HugDialogueContextVariables 用 getItemBySlot(CHEST).is(maidmarriage:wedding_dress) 判定 maid_wearing_wedding_dress）；穿着婚纱 → maid.setModelId("geckolib:winefox_wedding")（TLM 内置模型包 maid_model.json 实证的花嫁酒狐 model_id，实体数据同步客户端即时生效）；脱下婚纱 → 还原原模型（切换前把原模型 ID 存入女仆 persistentData heartfelt_original_model，重启不丢）。随 heartfelt_connection-1.5.88.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.359：婴儿剧本对话全量替换——定位：ChildGiftTextMixin（拦截 DialogueScriptManager.componentForMaid 文本汇聚点，日志实证已注入运行）对幼女(INFANT/JUVENILE,isTooSmall)已替换多数剧本键，但 daughterDialogueText 对【未覆盖的键】返回 null → 放行 maidmarriage 原版文本——成人送礼键 dialogue.maidmarriage.gift.*、pet_head 成人键、"陪她说话"等其他一切未列出的对话键全部漏网，婴儿仍会播正常台词。修复：①daughterDialogueText 全量兜底——tooSmall 时所有未覆盖的剧本键一律替换为婴儿旁白（无台词动作描写，按对话类型分池按天轮换：送礼"她好奇地抱着礼物看了又看…"/其他"她睁着圆溜溜的眼睛看着你，咿咿呀呀地挥着小手…"），原版文本完全不触发；已有的专属分支（child_gift/摸头/抱抱/思慕等）保留更贴合的文本；妈妈台词(carry_child.infant_hold.*)仍不拦。②新增旁白池时曾加的 RomanceSleepManager.speakSingleLine 冗余 mixin 已删除（componentForMaid 汇聚点已全覆盖，不需要第二层）。随 heartfelt_connection-1.5.87.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.358："摇摇晃晃地站起来"系统提示改革——根因：该消息挂在 checkChildGrowth 的 CHILD_STAGE 标签判定上（stored != stage 即触发），而 maidmarriage 每 tick 按 growthTicks+persistent 重写 ChildStateData 阶段——标签与实际阶段错位（标签陈旧/阶段数据震荡）时，消息就在错误时机误发，看起来"随机触发"。改革：站起动作与"站起来"系统提示统一移到 ChildGuardManager 的【可靠运行时检测】（lastStage Map 每 tick 对比实际阶段，只在真实 INFANT→JUVENILE 升级瞬间触发一次，v1.5.357 的机制）：同帧完成 站起 + 系统消息(会自己站起来了) + 幼儿旁白气泡(摇摇晃晃站起来) ——消息必然贴合"她刚刚真正站起来"的情境；checkChildGrowth 的 JUVENILE 分支只保留标签记录与站起保险，不再发消息（其余阶段 INFANT/CHILD/ADULT 的成长消息保持原样）。随 heartfelt_connection-1.5.86.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.357：幼儿站起方案修正——撤掉每 tick 强制站立——修正：①删除 v1.5.355 的幼儿每 tick 强制站立（本末倒置——幼儿从此无法自由坐/站）；②正确语义落地：强制坐下只约束婴儿（isInfant 判定天然对幼儿解除）；升级瞬间用【运行时阶段记录】（ChildGuardManager.lastStage Map，每 tick 记录上一阶段）检测 INFANT→JUVENILE 变化时站起一次（若还骑乘妈妈先 m_8127_() 放下，再 m_21837_(false)+m_20124_(STANDING)）——不依赖可能陈旧的 CHILD_STAGE 标签（陈旧标签会让 checkChildGrowth 跳过导致"消息有了但没站起来"），也不持续强制站立（升级后幼儿自由坐/站，与"婴儿幼儿唯一区别是能站起来"的模型一致）。随 heartfelt_connection-1.5.85.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.356：手册/配置面板里"LLM 调用次数限制(API 日配额)"设置找不到——排查结论：设置一直存在（MaidSmartConfig.DIALOGUE_API_DAILY_LIMIT，默认 40 次/天、0=不限；配置面板 对话提示 区），部署 jar 也确认包含；但它排在对话提示区第 5 行，窗口高度/GUI 缩放较小时被分页藏到第 2+ 页，看起来像"没了"（与 v1.5.293 自主决策、v1.5.295 主动对话同一类可见性问题）。修复：把 API 日配额行提到对话提示区【第一行】——任何窗口高度打开 对话提示 第一屏即可见。随 Promaid-1.0.12.jar 重新部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.355：幼儿"会自己站起来"消息有了但没实际站起来——根因：站起只有 checkChildGrowth 升级瞬间的一次性 m_21837_(false)，一旦被同 tick/后续任何按坐覆盖就失效；且静态排查发现多个可能按坐路径（婴儿强坐判定、伤心坐、哀悼坐、等妈妈坐等）。修复：ChildGuardManager 每 tick 对幼儿(JUVENILE,isTooSmall && !isInfant)【强制站立】（与婴儿强制坐下对称——完全贴合"婴儿幼儿唯一区别是能站起来"的模型），尊重已知"该坐"状态：伤心窗口(isHurtFeeling 赌气坐)/哀悼(isMourning)/等妈妈(WAITING_MOTHER)/心契交互(inChildInteraction 锁站姿)/被抱着(骑乘 m_20159_)；其余情况坐着即站起(m_21837_(false)+m_20124_(STANDING))。随 heartfelt_connection-1.5.84.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.354：幼儿束缚失效——调整器设阶段与 maidmarriage 重推导打架——根因（反编译 maidmarriage 2.3.0 实证）：MaidChildEntity.tickExternalChildLifecycle 每 tick 读 growthTicks 然后 resolveGrowthStageByTicks(ticks)【重新推导阶段】并写回 ChildStateData（覆盖存储的阶段字符串）。阈值：INFANT < 24000；JUVENILE < 24000+max(48000, adultAfter-24000)/2；CHILD < adultAfter（adultAfter = max(3, childGrowthDays)×24000，childGrowthDays 默认 10、可调 3~120）。而调试器 setStage 写死 growthTicks：幼儿=48000 在 childGrowthDays=3 时 ≥ childStage(48000) 被推导成 CHILD（幼儿变少女→ isTooSmall 假 → 语音/任务锁/手持限食物/拾取 ONLY_XP 全部失效）；少女=120000 在默认 10 天时 < childStage(132000) 被推导成 JUVENILE（少女变幼儿）。修复：新增 MaidMarriageCompat.stageTicksFor(stageName)，按 maidmarriage【实时 childGrowthDays 配置】复刻阈值并取各阶段区间中点——任何配置下都稳定落在目标阶段（婴儿=0、幼儿=24000+(childStage-24000)/2、少女=childStage+(adultAfter-childStage)/2、成年=adultAfter）；调整器四个阶段按钮改用 stageTicksFor。已误分类的档位需重新用调整器点一次对应阶段即恢复。随 heartfelt_connection-1.5.83.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.353：婴儿丢地武器主人捡不起来——按方案根治——根因：①v1.5.63 的 stripHand 给丢弃物品设 setPickUpDelay(1000000) 无限拾取延迟防女仆自捡循环，但原版 ItemEntity.playerTouch 先查拾取延迟——主人也被卡住（v1.5.75 的 ItemEntityPlayerPickupMixin 想清延迟，但误注册在 mixins.heartfelt.json 的 client 段——playerTouch 是服务端逻辑，客户端注册从不生效，一直没修好）。②按方案根治：TLM 拾取类型 PickType（反编译实证 EntityMaid 拾取逻辑先查 canPickItem 再捡 ItemEntity）——heartfelt 新增 enforcePickupXpOnly，把幼儿/婴儿（isTooSmall）的拾取类型【每 1 秒强制为 ONLY_XP】（canPickItem=false → 女仆从源头不拾取任何物品，丢→捡循环从源头断开），长大（CHILD 起）后还原静音前类型（纯内存 Map 记录）；stripHand 移除 1000000 无限拾取延迟——丢下的武器/杂物恢复正常拾取延迟，主人碰触即可拾起。同时删除失效的 ItemEntityPlayerPickupMixin（client 段、服务端不生效、已无必要）。随 heartfelt_connection-1.5.82.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.352：Alt+J 面板"进入一下就瞬间退出"修复——根因（反编译 maidmarriage 2.3.0 实证）：交互会话每 tick 的 isValidInteractionPair 含坐姿检查（isMaidInSittingPose → 会话失效 → stopInteraction → 面板瞬关）。两个"交互中把女仆按回坐下"的冲突源：①promaid tickBuildSit（建造任务强坐）的交互豁免只查成人管理器 MaidHugManager、漏了儿童管理器 ChildInteractionManager——建造中的女儿（儿童路径 Alt+J）交互时豁免不生效，每 tick 被强坐 → 会话立刻终止；②heartfelt ChildGuardManager 婴儿每 tick 强坐没有交互豁免，婴儿女儿交互同样被秒杀。修复：①promaid inMaidmarriageInteraction 改为双管理器检查（MaidHugManager + ChildInteractionManager）；②heartfelt 婴儿强坐增加 inChildInteraction 豁免（反射 ChildInteractionManager.getInteractionPlayer，交互中跳过强坐，交互结束恢复）。随 Promaid-1.0.12.jar + heartfelt_connection-1.5.81.jar 部署（deploy_latest.ps1 无备份），重启游戏生效。
promaid 1.5.351：审核整改二——①MixinMaidHugSittingAllow 重命名为 MixinInteractionSittingAllow（v1.5.344 起同时覆盖成人 MaidHugManager 与儿童 ChildInteractionManager 两个交互管理器，旧名已不准确；纯内部改名，行为不变）；②按玩家政策清理遗留：删除 C:\Users\Sketch\Desktop\.minecraft（229.8MB 死目录，非 PCL 运行目录）与工作区未实现的"红石机器改革"计划文档。随 Promaid-1.0.12.jar 部署（deploy_latest.ps1 无备份流程），重启游戏生效。
promaid 1.5.350：审核整改（heartfelt 1.5.80）——①mixins.heartfelt.json 去掉 UTF-8 BOM（源+部署一致，与 opt json/promaid json 风格统一；Mixin 的 Gson 此前容错没崩，属卫生问题）；②声音频率还原不再写死 1.0——v1.5.77 静音逻辑改为记录【静音前频率】、条件解除时还原原值（玩家在女仆配置 GUI 手动设的频率不再被覆盖，纯内存 Map 无额外字段）；③changelog 版本撞号重排：此前 1.5.345 出现两条（TNT 完工不炸膛 + 抱起回应），本次按部署时序重排为 1.5.344 Alt+J 儿童路径 / 1.5.345 TNT / 1.5.346 抱起回应 / 1.5.347 思慕 / 1.5.348 手册 bug / 1.5.349 坐姿缓降；④工作区清理临时脚本与提取目录、精简 mods 备份（每家族留最新 2 个）。随 heartfelt_connection-1.5.80.jar 与 Promaid-1.0.12.jar 部署（备份 .bak_v1580 / .bak_v1350），重启游戏生效。
promaid 1.5.349：坐姿女仆"一直坐着缓慢下落"修复——根因（源码实证）：SelfPreservationBehavior.m_6725_ （TLM 常驻 extra brain，每 tick 跑）的"坐下锁移动"（v1.5.212）在女仆坐姿且无环境危险时执行 m_20256_(Vec3.ZERO)【整速度清零】——坐着的女仆一往下掉，重力加速度刚积累就被抹掉，永远加不起下落速度 → 每 tick 只下落一个重力单位，呈缓慢下落（还顺带免疫摔落伤害，坐姿被架空成缓降模式）。修复：与 MaidStationaryMixin v1.5.98c 同款教训——只清水平速度（x/z 归零）、保留垂直 y（m_20256_(0, v.y, 0)）：坐姿照常锁水平移动（防"坐下还在走"），下落/上浮/落地恢复正常物理（水中也不影响上浮，不溺水）。随 Promaid-1.0.12.jar 重新部署（备份 .bak_v1348），重启游戏生效。
promaid 1.5.348：每次进游戏都送一本 Promaid 手册的 bug——根因：onPlayerLoggedIn 发放前的"只送一次"查重写的是 contains("maid_smart_blueprints_given", 99)——NBT 类型根本没有 99，而实际写入的是 Byte（TAG_BYTE=1）；contains 要求类型完全匹配，99 永远不匹配 → 标记永远等于"没发过" → 每次登录都重发。修复：类型 99 → 1（TAG_BYTE），与 m_128344_(putByte) 一致，"只送一次"标记真正生效；全库扫描确认仅此一处 99（其余 contains 都是合法类型 7/8/9/10/12/1）。已堆叠的多余手册不会自动消失，手动丢弃即可，之后进游戏不再重发。随 Promaid-1.0.12.jar 重新部署（备份 .bak_v1347），重启游戏生效。
promaid 1.5.347：思慕明显触发效果——背景（反编译 maidmarriage 2.3.0 实证）：maidmarriage 自带思慕呈现太弱，onMaidTick 每秒只在女仆身边撒 2 颗心形粒子加低频循环对话，玩家几乎感知不到；且 isLongingForInteraction 有 isDatingOrMarried 前置，女儿（儿童）永远进不了恋爱向思慕——v1.5.57 备好的三档女儿思慕文本（BABY/CHILD/ADULT_LONGING）因此一直是死代码（"要么触发不了"）。修复：heartfelt 侧新增 LongingEffectManager 每秒扫描（随 heartfelt_connection-1.5.79.jar 部署）：对【思慕中】的关系女仆（主人 24 格内）给足明显反馈——①心形粒子爆发每秒 8 颗（maidmarriage 的 4 倍）；②思慕气泡每 30 秒一句（妻子/恋人/女儿分文案，女儿按成长阶段轮换 LONGING 池，激活死代码）；③系统消息每游戏日一次明确"她在思念你"（触发看得见）。触发判定：妻子/恋人走 maidmarriage isLongingForInteraction（恋爱/结婚 + lastInteractionDay 距今 ≥3 天），女儿走同条件 lastInteractionDay ≥3 天（父女思念文案，不落恋爱向）。边界：伤心窗口/哀悼中不触发、主人不在附近不触发。调试器"long=1d"按钮可直接测：设完靠近女仆即可看到心形粒子爆发+气泡+系统消息。备份 .bak_v1579，重启游戏生效。
promaid 1.5.346：抱起回应 + 记忆库接入验证——
【验证结论】爱憎分明（callresponse 2.0.2）的 LLM 调用【已经能读到记忆库】：反编译实证它的唯一真实 LLM 调用点 MaidResponder → TLM MaidAIChatManager.chat（工具类都是 LLM 函数调用，不主动调 LLM）。而 chat() 内部 normalChat 做 <context> 替换（GameContextRegister → StoryMaidContext → StoryMemoryManager 剧情记忆：结婚/怀孕/心情/告白/父女/丧子/告白失败/心碎），getMessages 又全部汇聚到 LLMMessage.systemChat（SmartPromptMixin @WrapMethod 注入 SmartPromptAppender：关系准则+事件历史 P1+情境 P2+后果 P3）——两条注入链路对爱憎分明的调用同样生效（验证了部署 jar 的 mixins.heartfelt.opt.json 与 MANIFEST 双配置注册，opt 配置里 SmartPromptMixin 等 9 个可选 mixin 都在）。
【新功能】抱起回应（随 heartfelt_connection-1.5.78.jar 部署）：新 PickupResponseManager 监听 Forge EntityMountEvent （TLM 潜行右键抱起 = 女仆骑玩家，服务端骑乘瞬间触发）——确认关系女仆（妻子/女儿/恋人，strictRelationKey）被抱起时：有 LLM+配额 → 沉浸式回应（提示词含关系准则+记忆库）；无 LLM/配额满 → 固定文本气泡降级（女儿按成长阶段口吻：少女"爸爸爸爸！举高高——！"、成女"都这么大了还把我抱起来"、妻子"怎么突然把我抱起来了呀"、恋人"诶诶？！等、等一下啦——！"）。边界：伤心窗口/哀悼中不回应、婴儿幼儿不会说话（chatWithQuota 兜底）、每女仆 10 秒冷却防刷屏。maidmarriage 的举起/抱女儿走代理链且自带剧本对话，不在此路径（避免双重回应）。随 heartfelt_connection-1.5.78.jar 部署（备份 .bak_v1578），重启游戏生效。
promaid 1.5.345：TNT 完工不炸膛——点火保护升级为时间窗 + 完工点火结算——(1)【根因】v1.5.330 的 BuildTntGuard 线程护栏只挡 doPlace 放置瞬间的 onPlace；天机屠龙炮（Never4Get 蓝图，探针实证）320 个 TNT 六邻【无任何红石组件】（玻璃/TNT/石英/栅栏门/空气/珊瑚扇/活塞/釉陶），点火靠【观察者→活塞→推 TNT】：活建造下机器电路随建随跑，TNT 落位后观察者/活塞被放置事件触发 → 推 TNT → 移动重放的 onPlace 检测到邻接带电 → 点燃 → 全链引爆 = "刚建好直接炸膛"（活塞推动发生在 doPlace 之外，线程标记覆盖不到）；(2)【修复】BuildTntGuard 升级为【时间窗压制】（suppressing = 线程标记 || 游戏刻 < 窗口截止）：每次放置（placeTntSafe）与完工激活前都延长窗口（宽度 = 新配置 build.tntIgnitionGrace 秒，默认 120）；MixinTntBuildGuard 双入口压制（onPlace m_6807_ + neighborChanged m_6861_——放置/活塞推动/邻居更新全拦）；(3)【完工点火结算 settleTntIgnition】完工激活（recalcRedstone/activateWater）后遍历蓝图 TNT，只点燃【当前邻接带电】（hasNeighborSignal）的 TNT——轰炸机（矿车压轨带电）当场启动复制循环；天机屠龙炮 TNT 静止无电 → 保持惰性，触发（观察者→活塞）时才点火——不再"刚建好炸膛"，宽限期满后机器按正常红石逻辑点火；配置页·建造设置新增「TNT 点火保护期（秒）」（0 = 关闭保护回到 1.5.330 行为）。随 Promaid-1.0.12.jar 重新部署（备份 .bak_v1345），重启游戏生效。
promaid 1.5.344：Alt+J 对坐着的女仆无法进入对话面板——儿童路径漏修——根因（反编译 maidmarriage 2.3.0 实证）：成人/妻子路径 MaidHugManager.handleInteractionToggle 有 need_standing 坐姿拒绝（v1.5.333 已修）；但女儿走的是独立的儿童路径 ChildInteractionPayload → ChildInteractionManager.handleInteractionToggle——这个管理器里有一模一样的坐姿检查（isMaidInSittingPose → child_interaction.need_standing），之前三次修复只覆盖了成人管理器，儿童管理器从未修过，所以坐着的女儿一按 Alt+J 仍被 child_interaction.need_standing 拒绝。修复：MixinMaidHugSittingAllow 扩展为双 target（@Mixin(targets={MaidHugManager, ChildInteractionManager})）——两个 handleInteractionToggle HEAD 处都先把坐姿、未骑乘、主人的女仆站起来（m_21837_(false)+m_20124_(STANDING)），原版 need_standing 检查自然通过；坐着的妻子、坐着的女儿都能正常进入对话面板。随 Promaid-1.0.12.jar 重新部署（备份 .bak_v1344），重启游戏生效。
promaid 1.5.343：语音包改直接静音——声音频率=0（承接 heartfelt 1.5.77）——根因：TLM 语音包（声音包自主讲话）走的是独立路径 MaidSoundInstance → MaidSoundFreqEvent.onPlaySoundEvent，按 maid.getConfigManager().getSoundFreq()（每女仆声音频率 0..1）概率播放；之前用 mixin 拦 getAmbientSound（v1.5.64）拦不住这条独立路径，语音包仍在播。修复：按方案【直接静音】——ChildGuardManager 每 1 秒对 幼儿/婴儿（isTooSmall）或 伤心窗口（isHurtFeeling，妻子/女儿/恋人）的女仆强制 setSoundFreq(0) → MaidSoundFreqEvent 概率判定永不命中，语音包彻底不播；条件解除（长大/伤心结束）恢复默认 1.0（运行时 Set 记录被静音者，纯内存不落 NBT、无额外字段）；原有 TTS/心契语音 mixin 保留为冗余覆盖。随 heartfelt_connection-1.5.77.jar 部署（备份 .bak_v1577），重启游戏生效。
promaid 1.5.342：调试器设阶段不再吞成长事件（承接 heartfelt 1.5.76）——根因：AdjusterManager.setStage（调试器 4 档阶段按钮）直接把 heartfelt 的 CHILD_STAGE 标签同步成新阶段，checkChildGrowth 看到 stored==stage 直接跳过——用调试器从 婴儿→幼儿 测试时成长事件永不触发，"会自己站起来了"不出现（旧注释本意"触发成长事件"，实现却吞掉了）。修复：setStage 不再预同步 CHILD_STAGE 标签（设女儿 setChild 的同步保留——新建女儿本就不该触发成长事件）；下一 tick checkChildGrowth 检测到阶段变化，按新阶段触发事件文本+站起动作——婴儿→幼儿="会自己站起来了"+ 真正站起、幼儿→少女="又长大了一点"、少女→成年="长大成人了"。随 heartfelt_connection-1.5.76.jar 部署（备份 .bak_v1576），重启游戏生效。
promaid 1.5.341：婴儿丢地物品主人捡不起来（承接 heartfelt 1.5.75）——根因：ChildGuardManager.stripHand 为防女仆自捡（丢→捡→再丢循环，v1.5.63）给物品设了 setPickUpDelay(1000000) 无限拾取延迟，但原版 ItemEntity.playerTouch（m_6123_）【先查拾取延迟】——javap 实证开头 `if (f_31986_ > 0) return`，玩家（含主人）同样被挡，旧注释"玩家碰触清延迟可捡"在 1.20.1 并不成立。修复：新 mixin ItemEntityPlayerPickupMixin 在 playerTouch HEAD 处，若拾取延迟 ≥ 100 万（防自捡标记值）则清零——主人/任意玩家碰触即可正常拾取；女仆的捡拾路径不经过 playerTouch（走 TLM 拾取 AI、尊重延迟），防自捡循环保持不破。随 heartfelt_connection-1.5.75.jar 部署（备份 .bak_v1575），重启游戏生效。
promaid 1.5.340：启动崩溃修复——mods.toml 被误加 UTF-8 BOM——根因：本次迭代用 PowerShell `Set-Content -Encoding UTF8` 改版本号时给 META-INF/mods.toml 写入了 UTF-8 BOM（EF BB BF），Forge 的 tomlj 解析器拒绝 BOM → "corrupt or misconfigured toml" 启动崩溃（tomllib 实证：1.5.68 无 BOM 解析正常、1.5.69 起全带 BOM 全部 Invalid statement at line 1）；promaid 1.0.12 的 toml 同样中招（1.0.11 起）。修复：字节级剥离两个源 mods.toml 的 BOM（内容不动），重建 heartfelt 1.5.74 + promaid 1.0.12 并重新部署（备份 .bak_bomfix）；tomllib 验证两个新 jar 的 toml 均无 BOM、解析 OK。附带说明：描述字段是历史遗留 mojibake（1.0.4 时代起就这样，GBK 误转，字节已部分丢失无法还原）——但它始终是合法 TOML（仅 mod 列表显示乱码，不影响加载），非本次崩溃原因；后续改版本号禁用 PowerShell Set-Content（会加 BOM），改用 Python/编辑工具。
promaid 1.5.339：幼儿手持限食物主副手交叉 bug 修复（承接 heartfelt 1.5.74）——根因（源码实证）：ChildGuardManager.enforceHandItems 旧版 `stripHand(MAIN_HAND, maid.m_21206_())` 检查的是【副手】物品却清【主手】、OFF_HAND 同理反着来——主手的非食物物品永远不会被移除（它检查副手），副手却被错误清空；"非武器物品还留在幼儿手上"的确切原因。修复：参数一一对应（主手查主手 m_21205_、副手查副手 m_21206_），幼儿（INFANT/JUVENILE）主手/副手【任何非食物物品】——武器/工具/杂物/方块一律——移除并原地丢一个（先清手持再丢副本、归属玩家、无限拾取延迟防女仆自捡循环，v1.5.63 机制保留）；食物判定 = getFoodProperties() != null（"认标签food"，1.20.1 唯一标准方式）。promaid 侧 v1.5.332 的武器禁持（MaidWeaponGuard）保留为冗余安全网，与 heartfelt 非食物规则叠加无冲突。随 heartfelt_connection-1.5.74.jar 部署（备份 .bak_v1574），重启游戏生效。
promaid 1.5.338：伤心状态不播语音包（承接 heartfelt 1.5.73）——伤心窗口（被主人打伤赌气，HURT_UNTIL 未到期）内的关系女仆（妻子/女儿/恋人）不再播放任何语音包：三处语音拦截 mixin 全部追加 isHurtFeeling 判定——① MaidAmbientVoiceMixin（TLM 自主 ambient 声音包语音 getAmbientSound + 捡拾声）：伤心窗口返回 null（声音频率=0）；② HeartPactVoicePlaybackMixin（maidmarriage 心契语音包 play 统一出口）：伤心窗口 cancel；③ MaidSpiritTtsGuardMixin（TLM TTS 入口）：伤心窗口 cancel。FamilyInteractionManager.isHurtFeeling 改 public 供 mixin 复用；伤心窗口内她坐着赌气不开口说话（文本气泡/拒绝互动机制维持原样），窗口到期自动恢复。随 heartfelt_connection-1.5.73.jar 部署（备份 .bak_v1573），重启游戏生效。
promaid 1.5.337：婴儿强制坐下改每 tick（承接 heartfelt 1.5.72）——ChildGuardManager.onServerTick 的婴儿强制坐下从 5 tick（0.25 秒）节流改为【每 tick】独立循环：被背叛女仆攻击时战斗/自保 AI 会把婴儿短暂拉起站起反击，5 tick 窗口内肉眼可见；每 tick 按回坐下后站起窗口缩到 1 tick 内不可感知，婴儿永远坐姿（无法攻击）；任务锁空闲/手持限食物与坐姿无关，维持 5 tick 节流（消息另有 40 tick 冷却）。随 heartfelt_connection-1.5.72.jar 部署（备份 .bak_v1572），重启游戏生效。
promaid 1.5.336：成长"站起来"时刻移到婴儿→幼儿（承接 heartfelt 1.5.71）——heartfelt v1.5.64 起幼儿（JUVENILE）可行走（与婴儿唯一区别=能站），但"站起来"的成长时刻还挂在幼儿→少女（JUVENILE→CHILD），不一致；本次将站起动作与文本整体前移：(1)【站起动作】FamilyInteractionManager.checkChildGrowth 的 setOrderedToSit(false) 从 stage==CHILD 改为 stage==JUVENILE——婴儿→幼儿升级瞬间真正站起来一次（婴儿期一直被强制坐下，升级时她实际还坐着；幼儿→少女时幼儿已可行走，无需再站）；(2)【成长文本】PromptTexts 系统消息/LLM 提示词/降级气泡/幼儿旁白全部对调：JUVENILE="会自己站起来了"（摇摇晃晃站起来又惊又喜"爸爸！你看我！"/幼儿旁白无台词站起来要抱抱），CHILD="又长大了一点"（好奇打量自己）；(3)【promaid 同步】RelationshipMemoryAdapter.stageLabel：JUVENILE「会自己站起来的小宝贝」、CHILD「活泼的小女孩」（撤销 v1.5.50 的挪移，与 heartfelt 一致）。随 heartfelt_connection-1.5.71.jar + Promaid-1.0.12.jar 部署（备份 .bak_v1571/.bak_v1012），重启游戏生效。
promaid 1.5.335：婴儿/幼儿统一约束（承接 heartfelt 1.5.70）——heartfelt 侧：(1)【儿童工作漏网修复】maidmarriage 的儿童工作（学习/探险，MaidWorkManager）对 isTooSmall（INFANT/JUVENILE）强制阻止——旧 v1.5.82 的"坐姿→NONE 放行"对幼儿是反效果：婴儿被强制坐下却被放行可工作、幼儿不坐下直接可工作（"任何工作都做不了"漏网）；MaidWorkSittingMixin 在 resolveWorkBlockReason 加 isTooSmall 分支强制返回 SITTING 阻断；(2)【拒绝文案】heartfelt lang 覆盖 message.maidmarriage.child.work.sitting 为"还太小了，还不能安排工作"——只有幼儿会看到这条（其余女儿的坐姿被转 NONE 放行，不触发该消息）；(3)【语音包核对】三处拦截（MaidSpiritTtsGuard/HeartPactVoicePlayback/MaidAmbientVoice）均用 isTooSmall 已覆盖两者，无缺口；(4) 强制坐下仅 isInfant（婴儿），幼儿（JUVENILE）可站立——这是两者唯一区别，其余（任务锁空闲/手持限食物/禁语音/不产生主动话语）一律 isTooSmall 两者一致。随 heartfelt_connection-1.5.70.jar 部署（备份 .bak_v1570），重启游戏生效。
promaid 1.5.334：受伤文本统一去指向（承接 heartfelt 1.5.69）——heartfelt 侧 8 处"玩家伤害惩罚"文本（AftermathPrompt 伤心窗口提示词 + PromptTexts 的 harmPenaltyMessage/harmPenaltyBubble/harmPenaltyBubbleChild/harmPenaltyLLMPrompt/harmPenaltyLLMPromptChild/babyCryMessage/babyCryLLMPrompt）全部去掉"被你打/主人打了你/爸爸打了你/主人伤害了你"等来源指向，统一为"被弄疼了/受了伤"——玩家放岩浆、怪物、环境等非直接攻击触发该路径时不再误导成主人打的；其余反应描写（怔怔看着、背对、呜哇大哭）保留。promaid 侧无代码改动（文本全在 heartfelt），随 heartfelt_connection-1.5.69.jar 部署（备份 .bak_v1569），重启游戏生效。
promaid 1.5.333：心契誓约 Alt+J 对坐着的女仆无法进入交互面板——根因（javap 字节码实证 maidmarriage 2.3.0）：MaidHugManager.handleInteractionToggle（Alt+J 的服务器端处理器）校验链含 `if (maid.isMaidInSittingPose()) { 发 need_standing 消息; return; }`——坐着的女仆被直接拒绝，面板不开（child 女仆另有 need_adult 拒绝，但儿童走独立儿童交互面板路径，不受影响）；修复：(1)【放行坐姿】新 mixin MixinMaidHugSittingAllow（@Pseudo 软注入 MaidHugManager，require=0 版本变动静默降级）在 handleInteractionToggle HEAD 处把【目标坐姿女仆】先站起来（m_21837_(false) 清坐姿+指令位 + m_20124_(STANDING)——仅限坐姿中、主人、未骑乘，骑乘由原版 riding_blocked 继续拒绝）→ 原版 need_standing 检查自然通过 → 面板正常打开；后续 lockMaid 本就会把女仆设为 STANDING 并锁定姿势/位置，与预站起一致无副作用；(2)【建造不打架】MaidBuildBehavior.tickBuildSit 在女仆处于心契誓约交互中时（反射 MaidHugManager.getInteractionPlayer(maid) 非空，软联动）跳过强制坐下——否则交互锁定站立 vs 建造强制坐下每 tick 互搏（坐下↔站起振荡）；交互结束后自然恢复建造坐姿。随 Promaid-1.0.11.jar 部署（备份 .bak_v1333）。
promaid 1.5.332：幼儿女儿武器禁持——范围严格限定【女儿 且 婴儿/幼年阶段】（RelationshipMemoryAdapter.isTooSmall：isChild 为真且 heartfelt_child_stage 为 INFANT/JUVENILE，缺失时兜底读 child_state_data.growthStage——正是"幼儿女儿不产生主动话语"那套既有判定）；实现：MaidWeaponGuard 每 1 秒轮询全部已加载女仆（ProMaidExtension.onServerTick 挂载），主手/副手（getHandsInvWrapper：Forge EntityHandsInvWrapper，slot 0=主手、1=副手）出现武器（剑/斧/弓/弩/三叉戟）→ 从手上删除并【原地丢一个完全一样的】（ItemStack.copy 副本 → ItemEntity 生成），覆盖玩家喂给/自动装备/任务换装等一切入手机制；成年女儿/普通女仆不受影响，镐等挖掘工具不在武器判定内不受影响；移除日志 latest.log 搜 "weapon guard"。随 Promaid-1.0.10.jar 部署（备份 .bak_v1332）。
promaid 1.5.331：撤销 v1.0.7「图腾/濒死背叛保护」——实测确认女仆"全部消失"实为主人死亡传送（MasterDeathTeleportHandler）误传，非爱憎分明背叛：v1.5.326/327 基于"坠落触发图腾→女仆消失=背叛"的误判加入的 BetrayalGraceManager（5 分钟保护期 + 反射拉回背叛女仆 + 清 dangerTimer）、MixinEmotionBetrayalGrace（压制 triggerBetrayal 与危险计时）、MaidBaubleTotemMixin 主人分支两处无条件 activate、config 开关 loveLoatheBetrayalGrace 全部移除。不死图腾判定恢复 v1.5.325 原样：女仆自己饰品栏/背包图腾复活、主人致命伤时女仆共享图腾救主（TOTEM_SHARE_ENABLE），无背叛干预。死亡传送保留 v1.5.329 延迟 1 tick校验存活（图腾救活不传，真死才传）。
promaid 1.5.330：TNT 建造期防自燃 + 半透明渲染重发修复——(1)【半透明修复失效根因】resendPlacedChunks 节流初值 LAST_CHUNK_RESEND = Long.MIN_VALUE：首次调用 now - Long.MIN_VALUE 整数溢出为负 → 节流判定恒 <40 → return，区块重发【从不执行】= v1.5.322 声称的修复从未生效（字节码实证客户端链路上链路完整：ClientboundLevelChunkWithLightPacket → LevelChunk.replaceWithPacketData 换数据 → handleLevelChunkLighting → setSectionDirty 无条件触发重建，空光源掩码不影响）；修复：初值改 0（游戏刻恒 ≥0 首次即生效）+ 待重发集合改【静态跨轮累积】（旧版每轮新建局部集，节流 2 秒窗口内非触发轮的放置会漏发），重发成功后一次清空；(2)【TNT 自燃根因——Never4Get"游标走到底卡死/反复跟活塞过不去"的真相】活建造（v1.5.316）下动力源先带电，TNT 最后放置时旧代码用 flag 2 静默以为能防点燃——字节码实证 LevelChunk.m_6978_（setBlockState）服务端【无条件】调用 BlockState.m_60753_（onPlace），flag 2 挡不住；TntBlock.m_6807_（onPlace）检测相邻有信号（m_276867_）→ onCaughtFire 点燃 + m_7471_ 移除 → "放置后目标仍空气" → 旧计划 320 个 TNT 全延后 → 卡死（日志实证 "build stall: 游标=10391/10391 延后=320 [tnt@3,34,26 现=minecraft:air …]"）；修复：MaidBuildBehavior.doPlace 放置 TNT 时挂 BuildTntGuard 线程护栏（try/finally 清除）+ MixinTntBuildGuard 在 TntBlock.onPlace 头部 cancel → TNT 以稳定方块落地，机器运行时红石翻转/触发走 neighborChanged（m_6861_）正常点燃——"建好就能跑/手动标靶触发"不受影响；BlueprintLib.normalizeMachineState 对 TNT 归一 unstable=false（蓝图导出的点燃态不落地）；(3) 均随 Promaid-1.0.8.jar 部署（备份 .bak_v1330），重启游戏生效。
promaid 1.5.329：主人死亡传送延迟校验——图腾救活不传——根因：非背叛、非 1.5.327 排查的结论（当时判"图腾保命不触发 LivingDeathEvent"），玩家环境（charmofundying 不死图腾槽位等）在触发图腾时【先触发 LivingDeathEvent 再图腾复活】——MasterDeathTeleportHandler 立即执行，把女仆传到【重生点】（主人实际没死、离坠落现场很远）→ 女仆"凭空消失"。修复：死亡传送改为【延迟 1 tick 校验】——onPlayerDeath 只登记，下一 ServerTick 检查玩家存活（isDeadOrDying / 血量≤0）——图腾救活（活着）→ 跳过传送（女仆留在身边）；真死 → 才执行死亡传送。原传送逻辑（安全落点/追踪表未加载女仆/最近者播报）整体保留。
promaid 1.5.328：图腾/濒死背叛保护无条件激活——承接 1.5.327：旧保护激活（MaidBaubleTotemMixin）只认【主手/副手有图腾】与【女仆共享图腾】两个入口，漏了【背包/槽位图腾】触发场景（charmofundying 不死图腾槽位等扩展：图腾从背包/槽位触发时保护没激活 → 爱憎分明背叛判定继续走满 → 女仆全部消失）。修复：致命伤瞬间（m_21262_ 被调用 = 玩家死亡检查）无条件 activate 保护——无论图腾在哪个槽位（手/背包/槽位）甚至没有图腾（真死亡）都先进入 5 分钟保护期（拉回正背叛女仆 + 清 dangerTimer + 压制背叛判定），防"主人濒死瞬间女仆背叛跑掉"；手里有图腾仍放行原版路径（不抢消耗）。
promaid 1.5.327：图腾/濒死背叛保护——(1)【根因排查】不是 promaid 的死亡传送（字节码实证：图腾保命时 LivingEntity.m_6469_ 走 ifne 跳过分支，die() 不执行 → LivingDeathEvent 不触发，MasterDeathTeleportHandler 不运行，pro 死亡传送/目击死亡链均排除）；消失的是【爱憎分明（callresponse 2.0.2）的背叛机制】：EmotionBetrayalManager 每 tick 检查 信任<10 且 恐惧>90，持续 200 tick（10 秒）→ triggerBetrayal 解除契约（setOwner(null)）、停止跟随、跑开攻击，NBT IsBetraying 跨存档持久化（实测：汉服酒狐背叛后重进存档仍是背叛态，右键才恢复）——女仆的恐惧/信任早已被"主人打女仆"等事件积累到临界（日志实证 03:05"好痛…主人为什么要这样对我"→03:06 背叛→次日 13:05 仍在背叛态），玩家坠落触发图腾的瞬间恰好是危险计时（dangerTimer）走满 200 tick 的时刻 → 两只女仆同时触发背叛 = "突然全部消失"；(2)【修复】图腾/濒死保护：主人触发不死图腾（自己手里的原版路径 或 女仆共享图腾保命路径，MaidBaubleTotemMixin 双入口挂钩）→ 进入 5 分钟保护期——MixinEmotionBetrayalGrace（@Pseudo 软注入，target 爱憎分明 2.0.2，require=0 版本变动静默降级）保护期内压制 triggerBetrayal 与 dangerTimer 累加；BetrayalGraceManager 激活瞬间反射调用 EmotionBetrayalManager.resetBetrayal 拉回正背叛的女仆（播报"主人……我不该离开你的……我回来了！"+系统消息）并清空其 dangerTimer——给玩家时间喂食/互动抬信任降恐惧，濒死不再成为背叛导火索；(3)【配置】爱憎分明模组调试页新增「图腾/濒死背叛保护」（misc.loveLoatheBetrayalGrace，默认开，受爱憎分明联动总开关约束）；未装爱憎分明/版本变动时全部静默跳过，不影响任何功能。
promaid 1.5.326：LLM 防乱伦铁律（承接 heartfelt 1.5.55——要求大语言模型防止乱伦很有必要）——AiMemoryContext 女儿关系标签在称呼铁律后追加防乱伦铁律：我是他的女儿，对他只有亲情——严禁任何恋爱、亲密、暧昧的言行与情感，即使已经长大也永远是父女关系，遇到恋爱或亲密话题要困惑地拒绝；与 heartfelt 四段女儿准则的 RELATIONSHIP GUARD 及亲密工具行为层拦截构成三层防线。
promaid 1.5.325：幼女成长记忆描述修正（承接 heartfelt 1.5.50——"站起来"是幼女→少女(CHILD)的标志，JUVENILE 幼女站不起来）——stageLabel：JUVENILE「会自己站起来了的小宝贝」→「又长大了一点点的小宝贝」，CHILD「活泼的小女孩」→「会自己站起来的小女孩」；与 heartfelt 成长系统消息/提示词同步（幼女成长只报"又长大了一点"，CHILD 才报"会自己站起来了"）。
promaid 1.5.324：蓝图删除根因修复——根因：模组同时扫描 config/maid_smart/blueprints 与 <cwd>/schematics 两个目录，但蓝图书删除只删 EXTERNAL_PATHS 登记的那一份——同一蓝图文件若在两个目录都有副本（多实例/多存档残留），删一份、另一份下次扫描又注册回来 = "删了又出现/重登又出现"（RRR/SSS 删不掉的历史根因，v1.5.252ad 注释即有记录）；修复：deleteBlueprint 改为【全扫描目录清除同名文件】——按文件名（去扩展名、大小写不敏感，RRR/rrr 都删）在 config 与 schematics 全部扫描目录里清掉所有副本，再清内存缓存；删除后即彻底，不再复发。
promaid 1.5.323：内部版本号同步 1.0.2 → 1.0.4。
promaid 1.5.322：半透明渲染刷新修复——根因：建造过程中快速批量放置时，客户端区块重建队列积压，玻璃/粘液块等【半透明渲染层】迟迟不重建（实心层先重建、半透明层滞后），从区块外往里看就"看不见"（走近/建完后恢复正常）；修复：建造每轮放置后【节流重发本轮放置过的区块】给同维度玩家（每 2 秒一次；`ClientboundLevelChunkWithLightPacket` 空光源掩码=只刷方块渲染不动光照）→ 强制客户端整块重建（含半透明层），玻璃/粘液块即时可见；只重发本轮实际放置过的区块、2 秒节流，性能影响可忽略。
promaid 1.5.321：对外版本号 1.0.0 → 1.0.2——mods.toml version 与 jar 文件名同步改为 1.0.2（Promaid-1.0.2.jar），构建链（build_promaid.py/verify_jar_classes.py）与发布脚本（Modrinth/GitHub）同步更新；影响面核查：源码无硬编码版本号（游戏内不显示版本），modId 不变（promaid），持久化数据（config/maid_smart、灵魂记忆、存档 TaskData）按 modId/UUID 索引不受版本/文件名影响，TLM 依赖声明 [1.5.0,) 不变；唯一注意点=部署时旧 Promaid-1.0.0.jar 必须删除（同 modId 双 jar 会冲突崩溃），本次部署已同步删除。
promaid 1.5.320：矿车纳入工具需求——(1)【矿车=启动工具·消耗】轰炸机类完工自动放矿车不再凭空白给：每条探测铁轨消耗 1 辆矿车（女仆背包优先、主人背包兜底；主人创造模式无限），背包没有矿车 → 不自动生成；(2)【完工动态提示】按实际放置数提示——「已自动放置矿车 X 辆，即将启动轰炸循环——请撤离机器附近！」/「缺少矿车（需 N 辆），未自动启动——把矿车放进背包后，手动放到探测铁轨上即可启动轰炸循环」（machineFinishTip 轰炸机文案改动态）；(3)【材料提示全链】蓝图摘要/创建气泡/缺料消息追加"矿车×N（完工自动放置，需备齐）"（fluidBucketNeeds 统计探测铁轨数）；(4)【材料表工具行】矿车行加灰色角标「（工具·消耗）」（水桶「（工具）」、岩浆桶「（返还）」）；中文名补"矿车"；(5) LLM smart_build 汇报走 describe 自动携带。
promaid 1.5.319：材料表液体行角标（承接 v1.5.318 材料提示补全）——手册材料详情页的水桶/岩浆桶行加灰色小字角标：水桶「（工具）」、岩浆桶「（返还）」，与普通消耗材料视觉区分（工具不消耗、岩浆放置后返还空桶，这两行不是普通消耗品）；LLM smart_build 材料汇报无需改动——其汇报走 describe，v1.5.318 起已自动携带"另需水桶×1（作工具，不消耗）、岩浆桶×N（放置后返还空桶）"。
promaid 1.5.318：生存材料提示补全液体需求——水/岩浆被 countNeeds 排除（FORBIDDEN），旧版材料提示/材料表完全看不到桶的需求 → 玩家建造前不知道要备水桶/岩浆桶，建到一半才卡住看气泡。本次把液体需求补进全部材料提示面：(1)【蓝图摘要 describe】材料 top5 后追加"另需水桶×1（作工具，不消耗）、岩浆桶×N（放置后返还空桶）"；(2)【创建气泡 needBubbleText】"还需 X×N"后追加液体需求；(3)【缺料消息】"材料不足，缺少：X"与"背包里没有任何建造材料"后追加液体需求；(4)【手册材料表 buildCatalogEntriesWithMaterials】新增"水桶（工具）"与"岩浆桶×N"行（已有=玩家+绑定女仆桶数，需要=1/N；创造模式显示齐）；(5) 中文名补"岩浆桶"；空气/矿车维持不显示（空气非材料、矿车完工自动生成）。
promaid 1.5.317：水/岩浆/空气/物品判定改革——(1)【根因修复：水/岩浆从未被放置】旧版导入蓝图时 FORBIDDEN 黑名单把 water/lava 全部剥离、且方块无对应物品（物品是桶）→ 打包机/潜影盒仓库的冰道水道、甘蔗机水槽、南瓜机灌溉沟、分类机水冲、仓库岩浆焚烧口【建成全是干槽/空槽】——这才是机器"建好不动"的更深层根因（v1.5.315 activateWater 建立在错误前提上：计划里根本没有水步骤，重放=空转）；(2)【机器蓝图保留液体】parseStructure 新增 keepFluids：红石机器家族（文件名匹配）导入时保留 water/lava 步骤，普通建筑维持剥离（防洪水/岩浆事故）；(3)【材料链按桶结算】BLOCK_ITEM_OVERRIDES 加 water→water_bucket、lava→lava_bucket：水=【无限材料】——女仆或主人背包有 1 个水桶作工具即可放任意多水源（不消耗，与原版水源可再生一致，缺桶提示"需要水桶"）；岩浆=【消耗 1 岩浆桶/格、放置后返还空桶】（returnEmptyBucket：主人背包优先→女仆背包→掉落身边，防被完工清理；岩浆不可再生，需玩家备 N 桶周转）；(4)【液体只放源块】normalizeMachineState 对水/岩浆归一 level=0——蓝图导出的流动态不直接放置，流动由水源模拟产生（防串流/重复）；液体始终 flag 2 静默放置，完工 activateWater 批激活 → 统一流动/气泡柱成形（逐个活放会因相邻水源先流过来而跳过后续源块，气泡柱/水道不完整——机器与建筑水池均走此路径，旧"机器跳过 activateWater"一并修正）；(5)【空气判定保持】外部蓝图空气隐式剥离（不建不清，天然留空）；显式空气步骤（世界提取/JSON）保留"清除"语义（只清黑名单外可拆方块），材料统计排除空气不变；(6)【矿车等物品】实体不入蓝图（方块列表天然无实体），轰炸机完工自动放矿车已由 v1.5.316 提供；无物品方块（活塞头/气泡柱/附生茎/绊线/火）继续剥离并在完工提示按家族说明需手动补充项。
promaid 1.5.316：红石机器改革——(1)【去禁锢】机器不再"静默放置（flag 2 机械冻结）+ 完工唤醒/不唤醒"，取消旧禁锢链（红石线保留冻结 power、活塞保留冻结伸缩态 → 建好不运行的根因）；机器改走【活建造】（flag 3，红石/水流随放随算）；(2)【专属搭建顺序 sortMachinePlan】按红石拓扑分层：结构 → 惰性机构（漏斗/箱子/铁轨/冰/灵魂沙/水等）→ 活动件（活塞/粘液块/蜜块/红石灯）→ 传感/信号（观察者/比较器/中继器/标靶）→ 动力源（红石线先、红石块/火把/拉杆/按钮/压板最后）→ TNT（最后且始终静默放置）——动力源最后落位，机器在最后一格落下时自然进入运行态（"建好就能跑"）；相位内 y→x→z 自下而上（支撑/槽壁/灵魂沙/冰先于其上的附着物/水，气泡柱/冰道成形）；(3)【状态归一化 normalizeMachineState】机器模式丢弃蓝图导出时的冻结瞬态（伸出活塞 extended→缩回、通电铁轨 powered→断电、线 power→0、火把/灯 lit→自然态），方块以自然初始态落地、由活放置收敛到设计态；(4)【轰炸机自动启动 spawnStartMinecarts】单TNT自返回/1.111倍速等带探测铁轨的轰炸机，完工自动在每个探测铁轨上生成矿车（矿车压轨才带电 → TNT 复制循环自动启动），完工提示同步改为"已自动放置矿车,即将启动轰炸循环——请撤离机器附近!"；2TNT/29方块/推土机（纯观察者/活塞自启动）与 Never4Get（手动标靶触发）自动跳过；(5)【配置开关】新建「红石机器专属搭建」（build.machineSmart，默认开，面板·建造设置）——关 = 完整回退旧行为（常规顺序+静默+完工唤醒）；(6) 作用范围仅红石机器家族（外部 21 台 + 内置 machine_ 前缀 + LLM 机器），普通建筑保持静默放置防活塞推墙互搏；carveEntrance 红石豁免沿用（机器不开门洞）。
promaid 1.5.314：调试面补全——Promaid 手册·女仆记忆→「链路调试」页新增 3 行状态：【人格】人格名字·核心记忆条数·TLM人设=补充/完整（人设统一模式）、【纪念日】基准=告白/初遇·第N天·已达成M天·临近L天（heartfelt 联动游标直读）、【双agent】开关·提取中=是/否·关心点N条；状态区小窗口超行时右上角 ◀/▶ 翻页（不丢行）。
promaid 1.5.313：人设统一 + 动态化——(1)【人设统一（注入消歧）】检测 TLM 原版人设（per-maid「自定义设定」customSetting + per-model settings/*.yml，反射兜底）：TLM 已有人设时，人格种子块【降级为补充】——只注入 TLM 没有的[人格参数]（害羞/依赖/边界敏感等 8 维）+[核心记忆]（宪法级），块首声明"冲突以 TLM 设定为准"，不再重复身份/性格（TLM 模板 Data Overridden 规则让 <context> 优先于 system，双人设并存行为不可预期——根因在此）；TLM 无人设时保持完整人格渲染；新配置「人设统一」（memory.personaUnify）默认开，可一键关回旧行为；记忆面板显示「TLM 人设：有（补充模式）/无（完整模式）」；(2)【人设动态化（不一成不变）】重大关系事件沉淀进角色包核心记忆（core_memories.jsonl，宪法级随投影每轮注入）——结婚/告白/父女/纪念日里程碑达成时自动追加（内容去重 + 上限 20 条防膨胀）：人格的"自我认知"随时间成长（初遇 → 恋人 → 妻子 → 纪念日 N 天），配合已有的 ai_affect 情绪注入 + 关系状态注入，人设 = 稳定内核（persona.properties 种子保证连续性）+ 成长外壳（核心记忆/关系现状/情绪驱动演变）。
promaid 1.5.312：记忆升级四件套（借鉴 maidSoulCore 思路深度落地，全量向后兼容）——(1)【情绪快照入记忆】每条新写入的记忆自动附带当时 PAD 情绪（愉悦/唤醒/支配/亲密/冲突/思念/受伤债/修复债，存 metadata 字段；旧记忆不受影响）；情绪注入上下文（ai_affect）新增「表达建议」——受伤/修复债高→先接住余波再和好、亲密+思念高→可更粘人、心情低→回复短而软，LLM 不再只看数值；(2)【人格种子（角色包）】每女仆记忆目录自动生成 persona.properties（人格种子）/ traits.properties（人格参数）/ core_memories.jsonl（宪法级核心记忆，salience≥8），作为【只读投影】优先注入对话上下文——人设与聊天记忆彻底分离、聊天永不改写人格（maidSoulCore 哲学：「prompt 只是状态投影，不是人设本体」）；改人设直接编辑文件（UTF-8），女仆配置·记忆面板显示人格名字；(3)【每日关心点】每日回顾自动附加「下次该怎么对主人」的行动建议（从情绪残留/边界/偏好/风格推导，纯规则零 LLM），主动对话（TOPIC_PUSH 读 daily 段落）会自动复用当话题——记忆↔主动对话联动；(4)【双 agent 提取】记忆提取拆成摘要（SUMMARY/IMPORTANCE/TAGS）与事实事件（FACT/EVENT）两次独立 LLM 调用——更聚焦、互不阻塞，任一失败不阻塞对方，水位线等两者都完成才推进（防重试风暴）；memory.dualAgent=false 回退单次合并提取省 token；(5)【路由统一】主动对话（memoryTopic/relationMemory）与回复反馈（error_mark/强化）的记忆读写统一改走灵魂路由（SoulBindingService.storeFor）——灵魂女仆不再读错世界目录，人格/情绪/关心点路由一致；新配置四项：情绪快照入记忆 / 人格种子注入 / 每日关心点 / 双 agent 提取（配置面板·AI 记忆→「人格与情绪」小节，均默认开、可一键关停）
promaid 1.5.311：红石建造根因修复 + 红石/状态能力扩展（承接 v1.5.300"红石机器基本都不能用"的根因）——(1)【红石唤醒 v2（recalcRedstone）】旧版完成时对红石组件"同状态重放 flag 3"在 1.20.1 是失效操作：Level.setBlock 对状态相等的重放不调用 onPlace（红石线/火把/活塞的放置重算逻辑永不执行），updateNeighborsAt 又只广播水平邻居——红石线保留图纸导出时的冻结 power、活塞保留冻结伸缩态 → 机器建好不运行/状态错乱。v2 每格补齐：组件自身 neighborChanged 直调（红石线重算 power、活塞 checkIfExtend 重定伸缩含 BUD/准连接、灯/铁轨/火把重查供电）+ 垂直邻居手动补广播 + 白名单补全（活塞/铁轨/绊线/陷阱箱/门/音符盒/标靶）+ 3 轮收敛 + 替代品位置兼容；(2)【红石族进 LLM 白名单】redstone_wire/红石火把/红石块/红石灯/拉杆/按钮/中继器/比较器/观察者/活塞/粘性活塞/发射器/投掷器/漏斗/铁门/压力板/铁轨（充能/探测/普通）/标靶/音符盒/陷阱箱——LLM 现场生成的红石机器可以真实运行（v1.5.300 删机器是唤醒失效所致，根因已修复）；(3)【JSON 蓝图支持 state/nbt】LLM JSON 每块可带可选 state（SNBT，如 {facing:"north"}）与 nbt（方块实体）——门朝向/楼梯方向/漏斗朝向/箱子内容不再一律默认态；BlueprintLib.validate 与 smart_design 宽松校验同步兼容（state 含逗号，旧版 split(",") 误报格式错误）；(4)【开门洞红石感知】carveEntrance 对含红石组件的蓝图整体豁免（不再只认 machine_ 前缀）——外部红石蓝图墙内布线不会被完工开门洞切断。
promaid 1.5.310：爱憎分明（Love Loathe）软联动调试页——(1)【配置面板】装了爱憎分明（modId=callresponse）时首页左列多一个「爱憎分明模组调试」大按钮（未装不显示，软联动零影响），页面布局自动压缩不压保存按钮；页内【联动状态（调试）】只读探测：模组版本 / HungerData 反射接口 / EmotionData 反射接口（新旧包名双试，v1.5.284 机制）/ 饥饿门控注入状态 + 「重新探测」按钮；(2)【联动开关】爱憎分明联动总开关（默认开，关掉后不再反射读取其数据）、禁用爱憎分明饥饿（原杂项页迁入本页）、极端饥饿保命联动（饥饿值 ≤9 时吃金苹果）、情绪数据联动（信任/恐惧入记忆与 AI 上下文）；(3)【行为接入】SelfPreservationBehavior.isExtremeHungry 与 RelationshipMemoryAdapter.emotionValues 均受对应开关门控；(4) 指南「模组详细配置面板导航」章补充说明（11→12 板块）。
promaid 1.5.309：指南去虚假宣传——战斗与自保章逃生手段③ 由「卡墙窒息自动垫台阶翻越，溺水游上去」改为「窒息/卡墙时会尝试上浮，必要时传送到主人身边」（与实际防窒息措施一致）
promaid 1.5.308：区块名单页进度条重叠修复——根因：v1.5.302 给区块名单页补进度条时，行数公式只给翻页按钮预留了 32px，绑定女仆多 + 窗口矮时名单撑到进度条区域（h-94）→ 重叠。修复：行数公式【预留进度条空间 48px】（4 行状态文本 + 进度条 + 边距）——名单每页行数相应减少、自动分页，进度条永远在名单下方不重叠；按钮区与渲染区的行数口径同步（防进度条与翻页按钮错位）
promaid 1.5.307：缺吃的播报实现 + 喂食提示补全——排查结论：(a)【缺吃的播报从未实现】代码里根本没有该播报，手册确实是虚假宣传——日志实证女仆无食物时每 tick 刷屏"背包与双手都无投喂食物"（08:03:44 起每 50ms 一条）；现在实现：主人饿且女仆背包/双手无食物时，女仆气泡 + 系统消息「我背包里没有吃的了，给我备点食物吧～」（60 秒限频不刷屏，日志同步限频）；(b)【喂了什么系统提示】食物喂食的系统消息一直在（feedFoodDirect「女仆喂你吃了 X」），之所以"不生效"是因为女仆根本没有食物、喂食从未成功（日志实证）；金苹果路径确实只有气泡没有系统消息——补上「女仆给你吃了附魔金苹果（效果已加成）」，现在所有喂食路径（食物/蜂蜜/牛奶/金苹果）都有系统提示
promaid 1.5.306：指南微调——(1)【工头补充】女仆管理章补：没设立工头时，区块开始建造自动从绑定女仆里随机选一只当工头（想换人随时在名单页手动指定）；(2)【价值分保留】排查结论：价值分功能未失效——评分公式 `距离² + 深度惩罚 − 价值×权重`（权重默认 2.0）仍在用，内置价值表（钻石 500/绿宝石 450/铁金 250/煤 100…）+ 矿表自定义值（id=价值）双重生效；玩家配置里 oreValues 为空表 → 用的全是内置默认值，所以"感觉不到"；如需高价值矿更优先可把「价值权重」调大（最大 5.0）——不删除；(3)【落地水去重】战斗与自保章的逃生手段去掉落地水/岩浆逃生条目（与被动技能章重复），改为指引「被动技能」章统一介绍
promaid 1.5.305：手册调整——(1)【「女仆配置」按钮删除】手册女仆详情页的直达 TLM 配置按钮整体移除（OpenMaidGuiPacket 网络包一并删除；玩家判断该路径有 bug 且不想修——打开 TLM 女仆配置请直接右键女仆），指南中所有相关描述同步清理（跳转链路、女仆管理章、LLM 章直达路径）；(2)【指南：配置 LLM 章简化】AI 记忆的 API 只需一句"默认跟随原版（TLM）配置"——删除原"记忆 API 单独配置/留空=跟随 TLM"详细说明（AI 记忆章同改）；(3)【指南：建造教程补记】末尾新增「关于自动甘蔗机的废弃」：版本问题导致漏斗无法接收隔着一块泥巴的甘蔗掉落物，机器无法正常收集（搭建本身可正常收割，仅收集失效）；有一定历史意义（蓝图打印——终于能打印出可工作的红石机器），后续版本会尝试加入真正有用的红石机器；小知识补充自定义替代方块的作用（连材料等价物都找不到时，用玩家自定义方块替换，替代品名单在建造板块）
promaid 1.5.304：详细介绍全面重写——25 章保姆式教程：每章先讲"是什么"再手把手教"怎么用"，关键步骤配【举例】；新增「准备篇：配置 LLM（保姆式）」「模组详细配置面板导航」「被动技能（独立板块）」三章；重写同时修正全部过时内容：投喂直接喂（不再塞快捷栏）、手持食物可喂、蜂蜜是投喂食物、自主决策默认开且必须 LLM、投喂距离 16 格、极速模式放置间隔、畜牧数量控制已删除说明、阈值 4-20 真实生效、区块坐标显示、名单页跳转、进度条只在区块详细页、输出语言选项选择、红石机器只剩自动熔炉组、门落地修复——更新日志章节保持原样（读 changelog.txt）
promaid 1.5.303：对话输出语言改为选项选择——「对话提示 → 输出语言」原先是手填文本框（要填 zh_cn/en_us/ja_jp 语言代码，填"中文"这种自然语言无效、填错无提示），改为【循环选择按钮】：跟随游戏语言（默认）/ 中文 / 英文 / 日文 / 韩文 / 俄语——点一下换一个，选项直接写中文名，内部自动映射语言代码（跟随=留空，中文=zh_cn 等），不再有填错风险；旧配置里手填的未知值显示为"跟随"（点一次选项即修正）
promaid 1.5.302：进度条位置修正——【女仆管理页移除进度条】旧版底部进度/速度文本叠在女仆名单最后几行上（截图实证：第 6 行女仆按钮上叠着"速度：极速"；v1.5.190 只修过页数口径、没根治重叠）；【区块详细页（区块「X」· 绑定女仆名单）补上进度条】——进度条现在只在对应区块的详细界面显示（有翻页时上移避开底行、无翻页贴底）；建造总目录/蓝图材料详情页的进度显示不受影响
promaid 1.5.301：投喂阈值按钮真实生效——根因：配置定义 `aidFoodThreshold` 的 defineInRange 范围是【4-18】（注释写 0-20，范围上限没跟上）——面板填 20 → Forge 配置系统把越界值【静默钳制回 18】（输入框显示 20、实际生效 18）→ 饱食度 18~19 时永远不喂，「修改按键看起来无效」。修复：范围上限 18 → 20（填 20 = 只要不满就喂，真实生效）；治疗触发血量范围同步对齐（0.1-0.8 → 0.1-1.0，注释 0-1 同样存在钳制问题——测试调 1=掉血就治会真实生效）；两处提示语更新；`aid feed` 诊断日志加实际阈值（latest.log 搜 "aid feed" 可确认当前生效值）。修改即时生效无需重启（面板「保存并返回」写入内存+文件，行为每 tick 读配置）
promaid 1.5.300：红石机器精简 + 蓝图门修复——(1)【机器删除】自动甘蔗机/自动南瓜西瓜农场/昼夜自动灯 3 台整体移除（目录/生成器/离线验证同步删），只保留【自动熔炉组】（纯漏斗定向无红石，100% 可靠）——观察者+活塞脉冲时序在建造环境不可靠（信号线柱、脉冲驱动在女仆逐个放置/方块更新时序下经常不通），不再保留；(2)【门修复】两处根因：a) 门【离地 1 格】——旧版门放 y0+1、地基垫在门下，从外面看门悬空在地基上，不像正常的门；改为门【落地 y0】（地面高度），并清掉门内一格地基，玩家可从地面直接走进来（进门一步踏上室内地板）；b) 门【朝向错误】——正面墙 z=0 的门旧版 facing=south（朝屋里开），改为 facing=north（朝屋外开，玩家迎面推门）；15 小屋 + 10 别墅全部生效
promaid 1.5.299：投喂不触发根治——两个根因：(1)【硬编码阈值 15】giveFoodToOwner 内部写死 `foodLevel >= 15 就 return`（对话动作时代的旧闸门）——配置面板的「投喂触发饱食度」只在调用处生效，方法内部还有一道 15 的旧闸门：阈值调 20 时饱食度 15~19 被这道闸门拦住（阈值小于 15 时碰巧正常，所以看起来"时灵时不灵/奇怪的间隔"）。修复：改读配置阈值（阈值 20 = 只要不满就喂）；(2)【手持食物不识别】喂食扫描只查 getMaidInv()（TLM 实证：手部是独立 handsInvWrapper，不算背包）——肉排拿在女仆手上时永远找不到。修复：三条喂食路径（饱食投喂/治疗食物/牛奶蜂蜜）全部纳入主手+副手扫描（手持同饱食度优先用手上的，不再翻背包）；牛奶喂食公共动作抽出共用。触发间隔也正常化：配置阈值生效后，饥饿即喂、成功一次 3 秒冷却（原有投掷间隔），不再有"莫名不触发"
promaid 1.5.298：区块名单页跳转补齐——本页右上角新增「女仆管理」直达按钮（一键跳女仆管理页；女仆管理页点女仆行进详情页绑定/解绑，详情页有「女仆配置」直达 TLM 配置界面）；空名单提示同步改为指引右上角按钮。跳转链路全通：区块名单页 → 女仆管理 → 女仆详情 → TLM 配置
promaid 1.5.297：区块悬浮标签两修——(1)【外部可见】TLM renderFloatingText 末参（shadow）实测（javap 字节码）：false = NORMAL 深度测试（被方块/线框遮挡）、true = SEE_THROUGH 透显（TLM 女仆名字牌同款渲染）——旧版传 false，区块外看标签被遮挡，实际只有站在区块内部才看得到；两行全部改 true，任何角度、隔方块都可见；(2)【重叠修复】名字行「苔藓神庙·三（建造中）」与坐标行「创建于 x,y,z」锚点只差 0.35 格，而 0.15 字号行高约 1.3 格 → 两行叠在一起（截图实证 OCR 读成一行「苔藓神庙-214，-60 建造中」）；坐标行下移，锚点差 1.4 格、净距约 0.45 格不再重叠
promaid 1.5.296：【连接已丢失】崩溃根治 + 坐标显示/跳转真正落地——根因：v1.5.290 把 OpenBlueprintBookPacket/ProgressUpdatePacket 的 regions 区块数组 encode 改成 14 字段（追加创建坐标 r[11..13]），但【两处 decode 漏改仍读 11 字段】。后果：(a) 客户端区块永远只有 11 字段 → 创建坐标字段在传输中丢失 → 区块"创建于 x,y,z"坐标显示从未生效（玩家反复反馈"坐标显示没做出来"的最终根因）；(b) 每个区块多余 3 个坐标字符串错位到后续字段：1 个区块时 initialView 读到坐标数字（不崩但数据错乱），【≥2 个区块时 initialView 读到蓝图 id（如"maid_smart_ext:苔藓神庙·三"）→ NumberFormatException → 客户端连接损坏 → "此服务器发送了一个无效的数据包" → 连接已丢失】（日志实证：06:21:42 创建第二个区块后，06:21:55 打开手册即断连）。修复：两处 decode 改 14 字段——坐标显示、区块列表、跳转界面（区块名单行点击 → 女仆详情页；女仆详情页「女仆配置」→ TLM 配置界面）全部随此生效
promaid 1.5.295：UI 翻页陷阱全面排查——按"重要开关被翻页藏到第 2+ 页"标准审计全部界面，修 3 处：(1)【战斗自保页重排】旧版 41 行：逃生/搭高/逃跑的数值参数（22 行）夹在开关区中间，把「贴身辅助」（自动投喂/治疗主人、火把、盾牌、图腾）挤到第 3 页、「单兵战术」（近战贴脸后退等）挤到第 4 页——GUI 缩放 2 时这些关键开关根本看不见（与"自主决策按键没了"完全同类）。修复：自保行为开关 → 贴身辅助 → 单兵战术 → 页尾「自保参数」（数值集中，调参才需翻页）；所有开关现在前 2 页内可见；(2)【对话提示页】主动对话提到工作播报之前——自主决策+主动对话两个主开关都在第 1 页（旧版主动对话开关在第 2 页）；工作播报（次要）顺延；(3)【语音页】三个同名「语音包操作」按钮改名为「导入语音包/重新加载语音包/查看语音包状态」。审计结论：手册（BlueprintBookScreen）全部列表为同类条目+自适应翻页+显式翻页按钮、女仆详情页按钮位置小窗口安全、指南屏有完整章节翻页、其余板块（AI 工具 9 行/被动技能 7 行/感知开关等）第 1 页内可见——无同类问题
promaid 1.5.294：被动技能独立成大栏——配置面板【首页新增「被动技能」大栏按钮】（右列「战斗自保」正下方，与建造/挖矿等同样式的独立板块，非战斗页内小节）：落地水（含触发高度/保持/下探格数）、岩浆逃生放水、主人死亡传送共 7 行从「战斗自保」页整体搬入被动技能页；「战斗自保」页只保留主动行为（逃生与自保策略/贴身辅助/单兵战术）——布局上右列 6 按钮与左下「保存并返回」无水平重叠，矮窗口也不压按钮
promaid 1.5.293：详细设置「自主决策」按键找回——排查结论：分区一直存在（部署 jar 常量池/配置 toml 全实证），它在「对话提示」页第 14 行；该页共 30 行按窗口高翻页（每页行数 = (窗口高-128)/44），窗口高 ≤744 或 GUI 缩放大时「自主决策」被翻到第 2+ 页——第一屏只看到工作播报/主动对话，看起来就像"没了"。修复：把「自主决策」区块（开关+决策冷却+日上限+API 配额，共 5 行）整体提到对话提示页【第一屏】——任何窗口高度打开对话提示第一页第一行就是它；「工作播报」顺延为第二节。另修构建链：build_promaid.py 新增无源码陈旧 class 自动清除（v1.5.291 删除 MaidFeedAnimalCapMixin 后其 .class 残留 out 被一起打进 jar，本次起不会再发生）
promaid 1.5.292：喂食动作——自动投喂/治疗食物/蜂蜜瓶直接喂时，女仆会挥动手臂（原版摆臂动画，与投药水、给金苹果同款；服务端调用 swing 自动广播，主人可看到）；牛奶直接喂同补——所有喂食路径动作统一（含：饱食投喂、治疗食物、蜂蜜解中毒、牛奶清负面）
promaid 1.5.291：删除"杀幼保成"——畜牧数量控制功能（MaidFeedAnimalCapMixin：附近同种动物超上限时击杀多余幼年动物）整体移除：mixin 文件删除 + mixins.promaid.json 取消注册 + 配置项（animalCapControl/animalCapLimit）与面板两行删除——女仆喂食繁殖不再有任何击杀行为，动物数量交给玩家自己管理
promaid 1.5.290：六项修复（重启后实测反馈）——(1)【区块坐标不显示根治】根因：服务端 regions 已追加创建坐标（v1.5.279，14 字段），但 OpenBlueprintBookPacket/ProgressUpdatePacket 的 encode 写死 `i < 11`——坐标字段从未发出去，客户端 `r.length > 11` 恒 false 显示 "?"。修复：两处 encode 改 14 字段；【世界内区块标记显示坐标】——截图实证坐标要显示在游戏世界里"「苔藓神庙·三」（建造中）"红色悬浮文字【下方】：BlueprintAreaPreview 新增创建坐标第二行（灰色"创建于 x, y, z"，渲染在名字下方；服务端 r[11..13] 到达客户端后随 2 秒轮询刷新）；手册女仆管理页区块列表同样显示"创建于 x, y, z"；(2)【跳入水悬空修复】旧版(288)近水给水平+垂直速度"冲进去"，岸沿高一格/悬空边缘时反复小跳悬空进不了水。修复：距水面 2.5 格内直接【传送入水】（水源格内部，清摔落距离）；(3)【喂食音效+系统提示】女仆喂主人吃东西播放吃/喝音效（蜂蜜=喝、其他=吃）+ 系统消息「[maid_smart] 女仆喂你吃了 X」；牛奶同理（"女仆给你喝了牛奶，负面状态全解！"）；(4)【建造名单跳转女仆管理】手册建造名单页（VIEW_BUILD 列表）新增「女仆管理」按钮（原来只有返回/导入）+【区块详情页名单跳转】右击进入区块的详情页里，女仆名单每行原来是无动作的空按钮——现在点击跳转女仆详情页（查看/绑定/解绑区块）+【女仆配置直达】女仆详情页新增「女仆配置」按钮——点击直接打开 TLM 原版女仆配置界面（右键女仆同款：背包/外观/行为设置；新 OpenMaidGuiPacket 网络包 → 服务端按 UUID 找到女仆 → openMaidGui；512 格内找不到会提示）；(5)【蜂蜜/食物不喂根治】负面解除分支（牛奶/蜂蜜）提前到治疗分支之前（中毒+低血时先解毒再治疗）+ 饱食投喂分支【独立于其他动作】——旧版负面解除喂牛奶成功（清效果但不加饱食）→ aided 短路 → 饱食分支跳过；现在饿就喂，即使本轮已做其他动作；giveFoodToOwner 加诊断日志（latest.log 搜 "aid feed"——主人饱食度/FOODS 大小/喂了什么/背包无食物原因）；(6)【被动技能独立分区确认】配置面板「被动技能」（落地水/岩浆逃生放水/主人死亡传送）早已独立 SectionRow——重启后生效
promaid 1.5.289：投喂牛奶先查正面状态——负面解除分支的牛奶（清全部效果）加前提：主人身上【有增益效果（力量/再生/抗火等）时不喂牛奶】（牛奶会把增益一起清掉，与女仆自己喝牛奶同款前提）；此时只喂蜂蜜（蜂蜜只解中毒+饱食，不清增益）——主人中毒且有增益 → 喂蜂蜜保增益；无增益 → 牛奶全解；无中毒的其他负面且有增益 → 两者都不喂（等效果自然消失）
promaid 1.5.288：投喂机制修复 + 着火入水修复（玩家五项反馈）——(1)【蜂蜜瓶恢复投喂】蜂蜜瓶重回投喂食物清单（饱和 14.4 中等优先级；女仆自己背包的蜂蜜仍走自保解毒链路，两条链路独立不冲突）；(2)【投喂改直接喂食】自动投喂主人/治疗食物/负面解除（牛奶/蜂蜜）全部改为【直接喂】——饱食度直接加到主人（原版 FoodData.eat 语义），不再塞主人背包/手上；牛奶直接喂 = 清全部效果+空桶返还，蜂蜜直接喂 = 解中毒+饱食+玻璃瓶返还；(3)【着火入水修复】根因：女仆是陆地生物，寻路器默认避水——导航到水面格只会走到水边就停。修复：距水面 2.5 格内直接向水方向施加速度冲进去（着地时带小跳跨过岸沿），越过寻路限制；(4) 说明：区块坐标标签（v1.5.279）、替代品面板跳转女仆管理按键（v1.5.275）、配置面板被动技能独立分区均已实装——此前看不到是因为游戏自 v1.5.279 前一直未重启，本版本重启后全部生效
promaid 1.5.287：综合大版本——畜牧控制修复 + 干活不被打断补漏 + 自主决策修复 + 主人背包 AI 工具 + 建造优化 + 4 台红石机器(离线验证可运行)：
(1)【畜牧数量控制】击杀半径与统计半径统一(24 格——旧版统计 24 格只杀 4 格内,超限动物永远杀不到 = 控制失效根因)+ 命名动物不杀(宠物保护)+ 删除死代码;
(2)【干活不被打断】两处补漏：isNonCombatWork 排除 idle(旧版待机女仆也不吃工作餐/不偷吃/不恐慌——恢复空闲行为);新增 SchedulePosTickMixin 拦截每 2 秒的 home 模式周期拉回(旧版只堵了切班瞬间,周期传送拽人漏网);
(3)【自主决策】idle 判定改按任务 UID 比较(旧版对象同一性比较——第三方任务对象不同 → 自主决策永远静默不触发);
(4)【新 AI 工具 smart_owner_inventory】查看主人背包内容(只读查询,可选物品过滤,输出 id×数量+槽位区,限行防 token 爆表)——LLM 问"我背包里有什么"可直接答;配置/面板可关;
(5)【建造优化】tick 热路径 toPlan 惰性缓存(55 万步蓝图不再每 tick 全表拷贝)、scanGaps 用计划级 blockCache、缺口扫描限频键从维度改 planId(多区块互不挤占)、statusText 缺料走 countNeedsCached、延后轮询缺料条目 40 tick 退避(不再每 tick 扫空背包)、FAIL_LOG/PLAN_MAIN 惰性防膨胀;
(6)【红石机器 4 件套,全部离线红石验证通过后发布】修前置 bug:redstone_wire 无对应物品(红石粉是 minecraft:redstone)导致生存/创造都建不出线——BLOCK_ITEM_OVERRIDES 统一材料结算(含南瓜茎→种子、耕地→泥土);机器：自动甘蔗机(观察者+活塞+漏斗 3 单元)、自动南瓜/西瓜农场(茎长果+观察者检测+活塞 2 单元)、自动熔炉组(纯漏斗定向 2×2 无红石 100% 可靠)、昼夜自动灯(倒置阳光传感器+红石灯,需露天);carveEntrance 对 machine_ 前缀豁免(不开门洞破坏机器);红石件中文名补全;离线验证覆盖状态键白名单(1.20.1 合法键)/支撑可达/电源→执行器连通/信号路径
promaid 1.5.286：背包内不死图腾触发修复——根因：MaidBaubleTotemMixin 女仆自己分支只认"手 + 饰品栏"（主人共享分支反而查背包）——自保机制平时会把图腾提前放进饰品栏，但饰品栏满/未转移时背包里的图腾被白白浪费 → 秒杀直接死。修复：女仆分支补【背包查找】（findTotemSlotInInv + 真实消耗 + levelEvent 35 特效 + 气泡"不死图腾救了我一命！"）；致死伤害（含秒杀）原版都会先走 checkTotemDeathProtection（m_21262_），补上背包即全覆盖——优先级：手（原版）> 饰品栏 > 背包
promaid 1.5.285：蓝图书附魔光泽修复——根因：v1.5.251c 加过"始终显示附魔光效"但重写了错误的 SRG 方法（m_41463_，Item 里默认返回 false 的另一个方法），真正的 isFoil 是 m_5812_（javap 实证：原版附魔书 EnchantedBookItem 重写 m_5812_ 返回 true 才有光泽；m_8120_ 才是 isFireResistant）——所以光效从未生效（历史上"光效没出现"反馈的根因）。修复：改重写 m_5812_ 返回 true + 删除 10 秒节流调试日志——现在开局/合成/创造栏拿到的蓝图书天生带紫色附魔闪光
promaid 1.5.284：全链路试运行检查 + 安全加固（防再出"编译通过、运行时才炸"事故）——(1)【离线试运行 harness】（offline_check/RunProMaidCheck.java，纯 JVM 不启动游戏）：25 个内置蓝图全部生成 + 步骤可解析 + 材料统计/摘要 + 并发生成不串步；BlueprintLib 纯方法 parseStep/blueprintSize/countNeeds/cnName/trimTerrainLayers/describe 全走通；BuildPlan 头部解析 + 空输入容错；BuildArchive 序列化往返一致；13 份 .snbt 预制蓝图 21.7 万步全部可读——43 项 PASS 0 FAIL（validate 依赖 config 离线 SKIP，游戏内生效）；(2)【构建链补漏】verify 新增 src→out 全量比对：120 个 .java 源文件必须都有编译产物（防源文件漏编译——内部类 $ 由 javac 连带生成，上次 $BlockCheck 缺失就是此类盲区）；(3)【防崩溃判空】EmotionalActionExecutor.addFood 物品查询判空（防类加载即崩）、materialFamily/blockFunction/isAltPlaced 的 getKey 判空、supportBlockFor 支撑方块查询判空兜底；(4)【bug 修复】爱憎分明反射旧包名改双兼容（2.0.2 迁移 com.github.tartaricacid → com.github.JumDa5he——旧包名反射永远 ClassNotFoundException → 极端饥饿判定/情绪投影静默失效，现在新旧都认）；创造栏 modid 修复（旧写 maid_smart ≠ modId promaid → 蓝图书进创造栏从未生效，现在「建筑方块/工具」能直接拿）；zh_cn.json 重复键去重（cook/brew）；(5)【线程安全】BuiltinHouses 生成缓冲 S 改 ThreadLocal + 缓存改 ConcurrentHashMap（并发首次生成不串步）；(6)【资源清理】删除 soul_core 孤儿模型/贴图（无物品注册、未接线）
promaid 1.5.283：崩溃修复——女仆环境逃生找水时 `ClassNotFoundException: SelfPreservationBehavior$BlockCheck`(日志实证 02:03:46 女仆"汉服酒狐"手持冰火传说龙钢火斧进自保 → 着火逃生 findWater → 崩)。根因：验证脚本 verify_jar_classes.py 旧版只比对 6 个指定类，`SelfPreservationBehavior` 及其内部类从未被验证 → 某个历史构建的 jar 缺 `$BlockCheck.class` 却一路"ALL OK"部署(Java 对内部类懒加载,启动不报错,女仆第一次走"找水"路径才炸)。修复：verify_jar_classes.py 重写为【双向全量】(遍历 out 全部 221 个 .class 必须存在于 jar 且哈希一致 + jar 无多余条目 + mixin 齐全),并内联进 build_promaid.py(构建后自动自检,不通过即 FATAL);本次重建的 jar 双向验证全部通过后重新部署
promaid 1.5.282：剑单敌跳劈 70% → 100%——单敌时攻击冷却满必跳劈（空中暴击 1.5 倍）；跳劈冷却 2 秒空档由 TLM 攻击行为自动打普攻/横扫（战术只接管移动+跳劈，攻击一直由 TLM 原版 MaidMeleeAttack 执行——"普攻/横扫从哪儿来"的答案），所以跳劈 100% 不挤掉横扫；多敌仍完全不跳（群怪尽横扫），4.5~6.5 格大跳仍受 10 秒 CD 约束
promaid 1.5.281：蜂蜜瓶解毒修复 + 女仆自喝牛奶——根因：v1.5.202 轻量化后自保是常驻检查器，但蜂蜜瓶检查在【自保会话主流程内】，满血中毒（血未低到触发自保、无环境危险）时会话不激活 → 提前 return → 蜂蜜瓶永远不会喝。修复：蜂蜜解毒 + 牛奶清负面提升为【会话外也生效】的常驻轻量逻辑（每 tick 只查效果状态，有负面效果才扫背包）——被洞穴蜘蛛/毒马铃薯/药水箭中毒满血也会立刻喝蜂蜜瓶（精准解毒+回血+留玻璃瓶，只清中毒不误伤增益）；蜂蜜瓶之后，若自身【无任何增益效果】且【有负面效果】才喝牛奶（牛奶清全部效果——有增益时喝会把增益也清掉，所以前提是"只有负面 buff"；喝 1 桶清全部效果并返还空桶，原版一致；饥饿/虚弱/凋零/失明等都能解；蜂蜜与牛奶各自独立冷却）
promaid 1.5.280：近战贴脸后退——近战走位新增【贴脸后退】：敌人贴进 2 格内（= 僵尸/骷髅的近战攻击范围）主动后退拉开，退到 3 格即停——女仆手长（攻击距离 3.1）退开后照样挥砍（"女仆的手很长，完全打得到"），同时脱离敌人近战范围不再白挨刀；与打一刀退一步（攻击瞬间短撤 14 tick）互补、与跳劈衔接（贴脸不跳劈，后退拉开后再蛇形接近/跳劈——斧的"跳劈→普攻→后退"节奏对剑同样成立）；非自保天然满足（自保移动保命动作时战术行为已让位）；面板「战斗自保 → 单兵战术」新增【近战贴脸后退】开关（默认开，可关）
promaid 1.5.279：区块打标签 + 替代品多维度划分——(1) 女仆管理页区块列表【打标签】：每区块竖排两行（名字/维度/状态 + 「创建于 x, y, z」——玩家创建区块时的原点坐标；上限 6 区块防撑爆，女仆按钮自动下移避让）；(2) 替代方块多维度划分：新增两个自动判定维度——【材质族】（木/石/砖/矿/璃/陶/毛/他）与【功能】（红石/照明/存储/炉/装饰/结构），替代品面板条目显示「族·功能」标记（如「木·结构」橡木木板）；匹配升级：高度/碰撞严格匹配之上，表内【同族优先】（第一轮只扫同材质族，第二轮才扫其余）
promaid 1.5.278：手册进度显示三修——(1) 速度/预计【无条件显示】：旧版缺料停滞时速度统计 ema→0 → 进度条旁只剩"56%"（日志实证 speed=0.0 eta=-1）；现在停滞时如实显示"0.0块/秒 · 预计--"（-- = 缺料/统计窗口内无法估计），有速度时正常显示实测值；(2) 材料表"已建"按【蓝图隔离】：旧版把所有计划的已建数混在一起（石质山景别墅 + 现代红石智能住宅共用石头/木板 → 其他计划已建把本蓝图剩余需求扣成 0）→ 材料表只剩 3 种未污染的（截图：圆石墙/蓝色床/火把）；现在只扣本蓝图计划的已建，17 种材料完整显示；(3) "共 X 块"用去重后计数（旧版原始 steps.size() 含同坐标重复步骤 → "共2138块" vs 进度"2024块"不一致，截图实证 114 块差额）
promaid 1.5.277：斧特殊战术 + 图腾特效——(1) 主手为斧时（AxeItem）战斗节奏改为"每一击都尝试跳劈 → 普攻 → 后退"：跳劈概率 70% → 100%（无视单/群怪分流，旧版群怪全禁是剑的横扫节奏，斧无横扫之刃、跳劈是唯一高伤手段；4.5 格内必跳、更远需大跳受 10 秒 CD 约束先走近再跳；跳劈落地后 TLM 普攻、攻击完成自动后撤 14 tick 拉开，节奏闭环）；(2) 女仆饰品栏不死图腾触发补上原版同款特效（levelEvent 35 绿色粒子 + 音效——旧版只有复活和气泡、无特效，主人分支一直有播 35，女仆分支漏了）
promaid 1.5.276：替代品"搭一个又掉一个"根治——根源：替代品放置后被"已建判定"（主循环/延后轮询/缺口扫描三处）不认可 → 拆掉重放 → 拆→掉→捡回背包→再放→再拆 循环（掉落物回收只治标，捡回背包的删不掉）。修复：放置成功时记录该步骤的替代品（altUsed 表），三处已建判定认可"目标格=该替代品"即视为完成 → 不再拆、不再掉、不再翻倍；放置后同 id 掉落物回收降级为兜底（仅清理拆障残留/悬空废料）
promaid 1.5.275：批量优化——(1) 右击手册卡顿：25 个内置蓝图生成结果静态缓存（旧版每次打开重新生成 600~2100 步 ×25）；(2) 缺料播报 30 秒冷却（旧版 blockId 轮流缺就每 5~11 秒刷屏，日志实证）+ 有替代品时不报缺料、改报"缺 X，我用 Y 替代一下"（30 秒冷却）；(3) 放置后回收目标格附近同 id 掉落物（替代品放置 + 同类掉落并存 = 材料"翻倍"观感；276 起为兜底）；(4) 钓鱼一步一停再根治：mixin 记录原版 FindSit 椅子目标 + 每 3 tick 高频补寻路（TLM 站立等行为清 WALK_TARGET 后 3 tick 内补回，绕过 12 tick 间隙）；(5) 替代品分类扩展：两格再分【竖两格（门/高植物/甘蔗/竹子）】与【横两格（床）】，新增【无碰撞方块】单独区（花/火把/地毯等），面板 5 个分类标签 + 执行层严格匹配；(6) 替代品面板加【女仆管理】跳转按钮（新 OpenBookRequestPacket 网络包 → 服务端重新下发手册并直接打开女仆管理页）
promaid 1.5.274：钓鱼找椅子完全套用原版——删除自研 findNearbySeat（16/32 格实体扫描）+ PENDING_SEAT/SEAT_GIVEUP 走向机制：原版 FindSit 已用可见实体内存（NEAREST_VISIBLE_LIVING_ENTITIES）找椅子并设置 walk target（找到 → sitEntity 非空 → 完全走原版流畅流程，promaid 零干预）；原版没找到（不可见/被占）→ promaid 只做 7 秒宽限（原版传感器刷新窗口）→ 生成坐垫。彻底消除"原版没找到但 promaid 扫到 → 接管走向 → 每 12 tick 重设 walk target → 一步一停"的分歧根源
promaid 1.5.273：钓鱼一步一停根治（日志实证：25 格走了 18 秒——findNearbySeat 每 0.6 秒被调用，tryAutoChair 每 12 tick 无条件重设 walk target + 重写 PENDING_SEAT → 寻路每 0.6 秒重算一次）——已在走向目标（PENDING 远水坐垫 / PENDING_SEAT 现成椅子）时 tryAutoChair 直接跳过，走向由 sweep 推进（272 起仅在无 walk target 时补）——不再打断寻路；顺带修复 PENDING_SEAT 超时计时被反复重置（60 秒超时永不触发）的问题；scanGaps 全表扫描限频 60 秒（55 万步 O(N) 每 20 秒一次 tick 尖峰）+ 缺口统计日志（"建造永不完成"直接看日志定位缺什么）
promaid 1.5.272：钓鱼移动"一走一卡"修复（实测："移动方式又变成一走一卡，恢复成跟空闲状态一样"）——根因：FindSit 每 12 tick 设置 walk target，promaid sweep 每秒无条件重设 → 两者交替重置 → 寻路频繁重算 → 一走一卡。修复：补寻路只在【女仆当前没有 walk target】时进行（MemoryModuleType.f_26370_ 为空）——FindSit 已设目标时由 MoveToTargetSink 持续走（流畅），目标被清/被打断才补（PENDING 远水坐垫 + PENDING_SEAT 现成椅子两处同改）
promaid 1.5.271：收官内置蓝图——新增 15 个生存简易小屋（各 636 块，橡木/圆石/石头等易得材料、种类少，标配门/火把/熔炉/工作台/床/箱子/玻璃窗，带烟囱与三角屋顶：橡木原木/圆石/石砖/砂岩/雪原/桦木/云杉/丛林/红砖/山岩/渔屋/矿工/猎人/花园/农舍）+ 10 个进阶别墅（各 2124~2138 块，3 层 + 三角屋顶 + 塔楼 + 花园围墙 + 后院露台 + 阳台，木质/石质/砖质/现代玻璃/陶瓦等风格）——全部程序化生成（BuiltinHouses），支撑自洽可正常建造
promaid 1.5.270：手册蓝图大清理——(1) 外部蓝图（config/maid_smart/blueprints）：43 个 <2000 块的已从文件层面删除（含甘蔗农场 727/花园藤架 259/锁链吊桥 319/小神社×3/森林系列/苔藓小建筑等，备份在 analysis/blueprints_deleted_backup，需要可恢复）；(2) jar 内置预制 19 个 <2000 的删除（installBuiltinBlueprints 不再复制——否则下次启动又回来）；(3) 内置 5 个示例（小木屋/凉亭/喷泉/瞭望塔/水井 22~100 块）从代码注册移除（BUILT_IN_NAMES/getBuiltIn/buildCatalog）；(4) 手册只剩 2 千 ~ 673 万块级的大蓝图；(5) 顺带清掉 RR/SS/aaa/qqq/www 测试蓝图
promaid 1.5.269：钓鱼找椅时间延长（实测："钓鱼正常了，但找椅时间太短，有时还是会自己做坐垫"）——生成坐垫前加 7 秒（140 tick）找椅宽限：当轮 32 格扫描没找到椅子时不立即生成坐垫，每 0.6 秒 FindSit 触发都重新扫描，7 秒内找到椅子就走过去坐，7 秒后仍没有才生成坐垫（覆盖"椅子刚放置/实体列表未收录/女仆移动中"的时机差）
promaid 1.5.268：智能科技住宅"大量方块放不了"根除——日志实证：藤蔓（vine）大量 place-fail/skip（"目标现=air"）——藤蔓/发光地衣是贴墙方块，supportDirection 漏网（返回 null）→ 墙未建时直接放 → canSurvive 失败掉落 → 3 次失败永久跳过 → **墙建好后也不补** → 完成时报"悬空放不上"。修复：supportDirection 识别藤蔓/发光地衣（多方向布尔属性取贴面方向）+ 可可豆/仙人掌（贴丛林木/需沙地）→ 墙缺失时延后等墙建好再补建（悬空无墙时补石头/沙）；钓鱼椅子被占用提示（实测：自己坐在椅子上时女仆"找不到"——乘=1 被排除，现在气泡告知原因）
promaid 1.5.267：钓鱼"玩家放的椅子识别不到"修复（实测："只认自动召唤的垫子；玩家放的坐垫位置稍刁钻就识别不到，其他种类都不坐"）——(1) 找椅子范围 16 → 32 格（椅子在水边 17+ 格外时旧版扫不到 → 直接生成坐垫）；(2) 支持 TLM "座位"（EntitySit，LLM"坐下"工具实体）；(3) 椅子走向超时 30 → 60 秒，超时后记"这只椅子走不到"30 秒内转生成坐垫钓鱼（防死磕卡死），之后重新尝试；(4) 坐垫删除原因日志（sweep：女仆不在/任务非钓鱼/脱离超时）定位"生成坐垫被删循环"；(5) removeOldChairs 不删正被骑着的坐垫（防误删致女仆掉下来）
promaid 1.5.266：工头"没设置时随机设一个"真正落地——根因：v1.5.182 的补选只在建造行为 start 时跑一次，创建区块时女仆还没绑定、远程绑定 scanAreaMaids 扫不到 → chooseForeman 返回空 → foremanUuid 恒空 → isForeman 全员放行 = "所有人都能发"（完成汇报/跳过/缺料全刷屏）。修复：isForeman 遇到无工头/工头失效时【当场随机挑一只绑定该区块的活跃建造女仆顶上并持久化】再判断（服务端单线程顺序执行无竞态）；随机失败（真没人）才放行兜底防静默；工头被手动暂停仍放行（面板操作语义）
promaid 1.5.265：三修复——(1) 钓鱼"旁边有椅子/坐垫不坐"：找椅子范围 8→16 格（对齐 TLM 原版传感器半径）+ 新增 PENDING_SEAT 持续走向机制（现成椅子 2~16 格时每秒补寻路直到骑上，30 秒走不到才放弃提示，不再直接生成自己的坐垫）；(2) olymp-final 95 万方块图延后 10324 永不收敛：蓝图支撑格已加载但 10 次重试仍未建成（悬空依赖链）→ 超时跳过收敛，建造能正常完成（缺口重下达补建）；(3) 工头名存实亡：skip 气泡/缺料播报统一只由工头发（有有效工头时非工头静默——完成汇报早已过滤，这次补全跳过错报/缺料提示）
promaid 1.5.263：悬浮红石放不上修复（实测日志：甘蔗农场红石线 y=4 层 3 次失败永久跳过）——supportBlockFor 补支撑用蓝图主要建材（甘蔗农场=甘蔗）→ 红石线补在甘蔗上 canSurvive 失败 → 红石科技件（红石线/中继器/铁轨/压板/活板门/拉杆/按钮/火把等）固定补石头支撑；另修空气清除步骤的 canSurvive 误判（air 清除红石线报"目标仍空气"）
promaid 1.5.262：替代品面板按类别过滤显示（玩家建议："应该直接不显示"）——半格表只显示台阶类、一格表只显示整方块、两格表只显示两格高，类别不匹配的方块根本不出现（无需点击再拒绝；矿表面板保持全物品）+ 确认创造面板动态兼容模组物品（遍历 ForgeRegistries.ITEMS 全注册表，1 分钟缓存）
promaid 1.5.261：替代品高度类别严格匹配（需求："1 格只能用 1 格替换，半格/两格同理"）——面板添加/点击时校验类别（半格表只收台阶、一格表只收整方块、两格表只收门/植物/床/甘蔗/竹子，不匹配拒绝并提示）+ 执行层双保险（旧配置/误添加的错配条目跳过，防半格位置被一格方块顶坏建筑）
promaid 1.5.260：m_60815_ 全套误用修复（反编译实证：0 参 m_60815_ 是 isSolid 有碰撞、不是 isLiquid！日志统计对比验证）——建造支撑判定 5 处（已建实心支撑格被误判"空"→ 疯狂补沙子循环 + 红石线支撑被换掉放不上，实测甘蔗农场）+ 钓鱼 findBank 岸边判定 + 自保倒水判定 + PlayerWaterLog 水判定——统一改 getFluidState().is(FluidTags.WATER) 或语义修正
promaid 1.5.258：钓鱼大扫描卡死修复（256 实测卡死——日志实证 "Can't keep up! Running 7404ms"：单次 160 万次逐格检查 + 30 秒一次 → 服务端主线程冻结 7 秒）——大扫描改多阶段递减（A1 同层 dy=0 半径 64 ≈ 1.6 万次 5ms / A2 ±3 ≈ 11 万次 35ms / B 全垂直 -16..+32 半径 40 ≈ 29 万次 100ms 限频 30 秒）
promaid 1.5.257：钓鱼问题诊断增强（玩家提议"把玩家行为也写日志"）——玩家放置/收走水的位置日志（latest.log 搜 "player water"）+ 大扫描失败日志带判定链路统计（液体 N 格/上方空气 N/合法岸边 N——卡在哪一步一目了然）
promaid 1.5.256：钓鱼坐垫大范围找水再扩大（实测：超平坦世界水池在女仆 55 格外、高 46 层——255 的 40 格/±40 层够不到）——半径 64、垂直 -32..+64（模拟验证可找到）；找不到水/走不到水边时气泡提示（旧版只有日志——玩家体感"毫无反应"）
promaid 1.5.255：钓鱼坐垫"又放不出"修复（日志实证：女仆附近 12 格内无水 → 一直不放坐垫）——12 格内找不到水域时大范围扫描（半径 40、垂直 -24..+40，30 秒限频）最近岸边，生成标记坐垫并让女仆自动走向水边坐下（sweep 每秒推进寻路，2.5 格内上骑，60 秒超时删垫重试，任务解除自动清理）
promaid 1.5.254：缺料自动替代（先同族后自定义，按高度分类的半格/一格/两格三张表，开关在详细设置-建造栏，自定义面板同挖矿矿物/障碍物同款创造面板）+ 修复状态串从未生效（NbtUtils 无 Name 返回空气——台阶上下半/楼梯朝向/门开合补 Name 后真正恢复）+ 台阶/楼梯等价族扩充
promaid 1.5.253：世界提取"中间镂空"根因修复——1.12 老格式完整注册表映射（旧版仅 1.8 子集：天安门 1.12 地图丢 125/126 木台阶 5470 块、96 活板门 511、136 丛林楼梯 312、139 石墙 156、235-250 釉陶瓦/混凝土 1900+；159 染色陶瓦 14930 块被映射成 1.20.1 不存在的 stained_hardened_clay → 解析为空气 → 整面红墙当"清除步骤"不建 → 城楼中间完全镂空）+ 读取元数据（羊毛/陶瓦 16 色、台阶上下半、楼梯朝向、门/活板门开合全恢复）+ 状态串改规范 SNBT（doPlace 保证可解析，旧 "{prop=val}" 能否解析不确定）
promaid 1.5.252af：支撑格在蓝图内且未建 → 延后等蓝图支撑（甘蔗泥巴缺料不再跳过）+ 支撑格区块未加载不再 setBlock 静默失败（补支撑后仍空的根因）+ 已建但不合法支撑走补支撑
promaid 1.5.252ae：控制按钮只在区块内显示（旧版区块外也显示 → 点击误报"区块不存在"，实测）+ 区块外操作提示更准确
promaid 1.5.252ad：悬空误判根治（放置后目标已是目标方块即算成功——旧版 canSurvive 对已放置的玻璃/树叶/活塞等误判失败致 130 个跳过）+ 名单空提示残留修复 + 删除/打开手册诊断日志
promaid 1.5.252ac：预计完成时间修正——剩余 = 总 − 已放 − 永久跳过，除以速度（已放的不算；跳过的不会再放也不计入剩余）
promaid 1.5.252ab：红石机器建好不运行修复（红石激活提前到缺口检查之前——scanGaps 发现缺口就 return 导致 recalcRedstone 永不执行）
promaid 1.5.252aa：极速模式放置冷却归零（13 女仆从 25 块/秒提到服务器极限）+ 补支撑默认方块改蓝图主要建材（不再无中生有出石头）
promaid 1.5.252z：打开手册立即显示速度/预计时间（OpenBlueprintBookPacket 带 etaSec/speedBps，不再等 2 秒轮询）+ 进度条标签上移不再压条 + 材料表已建完条目不显示 0/0
promaid 1.5.252y：进度条百分比/速度/预计标签上移不再压进度条（截图实证重叠）+ 材料表剩余需求≤0（已建完）条目不再显示 0/0
promaid 1.5.252x：拟人化排序加骨架优先（结构类内部先搭水平外轮廓：墙圈/四角柱/屋顶边缘先立，再逐层填充内部——排序键 prio→骨架→y→x→z）
promaid 1.5.252w：材料表排除空气等不可获取方块（0/0 消失）+ 手册大目录不再显示建造进度/进度条 + 悬空跳过实锤日志（build skip/build place-fail）
promaid 1.5.252v：坐垫实心判定改碰撞箱（花/草/火把不再误当地面）+ 坐垫下方位块与手册速度/ETA 双向诊断日志
promaid 1.5.252u：建造进度字段分行显示（状态文本
 分行：进度/缺料/参与女仆各行独立右对齐，进度条随行数自适应下移）
promaid 1.5.252t：进度条上方字段出屏修复（右对齐改左锚点绘制——旧版以 x-lw 为圆心右缘偏左悬空；换行截断补省略号；蓝图名截断）
promaid 1.5.252s：坐垫贴地修复（岸格改找最上面实心块，不再悬浮/放进水里）+ 手册进度条旁显示 块/秒速度与预计完成时间（防出屏钳制）+ HUD 广播限频验证日志
promaid 1.5.252r：修复进世界第一 tick 即崩（普通代码直接引用 mixin 类被 JVM 判 invalid；钓鱼坐垫逻辑全部迁出到普通类 FishingChairService，mixin 仅留注入壳）
promaid 1.5.252q：钓鱼坐垫重做（有坐垫直接坐/无则在最近岸边生成带标记坐垫并直接坐上/任务解除或脱离坐垫自动删除）+ 建造 HUD 速度/剩余时间修复（多行折行显示、速度显示小数、总块数去头部行）+ 清理 5 处调试日志刷屏 + 建造瞬移拦截恒 false 比较修复（自动坐垫被摧毁无掉落）
promaid 1.5.252p：创造模式材料显示 -21 亿修复（MAX_VALUE 溢出短路）+ 拟人化排序扩充装饰分类（灯笼/书架/陶罐/蜡烛/地衣等）
promaid 1.5.252o：修复爱憎分明饥饿开关失效（2.0.2 作者包名 tartaricacid→JumDa5he,mixin 从未加载）
promaid 1.5.252n：参与女仆数改为绑定数口径（手动绑定/全员加入计数一致,不再按区块附近统计）
promaid 1.5.252m：悬空补支撑不再把树叶换成石头（树冠装饰恢复跳过，保护树冠外观）
promaid 1.5.252l：世界存档提取不再把石头/砂岩等建材当地形过滤（天安门 32 块根因修复）
promaid 1.5.252k：删除红石智能住宅·挖空版蓝图（挖空设计致附着物悬空、补支撑卡死下部设施,仅保留原版）
promaid 1.5.252j：建造 HUD——左上角实时显示建造速度与预计完成时间（防错位防出屏）
promaid 1.5.252i：钓鱼坐垫岸边判定修复（水面高 1 格才找岸边）+ 世界存档导入兼容带顶层目录的 zip + 悬空方块强制补支撑（不再大量跳过）
promaid 1.5.252g15：治疗链只看血量（环境优先由分支顺序保证）
promaid 1.5.252g14：治疗链跳过条件改为"正处于危险情境中"（不再看效果残留）
promaid 1.5.252g13：情境药水改用【效果判定】做正门（按规则重做）
promaid 1.5.252g12：投掷间隔按女仆记 + 主人有效果不投 + 情境中跳过治疗
promaid 1.5.252g11：投喂优先级重排——情境保命（着火/溺水）优先于低血治疗
promaid 1.5.252g10：蜂蜜瓶归为药物（只在中毒喝，不当食物）
promaid 1.5.252g9：CD key 改为【效果种类】（变体不再各算一种）+ 投喂/自喝日志
promaid 1.5.252g8：消灭药水浪费（饮用优先 / 喷溅优先 / 跳跃归情境）
promaid 1.5.252g7：药水 CD 改为【按药水种类】记（异种互不阻塞）
promaid 1.5.252g6：塞给主人的物品优先放快捷栏空位
promaid 1.5.252g5：抗火药水也归为情境药水（不通用乱喝）
promaid 1.5.252g4：投喂药水形态修正 + 情境药水不乱喝
promaid 1.5.252g2：女仆投喂主人的药水补全（水肺/增益）
promaid 1.5.252g：情境药水系统（溺水喝水肺 / 中毒喝蜂蜜 / 增益 CD=效果时长）
promaid 1.5.252f：工作卡住播报降频（20 秒才说一次）
promaid 1.5.252e：去掉冶炼，回归纯烹饪
promaid 1.5.252d：回退复杂化，回归简洁
promaid 1.5.252c：烹饪/酿造按女仆绑定调控 + 炉子/酿造台独占（v1.5.252d
promaid 1.5.252b：手册新增"烹饪和冶炼"/"酿造"调控两页
promaid 1.5.252：烹饪和冶炼重写（烟熏/高炉/熔炉 + 燃料修正 + 坐下绑定）+ 酿造台坐下 + 灵魂核心移除补全
promaid 1.5.251e：灵魂核心功能移除 + 手册附魔光效验证
promaid 1.5.251d：灵魂核心键位冲突修复 + 附魔光效 + 手册改蓝色
promaid 1.5.251c：同存档双分身防护（一魂一仆）
promaid 1.5.251b：记忆开关加固（磁盘优先 + 未加载女仆可关）
promaid 1.5.251：物品纹理换色 + 记忆世界/时间标注 + 灵魂共享存储（双向同步/克隆继承）
promaid 1.5.250：三处 SRG 错用根因修复（放水 / 记忆开关 / 记忆目录）
promaid 1.5.249：记忆开关"关了又开"根因修复 + 放水双向诊断
promaid 1.5.248：农场"走一步停一步"修复（批量种植/连锁收割性能优化）
promaid 1.5.247：修正"包里什么都没有"误导文本
promaid 1.5.246：放水失败定位诊断（有水桶却放不出水的排查版）
promaid 1.5.245：自保会话进出防抖 + 高血量着火不喊救命（日志审查修正）
promaid 1.5.244：WorldProbe 启动预热加载（"让女仆帮忙填坑"报错修复）
promaid 1.5.243：着火链路补末影珍珠逃生（"跳入水坑和用末影珍珠都没有了"）
promaid 1.5.242：记忆开关"关了一会儿又变回开"修复（显示 + 持久化双管）
promaid 1.5.241：逃跑避让岩浆 + 搭高防跌落修复（getValue 全链替换为注册名比较）
promaid 1.5.240：修复"有水桶却说没招了"——hasWaterBucket 改 getKey + 放水链
promaid 1.5.239：修复启动崩溃（真正根因）——追踪药水 mixin 目标类改声明者
promaid 1.5.238：修复启动崩溃——追踪药水 mixin 方法名漏写 SRG 名
promaid 1.5.237：末影珍珠逃生改原版投掷特效（紫色轨迹 + 落地传送爆炸）
promaid 1.5.236：岩浆误报"卡住"修复 + 农场批量种植（与连锁收割同设置格式）
promaid 1.5.235：自保播报精简（不聒噪）——只留危险/求救，删光动作汇报
promaid 1.5.234：阶梯判定思想推广——环境逃生补全阶梯 + 回血资源阶梯化
promaid 1.5.233：判定阶梯（岩浆 300 > 着火 280 > 自保 250）+ 链路全失败让位恢复
promaid 1.5.232：岩浆/着火链路按玩家规范重写 + 避让降级为仅移动 + 全失败"我没招了"播报
promaid 1.5.231d：语言检测改自动重刷（直到中文才放行）+ 背包满明确"我给不了东西"
promaid 1.5.231：着火不逃窜（朝主人走）/ 追踪药水弹 / 死亡传送全维度 / 女仆烧死兜底 / 记忆防注入污染
promaid 1.5.230：放水判定补强（岩浆放水 fallback + 着火多位置）
promaid 1.5.229：岩浆判定全面优化（感知半径/逃生顺序/抗火豁免/地狱特判）
promaid 1.5.228：投喂/火把/盾牌从出生起就没运行过的根因修复（canStillUse）+ 死亡传送落点贴地 + 日文根治
promaid 1.5.227：主人死亡传送安全落点（女仆"消失"）+ 系统消息刷屏根治 + 记忆开关显示修 + 投喂/火把运行时诊断
promaid 1.5.226：AI 记忆开关真正生效（事件源守卫 + 客户端状态同步）
promaid 1.5.225：修复编译链（5 个编译错误）+ 锄头黑名单 + 抗火豁免补全 + Brain 诊断
promaid 1.5.224：手册"导入世界地图"按钮——玩家自助提取，无需手动放文件
promaid 1.5.223：世界存档 ZIP 提取（"Tiananmen Palace.zip" 实测打通）
promaid 1.5.222：构建链上限放开到 50 万 + ZIP 打包蓝图解析
promaid 1.5.221：区块材料表单（0/88 页）公式修正——已建 + 女仆背包 + 玩家背包
promaid 1.5.220：手册"导入建筑"按钮（文件选择器 + 版本警告确认 + 服务端解析校验注册）
promaid 1.5.219：链路调试页按钮重叠修复（刷新 vs 重要度 / 页码 vs 标记删除恢复）
promaid 1.5.218：建造悬空方块根治（门/活板门/中继器支撑判错）+ 材料缺口公式修正（已搭建+主人+女仆）
promaid 1.5.217：图腾触发系统消息 + 盾牌诊断日志 + 语音包按钮反馈 + 玩家伤害模式 4 + 音量注释
promaid 1.5.216：岩浆脱困五项修正（walk-out 时限/抗火豁免/逃跑防抖/范围云/卡墙误报）
promaid 1.5.215：岩浆水桶时序修复 + TTS 音量 mixin FATAL 修复 + 投喂/火把诊断日志
promaid 1.5.214：修复进入世界卡死（Server thread 自锁）——农场扫描/自保扫描加区块加载检查
promaid 1.5.213：坐下受伤立刻站起来（锁移动判定保留，仅加受伤起身）
promaid 1.5.212：删除施工区避让行为 + 坐下锁移动根治（每 tick 判定）
promaid 1.5.211：着火分支尾部"贴脸反击"兜底（逃出岩浆带火的 15 秒窗口收口）
promaid 1.5.210：着火分支"抗火/找水"位置互换
promaid 1.5.209：岩浆逃生分支重构——walk-out 加时限 + 主分支 2 逃生链路重排 + 岩浆内/烧伤职责分离
promaid 1.5.207：玩家对女仆伤害策略（面板可调——TLM 原版压制 / 完全免疫 / 无限制 / 有上限）
promaid 1.5.206：投喂/治疗策略全面化——状态感知优先级链，不再只投喂单一药水/食物
promaid 1.5.205：对话语言根治（TLM 聊天 GUI 也强制中文）+ 治疗药水判定修复 + 图腾扣减修正
promaid 1.5.204：不死图腾真实消耗 + 岩浆感知/逃生大修（播报/无水自救/避让）+ 放水 3 秒回收 + 建造两步流程解锁
promaid 1.5.203：搭高安全高度配置化（与落地水触发高度配对）
promaid 1.5.202：轻量级自保（落地水格式）——边打边保命，不再与战斗冲突
promaid 1.5.201：喂食按饱和度恢复量排序 + 金苹果改即时增益道具（不再当常规食物）
promaid 1.5.200：自保退出稳定期（防 70% 上下浮动频繁进出）
promaid 1.5.199：自保逻辑链修复（搭高积极性/传送保命/围殴喝药）+ 水桶垫水 + 岩浆逃生 + 环境提示 + 爱憎分明饥饿开关
promaid 1.5.198：TTS 音量倍率 + 系统消息朗读（训练一次缓存复用）+ 系统语音包导入 + 记忆 API 绑定 + 对话语言强制
promaid 1.5.197：自绘蓝图大小无限制 + 只入册不自动动工（防止拆周围）
promaid 1.5.196：LLM 查询-行动闭环 + 感知查询工具 + 工作清单 + 画蓝图防超时（移植 PatchouliAI）
promaid 1.5.195：威胁判定扩大——所有携带仇恨的生物（含中立反咬/主人被攻击）+ 文案"敌人"
promaid 1.5.194：搭方块中途窒息封头（替换"搭完后糊脸"）+ 所有系统对话青色
promaid 1.5.193：女仆说话的时宜——敌袭状态冻结情绪价值/主动对话 + 系统提示特殊颜色
promaid 1.5.192：Promaid 手册——女仆工作链路调试面板 + 改名
promaid 1.5.191：女仆大脑升级——7 阶段主动对话 + 配额改革 + 记忆维护周期 + 回复反馈学习
promaid 1.5.190：AI 双手工具 + 记忆系统修复 + 面板修复（全链路排查）
promaid 1.5.189：全能管家扩展——农业畜牧运维 + 玩家贴身辅助 + 环境交互
promaid 1.5.187b/188：死循环修复 + 区块范围精确化 + 建造确认流程 + 战斗调整
promaid 1.5.187：删掉站桩围壁，改为"拿方块糊怪物的脸"
promaid 1.5.186：自保搭高统一——不再按敌人近战/远程划分
promaid 1.5.185：大跳劈距离修复——触发距离与实际可达距离一致
promaid 1.5.184：跳劈重构——普通跳劈 = 玩家同款垂直跳 + 玩家式暴击结算
promaid 1.5.183：修复绑定失败 + 女仆管理显示问题
promaid 1.5.182：女仆管理 UI 重构（详情页绑定 + 区块名单/工头）
promaid 1.5.182：普通跳劈 = 玩家跳跃高度 + 修复"莫名其妙跳一下"（跳劈动作同步）
promaid 1.5.181：大跳劈降低高度（不触发落地水）+ 大跳 10 秒 CD
promaid 1.5.180：多区块共存 + 无女仆创建 + 女仆-区块显式绑定（架构级重构）
promaid 1.5.179：缺料数字改为实时计算（需求 − 已建 − 绑定女仆/主人背包）
promaid 1.5.178：区块内控制限制 + 女仆管理升级（区块列表/命名/绑定解绑）
promaid 1.5.177：暂停 = 解除绑定——暂停后女仆可以停下来去干别的事
promaid 1.5.176：修复游戏加载世界时崩溃（MixinTransformerError 致命错误）
promaid 2.0：建造系统彻底重构（单计划状态机 + 统一已建感知 + 区块内右击进详情）
promaid 1.5.175：跳劈斩改抛物线大跳（玩家指定"那种抛物线曲线"）
promaid 1.5.174：跳劈触发重构（距离触发 + 人数分流）+ 取消"平A"概念
promaid 1.5.173：建造不启动根因修复（TLM 时间表 activity≠WORK → 任务行为不被评估）
promaid 1.5.172：连锁采集改为同时破坏（FTB Ultimine 式）+ 挖矿换镐改目标驱动
promaid 1.5.171：控制按钮不再依赖玩家位置（修复"继续建造按钮消失"）+ canUse 诊断 + 清理残留存档
promaid 1.5.170：建造死锁修复（被拒时看不到计划位置→无法取消）+ 恢复诊断日志
promaid 1.5.169：手中正在使用的工具/武器/盾牌不触发切换，除非即将用坏自动换下一个
promaid 1.5.168：附魔装备黑名单保护（即将用坏）+ 评分翻转（附魔>耐久）+ 镐切换挖掘等级对标
promaid 1.5.167：武器切换优先级重写（DPS>耐久>附魔）+ 三叉戟自保确认覆盖 + 记忆调试面板
promaid 1.5.166：弓/弩自保失效修复（StartAttacking 断源）+ 御币武器切换修复 + 自保诊断日志
promaid 1.5.165：血机制解除自保后第一件事 = 定位主人并传送过去
promaid 1.5.164：建造区块红色固定框 + 自保退出传送 + 跳劈连贯性 + 挖矿诊断日志
promaid 1.5.163：连锁采集 / 连锁收获的范围可自定义
promaid 1.5.162：建造区块标记机制 + 控制按钮按区块显示 + 去掉强制建造/强制续建
promaid 1.5.161：进阶采集——挖矿连锁采集/自动收集 + 农场连锁收获/自动收集（默认关闭）
promaid 1.5.160：详情页控制按钮随"有无进行中计划"动态显示
promaid 1.5.159：手册建造面板 UI 重做 + 区块显示（建造范围预览）
promaid 1.5.158：自保提示矛盾消除——威胁播报/退出播报区分 + 传送免触发窗口
promaid 1.5.157：搭高不再扔珍珠 / 传送重试封顶 5 秒（旧配置 60 秒不跟随修复）/ 自保解除播报
promaid 1.5.156：建造"瞬间完成"根因修复——建材等价不再算"已建"
promaid 1.5.155：跳劈全程禁横扫 / 挥砍延迟 / 跳劈斩弧线加高 / 跳劈不后撤
promaid 1.5.154b：跳劈斩改为"跳向"敌人（抛物线弧线，非贴地冲刺）
promaid 1.5.154：跳劈斩（30% 概率冲向敌人 + 大击退），其余普通垂直跳
promaid 1.5.153：单敌必跳劈 + 自保触发/取消机制重定义
promaid 1.5.152：跳劈/横扫按敌人数分流 + 自保全程实时传送判定
promaid 1.5.151：传送安全半径默认 4→5 格（防远程怪；魂符可兜底绝对安全）
promaid 1.5.150：自保传送只判定主人身边安全（撤销"自己身边无怪"拦截）
promaid 1.5.149：跳劈"只跳不打"根因修复——空中挥砍由行为亲自执行 + 明显暴击提示
promaid 1.5.148：半成品原点识别改为"世界方块种类 ∩ 蓝图"交集锚点（方案）
promaid 1.5.147：御币弹幕还击（遵循御币原版攻击方式）/ 取消后续建识别兜底
promaid 1.5.146：跳劈高度回调（0.8 ≈4 格 → 0.5 ≈1.7 格，和玩家差不多）
promaid 1.5.145：自保近身反击支持远程武器（弓/弩贴脸直接放箭）
promaid 1.5.144：生存模式续建修复（缺料步骤不再被截断丢弃）/ 缺料播报中文名
promaid 1.5.143：障碍播报带矿物名 / 自保近身回击 / 跳劈加高+暴击特效
promaid 1.5.142：进阶装备控制（副手盾牌 + 饰品栏图腾）/ 跨维度跟随 / 蛋糕可吃（整块回复7切片量）/ 建造强制坐下
promaid 1.5.141：平A横扫修复 / 后撤加强 / 蛇形走位 / 攻击词条过滤
promaid 1.5.140：挖矿拾取/中文播报 / 删除建造传送 / 搭建速度档位硬限 / 删除伐木 / 搭方块边缘保护 / 换武器词条匹配
promaid 1.5.139：挖矿耐久根治——软方块判定从"硬度"改为"镐正确工具"
promaid 1.5.138：挖矿耐久对齐伐木 / 自动换武器只换空手 / 伐木补强（砍树叶+垫高+中文名）/ 建造传送根治
promaid 1.5.137：修复两个 bug（虚空误判疯狂传送 / 手册按钮重叠）
promaid 1.5.136：战斗指挥工具（smart_attack）——AI 对话直接下令开打
promaid 1.5.135：自保盲区修复（自然伤害/无来源伤害/非 Monster 生物）+ 骷髅对策
promaid 1.5.134：单兵作战战术（PVP 式战斗）——删除战斗协同与整理任务
promaid 1.5.133：新增伐木任务（maid_smart:woodcut）——TLM 缺失的高需求任务
promaid 1.5.132：战斗任务增强——协同作战（共享目标 + 护主集火）
promaid 1.5.131：AI 聊天/记忆大脑链路全面核查 + 记忆可诊断性改进
promaid 1.5.130：产出型任务专项增强（农场连收连种 + 钓鱼主动找水域）
promaid 1.5.129：TLM 原生任务通用呆滞修复 + 干活不被打断（两个总开关可回滚）
promaid 1.5.128：输入框 StackOverflowError 根治（真正的 setTextColor 是 m_94202_）+ 崩溃日志确认旧 jar 缺内部类
promaid 1.5.127：挖矿"愣 2~3 秒"根治（直接导航 + 扫描重建提速）+ 整理任务大升级
promaid 1.5.126：主人防窒息保护 + 材料提示中文名 + 输入框根治（照搬原版搜索框）
promaid 1.5.125：创造模式"缺 21 亿材料"整数溢出根治（不建造链路之一）
promaid 1.5.124：建造根治（暂停改内存态）+ 行为不再 3 秒重启 + 挖矿节流减半 + 输入延迟提交
promaid 1.5.123：三 bug 根治（挖矿"一步一停"根因 / 配置面板输入 / 下达后不建造根因）
promaid 1.5.110：配置面板每项注释 + 全部文本"偏左超出屏幕"修复
promaid 1.5.109：上一版 4 个问题真正修复（换镐/搭高漂移/不停传送/安全区传送）
promaid 1.5.108：建造"没规划就提前传送"修复（根因：存档静默恢复旧计划）
promaid 1.5.107：挖矿按需换镐（不再无条件切最高级）+ 耐久核实
promaid 1.5.105：记忆系统 ×（心契誓约 + 爱憎分明）联动全修（优雅降级）
1.5.122：挖矿"完全不动"修复 + 面板输入修复 + 建造诊断日志
1.5.121：建造恢复 home 模式（回归修复）+ 挖矿移动容差 + 面板输入聚焦
1.5.120：感知播报"分时宜"——危险时停止不合时宜的非紧急感知
1.5.119：敌对感知显示降频（感知检测照常，仅显示频率降低）
1.5.118：挖矿移速对齐 TLM 伐木（0.6）+ 部署 116/117
1.5.117：建造侧传送从根源停用（玩家决策）+ 撤销强制 home 模式
1.5.116：挖矿"一走一停"修复 + 建造被埋判定消抖（诊断预备）
1.5.115：确认建造 → 施工区【一次性清场传送】（按玩家预期修订）
1.5.114：建造逻辑深度优化（A 正确性 + B 性能 + C 手感 + D 清理 全组实施）
1.5.113：挖矿机制深度优化（A 性能 + B 正确性 + C 手感 + D 清理 全组实施）
1.5.112：自保传送节奏 + 死亡传送重定位 + 换工具评分分离 + 手册注释全面重写
1.5.111：标题居中模板 + 挖矿漂移根治 + 建造传送修复（3 大项）
1.5.104：审查建议实施——确认弹窗 + 建造完成通知 + 优化
1.5.103：全模组审查修复（1 高 + 4 中）+ 优化
1.5.102h：修复 heartfelt SmartPromptMixin（与 102g 同源的第二个崩溃点）
1.5.102g：修复 PromaidPromptMixin 注入非法导致女仆对话崩服
1.5.102f：模组镐评分兜底（模组武器/附魔兼容确认）
1.5.102e：修复耐久扣错对象 + 方块秒破（旧版残留问题）
1.5.102d：矿表面板/搜索/障碍物预勾选 + 换镐升级 + 拖拽削弱 + 无矿挡路上报
1.5.102c：进度文字右对齐 + 报点中文名 + 石质方块开路
1.5.102b：修复建造中进度条/进度文本贴出屏幕底边
1.5.102：全模组数值面板化——所有剩余硬编码数值全部纳入配置面板
1.5.101f 末影珍珠逃生 CD 缩短 + 数值全部进配置面板
1.5.101e 珍稀掉落物捡不到提示（气泡 + 主人聊天栏双提示）
1.5.101d 珍稀标记矿物（掉落物回收改为"标记格"机制 + 手册第三个创造物品栏名单）
1.5.101c 挖矿掉落物隔墙回收 + 拾取优先级按价值（原版低价值 0.5）
1.5.101b 挖矿黑白名单升级（目标矿物 + 障碍物 双名单，创造面板 toggle + 输入添加恢复）
1.5.101 修复 AI 记忆开关崩溃（TaskData ByteTag 强转 CompoundTag）
1.5.100d 修复女仆莫名传送（施工区防接近传送无冷却反复拽）
1.5.100c 开路白名单批量扩容（原木等自然方块）+ 矿物扫描加速
1.5.100b 挖矿目标拖拽 + 矿表创造面板 + 记忆页全面增强 + 面板细节修正
1.5.100 配置面板重构（手册式跳转+翻页）+ 手册目录按钮调小
1.5.99c 挖矿挡路判定根因修复（SRG 映射错误）+ 自动装备全面激活
1.5.99b 感知播报全局限频 + Blocker 崩溃排查
1.5.99 配置面板 UI 重构（可滚动 + 加大行距 + 标签对齐）
1.5.98c 修复站桩女仆溺水 + 主人注视感知刷屏
1.5.98b 启动崩溃修复（换回原版 TLM 后 mixin apply 失败）
1.5.98 关系记忆适配层（模组特色联动：记忆系统软感知心契誓约×爱憎分明）
1.5.97 Soul 灵魂系统（跨存档/换女仆迁移记忆）
1.5.96 全子系统精准开关体系（防未来 agent 冲突）+ Soul 系统评估
1.5.95 女仆大脑全面加强（记忆 6 项增强 + maidsoulcore 4 个子系统借鉴）
1.5.94 AI 画蓝图（子 Agent 设计器）+ 蓝图手册删除
1.5.93 站桩锁死位移（治"坐着/站桩女仆诡异地动"）
1.5.92 建造期传送抖动根治（建仆强制 home 模式，从 TLM 源头断跟随）
1.5.91 自保传送加固（双判定 + 珍珠落点安全）
1.5.90 挖矿穿墙 + 任务工具自动装备（修复"主手有镐仍不挖挡路方块"）
1.5.25 落地水（被动生存技能）——女仆自动落地水
1.5.25 续建修复（生存分批建造闭环）——超大型建筑（上万块）背包放不下，
1.5.9（BALANCED 补丁）：修复"第 6 格误判"——爱憎分明原版逻辑把女仆背包第 6 格
1.5.25（当前）：搭方块/挖矿搭高/酿造全自动/整理增强（测试反馈）——
1.5.24：五项测试反馈修复 + 海景房蓝图 + 材料展示重构 + 6 种风格建筑——
1.5.23：自保"可见性"修复（测试反馈反思）——
1.5.22：挖矿回归修复（测试反馈）——
1.5.21：自保优化（保命道具/威胁感知/智能逃生）——
1.5.20：自保状态机重构（新逻辑）——
1.5.19：挖矿渐进化（对齐 maid_useful_task 伐木逻辑）——
1.5.18：蓝图卷轴移除 + 触发方式重述 + 手册材料缺口——
1.5.17：四问题修复（测试反馈）——
1.5.16：三入口建造闭环（非 LLM 全流程 + LLM 状态查询）——
1.5.15：预制精美建筑（5 套，首次启动自动安装）——
1.5.14：复杂精美建筑能力（迁移 numen BlueprintFormats）——
1.5.13：建造体验优化 + 蓝图获取生存化——
1.5.12：numen 式结构文件蓝图迁移——
1.5.11：不依赖 LLM 的建造触发方式 + 建造种类/数量扩展——
1.5.10：建筑链路重构（借鉴 numen 蓝图设计）——
1.5.9
1.5.8：小女仆与父亲的剧情记忆——child_state/child_lineage 的
1.5.7：自保不再"抽空打怪"（每 tick 清攻击目标，Brain 各优先级组
1.5.6：工作状态播报——女仆选了 maid_smart 任务却不干活时，每 10 秒
1.5.5：记忆写入崩溃修复——TLM 的 TaskData 用 unboundedMap codec 解码
1.5.4：借鉴史诗攻城 + numen AI——
1.5.3：任务切换修复（createBrainTasks 必须返回可变列表——TLM 的
1.5.2：任务修复（行为有目标才启动，不再空转发呆，无目标时正常漫游）、
1.5.1：自保升级——覆盖一切状态（不限战斗）、优先级 250 全局最高（压过跟随/任务/睡觉/恐慌）、双退出条件恢复原状态、直接寻路逃跑
1.5.0：战斗自保（低血逃跑/进食/搭方块，纯规则零 LLM）
1.4.1：建筑材料判定升级——缺料时先问玩家"建一半还是放弃"（mode=full/partial）
1.4.0：建筑功能（smart_build 工具 + 3 个内置蓝图 + LLM 生成蓝图 + 材料判定）
1.3.0：心契誓约剧情记忆（结婚/怀孕/心情/丧子/告白 实时注入 AI 对话）
1.2.0：情绪价值动作（跑过来/递食物/看向/撒爱心）+ 家庭保护（防同主女仆互殴）
1.1.0：新增烹饪/酿造任务、自主决策（空闲自判任务）、长期记忆（事件写入+context 注入）
1.0.0：P1 四工具 + P2 挖矿/整理 + P3 主动对话
