314 lines
9.6 KiB
Rust
314 lines
9.6 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum PuzzleClearGenerationStatus {
|
|
Draft,
|
|
Generating,
|
|
Ready,
|
|
Failed,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum PuzzleClearActionType {
|
|
CompileDraft,
|
|
RegenerateAtlas,
|
|
UpdateWorkMeta,
|
|
UpdateBoardBackground,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum PuzzleClearRunStatus {
|
|
Playing,
|
|
LevelFailed,
|
|
LevelCleared,
|
|
Finished,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearImageAsset {
|
|
pub asset_id: String,
|
|
pub image_src: String,
|
|
pub image_object_key: String,
|
|
pub asset_object_id: String,
|
|
pub generation_provider: String,
|
|
pub prompt: String,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearPatternGroup {
|
|
pub group_id: String,
|
|
pub shape: String,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub atlas_x: u32,
|
|
pub atlas_y: u32,
|
|
pub atlas_width: u32,
|
|
pub atlas_height: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearCardAsset {
|
|
pub card_id: String,
|
|
pub group_id: String,
|
|
pub shape: String,
|
|
pub orientation: String,
|
|
pub part_x: u32,
|
|
pub part_y: u32,
|
|
pub image_src: String,
|
|
pub image_object_key: String,
|
|
pub asset_object_id: String,
|
|
pub source_atlas_cell: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorkspaceCreateRequest {
|
|
pub template_id: String,
|
|
pub work_title: String,
|
|
pub work_description: String,
|
|
pub theme_prompt: String,
|
|
#[serde(default)]
|
|
pub board_background_prompt: String,
|
|
pub generate_board_background: bool,
|
|
pub board_background_asset: Option<PuzzleClearImageAsset>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearActionRequest {
|
|
pub action_type: PuzzleClearActionType,
|
|
pub profile_id: Option<String>,
|
|
pub work_title: Option<String>,
|
|
pub work_description: Option<String>,
|
|
pub theme_prompt: Option<String>,
|
|
#[serde(default)]
|
|
pub board_background_prompt: Option<String>,
|
|
pub generate_board_background: Option<bool>,
|
|
pub board_background_asset: Option<PuzzleClearImageAsset>,
|
|
pub atlas_asset: Option<PuzzleClearImageAsset>,
|
|
pub pattern_groups: Option<Vec<PuzzleClearPatternGroup>>,
|
|
pub card_assets: Option<Vec<PuzzleClearCardAsset>>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearDraftResponse {
|
|
pub template_id: String,
|
|
pub template_name: String,
|
|
pub profile_id: Option<String>,
|
|
pub work_title: String,
|
|
pub work_description: String,
|
|
pub theme_prompt: String,
|
|
#[serde(default)]
|
|
pub board_background_prompt: String,
|
|
pub generate_board_background: bool,
|
|
pub board_background_asset: Option<PuzzleClearImageAsset>,
|
|
pub card_back_image_src: Option<String>,
|
|
pub atlas_asset: Option<PuzzleClearImageAsset>,
|
|
pub pattern_groups: Vec<PuzzleClearPatternGroup>,
|
|
pub card_assets: Vec<PuzzleClearCardAsset>,
|
|
pub generation_status: PuzzleClearGenerationStatus,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearSessionSnapshotResponse {
|
|
pub session_id: String,
|
|
pub owner_user_id: String,
|
|
pub status: PuzzleClearGenerationStatus,
|
|
pub draft: Option<PuzzleClearDraftResponse>,
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearSessionResponse {
|
|
pub session: PuzzleClearSessionSnapshotResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearActionResponse {
|
|
pub action_type: PuzzleClearActionType,
|
|
pub session: PuzzleClearSessionSnapshotResponse,
|
|
pub work: Option<PuzzleClearWorkProfileResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorkSummaryResponse {
|
|
pub runtime_kind: String,
|
|
pub work_id: String,
|
|
pub profile_id: String,
|
|
pub owner_user_id: String,
|
|
pub source_session_id: Option<String>,
|
|
pub work_title: String,
|
|
pub work_description: String,
|
|
pub theme_prompt: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub publication_status: String,
|
|
pub play_count: u32,
|
|
pub updated_at: String,
|
|
pub published_at: Option<String>,
|
|
pub publish_ready: bool,
|
|
pub generation_status: PuzzleClearGenerationStatus,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorkProfileResponse {
|
|
pub summary: PuzzleClearWorkSummaryResponse,
|
|
pub draft: PuzzleClearDraftResponse,
|
|
pub board_background_asset: Option<PuzzleClearImageAsset>,
|
|
pub atlas_asset: PuzzleClearImageAsset,
|
|
pub pattern_groups: Vec<PuzzleClearPatternGroup>,
|
|
pub card_assets: Vec<PuzzleClearCardAsset>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorksResponse {
|
|
pub items: Vec<PuzzleClearWorkSummaryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorkDetailResponse {
|
|
pub item: PuzzleClearWorkProfileResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearWorkMutationResponse {
|
|
pub item: PuzzleClearWorkProfileResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearBoardCell {
|
|
pub row: u32,
|
|
pub col: u32,
|
|
pub card: Option<PuzzleClearCardAsset>,
|
|
pub locked_group_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearBoardSnapshot {
|
|
pub rows: u32,
|
|
pub cols: u32,
|
|
pub cells: Vec<PuzzleClearBoardCell>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearRuntimeSnapshotResponse {
|
|
pub run_id: String,
|
|
pub profile_id: String,
|
|
pub owner_user_id: String,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
pub runtime_mode: Option<String>,
|
|
pub status: PuzzleClearRunStatus,
|
|
pub level_index: u32,
|
|
pub clears_done: u32,
|
|
pub target_clears: u32,
|
|
pub level_duration_seconds: u32,
|
|
pub level_started_at_ms: u64,
|
|
pub board: PuzzleClearBoardSnapshot,
|
|
pub ready_columns: Vec<Vec<PuzzleClearCardAsset>>,
|
|
pub started_at_ms: u64,
|
|
pub finished_at_ms: Option<u64>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearRunResponse {
|
|
pub run: PuzzleClearRuntimeSnapshotResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearStartRunRequest {
|
|
pub profile_id: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearSwapRequest {
|
|
pub from_row: u32,
|
|
pub from_col: u32,
|
|
pub to_row: u32,
|
|
pub to_col: u32,
|
|
pub client_action_id: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearRetryLevelRequest {
|
|
pub client_action_id: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearNextLevelRequest {
|
|
pub client_action_id: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PuzzleClearTimeUpRequest {
|
|
pub client_action_id: String,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn workspace_create_request_uses_camel_case() {
|
|
let payload = PuzzleClearWorkspaceCreateRequest {
|
|
template_id: "puzzle-clear".to_string(),
|
|
work_title: "花园拼消消".to_string(),
|
|
work_description: "轻松消除".to_string(),
|
|
theme_prompt: "春日花园".to_string(),
|
|
board_background_prompt: "樱花庭院".to_string(),
|
|
generate_board_background: true,
|
|
board_background_asset: None,
|
|
};
|
|
|
|
let value = serde_json::to_value(payload).expect("request should serialize");
|
|
|
|
assert_eq!(value["templateId"], json!("puzzle-clear"));
|
|
assert_eq!(value["themePrompt"], json!("春日花园"));
|
|
assert_eq!(value["boardBackgroundPrompt"], json!("樱花庭院"));
|
|
assert_eq!(value["generateBoardBackground"], json!(true));
|
|
}
|
|
|
|
#[test]
|
|
fn runtime_swap_request_uses_camel_case() {
|
|
let payload = PuzzleClearSwapRequest {
|
|
from_row: 1,
|
|
from_col: 2,
|
|
to_row: 1,
|
|
to_col: 3,
|
|
client_action_id: "swap-1".to_string(),
|
|
};
|
|
|
|
let value = serde_json::to_value(payload).expect("request should serialize");
|
|
|
|
assert_eq!(value["fromRow"], json!(1));
|
|
assert_eq!(value["toCol"], json!(3));
|
|
assert_eq!(value["clientActionId"], json!("swap-1"));
|
|
}
|
|
}
|