Skip to content

feat(AutoEcoFarm):引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。#934

Merged
MistEO merged 34 commits intoMaaEnd:mainfrom
jwtggg:AutoEcoFarm1
Mar 7, 2026
Merged

feat(AutoEcoFarm):引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。#934
MistEO merged 34 commits intoMaaEnd:mainfrom
jwtggg:AutoEcoFarm1

Conversation

@jwtggg
Copy link
Contributor

@jwtggg jwtggg commented Mar 2, 2026

功能说明:
该任务会调用maptracker跑到农场,然后打开地图寻找农作物标记,找到后追踪标记并向着标记前进,收掉路上碰到的所有农田,且每收一个会等一段时间让队友帮忙收周围的,以此来达成自动收菜的功能

目前只有一个收菜方案:即先到达农场的右下角,然后寻找左上角最远的农作物,然后按着对角线移动并收菜,需要使用者将农田摆成方形(长方形最佳),以保证没有遗漏

工作进度:

  • 目前已经完成从开始到四号谷地收菜的流程
  • 完善去武陵农场的寻路路径
  • 想办法优化标记的识别精度
  • 添加行走模式(已经换成更加不容易卡住的蹦蹦跳跳模式)
    - [ ] 添加拍照模式(拍照模式下无法识别标记,暂时不做了)
  • 删掉废弃的旧节点
  • 增加收完菜回帝江号存进仓库的功能
  • 目前ocr识别只支持中文,需要将语言调成中文,后续再补上国际化支持
  • 调整一下pipeline结构,把和地区相关的打包成块(考虑使用anchor技术),目标出下一个新农场时只需要复制粘贴节点块,然后微调下参数就能完成,这样可以方便维护(但是yj有可能在出下个农场前先自动化农场了,不急着做)
  • 测试bug(永远做不完的任务TAT)

Summary by Sourcery

引入一个自动化生态农场采集任务,并将其集成到现有的智能体服务和任务流水线系统中。

New Features:

  • 添加 AutoEcoFarm 任务,以及用于导航、农田识别和采集工作流的相关流水线配置。
  • 在界面配置中公开 AutoEcoFarm 任务,并为所有支持的语言提供本地化文案。
  • 提供自定义的 3D 移动和精细调整动作,用于支持游戏内相机与角色在生态农场工作流中的对齐。

Enhancements:

  • 在 Go 智能体服务中注册新的 AutoEcoFarm 自定义动作,以便可由流水线调用。
Original summary in English

Summary by Sourcery

Introduce an automated eco farm harvesting task and integrate it into the existing agent service and task pipeline system.

New Features:

  • Add an AutoEcoFarm task with associated pipeline configurations for navigation, field detection, and harvesting workflow.
  • Expose the AutoEcoFarm task in the interface configuration with localized strings across supported languages.
  • Provide custom 3D movement and fine-adjustment actions to support in-game camera and character alignment for the eco farm workflow.

Enhancements:

  • Register new AutoEcoFarm custom actions in the Go agent service so they can be invoked from pipelines.

由 Sourcery 提供的总结

引入一个 AutoEcoFarm 自动收割任务,并将其集成到现有的智能体服务和任务流水线系统中。

新特性:

  • 添加 AutoEcoFarm 任务,以及用于导航、农田发现、移动和收割工作流的相关流水线配置。
  • 在界面配置中暴露 AutoEcoFarm 任务,并为所有支持的语言提供本地化字符串。

增强:

  • 实现自定义的 3D 移动和精细调整动作,用于对齐游戏内摄像机和角色,并在 Go 智能体服务中注册这些动作以供流水线使用。
Original summary in English

Summary by Sourcery

Introduce an AutoEcoFarm automated harvesting task and integrate it into the existing agent service and task pipeline system.

New Features:

  • Add an AutoEcoFarm task with associated pipeline configurations for navigation, farmland discovery, movement, and harvesting workflows.
  • Expose the AutoEcoFarm task in the interface configuration with localized strings across supported languages.

Enhancements:

  • Implement custom 3D movement and fine-adjustment actions for aligning the in-game camera and character, and register them in the Go agent service for use by pipelines.

Summary by Sourcery

引入一个自动生态农场收获任务,并将其集成到现有的代理服务和任务流水线系统中。

新功能:

  • 添加一个 AutoEcoFarm 任务,包含用于导航至农场、检测农田、移动以及执行收获操作的流水线。
  • 在界面配置中暴露 AutoEcoFarm 任务,并为所有受支持的语言提供本地化字符串。
  • 提供一个自定义识别动作,用于计算相机朝向农耕区域移动时的滑动目标。

改进:

  • 在 Go 代理服务中注册新的 AutoEcoFarm 自定义识别运行器,以便可以从流水线中调用。
Original summary in English

Summary by Sourcery

Introduce an automated eco farm harvesting task and integrate it into the existing agent service and task pipeline system.

New Features:

  • Add an AutoEcoFarm task with pipelines for navigating to the farm, detecting farmland, moving, and performing harvesting actions.
  • Expose the AutoEcoFarm task in the interface configuration with localized strings across supported languages.
  • Provide a custom recognition action to calculate swipe targets for camera movement toward farming areas.

Enhancements:

  • Register the new AutoEcoFarm custom recognition runner in the Go agent service so it can be invoked from pipelines.

@jwtggg jwtggg marked this pull request as draft March 2, 2026 23:29
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并给出了一些总体反馈:

  • autoecofarm.go 中,embed 的导入和 RecognitionDetailJson 的解析结果目前都没有被使用;建议删除这个导入,并/或把解析出来的识别数据接入逻辑中,以避免产生死代码。
  • MoveToTarget3D 中的旋转角度计算中,日志使用的是 RealangleDeg,但 swipex 仍然是从 angleDeg 推导出来的;将滑动距离与同一个变换后的角度对齐(或者说明它们为什么不同)会让行为更清晰,也更不容易出错。
  • 硬编码的屏幕尺寸和 FootY 默认值(screenWscreenHfootXFootY: 500)可能与运行环境不匹配;将它们暴露为可配置项或从上下文中推导,可以提升在不同设备上的健壮性。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `autoecofarm.go`, the `embed` import and the `RecognitionDetailJson` parsing result are currently unused; consider removing the import and/or wiring the parsed recognition data into the logic to avoid dead code.
- The rotation angle calculation in `MoveToTarget3D` uses `RealangleDeg` for logging but still derives `swipex` from `angleDeg`; aligning the swipe distance with the same transformed angle (or documenting why they differ) would make the behavior clearer and less error-prone.
- The hard-coded screen dimensions and `FootY` default (`screenW`, `screenH`, `footX`, `FootY: 500`) may not match all runtime environments; exposing these as configuration or deriving them from context would improve robustness across devices.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="110-115" />
<code_context>
+	angleRad := math.Atan2(deltax, -deltay)
+	angleDeg := angleRad * 180.0 / math.Pi
+	//将屏幕角度通过映射转换成实际角度
+	RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg
+
+	msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
+	maafocus.NodeActionStarting(ctx, msg1)
+
+	swipex := int(angleDeg / 90 * rotate90)
+	msg2 := fmt.Sprintf("需要移动%d像素", swipex)
+	maafocus.NodeActionStarting(ctx, msg2)
</code_context>
<issue_to_address>
**issue (bug_risk):** Rotation distance is computed from angleDeg instead of RealangleDeg, which likely breaks the pitch correction logic.

`RealangleDeg` compensates for camera pitch via `Y2Pitch`, but the swipe distance still uses `angleDeg`. If rotation should follow the pitch-corrected angle, derive `swipex` from `RealangleDeg`; otherwise remove `RealangleDeg`. As is, the pitch mapping does not affect swipe distance and can cause rotation misalignment.
</issue_to_address>

### Comment 2
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="169-172" />
<code_context>
+	threshold := params.Threshold
+
+	//判断box是否为空
+	if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
+		err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
+			arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
+		log.Error().Err(err).Msg("目标坐标读取失败")
+		return false // 必须返回false,终止执行
+	}
</code_context>
<issue_to_address>
**issue (bug_risk):** Box validation treats X/Y=0 as invalid, which can reject valid targets at the screen edges.

This will reject boxes at the left/top edge where X or Y is 0, even though those are valid coordinates. If the intent is only to forbid empty boxes, check Width()/Height() for `<= 0` instead, and optionally handle an all-zero box explicitly if that’s your sentinel case.
</issue_to_address>

### Comment 3
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="62-71" />
<code_context>
+	var params = MoveToTarget3DParam{
+		FootY: 500,
+	}
+	var results = RecognitionDetailJson{}
+
+	//解析 JSON 参数到结构体中
+	err := json.Unmarshal([]byte(arg.CustomActionParam), &params)
+	if err != nil {
+		log.Error().Err(err).Msg("参数解析失败")
+		maafocus.NodeActionStarting(ctx, "参数解析失败")
+		return false
+	}
+	msg_foot := fmt.Sprintf("当前角色脚的y坐标是:%d", params.FootY)
+	maafocus.NodeActionStarting(ctx, msg_foot)
+
+	err = json.Unmarshal([]byte(arg.RecognitionDetail.DetailJson), &results)
+	if err != nil {
+		log.Error().Err(err).Msg("识别区域解析失败")
</code_context>
<issue_to_address>
**suggestion:** RecognitionDetailJson is parsed but never used, adding unnecessary work and complexity.

`RecognitionDetail.DetailJson` is unmarshalled into `results` but never read. If this information isn’t required here, remove the `RecognitionDetailJson` struct usage, the unmarshal, and related logging to avoid unnecessary parsing and complexity.

Suggested implementation:

```golang
	//初始化结构体默认值
	var params = MoveToTarget3DParam{
		FootY: 500,
	}

```

```golang
	msg_json := fmt.Sprintf("Value JSON: %s\n", arg.RecognitionDetail.DetailJson)
	maafocus.NodeActionStarting(ctx, msg_json)

```
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,请考虑分享给更多人 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • In autoecofarm.go, the embed import and the RecognitionDetailJson parsing result are currently unused; consider removing the import and/or wiring the parsed recognition data into the logic to avoid dead code.
  • The rotation angle calculation in MoveToTarget3D uses RealangleDeg for logging but still derives swipex from angleDeg; aligning the swipe distance with the same transformed angle (or documenting why they differ) would make the behavior clearer and less error-prone.
  • The hard-coded screen dimensions and FootY default (screenW, screenH, footX, FootY: 500) may not match all runtime environments; exposing these as configuration or deriving them from context would improve robustness across devices.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `autoecofarm.go`, the `embed` import and the `RecognitionDetailJson` parsing result are currently unused; consider removing the import and/or wiring the parsed recognition data into the logic to avoid dead code.
- The rotation angle calculation in `MoveToTarget3D` uses `RealangleDeg` for logging but still derives `swipex` from `angleDeg`; aligning the swipe distance with the same transformed angle (or documenting why they differ) would make the behavior clearer and less error-prone.
- The hard-coded screen dimensions and `FootY` default (`screenW`, `screenH`, `footX`, `FootY: 500`) may not match all runtime environments; exposing these as configuration or deriving them from context would improve robustness across devices.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="110-115" />
<code_context>
+	angleRad := math.Atan2(deltax, -deltay)
+	angleDeg := angleRad * 180.0 / math.Pi
+	//将屏幕角度通过映射转换成实际角度
+	RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg
+
+	msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
+	maafocus.NodeActionStarting(ctx, msg1)
+
+	swipex := int(angleDeg / 90 * rotate90)
+	msg2 := fmt.Sprintf("需要移动%d像素", swipex)
+	maafocus.NodeActionStarting(ctx, msg2)
</code_context>
<issue_to_address>
**issue (bug_risk):** Rotation distance is computed from angleDeg instead of RealangleDeg, which likely breaks the pitch correction logic.

`RealangleDeg` compensates for camera pitch via `Y2Pitch`, but the swipe distance still uses `angleDeg`. If rotation should follow the pitch-corrected angle, derive `swipex` from `RealangleDeg`; otherwise remove `RealangleDeg`. As is, the pitch mapping does not affect swipe distance and can cause rotation misalignment.
</issue_to_address>

### Comment 2
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="169-172" />
<code_context>
+	threshold := params.Threshold
+
+	//判断box是否为空
+	if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
+		err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
+			arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
+		log.Error().Err(err).Msg("目标坐标读取失败")
+		return false // 必须返回false,终止执行
+	}
</code_context>
<issue_to_address>
**issue (bug_risk):** Box validation treats X/Y=0 as invalid, which can reject valid targets at the screen edges.

This will reject boxes at the left/top edge where X or Y is 0, even though those are valid coordinates. If the intent is only to forbid empty boxes, check Width()/Height() for `<= 0` instead, and optionally handle an all-zero box explicitly if that’s your sentinel case.
</issue_to_address>

### Comment 3
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="62-71" />
<code_context>
+	var params = MoveToTarget3DParam{
+		FootY: 500,
+	}
+	var results = RecognitionDetailJson{}
+
+	//解析 JSON 参数到结构体中
+	err := json.Unmarshal([]byte(arg.CustomActionParam), &params)
+	if err != nil {
+		log.Error().Err(err).Msg("参数解析失败")
+		maafocus.NodeActionStarting(ctx, "参数解析失败")
+		return false
+	}
+	msg_foot := fmt.Sprintf("当前角色脚的y坐标是:%d", params.FootY)
+	maafocus.NodeActionStarting(ctx, msg_foot)
+
+	err = json.Unmarshal([]byte(arg.RecognitionDetail.DetailJson), &results)
+	if err != nil {
+		log.Error().Err(err).Msg("识别区域解析失败")
</code_context>
<issue_to_address>
**suggestion:** RecognitionDetailJson is parsed but never used, adding unnecessary work and complexity.

`RecognitionDetail.DetailJson` is unmarshalled into `results` but never read. If this information isn’t required here, remove the `RecognitionDetailJson` struct usage, the unmarshal, and related logging to avoid unnecessary parsing and complexity.

Suggested implementation:

```golang
	//初始化结构体默认值
	var params = MoveToTarget3DParam{
		FootY: 500,
	}

```

```golang
	msg_json := fmt.Sprintf("Value JSON: %s\n", arg.RecognitionDetail.DetailJson)
	maafocus.NodeActionStarting(ctx, msg_json)

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +110 to +115
RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg

msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
maafocus.NodeActionStarting(ctx, msg1)

swipex := int(angleDeg / 90 * rotate90)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 旋转距离是根据 angleDeg 而不是 RealangleDeg 计算的,这很可能会破坏俯仰角校正逻辑。

RealangleDeg 通过 Y2Pitch 来补偿相机俯仰,但滑动距离仍然使用 angleDeg。如果旋转应该遵从俯仰校正后的角度,应该从 RealangleDeg 推导 swipex;否则就移除 RealangleDeg。按目前写法,俯仰映射不会影响滑动距离,可能导致旋转偏移。

Original comment in English

issue (bug_risk): Rotation distance is computed from angleDeg instead of RealangleDeg, which likely breaks the pitch correction logic.

RealangleDeg compensates for camera pitch via Y2Pitch, but the swipe distance still uses angleDeg. If rotation should follow the pitch-corrected angle, derive swipex from RealangleDeg; otherwise remove RealangleDeg. As is, the pitch mapping does not affect swipe distance and can cause rotation misalignment.

Comment on lines +169 to +172
if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
log.Error().Err(err).Msg("目标坐标读取失败")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Box 校验把 X/Y=0 当作无效,这会导致屏幕边缘上合法的目标被拒绝。

这样会拒绝左侧/顶部边缘上 X 或 Y 为 0 的 box,尽管这些坐标是合法的。如果你的意图只是禁止空 box,建议只对 Width()/Height() 做 <= 0 校验,并在需要时额外处理“全 0 box”这种特例(如果它是你约定的哨兵值)。

Original comment in English

issue (bug_risk): Box validation treats X/Y=0 as invalid, which can reject valid targets at the screen edges.

This will reject boxes at the left/top edge where X or Y is 0, even though those are valid coordinates. If the intent is only to forbid empty boxes, check Width()/Height() for <= 0 instead, and optionally handle an all-zero box explicitly if that’s your sentinel case.

Comment on lines +62 to +71
var results = RecognitionDetailJson{}

//解析 JSON 参数到结构体中
err := json.Unmarshal([]byte(arg.CustomActionParam), &params)
if err != nil {
log.Error().Err(err).Msg("参数解析失败")
maafocus.NodeActionStarting(ctx, "参数解析失败")
return false
}
msg_foot := fmt.Sprintf("当前角色脚的y坐标是:%d", params.FootY)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: RecognitionDetailJson 被解析出来却从未使用,只会增加不必要的计算和复杂度。

RecognitionDetail.DetailJson 被反序列化到 results 中,但之后完全没有被读取。如果这些信息在当前逻辑中并不需要,建议移除 RecognitionDetailJson 结构体的使用、反序列化代码以及相关日志,以避免不必要的解析和复杂度。

Suggested implementation:

	//初始化结构体默认值
	var params = MoveToTarget3DParam{
		FootY: 500,
	}
	msg_json := fmt.Sprintf("Value JSON: %s\n", arg.RecognitionDetail.DetailJson)
	maafocus.NodeActionStarting(ctx, msg_json)
Original comment in English

suggestion: RecognitionDetailJson is parsed but never used, adding unnecessary work and complexity.

RecognitionDetail.DetailJson is unmarshalled into results but never read. If this information isn’t required here, remove the RecognitionDetailJson struct usage, the unmarshal, and related logging to avoid unnecessary parsing and complexity.

Suggested implementation:

	//初始化结构体默认值
	var params = MoveToTarget3DParam{
		FootY: 500,
	}
	msg_json := fmt.Sprintf("Value JSON: %s\n", arg.RecognitionDetail.DetailJson)
	maafocus.NodeActionStarting(ctx, msg_json)

@jwtggg jwtggg changed the title 引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。 feat:引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。 Mar 2, 2026
@jwtggg jwtggg changed the title feat:引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。 feat(AutoEcoFarm):引入一个新的自动生态农场收获任务,并将其接入现有的界面和任务配置中。 Mar 3, 2026
@Daydreamer114
Copy link
Contributor

Daydreamer114 commented Mar 4, 2026

image

对于武陵的 4*5 田地,昨天想出来这样一种摆法,在中心两个田地其中一个靠中间的位置进行收获/育种,队友可以自动处理全部田地,不需要在拍照模式隐藏设备

@jwtggg jwtggg marked this pull request as ready for review March 5, 2026 14:32
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 3 个问题,并给出了一些整体性的反馈:

  • 3D 移动逻辑里对 screenWscreenHfootX 进行了硬编码,这会在其他分辨率或纵横比下失效;建议从运行时上下文或配置中推导这些值,而不是使用常量。
  • MoveToTarget3D.Run 中,RecognitionDetailJson 被填充了但从未真正使用(只使用了 arg.Box);要么移除未使用的解析/日志代码,要么改为使用解析得到的 box,以避免死代码并减少日志噪音。
  • autoecofarm/register.goRegister 函数的注释仍然提到“aspect ratio checker”;请更新注释,让其准确描述 AutoEcoFarm 自定义动作的注册逻辑,以避免在维护该模块时造成混淆。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- 3D movement logic hardcodes `screenW`, `screenH`, and `footX`, which will break on other resolutions or aspect ratios; consider deriving these from the runtime context or configuration instead of constants.
- In `MoveToTarget3D.Run`, `RecognitionDetailJson` is populated but never actually used (only `arg.Box` is used); either remove the unused parsing/logging or switch to using the parsed box to avoid dead code and reduce log noise.
- The `Register` function comment in `autoecofarm/register.go` still mentions "aspect ratio checker"; update it to accurately describe registration of the AutoEcoFarm custom actions to avoid confusion when maintaining this module.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="110-115" />
<code_context>
+	angleRad := math.Atan2(deltax, -deltay)
+	angleDeg := angleRad * 180.0 / math.Pi
+	//将屏幕角度通过映射转换成实际角度
+	RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg
+
+	msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
+	maafocus.NodeActionStarting(ctx, msg1)
+
+	swipex := int(angleDeg / 90 * rotate90)
+	msg2 := fmt.Sprintf("需要移动%d像素", swipex)
+	maafocus.NodeActionStarting(ctx, msg2)
</code_context>
<issue_to_address>
**issue (bug_risk):** 计算出来的 RealangleDeg 没有用于滑动距离,这可能会削弱基于俯仰缩放的意义。

`RealangleDeg` 是通过 `Y2Pitch` 计算得到的,但只用于日志输出;`swipex` 仍然使用 `angleDeg``swipex := int(angleDeg / 90 * rotate90)`)。如果目的是根据俯仰对旋转/移动进行校准,`swipex` 很可能应该基于 `RealangleDeg`,或者代码需要澄清为什么俯仰缩放没有应用到实际滑动上。就目前而言,`Y2Pitch` 对行为没有任何影响。
</issue_to_address>

### Comment 2
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="169-173" />
<code_context>
+	duration := time.Duration(params.Duration) * time.Millisecond
+
+	//判断box是否为空
+	if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
+		err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
+			arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
+		log.Error().Err(err).Msg("目标坐标读取失败")
+		return false // 必须返回false,终止执行
+	}
+
</code_context>
<issue_to_address>
**issue (bug_risk):** 将 X==0 或 Y==0 视为无效会拒绝位于屏幕顶部/左侧边缘的合法目标。

使用 `X() == 0 || Y() == 0` 会把任何接触左边或上边缘的 box 都视为无效,即便其宽高是正数。如果目标是检测“空 box”,应改为根据尺寸(以及符号)来判断,例如 `if arg.Box.Width() <= 0 || arg.Box.Height() <= 0 { ... }`。
</issue_to_address>

### Comment 3
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="165-166" />
<code_context>
+	stepRatio := params.StepRatio
</code_context>
<issue_to_address>
**suggestion (bug_risk):** StepRatio 没有被限制范围,在极端取值时可能导致过冲或完全不移动。

由于 `stepRatio` 是从 JSON 中读取的,像 `0`、负数或者大于 1 的值都可能导致完全不移动或步长过大。建议在用于计算滑动前,将其钳制到一个安全范围内(例如 `[0.1, 1.0]`)。

```suggestion
	stepRatio := params.StepRatio
	// Clamp stepRatio to a safe range to avoid no movement or overshoot
	if stepRatio < 0.1 {
		stepRatio = 0.1
	} else if stepRatio > 1.0 {
		stepRatio = 1.0
	}

	duration := time.Duration(params.Duration) * time.Millisecond
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据反馈来改进之后的评审。
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • The 3D movement logic hardcodes screenW, screenH, and footX, which will break on other resolutions or aspect ratios; consider deriving these from the runtime context or configuration instead of constants.
  • In MoveToTarget3D.Run, RecognitionDetailJson is populated but never actually used (only arg.Box is used); either remove the unused parsing/logging or switch to using the parsed box to avoid dead code and reduce log noise.
  • The Register function comment in autoecofarm/register.go still mentions "aspect ratio checker"; update it to accurately describe registration of the AutoEcoFarm custom actions to avoid confusion when maintaining this module.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The 3D movement logic hardcodes `screenW`, `screenH`, and `footX`, which will break on other resolutions or aspect ratios; consider deriving these from the runtime context or configuration instead of constants.
- In `MoveToTarget3D.Run`, `RecognitionDetailJson` is populated but never actually used (only `arg.Box` is used); either remove the unused parsing/logging or switch to using the parsed box to avoid dead code and reduce log noise.
- The `Register` function comment in `autoecofarm/register.go` still mentions "aspect ratio checker"; update it to accurately describe registration of the AutoEcoFarm custom actions to avoid confusion when maintaining this module.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="110-115" />
<code_context>
+	angleRad := math.Atan2(deltax, -deltay)
+	angleDeg := angleRad * 180.0 / math.Pi
+	//将屏幕角度通过映射转换成实际角度
+	RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg
+
+	msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
+	maafocus.NodeActionStarting(ctx, msg1)
+
+	swipex := int(angleDeg / 90 * rotate90)
+	msg2 := fmt.Sprintf("需要移动%d像素", swipex)
+	maafocus.NodeActionStarting(ctx, msg2)
</code_context>
<issue_to_address>
**issue (bug_risk):** The computed RealangleDeg is not used for swipe distance, which may defeat the purpose of the pitch-based scaling.

`RealangleDeg` is computed via `Y2Pitch` but only used for logging; `swipex` still uses `angleDeg` (`swipex := int(angleDeg / 90 * rotate90)`). If the goal is to pitch-calibrate the rotation/movement, `swipex` should likely be based on `RealangleDeg`, or the code should clarify why pitch scaling is not applied to the actual swipe. As is, `Y2Pitch` has no behavioral effect.
</issue_to_address>

### Comment 2
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="169-173" />
<code_context>
+	duration := time.Duration(params.Duration) * time.Millisecond
+
+	//判断box是否为空
+	if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
+		err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
+			arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
+		log.Error().Err(err).Msg("目标坐标读取失败")
+		return false // 必须返回false,终止执行
+	}
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Treating X==0 or Y==0 as invalid will reject valid targets at the top/left edge of the screen.

Using `X() == 0 || Y() == 0` treats any box touching the left or top edge as invalid, even when width/height are positive. If the goal is to detect empty boxes, guard on size (and sign) instead, e.g. `if arg.Box.Width() <= 0 || arg.Box.Height() <= 0 { ... }`.
</issue_to_address>

### Comment 3
<location path="agent/go-service/autoecofarm/autoecofarm.go" line_range="165-166" />
<code_context>
+	stepRatio := params.StepRatio
</code_context>
<issue_to_address>
**suggestion (bug_risk):** StepRatio is not bounded, which can cause overshoot or no movement with extreme values.

Because `stepRatio` is read from JSON, values like `0`, negatives, or >1 can cause no movement or overly large jumps. Consider clamping it to a safe range (e.g. `[0.1, 1.0]`) before using it in the swipe calculation.

```suggestion
	stepRatio := params.StepRatio
	// Clamp stepRatio to a safe range to avoid no movement or overshoot
	if stepRatio < 0.1 {
		stepRatio = 0.1
	} else if stepRatio > 1.0 {
		stepRatio = 1.0
	}

	duration := time.Duration(params.Duration) * time.Millisecond
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +110 to +115
RealangleDeg := Y2Pitch(float64(params.FootY)) / 45 * angleDeg

msg1 := fmt.Sprintf("需要旋转%.0f°", RealangleDeg)
maafocus.NodeActionStarting(ctx, msg1)

swipex := int(angleDeg / 90 * rotate90)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 计算出来的 RealangleDeg 没有用于滑动距离,这可能会削弱基于俯仰缩放的意义。

RealangleDeg 是通过 Y2Pitch 计算得到的,但只用于日志输出;swipex 仍然使用 angleDegswipex := int(angleDeg / 90 * rotate90))。如果目的是根据俯仰对旋转/移动进行校准,swipex 很可能应该基于 RealangleDeg,或者代码需要澄清为什么俯仰缩放没有应用到实际滑动上。就目前而言,Y2Pitch 对行为没有任何影响。

Original comment in English

issue (bug_risk): The computed RealangleDeg is not used for swipe distance, which may defeat the purpose of the pitch-based scaling.

RealangleDeg is computed via Y2Pitch but only used for logging; swipex still uses angleDeg (swipex := int(angleDeg / 90 * rotate90)). If the goal is to pitch-calibrate the rotation/movement, swipex should likely be based on RealangleDeg, or the code should clarify why pitch scaling is not applied to the actual swipe. As is, Y2Pitch has no behavioral effect.

Comment on lines +169 to +173
if arg.Box.X() == 0 || arg.Box.Y() == 0 || arg.Box.Width() == 0 || arg.Box.Height() == 0 {
err := fmt.Errorf("目标坐标/尺寸为空(X:%d,Y:%d,W:%d,H:%d)",
arg.Box.X(), arg.Box.Y(), arg.Box.Width(), arg.Box.Height())
log.Error().Err(err).Msg("目标坐标读取失败")
return false // 必须返回false,终止执行
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 将 X==0 或 Y==0 视为无效会拒绝位于屏幕顶部/左侧边缘的合法目标。

使用 X() == 0 || Y() == 0 会把任何接触左边或上边缘的 box 都视为无效,即便其宽高是正数。如果目标是检测“空 box”,应改为根据尺寸(以及符号)来判断,例如 if arg.Box.Width() <= 0 || arg.Box.Height() <= 0 { ... }

Original comment in English

issue (bug_risk): Treating X==0 or Y==0 as invalid will reject valid targets at the top/left edge of the screen.

Using X() == 0 || Y() == 0 treats any box touching the left or top edge as invalid, even when width/height are positive. If the goal is to detect empty boxes, guard on size (and sign) instead, e.g. if arg.Box.Width() <= 0 || arg.Box.Height() <= 0 { ... }.

@jwtggg
Copy link
Contributor Author

jwtggg commented Mar 5, 2026

image 对于武陵的 4*5 田地,昨天想出来这样一种摆法,在中心两个田地其中一个靠中间的位置进行收获/育种,队友可以自动处理全部田地,不需要在拍照模式隐藏设备

其实还好,因为我是从对角线一路收过去的,只要是方形密集阵型就可以,拍照模式好像没有也能用

@MistEO
Copy link
Contributor

MistEO commented Mar 6, 2026

看看怎么没编过?

@jwtggg jwtggg marked this pull request as draft March 7, 2026 03:08
@jwtggg jwtggg marked this pull request as ready for review March 7, 2026 03:27
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好——我发现了 1 个问题,并给出了一些整体性的反馈:

  • 变量 oTragetX/Y/W/H 的命名中似乎有一个一致的拼写错误;建议将它们(以及相关日志中的变量)重命名为 oTarget*,以提高可读性并避免混淆。
  • autoEcoFarmCalculateSwipeTarget.Run 中,可能需要对 XStepRatioYStepRatio 做校验(例如限制在 [0, 1] 这样合理的范围内),以防止由于 JSON 输入异常而产生意外的滑动坐标。
  • 当前 Run 中的 Info 级别日志会输出每次调用的详细几何信息(屏幕中心、ROI 等);如果该函数被频繁调用,建议将日志级别下调到 Debug 或通过条件控制,避免在正常运行时产生过多噪声日志。
面向 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
- The variables `oTragetX/Y/W/H` appear to have a consistent typo in their names; consider renaming them (and related logs) to `oTarget*` for clarity and to avoid confusion.
- In `autoEcoFarmCalculateSwipeTarget.Run`, it may be worth validating `XStepRatio` and `YStepRatio` (e.g., clamping to a sane range like [0, 1]) to prevent unexpected swipe coordinates from malformed JSON input.
- The current `Info`-level logging in `Run` prints detailed per-call geometry (screen center, ROI, etc.); if this runs frequently, consider downgrading to `Debug` or guarding it to avoid noisy logs in normal operation.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/scaletarget.go" line_range="45-63" />
<code_context>
+		}
+	}
+
+	oTragetX := float64(arg.Roi.X())      // 传入矩形左上角X
+	oTragetY := float64(arg.Roi.Y())      // 传入矩形左上角Y
+	oTragetW := float64(arg.Roi.Width())  // 传入矩形宽度(X轴方向)
+	oTragetH := float64(arg.Roi.Height()) // 传入矩形高度(Y轴方向)
+
+	log.Info().Msgf(
+		"Roi矩形参数:左上角X=%.2f, 左上角Y=%.2f, 宽度=%.2f, 高度=%.2f",
+		oTragetX, oTragetY, oTragetW, oTragetH,
+	)
+
+	// 计算传入矩形的中点坐标
+	oTragetCenterX := oTragetX + oTragetW/2 // 中点X = 左上角X + 宽度/2
+	oTragetCenterY := oTragetY + oTragetH/2 // 中点Y = 左上角Y + 高度/2
+
+	//  计算屏幕中心坐标
</code_context>
<issue_to_address>
**建议(拼写):** 若干变量名将 `Target` 拼写成了 `Traget`,这会影响可读性并可能造成混淆。

建议将这些变量(`oTragetX/Y/W/H``oTragetCenterX/Y`)重命名为使用正确的 `Target` 拼写(例如 `oTargetX``oTargetCenterX`),以与预期含义保持一致并统一命名风格。

```suggestion
	oTargetX := float64(arg.Roi.X())      // 传入矩形左上角X
	oTargetY := float64(arg.Roi.Y())      // 传入矩形左上角Y
	oTargetW := float64(arg.Roi.Width())  // 传入矩形宽度(X轴方向)
	oTargetH := float64(arg.Roi.Height()) // 传入矩形高度(Y轴方向)

	log.Info().Msgf(
		"Roi矩形参数:左上角X=%.2f, 左上角Y=%.2f, 宽度=%.2f, 高度=%.2f",
		oTargetX, oTargetY, oTargetW, oTargetH,
	)

	// 计算传入矩形的中点坐标
	oTargetCenterX := oTargetX + oTargetW/2 // 中点X = 左上角X + 宽度/2
	oTargetCenterY := oTargetY + oTargetH/2 // 中点Y = 左上角Y + 高度/2

	//  计算屏幕中心坐标

	//计算距离
	dx := oTargetCenterX - screenCenterX
	dy := oTargetCenterY - screenCenterY
```
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The variables oTragetX/Y/W/H appear to have a consistent typo in their names; consider renaming them (and related logs) to oTarget* for clarity and to avoid confusion.
  • In autoEcoFarmCalculateSwipeTarget.Run, it may be worth validating XStepRatio and YStepRatio (e.g., clamping to a sane range like [0, 1]) to prevent unexpected swipe coordinates from malformed JSON input.
  • The current Info-level logging in Run prints detailed per-call geometry (screen center, ROI, etc.); if this runs frequently, consider downgrading to Debug or guarding it to avoid noisy logs in normal operation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The variables `oTragetX/Y/W/H` appear to have a consistent typo in their names; consider renaming them (and related logs) to `oTarget*` for clarity and to avoid confusion.
- In `autoEcoFarmCalculateSwipeTarget.Run`, it may be worth validating `XStepRatio` and `YStepRatio` (e.g., clamping to a sane range like [0, 1]) to prevent unexpected swipe coordinates from malformed JSON input.
- The current `Info`-level logging in `Run` prints detailed per-call geometry (screen center, ROI, etc.); if this runs frequently, consider downgrading to `Debug` or guarding it to avoid noisy logs in normal operation.

## Individual Comments

### Comment 1
<location path="agent/go-service/autoecofarm/scaletarget.go" line_range="45-63" />
<code_context>
+		}
+	}
+
+	oTragetX := float64(arg.Roi.X())      // 传入矩形左上角X
+	oTragetY := float64(arg.Roi.Y())      // 传入矩形左上角Y
+	oTragetW := float64(arg.Roi.Width())  // 传入矩形宽度(X轴方向)
+	oTragetH := float64(arg.Roi.Height()) // 传入矩形高度(Y轴方向)
+
+	log.Info().Msgf(
+		"Roi矩形参数:左上角X=%.2f, 左上角Y=%.2f, 宽度=%.2f, 高度=%.2f",
+		oTragetX, oTragetY, oTragetW, oTragetH,
+	)
+
+	// 计算传入矩形的中点坐标
+	oTragetCenterX := oTragetX + oTragetW/2 // 中点X = 左上角X + 宽度/2
+	oTragetCenterY := oTragetY + oTragetH/2 // 中点Y = 左上角Y + 高度/2
+
+	//  计算屏幕中心坐标
</code_context>
<issue_to_address>
**suggestion (typo):** Several variable names are misspelled as `Traget`, which hurts readability and may cause confusion.

These variables (`oTragetX/Y/W/H`, `oTragetCenterX/Y`) should be renamed to use `Target` (e.g., `oTargetX`, `oTargetCenterX`) to align with the intended word and keep naming consistent.

```suggestion
	oTargetX := float64(arg.Roi.X())      // 传入矩形左上角X
	oTargetY := float64(arg.Roi.Y())      // 传入矩形左上角Y
	oTargetW := float64(arg.Roi.Width())  // 传入矩形宽度(X轴方向)
	oTargetH := float64(arg.Roi.Height()) // 传入矩形高度(Y轴方向)

	log.Info().Msgf(
		"Roi矩形参数:左上角X=%.2f, 左上角Y=%.2f, 宽度=%.2f, 高度=%.2f",
		oTargetX, oTargetY, oTargetW, oTargetH,
	)

	// 计算传入矩形的中点坐标
	oTargetCenterX := oTargetX + oTargetW/2 // 中点X = 左上角X + 宽度/2
	oTargetCenterY := oTargetY + oTargetH/2 // 中点Y = 左上角Y + 高度/2

	//  计算屏幕中心坐标

	//计算距离
	dx := oTargetCenterX - screenCenterX
	dy := oTargetCenterY - screenCenterY
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants