合并 origin/master:保留 3D 契约与 provider checkpoint,旧玩法表随主线退役
- server-rs/crates/shared-contracts/src/lib.rs:采用主线的模块裁剪(删掉 cfg(any()) 遗留模块、补上 agc_analytics 与 game_distribution),同时保留本分支的 editor_canvas、model3d 模块与 EDITOR_GENERATION_OPERATION_KINDS 导出 - server-rs/crates/spacetime-module/src/migration.rs:主线删除的 410 行旧玩法表 normalize 段保持删除,保留本分支的 provider_kind / provider_task_id 兼容段与对应用例 - docs/【开发运维】本地开发验证与生产运维-2026-05-15.md:校验清单同时保留 Tripo 3D 生成任务与 editor_background_music_generation / model3d_text_to_model / model3d_image_to_model - .gitignore:补回本分支新增的 3D 模型文件忽略规则(*.glb / *.gltf 等 12 行),压测数据段随主线一并删除 - 共享记忆:本分支的 3D 决策与踩坑条目保留在主线重排后的 decision-log.md 与 pitfalls.md 中
This commit is contained in:
@@ -10,12 +10,13 @@ use crate::creation_entry_config::{
|
||||
};
|
||||
|
||||
/// 后台 member 可被授予的一级 Tab 权限;账号管理仅 owner 可见,不进入该集合。
|
||||
pub const ADMIN_TAB_PERMISSIONS: [&str; 18] = [
|
||||
pub const ADMIN_TAB_PERMISSIONS: [&str; 19] = [
|
||||
"dashboard",
|
||||
"overview",
|
||||
"tables",
|
||||
"debug",
|
||||
"tracking",
|
||||
"agc-tracking",
|
||||
"gray-release",
|
||||
"redeem",
|
||||
"invite",
|
||||
@@ -1495,3 +1496,47 @@ pub struct AdminAgcModelCatalog {
|
||||
pub default_model_id: String,
|
||||
pub models: Vec<AdminAgcModel>,
|
||||
}
|
||||
|
||||
// 客户端埋点明细;时间范围按发生时间,按 (event_time, event_id) 倒序分页。
|
||||
// received_at 仅用于固定分页快照的入库时间上界。
|
||||
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct AdminAgcTrackingEventListQuery {
|
||||
pub user_id: Option<String>,
|
||||
pub project_id: Option<String>,
|
||||
pub creative_task_id: Option<String>,
|
||||
pub agent_run_id: Option<String>,
|
||||
pub event_name: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub start_time: Option<String>,
|
||||
pub end_time: Option<String>,
|
||||
pub cursor: Option<String>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdminAgcTrackingEventEntry {
|
||||
pub event_id: String,
|
||||
pub schema_version: u32,
|
||||
pub event_name: String,
|
||||
pub event_time: String,
|
||||
pub user_id: String,
|
||||
pub editor_session_id: String,
|
||||
pub project_id: Option<String>,
|
||||
pub creative_task_id: Option<String>,
|
||||
pub agent_run_id: Option<String>,
|
||||
pub agent_turn_id: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub error_code: Option<String>,
|
||||
pub source: String,
|
||||
pub client_version: String,
|
||||
pub properties: serde_json::Value,
|
||||
pub batch_id: String,
|
||||
pub received_at: String,
|
||||
}
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdminAgcTrackingEventListPayload {
|
||||
pub entries: Vec<AdminAgcTrackingEventEntry>,
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
//! 客户端埋点上传合同;字段与本地 schema v1 保持一致。
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
fn required_nullable<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
Option::<T>::deserialize(deserializer)
|
||||
}
|
||||
|
||||
macro_rules! values {
|
||||
($name:ident { $($variant:ident),+ $(,)? }) => {
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum $name { $($variant),+ }
|
||||
};
|
||||
}
|
||||
|
||||
values!(Source {
|
||||
Editor,
|
||||
Direct,
|
||||
DesignAgent,
|
||||
AssetCanvas,
|
||||
ResourceEditor,
|
||||
UiEditor,
|
||||
Manual,
|
||||
System
|
||||
});
|
||||
values!(Status { Success, Failed });
|
||||
values!(EntrySource {
|
||||
DirectLaunch,
|
||||
ProjectAssociation,
|
||||
AppRestore
|
||||
});
|
||||
values!(SessionEndReason {
|
||||
UserExit,
|
||||
AppRestart
|
||||
});
|
||||
values!(FocusReason {
|
||||
InitialFocus,
|
||||
WindowFocus,
|
||||
Restore,
|
||||
AccountChange
|
||||
});
|
||||
values!(BlurReason {
|
||||
WindowBlur,
|
||||
Minimized,
|
||||
AppExit,
|
||||
SystemSuspend,
|
||||
AccountChange
|
||||
});
|
||||
values!(CreationSource {
|
||||
HomeGame,
|
||||
HomeDesign,
|
||||
Template,
|
||||
SelectedDirectory
|
||||
});
|
||||
values!(OpenSource {
|
||||
Create,
|
||||
Picker,
|
||||
Recent,
|
||||
AppRestore,
|
||||
ProjectAssociation
|
||||
});
|
||||
values!(AgentType {
|
||||
GameAgent,
|
||||
DesignAgent
|
||||
});
|
||||
values!(RunSource {
|
||||
UserSubmit,
|
||||
UserContinue,
|
||||
Clarification,
|
||||
Approval,
|
||||
UserRetry
|
||||
});
|
||||
values!(RunEndReason {
|
||||
Finished,
|
||||
WaitingForUser,
|
||||
WaitingForApproval,
|
||||
Failed
|
||||
});
|
||||
values!(ErrorCode {
|
||||
ProviderAuthFailed,
|
||||
ProviderRateLimited,
|
||||
ProviderUnavailable,
|
||||
ProviderTimeout,
|
||||
ProviderInvalidResponse,
|
||||
LocalIoFailed,
|
||||
RuntimeFailed,
|
||||
RuntimeErrorUnclassified
|
||||
});
|
||||
values!(RevisionSource {
|
||||
Agent,
|
||||
AssetCanvas,
|
||||
ResourceEditor,
|
||||
UiEditor,
|
||||
ManualEdit,
|
||||
SystemProjection
|
||||
});
|
||||
values!(ChangeKind {
|
||||
Code,
|
||||
Asset,
|
||||
Ui,
|
||||
DesignDocument,
|
||||
Mixed
|
||||
});
|
||||
values!(PreviewSource {
|
||||
User,
|
||||
Agent,
|
||||
AutoRestore
|
||||
});
|
||||
values!(SaveSource {
|
||||
Manual,
|
||||
Auto,
|
||||
Checkpoint
|
||||
});
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SessionStart {
|
||||
pub entry_source: EntrySource,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub first_project_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SessionEnd {
|
||||
pub end_reason: SessionEndReason,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub session_duration_ms: Option<u64>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub last_project_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FocusStart {
|
||||
pub focus_interval_id: String,
|
||||
pub focus_reason: FocusReason,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub active_project_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FocusEnd {
|
||||
pub focus_interval_id: String,
|
||||
pub blur_reason: BlurReason,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub focus_duration_ms: Option<u64>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub active_project_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ProjectCreated {
|
||||
pub creation_source: CreationSource,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub project_template_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ProjectOpened {
|
||||
pub open_source: OpenSource,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub is_first_open: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EmptyProperties {}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RunFinished {
|
||||
pub agent_type: AgentType,
|
||||
pub run_source: RunSource,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub duration_ms: Option<u64>,
|
||||
pub retry_index: u64,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub output_change_detected: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub revision_id: Option<String>,
|
||||
pub end_reason: RunEndReason,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RevisionCreated {
|
||||
pub revision_id: String,
|
||||
pub revision_source: RevisionSource,
|
||||
pub change_kind: ChangeKind,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub files_changed_count: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PreviewReady {
|
||||
pub preview_source: PreviewSource,
|
||||
pub preview_version: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ready_duration_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ProjectSaved {
|
||||
pub save_source: SaveSource,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub revision_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(
|
||||
tag = "event_name",
|
||||
content = "properties",
|
||||
rename_all = "snake_case",
|
||||
deny_unknown_fields
|
||||
)]
|
||||
pub enum EventData {
|
||||
EditorSessionStart(SessionStart),
|
||||
EditorSessionEnd(SessionEnd),
|
||||
EditorFocusStart(FocusStart),
|
||||
EditorFocusEnd(FocusEnd),
|
||||
ProjectCreateSuccess(ProjectCreated),
|
||||
ProjectOpen(ProjectOpened),
|
||||
CreativeTaskSubmit(EmptyProperties),
|
||||
AgentRunCompleted(RunFinished),
|
||||
AgentRunFailed(RunFinished),
|
||||
ProjectRevisionCreated(RevisionCreated),
|
||||
PreviewReady(PreviewReady),
|
||||
ProjectSave(ProjectSaved),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Event {
|
||||
pub schema_version: u32,
|
||||
pub event_id: String,
|
||||
pub event_name: String,
|
||||
pub event_time: String,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub user_id: Option<String>,
|
||||
pub editor_session_id: String,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub project_id: Option<String>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub creative_task_id: Option<String>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub agent_run_id: Option<String>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub agent_turn_id: Option<String>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub status: Option<Status>,
|
||||
#[serde(deserialize_with = "required_nullable")]
|
||||
pub error_code: Option<ErrorCode>,
|
||||
pub source: Source,
|
||||
pub client_version: String,
|
||||
pub properties: Value,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct AgcAnalyticsBatch {
|
||||
pub schema_version: u32,
|
||||
pub batch_id: String,
|
||||
pub destination_origin: String,
|
||||
pub user_id: String,
|
||||
pub events: Vec<Event>,
|
||||
}
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct AgcAnalyticsAcknowledgement {
|
||||
pub acknowledged_batch_ids: Vec<String>,
|
||||
pub event_count: u32,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,261 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateBigFishSessionRequest {
|
||||
#[serde(default)]
|
||||
pub seed_text: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SendBigFishMessageRequest {
|
||||
pub client_message_id: String,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub quick_fill_requested: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecuteBigFishActionRequest {
|
||||
pub action: String,
|
||||
#[serde(default)]
|
||||
pub level: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub motion_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RecordBigFishPlayRequest {
|
||||
#[serde(default)]
|
||||
pub elapsed_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SubmitBigFishInputRequest {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishAnchorItemResponse {
|
||||
pub key: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishAnchorPackResponse {
|
||||
pub gameplay_promise: BigFishAnchorItemResponse,
|
||||
pub ecology_visual_theme: BigFishAnchorItemResponse,
|
||||
pub growth_ladder: BigFishAnchorItemResponse,
|
||||
pub risk_tempo: BigFishAnchorItemResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishLevelBlueprintResponse {
|
||||
pub level: u32,
|
||||
pub name: String,
|
||||
pub one_line_fantasy: String,
|
||||
pub text_description: String,
|
||||
pub silhouette_direction: String,
|
||||
pub size_ratio: f32,
|
||||
pub visual_description: String,
|
||||
pub visual_prompt_seed: String,
|
||||
pub idle_motion_description: String,
|
||||
pub move_motion_description: String,
|
||||
pub motion_prompt_seed: String,
|
||||
pub merge_source_level: Option<u32>,
|
||||
pub prey_window: Vec<u32>,
|
||||
pub threat_window: Vec<u32>,
|
||||
pub is_final_level: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishBackgroundBlueprintResponse {
|
||||
pub theme: String,
|
||||
pub color_mood: String,
|
||||
pub foreground_hints: String,
|
||||
pub midground_composition: String,
|
||||
pub background_depth: String,
|
||||
pub safe_play_area_hint: String,
|
||||
pub spawn_edge_hint: String,
|
||||
pub background_prompt_seed: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishRuntimeParamsResponse {
|
||||
pub level_count: u32,
|
||||
pub merge_count_per_upgrade: u32,
|
||||
pub spawn_target_count: u32,
|
||||
pub leader_move_speed: f32,
|
||||
pub follower_catch_up_speed: f32,
|
||||
pub offscreen_cull_seconds: f32,
|
||||
pub prey_spawn_delta_levels: Vec<u32>,
|
||||
pub threat_spawn_delta_levels: Vec<u32>,
|
||||
pub win_level: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishGameDraftResponse {
|
||||
pub title: String,
|
||||
pub subtitle: String,
|
||||
pub core_fun: String,
|
||||
pub ecology_theme: String,
|
||||
pub levels: Vec<BigFishLevelBlueprintResponse>,
|
||||
pub background: BigFishBackgroundBlueprintResponse,
|
||||
pub runtime_params: BigFishRuntimeParamsResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishAgentMessageResponse {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishAssetSlotResponse {
|
||||
pub slot_id: String,
|
||||
pub asset_kind: String,
|
||||
pub level: Option<u32>,
|
||||
pub motion_key: Option<String>,
|
||||
pub status: String,
|
||||
pub asset_url: Option<String>,
|
||||
pub prompt_snapshot: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishAssetCoverageResponse {
|
||||
pub level_main_image_ready_count: u32,
|
||||
pub level_motion_ready_count: u32,
|
||||
pub background_ready: bool,
|
||||
pub required_level_count: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: BigFishAnchorPackResponse,
|
||||
pub draft: Option<BigFishGameDraftResponse>,
|
||||
pub asset_slots: Vec<BigFishAssetSlotResponse>,
|
||||
pub asset_coverage: BigFishAssetCoverageResponse,
|
||||
pub messages: Vec<BigFishAgentMessageResponse>,
|
||||
pub last_assistant_reply: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishSessionResponse {
|
||||
pub session: BigFishSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishActionResponse {
|
||||
pub session: BigFishSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishVector2Response {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishRuntimeEntityResponse {
|
||||
pub entity_id: String,
|
||||
pub level: u32,
|
||||
pub position: BigFishVector2Response,
|
||||
pub radius: f32,
|
||||
pub offscreen_seconds: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishRuntimeSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub session_id: String,
|
||||
pub status: String,
|
||||
pub tick: u64,
|
||||
pub player_level: u32,
|
||||
pub win_level: u32,
|
||||
pub leader_entity_id: Option<String>,
|
||||
pub owned_entities: Vec<BigFishRuntimeEntityResponse>,
|
||||
pub wild_entities: Vec<BigFishRuntimeEntityResponse>,
|
||||
pub camera_center: BigFishVector2Response,
|
||||
pub last_input: BigFishVector2Response,
|
||||
pub event_log: Vec<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishRunResponse {
|
||||
pub run: BigFishRuntimeSnapshotResponse,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn big_fish_session_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(CreateBigFishSessionRequest {
|
||||
seed_text: Some("深海机械鱼".to_string()),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload, json!({ "seedText": "深海机械鱼" }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_fish_action_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(ExecuteBigFishActionRequest {
|
||||
action: "big_fish_generate_level_motion".to_string(),
|
||||
level: Some(3),
|
||||
motion_key: Some("move_swim".to_string()),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["motionKey"], json!("move_swim"));
|
||||
assert_eq!(payload["level"], json!(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_big_fish_play_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(RecordBigFishPlayRequest {
|
||||
elapsed_ms: Some(12_345),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload, json!({ "elapsedMs": 12_345 }));
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishWorkSummaryResponse {
|
||||
pub work_id: String,
|
||||
pub source_session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub author_display_name: String,
|
||||
pub title: String,
|
||||
pub subtitle: String,
|
||||
pub summary: String,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub status: String,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
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,
|
||||
#[serde(default)]
|
||||
pub play_count: u32,
|
||||
#[serde(default)]
|
||||
pub remix_count: u32,
|
||||
#[serde(default)]
|
||||
pub like_count: u32,
|
||||
#[serde(default)]
|
||||
pub recent_play_count_7d: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BigFishWorksResponse {
|
||||
pub items: Vec<BigFishWorkSummaryResponse>,
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParseCreationAgentDocumentInputRequest {
|
||||
pub file_name: String,
|
||||
#[serde(default)]
|
||||
pub content_type: Option<String>,
|
||||
pub content_base64: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreationAgentDocumentInputPayload {
|
||||
pub file_name: String,
|
||||
#[serde(default)]
|
||||
pub content_type: Option<String>,
|
||||
pub size_bytes: usize,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub source_asset_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ParseCreationAgentDocumentInputResponse {
|
||||
pub document: CreationAgentDocumentInputPayload,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
//! 游戏分发 API 的跨端 DTO。
|
||||
//!
|
||||
//! 领域状态机位于 `module-game-distribution`;本文件只描述 HTTP/客户端可见的
|
||||
//! 数据形状,不能承载 owner、审核或公开切换规则。
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const GAME_DISTRIBUTION_CATEGORIES: [&str; 7] =
|
||||
["休闲", "益智", "动作", "冒险", "模拟", "策略", "其他"];
|
||||
|
||||
/// 发布页免费生成简介与分类的输入。
|
||||
///
|
||||
/// 只传经过裁剪的项目摘要,不传本地绝对路径、聊天记录、凭据或完整 manifest。
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionPublishMetadataSuggestionRequest {
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub goal: Option<String>,
|
||||
#[serde(default)]
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionPublishMetadataSuggestion {
|
||||
pub summary: String,
|
||||
pub category: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GameDistributionVersionStatus {
|
||||
AwaitingUpload,
|
||||
Uploaded,
|
||||
Validating,
|
||||
PendingReview,
|
||||
Published,
|
||||
UploadFailed,
|
||||
ValidationFailed,
|
||||
Rejected,
|
||||
Cancelled,
|
||||
Revoked,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GameDistributionVisibility {
|
||||
Unpublished,
|
||||
Published,
|
||||
Suspended,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GameDistributionInputMode {
|
||||
Keyboard,
|
||||
Mouse,
|
||||
Touch,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GameDistributionOrientation {
|
||||
Landscape,
|
||||
Portrait,
|
||||
Responsive,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionDeviceSupport {
|
||||
pub desktop: bool,
|
||||
pub mobile: bool,
|
||||
pub touch: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionAuthor {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub avatar_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionVersionSummary {
|
||||
pub id: String,
|
||||
pub version: String,
|
||||
pub entry_url: String,
|
||||
pub sha256: String,
|
||||
pub published_at: String,
|
||||
pub controls: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionGameSummary {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub summary: String,
|
||||
pub description: String,
|
||||
pub category: String,
|
||||
pub tags: Vec<String>,
|
||||
pub cover_color: String,
|
||||
pub icon: String,
|
||||
pub author: GameDistributionAuthor,
|
||||
pub device_support: GameDistributionDeviceSupport,
|
||||
#[serde(default)]
|
||||
pub input_modes: Vec<GameDistributionInputMode>,
|
||||
#[serde(default)]
|
||||
pub orientation: Option<GameDistributionOrientation>,
|
||||
pub status: GameDistributionVisibility,
|
||||
pub current_version: Option<GameDistributionVersionSummary>,
|
||||
pub play_count: u64,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionListResponse {
|
||||
pub games: Vec<GameDistributionGameSummary>,
|
||||
#[serde(default)]
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionCreateGameRequest {
|
||||
#[serde(default)]
|
||||
pub local_project_id: Option<String>,
|
||||
pub title: String,
|
||||
pub summary: String,
|
||||
#[serde(default)]
|
||||
pub description: Option<String>,
|
||||
pub category: String,
|
||||
#[serde(default)]
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
/// 截图素材 ID(最多 6 张,复用平台图片上传与归属校验)。
|
||||
#[serde(default)]
|
||||
pub screenshots: Vec<String>,
|
||||
pub device_support: GameDistributionDeviceSupport,
|
||||
pub input_modes: Vec<GameDistributionInputMode>,
|
||||
pub orientation: GameDistributionOrientation,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionCreateVersionRequest {
|
||||
#[serde(default)]
|
||||
pub local_project_id: Option<String>,
|
||||
pub package_sha256: String,
|
||||
pub package_bytes: u64,
|
||||
pub package_file_count: u32,
|
||||
pub package_entry_path: String,
|
||||
pub game_metadata: GameDistributionCreateGameRequest,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GameDistributionPrivateVersion {
|
||||
pub version_id: String,
|
||||
pub game_id: String,
|
||||
pub version_number: u64,
|
||||
pub package_sha256: String,
|
||||
pub package_bytes: u64,
|
||||
pub status: GameDistributionVersionStatus,
|
||||
#[serde(default)]
|
||||
pub review_reason: Option<String>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_game_request_round_trips_local_project_id() {
|
||||
let payload: GameDistributionCreateGameRequest =
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"localProjectId": "proj-1",
|
||||
"title": "游戏",
|
||||
"summary": "简介",
|
||||
"category": "益智",
|
||||
"deviceSupport": { "desktop": true, "mobile": false, "touch": false },
|
||||
"inputModes": ["keyboard"],
|
||||
"orientation": "responsive",
|
||||
}))
|
||||
.expect("请求应可解析");
|
||||
assert_eq!(payload.local_project_id.as_deref(), Some("proj-1"));
|
||||
let serialized = serde_json::to_value(&payload).expect("请求应可序列化");
|
||||
assert_eq!(serialized["localProjectId"], "proj-1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_create_game_request_without_local_project_id_stays_compatible() {
|
||||
let payload: GameDistributionCreateGameRequest =
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"title": "游戏",
|
||||
"summary": "简介",
|
||||
"category": "益智",
|
||||
"deviceSupport": { "desktop": true, "mobile": false, "touch": false },
|
||||
"inputModes": ["keyboard"],
|
||||
"orientation": "responsive",
|
||||
}))
|
||||
.expect("旧请求应继续可解析");
|
||||
assert_eq!(payload.local_project_id, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_version_request_accepts_local_project_id() {
|
||||
let payload: GameDistributionCreateVersionRequest =
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"localProjectId": "proj-1",
|
||||
"packageSha256": "a".repeat(64),
|
||||
"packageBytes": 10,
|
||||
"packageFileCount": 1,
|
||||
"packageEntryPath": "index.html",
|
||||
"gameMetadata": {
|
||||
"title": "游戏",
|
||||
"summary": "简介",
|
||||
"category": "益智",
|
||||
"deviceSupport": { "desktop": true, "mobile": false, "touch": false },
|
||||
"inputModes": ["keyboard"],
|
||||
"orientation": "responsive",
|
||||
},
|
||||
}))
|
||||
.expect("版本请求应可解析");
|
||||
assert_eq!(payload.local_project_id.as_deref(), Some("proj-1"));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,13 @@
|
||||
pub mod admin;
|
||||
pub mod agc_analytics;
|
||||
pub mod agc_project_snapshots;
|
||||
pub mod ai;
|
||||
pub mod api;
|
||||
#[cfg(feature = "oss-contracts")]
|
||||
pub mod assets;
|
||||
pub mod auth;
|
||||
#[cfg(any())]
|
||||
pub mod bark_battle;
|
||||
#[cfg(any())]
|
||||
pub mod big_fish;
|
||||
#[cfg(any())]
|
||||
pub mod big_fish_works;
|
||||
pub mod client_downloads;
|
||||
#[cfg(any())]
|
||||
pub mod creation_agent_document_input;
|
||||
pub mod creation_audio;
|
||||
#[cfg(any())]
|
||||
pub mod creation_entry_config;
|
||||
#[cfg(any())]
|
||||
pub mod creative_agent;
|
||||
pub mod editor_agent;
|
||||
pub mod editor_canvas;
|
||||
pub mod editor_generation;
|
||||
@@ -32,35 +21,8 @@ pub use editor_generation::{
|
||||
};
|
||||
pub mod external_generation;
|
||||
pub mod game_creation_app;
|
||||
pub mod game_distribution;
|
||||
pub mod hyper3d;
|
||||
pub mod llm;
|
||||
pub mod model3d;
|
||||
#[cfg(any())]
|
||||
pub mod public_work;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_agent;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_clear;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_creative_template;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_gallery;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_runtime;
|
||||
#[cfg(any())]
|
||||
pub mod puzzle_works;
|
||||
pub mod runtime;
|
||||
#[cfg(any())]
|
||||
pub mod runtime_story;
|
||||
#[cfg(any())]
|
||||
pub mod square_hole_agent;
|
||||
#[cfg(any())]
|
||||
pub mod square_hole_runtime;
|
||||
#[cfg(any())]
|
||||
pub mod square_hole_works;
|
||||
#[cfg(any())]
|
||||
pub mod story;
|
||||
#[cfg(any())]
|
||||
pub mod visual_novel;
|
||||
#[cfg(any())]
|
||||
pub mod wooden_fish;
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::creation_audio::CreationAudioAsset;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateMatch3DAgentSessionRequest {
|
||||
#[serde(default)]
|
||||
pub seed_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub clear_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub difficulty: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub asset_style_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub asset_style_label: Option<String>,
|
||||
#[serde(default)]
|
||||
pub asset_style_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub generate_click_sound: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SendMatch3DAgentMessageRequest {
|
||||
pub client_message_id: String,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub quick_fill_requested: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecuteMatch3DAgentActionRequest {
|
||||
pub action: String,
|
||||
#[serde(default)]
|
||||
pub game_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub summary: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub clear_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub difficulty: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub generate_click_sound: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DCreatorConfigResponse {
|
||||
pub theme_text: String,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
pub clear_count: u32,
|
||||
pub difficulty: u32,
|
||||
#[serde(default)]
|
||||
pub asset_style_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub asset_style_label: Option<String>,
|
||||
#[serde(default)]
|
||||
pub asset_style_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub generate_click_sound: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DResultDraftResponse {
|
||||
pub profile_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
#[serde(default)]
|
||||
pub summary_text: Option<String>,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
pub clear_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub total_item_count: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub background_prompt: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub background_image_object_key: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub generated_background_asset: Option<Match3DGeneratedBackgroundAssetResponse>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub generated_item_assets: Vec<Match3DGeneratedItemAssetResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedBackgroundAssetResponse {
|
||||
pub prompt: String,
|
||||
#[serde(default)]
|
||||
pub level_scene_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_image_object_key: Option<String>,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedItemImageViewResponse {
|
||||
pub view_id: String,
|
||||
pub view_index: u32,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedItemAssetResponse {
|
||||
pub item_id: String,
|
||||
pub item_name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub item_size: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub image_views: Vec<Match3DGeneratedItemImageViewResponse>,
|
||||
#[serde(default)]
|
||||
pub model_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub model_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub model_file_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub task_uuid: Option<String>,
|
||||
#[serde(default)]
|
||||
pub subscription_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub sound_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_style: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music: Option<CreationAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub click_sound: Option<CreationAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub background_asset: Option<Match3DGeneratedBackgroundAssetResponse>,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAnchorItemResponse {
|
||||
pub key: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAnchorPackResponse {
|
||||
pub theme: Match3DAnchorItemResponse,
|
||||
pub clear_count: Match3DAnchorItemResponse,
|
||||
pub difficulty: Match3DAnchorItemResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAgentMessageResponse {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAgentSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: Match3DAnchorPackResponse,
|
||||
#[serde(default)]
|
||||
pub config: Option<Match3DCreatorConfigResponse>,
|
||||
#[serde(default)]
|
||||
pub draft: Option<Match3DResultDraftResponse>,
|
||||
pub messages: Vec<Match3DAgentMessageResponse>,
|
||||
#[serde(default)]
|
||||
pub last_assistant_reply: Option<String>,
|
||||
#[serde(default)]
|
||||
pub published_profile_id: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAgentSessionResponse {
|
||||
pub session: Match3DAgentSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DAgentActionResponse {
|
||||
pub session: Match3DAgentSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn create_match3d_session_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(CreateMatch3DAgentSessionRequest {
|
||||
seed_text: Some("水果消除".to_string()),
|
||||
theme_text: Some("水果".to_string()),
|
||||
reference_image_src: Some("data:image/png;base64,abc".to_string()),
|
||||
clear_count: Some(4),
|
||||
difficulty: Some(3),
|
||||
asset_style_id: Some("flat-icon".to_string()),
|
||||
asset_style_label: Some("扁平图标".to_string()),
|
||||
asset_style_prompt: Some("干净扁平 2D 游戏道具图标风格".to_string()),
|
||||
generate_click_sound: Some(true),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["seedText"], json!("水果消除"));
|
||||
assert_eq!(payload["themeText"], json!("水果"));
|
||||
assert_eq!(
|
||||
payload["referenceImageSrc"],
|
||||
json!("data:image/png;base64,abc")
|
||||
);
|
||||
assert_eq!(payload["clearCount"], json!(4));
|
||||
assert_eq!(payload["assetStyleId"], json!("flat-icon"));
|
||||
assert_eq!(payload["generateClickSound"], json!(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_match3d_action_request_serializes_click_sound_toggle() {
|
||||
let payload = serde_json::to_value(ExecuteMatch3DAgentActionRequest {
|
||||
action: "match3d_compile_draft".to_string(),
|
||||
game_name: None,
|
||||
summary: None,
|
||||
tags: None,
|
||||
cover_image_src: None,
|
||||
clear_count: None,
|
||||
difficulty: None,
|
||||
generate_click_sound: Some(true),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["action"], json!("match3d_compile_draft"));
|
||||
assert_eq!(payload["generateClickSound"], json!(true));
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartMatch3DRunRequest {
|
||||
pub profile_id: String,
|
||||
#[serde(default)]
|
||||
pub item_type_count_override: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClickMatch3DItemRequest {
|
||||
#[serde(default)]
|
||||
pub run_id: Option<String>,
|
||||
pub item_instance_id: String,
|
||||
pub client_snapshot_version: u64,
|
||||
pub client_event_id: String,
|
||||
pub clicked_at_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StopMatch3DRunRequest {
|
||||
pub client_action_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DItemSnapshotResponse {
|
||||
pub item_instance_id: String,
|
||||
pub item_type_id: String,
|
||||
pub visual_key: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub radius: f32,
|
||||
pub layer: u32,
|
||||
pub state: String,
|
||||
pub clickable: bool,
|
||||
#[serde(default)]
|
||||
pub tray_slot_index: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DTraySlotResponse {
|
||||
pub slot_index: u32,
|
||||
#[serde(default)]
|
||||
pub item_instance_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_type_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub visual_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
/// 对外 HTTP 快照版本。领域层内部字段名为 board_version,facade 需要在这里完成映射。
|
||||
pub snapshot_version: u64,
|
||||
pub started_at_ms: u64,
|
||||
pub duration_limit_ms: u64,
|
||||
#[serde(default)]
|
||||
pub server_now_ms: Option<u64>,
|
||||
pub remaining_ms: u64,
|
||||
pub clear_count: u32,
|
||||
pub total_item_count: u32,
|
||||
pub cleared_item_count: u32,
|
||||
pub items: Vec<Match3DItemSnapshotResponse>,
|
||||
pub tray_slots: Vec<Match3DTraySlotResponse>,
|
||||
#[serde(default)]
|
||||
pub failure_reason: Option<String>,
|
||||
#[serde(default)]
|
||||
pub last_confirmed_action_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DClickConfirmationResponse {
|
||||
pub accepted: bool,
|
||||
#[serde(default)]
|
||||
pub reject_reason: Option<String>,
|
||||
#[serde(default)]
|
||||
pub entered_slot_index: Option<u32>,
|
||||
pub cleared_item_instance_ids: Vec<String>,
|
||||
pub run: Match3DRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DRunResponse {
|
||||
pub run: Match3DRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DClickResponse {
|
||||
pub confirmation: Match3DClickConfirmationResponse,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn click_match3d_item_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(ClickMatch3DItemRequest {
|
||||
run_id: Some("run-1".to_string()),
|
||||
item_instance_id: "item-1".to_string(),
|
||||
client_snapshot_version: 7,
|
||||
client_event_id: "event-1".to_string(),
|
||||
clicked_at_ms: 12_345,
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["runId"], json!("run-1"));
|
||||
assert_eq!(payload["itemInstanceId"], json!("item-1"));
|
||||
assert_eq!(payload["clientSnapshotVersion"], json!(7));
|
||||
assert_eq!(payload["clientEventId"], json!("event-1"));
|
||||
assert_eq!(payload["clickedAtMs"], json!(12_345));
|
||||
}
|
||||
}
|
||||
@@ -1,337 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::creation_audio::CreationAudioAsset;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PutMatch3DWorkRequest {
|
||||
pub game_name: String,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
pub clear_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DWorkTagsRequest {
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
#[serde(default)]
|
||||
pub summary: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DWorkTagsResponse {
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PutMatch3DAudioAssetsRequest {
|
||||
pub generated_item_assets: Vec<Match3DGeneratedItemAssetResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PersistMatch3DGeneratedModelRequest {
|
||||
pub item_id: String,
|
||||
pub item_name: String,
|
||||
pub source_url: String,
|
||||
#[serde(default)]
|
||||
pub file_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub task_uuid: Option<String>,
|
||||
#[serde(default)]
|
||||
pub subscription_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PersistMatch3DGeneratedModelResponse {
|
||||
pub asset: Match3DGeneratedItemAssetResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DCoverImageRequest {
|
||||
pub prompt: String,
|
||||
#[serde(default)]
|
||||
pub uploaded_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_srcs: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DCoverImageResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
pub cover_image_src: String,
|
||||
pub cover_image_object_key: String,
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DBackgroundImageRequest {
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DBackgroundImageResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
pub background_image_src: String,
|
||||
pub background_image_object_key: String,
|
||||
pub generated_background_asset: Match3DGeneratedBackgroundAssetResponse,
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DContainerImageRequest {
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DContainerImageResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
pub container_image_src: String,
|
||||
pub container_image_object_key: String,
|
||||
pub generated_background_asset: Match3DGeneratedBackgroundAssetResponse,
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DItemAssetsRequest {
|
||||
pub item_names: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub mode: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GenerateMatch3DItemAssetsResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
pub generated_item_assets: Vec<Match3DGeneratedItemAssetResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DWorkSummaryResponse {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
pub clear_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[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")]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub background_image_object_key: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub generated_background_asset: Option<Match3DGeneratedBackgroundAssetResponse>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub generated_item_assets: Vec<Match3DGeneratedItemAssetResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedBackgroundAssetResponse {
|
||||
pub prompt: String,
|
||||
#[serde(default)]
|
||||
pub level_scene_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub item_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub container_image_object_key: Option<String>,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedItemImageViewResponse {
|
||||
pub view_id: String,
|
||||
pub view_index: u32,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DGeneratedItemAssetResponse {
|
||||
pub item_id: String,
|
||||
pub item_name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub item_size: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub image_object_key: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub image_views: Vec<Match3DGeneratedItemImageViewResponse>,
|
||||
#[serde(default)]
|
||||
pub model_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub model_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub model_file_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub task_uuid: Option<String>,
|
||||
#[serde(default)]
|
||||
pub subscription_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub sound_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_style: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music: Option<CreationAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub click_sound: Option<CreationAudioAsset>,
|
||||
#[serde(default)]
|
||||
pub background_asset: Option<Match3DGeneratedBackgroundAssetResponse>,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DWorkProfileResponse {
|
||||
#[serde(flatten)]
|
||||
pub summary: Match3DWorkSummaryResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DWorksResponse {
|
||||
pub items: Vec<Match3DWorkSummaryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DWorkDetailResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Match3DWorkMutationResponse {
|
||||
pub item: Match3DWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn match3d_work_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(PutMatch3DWorkRequest {
|
||||
game_name: "水果抓大鹅".to_string(),
|
||||
theme_text: Some("水果".to_string()),
|
||||
summary: "水果主题".to_string(),
|
||||
tags: vec!["水果".to_string()],
|
||||
cover_image_src: None,
|
||||
reference_image_src: None,
|
||||
clear_count: 4,
|
||||
difficulty: 5,
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 公开作品列表统一契约。
|
||||
///
|
||||
/// 该契约面向 BFF 和后续可选前端直连订阅,字段只包含平台公开卡片需要的摘要信息。
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PublicWorkGalleryEntryResponse {
|
||||
pub source_type: String,
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub public_work_code: String,
|
||||
pub owner_user_id: String,
|
||||
pub author_display_name: String,
|
||||
pub world_name: String,
|
||||
pub subtitle: String,
|
||||
pub summary_text: String,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub play_count: u32,
|
||||
pub remix_count: u32,
|
||||
pub like_count: u32,
|
||||
#[serde(default)]
|
||||
pub recent_play_count_7d: u32,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub updated_at: String,
|
||||
pub sort_time_micros: i64,
|
||||
}
|
||||
|
||||
/// 公开作品详情统一摘要契约。
|
||||
///
|
||||
/// `detail_payload_json` 只承载详情页展示扩展字段,不承载正式 runtime 配置。
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PublicWorkDetailEntryResponse {
|
||||
#[serde(flatten)]
|
||||
pub entry: PublicWorkGalleryEntryResponse,
|
||||
pub detail_payload_json: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PublicWorkGalleryResponse {
|
||||
pub items: Vec<PublicWorkGalleryEntryResponse>,
|
||||
#[serde(default)]
|
||||
pub has_more: bool,
|
||||
#[serde(default)]
|
||||
pub next_cursor: Option<String>,
|
||||
#[serde(default)]
|
||||
pub total_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PublicWorkDetailResponse {
|
||||
pub item: PublicWorkDetailEntryResponse,
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::creation_audio::CreationAudioAsset;
|
||||
use crate::external_generation::ExternalGenerationJobStatusRecord;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreatePuzzleAgentSessionRequest {
|
||||
#[serde(default)]
|
||||
pub seed_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub picture_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_srcs: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_asset_object_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_asset_object_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub image_model: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ai_redraw: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SendPuzzleAgentMessageRequest {
|
||||
pub client_message_id: String,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub quick_fill_requested: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecutePuzzleAgentActionRequest {
|
||||
pub action: String,
|
||||
#[serde(default)]
|
||||
pub prompt_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_srcs: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_asset_object_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub reference_image_asset_object_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub image_model: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ai_redraw: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub candidate_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub should_auto_name_level: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub candidate_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub picture_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub summary: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub levels_json: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleFormDraftResponse {
|
||||
#[serde(default)]
|
||||
pub work_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub picture_description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAnchorItemResponse {
|
||||
pub key: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAnchorPackResponse {
|
||||
pub theme_promise: PuzzleAnchorItemResponse,
|
||||
pub visual_subject: PuzzleAnchorItemResponse,
|
||||
pub visual_mood: PuzzleAnchorItemResponse,
|
||||
pub composition_hooks: PuzzleAnchorItemResponse,
|
||||
pub tags_and_forbidden: PuzzleAnchorItemResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleGeneratedImageCandidateResponse {
|
||||
pub candidate_id: String,
|
||||
pub image_src: String,
|
||||
pub asset_id: String,
|
||||
pub prompt: String,
|
||||
#[serde(default)]
|
||||
pub actual_prompt: Option<String>,
|
||||
pub source_type: String,
|
||||
pub selected: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleCreatorIntentResponse {
|
||||
pub source_mode: String,
|
||||
pub raw_messages_summary: String,
|
||||
pub theme_promise: String,
|
||||
pub visual_subject: String,
|
||||
pub visual_mood: Vec<String>,
|
||||
pub composition_hooks: Vec<String>,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub forbidden_directives: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleResultDraftResponse {
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub level_name: String,
|
||||
pub summary: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub forbidden_directives: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub creator_intent: Option<PuzzleCreatorIntentResponse>,
|
||||
pub anchor_pack: PuzzleAnchorPackResponse,
|
||||
pub candidates: Vec<PuzzleGeneratedImageCandidateResponse>,
|
||||
#[serde(default)]
|
||||
pub selected_candidate_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
pub generation_status: String,
|
||||
pub levels: Vec<PuzzleDraftLevelResponse>,
|
||||
#[serde(default)]
|
||||
pub form_draft: Option<PuzzleFormDraftResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleDraftLevelResponse {
|
||||
pub level_id: String,
|
||||
pub level_name: String,
|
||||
pub picture_description: String,
|
||||
#[serde(default)]
|
||||
pub picture_reference: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_background_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_background_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_scene_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_background_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music: Option<CreationAudioAsset>,
|
||||
pub candidates: Vec<PuzzleGeneratedImageCandidateResponse>,
|
||||
#[serde(default)]
|
||||
pub selected_candidate_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
pub generation_status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentMessageResponse {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentSuggestedActionResponse {
|
||||
pub id: String,
|
||||
pub action_type: String,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleResultPreviewBlockerResponse {
|
||||
pub id: String,
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleResultPreviewFindingResponse {
|
||||
pub id: String,
|
||||
pub severity: String,
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleResultPreviewEnvelopeResponse {
|
||||
pub draft: PuzzleResultDraftResponse,
|
||||
pub blockers: Vec<PuzzleResultPreviewBlockerResponse>,
|
||||
pub quality_findings: Vec<PuzzleResultPreviewFindingResponse>,
|
||||
pub publish_ready: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub seed_text: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: PuzzleAnchorPackResponse,
|
||||
#[serde(default)]
|
||||
pub draft: Option<PuzzleResultDraftResponse>,
|
||||
pub messages: Vec<PuzzleAgentMessageResponse>,
|
||||
#[serde(default)]
|
||||
pub last_assistant_reply: Option<String>,
|
||||
#[serde(default)]
|
||||
pub published_profile_id: Option<String>,
|
||||
pub suggested_actions: Vec<PuzzleAgentSuggestedActionResponse>,
|
||||
#[serde(default)]
|
||||
pub result_preview: Option<PuzzleResultPreviewEnvelopeResponse>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentSessionResponse {
|
||||
pub session: PuzzleAgentSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentOperationResponse {
|
||||
pub operation_id: String,
|
||||
pub operation_type: String,
|
||||
pub status: String,
|
||||
pub phase_label: String,
|
||||
pub phase_detail: String,
|
||||
pub progress: u32,
|
||||
#[serde(default)]
|
||||
pub error: Option<String>,
|
||||
#[serde(default)]
|
||||
pub queue_state: Option<ExternalGenerationJobStatusRecord>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleAgentActionResponse {
|
||||
pub operation: PuzzleAgentOperationResponse,
|
||||
/// 操作完成后的最新会话快照,供前端直接更新界面,避免重复拉取完整 session。
|
||||
pub session: PuzzleAgentSessionSnapshotResponse,
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::external_generation::ExternalGenerationJobStatusRecord;
|
||||
|
||||
#[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>,
|
||||
#[serde(default)]
|
||||
pub queue_state: Option<ExternalGenerationJobStatusRecord>,
|
||||
}
|
||||
|
||||
#[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"));
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum PuzzleTemplatePricingUnit {
|
||||
Point,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PuzzleSupportedLevelMode {
|
||||
Single,
|
||||
Multi,
|
||||
SingleOrMulti,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PuzzleLevelGenerationMode {
|
||||
SingleLevel,
|
||||
MultiLevel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleTemplateCostRange {
|
||||
pub min_points: u32,
|
||||
pub max_points: u32,
|
||||
pub pricing_unit: PuzzleTemplatePricingUnit,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum PuzzleDraftEditableFieldPath {
|
||||
#[serde(rename = "workTitle")]
|
||||
WorkTitle,
|
||||
#[serde(rename = "workDescription")]
|
||||
WorkDescription,
|
||||
#[serde(rename = "workTags")]
|
||||
WorkTags,
|
||||
#[serde(rename = "levels[].levelName")]
|
||||
LevelName,
|
||||
#[serde(rename = "levels[].pictureDescription")]
|
||||
LevelPictureDescription,
|
||||
#[serde(rename = "levels[].pictureReference")]
|
||||
LevelPictureReference,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleTemplateImageGenerationPolicy {
|
||||
pub allow_uploaded_image_directly: bool,
|
||||
pub allow_generated_images: bool,
|
||||
pub allow_per_level_reference_image: bool,
|
||||
pub default_candidate_count_per_level: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleCreativeTemplateProtocol {
|
||||
pub template_id: String,
|
||||
pub title: String,
|
||||
pub summary: String,
|
||||
#[serde(default)]
|
||||
pub preview_image_src: Option<String>,
|
||||
pub supported_level_mode: PuzzleSupportedLevelMode,
|
||||
pub min_level_count: u32,
|
||||
pub max_level_count: u32,
|
||||
pub default_level_count: u32,
|
||||
pub cost_range: PuzzleTemplateCostRange,
|
||||
pub required_draft_fields: Vec<PuzzleDraftEditableFieldPath>,
|
||||
pub image_policy: PuzzleTemplateImageGenerationPolicy,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleCreativeTemplateSelection {
|
||||
pub template_id: String,
|
||||
pub title: String,
|
||||
pub reason: String,
|
||||
pub cost_range: PuzzleTemplateCostRange,
|
||||
pub supported_level_mode: PuzzleSupportedLevelMode,
|
||||
pub selected_level_mode: PuzzleLevelGenerationMode,
|
||||
pub planned_level_count: u32,
|
||||
pub requires_user_confirmation: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreativePuzzleLevelDraftInput {
|
||||
pub level_name: String,
|
||||
pub picture_description: String,
|
||||
/// 任务 A 冻结:Phase 1 采用正式字段方案,后续拼图草稿落地需补正式 pictureReference 字段。
|
||||
#[serde(default)]
|
||||
pub picture_reference: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreativePuzzleDraftToolInput {
|
||||
pub template_id: String,
|
||||
pub template_cost_range: PuzzleTemplateCostRange,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub work_tags: Vec<String>,
|
||||
pub levels: Vec<CreativePuzzleLevelDraftInput>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleImageGenerationPlanLevel {
|
||||
pub level_id: String,
|
||||
pub level_name: String,
|
||||
pub picture_description: String,
|
||||
pub image_prompt: String,
|
||||
#[serde(default)]
|
||||
pub picture_reference: Option<String>,
|
||||
pub candidate_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleImageGenerationPlan {
|
||||
pub mode: PuzzleLevelGenerationMode,
|
||||
pub template_id: String,
|
||||
pub estimated_cost_range: PuzzleTemplateCostRange,
|
||||
pub levels: Vec<PuzzleImageGenerationPlanLevel>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PuzzleDraftFieldPatchOperation {
|
||||
Set,
|
||||
Append,
|
||||
Replace,
|
||||
Remove,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleDraftFieldPatch {
|
||||
pub field_path: PuzzleDraftEditableFieldPath,
|
||||
pub operation: PuzzleDraftFieldPatchOperation,
|
||||
#[serde(default)]
|
||||
pub level_id: Option<String>,
|
||||
pub value: serde_json::Value,
|
||||
pub rationale: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
fn cost_range() -> PuzzleTemplateCostRange {
|
||||
PuzzleTemplateCostRange {
|
||||
min_points: 2,
|
||||
max_points: 12,
|
||||
pricing_unit: PuzzleTemplatePricingUnit::Point,
|
||||
reason: "按关卡数和每关图片生成次数估算".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creative_agent_puzzle_template_protocol_uses_camel_case() {
|
||||
let payload = serde_json::to_value(PuzzleCreativeTemplateProtocol {
|
||||
template_id: "puzzle.default-creative".to_string(),
|
||||
title: "创意拼图".to_string(),
|
||||
summary: "把图文灵感做成拼图".to_string(),
|
||||
preview_image_src: None,
|
||||
supported_level_mode: PuzzleSupportedLevelMode::SingleOrMulti,
|
||||
min_level_count: 1,
|
||||
max_level_count: 6,
|
||||
default_level_count: 1,
|
||||
cost_range: cost_range(),
|
||||
required_draft_fields: vec![
|
||||
PuzzleDraftEditableFieldPath::WorkTitle,
|
||||
PuzzleDraftEditableFieldPath::LevelPictureReference,
|
||||
],
|
||||
image_policy: PuzzleTemplateImageGenerationPolicy {
|
||||
allow_uploaded_image_directly: true,
|
||||
allow_generated_images: true,
|
||||
allow_per_level_reference_image: true,
|
||||
default_candidate_count_per_level: 1,
|
||||
},
|
||||
})
|
||||
.expect("template should serialize");
|
||||
|
||||
assert_eq!(payload["templateId"], json!("puzzle.default-creative"));
|
||||
assert_eq!(payload["previewImageSrc"], json!(null));
|
||||
assert_eq!(payload["supportedLevelMode"], json!("single_or_multi"));
|
||||
assert_eq!(payload["costRange"]["pricingUnit"], json!("point"));
|
||||
assert_eq!(
|
||||
payload["requiredDraftFields"],
|
||||
json!(["workTitle", "levels[].pictureReference"])
|
||||
);
|
||||
assert_eq!(
|
||||
payload["imagePolicy"]["allowPerLevelReferenceImage"],
|
||||
json!(true)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creative_agent_puzzle_image_plan_roundtrips() {
|
||||
let plan = PuzzleImageGenerationPlan {
|
||||
mode: PuzzleLevelGenerationMode::MultiLevel,
|
||||
template_id: "puzzle.default-creative".to_string(),
|
||||
estimated_cost_range: cost_range(),
|
||||
levels: vec![PuzzleImageGenerationPlanLevel {
|
||||
level_id: "level-1".to_string(),
|
||||
level_name: "第一关".to_string(),
|
||||
picture_description: "温暖的家庭照片".to_string(),
|
||||
image_prompt: "pixel puzzle, warm family photo".to_string(),
|
||||
picture_reference: Some("asset-ref-1".to_string()),
|
||||
candidate_count: 1,
|
||||
}],
|
||||
};
|
||||
|
||||
let payload = serde_json::to_value(&plan).expect("plan should serialize");
|
||||
assert_eq!(payload["mode"], json!("multi_level"));
|
||||
assert_eq!(
|
||||
payload["levels"][0]["pictureReference"],
|
||||
json!("asset-ref-1")
|
||||
);
|
||||
|
||||
let decoded: PuzzleImageGenerationPlan =
|
||||
serde_json::from_value(payload).expect("plan should deserialize");
|
||||
assert_eq!(decoded, plan);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::puzzle_works::{PuzzleWorkProfileResponse, PuzzleWorkSummaryResponse};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleGalleryResponse {
|
||||
pub items: Vec<PuzzleWorkSummaryResponse>,
|
||||
#[serde(default)]
|
||||
pub preview_refs: Vec<PuzzleGalleryWorkRefResponse>,
|
||||
#[serde(default)]
|
||||
pub has_more: bool,
|
||||
#[serde(default)]
|
||||
pub next_cursor: Option<String>,
|
||||
#[serde(default)]
|
||||
pub total_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleGalleryWorkRefResponse {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleGalleryDetailResponse {
|
||||
pub item: PuzzleWorkProfileResponse,
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
use crate::creation_audio::CreationAudioAsset;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartPuzzleRunRequest {
|
||||
pub profile_id: String,
|
||||
#[serde(default)]
|
||||
pub level_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SwapPuzzlePiecesRequest {
|
||||
pub first_piece_id: String,
|
||||
pub second_piece_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DragPuzzlePieceRequest {
|
||||
pub piece_id: String,
|
||||
pub target_row: u32,
|
||||
pub target_col: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AdvancePuzzleNextLevelRequest {
|
||||
#[serde(default)]
|
||||
pub target_profile_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub prefer_similar_work: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UsePuzzleRuntimePropRequest {
|
||||
pub prop_kind: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpdatePuzzleRuntimePauseRequest {
|
||||
pub paused: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SubmitPuzzleLeaderboardRequest {
|
||||
pub profile_id: String,
|
||||
pub grid_size: u32,
|
||||
pub elapsed_ms: u64,
|
||||
pub nickname: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleCellPositionResponse {
|
||||
pub row: u32,
|
||||
pub col: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzlePieceStateResponse {
|
||||
pub piece_id: String,
|
||||
pub correct_row: u32,
|
||||
pub correct_col: u32,
|
||||
pub current_row: u32,
|
||||
pub current_col: u32,
|
||||
#[serde(default)]
|
||||
pub merged_group_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleMergedGroupStateResponse {
|
||||
pub group_id: String,
|
||||
pub piece_ids: Vec<String>,
|
||||
pub occupied_cells: Vec<PuzzleCellPositionResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleLeaderboardEntryResponse {
|
||||
pub rank: u32,
|
||||
pub nickname: String,
|
||||
pub elapsed_ms: u64,
|
||||
#[serde(default)]
|
||||
pub visible_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub is_current_player: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleBoardSnapshotResponse {
|
||||
pub rows: u32,
|
||||
pub cols: u32,
|
||||
pub pieces: Vec<PuzzlePieceStateResponse>,
|
||||
pub merged_groups: Vec<PuzzleMergedGroupStateResponse>,
|
||||
#[serde(default)]
|
||||
pub selected_piece_id: Option<String>,
|
||||
pub all_tiles_resolved: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleRuntimeLevelSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub level_index: u32,
|
||||
#[serde(default)]
|
||||
pub level_id: Option<String>,
|
||||
pub grid_size: u32,
|
||||
pub profile_id: String,
|
||||
pub level_name: String,
|
||||
pub author_display_name: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_background_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub level_background_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub ui_spritesheet_image_object_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_music: Option<CreationAudioAsset>,
|
||||
pub board: PuzzleBoardSnapshotResponse,
|
||||
pub status: String,
|
||||
#[serde(default)]
|
||||
pub started_at_ms: u64,
|
||||
#[serde(default)]
|
||||
pub cleared_at_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub elapsed_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub time_limit_ms: u64,
|
||||
#[serde(default)]
|
||||
pub remaining_ms: u64,
|
||||
#[serde(default)]
|
||||
pub paused_accumulated_ms: u64,
|
||||
#[serde(default)]
|
||||
pub pause_started_at_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub freeze_accumulated_ms: u64,
|
||||
#[serde(default)]
|
||||
pub freeze_started_at_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub freeze_until_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub leaderboard_entries: Vec<PuzzleLeaderboardEntryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleRecommendedNextWorkResponse {
|
||||
pub profile_id: String,
|
||||
pub level_name: String,
|
||||
pub author_display_name: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub similarity_score: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub entry_profile_id: String,
|
||||
pub cleared_level_count: u32,
|
||||
pub current_level_index: u32,
|
||||
pub current_grid_size: u32,
|
||||
pub played_profile_ids: Vec<String>,
|
||||
pub previous_level_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub current_level: Option<PuzzleRuntimeLevelSnapshotResponse>,
|
||||
#[serde(default)]
|
||||
pub recommended_next_profile_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub next_level_mode: String,
|
||||
#[serde(default)]
|
||||
pub next_level_profile_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub next_level_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub recommended_next_works: Vec<PuzzleRecommendedNextWorkResponse>,
|
||||
#[serde(default)]
|
||||
pub leaderboard_entries: Vec<PuzzleLeaderboardEntryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleRunResponse {
|
||||
pub run: PuzzleRunSnapshotResponse,
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::puzzle_agent::{PuzzleAnchorPackResponse, PuzzleDraftLevelResponse};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PutPuzzleWorkRequest {
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub level_name: String,
|
||||
pub summary: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub levels: Vec<PuzzleDraftLevelResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleWorkSummaryResponse {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub author_display_name: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub level_name: String,
|
||||
pub summary: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cover_asset_id: Option<String>,
|
||||
pub publication_status: String,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub play_count: u32,
|
||||
#[serde(default)]
|
||||
pub remix_count: u32,
|
||||
#[serde(default)]
|
||||
pub like_count: u32,
|
||||
#[serde(default)]
|
||||
pub recent_play_count_7d: u32,
|
||||
#[serde(default)]
|
||||
pub point_incentive_total_half_points: u64,
|
||||
#[serde(default)]
|
||||
pub point_incentive_claimed_points: u64,
|
||||
#[serde(default)]
|
||||
pub point_incentive_total_points: f64,
|
||||
#[serde(default)]
|
||||
pub point_incentive_claimable_points: u64,
|
||||
pub publish_ready: bool,
|
||||
#[serde(default)]
|
||||
pub generation_status: Option<String>,
|
||||
#[serde(default)]
|
||||
pub levels: Vec<PuzzleDraftLevelResponse>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn puzzle_work_summary_response_uses_point_incentive_fields() {
|
||||
let payload = serde_json::to_value(PuzzleWorkSummaryResponse {
|
||||
work_id: "work-1".to_string(),
|
||||
profile_id: "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,
|
||||
publication_status: "published".to_string(),
|
||||
updated_at: "2026-05-01T00:00:00Z".to_string(),
|
||||
published_at: Some("2026-05-01T00:00:00Z".to_string()),
|
||||
play_count: 1,
|
||||
remix_count: 0,
|
||||
like_count: 0,
|
||||
recent_play_count_7d: 1,
|
||||
point_incentive_total_half_points: 3,
|
||||
point_incentive_claimed_points: 1,
|
||||
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");
|
||||
|
||||
assert_eq!(payload["pointIncentiveTotalHalfPoints"], 3);
|
||||
assert_eq!(payload["pointIncentiveClaimedPoints"], 1);
|
||||
assert_eq!(payload["pointIncentiveTotalPoints"], 1.5);
|
||||
assert_eq!(payload["pointIncentiveClaimablePoints"], 0);
|
||||
assert_eq!(payload["generationStatus"], "ready");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleWorkProfileResponse {
|
||||
#[serde(flatten)]
|
||||
pub summary: PuzzleWorkSummaryResponse,
|
||||
pub anchor_pack: PuzzleAnchorPackResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleWorksResponse {
|
||||
pub items: Vec<PuzzleWorkSummaryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleWorkDetailResponse {
|
||||
pub item: PuzzleWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleWorkMutationResponse {
|
||||
pub item: PuzzleWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleOnboardingGenerateRequest {
|
||||
pub prompt_text: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleOnboardingGenerateResponse {
|
||||
pub item: PuzzleWorkSummaryResponse,
|
||||
pub level: PuzzleDraftLevelResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleOnboardingSaveRequest {
|
||||
pub prompt_text: String,
|
||||
pub item: PuzzleWorkSummaryResponse,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,171 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSquareHoleSessionRequest {
|
||||
#[serde(default)]
|
||||
pub seed_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub twist_rule: Option<String>,
|
||||
#[serde(default)]
|
||||
pub shape_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub difficulty: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SendSquareHoleMessageRequest {
|
||||
pub client_message_id: String,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub quick_fill_requested: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecuteSquareHoleActionRequest {
|
||||
pub action: String,
|
||||
#[serde(default)]
|
||||
pub game_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub summary: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub regenerate_visual_assets: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub visual_asset_slot: Option<String>,
|
||||
#[serde(default)]
|
||||
pub visual_asset_option_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleShapeOptionResponse {
|
||||
pub option_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub target_hole_id: String,
|
||||
pub image_prompt: String,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleHoleOptionResponse {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub image_prompt: String,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleAnchorItemResponse {
|
||||
pub key: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleAnchorPackResponse {
|
||||
pub theme: SquareHoleAnchorItemResponse,
|
||||
pub twist_rule: SquareHoleAnchorItemResponse,
|
||||
pub shape_count: SquareHoleAnchorItemResponse,
|
||||
pub difficulty: SquareHoleAnchorItemResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleCreatorConfigResponse {
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
#[serde(default)]
|
||||
pub shape_options: Vec<SquareHoleShapeOptionResponse>,
|
||||
#[serde(default)]
|
||||
pub hole_options: Vec<SquareHoleHoleOptionResponse>,
|
||||
#[serde(default)]
|
||||
pub background_prompt: String,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleResultDraftResponse {
|
||||
pub profile_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_prompt: String,
|
||||
#[serde(default)]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub shape_options: Vec<SquareHoleShapeOptionResponse>,
|
||||
#[serde(default)]
|
||||
pub hole_options: Vec<SquareHoleHoleOptionResponse>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleAgentMessageResponse {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: SquareHoleAnchorPackResponse,
|
||||
pub config: SquareHoleCreatorConfigResponse,
|
||||
#[serde(default)]
|
||||
pub draft: Option<SquareHoleResultDraftResponse>,
|
||||
pub messages: Vec<SquareHoleAgentMessageResponse>,
|
||||
#[serde(default)]
|
||||
pub last_assistant_reply: Option<String>,
|
||||
#[serde(default)]
|
||||
pub published_profile_id: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleSessionResponse {
|
||||
pub session: SquareHoleSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleActionResponse {
|
||||
pub session: SquareHoleSessionSnapshotResponse,
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartSquareHoleRunRequest {
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DropSquareHoleShapeRequest {
|
||||
#[serde(default)]
|
||||
pub run_id: Option<String>,
|
||||
pub hole_id: String,
|
||||
pub client_snapshot_version: u64,
|
||||
pub client_event_id: String,
|
||||
pub dropped_at_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StopSquareHoleRunRequest {
|
||||
pub client_action_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleShapeSnapshotResponse {
|
||||
pub shape_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub target_hole_id: String,
|
||||
pub color: String,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleHoleSnapshotResponse {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleDropFeedbackResponse {
|
||||
pub accepted: bool,
|
||||
#[serde(default)]
|
||||
pub reject_reason: Option<String>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
pub snapshot_version: u64,
|
||||
pub started_at_ms: u64,
|
||||
pub duration_limit_ms: u64,
|
||||
pub remaining_ms: u64,
|
||||
pub total_shape_count: u32,
|
||||
pub completed_shape_count: u32,
|
||||
pub combo: u32,
|
||||
pub best_combo: u32,
|
||||
pub score: u32,
|
||||
pub rule_label: String,
|
||||
#[serde(default)]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub current_shape: Option<SquareHoleShapeSnapshotResponse>,
|
||||
pub holes: Vec<SquareHoleHoleSnapshotResponse>,
|
||||
#[serde(default)]
|
||||
pub last_feedback: Option<SquareHoleDropFeedbackResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleRunResponse {
|
||||
pub run: SquareHoleRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleDropResponse {
|
||||
pub feedback: SquareHoleDropFeedbackResponse,
|
||||
pub run: SquareHoleRunSnapshotResponse,
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleShapeOptionResponse {
|
||||
pub option_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub target_hole_id: String,
|
||||
pub image_prompt: String,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleHoleOptionResponse {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub image_prompt: String,
|
||||
#[serde(default)]
|
||||
pub image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PutSquareHoleWorkRequest {
|
||||
pub game_name: String,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub shape_options: Option<Vec<SquareHoleShapeOptionResponse>>,
|
||||
#[serde(default)]
|
||||
pub hole_options: Option<Vec<SquareHoleHoleOptionResponse>>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RegenerateSquareHoleWorkImageRequest {
|
||||
pub visual_asset_slot: String,
|
||||
#[serde(default)]
|
||||
pub visual_asset_option_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkSummaryResponse {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub background_prompt: String,
|
||||
#[serde(default)]
|
||||
pub background_image_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub shape_options: Vec<SquareHoleShapeOptionResponse>,
|
||||
#[serde(default)]
|
||||
pub hole_options: Vec<SquareHoleHoleOptionResponse>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkProfileResponse {
|
||||
#[serde(flatten)]
|
||||
pub summary: SquareHoleWorkSummaryResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorksResponse {
|
||||
pub items: Vec<SquareHoleWorkSummaryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkDetailResponse {
|
||||
pub item: SquareHoleWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkMutationResponse {
|
||||
pub item: SquareHoleWorkProfileResponse,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user