feat: 完善敲木鱼玩法模板链路
This commit is contained in:
@@ -450,6 +450,10 @@ mod tests {
|
||||
cover_image_src: None,
|
||||
ui_background_image_src: None,
|
||||
ui_background_image_object_key: None,
|
||||
level_background_image_src: None,
|
||||
level_background_image_object_key: None,
|
||||
ui_spritesheet_image_src: None,
|
||||
ui_spritesheet_image_object_key: None,
|
||||
background_music: None,
|
||||
board: PuzzleBoardSnapshot {
|
||||
rows: 3,
|
||||
|
||||
@@ -113,6 +113,7 @@ fn map_wooden_fish_work_snapshot(
|
||||
floating_words: snapshot.floating_words.clone(),
|
||||
hit_object_asset: snapshot.hit_object_asset.clone().map(map_image_asset),
|
||||
background_asset: snapshot.background_asset.clone().map(map_image_asset),
|
||||
back_button_asset: snapshot.back_button_asset.clone().map(map_image_asset),
|
||||
hit_sound_asset: snapshot.hit_sound_asset.clone().map(map_audio_asset),
|
||||
cover_image_src: empty_string_to_none(snapshot.cover_image_src.clone()),
|
||||
generation_status: parse_generation_status(&snapshot.generation_status),
|
||||
@@ -147,6 +148,7 @@ fn map_wooden_fish_work_snapshot(
|
||||
draft,
|
||||
hit_object_asset,
|
||||
background_asset: snapshot.background_asset.map(map_image_asset),
|
||||
back_button_asset: snapshot.back_button_asset.map(map_image_asset),
|
||||
hit_sound_asset,
|
||||
floating_words: snapshot.floating_words,
|
||||
})
|
||||
@@ -166,6 +168,7 @@ fn map_wooden_fish_draft_snapshot(snapshot: WoodenFishDraftSnapshot) -> WoodenFi
|
||||
floating_words: snapshot.floating_words,
|
||||
hit_object_asset: snapshot.hit_object_asset.map(map_image_asset),
|
||||
background_asset: snapshot.background_asset.map(map_image_asset),
|
||||
back_button_asset: snapshot.back_button_asset.map(map_image_asset),
|
||||
hit_sound_asset: snapshot.hit_sound_asset.map(map_audio_asset),
|
||||
cover_image_src: snapshot.cover_image_src,
|
||||
generation_status: parse_generation_status(&snapshot.generation_status),
|
||||
|
||||
@@ -20,6 +20,7 @@ pub struct WoodenFishDraftCompileInput {
|
||||
pub hit_object_asset_json: Option<String>,
|
||||
pub background_asset_json: Option<String>,
|
||||
pub hit_sound_asset_json: Option<String>,
|
||||
pub back_button_asset_json: Option<String>,
|
||||
pub floating_words_json: Option<String>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub generation_status: Option<String>,
|
||||
|
||||
@@ -22,6 +22,7 @@ pub struct WoodenFishDraftSnapshot {
|
||||
pub floating_words: Vec<String>,
|
||||
pub hit_object_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub background_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub back_button_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAssetSnapshot>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub generation_status: String,
|
||||
|
||||
@@ -24,6 +24,7 @@ pub struct WoodenFishGalleryViewRow {
|
||||
pub hit_sound_prompt: Option<String>,
|
||||
pub hit_object_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub background_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub back_button_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAssetSnapshot>,
|
||||
pub floating_words: Vec<String>,
|
||||
pub cover_image_src: String,
|
||||
@@ -60,6 +61,8 @@ pub struct WoodenFishGalleryViewRowCols {
|
||||
__sdk::__query_builder::Col<WoodenFishGalleryViewRow, Option<WoodenFishImageAssetSnapshot>>,
|
||||
pub background_asset:
|
||||
__sdk::__query_builder::Col<WoodenFishGalleryViewRow, Option<WoodenFishImageAssetSnapshot>>,
|
||||
pub back_button_asset:
|
||||
__sdk::__query_builder::Col<WoodenFishGalleryViewRow, Option<WoodenFishImageAssetSnapshot>>,
|
||||
pub hit_sound_asset:
|
||||
__sdk::__query_builder::Col<WoodenFishGalleryViewRow, Option<WoodenFishAudioAssetSnapshot>>,
|
||||
pub floating_words: __sdk::__query_builder::Col<WoodenFishGalleryViewRow, Vec<String>>,
|
||||
@@ -96,6 +99,7 @@ impl __sdk::__query_builder::HasCols for WoodenFishGalleryViewRow {
|
||||
hit_sound_prompt: __sdk::__query_builder::Col::new(table_name, "hit_sound_prompt"),
|
||||
hit_object_asset: __sdk::__query_builder::Col::new(table_name, "hit_object_asset"),
|
||||
background_asset: __sdk::__query_builder::Col::new(table_name, "background_asset"),
|
||||
back_button_asset: __sdk::__query_builder::Col::new(table_name, "back_button_asset"),
|
||||
hit_sound_asset: __sdk::__query_builder::Col::new(table_name, "hit_sound_asset"),
|
||||
floating_words: __sdk::__query_builder::Col::new(table_name, "floating_words"),
|
||||
cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"),
|
||||
|
||||
@@ -28,6 +28,7 @@ pub struct WoodenFishWorkProfileRow {
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub background_asset_json: Option<String>,
|
||||
pub back_button_asset_json: Option<String>,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WoodenFishWorkProfileRow {
|
||||
@@ -62,6 +63,8 @@ pub struct WoodenFishWorkProfileRowCols {
|
||||
__sdk::__query_builder::Col<WoodenFishWorkProfileRow, Option<__sdk::Timestamp>>,
|
||||
pub background_asset_json:
|
||||
__sdk::__query_builder::Col<WoodenFishWorkProfileRow, Option<String>>,
|
||||
pub back_button_asset_json:
|
||||
__sdk::__query_builder::Col<WoodenFishWorkProfileRow, Option<String>>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for WoodenFishWorkProfileRow {
|
||||
@@ -107,6 +110,10 @@ impl __sdk::__query_builder::HasCols for WoodenFishWorkProfileRow {
|
||||
table_name,
|
||||
"background_asset_json",
|
||||
),
|
||||
back_button_asset_json: __sdk::__query_builder::Col::new(
|
||||
table_name,
|
||||
"back_button_asset_json",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct WoodenFishWorkSnapshot {
|
||||
pub hit_sound_prompt: Option<String>,
|
||||
pub hit_object_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub background_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub back_button_asset: Option<WoodenFishImageAssetSnapshot>,
|
||||
pub hit_sound_asset: Option<WoodenFishAudioAssetSnapshot>,
|
||||
pub floating_words: Vec<String>,
|
||||
pub cover_image_src: String,
|
||||
|
||||
@@ -18,6 +18,7 @@ pub struct WoodenFishWorkUpdateInput {
|
||||
pub hit_object_asset_json: Option<String>,
|
||||
pub background_asset_json: Option<String>,
|
||||
pub hit_sound_asset_json: Option<String>,
|
||||
pub back_button_asset_json: Option<String>,
|
||||
pub floating_words_json: Option<String>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub generation_status: Option<String>,
|
||||
|
||||
@@ -15,7 +15,6 @@ use shared_kernel::build_prefixed_uuid_id;
|
||||
const WOODEN_FISH_TEMPLATE_ID: &str = "wooden-fish";
|
||||
const WOODEN_FISH_TEMPLATE_NAME: &str = "敲木鱼";
|
||||
const DEFAULT_HIT_OBJECT_PROMPT: &str = "默认敲击物图案,圆润木质质感,透明背景";
|
||||
const DEFAULT_HIT_SOUND_PROMPT: &str = "清脆短促的木鱼敲击声";
|
||||
|
||||
impl SpacetimeClient {
|
||||
pub async fn create_wooden_fish_session(
|
||||
@@ -532,21 +531,11 @@ fn merge_action_into_draft(
|
||||
if let Some(asset) = payload.background_asset.clone() {
|
||||
draft.background_asset = Some(asset);
|
||||
}
|
||||
}
|
||||
if matches!(
|
||||
scope,
|
||||
WoodenFishDraftMergeScope::CompileDraft
|
||||
| WoodenFishDraftMergeScope::GenerateHitSound
|
||||
| WoodenFishDraftMergeScope::ReplaceHitSound
|
||||
) {
|
||||
if let Some(value) = payload
|
||||
.hit_sound_prompt
|
||||
.as_ref()
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
{
|
||||
draft.hit_sound_prompt = Some(value.trim().to_string());
|
||||
if let Some(asset) = payload.back_button_asset.clone() {
|
||||
draft.back_button_asset = Some(asset);
|
||||
}
|
||||
}
|
||||
draft.hit_sound_prompt = None;
|
||||
if matches!(scope, WoodenFishDraftMergeScope::GenerateHitSound) {
|
||||
draft.hit_sound_asset = payload.hit_sound_asset.clone();
|
||||
} else if matches!(
|
||||
@@ -577,6 +566,7 @@ fn merge_action_into_draft(
|
||||
{
|
||||
draft.hit_object_asset = None;
|
||||
draft.background_asset = None;
|
||||
draft.back_button_asset = None;
|
||||
}
|
||||
if draft.floating_words.is_empty() {
|
||||
draft.floating_words = default_floating_words();
|
||||
@@ -613,6 +603,9 @@ fn build_compile_input(
|
||||
let background_asset = draft.background_asset.clone().ok_or_else(|| {
|
||||
SpacetimeClientError::validation_failed("wooden fish background asset 缺少真实生成资产")
|
||||
})?;
|
||||
let back_button_asset = draft.back_button_asset.clone().ok_or_else(|| {
|
||||
SpacetimeClientError::validation_failed("wooden fish back button asset 缺少真实生成资产")
|
||||
})?;
|
||||
|
||||
Ok(WoodenFishDraftCompileInput {
|
||||
session_id: current.session_id.clone(),
|
||||
@@ -628,6 +621,7 @@ fn build_compile_input(
|
||||
hit_object_asset_json: Some(json_string(&hit_object_asset)?),
|
||||
background_asset_json: Some(json_string(&background_asset)?),
|
||||
hit_sound_asset_json: Some(json_string(&hit_sound_asset)?),
|
||||
back_button_asset_json: Some(json_string(&back_button_asset)?),
|
||||
floating_words_json: Some(json_string(&draft.floating_words)?),
|
||||
cover_image_src: draft.cover_image_src.clone(),
|
||||
generation_status: Some("ready".to_string()),
|
||||
@@ -662,6 +656,7 @@ fn build_update_input(
|
||||
} else {
|
||||
None
|
||||
},
|
||||
back_button_asset_json: None,
|
||||
floating_words_json: Some(json_string(&draft.floating_words)?),
|
||||
cover_image_src: draft.cover_image_src.clone(),
|
||||
generation_status: None,
|
||||
@@ -716,10 +711,11 @@ fn default_draft() -> WoodenFishDraftResponse {
|
||||
theme_tags: vec!["休闲".to_string()],
|
||||
hit_object_prompt: DEFAULT_HIT_OBJECT_PROMPT.to_string(),
|
||||
hit_object_reference_image_src: None,
|
||||
hit_sound_prompt: Some(DEFAULT_HIT_SOUND_PROMPT.to_string()),
|
||||
hit_sound_prompt: None,
|
||||
floating_words: default_floating_words(),
|
||||
hit_object_asset: None,
|
||||
background_asset: None,
|
||||
back_button_asset: None,
|
||||
hit_sound_asset: None,
|
||||
cover_image_src: None,
|
||||
generation_status: WoodenFishGenerationStatus::Draft,
|
||||
@@ -807,6 +803,7 @@ mod tests {
|
||||
let mut payload = action(WoodenFishActionType::CompileDraft);
|
||||
payload.hit_object_asset = Some(generated_hit_object_asset("generated-compile-object"));
|
||||
payload.background_asset = Some(generated_background_asset("generated-compile-background"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
|
||||
let (plan, draft) =
|
||||
@@ -840,6 +837,13 @@ mod tests {
|
||||
.unwrap_or("")
|
||||
.contains("generated-compile-background")
|
||||
);
|
||||
assert!(
|
||||
input
|
||||
.back_button_asset_json
|
||||
.as_deref()
|
||||
.unwrap_or("")
|
||||
.contains("generated-compile-back")
|
||||
);
|
||||
assert_eq!(draft.generation_status, WoodenFishGenerationStatus::Ready);
|
||||
}
|
||||
|
||||
@@ -849,6 +853,7 @@ mod tests {
|
||||
let mut payload = action(WoodenFishActionType::CompileDraft);
|
||||
payload.hit_object_asset = Some(generated_hit_object_asset("generated-compile-object"));
|
||||
payload.background_asset = Some(generated_background_asset("generated-compile-background"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
@@ -869,6 +874,7 @@ mod tests {
|
||||
let mut payload = action(WoodenFishActionType::CompileDraft);
|
||||
payload.hit_object_asset = Some(generated_hit_object_asset("generated-compile-object"));
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
@@ -883,6 +889,27 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_compile_requires_real_back_button_asset_from_api_server() {
|
||||
let session = session_with_draft(draft_without_assets());
|
||||
let mut payload = action(WoodenFishActionType::CompileDraft);
|
||||
payload.hit_object_asset = Some(generated_hit_object_asset("generated-compile-object"));
|
||||
payload.background_asset = Some(generated_background_asset("generated-compile-background"));
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
Ok(_) => panic!("compile-draft should not publish without back button asset"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert!(
|
||||
error
|
||||
.to_string()
|
||||
.contains("back button asset 缺少真实生成资产")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_action_regenerate_hit_object_replaces_only_object_asset() {
|
||||
let session = session_with_draft(draft_with_assets());
|
||||
@@ -890,6 +917,7 @@ mod tests {
|
||||
payload.hit_object_prompt = Some("新的敲击物".to_string());
|
||||
payload.hit_object_asset = Some(generated_hit_object_asset("generated-object"));
|
||||
payload.background_asset = Some(generated_background_asset("generated-background"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-back"));
|
||||
|
||||
let (plan, _draft) =
|
||||
build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS)
|
||||
@@ -933,6 +961,13 @@ mod tests {
|
||||
.unwrap_or("")
|
||||
.contains("generated-background")
|
||||
);
|
||||
assert!(
|
||||
input
|
||||
.back_button_asset_json
|
||||
.as_deref()
|
||||
.unwrap_or("")
|
||||
.contains("generated-back")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -967,6 +1002,13 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_default_draft_has_no_hit_sound_prompt() {
|
||||
let draft = default_draft();
|
||||
|
||||
assert!(draft.hit_sound_prompt.is_none());
|
||||
}
|
||||
|
||||
fn action(action_type: WoodenFishActionType) -> WoodenFishActionRequest {
|
||||
WoodenFishActionRequest {
|
||||
action_type,
|
||||
@@ -978,6 +1020,7 @@ mod tests {
|
||||
hit_object_reference_image_src: None,
|
||||
hit_object_asset: None,
|
||||
background_asset: None,
|
||||
back_button_asset: None,
|
||||
hit_sound_prompt: None,
|
||||
hit_sound_asset: None,
|
||||
floating_words: None,
|
||||
@@ -1032,6 +1075,21 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn generated_back_button_asset(asset_id: &str) -> WoodenFishImageAsset {
|
||||
WoodenFishImageAsset {
|
||||
asset_id: asset_id.to_string(),
|
||||
image_src: "/generated-wooden-fish-assets/real-profile/back-button/image.png"
|
||||
.to_string(),
|
||||
image_object_key: "generated-wooden-fish-assets/real-profile/back-button/image.png"
|
||||
.to_string(),
|
||||
asset_object_id: format!("{asset_id}-asset"),
|
||||
generation_provider: "image2".to_string(),
|
||||
prompt: "新的返回按钮".to_string(),
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
}
|
||||
}
|
||||
|
||||
fn generated_hit_sound_asset(asset_id: &str) -> WoodenFishAudioAsset {
|
||||
WoodenFishAudioAsset {
|
||||
asset_id: asset_id.to_string(),
|
||||
@@ -1068,6 +1126,16 @@ mod tests {
|
||||
width: 1024,
|
||||
height: 1536,
|
||||
}),
|
||||
back_button_asset: Some(WoodenFishImageAsset {
|
||||
asset_id: "old-back".to_string(),
|
||||
image_src: "/generated-wooden-fish-assets/old-back.png".to_string(),
|
||||
image_object_key: "generated-wooden-fish-assets/old-back.png".to_string(),
|
||||
asset_object_id: "old-back-asset".to_string(),
|
||||
generation_provider: "image2".to_string(),
|
||||
prompt: "旧返回按钮".to_string(),
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
}),
|
||||
hit_sound_asset: Some(WoodenFishAudioAsset {
|
||||
asset_id: "old-sound".to_string(),
|
||||
audio_src: "/generated-wooden-fish-assets/old-sound.mp3".to_string(),
|
||||
@@ -1093,10 +1161,11 @@ mod tests {
|
||||
theme_tags: vec!["旧标签".to_string()],
|
||||
hit_object_prompt: "旧敲击物".to_string(),
|
||||
hit_object_reference_image_src: None,
|
||||
hit_sound_prompt: Some("旧音效".to_string()),
|
||||
hit_sound_prompt: None,
|
||||
floating_words: default_floating_words(),
|
||||
hit_object_asset: None,
|
||||
background_asset: None,
|
||||
back_button_asset: None,
|
||||
hit_sound_asset: None,
|
||||
cover_image_src: None,
|
||||
generation_status: WoodenFishGenerationStatus::Draft,
|
||||
|
||||
Reference in New Issue
Block a user