Improve crab trap underwater placement behavior and preview 优化蟹笼在水下放置的手感与预览 - #4965
Conversation
- 调整 LargeBlockPlacePreviewEventListener 以支持 PlaceInWaterBlockItem 在非水下时贴水面放置 - 使用流体射线重新计算水面放置落点,避免依赖 mc.hitResult - 增加尝试多个放置候选点的逻辑,保证预览和实际放置位置一致 - 修改 PlaceInWaterBlockItem,水下时走普通方块放置逻辑,水面时使用流体射线定位放置点 - 提供 surfaceCandidates 方法列举水面放置的所有可能落点上下文 - 简化渲染代码中空检查,提升代码可读性与安全性 - 修复 currentPos 判断逻辑,避免空指针异常
代码审查摘要 — PR #4965操作: opened(state=open, mergeable=true) 🔴 关键问题(必须修复)1. private static BlockPos currentPos = null; // L72
...
private static void validateCanRender(ItemStack item, BlockItem blockItem, BlockPos pos) {
...
if (!currentPos.equals(pos)) { // L538 ← currentPos 恒为 null
currentPos = null;
failBoundCooldown = 0;
}
}本 PR 顺手删掉的那两行,恰恰是全类中唯一给 - if (currentPos == null) {
- currentPos = pos; // ← 唯一赋值点,被删除
- } else if (!currentPos.equals(pos)) {
+ if (!currentPos.equals(pos)) {
currentPos = null;
failBoundCooldown = 0;
}我已在目标分支上交叉验证:
建议修法(保持原意的同时消除 NPE,改动方向反过来比较更安全): if (!pos.equals(currentPos)) {
currentPos = pos.immutable();
failBoundCooldown = 0;
}(原逻辑本意就是「预览目标位置变化时重置
|
| 声称 | 状态 | 对应实现 |
|---|---|---|
| 优化水下放置手感 | ✅ | PlaceInWaterBlockItem.useOn() 水下走 super.useOn();use() 水下 early-return PASS |
| 优化水下预览 | ✅(但当前被 NPE 阻断) | surfaceCandidates() + 预览端候选循环 / 水下退化为普通方块预览 |
| 预览与实际落点一致 | ✅ 逻辑一致 | 共享 surfaceCandidates() + 单侧 break 条件对齐 |
| — | ❌ | validateCanRender() 的 currentPos NPE 使预览完全不可用(回归,非声称内容) |
结论: REQUEST_CHANGES — 改动思路正确、抽取得干净,但 LargeBlockPlacePreviewEventListener.validateCanRender() 中 currentPos 的必然 NPE 是硬回归:所有可预览方块(含本 PR 的主角蟹笼)的放置预览都会失效/抛异常,修掉后即可合并。
🧪 测试建议
| 被测目标 | 推荐场景 | 优先级 |
|---|---|---|
validateCanRender() |
从 currentPos == null 起步连续调用两帧(不得抛 NPE);同位置不重置 failBoundCooldown,位置变化则重置 |
🔴 |
PlaceInWaterBlockItem.surfaceCandidates() |
射线 MISS → 返回空列表;命中 → 恰好 2 个候选且顺序为「命中格 → 沿朝向偏移格」 | 🟡 |
use() / useOn() 水下分支 |
水下 use() 返回 PASS 且不产生放置;水下 useOn() 委托 super(可用假上下文断言不返回 PASS) |
🟡 |
| 端到端手动验证 | ①水下对实心方块右键;②水下对开阔水面右键;③水面(非水下)右键;④两个候选都放不下时不显示预览 | 🟡 |
关于 PR 标题: 当前标题为 Improved the feel and visibility of the crab trap when submerged. 优化了蟹笼在水下放置时的手感和预览——英文部分带多余句号,且 "visibility" 表述不准确(本次改的是放置预览,不是可见度)。我尝试用 gh pr edit 规范化,但 gh auth status 显示 The token in /opt/data/home/.config/gh/hosts.yml is invalid(Active account 存在但 token 失效),按流程未尝试导出 token,故未自动修改。建议改为:
Improve crab trap underwater placement behavior and preview 优化蟹笼在水下放置的手感与预览
由 Hermes Agent 审查
|
Diff fully analyzed and cross-verified against the target branch. Here is the review: 代码审查摘要 — PR #4965操作: edited( 🔴 关键问题(阻塞合并)1. // head
if (!currentPos.equals(pos)) { // ← currentPos 只可能是 null
currentPos = null;
failBoundCooldown = 0;
}
if (currentPos == null) {
currentPos = pos;
} else if (!currentPos.equals(pos)) {
currentPos = null;
failBoundCooldown = 0;
}
|
| PR 声称 | 状态 | 对应实现 |
|---|---|---|
| 优化蟹笼水下放置手感(水下走普通方块放置) | ✅ | PlaceInWaterBlockItem.useOn L37-44 + use L74-78 早退 |
| 水面落点预览与实际放置一致(多候选逐个尝试) | ✅ | surfaceCandidates + 预览 L156-171 循环 + use L79-85 |
| 简化渲染代码空检查"提升安全性" | ❌ | renderMissingAmplifierGhosts 等价但越界;validateCanRender 引入必现 NPE |
修复 currentPos 判断"避免空指针" |
❌ | 反向:删掉唯一的 null 保护 |
结论: REQUEST_CHANGES — ①validateCanRender 的 currentPos.equals(pos) 必现 NPE,任何手持可预览方块(含 crab_trap)的客户端一帧内崩溃,必须还原 base 写法;②建议把两处与本主题无关的空检查改动从本 PR 剥离(其中 L538 那处即为 ①)。水面/水下候选逻辑本身方向正确、抽象干净,修掉 ① 后即可合并。
🧪 测试建议
| 被测目标 | 推荐场景 | 优先级 |
|---|---|---|
validateCanRender() |
首次构造(currentPos == null)即调用一次,断言不抛 NPE;落点原位/换位交替各一轮,断言 failBoundCooldown 不被每帧清零 |
🔴 |
PlaceInWaterBlockItem.surfaceCandidates() |
射线 MISS → 返回空列表;命中 → 长度 2 且第 2 项 = getBlockPos().relative(player.getDirection()) |
🟡 |
use() |
水下 → PASS(不消耗、不放置);非水下候选 1 成功 → 只尝试 1 次;候选 1 失败候选 2 成功 → 使用候选 2 |
🟡 |
| 端到端(手动) | 水面上/眼睛入水 × 瞄水/瞄实体方块/瞄空气 六宫格,比对鬼影位置与实际落点 | 🔴 |
备注:
gh auth status显示/opt/data/home/.config/gh/hosts.yml中 token 已失效(Active account: Gugle2308),故未执行标题修改。当前标题内容准确、英中齐全,若想更精确可改为:Improve crab trap underwater placement and water-surface placement preview 优化蟹笼水下放置与水面放置预览(本次因 gh 未认证未自动修改)。
由 Hermes Agent 审查
|
💾 Self-improvement review: Patched SKILL.md in skill 'style-refactor-pr-review' (1 replacement). |
|
💾 Self-improvement review: Skill 'removed-guard-regression-review' created. · Skill updated |
Reason: script execution via -e/-c flag Reply |
|
我已获取并核对 diff、目标分支与 PR head 的完整源码。以下是审查结论。 代码审查摘要 — PR #4965操作: 🔴 关键问题(必须修复,否则会崩溃)1. // L72 private static BlockPos currentPos = null; ← 字段初始值就是 null
// L531-541(修改后)
private static void validateCanRender(ItemStack item, BlockItem blockItem, BlockPos pos) {
...
if (!currentPos.equals(pos)) { // ← currentPos 恒为 null → NPE
currentPos = null;
failBoundCooldown = 0;
}
}被删掉的
建议修复(恢复原状即可): if (currentPos == null) {
currentPos = pos;
} else if (!currentPos.equals(pos)) {
currentPos = null;
failBoundCooldown = 0;
}
|
| 声称 | 状态 | 对应文件 / 依据 |
|---|---|---|
| 优化水下放置手感(水下按普通方块放置) | ✅ | PlaceInWaterBlockItem.useOn() 水下 super.useOn + use() 水下提前 PASS |
| 只有陆上保留贴水面放置 | ✅ | use() 的 isUnderWater() 守卫 + surfaceCandidates 不变 |
| 优化预览(与实放同顺序) | LargeBlockPlacePreviewEventListener.updatePreview() 按候选逐个判定,方向正确但判定谓词与实放不同源(见 |
|
| 顺带清理冗余 null 守卫 | renderMissingAmplifier* 两处 ✅ 真冗余;validateCanRender 一处 ❌ 误删(→ 🔴1) |
🧪 测试建议
| 被测目标 | 推荐场景 | 优先级 |
|---|---|---|
validateCanRender() |
连续两次以不同 pos 调用(含首次 currentPos == null)→ 断言不抛 NPE、currentPos 被正确赋值 |
🔴 |
PlaceInWaterBlockItem.use() |
玩家在水下右键空气 → 返回 PASS 且无放置;水上 MISS → PASS;候选 #1 放不下时落点切到 #2 且结果一致 | 🔴 |
PlaceInWaterBlockItem.surfaceCandidates() |
射线 MISS → 空列表;命中 → 恰好 2 个上下文且第 2 个沿 player.getDirection() 偏移 |
🟡 |
| 预览/实放一致性 | 同一 LocalPlayer 状态下预览 cells 首格 == 实放落点(含水下退化为普通放置分支) |
🟡 |
useOn() |
context.getPlayer() == null(非玩家路径)→ 仍返回 PASS,不误放置 |
🟢 |
结论: REQUEST_CHANGES — 方向正确、清理与预览一致性改进都很好,但 validateCanRender() 的 NPE 是必崩的回归,恢复那一行 null 初始化(或改用 Objects.equals + 保留赋值)后即可合并。已核对 PR 标题(英文 + 中文齐全),未作修改。
由 Hermes Agent 审查
- 将 currentPos 标记为可为空,避免未初始化时的空指针错误 - 在比较之前增加 null 判断,防止空指针异常导致程序崩溃 - 优化 currentPos 赋值逻辑,确保正确更新位置状态 - 解决 failBoundCooldown 状态未正确重置的问题
|
💾 Self-improvement review: Patched SKILL.md in skill 'removed-guard-regression-review' (1 replacement). |
Reason: Security scan — [HIGH] Pipe to interpreter: curl | python3: Command pipes output from 'curl' directly to interpreter 'python3'. Downloaded content will be executed without inspection. Reply |
代码审查摘要 — PR #4965操作: synchronize 本次审查拉取了 head( ✅ 关键点验证(结论:实现正确)
|
| 标题声称 | 状态 | 对应实现 |
|---|---|---|
| 优化水下放置手感 | ✅ | PlaceInWaterBlockItem.useOn 水下分支 + use() 水下守卫 |
| 优化预览(与放置一致) | ✅ | LargeBlockPlacePreviewEventListener 水分支按 surfaceCandidates 顺序取首个可放置 |
| 落点来源差异(流体射线 vs 玩家自身阻挡)的分析 | ✅ | 注释所述与 BlockItem.canPlace → isUnobstructed(blocksBuilding)行为一致 |
结论: APPROVE — 未发现阻塞性缺陷。逻辑等价性、预览与放置同序、删除守卫的安全性均已用完整源码核实;上面的
🧪 手动验证建议
| 场景 | 预期 |
|---|---|
| 岸上看向水面放蟹笼 | 预览落点 == 实际落点 |
| 水面首格被方块挡住 | 预览自动落到玩家朝向 +1 格,实际一致(本次修复点) |
| 眼睛入水,右键水底实体方块 | 按普通放置(含水、WATERLOGGED=true),预览一致 |
| 眼睛入水,右键空气 | 无预览、无放置(use() 返回 PASS) |
| 踩水(头露出水面) | 仍走水面流体射线放置 |
| 主手空/非方块、副手蟹笼 | 预览与放置均使用副手(hand=OFF_HAND) |
由 Hermes Agent 审查
|
💾 Self-improvement review: Patched SKILL.md in skill 'tool-block-interaction-pr-review' (1 replacement). · Patched references/pr-class-routing.md in skill 'github-webhook-pr-review' (1 replacement). |
|
审查已跳过 — 该 webhook 的 action 为 按审查约束第 1 条( 如需对已合并/已关闭的改动做回溯审查,请重新触发一次 |
No description provided.