保留浏览器试玩 IPC 错误正文

补充固定试玩和 runner-v1 的 CDP 查询与输入原因
This commit is contained in:
kdletters
2026-10-05 17:23:01 +08:00
parent f6b1e0fe66
commit 1a1f3df951
2 changed files with 23 additions and 18 deletions
@@ -643,10 +643,10 @@ pub(super) async fn read_playable_web_game_state(
let evaluated = tokio::time::timeout(remaining, page.evaluate(READ_PLAYABLE_GAME_STATE_SCRIPT))
.await
.map_err(|_| "读取固定试玩状态超时".to_string())?
.map_err(|_| "读取固定试玩状态失败".to_string())?;
.map_err(|error| format!("读取固定试玩状态失败:{error}"))?;
let surface = evaluated
.into_value::<PlayableStateSurfaceRead>()
.map_err(|_| "解析固定试玩状态面读取结果失败".to_string())?;
.map_err(|error| format!("解析固定试玩状态面读取结果失败:{error}"))?;
if surface.content_length > MAX_PLAYABLE_GAME_STATE_JSON_CHARS {
return Err("固定试玩状态 JSON 超过大小上限".to_string());
}
@@ -675,7 +675,7 @@ pub(super) async fn click_playtest_control(
let mut elements = tokio::time::timeout(remaining, page.find_elements(selector))
.await
.map_err(|_| format!("固定试玩动作 {action} 超时"))?
.map_err(|_| format!("固定试玩控件 {action} 不存在或查询失败"))?;
.map_err(|error| format!("固定试玩控件 {action} 不存在或查询失败:{error}"))?;
if elements.len() != 1 {
return Err(format!(
"固定试玩控件 {action} 必须唯一,实际数量为 {}",
@@ -690,7 +690,7 @@ pub(super) async fn click_playtest_control(
tokio::time::timeout(remaining, element.scroll_into_view())
.await
.map_err(|_| format!("固定试玩动作 {action} 超时"))?
.map_err(|_| format!("固定试玩控件 {action} 无法滚动到可见区域"))?;
.map_err(|error| format!("固定试玩控件 {action} 无法滚动到可见区域:{error}"))?;
let remaining = playtest_remaining(deadline)?;
let evaluated = tokio::time::timeout(
@@ -699,7 +699,7 @@ pub(super) async fn click_playtest_control(
)
.await
.map_err(|_| format!("固定试玩动作 {action} 超时"))?
.map_err(|_| format!("固定试玩控件 {action} 可见性/禁用态读取失败"))?;
.map_err(|error| format!("固定试玩控件 {action} 可见性/禁用态读取失败:{error}"))?;
let probe = evaluated
.result
.value
@@ -708,7 +708,7 @@ pub(super) async fn click_playtest_control(
.as_str()
.ok_or_else(|| format!("固定试玩控件 {action} 可见性/禁用态结果无效"))?;
let probe = serde_json::from_str::<PlaytestControlProbe>(probe)
.map_err(|_| format!("固定试玩控件 {action} 可见性/禁用态结果无效"))?;
.map_err(|error| format!("固定试玩控件 {action} 可见性/禁用态结果无效:{error}"))?;
if !probe.is_html_element {
return Err(format!("固定试玩控件 {action} 必须是 HTMLElement"));
}
@@ -723,7 +723,7 @@ pub(super) async fn click_playtest_control(
tokio::time::timeout(remaining, element.click())
.await
.map_err(|_| format!("固定试玩动作 {action} 超时"))?
.map_err(|_| format!("固定试玩控件 {action} 不可点击"))?;
.map_err(|error| format!("固定试玩控件 {action} 不可点击:{error}"))?;
Ok(())
}
@@ -135,15 +135,16 @@ async fn snapshot(page: &Page) -> Result<(PlayableWebGameState, RunnerState), St
let raw: Value = page
.evaluate(READ_PLAYABLE_GAME_STATE_SCRIPT)
.await
.map_err(|_| "runner-v1 读取状态失败")?
.map_err(|error| format!("runner-v1 读取状态失败:{error}"))?
.into_value()
.map_err(|_| "runner-v1 状态读取结果无效")?;
.map_err(|error| format!("runner-v1 状态读取结果无效:{error}"))?;
let text = raw
.get("content")
.and_then(Value::as_str)
.ok_or("runner-v1 状态接口缺失或超限")?;
let base = parse_playable_web_game_state(text, BrowserPlaytestScenario::RunnerV1)?;
let value: Value = serde_json::from_str(text).map_err(|_| "runner-v1 JSON 无效")?;
let value: Value =
serde_json::from_str(text).map_err(|error| format!("runner-v1 JSON 无效:{error}"))?;
Ok((base, parse_runner_state(&value)?))
}
@@ -151,7 +152,7 @@ async fn control_center(page: &Page, selector: &'static str) -> Result<(f64, f64
let mut elements = page
.find_elements(selector)
.await
.map_err(|_| "runner-v1 查询控件失败")?;
.map_err(|error| format!("runner-v1 查询控件失败:{error}"))?;
if elements.len() != 1 {
return Err("runner-v1 真实控件必须唯一".into());
}
@@ -159,11 +160,11 @@ async fn control_center(page: &Page, selector: &'static str) -> Result<(f64, f64
element
.scroll_into_view()
.await
.map_err(|_| "runner-v1 控件无法进入视口")?;
.map_err(|error| format!("runner-v1 控件无法进入视口:{error}"))?;
let probe = element
.call_js_fn(PROBE_PLAYTEST_CONTROL_SCRIPT, false)
.await
.map_err(|_| "runner-v1 控件检查失败")?;
.map_err(|error| format!("runner-v1 控件检查失败:{error}"))?;
let probe: PlaytestControlProbe = serde_json::from_str(
probe
.result
@@ -172,14 +173,18 @@ async fn control_center(page: &Page, selector: &'static str) -> Result<(f64, f64
.and_then(Value::as_str)
.ok_or("runner-v1 控件信息缺失")?,
)
.map_err(|_| "runner-v1 控件信息无效")?;
.map_err(|error| format!("runner-v1 控件信息无效:{error}"))?;
if !probe.is_html_element || !probe.visible || probe.disabled {
return Err("runner-v1 控件必须可见且可用".into());
}
let point = element.call_js_fn("function(){const r=this.getBoundingClientRect();return JSON.stringify({x:r.left+r.width/2,y:r.top+r.height/2});}", false)
.await.map_err(|_| "runner-v1 控件坐标读取失败")?.result.value.ok_or("runner-v1 控件坐标缺失")?;
.await
.map_err(|error| format!("runner-v1 控件坐标读取失败:{error}"))?
.result
.value
.ok_or("runner-v1 控件坐标缺失")?;
let point: Value = serde_json::from_str(point.as_str().ok_or("runner-v1 控件坐标结果无效")?)
.map_err(|_| "runner-v1 控件坐标 JSON 无效")?;
.map_err(|error| format!("runner-v1 控件坐标 JSON 无效:{error}"))?;
Ok((
point["x"].as_f64().ok_or("runner-v1 x 坐标无效")?,
point["y"].as_f64().ok_or("runner-v1 y 坐标无效")?,
@@ -196,7 +201,7 @@ async fn touch(page: &Page, point: Option<(f64, f64)>) -> Result<(), String> {
};
page.execute(RunnerTouchInput { kind, points })
.await
.map_err(|_| "runner-v1 真实触摸输入失败")?;
.map_err(|error| format!("runner-v1 真实触摸输入失败:{error}"))?;
Ok(())
}
@@ -242,7 +247,7 @@ async fn held_input(
input.windows_virtual_key_code = Some(if jump { 32 } else { 40 });
page.execute(input)
.await
.map_err(|_| "runner-v1 键盘输入失败")?;
.map_err(|error| format!("runner-v1 键盘输入失败:{error}"))?;
Ok(())
}