720 lines
24 KiB
Rust
720 lines
24 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
pub const RUNTIME_PLATFORM_THEME_LIGHT: &str = "light";
|
|
pub const RUNTIME_PLATFORM_THEME_DARK: &str = "dark";
|
|
pub const SAVE_SNAPSHOT_VERSION: u32 = 2;
|
|
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_SNAPSHOT_SYNC: &str = "snapshot_sync";
|
|
pub const BROWSE_HISTORY_THEME_MODE_MARTIAL: &str = "martial";
|
|
pub const BROWSE_HISTORY_THEME_MODE_ARCANE: &str = "arcane";
|
|
pub const BROWSE_HISTORY_THEME_MODE_MACHINA: &str = "machina";
|
|
pub const BROWSE_HISTORY_THEME_MODE_TIDE: &str = "tide";
|
|
pub const BROWSE_HISTORY_THEME_MODE_RIFT: &str = "rift";
|
|
pub const BROWSE_HISTORY_THEME_MODE_MYTHIC: &str = "mythic";
|
|
pub const CUSTOM_WORLD_VISIBILITY_DRAFT: &str = "draft";
|
|
pub const CUSTOM_WORLD_VISIBILITY_PUBLISHED: &str = "published";
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RuntimeSettingsResponse {
|
|
pub music_volume: f32,
|
|
pub platform_theme: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PutRuntimeSettingsRequest {
|
|
pub music_volume: f32,
|
|
pub platform_theme: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SavedGameSnapshotResponse {
|
|
pub version: u32,
|
|
pub saved_at: String,
|
|
pub game_state: serde_json::Value,
|
|
pub bottom_tab: String,
|
|
pub current_story: Option<serde_json::Value>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PutSavedGameSnapshotRequest {
|
|
pub game_state: serde_json::Value,
|
|
pub bottom_tab: String,
|
|
#[serde(default)]
|
|
pub current_story: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub saved_at: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct BasicOkResponse {
|
|
pub ok: bool,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PlatformBrowseHistoryEntryResponse {
|
|
pub owner_user_id: String,
|
|
pub profile_id: String,
|
|
pub world_name: String,
|
|
pub subtitle: String,
|
|
pub summary_text: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub theme_mode: String,
|
|
pub author_display_name: String,
|
|
pub visited_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PlatformBrowseHistoryWriteEntryRequest {
|
|
pub owner_user_id: String,
|
|
pub profile_id: String,
|
|
pub world_name: String,
|
|
#[serde(default)]
|
|
pub subtitle: Option<String>,
|
|
#[serde(default)]
|
|
pub summary_text: Option<String>,
|
|
#[serde(default)]
|
|
pub cover_image_src: Option<String>,
|
|
#[serde(default)]
|
|
pub theme_mode: Option<String>,
|
|
#[serde(default)]
|
|
pub author_display_name: Option<String>,
|
|
#[serde(default)]
|
|
pub visited_at: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PlatformBrowseHistoryBatchSyncRequest {
|
|
pub entries: Vec<PlatformBrowseHistoryWriteEntryRequest>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(untagged)]
|
|
pub enum PlatformBrowseHistoryUpsertRequest {
|
|
Single(PlatformBrowseHistoryWriteEntryRequest),
|
|
Batch(PlatformBrowseHistoryBatchSyncRequest),
|
|
}
|
|
|
|
impl PlatformBrowseHistoryUpsertRequest {
|
|
pub fn into_entries(self) -> Vec<PlatformBrowseHistoryWriteEntryRequest> {
|
|
match self {
|
|
Self::Single(entry) => vec![entry],
|
|
Self::Batch(batch) => batch.entries,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct PlatformBrowseHistoryResponse {
|
|
pub entries: Vec<PlatformBrowseHistoryEntryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileDashboardSummaryResponse {
|
|
pub wallet_balance: u64,
|
|
pub total_play_time_ms: u64,
|
|
pub played_world_count: u32,
|
|
pub updated_at: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileWalletLedgerEntryResponse {
|
|
pub id: String,
|
|
pub amount_delta: i64,
|
|
pub balance_after: u64,
|
|
pub source_type: String,
|
|
pub created_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileWalletLedgerResponse {
|
|
pub entries: Vec<ProfileWalletLedgerEntryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfilePlayedWorkSummaryResponse {
|
|
pub world_key: String,
|
|
pub owner_user_id: Option<String>,
|
|
pub profile_id: Option<String>,
|
|
pub world_type: Option<String>,
|
|
pub world_title: String,
|
|
pub world_subtitle: String,
|
|
pub first_played_at: String,
|
|
pub last_played_at: String,
|
|
pub last_observed_play_time_ms: u64,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfilePlayStatsResponse {
|
|
pub total_play_time_ms: u64,
|
|
pub played_works: Vec<ProfilePlayedWorkSummaryResponse>,
|
|
pub updated_at: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileSaveArchiveSummaryResponse {
|
|
pub world_key: String,
|
|
pub owner_user_id: Option<String>,
|
|
pub profile_id: Option<String>,
|
|
pub world_type: Option<String>,
|
|
pub world_name: String,
|
|
pub subtitle: String,
|
|
pub summary_text: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub last_played_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileSaveArchiveListResponse {
|
|
pub entries: Vec<ProfileSaveArchiveSummaryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ProfileSaveArchiveResumeResponse {
|
|
pub entry: ProfileSaveArchiveSummaryResponse,
|
|
pub snapshot: SavedGameSnapshotResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RuntimeInventorySlotResponse {
|
|
pub slot_id: String,
|
|
pub container_kind: String,
|
|
pub slot_key: String,
|
|
pub item_id: String,
|
|
pub category: String,
|
|
pub name: String,
|
|
pub description: Option<String>,
|
|
pub quantity: u32,
|
|
pub rarity: String,
|
|
pub tags: Vec<String>,
|
|
pub stackable: bool,
|
|
pub stack_key: String,
|
|
pub equipment_slot_id: Option<String>,
|
|
pub source_kind: String,
|
|
pub source_reference_id: Option<String>,
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RuntimeInventoryStateResponse {
|
|
pub runtime_session_id: String,
|
|
pub actor_user_id: String,
|
|
pub backpack_items: Vec<RuntimeInventorySlotResponse>,
|
|
pub equipment_items: Vec<RuntimeInventorySlotResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldProfileUpsertRequest {
|
|
pub profile: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldLibraryEntryResponse {
|
|
pub owner_user_id: String,
|
|
pub profile_id: String,
|
|
pub profile: serde_json::Value,
|
|
pub visibility: String,
|
|
pub published_at: Option<String>,
|
|
pub updated_at: String,
|
|
pub author_display_name: String,
|
|
pub world_name: String,
|
|
pub subtitle: String,
|
|
pub summary_text: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub theme_mode: String,
|
|
pub playable_npc_count: u32,
|
|
pub landmark_count: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldGalleryCardResponse {
|
|
pub owner_user_id: String,
|
|
pub profile_id: String,
|
|
pub visibility: String,
|
|
pub published_at: Option<String>,
|
|
pub updated_at: String,
|
|
pub author_display_name: String,
|
|
pub world_name: String,
|
|
pub subtitle: String,
|
|
pub summary_text: String,
|
|
pub cover_image_src: Option<String>,
|
|
pub theme_mode: String,
|
|
pub playable_npc_count: u32,
|
|
pub landmark_count: u32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldLibraryResponse {
|
|
pub entries: Vec<CustomWorldLibraryEntryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldLibraryMutationResponse {
|
|
pub entry: CustomWorldLibraryEntryResponse,
|
|
pub entries: Vec<CustomWorldLibraryEntryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldGalleryResponse {
|
|
pub entries: Vec<CustomWorldGalleryCardResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldGalleryDetailResponse {
|
|
pub entry: CustomWorldLibraryEntryResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldWorkSummaryResponse {
|
|
pub work_id: String,
|
|
pub source_type: String,
|
|
pub status: String,
|
|
pub title: String,
|
|
pub subtitle: String,
|
|
pub summary: String,
|
|
pub cover_image_src: Option<String>,
|
|
#[serde(default)]
|
|
pub cover_render_mode: Option<String>,
|
|
#[serde(default)]
|
|
pub cover_character_image_srcs: Vec<String>,
|
|
pub updated_at: String,
|
|
pub published_at: Option<String>,
|
|
pub stage: Option<String>,
|
|
pub stage_label: Option<String>,
|
|
pub playable_npc_count: u32,
|
|
pub landmark_count: u32,
|
|
pub role_visual_ready_count: Option<u32>,
|
|
pub role_animation_ready_count: Option<u32>,
|
|
pub role_asset_summary_label: Option<String>,
|
|
pub session_id: Option<String>,
|
|
pub profile_id: Option<String>,
|
|
pub can_resume: bool,
|
|
pub can_enter_world: bool,
|
|
pub blocker_count: u32,
|
|
pub publish_ready: bool,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldWorksResponse {
|
|
pub items: Vec<CustomWorldWorkSummaryResponse>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CreateCustomWorldAgentSessionRequest {
|
|
#[serde(default)]
|
|
pub seed_text: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SendCustomWorldAgentMessageRequest {
|
|
pub client_message_id: String,
|
|
pub text: String,
|
|
#[serde(default)]
|
|
pub quick_fill_requested: Option<bool>,
|
|
#[serde(default)]
|
|
pub focus_card_id: Option<String>,
|
|
#[serde(default)]
|
|
pub selected_card_ids: Option<Vec<String>>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentMessageResponse {
|
|
pub id: String,
|
|
pub role: String,
|
|
pub kind: String,
|
|
pub text: String,
|
|
pub created_at: String,
|
|
pub related_operation_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentOperationResponse {
|
|
pub operation_id: String,
|
|
#[serde(rename = "type")]
|
|
pub operation_type: String,
|
|
pub status: String,
|
|
pub phase_label: String,
|
|
pub phase_detail: String,
|
|
pub progress: u32,
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldDraftCardSummaryResponse {
|
|
pub id: String,
|
|
pub kind: String,
|
|
pub title: String,
|
|
pub subtitle: String,
|
|
pub summary: String,
|
|
pub status: String,
|
|
pub linked_ids: Vec<String>,
|
|
pub warning_count: u32,
|
|
pub asset_status: Option<String>,
|
|
pub asset_status_label: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldDraftCardDetailSectionResponse {
|
|
pub id: String,
|
|
pub label: String,
|
|
pub value: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldDraftCardDetailResponse {
|
|
pub id: String,
|
|
pub kind: String,
|
|
pub title: String,
|
|
pub sections: Vec<CustomWorldDraftCardDetailSectionResponse>,
|
|
pub linked_ids: Vec<String>,
|
|
pub locked: bool,
|
|
pub editable: bool,
|
|
pub editable_section_ids: Vec<String>,
|
|
pub warning_messages: Vec<String>,
|
|
pub asset_status: Option<String>,
|
|
pub asset_status_label: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentCardDetailResponse {
|
|
pub card: CustomWorldDraftCardDetailResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentCheckpointResponse {
|
|
pub checkpoint_id: String,
|
|
pub created_at: String,
|
|
pub label: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldSupportedActionResponse {
|
|
pub action: String,
|
|
pub enabled: bool,
|
|
pub reason: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldResultPreviewBlockerResponse {
|
|
pub id: String,
|
|
pub code: String,
|
|
pub message: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldPublishGateResponse {
|
|
pub profile_id: String,
|
|
pub blockers: Vec<CustomWorldResultPreviewBlockerResponse>,
|
|
pub blocker_count: u32,
|
|
pub publish_ready: bool,
|
|
pub can_enter_world: bool,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentSessionSnapshotResponse {
|
|
pub session_id: String,
|
|
pub current_turn: u32,
|
|
pub anchor_content: serde_json::Value,
|
|
pub progress_percent: u32,
|
|
pub last_assistant_reply: Option<String>,
|
|
pub stage: String,
|
|
pub focus_card_id: Option<String>,
|
|
pub creator_intent: serde_json::Value,
|
|
pub creator_intent_readiness: serde_json::Value,
|
|
pub anchor_pack: serde_json::Value,
|
|
pub lock_state: serde_json::Value,
|
|
pub draft_profile: serde_json::Value,
|
|
pub messages: Vec<CustomWorldAgentMessageResponse>,
|
|
pub draft_cards: Vec<CustomWorldDraftCardSummaryResponse>,
|
|
pub pending_clarifications: Vec<serde_json::Value>,
|
|
pub suggested_actions: Vec<serde_json::Value>,
|
|
pub recommended_replies: Vec<String>,
|
|
pub quality_findings: Vec<serde_json::Value>,
|
|
pub asset_coverage: serde_json::Value,
|
|
pub checkpoints: Vec<CustomWorldAgentCheckpointResponse>,
|
|
pub supported_actions: Vec<CustomWorldSupportedActionResponse>,
|
|
pub publish_gate: Option<CustomWorldPublishGateResponse>,
|
|
pub result_preview: Option<serde_json::Value>,
|
|
pub updated_at: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CustomWorldAgentSessionResponse {
|
|
pub session: CustomWorldAgentSessionSnapshotResponse,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecuteCustomWorldAgentActionRequest {
|
|
pub action: String,
|
|
#[serde(default)]
|
|
pub profile_id: Option<String>,
|
|
#[serde(default)]
|
|
pub draft_profile: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub legacy_result_profile: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub setting_text: Option<String>,
|
|
#[serde(default)]
|
|
pub card_id: Option<String>,
|
|
#[serde(default)]
|
|
pub sections: Option<Vec<ExecuteCustomWorldAgentDraftCardSectionPatch>>,
|
|
#[serde(default)]
|
|
pub profile: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub count: Option<u32>,
|
|
#[serde(default)]
|
|
pub prompt_text: Option<String>,
|
|
#[serde(default)]
|
|
pub anchor_card_ids: Option<Vec<String>>,
|
|
#[serde(default)]
|
|
pub role_ids: Option<Vec<String>>,
|
|
#[serde(default)]
|
|
pub role_id: Option<String>,
|
|
#[serde(default)]
|
|
pub portrait_path: Option<String>,
|
|
#[serde(default)]
|
|
pub generated_visual_asset_id: Option<String>,
|
|
#[serde(default)]
|
|
pub generated_animation_set_id: Option<String>,
|
|
#[serde(default)]
|
|
pub animation_map: Option<serde_json::Value>,
|
|
#[serde(default)]
|
|
pub scene_ids: Option<Vec<String>>,
|
|
#[serde(default)]
|
|
pub scene_id: Option<String>,
|
|
#[serde(default)]
|
|
pub scene_kind: Option<String>,
|
|
#[serde(default)]
|
|
pub image_src: Option<String>,
|
|
#[serde(default)]
|
|
pub generated_scene_asset_id: Option<String>,
|
|
#[serde(default)]
|
|
pub generated_scene_prompt: Option<String>,
|
|
#[serde(default)]
|
|
pub generated_scene_model: Option<String>,
|
|
#[serde(default)]
|
|
pub checkpoint_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecuteCustomWorldAgentDraftCardSectionPatch {
|
|
pub section_id: String,
|
|
pub value: String,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn runtime_settings_request_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(PutRuntimeSettingsRequest {
|
|
music_volume: 0.42,
|
|
platform_theme: RUNTIME_PLATFORM_THEME_LIGHT.to_string(),
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["platformTheme"], json!("light"));
|
|
let music_volume = payload["musicVolume"]
|
|
.as_f64()
|
|
.expect("musicVolume should serialize as number");
|
|
assert!((music_volume - 0.42).abs() < 0.0001);
|
|
}
|
|
|
|
#[test]
|
|
fn browse_history_response_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(PlatformBrowseHistoryResponse {
|
|
entries: vec![PlatformBrowseHistoryEntryResponse {
|
|
owner_user_id: "owner-1".to_string(),
|
|
profile_id: "profile-1".to_string(),
|
|
world_name: "世界".to_string(),
|
|
subtitle: "".to_string(),
|
|
summary_text: "".to_string(),
|
|
cover_image_src: None,
|
|
theme_mode: BROWSE_HISTORY_THEME_MODE_MYTHIC.to_string(),
|
|
author_display_name: "玩家".to_string(),
|
|
visited_at: "2026-04-21T00:00:00Z".to_string(),
|
|
}],
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["entries"][0]["ownerUserId"], json!("owner-1"));
|
|
assert_eq!(payload["entries"][0]["themeMode"], json!("mythic"));
|
|
assert_eq!(
|
|
payload["entries"][0]["visitedAt"],
|
|
json!("2026-04-21T00:00:00Z")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn browse_history_upsert_request_accepts_single_or_batch_shape() {
|
|
let single: PlatformBrowseHistoryUpsertRequest = serde_json::from_value(json!({
|
|
"ownerUserId": "owner-1",
|
|
"profileId": "profile-1",
|
|
"worldName": "世界"
|
|
}))
|
|
.expect("single shape should deserialize");
|
|
let batch: PlatformBrowseHistoryUpsertRequest = serde_json::from_value(json!({
|
|
"entries": [{
|
|
"ownerUserId": "owner-1",
|
|
"profileId": "profile-1",
|
|
"worldName": "世界"
|
|
}]
|
|
}))
|
|
.expect("batch shape should deserialize");
|
|
|
|
assert_eq!(single.into_entries().len(), 1);
|
|
assert_eq!(batch.into_entries().len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn profile_dashboard_response_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(ProfileDashboardSummaryResponse {
|
|
wallet_balance: 8,
|
|
total_play_time_ms: 16,
|
|
played_world_count: 3,
|
|
updated_at: Some("2026-04-22T10:00:00Z".to_string()),
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["walletBalance"], json!(8));
|
|
assert_eq!(payload["totalPlayTimeMs"], json!(16));
|
|
assert_eq!(payload["playedWorldCount"], json!(3));
|
|
assert_eq!(payload["updatedAt"], json!("2026-04-22T10:00:00Z"));
|
|
}
|
|
|
|
#[test]
|
|
fn profile_wallet_ledger_response_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(ProfileWalletLedgerResponse {
|
|
entries: vec![ProfileWalletLedgerEntryResponse {
|
|
id: "ledger-1".to_string(),
|
|
amount_delta: 12,
|
|
balance_after: 80,
|
|
source_type: PROFILE_WALLET_LEDGER_SOURCE_TYPE_SNAPSHOT_SYNC.to_string(),
|
|
created_at: "2026-04-22T10:00:00Z".to_string(),
|
|
}],
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["entries"][0]["amountDelta"], json!(12));
|
|
assert_eq!(payload["entries"][0]["balanceAfter"], json!(80));
|
|
assert_eq!(payload["entries"][0]["sourceType"], json!("snapshot_sync"));
|
|
assert_eq!(
|
|
payload["entries"][0]["createdAt"],
|
|
json!("2026-04-22T10:00:00Z")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn profile_play_stats_response_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(ProfilePlayStatsResponse {
|
|
total_play_time_ms: 18,
|
|
played_works: vec![ProfilePlayedWorkSummaryResponse {
|
|
world_key: "builtin:WUXIA".to_string(),
|
|
owner_user_id: None,
|
|
profile_id: None,
|
|
world_type: Some("WUXIA".to_string()),
|
|
world_title: "武侠世界".to_string(),
|
|
world_subtitle: "".to_string(),
|
|
first_played_at: "2026-04-20T10:00:00Z".to_string(),
|
|
last_played_at: "2026-04-22T10:00:00Z".to_string(),
|
|
last_observed_play_time_ms: 1200,
|
|
}],
|
|
updated_at: Some("2026-04-22T10:00:00Z".to_string()),
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["totalPlayTimeMs"], json!(18));
|
|
assert_eq!(
|
|
payload["playedWorks"][0]["worldKey"],
|
|
json!("builtin:WUXIA")
|
|
);
|
|
assert_eq!(
|
|
payload["playedWorks"][0]["lastObservedPlayTimeMs"],
|
|
json!(1200)
|
|
);
|
|
assert_eq!(payload["updatedAt"], json!("2026-04-22T10:00:00Z"));
|
|
}
|
|
|
|
#[test]
|
|
fn runtime_inventory_state_response_uses_camel_case_fields() {
|
|
let payload = serde_json::to_value(RuntimeInventoryStateResponse {
|
|
runtime_session_id: "runtime_001".to_string(),
|
|
actor_user_id: "user_001".to_string(),
|
|
backpack_items: vec![RuntimeInventorySlotResponse {
|
|
slot_id: "invslot_001".to_string(),
|
|
container_kind: "backpack".to_string(),
|
|
slot_key: "invslot_001".to_string(),
|
|
item_id: "consumable_heal_potion".to_string(),
|
|
category: "消耗品".to_string(),
|
|
name: "疗伤药".to_string(),
|
|
description: Some("用于恢复少量气血。".to_string()),
|
|
quantity: 2,
|
|
rarity: "common".to_string(),
|
|
tags: vec!["healing".to_string()],
|
|
stackable: true,
|
|
stack_key: "heal_potion".to_string(),
|
|
equipment_slot_id: None,
|
|
source_kind: "treasure_reward".to_string(),
|
|
source_reference_id: Some("treasure_001".to_string()),
|
|
created_at: "2026-04-22T10:00:00Z".to_string(),
|
|
updated_at: "2026-04-22T10:01:00Z".to_string(),
|
|
}],
|
|
equipment_items: vec![],
|
|
})
|
|
.expect("payload should serialize");
|
|
|
|
assert_eq!(payload["runtimeSessionId"], json!("runtime_001"));
|
|
assert_eq!(payload["actorUserId"], json!("user_001"));
|
|
assert_eq!(payload["backpackItems"][0]["slotId"], json!("invslot_001"));
|
|
assert_eq!(
|
|
payload["backpackItems"][0]["sourceKind"],
|
|
json!("treasure_reward")
|
|
);
|
|
}
|
|
}
|