621 lines
24 KiB
Rust
621 lines
24 KiB
Rust
use super::*;
|
|
|
|
pub(crate) fn map_big_fish_session_procedure_result(
|
|
result: BigFishSessionProcedureResult,
|
|
) -> Result<BigFishSessionRecord, SpacetimeClientError> {
|
|
if !result.ok {
|
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
|
}
|
|
|
|
let session = result
|
|
.session
|
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("big fish session 快照"))?;
|
|
|
|
Ok(map_big_fish_session_snapshot(session))
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_works_procedure_result(
|
|
result: BigFishWorksProcedureResult,
|
|
_fallback_owner_user_id: Option<&str>,
|
|
) -> Result<Vec<BigFishWorkSummaryRecord>, SpacetimeClientError> {
|
|
if !result.ok {
|
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
|
}
|
|
|
|
Ok(result
|
|
.items
|
|
.into_iter()
|
|
.map(map_big_fish_work_summary_snapshot)
|
|
.collect())
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_run_procedure_result(
|
|
result: BigFishRunProcedureResult,
|
|
) -> Result<BigFishRuntimeRunRecord, SpacetimeClientError> {
|
|
if !result.ok {
|
|
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
|
}
|
|
|
|
let run = result
|
|
.run
|
|
.ok_or_else(|| SpacetimeClientError::missing_snapshot("big fish run 快照"))?;
|
|
Ok(map_big_fish_runtime_snapshot(run))
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_session_snapshot(
|
|
snapshot: BigFishSessionSnapshot,
|
|
) -> BigFishSessionRecord {
|
|
BigFishSessionRecord {
|
|
session_id: snapshot.session_id,
|
|
current_turn: snapshot.current_turn,
|
|
progress_percent: snapshot.progress_percent,
|
|
stage: format_big_fish_creation_stage(snapshot.stage).to_string(),
|
|
anchor_pack: map_big_fish_anchor_pack(snapshot.anchor_pack),
|
|
draft: snapshot.draft.map(map_big_fish_game_draft),
|
|
asset_slots: snapshot
|
|
.asset_slots
|
|
.into_iter()
|
|
.map(map_big_fish_asset_slot_snapshot)
|
|
.collect(),
|
|
asset_coverage: map_big_fish_asset_coverage(snapshot.asset_coverage),
|
|
messages: snapshot
|
|
.messages
|
|
.into_iter()
|
|
.map(map_big_fish_agent_message_snapshot)
|
|
.collect(),
|
|
last_assistant_reply: snapshot.last_assistant_reply,
|
|
publish_ready: snapshot.publish_ready,
|
|
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_anchor_pack(snapshot: BigFishAnchorPack) -> BigFishAnchorPackRecord {
|
|
BigFishAnchorPackRecord {
|
|
gameplay_promise: map_big_fish_anchor_item(snapshot.gameplay_promise),
|
|
ecology_visual_theme: map_big_fish_anchor_item(snapshot.ecology_visual_theme),
|
|
growth_ladder: map_big_fish_anchor_item(snapshot.growth_ladder),
|
|
risk_tempo: map_big_fish_anchor_item(snapshot.risk_tempo),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_anchor_item(snapshot: BigFishAnchorItem) -> BigFishAnchorItemRecord {
|
|
BigFishAnchorItemRecord {
|
|
key: snapshot.key,
|
|
label: snapshot.label,
|
|
value: snapshot.value,
|
|
status: format_big_fish_anchor_status(snapshot.status).to_string(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_game_draft(snapshot: BigFishGameDraft) -> BigFishGameDraftRecord {
|
|
BigFishGameDraftRecord {
|
|
title: snapshot.title,
|
|
subtitle: snapshot.subtitle,
|
|
core_fun: snapshot.core_fun,
|
|
ecology_theme: snapshot.ecology_theme,
|
|
levels: snapshot
|
|
.levels
|
|
.into_iter()
|
|
.map(map_big_fish_level_blueprint)
|
|
.collect(),
|
|
background: map_big_fish_background_blueprint(snapshot.background),
|
|
runtime_params: map_big_fish_runtime_params(snapshot.runtime_params),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_level_blueprint(
|
|
snapshot: BigFishLevelBlueprint,
|
|
) -> BigFishLevelBlueprintRecord {
|
|
BigFishLevelBlueprintRecord {
|
|
level: snapshot.level,
|
|
name: snapshot.name,
|
|
one_line_fantasy: snapshot.one_line_fantasy,
|
|
text_description: snapshot.text_description,
|
|
silhouette_direction: snapshot.silhouette_direction,
|
|
size_ratio: snapshot.size_ratio,
|
|
visual_description: snapshot.visual_description,
|
|
visual_prompt_seed: snapshot.visual_prompt_seed,
|
|
idle_motion_description: snapshot.idle_motion_description,
|
|
move_motion_description: snapshot.move_motion_description,
|
|
motion_prompt_seed: snapshot.motion_prompt_seed,
|
|
merge_source_level: snapshot.merge_source_level,
|
|
prey_window: snapshot.prey_window,
|
|
threat_window: snapshot.threat_window,
|
|
is_final_level: snapshot.is_final_level,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_background_blueprint(
|
|
snapshot: BigFishBackgroundBlueprint,
|
|
) -> BigFishBackgroundBlueprintRecord {
|
|
BigFishBackgroundBlueprintRecord {
|
|
theme: snapshot.theme,
|
|
color_mood: snapshot.color_mood,
|
|
foreground_hints: snapshot.foreground_hints,
|
|
midground_composition: snapshot.midground_composition,
|
|
background_depth: snapshot.background_depth,
|
|
safe_play_area_hint: snapshot.safe_play_area_hint,
|
|
spawn_edge_hint: snapshot.spawn_edge_hint,
|
|
background_prompt_seed: snapshot.background_prompt_seed,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_runtime_params(
|
|
snapshot: BigFishRuntimeParams,
|
|
) -> BigFishRuntimeParamsRecord {
|
|
BigFishRuntimeParamsRecord {
|
|
level_count: snapshot.level_count,
|
|
merge_count_per_upgrade: snapshot.merge_count_per_upgrade,
|
|
spawn_target_count: snapshot.spawn_target_count,
|
|
leader_move_speed: snapshot.leader_move_speed,
|
|
follower_catch_up_speed: snapshot.follower_catch_up_speed,
|
|
offscreen_cull_seconds: snapshot.offscreen_cull_seconds,
|
|
prey_spawn_delta_levels: snapshot.prey_spawn_delta_levels,
|
|
threat_spawn_delta_levels: snapshot.threat_spawn_delta_levels,
|
|
win_level: snapshot.win_level,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_asset_slot_snapshot(
|
|
snapshot: BigFishAssetSlotSnapshot,
|
|
) -> BigFishAssetSlotRecord {
|
|
BigFishAssetSlotRecord {
|
|
slot_id: snapshot.slot_id,
|
|
asset_kind: format_big_fish_asset_kind(snapshot.asset_kind).to_string(),
|
|
level: snapshot.level,
|
|
motion_key: snapshot.motion_key,
|
|
status: format_big_fish_asset_status(snapshot.status).to_string(),
|
|
asset_url: snapshot.asset_url,
|
|
prompt_snapshot: snapshot.prompt_snapshot,
|
|
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_asset_coverage(
|
|
snapshot: BigFishAssetCoverage,
|
|
) -> BigFishAssetCoverageRecord {
|
|
BigFishAssetCoverageRecord {
|
|
level_main_image_ready_count: snapshot.level_main_image_ready_count,
|
|
level_motion_ready_count: snapshot.level_motion_ready_count,
|
|
background_ready: snapshot.background_ready,
|
|
required_level_count: snapshot.required_level_count,
|
|
publish_ready: snapshot.publish_ready,
|
|
blockers: snapshot.blockers,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_agent_message_snapshot(
|
|
snapshot: BigFishAgentMessageSnapshot,
|
|
) -> BigFishAgentMessageRecord {
|
|
BigFishAgentMessageRecord {
|
|
message_id: snapshot.message_id,
|
|
role: format_big_fish_agent_message_role(snapshot.role).to_string(),
|
|
kind: format_big_fish_agent_message_kind(snapshot.kind).to_string(),
|
|
text: snapshot.text,
|
|
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_work_summary_snapshot(
|
|
snapshot: BigFishWorkSummarySnapshot,
|
|
) -> BigFishWorkSummaryRecord {
|
|
BigFishWorkSummaryRecord {
|
|
work_id: snapshot.work_id,
|
|
source_session_id: snapshot.source_session_id,
|
|
owner_user_id: snapshot.owner_user_id,
|
|
title: snapshot.title,
|
|
subtitle: snapshot.subtitle,
|
|
summary: snapshot.summary,
|
|
cover_image_src: snapshot.cover_image_src,
|
|
status: snapshot.status,
|
|
updated_at_micros: snapshot.updated_at_micros,
|
|
published_at_micros: snapshot.published_at_micros,
|
|
publish_ready: snapshot.publish_ready,
|
|
level_count: snapshot.level_count,
|
|
level_main_image_ready_count: snapshot.level_main_image_ready_count,
|
|
level_motion_ready_count: snapshot.level_motion_ready_count,
|
|
background_ready: snapshot.background_ready,
|
|
play_count: snapshot.play_count,
|
|
remix_count: snapshot.remix_count,
|
|
like_count: snapshot.like_count,
|
|
recent_play_count_7d: snapshot.recent_play_count_7_d,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_gallery_view_row(
|
|
row: BigFishWorkSummarySnapshot,
|
|
recent_play_count_7d: u32,
|
|
) -> BigFishWorkSummaryRecord {
|
|
let mut record = map_big_fish_work_summary_snapshot(row);
|
|
record.recent_play_count_7d = recent_play_count_7d;
|
|
record
|
|
}
|
|
|
|
pub(crate) fn map_big_fish_runtime_snapshot(
|
|
snapshot: BigFishRuntimeSnapshot,
|
|
) -> BigFishRuntimeRunRecord {
|
|
BigFishRuntimeRunRecord {
|
|
run_id: snapshot.run_id,
|
|
session_id: snapshot.session_id,
|
|
status: format_big_fish_run_status(snapshot.status).to_string(),
|
|
tick: snapshot.tick,
|
|
player_level: snapshot.player_level,
|
|
win_level: snapshot.win_level,
|
|
leader_entity_id: snapshot.leader_entity_id,
|
|
owned_entities: snapshot
|
|
.owned_entities
|
|
.into_iter()
|
|
.map(map_big_fish_runtime_entity_snapshot)
|
|
.collect(),
|
|
wild_entities: snapshot
|
|
.wild_entities
|
|
.into_iter()
|
|
.map(map_big_fish_runtime_entity_snapshot)
|
|
.collect(),
|
|
camera_center: map_big_fish_vector2(snapshot.camera_center),
|
|
last_input: map_big_fish_vector2(snapshot.last_input),
|
|
event_log: snapshot.event_log,
|
|
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
|
}
|
|
}
|
|
|
|
fn map_big_fish_runtime_entity_snapshot(
|
|
snapshot: BigFishRuntimeEntitySnapshot,
|
|
) -> BigFishRuntimeEntityRecord {
|
|
BigFishRuntimeEntityRecord {
|
|
entity_id: snapshot.entity_id,
|
|
level: snapshot.level,
|
|
position: map_big_fish_vector2(snapshot.position),
|
|
radius: snapshot.radius,
|
|
offscreen_seconds: snapshot.offscreen_seconds,
|
|
}
|
|
}
|
|
|
|
fn map_big_fish_vector2(snapshot: BigFishVector2) -> BigFishVector2Record {
|
|
BigFishVector2Record {
|
|
x: snapshot.x,
|
|
y: snapshot.y,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn parse_big_fish_creation_stage(
|
|
value: &str,
|
|
) -> Result<BigFishCreationStage, SpacetimeClientError> {
|
|
match value.trim() {
|
|
"collecting_anchors" => Ok(BigFishCreationStage::CollectingAnchors),
|
|
"draft_ready" => Ok(BigFishCreationStage::DraftReady),
|
|
"asset_refining" => Ok(BigFishCreationStage::AssetRefining),
|
|
"ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish),
|
|
"published" => Ok(BigFishCreationStage::Published),
|
|
other => Err(SpacetimeClientError::Runtime(format!(
|
|
"big fish creation stage `{other}` 当前尚未支持"
|
|
))),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_creation_stage(value: BigFishCreationStage) -> &'static str {
|
|
match value {
|
|
BigFishCreationStage::CollectingAnchors => "collecting_anchors",
|
|
BigFishCreationStage::DraftReady => "draft_ready",
|
|
BigFishCreationStage::AssetRefining => "asset_refining",
|
|
BigFishCreationStage::ReadyToPublish => "ready_to_publish",
|
|
BigFishCreationStage::Published => "published",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_anchor_status(value: BigFishAnchorStatus) -> &'static str {
|
|
match value {
|
|
BigFishAnchorStatus::Confirmed => "confirmed",
|
|
BigFishAnchorStatus::Inferred => "inferred",
|
|
BigFishAnchorStatus::Missing => "missing",
|
|
BigFishAnchorStatus::Locked => "locked",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_agent_message_role(value: BigFishAgentMessageRole) -> &'static str {
|
|
match value {
|
|
BigFishAgentMessageRole::User => "user",
|
|
BigFishAgentMessageRole::Assistant => "assistant",
|
|
BigFishAgentMessageRole::System => "system",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_agent_message_kind(value: BigFishAgentMessageKind) -> &'static str {
|
|
match value {
|
|
BigFishAgentMessageKind::Chat => "chat",
|
|
BigFishAgentMessageKind::Summary => "summary",
|
|
BigFishAgentMessageKind::ActionResult => "action_result",
|
|
BigFishAgentMessageKind::Warning => "warning",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_asset_kind(value: BigFishAssetKind) -> &'static str {
|
|
match value {
|
|
BigFishAssetKind::LevelMainImage => "level_main_image",
|
|
BigFishAssetKind::LevelMotion => "level_motion",
|
|
BigFishAssetKind::StageBackground => "stage_background",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_asset_status(value: BigFishAssetStatus) -> &'static str {
|
|
match value {
|
|
BigFishAssetStatus::Missing => "missing",
|
|
BigFishAssetStatus::Ready => "ready",
|
|
}
|
|
}
|
|
|
|
pub(crate) fn format_big_fish_run_status(value: BigFishRunStatus) -> &'static str {
|
|
match value {
|
|
BigFishRunStatus::Running => "running",
|
|
BigFishRunStatus::Won => "won",
|
|
BigFishRunStatus::Failed => "failed",
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
|
pub struct BigFishWorkSummaryRecord {
|
|
pub work_id: String,
|
|
pub source_session_id: String,
|
|
pub owner_user_id: String,
|
|
pub title: String,
|
|
pub subtitle: String,
|
|
pub summary: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub status: String,
|
|
pub updated_at_micros: i64,
|
|
pub published_at_micros: Option<i64>,
|
|
pub publish_ready: bool,
|
|
pub level_count: u32,
|
|
pub level_main_image_ready_count: u32,
|
|
pub level_motion_ready_count: u32,
|
|
pub background_ready: bool,
|
|
pub play_count: u32,
|
|
pub remix_count: u32,
|
|
pub like_count: u32,
|
|
pub recent_play_count_7d: u32,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn puzzle_works_mapper_keeps_typed_public_stat_fields() {
|
|
let result = PuzzleWorksProcedureResult {
|
|
ok: true,
|
|
items: vec![PuzzleWorkProfile {
|
|
work_id: "puzzle-work-1".to_string(),
|
|
profile_id: "puzzle-profile-1".to_string(),
|
|
owner_user_id: "user-1".to_string(),
|
|
source_session_id: None,
|
|
author_display_name: "测试作者".to_string(),
|
|
work_title: "雨夜拼图作品".to_string(),
|
|
work_description: "拼图作品说明".to_string(),
|
|
level_name: "雨夜拼图".to_string(),
|
|
summary: "公开作品摘要".to_string(),
|
|
theme_tags: vec!["雨夜".to_string(), "猫咪".to_string(), "神庙".to_string()],
|
|
cover_image_src: None,
|
|
cover_asset_id: None,
|
|
levels: Vec::new(),
|
|
publication_status: PuzzlePublicationStatus::Published,
|
|
updated_at_micros: 123000000,
|
|
published_at_micros: Some(123000000),
|
|
play_count: 11,
|
|
remix_count: 7,
|
|
like_count: 5,
|
|
recent_play_count_7_d: 3,
|
|
point_incentive_total_half_points: 4,
|
|
point_incentive_claimed_points: 2,
|
|
publish_ready: true,
|
|
anchor_pack: test_puzzle_anchor_pack(),
|
|
}],
|
|
error_message: None,
|
|
};
|
|
|
|
let items = map_puzzle_works_procedure_result(result)
|
|
.expect("typed puzzle works result 应能映射统计字段");
|
|
|
|
assert_eq!(items.len(), 1);
|
|
assert_eq!(items[0].play_count, 11);
|
|
assert_eq!(items[0].remix_count, 7);
|
|
assert_eq!(items[0].like_count, 5);
|
|
assert_eq!(items[0].recent_play_count_7d, 3);
|
|
}
|
|
|
|
#[test]
|
|
fn puzzle_run_mapper_maps_typed_timer_fields() {
|
|
let result = PuzzleRunProcedureResult {
|
|
ok: true,
|
|
run: Some(PuzzleRunSnapshot {
|
|
run_id: "puzzle-run-1".to_string(),
|
|
entry_profile_id: "puzzle-profile-1".to_string(),
|
|
cleared_level_count: 0,
|
|
current_level_index: 1,
|
|
current_grid_size: 3,
|
|
played_profile_ids: vec!["puzzle-profile-1".to_string()],
|
|
previous_level_tags: vec![
|
|
"雨夜".to_string(),
|
|
"猫咪".to_string(),
|
|
"神庙".to_string(),
|
|
],
|
|
current_level: Some(PuzzleRuntimeLevelSnapshot {
|
|
run_id: "puzzle-run-1".to_string(),
|
|
level_index: 1,
|
|
level_id: None,
|
|
grid_size: 3,
|
|
profile_id: "puzzle-profile-1".to_string(),
|
|
level_name: "雨夜拼图".to_string(),
|
|
author_display_name: "测试作者".to_string(),
|
|
theme_tags: vec!["雨夜".to_string(), "猫咪".to_string(), "神庙".to_string()],
|
|
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,
|
|
cols: 3,
|
|
pieces: vec![PuzzlePieceState {
|
|
piece_id: "piece-1".to_string(),
|
|
correct_row: 0,
|
|
correct_col: 0,
|
|
current_row: 0,
|
|
current_col: 0,
|
|
merged_group_id: None,
|
|
}],
|
|
merged_groups: Vec::new(),
|
|
selected_piece_id: None,
|
|
all_tiles_resolved: false,
|
|
},
|
|
status: PuzzleRuntimeLevelStatus::Playing,
|
|
started_at_ms: 0,
|
|
cleared_at_ms: None,
|
|
elapsed_ms: None,
|
|
time_limit_ms: 0,
|
|
remaining_ms: 0,
|
|
paused_accumulated_ms: 0,
|
|
pause_started_at_ms: None,
|
|
freeze_accumulated_ms: 0,
|
|
freeze_started_at_ms: None,
|
|
freeze_until_ms: None,
|
|
leaderboard_entries: Vec::new(),
|
|
}),
|
|
recommended_next_profile_id: None,
|
|
next_level_mode: "none".to_string(),
|
|
next_level_profile_id: None,
|
|
next_level_id: None,
|
|
recommended_next_works: Vec::new(),
|
|
leaderboard_entries: Vec::new(),
|
|
}),
|
|
error_message: None,
|
|
};
|
|
|
|
let run = map_puzzle_run_procedure_result(result)
|
|
.expect("typed puzzle run result 应能映射计时字段");
|
|
let level = run.current_level.expect("兼容后仍应保留当前关卡");
|
|
|
|
assert_eq!(run.run_id, "puzzle-run-1");
|
|
assert!(level.started_at_ms > 0);
|
|
assert_eq!(level.time_limit_ms, 0);
|
|
assert_eq!(level.remaining_ms, 0);
|
|
assert!(level.leaderboard_entries.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn big_fish_works_mapper_uses_typed_owner_and_public_stats() {
|
|
let result = BigFishWorksProcedureResult {
|
|
ok: true,
|
|
items: vec![BigFishWorkSummarySnapshot {
|
|
work_id: "big-fish-work-session-1".to_string(),
|
|
source_session_id: "session-1".to_string(),
|
|
owner_user_id: "user-1".to_string(),
|
|
title: "深海草稿".to_string(),
|
|
subtitle: "副标题".to_string(),
|
|
summary: "摘要".to_string(),
|
|
cover_image_src: None,
|
|
status: "draft".to_string(),
|
|
updated_at_micros: 123,
|
|
publish_ready: false,
|
|
level_count: 8,
|
|
level_main_image_ready_count: 0,
|
|
level_motion_ready_count: 0,
|
|
background_ready: false,
|
|
play_count: 9,
|
|
remix_count: 4,
|
|
like_count: 2,
|
|
recent_play_count_7_d: 6,
|
|
published_at_micros: None,
|
|
}],
|
|
error_message: None,
|
|
};
|
|
|
|
let items = map_big_fish_works_procedure_result(result, Some("user-1"))
|
|
.expect("typed big fish works result 应能映射 owner 和统计字段");
|
|
|
|
assert_eq!(items.len(), 1);
|
|
assert_eq!(items[0].owner_user_id, "user-1");
|
|
assert_eq!(items[0].published_at_micros, None);
|
|
assert_eq!(items[0].play_count, 9);
|
|
assert_eq!(items[0].remix_count, 4);
|
|
assert_eq!(items[0].like_count, 2);
|
|
assert_eq!(items[0].recent_play_count_7d, 6);
|
|
}
|
|
|
|
#[test]
|
|
fn match3d_work_mapper_keeps_generated_item_assets_json() {
|
|
let result = Match3DWorkProcedureResult {
|
|
ok: true,
|
|
work: Some(Match3DWorkSnapshot {
|
|
profile_id: "match3d-profile-1".to_string(),
|
|
owner_user_id: "user-1".to_string(),
|
|
source_session_id: "match3d-session-1".to_string(),
|
|
author_display_name: "测试作者".to_string(),
|
|
game_name: "水果抓大鹅".to_string(),
|
|
theme_text: "水果".to_string(),
|
|
summary_text: "水果主题".to_string(),
|
|
tags: vec!["水果".to_string()],
|
|
cover_image_src: String::new(),
|
|
cover_asset_id: String::new(),
|
|
clear_count: 3,
|
|
difficulty: 3,
|
|
config: Match3DCreatorConfigSnapshot {
|
|
theme_text: "水果".to_string(),
|
|
reference_image_src: None,
|
|
clear_count: 3,
|
|
difficulty: 3,
|
|
asset_style_id: None,
|
|
asset_style_label: None,
|
|
asset_style_prompt: None,
|
|
generate_click_sound: false,
|
|
},
|
|
publication_status: "Draft".to_string(),
|
|
publish_ready: false,
|
|
play_count: 0,
|
|
updated_at_micros: 123000000,
|
|
published_at_micros: None,
|
|
generated_item_assets_json: Some(
|
|
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
|
.to_string(),
|
|
),
|
|
}),
|
|
error_message: None,
|
|
};
|
|
|
|
let item = map_match3d_work_procedure_result(result)
|
|
.expect("typed match3d work result 应保留生成素材 JSON");
|
|
|
|
assert_eq!(
|
|
item.generated_item_assets_json.as_deref(),
|
|
Some(
|
|
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
|
)
|
|
);
|
|
}
|
|
|
|
fn test_puzzle_anchor_pack() -> PuzzleAnchorPack {
|
|
PuzzleAnchorPack {
|
|
theme_promise: test_puzzle_anchor_item("themePromise", "题材承诺", "雨夜冒险"),
|
|
visual_subject: test_puzzle_anchor_item("visualSubject", "画面主体", "猫咪神庙"),
|
|
visual_mood: test_puzzle_anchor_item("visualMood", "视觉气质", "温暖"),
|
|
composition_hooks: test_puzzle_anchor_item("compositionHooks", "拼图记忆点", "灯光"),
|
|
tags_and_forbidden: test_puzzle_anchor_item(
|
|
"tagsAndForbidden",
|
|
"标签与禁忌",
|
|
"雨夜, 猫咪, 神庙",
|
|
),
|
|
}
|
|
}
|
|
|
|
fn test_puzzle_anchor_item(key: &str, label: &str, value: &str) -> PuzzleAnchorItem {
|
|
PuzzleAnchorItem {
|
|
key: key.to_string(),
|
|
label: label.to_string(),
|
|
value: value.to_string(),
|
|
status: PuzzleAnchorStatus::Inferred,
|
|
}
|
|
}
|
|
}
|