Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions agent/go-service/pkg/control/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,35 @@ func GetControlType(ctrl *maa.Controller) (string, error) {
return "", fmt.Errorf("unsupported controller type: %s", info.Type)
}

// GetWin32Hwnd retrieves the native window handle (HWND) of a Win32 controller
// by parsing its info string. It fails for non-Win32 controllers or when the
// info string carries no hwnd.
func GetWin32Hwnd(ctrl *maa.Controller) (uintptr, error) {
if ctrl == nil {
return 0, fmt.Errorf("nil controller")
}

infoStr, err := ctrl.GetInfo()
if err != nil {
return 0, fmt.Errorf("failed to get controller info: %w", err)
}
if strings.TrimSpace(infoStr) == "" {
return 0, fmt.Errorf("empty controller info")
}

var info maaControllerInfoDto
if err := json.Unmarshal([]byte(infoStr), &info); err != nil {
return 0, fmt.Errorf("failed to parse controller info: %w", err)
}
if info.Type != "" && !strings.EqualFold(info.Type, CONTROL_TYPE_WIN32) {
return 0, fmt.Errorf("controller type is %q, not win32", info.Type)
}
if info.HWnd == 0 {
return 0, fmt.Errorf("controller info has no hwnd")
}
return uintptr(info.HWnd), nil
}

/* ******** Screen Diagonal Size ******** */

// GetScreenDiagonalSize calculates the diagonal size of the screen based on the controller's raw resolution,
Expand Down
3 changes: 3 additions & 0 deletions agent/go-service/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func registerAll() {
resource.EnsureResourcePathSink()

// Pre-Check Custom
// GFN-App is a Win32 controller: aspectratio enforces the shared 16:9 +
// >=1280x720 contract for it like any other Win32 controller, so no
// GFN-specific forced resize is needed.
aspectratio.Register()
hdrcheck.Register()
processcheck.Register()
Expand Down
35 changes: 1 addition & 34 deletions agent/go-service/taskersink/aspectratio/altenter_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
package aspectratio

import (
"encoding/json"
"fmt"
"strings"
"time"
"unsafe"

Expand Down Expand Up @@ -47,11 +45,6 @@ var (
win32ProcGetCurrentThreadID = win32Kernel32.NewProc("GetCurrentThreadId")
)

type win32ControllerInfo struct {
Type string `json:"type"`
HWnd uint64 `json:"hwnd"`
}

type win32Rect struct {
Left int32
Top int32
Expand All @@ -64,7 +57,7 @@ func init() {
}

func sendAltEnterWin32(controller *maa.Controller) (resolutionReader, error) {
hwnd, err := controllerHwndWin32(controller)
hwnd, err := control.GetWin32Hwnd(controller)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -260,29 +253,3 @@ func setDPIAwareWin32() func() {
}
}
}

func controllerHwndWin32(controller *maa.Controller) (uintptr, error) {
if controller == nil {
return 0, fmt.Errorf("nil controller")
}

infoStr, err := controller.GetInfo()
if err != nil {
return 0, fmt.Errorf("failed to get controller info: %w", err)
}
if strings.TrimSpace(infoStr) == "" {
return 0, fmt.Errorf("empty controller info")
}

var info win32ControllerInfo
if err := json.Unmarshal([]byte(infoStr), &info); err != nil {
return 0, fmt.Errorf("failed to parse controller info: %w", err)
}
if info.Type != "" && !strings.EqualFold(info.Type, control.CONTROL_TYPE_WIN32) {
return 0, fmt.Errorf("controller type is %q, not win32", info.Type)
}
if info.HWnd == 0 {
return 0, fmt.Errorf("controller info has no hwnd")
}
return uintptr(info.HWnd), nil
}
17 changes: 17 additions & 0 deletions assets/interface.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@
// },
// "permission_required": true
// },
// GFN-App: GeForce NOW 原生客户端(CEF 流窗口),仅前台模式。
// 窗口标题已实测确认为 "Arknights: Endfield on GeForce NOW",
// 正则取语言无关片段,见 docs/zh_cn/developers/gfn-app-support-prd.md
// resource_gfn 覆盖串流压缩下失配的精确 ColorMatch 节点(PRD 风险 R3)
{
"name": "GFN-App",
"label": "$controller.GFN-App.label",
"description": "$controller.GFN-App.description",
"type": "Cloud",
"cloud": {
"provider": "geforce_now",
"game_title": "Endfield"
},
"attach_resource_path": [
"./resource_gfn"
]
},
{
"name": "ADB",
"label": "$controller.ADB.label",
Expand Down
2 changes: 2 additions & 0 deletions assets/locales/interface/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@
"controller.Win32-Front.description": "Best stability. Requires the game window to remain in the foreground and unobstructed; will fully grab the mouse.",
"controller.Win32-Window-Background.label": "PC-Background (Deprecated - incompatible with new version)",
"controller.Win32-Window-Background.description": "Due to game updates, it can no longer be adapted. The background controller has been deprecated and will be removed in a future version.",
"controller.GFN-App.label": "Cloud-GeForce NOW",
"controller.GFN-App.description": "Play via the GeForce NOW native client stream. Foreground mode only; will fully grab the mouse. Recommended: lock the streaming resolution to 1280x720 in GFN settings.",
"controller.ADB.label": "Android",
"controller.ADB.description": "Supports Android emulators and physical Android devices.",
"controller.Wlroots.label": "Linux-Wlroots",
Expand Down
2 changes: 2 additions & 0 deletions assets/locales/interface/ja_jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@
"controller.Win32-Front.description": "安定性が最も高い。ゲームウィンドウを最前面に表示し、遮られないようにする必要があります。マウスを完全に占有します。",
"controller.Win32-Window-Background.label": "PC-バックグラウンド(非推奨 - 新バージョンに対応不可)",
"controller.Win32-Window-Background.description": "ゲームの更新により適応を継続できなくなりました。バックグラウンドコントローラーは非推奨となり、今後のバージョンで削除される予定です。",
"controller.GFN-App.label": "クラウド-GeForce NOW",
"controller.GFN-App.description": "GeForce NOW ネイティブクライアントのストリーミングでプレイします。フォアグラウンドモードのみ対応で、マウスを完全に占有します。GFN の設定でストリーミング解像度を 1280x720 に固定することを推奨します。",
"controller.ADB.label": "Android",
"controller.ADB.description": "Androidエミュレーターおよび実機Androidデバイスに対応しています。",
"controller.Wlroots.label": "Linux-Wlroots",
Expand Down
2 changes: 2 additions & 0 deletions assets/locales/interface/ko_kr.json
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@
"controller.Win32-Front.description": "안정성이 가장 뛰어납니다. 게임 창이 항상 최앞단에 있고 가려지지 않아야 하며, 마우스를 완전히 점유합니다.",
"controller.Win32-Window-Background.label": "PC-백그라운드 (사용 중단 - 새 버전 호환 불가)",
"controller.Win32-Window-Background.description": "게임 업데이트로 인해 더 이상 호환할 수 없습니다. 백그라운드 컨트롤러는 사용 중단되었으며 향후 버전에서 제거될 예정입니다.",
"controller.GFN-App.label": "클라우드-GeForce NOW",
"controller.GFN-App.description": "GeForce NOW 네이티브 클라이언트 스트리밍으로 플레이합니다. 포그라운드 모드만 지원하며 마우스를 완전히 점유합니다. GFN 설정에서 스트리밍 해상도를 1280x720으로 고정하는 것을 권장합니다.",
"controller.ADB.label": "Android",
"controller.ADB.description": "안드로이드 에뮬레이터 및 실물 안드로이드 기기를 지원합니다.",
"controller.Wlroots.label": "Linux-Wlroots",
Expand Down
2 changes: 2 additions & 0 deletions assets/locales/interface/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@
"controller.Win32-Front.description": "稳定性最好,需要游戏窗口保持在最前且不被遮挡,会完全抢占鼠标",
"controller.Win32-Window-Background.label": "电脑端-后台弃用(无法适配新版本)",
"controller.Win32-Window-Background.description": "因游戏更新导致无法继续适配,后台控制器已弃用,并将在后续版本中移除。",
"controller.GFN-App.label": "云游戏-GeForce NOW",
"controller.GFN-App.description": "通过 GeForce NOW 原生客户端串流游玩,仅支持前台模式,会完全抢占鼠标;建议在 GFN 设置中将串流分辨率固定为 1280x720",
"controller.ADB.label": "安卓端",
"controller.ADB.description": "支持安卓模拟器和实体安卓设备",
"controller.Wlroots.label": "Linux端-Wlroots",
Expand Down
2 changes: 2 additions & 0 deletions assets/locales/interface/zh_tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,8 @@
"controller.Win32-Front.description": "穩定性最好,需要遊戲視窗保持在最前且不被遮擋,會完全搶占滑鼠",
"controller.Win32-Window-Background.label": "電腦端-後台棄用(無法適配新版本)",
"controller.Win32-Window-Background.description": "因遊戲更新導致無法繼續適配,後台控制器已棄用,並將在後續版本中移除。",
"controller.GFN-App.label": "雲遊戲-GeForce NOW",
"controller.GFN-App.description": "透過 GeForce NOW 原生客戶端串流遊玩,僅支援前台模式,會完全搶占滑鼠;建議在 GFN 設定中將串流解析度固定為 1280x720",
"controller.ADB.label": "安卓端",
"controller.ADB.description": "支援安卓模擬器及實體安卓裝置",
"controller.Wlroots.label": "Linux端-Wlroots",
Expand Down
116 changes: 116 additions & 0 deletions assets/resource_gfn/pipeline/Common/Button/ButtonColor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// GFN 云游戏专用覆盖:按钮颜色基础节点。
// GeForce NOW 串流帧经过 H.264/HEVC 编码(4:2:0 色度抽样 + 量化),
// 颜色相对本地渲染会偏移数个单位,基础资源中 1~2 个单位宽的精确
// ColorMatch 区间在串流帧上系统性失配(实测品牌黄 hue 由本地 28-29
// 扩散为 26-31,见 docs/zh_cn/developers/gfn-app-support-prd.md 风险 R3)。
// 本文件在保持节点结构不变的前提下放宽颜色容差,仅随 GFN-App 控制器加载。
{
"YellowButtonBackground": {
"desc": "黄色按钮背景色(GFN 串流容差版),用作黄色按钮组合识别的背景框",
"recognition": {
"type": "ColorMatch",
"param": {
"method": 40,
"lower": [
24,
90,
90
],
"upper": [
33,
255,
255
],
"connected": true,
"count": 3000
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
},
"WhiteButtonBackground": {
"desc": "白色按钮背景色(GFN 串流容差版),用作白色按钮组合识别的背景框",
"recognition": {
"type": "ColorMatch",
"param": {
"lower": [
[
246,
244,
244
],
[
230,
228,
228
],
[
145,
144,
144
]
],
"upper": [
[
255,
255,
255
],
[
247,
245,
245
],
[
175,
173,
173
]
],
"connected": true,
"count": 100
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
},
"GrayButtonBackground": {
"desc": "灰色按钮背景色(GFN 串流容差版),用作灰色按钮组合识别的背景框",
"recognition": {
"type": "ColorMatch",
"param": {
"lower": [
[
63,
62,
62
],
[
77,
76,
76
]
],
"upper": [
[
76,
75,
75
],
[
90,
89,
89
]
],
"connected": true,
"count": 100
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
}
}
92 changes: 92 additions & 0 deletions assets/resource_gfn/pipeline/SceneManager/SceneLoading.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// GFN 云游戏专用覆盖:加载界面颜色准确性检查。
// 基础资源要求校准色块 hue 精确单值且饱和度恒为 255,GeForce NOW 串流帧
// 经视频编码后饱和度与色相均有数个单位的偏移,精确匹配必然失败并触发
// "颜色识别失败" 误报(用户并未开启滤镜/HDR)。
// 本文件仅放宽 Success 判定节点的颜色容差(hue ±4、饱和度下限 200),
// 失败分支与流程结构由基础资源原样提供,仅随 GFN-App 控制器加载。
{
"__SceneCheckYellowColorSuccess": {
"desc": "检查颜色准确性:黄色 成功(GFN 串流容差版)",
"recognition": {
"type": "ColorMatch",
"param": {
"roi": [
0,
480,
65,
85
],
"method": 40,
"lower": [
26,
200,
1
],
"upper": [
34,
255,
255
]
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
},
"__SceneCheckTealColorSuccess": {
"desc": "检查颜色准确性:青色 成功(GFN 串流容差版)",
"recognition": {
"type": "ColorMatch",
"param": {
"roi": [
0,
518,
65,
85
],
"method": 40,
"lower": [
86,
200,
1
],
"upper": [
94,
255,
255
]
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
},
"__SceneCheckPurpleColorSuccess": {
"desc": "检查颜色准确性:紫色 成功(GFN 串流容差版)",
"recognition": {
"type": "ColorMatch",
"param": {
"roi": [
0,
553,
65,
85
],
"method": 40,
"lower": [
146,
200,
1
],
"upper": [
154,
255,
255
]
}
},
"pre_delay": 0,
"post_delay": 0,
"rate_limit": 0
}
}
1 change: 1 addition & 0 deletions assets/tasks/AutoCollect.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"ADB",
"PlayCover",
"Win32-Front",
"GFN-App",
"Wlroots"
],
"option": [
Expand Down
Loading
Loading