Add generationStatus and match3d/runtime fixes

Introduce persistent generationStatus to work summaries (puzzle & match3d) and propagate generation recovery rules across docs and frontend/backends so "generating" is restored from server-side work summary rather than ephemeral front-end notices. Update API server image/asset handling (improve match3d material sheet green/alpha decontamination and promote generatedItemAssets background fields) and add runtime improvements: alpha-based hotspot hit-testing, tray insertion/three-match animation behavior, and session re-read on client-side VectorEngine timeouts/lock-screen interruptions. Many docs, tests and related frontend modules updated/added to reflect these contract and behavior changes.
This commit is contained in:
2026-05-16 22:59:02 +08:00
parent bb60ca91ef
commit a45e358e83
42 changed files with 3872 additions and 443 deletions

View File

@@ -151,6 +151,8 @@ pub struct Match3DWorkSummaryResponse {
#[serde(default)]
pub published_at: Option<String>,
pub publish_ready: bool,
#[serde(default)]
pub generation_status: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub background_prompt: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -282,4 +284,36 @@ mod tests {
assert_eq!(payload["gameName"], json!("水果抓大鹅"));
assert_eq!(payload["clearCount"], json!(4));
}
#[test]
fn match3d_work_summary_uses_camel_case_generation_status() {
let payload = serde_json::to_value(Match3DWorkSummaryResponse {
work_id: "work-1".to_string(),
profile_id: "profile-1".to_string(),
owner_user_id: "user-1".to_string(),
source_session_id: Some("session-1".to_string()),
game_name: "水果抓大鹅".to_string(),
theme_text: "水果".to_string(),
summary: "水果主题".to_string(),
tags: vec!["水果".to_string()],
cover_image_src: None,
reference_image_src: None,
clear_count: 4,
difficulty: 5,
publication_status: "draft".to_string(),
play_count: 0,
updated_at: "2026-05-01T00:00:00Z".to_string(),
published_at: None,
publish_ready: false,
generation_status: Some("generating".to_string()),
background_prompt: None,
background_image_src: None,
background_image_object_key: None,
generated_background_asset: None,
generated_item_assets: Vec::new(),
})
.expect("payload should serialize");
assert_eq!(payload["generationStatus"], json!("generating"));
}
}

View File

@@ -57,6 +57,8 @@ pub struct PuzzleWorkSummaryResponse {
pub point_incentive_claimable_points: u64,
pub publish_ready: bool,
#[serde(default)]
pub generation_status: Option<String>,
#[serde(default)]
pub levels: Vec<PuzzleDraftLevelResponse>,
}
@@ -91,6 +93,7 @@ mod tests {
point_incentive_total_points: 1.5,
point_incentive_claimable_points: 0,
publish_ready: true,
generation_status: Some("ready".to_string()),
levels: Vec::new(),
})
.expect("payload should serialize");
@@ -99,6 +102,7 @@ mod tests {
assert_eq!(payload["pointIncentiveClaimedPoints"], 1);
assert_eq!(payload["pointIncentiveTotalPoints"], 1.5);
assert_eq!(payload["pointIncentiveClaimablePoints"], 0);
assert_eq!(payload["generationStatus"], "ready");
}
}