迁移至CsTrees - #3423
Conversation
- 迁移AutoFishing - 迁移到完整的黑板系统 - 截屏本身改为行为而非上下文 - 关键帧截图保存功能改用Visitor实现 - 迁移相应单元测试
Greptile Summary此 PR 将自动钓鱼行为树从 BehaviourTree 迁移到 CsTrees,并引入共享黑板、统一截图节点和异步 Tick。
Confidence Score: 4/5合并前应修复实时自动钓鱼触发器中未等待 TickOnce 的问题,避免同一行为树并发执行和异步异常丢失。 AutoFishingTrigger 会在连续截图回调中启动多个未等待的 TickOnce,它们复用同一个行为树和黑板,可能重叠修改节点状态并重复发送游戏输入。 Files Needing Attention: BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs
|
| Filename | Overview |
|---|---|
| BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs | 实时钓鱼树已迁移到 CsTrees,但同步 OnCapture 丢弃异步 TickOnce,允许同一树发生重叠 Tick。 |
| BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTask.cs | 独立任务改为异步 Tick,并通过 CsTrees 黑板和组合节点重建完整钓鱼流程。 |
| BetterGenshinImpact/GameTask/AutoFishing/Behaviours.PartII.cs | 新增超时、退出、流程检查和截图等 CsTrees 行为节点,截图资源由 TakeScreenshot 跨 Tick 轮换释放。 |
| BetterGenshinImpact/GameTask/AutoFishing/Blackboard.cs | 原有专用黑板状态迁移为 CsTrees BlackboardKey 定义及访问方式。 |
| BetterGenshinImpact/GameTask/AutoFishing/ScreenshotVisitor.cs | 新增基于节点终止事件保存关键帧的访问器。 |
| BetterGenshinImpact/BetterGenshinImpact.csproj | 移除 BehaviourTree 依赖并引入 CsTrees 1.0.1。 |
Sequence Diagram
sequenceDiagram
participant D as Capture Dispatcher
participant T as AutoFishingTrigger
participant B as BehaviourTreeLaTiao
D->>T: OnCapture(frame N)
T->>B: TickOnce()
Note over T,B: Task 未等待,OnCapture 立即返回
D->>T: OnCapture(frame N+1)
T->>B: TickOnce()
Note over B: 两次 Tick 可能重叠并共享节点状态与 Blackboard
Prompt To Fix All With AI
### Issue 1
BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs:100
**异步 Tick 未被串行化**
当 `IsExclusive` 为 true 且连续截图回调间隔超过 67ms 时,`OnCapture` 会丢弃 `TickOnce()` 返回的 `Task`,使下一次回调能在前一次 Tick 完成前再次操作同一个行为树和 Blackboard,导致节点状态并发修改、重复发送游戏输入,并使异步异常无法沿调用链处理。
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "清理 BehaviourTree" | Re-trigger Greptile
| } | ||
| else | ||
| { | ||
| BehaviourTreeLaTiao.TickOnce(); |
There was a problem hiding this comment.
当 IsExclusive 为 true 且连续截图回调间隔超过 67ms 时,OnCapture 会丢弃 TickOnce() 返回的 Task,使下一次回调能在前一次 Tick 完成前再次操作同一个行为树和 Blackboard,导致节点状态并发修改、重复发送游戏输入,并使异步异常无法沿调用链处理。
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs
Line: 100
Comment:
**异步 Tick 未被串行化**
当 `IsExclusive` 为 true 且连续截图回调间隔超过 67ms 时,`OnCapture` 会丢弃 `TickOnce()` 返回的 `Task`,使下一次回调能在前一次 Tick 完成前再次操作同一个行为树和 Blackboard,导致节点状态并发修改、重复发送游戏输入,并使异步异常无法沿调用链处理。
**Context Used:** AGENTS.md ([source](https://github.com/babalae/better-genshin-impact/blob/main/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 681f205317
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| } | ||
| else | ||
| { | ||
| BehaviourTreeLaTiao.TickOnce(); |
There was a problem hiding this comment.
严重程度:P1;问题位置:AutoFishingTrigger.OnCapture 的独占分支;问题原因:TickOnce() 在迁移后的 CsTrees 用法中返回 Task<Status>,这里直接丢弃返回值,导致每 67ms 的截图回调都可能在上一轮行为树还没完成时再次启动同一棵 BehaviourTreeLaTiao。可能造成的影响:半自动钓鱼会在同一个 blackboard、截图和游戏输入上并发 tick,出现重复提竿/鼠标按键、状态互相覆盖以及未观察异常。推荐修复方案:在 OnCapture 中串行等待该 tick 完成,或用正在运行的 _tickTask/锁做重入保护并观察异常,保证同一棵树不会并发执行。
Useful? React with 👍 / 👎.
| .FindFishTimeout("找到鱼", 20, _logger) | ||
| .End() | ||
| .EnterFishingMode("进入钓鱼模式", _logger, input, session, prototypes, cultureInfo: param.GameCultureInfo, stringLocalizer: param.StringLocalizer) | ||
| .SuccessIsRunning(@"\") |
There was a problem hiding this comment.
严重程度:P2;问题位置:全自动钓鱼循环装饰器;问题原因:这里用 SuccessIsRunning 代替原来的“直到失败”循环后,FindFishTimeout 设置 Abort、BubbleAbortCheck 返回 Failure 的场景会把失败冒泡到外层 Parallel,外层 Sequence 因此在到达 .QuitFishingMode(...) 之前结束。可能造成的影响:进入钓鱼界面后鱼群耗尽、找鱼超时或主动终止时,任务会记录结束但不再按 ESC/确认退出,玩家会被留在钓鱼界面。推荐修复方案:使用 CsTrees 中等价于 UntilFailed 且失败时让父序列继续的装饰器,或在该层把终止失败转换为成功后再执行 QuitFishingMode。
Useful? React with 👍 / 👎.
|
|
||
| async Task tickARound() | ||
| { | ||
| blackboard.Clear(); |
There was a problem hiding this comment.
严重程度:P2;问题位置:tickARound() 每轮开始清空黑板;问题原因:Sleep 只在树开头的 OneShot(SetSleep) 中写入一次,但第二次进入 tickARound()(例如昼夜策略会依次跑 7 点和 19 点)时 blackboard.Clear() 会把这个键删掉,而 OneShot 不会再次注册。可能造成的影响:第二轮开始后 MoveViewpointDown、TurnAround、ChooseBait 等节点调用 Sleep.Get() 时会因为黑板键缺失而中断任务。推荐修复方案:不要全量清空黑板,改为只重置钓鱼状态键,或在每次 Clear() 后重新写入 Sleep/不要把 SetSleep 包在一次性节点中。
Useful? React with 👍 / 👎.
| selectedBaitAccess.Set(BaitType.FakeFlyBait); | ||
| var fishpondAccess = blackboard.GrantWrite<Fishpond>(null!, "Fishpond"); | ||
|
|
||
| var sut = new ThrowRod("-", new FakeLogger(), new FakeInputSimulator(), Predictor, blackboard, new FakeTimeProvider(), drawContent: new FakeDrawContent()); |
There was a problem hiding this comment.
严重程度:P1;问题位置:迁移后的自动钓鱼单测;问题原因:ThrowRod 的构造函数现在是 (string, ILogger, IInputSimulator, BgiYoloPredictor, TimeProvider?, DrawContent?),但这里仍按旧模式把 blackboard 作为第五个参数传入,同类残留还出现在 BehavioursTests.FishBite.cs 的 FishBiteTimeout 构造调用。可能造成的影响:包含 BetterGenshinImpact.UnitTest 的解决方案编译会直接失败,单测无法运行。推荐修复方案:移除多余的 blackboard 参数,并把 FakeTimeProvider 传到新的 timeProvider 位置。
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
baka AI无法穿透SG来分析……
| if (_bitmap == null) | ||
| { | ||
| _logger.LogWarning("截图失败"); | ||
| return Status.Failure; |
There was a problem hiding this comment.
严重程度:P2;问题位置:TakeScreenshot.Update();问题原因:迁移前 CaptureGameImageNoRetry 偶发返回 null 时只记录“截图失败”并 continue 到下一帧,现在截图节点直接返回 Status.Failure,位于根 Sequence 前置步骤会让全自动钓鱼任务在一次瞬时截图失败后结束。可能造成的影响:游戏捕获短暂丢帧、窗口切换瞬间或采集后端偶发失败时,钓鱼流程会提前退出,甚至绕过后续正常钓鱼动作。推荐修复方案:让截图节点在失败时保持 Status.Running 并等待下一帧,或在调用方对截图失败做重试/跳过当前 tick 的处理。
Useful? React with 👍 / 👎.
| private Mat? _bitmap; | ||
| private CaptureContent? _content; |
There was a problem hiding this comment.
严重程度:P2;问题位置:TakeScreenshot 持有的截图字段;问题原因:该行为每次 tick 只释放上一帧 _bitmap/_content,但行为树结束后最后一次成功捕获的 Mat 和 CaptureContent 没有任何清理路径;迁移前这些对象在每轮循环中由 using 立即释放。可能造成的影响:每次全自动钓鱼任务结束都会遗留一张截图及其派生缓存的本机内存,重复运行会累积内存占用。推荐修复方案:在任务结束的 finally 中释放截图行为,或让 TakeScreenshot 实现受行为树调用的清理逻辑来释放 _content 和 _bitmap。
Useful? React with 👍 / 👎.
旧框架有许多不满意的地方
且无法满足未来的需要
但是它也有可圈可点的地方(流式构建),于是以它和py_trees为素材,要上了、CsTrees!成为Agent编程的Key吧!