use super::*; impl From for AssetEntityBindingInput { fn from(input: module_assets::AssetEntityBindingInput) -> Self { Self { binding_id: input.binding_id, asset_object_id: input.asset_object_id, entity_kind: input.entity_kind, entity_id: input.entity_id, slot: input.slot, asset_kind: input.asset_kind, owner_user_id: input.owner_user_id, profile_id: input.profile_id, updated_at_micros: input.updated_at_micros, } } } impl From for AssetObjectUpsertInput { fn from(input: module_assets::AssetObjectUpsertInput) -> Self { Self { asset_object_id: input.asset_object_id, bucket: input.bucket, object_key: input.object_key, access_policy: map_access_policy(input.access_policy), content_type: input.content_type, content_length: input.content_length, content_hash: input.content_hash, version: input.version, source_job_id: input.source_job_id, owner_user_id: input.owner_user_id, profile_id: input.profile_id, entity_id: input.entity_id, asset_kind: input.asset_kind, updated_at_micros: input.updated_at_micros, } } } impl From for AssetHistoryListInput { fn from(input: module_assets::AssetHistoryListInput) -> Self { Self { asset_kind: input.asset_kind, limit: input.limit, } } } impl From for RuntimeSettingGetInput { fn from(input: module_runtime::RuntimeSettingGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeSettingUpsertInput { fn from(input: module_runtime::RuntimeSettingUpsertInput) -> Self { Self { user_id: input.user_id, music_volume: input.music_volume, platform_theme: map_runtime_platform_theme(input.platform_theme), updated_at_micros: input.updated_at_micros, } } } impl From for RuntimeBrowseHistoryListInput { fn from(input: module_runtime::RuntimeBrowseHistoryListInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeBrowseHistoryClearInput { fn from(input: module_runtime::RuntimeBrowseHistoryClearInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeBrowseHistorySyncInput { fn from(input: module_runtime::RuntimeBrowseHistorySyncInput) -> Self { Self { user_id: input.user_id, entries: input.entries.into_iter().map(Into::into).collect(), updated_at_micros: input.updated_at_micros, } } } impl From for RuntimeBrowseHistoryWriteInput { fn from(input: module_runtime::RuntimeBrowseHistoryWriteInput) -> Self { Self { owner_user_id: input.owner_user_id, profile_id: input.profile_id, world_name: input.world_name, subtitle: input.subtitle, summary_text: input.summary_text, cover_image_src: input.cover_image_src, theme_mode: input.theme_mode, author_display_name: input.author_display_name, visited_at: input.visited_at, } } } impl From for RuntimeProfileDashboardGetInput { fn from(input: module_runtime::RuntimeProfileDashboardGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeProfileWalletLedgerListInput { fn from(input: module_runtime::RuntimeProfileWalletLedgerListInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeProfileWalletAdjustmentInput { fn from(input: module_runtime::RuntimeProfileWalletAdjustmentInput) -> Self { Self { user_id: input.user_id, amount: input.amount, ledger_id: input.ledger_id, created_at_micros: input.created_at_micros, } } } impl From for RuntimeProfileRechargeCenterGetInput { fn from(input: module_runtime::RuntimeProfileRechargeCenterGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeProfileRechargeOrderCreateInput { fn from(input: module_runtime::RuntimeProfileRechargeOrderCreateInput) -> Self { Self { user_id: input.user_id, product_id: input.product_id, payment_channel: input.payment_channel, created_at_micros: input.created_at_micros, } } } impl From for RuntimeReferralInviteCenterGetInput { fn from(input: module_runtime::RuntimeReferralInviteCenterGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeReferralRedeemInput { fn from(input: module_runtime::RuntimeReferralRedeemInput) -> Self { Self { user_id: input.user_id, invite_code: input.invite_code, updated_at_micros: input.updated_at_micros, } } } impl From for RuntimeProfilePlayStatsGetInput { fn from(input: module_runtime::RuntimeProfilePlayStatsGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeSnapshotGetInput { fn from(input: module_runtime::RuntimeSnapshotGetInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeSnapshotUpsertInput { fn from(input: module_runtime::RuntimeSnapshotUpsertInput) -> Self { Self { user_id: input.user_id, saved_at_micros: input.saved_at_micros, bottom_tab: input.bottom_tab, game_state_json: input.game_state_json, current_story_json: input.current_story_json, updated_at_micros: input.updated_at_micros, } } } impl From for RuntimeSnapshotDeleteInput { fn from(input: module_runtime::RuntimeSnapshotDeleteInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeProfileSaveArchiveListInput { fn from(input: module_runtime::RuntimeProfileSaveArchiveListInput) -> Self { Self { user_id: input.user_id, } } } impl From for RuntimeProfileSaveArchiveResumeInput { fn from(input: module_runtime::RuntimeProfileSaveArchiveResumeInput) -> Self { Self { user_id: input.user_id, world_key: input.world_key, } } } impl From for AiTaskCreateInput { fn from(input: DomainAiTaskCreateInput) -> Self { Self { task_id: input.task_id, task_kind: map_ai_task_kind(input.task_kind), owner_user_id: input.owner_user_id, request_label: input.request_label, source_module: input.source_module, source_entity_id: input.source_entity_id, request_payload_json: input.request_payload_json, stages: input.stages.into_iter().map(Into::into).collect(), created_at_micros: input.created_at_micros, } } } impl From for AiTaskStartInput { fn from(input: DomainAiTaskStartInput) -> Self { Self { task_id: input.task_id, started_at_micros: input.started_at_micros, } } } impl From for AiTaskStageStartInput { fn from(input: DomainAiTaskStageStartInput) -> Self { Self { task_id: input.task_id, stage_kind: map_ai_task_stage_kind(input.stage_kind), started_at_micros: input.started_at_micros, } } } impl From for AiTextChunkAppendInput { fn from(input: DomainAiTextChunkAppendInput) -> Self { Self { task_id: input.task_id, stage_kind: map_ai_task_stage_kind(input.stage_kind), sequence: input.sequence, delta_text: input.delta_text, created_at_micros: input.created_at_micros, } } } impl From for AiStageCompletionInput { fn from(input: DomainAiStageCompletionInput) -> Self { Self { task_id: input.task_id, stage_kind: map_ai_task_stage_kind(input.stage_kind), text_output: input.text_output, structured_payload_json: input.structured_payload_json, warning_messages: input.warning_messages, completed_at_micros: input.completed_at_micros, } } } impl From for AiResultReferenceInput { fn from(input: DomainAiResultReferenceInput) -> Self { Self { task_id: input.task_id, reference_kind: map_ai_result_reference_kind(input.reference_kind), reference_id: input.reference_id, label: input.label, created_at_micros: input.created_at_micros, } } } impl From for AiTaskFinishInput { fn from(input: DomainAiTaskFinishInput) -> Self { Self { task_id: input.task_id, completed_at_micros: input.completed_at_micros, } } } impl From for AiTaskFailureInput { fn from(input: DomainAiTaskFailureInput) -> Self { Self { task_id: input.task_id, failure_message: input.failure_message, completed_at_micros: input.completed_at_micros, } } } impl From for AiTaskCancelInput { fn from(input: DomainAiTaskCancelInput) -> Self { Self { task_id: input.task_id, completed_at_micros: input.completed_at_micros, } } } impl From for AiTaskStageBlueprint { fn from(blueprint: DomainAiTaskStageBlueprint) -> Self { Self { stage_kind: map_ai_task_stage_kind(blueprint.stage_kind), label: blueprint.label, detail: blueprint.detail, order: blueprint.order, } } } impl From for CustomWorldProfileUpsertInput { fn from(input: CustomWorldProfileUpsertRecordInput) -> Self { Self { profile_id: input.profile_id, owner_user_id: input.owner_user_id, public_work_code: input.public_work_code, author_public_user_code: input.author_public_user_code, source_agent_session_id: input.source_agent_session_id, world_name: input.world_name, subtitle: input.subtitle, summary_text: input.summary_text, theme_mode: map_custom_world_theme_mode(input.theme_mode), cover_image_src: input.cover_image_src, profile_payload_json: input.profile_payload_json, playable_npc_count: input.playable_npc_count, landmark_count: input.landmark_count, author_display_name: input.author_display_name, updated_at_micros: input.updated_at_micros, } } } impl From for CustomWorldPublishWorldInput { fn from(input: CustomWorldPublishWorldRecordInput) -> Self { Self { session_id: input.session_id, profile_id: input.profile_id, owner_user_id: input.owner_user_id, public_work_code: input.public_work_code, author_public_user_code: input.author_public_user_code, draft_profile_json: input.draft_profile_json, legacy_result_profile_json: input.legacy_result_profile_json, setting_text: input.setting_text, author_display_name: input.author_display_name, published_at_micros: input.published_at_micros, } } } impl From for StorySessionInput { fn from(input: DomainStorySessionInput) -> Self { Self { story_session_id: input.story_session_id, runtime_session_id: input.runtime_session_id, actor_user_id: input.actor_user_id, world_profile_id: input.world_profile_id, initial_prompt: input.initial_prompt, opening_summary: input.opening_summary, created_at_micros: input.created_at_micros, } } } impl From for StoryContinueInput { fn from(input: DomainStoryContinueInput) -> Self { Self { story_session_id: input.story_session_id, event_id: input.event_id, narrative_text: input.narrative_text, choice_function_id: input.choice_function_id, updated_at_micros: input.updated_at_micros, } } } impl From for StorySessionStateInput { fn from(input: DomainStorySessionStateInput) -> Self { Self { story_session_id: input.story_session_id, } } } impl From for RuntimeInventoryStateQueryInput { fn from(input: DomainRuntimeInventoryStateQueryInput) -> Self { Self { runtime_session_id: input.runtime_session_id, actor_user_id: input.actor_user_id, } } } impl From for BattleStateQueryInput { fn from(input: DomainBattleStateQueryInput) -> Self { Self { battle_state_id: input.battle_state_id, } } } impl From for BattleStateInput { fn from(input: DomainBattleStateInput) -> Self { Self { battle_state_id: input.battle_state_id, story_session_id: input.story_session_id, runtime_session_id: input.runtime_session_id, actor_user_id: input.actor_user_id, chapter_id: input.chapter_id, target_npc_id: input.target_npc_id, target_name: input.target_name, battle_mode: map_battle_mode(input.battle_mode), player_hp: input.player_hp, player_max_hp: input.player_max_hp, player_mana: input.player_mana, player_max_mana: input.player_max_mana, target_hp: input.target_hp, target_max_hp: input.target_max_hp, experience_reward: input.experience_reward, reward_items: input .reward_items .into_iter() .map(map_runtime_item_reward_item_snapshot) .collect(), created_at_micros: input.created_at_micros, } } } impl From for ResolveCombatActionInput { fn from(input: DomainResolveCombatActionInput) -> Self { Self { battle_state_id: input.battle_state_id, function_id: input.function_id, action_text: input.action_text, base_damage: input.base_damage, mana_cost: input.mana_cost, heal: input.heal, mana_restore: input.mana_restore, counter_multiplier_basis_points: input.counter_multiplier_basis_points, updated_at_micros: input.updated_at_micros, } } } pub(crate) fn map_procedure_result( result: AssetObjectProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回对象快照".to_string()) })?; Ok(build_asset_object_record(map_snapshot(snapshot))) } pub(crate) fn map_entity_binding_procedure_result( result: AssetEntityBindingProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回绑定快照".to_string()) })?; Ok(build_asset_entity_binding_record( map_entity_binding_snapshot(snapshot), )) } pub(crate) fn map_asset_history_list_result( result: AssetHistoryListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } Ok(result .entries .into_iter() .map(map_asset_history_entry_snapshot) .map(build_asset_history_entry_record) .collect()) } pub(crate) fn map_runtime_setting_procedure_result( result: RuntimeSettingProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 runtime settings 快照".to_string(), ) })?; Ok(build_runtime_setting_record(map_runtime_setting_snapshot( snapshot, ))) } pub(crate) fn map_auth_store_snapshot_procedure_result( result: AuthStoreSnapshotProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let record = result.record.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回认证快照".to_string()) })?; Ok(map_auth_store_snapshot_record(record)) } pub(crate) fn map_auth_store_snapshot_record( record: crate::module_bindings::AuthStoreSnapshotRecord, ) -> crate::AuthStoreSnapshotRecord { crate::AuthStoreSnapshotRecord { snapshot_json: record.snapshot_json, updated_at_micros: record.updated_at_micros, } } pub(crate) fn map_auth_store_snapshot_import_procedure_result( result: AuthStoreSnapshotImportProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure ??????".to_string()), )); } let record = result.record.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure ???????".to_string()) })?; Ok(AuthStoreSnapshotImportRecord { imported_user_count: record.imported_user_count, imported_identity_count: record.imported_identity_count, imported_refresh_session_count: record.imported_refresh_session_count, }) } pub(crate) fn map_runtime_browse_history_procedure_result( result: RuntimeBrowseHistoryProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } Ok(result .entries .into_iter() .map(|snapshot| { build_runtime_browse_history_record(map_runtime_browse_history_snapshot(snapshot)) }) .collect()) } pub(crate) fn map_runtime_profile_dashboard_procedure_result( result: RuntimeProfileDashboardProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(), ) })?; Ok(build_runtime_profile_dashboard_record( map_runtime_profile_dashboard_snapshot(snapshot), )) } pub(crate) fn map_runtime_profile_wallet_ledger_procedure_result( result: RuntimeProfileWalletLedgerProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } Ok(result .entries .into_iter() .map(|snapshot| { build_runtime_profile_wallet_ledger_entry_record( map_runtime_profile_wallet_ledger_entry_snapshot(snapshot), ) }) .collect()) } pub(crate) fn map_runtime_profile_wallet_adjustment_procedure_result( result: RuntimeProfileWalletAdjustmentProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(), ) })?; Ok(build_runtime_profile_dashboard_record( map_runtime_profile_dashboard_snapshot(snapshot), )) } pub(crate) fn map_runtime_profile_recharge_center_procedure_result( result: RuntimeProfileRechargeCenterProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(), ) })?; Ok(build_runtime_profile_recharge_center_record( map_runtime_profile_recharge_center_snapshot(snapshot), )) } pub(crate) fn map_runtime_profile_recharge_order_procedure_result( result: RuntimeProfileRechargeCenterProcedureResult, ) -> Result< ( RuntimeProfileRechargeCenterRecord, RuntimeProfileRechargeOrderRecord, ), SpacetimeClientError, > { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let center = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile recharge center 快照".to_string(), ) })?; let order = result.order.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile recharge order 快照".to_string(), ) })?; Ok(( build_runtime_profile_recharge_center_record(map_runtime_profile_recharge_center_snapshot( center, )), module_runtime::build_runtime_profile_recharge_order_record( map_runtime_profile_recharge_order_snapshot(order), ), )) } pub(crate) fn map_runtime_referral_invite_center_procedure_result( result: RuntimeReferralInviteCenterProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 referral invite center 快照".to_string(), ) })?; Ok(build_runtime_referral_invite_center_record( map_runtime_referral_invite_center_snapshot(snapshot), )) } pub(crate) fn map_runtime_referral_redeem_procedure_result( result: RuntimeReferralRedeemProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 referral redeem 快照".to_string(), ) })?; Ok(build_runtime_referral_redeem_record( map_runtime_referral_redeem_snapshot(snapshot), )) } pub(crate) fn map_runtime_profile_play_stats_procedure_result( result: RuntimeProfilePlayStatsProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 profile play stats 快照".to_string(), ) })?; Ok(build_runtime_profile_play_stats_record( map_runtime_profile_play_stats_snapshot(snapshot), )) } pub(crate) fn map_runtime_snapshot_procedure_result( result: RuntimeSnapshotProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } result .record .map(|snapshot| { build_runtime_snapshot_record(map_runtime_snapshot_snapshot(snapshot)) .map_err(|error| SpacetimeClientError::Runtime(error.to_string())) }) .transpose() } pub(crate) fn map_runtime_snapshot_required_procedure_result( result: RuntimeSnapshotProcedureResult, ) -> Result { map_runtime_snapshot_procedure_result(result)?.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 runtime snapshot 快照".to_string(), ) }) } pub(crate) fn map_runtime_snapshot_delete_procedure_result( result: RuntimeSnapshotProcedureResult, ) -> Result { map_runtime_snapshot_procedure_result(result).map(|record| record.is_some()) } pub(crate) fn map_runtime_profile_save_archive_list_procedure_result( result: RuntimeProfileSaveArchiveProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } result .entries .into_iter() .map(|snapshot| { build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot( snapshot, )) .map_err(|error| SpacetimeClientError::Runtime(error.to_string())) }) .collect() } pub(crate) fn map_runtime_profile_save_archive_resume_procedure_result( result: RuntimeProfileSaveArchiveProcedureResult, ) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let archive = result.record.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 save archive 快照".to_string(), ) })?; let snapshot = result.current_snapshot.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回恢复后的 runtime snapshot".to_string(), ) })?; Ok(( build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot( archive, )) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, build_runtime_snapshot_record(map_runtime_snapshot_snapshot(snapshot)) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, )) } pub(crate) fn map_ai_task_procedure_result( result: AiTaskProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Runtime( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let task = result.task.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 ai_task 快照".to_string()) })?; Ok(AiTaskMutationRecord { task: map_ai_task_snapshot(task), text_chunk: result.text_chunk.map(map_ai_text_chunk_snapshot), }) } pub(crate) fn map_custom_world_profile_list_result( result: CustomWorldProfileListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } result .entries .into_iter() .map(map_custom_world_library_entry_from_profile_snapshot) .collect() } pub(crate) fn map_custom_world_library_detail_result( result: CustomWorldLibraryMutationResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let entry = result .entry .ok_or_else(|| SpacetimeClientError::Procedure("custom_world_profile 不存在".to_string())) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; Ok(CustomWorldLibraryMutationRecord { entry, gallery_entry, }) } pub(crate) fn map_custom_world_gallery_list_result( result: CustomWorldGalleryListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } Ok(result .entries .into_iter() .map(map_custom_world_gallery_entry_snapshot) .collect::, _>>()?) } pub(crate) fn map_custom_world_library_mutation_result( result: CustomWorldLibraryMutationResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let entry = result .entry .ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string()) }) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; Ok(CustomWorldLibraryMutationRecord { entry, gallery_entry, }) } pub(crate) fn map_custom_world_publish_world_result( result: CustomWorldPublishWorldResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let compiled_record = result .compiled_record .ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 published profile compile 快照".to_string(), ) }) .and_then(map_custom_world_published_profile_compile_snapshot)?; let entry = result .entry .ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string()) }) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; let session_stage = result .session_stage .ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB 未返回 session stage".to_string()) }) .map(map_rpg_agent_stage)?; Ok(CustomWorldPublishWorldRecord { compiled_record, entry, gallery_entry, session_stage, }) } pub(crate) fn map_custom_world_agent_session_procedure_result( result: CustomWorldAgentSessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let session = result.session.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 custom world agent session 快照".to_string(), ) })?; map_custom_world_agent_session_snapshot(session) } pub(crate) fn map_custom_world_agent_operation_procedure_result( result: CustomWorldAgentOperationProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let operation = result.operation.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 custom world agent operation 快照".to_string(), ) })?; Ok(map_custom_world_agent_operation_snapshot(operation)) } pub(crate) fn map_custom_world_works_list_result( result: CustomWorldWorksListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } result .items .into_iter() .map(map_custom_world_work_summary_snapshot) .collect() } pub(crate) fn map_custom_world_draft_card_detail_result( result: CustomWorldDraftCardDetailResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let card = result.card.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 custom world card detail 快照".to_string(), ) })?; map_custom_world_draft_card_detail_snapshot(card) } pub(crate) fn map_custom_world_agent_action_execute_result( result: CustomWorldAgentActionExecuteResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let operation = result.operation.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 custom world action operation 快照".to_string(), ) })?; Ok(CustomWorldAgentActionExecuteRecord { operation: map_custom_world_agent_operation_snapshot(operation), }) } pub(crate) fn map_puzzle_agent_session_procedure_result( result: PuzzleAgentSessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let session_json = result.session_json.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 puzzle agent session 快照".to_string(), ) })?; let session: DomainPuzzleAgentSessionSnapshot = serde_json::from_str(&session_json).map_err(|error| { SpacetimeClientError::Runtime(format!("puzzle agent session_json 非法: {error}")) })?; Ok(map_puzzle_agent_session_snapshot(session)) } pub(crate) fn map_puzzle_work_procedure_result( result: PuzzleWorkProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let item_json = result.item_json.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle work 快照".to_string()) })?; let item: DomainPuzzleWorkProfile = serde_json::from_str(&item_json).map_err(|error| { SpacetimeClientError::Runtime(format!("puzzle work item_json 非法: {error}")) })?; Ok(map_puzzle_work_profile(item)) } pub(crate) fn map_puzzle_works_procedure_result( result: PuzzleWorksProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let items_json = result.items_json.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 puzzle works 快照".to_string(), ) })?; let items: Vec = serde_json::from_str(&items_json).map_err(|error| { SpacetimeClientError::Runtime(format!("puzzle works items_json 非法: {error}")) })?; Ok(items.into_iter().map(map_puzzle_work_profile).collect()) } pub(crate) fn map_puzzle_run_procedure_result( result: PuzzleRunProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let run_json = result.run_json.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle run 快照".to_string()) })?; let run: DomainPuzzleRunSnapshot = serde_json::from_str(&run_json).map_err(|error| { SpacetimeClientError::Runtime(format!("puzzle run run_json 非法: {error}")) })?; Ok(map_puzzle_run_snapshot(run)) } pub(crate) fn map_big_fish_session_procedure_result( result: BigFishSessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let session = result.session.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 big fish session 快照".to_string(), ) })?; Ok(map_big_fish_session_snapshot(session)) } pub(crate) fn map_big_fish_works_procedure_result( result: BigFishWorksProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let items_json = result.items_json.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 big fish works 快照".to_string(), ) })?; serde_json::from_str::>(&items_json).map_err(|error| { SpacetimeClientError::Runtime(format!("big fish works items_json 非法: {error}")) }) } pub(crate) fn map_story_session_procedure_result( result: StorySessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let session = result.session.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 story session 快照".to_string(), ) })?; let event = result.event.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 story event 快照".to_string()) })?; Ok(StorySessionResultRecord { session: map_story_session_snapshot(session), event: map_story_event_snapshot(event), }) } pub(crate) fn map_story_session_state_procedure_result( result: StorySessionStateProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let session = result.session.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 story session state 快照".to_string(), ) })?; Ok(StorySessionStateRecord { session: map_story_session_snapshot(session), events: result .events .into_iter() .map(map_story_event_snapshot) .collect(), }) } pub(crate) fn map_runtime_inventory_state_procedure_result( result: RuntimeInventoryStateProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.snapshot.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 runtime inventory state 快照".to_string(), ) })?; Ok(build_runtime_inventory_state_record( map_runtime_inventory_state_snapshot(snapshot), )) } pub(crate) fn map_battle_state_procedure_result( result: BattleStateProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let snapshot = result.snapshot.ok_or_else(|| { SpacetimeClientError::Procedure( "SpacetimeDB procedure 未返回 battle_state 快照".to_string(), ) })?; Ok(build_battle_state_record(map_battle_state_snapshot( snapshot, ))) } pub(crate) fn map_resolve_combat_action_procedure_result( result: ResolveCombatActionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let action_result = result.result.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回战斗结算结果".to_string()) })?; Ok(build_resolve_combat_action_record( map_resolve_combat_action_result(action_result), )) } pub(crate) fn map_npc_battle_interaction_procedure_result( result: NpcBattleInteractionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::Procedure( result .error_message .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), )); } let interaction_result = result.result.ok_or_else(|| { SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 NPC 开战结果".to_string()) })?; Ok(build_npc_battle_interaction_record( map_npc_battle_interaction_result(interaction_result), )) } pub(crate) fn map_entity_binding_snapshot( snapshot: AssetEntityBindingSnapshot, ) -> module_assets::AssetEntityBindingSnapshot { module_assets::AssetEntityBindingSnapshot { binding_id: snapshot.binding_id, asset_object_id: snapshot.asset_object_id, entity_kind: snapshot.entity_kind, entity_id: snapshot.entity_id, slot: snapshot.slot, asset_kind: snapshot.asset_kind, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_snapshot( snapshot: AssetObjectUpsertSnapshot, ) -> module_assets::AssetObjectUpsertSnapshot { module_assets::AssetObjectUpsertSnapshot { asset_object_id: snapshot.asset_object_id, bucket: snapshot.bucket, object_key: snapshot.object_key, access_policy: map_access_policy_back(snapshot.access_policy), content_type: snapshot.content_type, content_length: snapshot.content_length, content_hash: snapshot.content_hash, version: snapshot.version, source_job_id: snapshot.source_job_id, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, entity_id: snapshot.entity_id, asset_kind: snapshot.asset_kind, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_asset_history_entry_snapshot( snapshot: AssetHistoryEntrySnapshot, ) -> module_assets::AssetHistoryEntrySnapshot { module_assets::AssetHistoryEntrySnapshot { asset_object_id: snapshot.asset_object_id, asset_kind: snapshot.asset_kind, image_src: snapshot.image_src, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, entity_id: snapshot.entity_id, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_setting_snapshot( snapshot: RuntimeSettingSnapshot, ) -> module_runtime::RuntimeSettingSnapshot { module_runtime::RuntimeSettingSnapshot { user_id: snapshot.user_id, music_volume: snapshot.music_volume, platform_theme: map_runtime_platform_theme_back(snapshot.platform_theme), created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_browse_history_snapshot( snapshot: RuntimeBrowseHistorySnapshot, ) -> module_runtime::RuntimeBrowseHistorySnapshot { module_runtime::RuntimeBrowseHistorySnapshot { browse_history_id: snapshot.browse_history_id, user_id: snapshot.user_id, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, theme_mode: map_runtime_browse_history_theme_mode_back(snapshot.theme_mode), author_display_name: snapshot.author_display_name, visited_at_micros: snapshot.visited_at_micros, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_profile_dashboard_snapshot( snapshot: RuntimeProfileDashboardSnapshot, ) -> module_runtime::RuntimeProfileDashboardSnapshot { module_runtime::RuntimeProfileDashboardSnapshot { user_id: snapshot.user_id, wallet_balance: snapshot.wallet_balance, total_play_time_ms: snapshot.total_play_time_ms, played_world_count: snapshot.played_world_count, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_profile_wallet_ledger_entry_snapshot( snapshot: RuntimeProfileWalletLedgerEntrySnapshot, ) -> module_runtime::RuntimeProfileWalletLedgerEntrySnapshot { module_runtime::RuntimeProfileWalletLedgerEntrySnapshot { wallet_ledger_id: snapshot.wallet_ledger_id, user_id: snapshot.user_id, amount_delta: snapshot.amount_delta, balance_after: snapshot.balance_after, source_type: map_runtime_profile_wallet_ledger_source_type_back(snapshot.source_type), created_at_micros: snapshot.created_at_micros, } } pub(crate) fn map_runtime_profile_recharge_center_snapshot( snapshot: RuntimeProfileRechargeCenterSnapshot, ) -> module_runtime::RuntimeProfileRechargeCenterSnapshot { module_runtime::RuntimeProfileRechargeCenterSnapshot { user_id: snapshot.user_id, wallet_balance: snapshot.wallet_balance, membership: map_runtime_profile_membership_snapshot(snapshot.membership), point_products: snapshot .point_products .into_iter() .map(map_runtime_profile_recharge_product_snapshot) .collect(), membership_products: snapshot .membership_products .into_iter() .map(map_runtime_profile_recharge_product_snapshot) .collect(), benefits: snapshot .benefits .into_iter() .map(map_runtime_profile_membership_benefit_snapshot) .collect(), latest_order: snapshot .latest_order .map(map_runtime_profile_recharge_order_snapshot), has_points_recharged: snapshot.has_points_recharged, } } pub(crate) fn map_runtime_profile_recharge_product_snapshot( snapshot: RuntimeProfileRechargeProductSnapshot, ) -> module_runtime::RuntimeProfileRechargeProductSnapshot { module_runtime::RuntimeProfileRechargeProductSnapshot { product_id: snapshot.product_id, title: snapshot.title, price_cents: snapshot.price_cents, kind: map_runtime_profile_recharge_product_kind_back(snapshot.kind), points_amount: snapshot.points_amount, bonus_points: snapshot.bonus_points, duration_days: snapshot.duration_days, badge_label: snapshot.badge_label, description: snapshot.description, tier: map_runtime_profile_membership_tier_back(snapshot.tier), } } pub(crate) fn map_runtime_profile_membership_benefit_snapshot( snapshot: RuntimeProfileMembershipBenefitSnapshot, ) -> module_runtime::RuntimeProfileMembershipBenefitSnapshot { module_runtime::RuntimeProfileMembershipBenefitSnapshot { benefit_name: snapshot.benefit_name, normal_value: snapshot.normal_value, month_value: snapshot.month_value, season_value: snapshot.season_value, year_value: snapshot.year_value, } } pub(crate) fn map_runtime_profile_membership_snapshot( snapshot: RuntimeProfileMembershipSnapshot, ) -> module_runtime::RuntimeProfileMembershipSnapshot { module_runtime::RuntimeProfileMembershipSnapshot { user_id: snapshot.user_id, status: map_runtime_profile_membership_status_back(snapshot.status), tier: map_runtime_profile_membership_tier_back(snapshot.tier), started_at_micros: snapshot.started_at_micros, expires_at_micros: snapshot.expires_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_profile_recharge_order_snapshot( snapshot: RuntimeProfileRechargeOrderSnapshot, ) -> module_runtime::RuntimeProfileRechargeOrderSnapshot { module_runtime::RuntimeProfileRechargeOrderSnapshot { order_id: snapshot.order_id, user_id: snapshot.user_id, product_id: snapshot.product_id, product_title: snapshot.product_title, kind: map_runtime_profile_recharge_product_kind_back(snapshot.kind), amount_cents: snapshot.amount_cents, status: map_runtime_profile_recharge_order_status_back(snapshot.status), payment_channel: snapshot.payment_channel, paid_at_micros: snapshot.paid_at_micros, created_at_micros: snapshot.created_at_micros, points_delta: snapshot.points_delta, membership_expires_at_micros: snapshot.membership_expires_at_micros, } } pub(crate) fn map_runtime_referral_invite_center_snapshot( snapshot: RuntimeReferralInviteCenterSnapshot, ) -> module_runtime::RuntimeReferralInviteCenterSnapshot { module_runtime::RuntimeReferralInviteCenterSnapshot { user_id: snapshot.user_id, invite_code: snapshot.invite_code, invite_link_path: snapshot.invite_link_path, invited_count: snapshot.invited_count, rewarded_invite_count: snapshot.rewarded_invite_count, today_inviter_reward_count: snapshot.today_inviter_reward_count, today_inviter_reward_remaining: snapshot.today_inviter_reward_remaining, reward_points: snapshot.reward_points, has_redeemed_code: snapshot.has_redeemed_code, bound_inviter_user_id: snapshot.bound_inviter_user_id, bound_at_micros: snapshot.bound_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_referral_redeem_snapshot( snapshot: RuntimeReferralRedeemSnapshot, ) -> module_runtime::RuntimeReferralRedeemSnapshot { module_runtime::RuntimeReferralRedeemSnapshot { center: map_runtime_referral_invite_center_snapshot(snapshot.center), invitee_reward_granted: snapshot.invitee_reward_granted, inviter_reward_granted: snapshot.inviter_reward_granted, invitee_balance_after: snapshot.invitee_balance_after, inviter_balance_after: snapshot.inviter_balance_after, } } pub(crate) fn map_runtime_profile_played_world_snapshot( snapshot: RuntimeProfilePlayedWorldSnapshot, ) -> module_runtime::RuntimeProfilePlayedWorldSnapshot { module_runtime::RuntimeProfilePlayedWorldSnapshot { played_world_id: snapshot.played_world_id, user_id: snapshot.user_id, world_key: snapshot.world_key, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, world_type: snapshot.world_type, world_title: snapshot.world_title, world_subtitle: snapshot.world_subtitle, first_played_at_micros: snapshot.first_played_at_micros, last_played_at_micros: snapshot.last_played_at_micros, last_observed_play_time_ms: snapshot.last_observed_play_time_ms, } } pub(crate) fn map_runtime_profile_play_stats_snapshot( snapshot: RuntimeProfilePlayStatsSnapshot, ) -> module_runtime::RuntimeProfilePlayStatsSnapshot { module_runtime::RuntimeProfilePlayStatsSnapshot { user_id: snapshot.user_id, total_play_time_ms: snapshot.total_play_time_ms, played_works: snapshot .played_works .into_iter() .map(map_runtime_profile_played_world_snapshot) .collect(), updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_snapshot_snapshot( snapshot: RuntimeSnapshot, ) -> module_runtime::RuntimeSnapshot { module_runtime::RuntimeSnapshot { user_id: snapshot.user_id, version: snapshot.version, saved_at_micros: snapshot.saved_at_micros, bottom_tab: snapshot.bottom_tab, game_state_json: snapshot.game_state_json, current_story_json: snapshot.current_story_json, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_profile_save_archive_snapshot( snapshot: RuntimeProfileSaveArchiveSnapshot, ) -> module_runtime::RuntimeProfileSaveArchiveSnapshot { module_runtime::RuntimeProfileSaveArchiveSnapshot { archive_id: snapshot.archive_id, user_id: snapshot.user_id, world_key: snapshot.world_key, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, world_type: snapshot.world_type, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, saved_at_micros: snapshot.saved_at_micros, bottom_tab: snapshot.bottom_tab, game_state_json: snapshot.game_state_json, current_story_json: snapshot.current_story_json, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_custom_world_library_entry_from_profile_snapshot( snapshot: CustomWorldProfileSnapshot, ) -> Result { let profile = serde_json::from_str::(&snapshot.profile_payload_json) .map_err(|error| { SpacetimeClientError::Runtime(format!( "custom world profile payload JSON 非法: {error}" )) })?; Ok(CustomWorldLibraryEntryRecord { owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, public_work_code: snapshot.public_work_code, author_public_user_code: snapshot.author_public_user_code, profile, visibility: map_custom_world_publication_status(snapshot.publication_status).to_string(), published_at: snapshot.published_at_micros.map(format_timestamp_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), author_display_name: snapshot.author_display_name, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, }) } pub(crate) fn map_custom_world_gallery_entry_snapshot( snapshot: CustomWorldGalleryEntrySnapshot, ) -> Result { Ok(CustomWorldGalleryEntryRecord { owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, public_work_code: snapshot.public_work_code, author_public_user_code: snapshot.author_public_user_code, visibility: "published".to_string(), published_at: Some(format_timestamp_micros(snapshot.published_at_micros)), updated_at: format_timestamp_micros(snapshot.updated_at_micros), author_display_name: snapshot.author_display_name, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, }) } pub(crate) fn map_custom_world_published_profile_compile_snapshot( snapshot: CustomWorldPublishedProfileCompileSnapshot, ) -> Result { let compiled_profile = serde_json::from_str::(&snapshot.compiled_profile_payload_json) .map_err(|error| { SpacetimeClientError::Runtime(format!( "published profile compile JSON 非法: {error}" )) })?; Ok(CustomWorldPublishedProfileCompileRecord { profile_id: snapshot.profile_id, owner_user_id: snapshot.owner_user_id, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), cover_image_src: snapshot.cover_image_src, playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, author_display_name: snapshot.author_display_name, compiled_profile: compiled_profile, updated_at: format_timestamp_micros(snapshot.updated_at_micros), }) } pub(crate) fn map_custom_world_work_summary_snapshot( snapshot: CustomWorldWorkSummarySnapshot, ) -> Result { Ok(CustomWorldWorkSummaryRecord { work_id: snapshot.work_id, source_type: snapshot.source_type, status: snapshot.status, title: snapshot.title, subtitle: snapshot.subtitle, summary: snapshot.summary, cover_image_src: snapshot.cover_image_src, cover_render_mode: snapshot.cover_render_mode, cover_character_image_srcs: parse_json_string_array( &snapshot.cover_character_image_srcs_json, "custom world work cover_character_image_srcs_json", )?, updated_at: format_timestamp_micros(snapshot.updated_at_micros), published_at: snapshot.published_at_micros.map(format_timestamp_micros), stage: snapshot.stage.map(map_rpg_agent_stage), stage_label: snapshot.stage_label, playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, role_visual_ready_count: snapshot.role_visual_ready_count, role_animation_ready_count: snapshot.role_animation_ready_count, role_asset_summary_label: snapshot.role_asset_summary_label, session_id: snapshot.session_id, profile_id: snapshot.profile_id, can_resume: snapshot.can_resume, can_enter_world: snapshot.can_enter_world, blocker_count: snapshot.blocker_count, publish_ready: snapshot.publish_ready, }) } pub(crate) fn map_custom_world_agent_session_snapshot( snapshot: CustomWorldAgentSessionSnapshot, ) -> Result { let anchor_content = parse_json_value( &snapshot.anchor_content_json, "custom world agent anchor_content_json", )?; let creator_intent = parse_optional_json_value( snapshot.creator_intent_json.as_deref(), serde_json::json!({}), "custom world agent creator_intent_json", )?; let creator_intent_readiness = parse_json_value( &snapshot.creator_intent_readiness_json, "custom world agent creator_intent_readiness_json", )?; let anchor_pack = parse_optional_json_value( snapshot.anchor_pack_json.as_deref(), serde_json::json!({}), "custom world agent anchor_pack_json", )?; let lock_state = parse_optional_json_value( snapshot.lock_state_json.as_deref(), serde_json::json!({}), "custom world agent lock_state_json", )?; let draft_profile = parse_optional_json_value( snapshot.draft_profile_json.as_deref(), serde_json::json!({}), "custom world agent draft_profile_json", )?; let pending_clarifications = parse_json_array( &snapshot.pending_clarifications_json, "custom world agent pending_clarifications_json", )?; let suggested_actions = parse_json_array( &snapshot.suggested_actions_json, "custom world agent suggested_actions_json", )?; let recommended_replies = parse_json_string_array( &snapshot.recommended_replies_json, "custom world agent recommended_replies_json", )?; let quality_findings = parse_json_array( &snapshot.quality_findings_json, "custom world agent quality_findings_json", )?; let asset_coverage = parse_json_value( &snapshot.asset_coverage_json, "custom world agent asset_coverage_json", )?; let checkpoints_json = parse_json_array( &snapshot.checkpoints_json, "custom world agent checkpoints_json", )?; let checkpoints = checkpoints_json .into_iter() .map(map_custom_world_checkpoint_record) .collect::, _>>()?; let supported_actions = parse_supported_actions_json(&snapshot.supported_actions_json)?; let publish_gate = snapshot .publish_gate_json .as_deref() .map(parse_custom_world_publish_gate_record) .transpose()?; Ok(CustomWorldAgentSessionRecord { session_id: snapshot.session_id, seed_text: snapshot.seed_text, current_turn: snapshot.current_turn, anchor_content, progress_percent: snapshot.progress_percent, last_assistant_reply: snapshot.last_assistant_reply, stage: map_rpg_agent_stage(snapshot.stage), focus_card_id: snapshot.focus_card_id, creator_intent, creator_intent_readiness, anchor_pack, lock_state, draft_profile, messages: snapshot .messages .into_iter() .map(map_custom_world_agent_message_snapshot) .collect(), draft_cards: snapshot .draft_cards .into_iter() .map(map_custom_world_draft_card_snapshot) .collect::, _>>()?, pending_clarifications, suggested_actions, recommended_replies, quality_findings, asset_coverage, checkpoints, supported_actions, publish_gate, result_preview: snapshot .result_preview_json .as_deref() .map(|value| parse_json_value(value, "custom world agent result_preview_json")) .transpose()?, updated_at: format_timestamp_micros(snapshot.updated_at_micros), }) } pub(crate) fn map_custom_world_agent_message_snapshot( snapshot: CustomWorldAgentMessageSnapshot, ) -> CustomWorldAgentMessageRecord { CustomWorldAgentMessageRecord { message_id: snapshot.message_id, role: format_rpg_agent_message_role(snapshot.role).to_string(), kind: format_rpg_agent_message_kind(snapshot.kind).to_string(), text: snapshot.text, created_at: format_timestamp_micros(snapshot.created_at_micros), related_operation_id: snapshot.related_operation_id, } } pub(crate) fn map_custom_world_agent_operation_snapshot( snapshot: CustomWorldAgentOperationSnapshot, ) -> CustomWorldAgentOperationRecord { CustomWorldAgentOperationRecord { operation_id: snapshot.operation_id, operation_type: format_rpg_agent_operation_type(snapshot.operation_type).to_string(), status: format_rpg_agent_operation_status(snapshot.status).to_string(), phase_label: snapshot.phase_label, phase_detail: snapshot.phase_detail, progress: snapshot.progress, error_message: snapshot.error_message, started_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_custom_world_draft_card_snapshot( snapshot: CustomWorldDraftCardSnapshot, ) -> Result { Ok(CustomWorldDraftCardRecord { card_id: snapshot.card_id, kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), title: snapshot.title, subtitle: snapshot.subtitle, summary: snapshot.summary, status: format_rpg_agent_draft_card_status(snapshot.status).to_string(), linked_ids: parse_json_string_array( &snapshot.linked_ids_json, "custom world draft_card linked_ids_json", )?, warning_count: snapshot.warning_count, asset_status: snapshot .asset_status .map(format_custom_world_role_asset_status_back), asset_status_label: snapshot.asset_status_label, detail_payload: snapshot .detail_payload_json .as_deref() .map(|value| parse_json_value(value, "custom world draft_card detail_payload_json")) .transpose()?, }) } pub(crate) fn map_custom_world_draft_card_detail_snapshot( snapshot: CustomWorldDraftCardDetailSnapshot, ) -> Result { Ok(CustomWorldDraftCardDetailRecord { card_id: snapshot.card_id, kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), title: snapshot.title, sections: snapshot .sections .into_iter() .map(map_custom_world_draft_card_detail_section_snapshot) .collect(), linked_ids: parse_json_string_array( &snapshot.linked_ids_json, "custom world card detail linked_ids_json", )?, locked: snapshot.locked, editable: snapshot.editable, editable_section_ids: parse_json_string_array( &snapshot.editable_section_ids_json, "custom world card detail editable_section_ids_json", )?, warning_messages: parse_json_string_array( &snapshot.warning_messages_json, "custom world card detail warning_messages_json", )?, asset_status: snapshot .asset_status .map(format_custom_world_role_asset_status_back), asset_status_label: snapshot.asset_status_label, }) } pub(crate) fn map_custom_world_draft_card_detail_section_snapshot( snapshot: CustomWorldDraftCardDetailSectionSnapshot, ) -> CustomWorldDraftCardDetailSectionRecord { CustomWorldDraftCardDetailSectionRecord { section_id: snapshot.section_id, label: snapshot.label, value: snapshot.value, } } pub(crate) fn map_big_fish_session_snapshot( snapshot: BigFishSessionSnapshot, ) -> BigFishSessionRecord { BigFishSessionRecord { session_id: snapshot.session_id, current_turn: snapshot.current_turn, progress_percent: snapshot.progress_percent, stage: format_big_fish_creation_stage(snapshot.stage).to_string(), anchor_pack: map_big_fish_anchor_pack(snapshot.anchor_pack), draft: snapshot.draft.map(map_big_fish_game_draft), asset_slots: snapshot .asset_slots .into_iter() .map(map_big_fish_asset_slot_snapshot) .collect(), asset_coverage: map_big_fish_asset_coverage(snapshot.asset_coverage), messages: snapshot .messages .into_iter() .map(map_big_fish_agent_message_snapshot) .collect(), last_assistant_reply: snapshot.last_assistant_reply, publish_ready: snapshot.publish_ready, updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn map_puzzle_agent_session_snapshot( snapshot: DomainPuzzleAgentSessionSnapshot, ) -> PuzzleAgentSessionRecord { PuzzleAgentSessionRecord { session_id: snapshot.session_id, current_turn: snapshot.current_turn, progress_percent: snapshot.progress_percent, stage: snapshot.stage.as_str().to_string(), anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), draft: snapshot.draft.map(map_puzzle_result_draft), messages: snapshot .messages .into_iter() .map(map_puzzle_agent_message_snapshot) .collect(), last_assistant_reply: snapshot.last_assistant_reply, published_profile_id: snapshot.published_profile_id, suggested_actions: snapshot .suggested_actions .into_iter() .map(map_puzzle_suggested_action) .collect(), result_preview: snapshot.result_preview.map(map_puzzle_result_preview), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn map_puzzle_anchor_pack(snapshot: DomainPuzzleAnchorPack) -> PuzzleAnchorPackRecord { PuzzleAnchorPackRecord { theme_promise: map_puzzle_anchor_item(snapshot.theme_promise), visual_subject: map_puzzle_anchor_item(snapshot.visual_subject), visual_mood: map_puzzle_anchor_item(snapshot.visual_mood), composition_hooks: map_puzzle_anchor_item(snapshot.composition_hooks), tags_and_forbidden: map_puzzle_anchor_item(snapshot.tags_and_forbidden), } } pub(crate) fn map_puzzle_anchor_item(snapshot: DomainPuzzleAnchorItem) -> PuzzleAnchorItemRecord { PuzzleAnchorItemRecord { key: snapshot.key, label: snapshot.label, value: snapshot.value, status: snapshot.status.as_str().to_string(), } } pub(crate) fn map_puzzle_result_draft( snapshot: DomainPuzzleResultDraft, ) -> PuzzleResultDraftRecord { PuzzleResultDraftRecord { level_name: snapshot.level_name, summary: snapshot.summary, theme_tags: snapshot.theme_tags, forbidden_directives: snapshot.forbidden_directives, creator_intent: snapshot.creator_intent.map(map_puzzle_creator_intent), anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), candidates: snapshot .candidates .into_iter() .map(map_puzzle_generated_image_candidate) .collect(), selected_candidate_id: snapshot.selected_candidate_id, cover_image_src: snapshot.cover_image_src, cover_asset_id: snapshot.cover_asset_id, generation_status: snapshot.generation_status, } } pub(crate) fn map_puzzle_creator_intent( snapshot: DomainPuzzleCreatorIntent, ) -> PuzzleCreatorIntentRecord { PuzzleCreatorIntentRecord { source_mode: snapshot.source_mode, raw_messages_summary: snapshot.raw_messages_summary, theme_promise: snapshot.theme_promise, visual_subject: snapshot.visual_subject, visual_mood: snapshot.visual_mood, composition_hooks: snapshot.composition_hooks, theme_tags: snapshot.theme_tags, forbidden_directives: snapshot.forbidden_directives, } } pub(crate) fn map_puzzle_generated_image_candidate( snapshot: DomainPuzzleGeneratedImageCandidate, ) -> PuzzleGeneratedImageCandidateRecord { PuzzleGeneratedImageCandidateRecord { candidate_id: snapshot.candidate_id, image_src: snapshot.image_src, asset_id: snapshot.asset_id, prompt: snapshot.prompt, actual_prompt: snapshot.actual_prompt, source_type: snapshot.source_type, selected: snapshot.selected, } } pub(crate) fn map_puzzle_agent_message_snapshot( snapshot: DomainPuzzleAgentMessageSnapshot, ) -> PuzzleAgentMessageRecord { PuzzleAgentMessageRecord { message_id: snapshot.message_id, role: snapshot.role.as_str().to_string(), kind: snapshot.kind.as_str().to_string(), text: snapshot.text, created_at: format_timestamp_micros(snapshot.created_at_micros), } } pub(crate) fn map_puzzle_suggested_action( snapshot: DomainPuzzleAgentSuggestedAction, ) -> PuzzleAgentSuggestedActionRecord { PuzzleAgentSuggestedActionRecord { action_id: snapshot.id, action_type: snapshot.action_type, label: snapshot.label, } } pub(crate) fn map_puzzle_result_preview( snapshot: DomainPuzzleResultPreviewEnvelope, ) -> PuzzleResultPreviewRecord { PuzzleResultPreviewRecord { draft: map_puzzle_result_draft(snapshot.draft), blockers: snapshot .blockers .into_iter() .map(map_puzzle_result_preview_blocker) .collect(), quality_findings: snapshot .quality_findings .into_iter() .map(map_puzzle_result_preview_finding) .collect(), publish_ready: snapshot.publish_ready, } } pub(crate) fn map_puzzle_result_preview_blocker( snapshot: DomainPuzzleResultPreviewBlocker, ) -> PuzzleResultPreviewBlockerRecord { PuzzleResultPreviewBlockerRecord { blocker_id: snapshot.id, code: snapshot.code, message: snapshot.message, } } pub(crate) fn map_puzzle_result_preview_finding( snapshot: DomainPuzzleResultPreviewFinding, ) -> PuzzleResultPreviewFindingRecord { PuzzleResultPreviewFindingRecord { finding_id: snapshot.id, severity: snapshot.severity, code: snapshot.code, message: snapshot.message, } } pub(crate) fn map_puzzle_work_profile( snapshot: DomainPuzzleWorkProfile, ) -> PuzzleWorkProfileRecord { PuzzleWorkProfileRecord { work_id: snapshot.work_id, profile_id: snapshot.profile_id, owner_user_id: snapshot.owner_user_id, source_session_id: snapshot.source_session_id, author_display_name: snapshot.author_display_name, level_name: snapshot.level_name, summary: snapshot.summary, theme_tags: snapshot.theme_tags, cover_image_src: snapshot.cover_image_src, cover_asset_id: snapshot.cover_asset_id, publication_status: snapshot.publication_status.as_str().to_string(), updated_at: format_timestamp_micros(snapshot.updated_at_micros), published_at: snapshot.published_at_micros.map(format_timestamp_micros), play_count: snapshot.play_count, publish_ready: snapshot.publish_ready, anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), } } pub(crate) fn map_puzzle_run_snapshot(snapshot: DomainPuzzleRunSnapshot) -> PuzzleRunRecord { PuzzleRunRecord { run_id: snapshot.run_id, entry_profile_id: snapshot.entry_profile_id, cleared_level_count: snapshot.cleared_level_count, current_level_index: snapshot.current_level_index, current_grid_size: snapshot.current_grid_size, played_profile_ids: snapshot.played_profile_ids, previous_level_tags: snapshot.previous_level_tags, current_level: snapshot .current_level .map(map_puzzle_runtime_level_snapshot), recommended_next_profile_id: snapshot.recommended_next_profile_id, leaderboard_entries: snapshot .leaderboard_entries .into_iter() .map(map_puzzle_leaderboard_entry) .collect(), } } pub(crate) fn map_puzzle_runtime_level_snapshot( snapshot: DomainPuzzleRuntimeLevelSnapshot, ) -> PuzzleRuntimeLevelRecord { PuzzleRuntimeLevelRecord { run_id: snapshot.run_id, level_index: snapshot.level_index, grid_size: snapshot.grid_size, profile_id: snapshot.profile_id, level_name: snapshot.level_name, author_display_name: snapshot.author_display_name, theme_tags: snapshot.theme_tags, cover_image_src: snapshot.cover_image_src, board: map_puzzle_board_snapshot(snapshot.board), status: snapshot.status.as_str().to_string(), started_at_ms: snapshot.started_at_ms, cleared_at_ms: snapshot.cleared_at_ms, elapsed_ms: snapshot.elapsed_ms, leaderboard_entries: snapshot .leaderboard_entries .into_iter() .map(map_puzzle_leaderboard_entry) .collect(), } } pub(crate) fn map_puzzle_leaderboard_entry( snapshot: module_puzzle::PuzzleLeaderboardEntry, ) -> PuzzleLeaderboardEntryRecord { PuzzleLeaderboardEntryRecord { rank: snapshot.rank, nickname: snapshot.nickname, elapsed_ms: snapshot.elapsed_ms, is_current_player: snapshot.is_current_player, } } pub(crate) fn map_puzzle_board_snapshot(snapshot: DomainPuzzleBoardSnapshot) -> PuzzleBoardRecord { PuzzleBoardRecord { rows: snapshot.rows, cols: snapshot.cols, pieces: snapshot .pieces .into_iter() .map(map_puzzle_piece_state) .collect(), merged_groups: snapshot .merged_groups .into_iter() .map(map_puzzle_merged_group_state) .collect(), selected_piece_id: snapshot.selected_piece_id, all_tiles_resolved: snapshot.all_tiles_resolved, } } pub(crate) fn map_puzzle_piece_state(snapshot: DomainPuzzlePieceState) -> PuzzlePieceStateRecord { PuzzlePieceStateRecord { piece_id: snapshot.piece_id, correct_row: snapshot.correct_row, correct_col: snapshot.correct_col, current_row: snapshot.current_row, current_col: snapshot.current_col, merged_group_id: snapshot.merged_group_id, } } pub(crate) fn map_puzzle_merged_group_state( snapshot: DomainPuzzleMergedGroupState, ) -> PuzzleMergedGroupRecord { PuzzleMergedGroupRecord { group_id: snapshot.group_id, piece_ids: snapshot.piece_ids, occupied_cells: snapshot .occupied_cells .into_iter() .map(map_puzzle_cell_position) .collect(), } } pub(crate) fn map_puzzle_cell_position( snapshot: DomainPuzzleCellPosition, ) -> PuzzleCellPositionRecord { PuzzleCellPositionRecord { row: snapshot.row, col: snapshot.col, } } pub(crate) fn map_big_fish_anchor_pack(snapshot: BigFishAnchorPack) -> BigFishAnchorPackRecord { BigFishAnchorPackRecord { gameplay_promise: map_big_fish_anchor_item(snapshot.gameplay_promise), ecology_visual_theme: map_big_fish_anchor_item(snapshot.ecology_visual_theme), growth_ladder: map_big_fish_anchor_item(snapshot.growth_ladder), risk_tempo: map_big_fish_anchor_item(snapshot.risk_tempo), } } pub(crate) fn map_big_fish_anchor_item(snapshot: BigFishAnchorItem) -> BigFishAnchorItemRecord { BigFishAnchorItemRecord { key: snapshot.key, label: snapshot.label, value: snapshot.value, status: format_big_fish_anchor_status(snapshot.status).to_string(), } } pub(crate) fn map_big_fish_game_draft(snapshot: BigFishGameDraft) -> BigFishGameDraftRecord { BigFishGameDraftRecord { title: snapshot.title, subtitle: snapshot.subtitle, core_fun: snapshot.core_fun, ecology_theme: snapshot.ecology_theme, levels: snapshot .levels .into_iter() .map(map_big_fish_level_blueprint) .collect(), background: map_big_fish_background_blueprint(snapshot.background), runtime_params: map_big_fish_runtime_params(snapshot.runtime_params), } } pub(crate) fn map_big_fish_level_blueprint( snapshot: BigFishLevelBlueprint, ) -> BigFishLevelBlueprintRecord { BigFishLevelBlueprintRecord { level: snapshot.level, name: snapshot.name, one_line_fantasy: snapshot.one_line_fantasy, silhouette_direction: snapshot.silhouette_direction, size_ratio: snapshot.size_ratio, visual_prompt_seed: snapshot.visual_prompt_seed, motion_prompt_seed: snapshot.motion_prompt_seed, merge_source_level: snapshot.merge_source_level, prey_window: snapshot.prey_window, threat_window: snapshot.threat_window, is_final_level: snapshot.is_final_level, } } pub(crate) fn map_big_fish_background_blueprint( snapshot: BigFishBackgroundBlueprint, ) -> BigFishBackgroundBlueprintRecord { BigFishBackgroundBlueprintRecord { theme: snapshot.theme, color_mood: snapshot.color_mood, foreground_hints: snapshot.foreground_hints, midground_composition: snapshot.midground_composition, background_depth: snapshot.background_depth, safe_play_area_hint: snapshot.safe_play_area_hint, spawn_edge_hint: snapshot.spawn_edge_hint, background_prompt_seed: snapshot.background_prompt_seed, } } pub(crate) fn map_big_fish_runtime_params( snapshot: BigFishRuntimeParams, ) -> BigFishRuntimeParamsRecord { BigFishRuntimeParamsRecord { level_count: snapshot.level_count, merge_count_per_upgrade: snapshot.merge_count_per_upgrade, spawn_target_count: snapshot.spawn_target_count, leader_move_speed: snapshot.leader_move_speed, follower_catch_up_speed: snapshot.follower_catch_up_speed, offscreen_cull_seconds: snapshot.offscreen_cull_seconds, prey_spawn_delta_levels: snapshot.prey_spawn_delta_levels, threat_spawn_delta_levels: snapshot.threat_spawn_delta_levels, win_level: snapshot.win_level, } } pub(crate) fn map_big_fish_asset_slot_snapshot( snapshot: BigFishAssetSlotSnapshot, ) -> BigFishAssetSlotRecord { BigFishAssetSlotRecord { slot_id: snapshot.slot_id, asset_kind: format_big_fish_asset_kind(snapshot.asset_kind).to_string(), level: snapshot.level, motion_key: snapshot.motion_key, status: format_big_fish_asset_status(snapshot.status).to_string(), asset_url: snapshot.asset_url, prompt_snapshot: snapshot.prompt_snapshot, updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn map_big_fish_asset_coverage( snapshot: BigFishAssetCoverage, ) -> BigFishAssetCoverageRecord { BigFishAssetCoverageRecord { level_main_image_ready_count: snapshot.level_main_image_ready_count, level_motion_ready_count: snapshot.level_motion_ready_count, background_ready: snapshot.background_ready, required_level_count: snapshot.required_level_count, publish_ready: snapshot.publish_ready, blockers: snapshot.blockers, } } pub(crate) fn map_big_fish_agent_message_snapshot( snapshot: BigFishAgentMessageSnapshot, ) -> BigFishAgentMessageRecord { BigFishAgentMessageRecord { message_id: snapshot.message_id, role: format_big_fish_agent_message_role(snapshot.role).to_string(), kind: format_big_fish_agent_message_kind(snapshot.kind).to_string(), text: snapshot.text, created_at: format_timestamp_micros(snapshot.created_at_micros), } } pub(crate) fn map_story_session_snapshot(snapshot: StorySessionSnapshot) -> StorySessionRecord { StorySessionRecord { story_session_id: snapshot.story_session_id, runtime_session_id: snapshot.runtime_session_id, actor_user_id: snapshot.actor_user_id, world_profile_id: snapshot.world_profile_id, initial_prompt: snapshot.initial_prompt, opening_summary: snapshot.opening_summary, latest_narrative_text: snapshot.latest_narrative_text, latest_choice_function_id: snapshot.latest_choice_function_id, status: map_story_session_status(snapshot.status) .as_str() .to_string(), version: snapshot.version, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn map_ai_task_snapshot(snapshot: AiTaskSnapshot) -> AiTaskRecord { AiTaskRecord { task_id: snapshot.task_id, task_kind: format_ai_task_kind(snapshot.task_kind).to_string(), owner_user_id: snapshot.owner_user_id, request_label: snapshot.request_label, source_module: snapshot.source_module, source_entity_id: snapshot.source_entity_id, request_payload_json: snapshot.request_payload_json, status: format_ai_task_status(snapshot.status).to_string(), failure_message: snapshot.failure_message, stages: snapshot .stages .into_iter() .map(map_ai_task_stage_snapshot) .collect(), result_references: snapshot .result_references .into_iter() .map(map_ai_result_reference_snapshot) .collect(), latest_text_output: snapshot.latest_text_output, latest_structured_payload_json: snapshot.latest_structured_payload_json, version: snapshot.version, created_at: format_timestamp_micros(snapshot.created_at_micros), started_at: snapshot.started_at_micros.map(format_timestamp_micros), completed_at: snapshot.completed_at_micros.map(format_timestamp_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn map_ai_task_stage_snapshot(snapshot: AiTaskStageSnapshot) -> AiTaskStageRecord { AiTaskStageRecord { stage_kind: format_ai_task_stage_kind(snapshot.stage_kind).to_string(), label: snapshot.label, detail: snapshot.detail, order: snapshot.order, status: format_ai_task_stage_status(snapshot.status).to_string(), text_output: snapshot.text_output, structured_payload_json: snapshot.structured_payload_json, warning_messages: snapshot.warning_messages, started_at: snapshot.started_at_micros.map(format_timestamp_micros), completed_at: snapshot.completed_at_micros.map(format_timestamp_micros), } } pub(crate) fn map_ai_text_chunk_snapshot(snapshot: AiTextChunkSnapshot) -> AiTextChunkRecord { AiTextChunkRecord { chunk_id: snapshot.chunk_id, task_id: snapshot.task_id, stage_kind: format_ai_task_stage_kind(snapshot.stage_kind).to_string(), sequence: snapshot.sequence, delta_text: snapshot.delta_text, created_at: format_timestamp_micros(snapshot.created_at_micros), } } pub(crate) fn map_ai_result_reference_snapshot( snapshot: AiResultReferenceSnapshot, ) -> AiResultReferenceRecord { AiResultReferenceRecord { result_ref_id: snapshot.result_ref_id, task_id: snapshot.task_id, reference_kind: format_ai_result_reference_kind(snapshot.reference_kind).to_string(), reference_id: snapshot.reference_id, label: snapshot.label, created_at: format_timestamp_micros(snapshot.created_at_micros), } } pub(crate) fn map_story_event_snapshot(snapshot: StoryEventSnapshot) -> StoryEventRecord { StoryEventRecord { event_id: snapshot.event_id, story_session_id: snapshot.story_session_id, event_kind: map_story_event_kind(snapshot.event_kind) .as_str() .to_string(), narrative_text: snapshot.narrative_text, choice_function_id: snapshot.choice_function_id, created_at: format_timestamp_micros(snapshot.created_at_micros), } } pub(crate) fn map_battle_state_snapshot( snapshot: BattleStateSnapshot, ) -> DomainBattleStateSnapshot { DomainBattleStateSnapshot { battle_state_id: snapshot.battle_state_id, story_session_id: snapshot.story_session_id, runtime_session_id: snapshot.runtime_session_id, actor_user_id: snapshot.actor_user_id, chapter_id: snapshot.chapter_id, target_npc_id: snapshot.target_npc_id, target_name: snapshot.target_name, battle_mode: map_battle_mode_back(snapshot.battle_mode), status: map_battle_status(snapshot.status), player_hp: snapshot.player_hp, player_max_hp: snapshot.player_max_hp, player_mana: snapshot.player_mana, player_max_mana: snapshot.player_max_mana, target_hp: snapshot.target_hp, target_max_hp: snapshot.target_max_hp, experience_reward: snapshot.experience_reward, reward_items: snapshot .reward_items .into_iter() .map(map_runtime_item_reward_item_snapshot_back) .collect(), turn_index: snapshot.turn_index, last_action_function_id: snapshot.last_action_function_id, last_action_text: snapshot.last_action_text, last_result_text: snapshot.last_result_text, last_damage_dealt: snapshot.last_damage_dealt, last_damage_taken: snapshot.last_damage_taken, last_outcome: map_combat_outcome(snapshot.last_outcome), version: snapshot.version, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_runtime_inventory_state_snapshot( snapshot: RuntimeInventoryStateSnapshot, ) -> DomainRuntimeInventoryStateSnapshot { DomainRuntimeInventoryStateSnapshot { runtime_session_id: snapshot.runtime_session_id, actor_user_id: snapshot.actor_user_id, backpack_items: snapshot .backpack_items .into_iter() .map(map_inventory_slot_snapshot) .collect(), equipment_items: snapshot .equipment_items .into_iter() .map(map_inventory_slot_snapshot) .collect(), } } pub(crate) fn map_resolve_combat_action_result( result: ResolveCombatActionResult, ) -> DomainResolveCombatActionResult { DomainResolveCombatActionResult { snapshot: map_battle_state_snapshot(result.snapshot), damage_dealt: result.damage_dealt, damage_taken: result.damage_taken, outcome: map_combat_outcome(result.outcome), } } pub(crate) fn map_npc_battle_interaction_result( result: NpcBattleInteractionResult, ) -> NpcBattleInteractionSnapshot { NpcBattleInteractionSnapshot { interaction: map_npc_interaction_result(result.interaction), battle_state: map_battle_state_snapshot(result.battle_state), } } pub(crate) fn map_inventory_slot_snapshot( snapshot: InventorySlotSnapshot, ) -> module_inventory::InventorySlotSnapshot { module_inventory::InventorySlotSnapshot { slot_id: snapshot.slot_id, runtime_session_id: snapshot.runtime_session_id, story_session_id: snapshot.story_session_id, actor_user_id: snapshot.actor_user_id, container_kind: map_inventory_container_kind(snapshot.container_kind), slot_key: snapshot.slot_key, item_id: snapshot.item_id, category: snapshot.category, name: snapshot.name, description: snapshot.description, quantity: snapshot.quantity, rarity: map_inventory_item_rarity(snapshot.rarity), tags: snapshot.tags, stackable: snapshot.stackable, stack_key: snapshot.stack_key, equipment_slot_id: snapshot.equipment_slot_id.map(map_inventory_equipment_slot), source_kind: map_inventory_item_source_kind(snapshot.source_kind), source_reference_id: snapshot.source_reference_id, created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_npc_interaction_result( result: NpcInteractionResult, ) -> DomainNpcInteractionResult { DomainNpcInteractionResult { npc_state: map_npc_state_snapshot(result.npc_state), interaction_status: map_npc_interaction_status(result.interaction_status), action_text: result.action_text, result_text: result.result_text, story_text: result.story_text, battle_mode: result.battle_mode.map(map_npc_interaction_battle_mode), encounter_closed: result.encounter_closed, affinity_changed: result.affinity_changed, previous_affinity: result.previous_affinity, next_affinity: result.next_affinity, } } pub(crate) fn map_npc_state_snapshot(snapshot: NpcStateSnapshot) -> DomainNpcStateSnapshot { DomainNpcStateSnapshot { npc_state_id: snapshot.npc_state_id, runtime_session_id: snapshot.runtime_session_id, npc_id: snapshot.npc_id, npc_name: snapshot.npc_name, affinity: snapshot.affinity, relation_state: map_npc_relation_state(snapshot.relation_state), help_used: snapshot.help_used, chatted_count: snapshot.chatted_count, gifts_given: snapshot.gifts_given, recruited: snapshot.recruited, trade_stock_signature: snapshot.trade_stock_signature, revealed_facts: snapshot.revealed_facts, known_attribute_rumors: snapshot.known_attribute_rumors, first_meaningful_contact_resolved: snapshot.first_meaningful_contact_resolved, seen_backstory_chapter_ids: snapshot.seen_backstory_chapter_ids, stance_profile: map_npc_stance_profile(snapshot.stance_profile), created_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_npc_relation_state(value: NpcRelationState) -> DomainNpcRelationState { DomainNpcRelationState { affinity: value.affinity, stance: map_npc_relation_stance(value.stance), } } pub(crate) fn map_npc_stance_profile(value: NpcStanceProfile) -> DomainNpcStanceProfile { DomainNpcStanceProfile { trust: value.trust, warmth: value.warmth, ideological_fit: value.ideological_fit, fear_or_guard: value.fear_or_guard, loyalty: value.loyalty, current_conflict_tag: value.current_conflict_tag, recent_approvals: value.recent_approvals, recent_disapprovals: value.recent_disapprovals, } } pub(crate) fn map_npc_interaction_status( value: NpcInteractionStatus, ) -> DomainNpcInteractionStatus { match value { NpcInteractionStatus::Previewed => DomainNpcInteractionStatus::Previewed, NpcInteractionStatus::Dialogue => DomainNpcInteractionStatus::Dialogue, NpcInteractionStatus::Resolved => DomainNpcInteractionStatus::Resolved, NpcInteractionStatus::Recruited => DomainNpcInteractionStatus::Recruited, NpcInteractionStatus::BattlePending => DomainNpcInteractionStatus::BattlePending, NpcInteractionStatus::Left => DomainNpcInteractionStatus::Left, } } pub(crate) fn map_npc_interaction_battle_mode( value: NpcInteractionBattleMode, ) -> DomainNpcInteractionBattleMode { match value { NpcInteractionBattleMode::Fight => DomainNpcInteractionBattleMode::Fight, NpcInteractionBattleMode::Spar => DomainNpcInteractionBattleMode::Spar, } } pub(crate) fn map_npc_relation_stance(value: NpcRelationStance) -> DomainNpcRelationStance { match value { NpcRelationStance::Hostile => DomainNpcRelationStance::Hostile, NpcRelationStance::Guarded => DomainNpcRelationStance::Guarded, NpcRelationStance::Neutral => DomainNpcRelationStance::Neutral, NpcRelationStance::Cooperative => DomainNpcRelationStance::Cooperative, NpcRelationStance::Bonded => DomainNpcRelationStance::Bonded, } } pub(crate) fn map_access_policy( value: AssetObjectAccessPolicy, ) -> crate::module_bindings::AssetObjectAccessPolicy { match value { AssetObjectAccessPolicy::Private => { crate::module_bindings::AssetObjectAccessPolicy::Private } AssetObjectAccessPolicy::PublicRead => { crate::module_bindings::AssetObjectAccessPolicy::PublicRead } } } pub(crate) fn map_access_policy_back( value: crate::module_bindings::AssetObjectAccessPolicy, ) -> AssetObjectAccessPolicy { match value { crate::module_bindings::AssetObjectAccessPolicy::Private => { AssetObjectAccessPolicy::Private } crate::module_bindings::AssetObjectAccessPolicy::PublicRead => { AssetObjectAccessPolicy::PublicRead } } } pub(crate) fn map_runtime_platform_theme( value: DomainRuntimePlatformTheme, ) -> crate::module_bindings::RuntimePlatformTheme { match value { DomainRuntimePlatformTheme::Light => crate::module_bindings::RuntimePlatformTheme::Light, DomainRuntimePlatformTheme::Dark => crate::module_bindings::RuntimePlatformTheme::Dark, } } pub(crate) fn map_runtime_item_reward_item_rarity( value: DomainRuntimeItemRewardItemRarity, ) -> RuntimeItemRewardItemRarity { match value { DomainRuntimeItemRewardItemRarity::Common => RuntimeItemRewardItemRarity::Common, DomainRuntimeItemRewardItemRarity::Uncommon => RuntimeItemRewardItemRarity::Uncommon, DomainRuntimeItemRewardItemRarity::Rare => RuntimeItemRewardItemRarity::Rare, DomainRuntimeItemRewardItemRarity::Epic => RuntimeItemRewardItemRarity::Epic, DomainRuntimeItemRewardItemRarity::Legendary => RuntimeItemRewardItemRarity::Legendary, } } pub(crate) fn map_runtime_item_equipment_slot( value: DomainRuntimeItemEquipmentSlot, ) -> RuntimeItemEquipmentSlot { match value { DomainRuntimeItemEquipmentSlot::Weapon => RuntimeItemEquipmentSlot::Weapon, DomainRuntimeItemEquipmentSlot::Armor => RuntimeItemEquipmentSlot::Armor, DomainRuntimeItemEquipmentSlot::Relic => RuntimeItemEquipmentSlot::Relic, } } pub(crate) fn map_custom_world_theme_mode( value: DomainCustomWorldThemeMode, ) -> CustomWorldThemeMode { match value { DomainCustomWorldThemeMode::Martial => CustomWorldThemeMode::Martial, DomainCustomWorldThemeMode::Arcane => CustomWorldThemeMode::Arcane, DomainCustomWorldThemeMode::Machina => CustomWorldThemeMode::Machina, DomainCustomWorldThemeMode::Tide => CustomWorldThemeMode::Tide, DomainCustomWorldThemeMode::Rift => CustomWorldThemeMode::Rift, DomainCustomWorldThemeMode::Mythic => CustomWorldThemeMode::Mythic, } } pub(crate) fn map_battle_mode(value: DomainBattleMode) -> BattleMode { match value { DomainBattleMode::Fight => BattleMode::Fight, DomainBattleMode::Spar => BattleMode::Spar, } } pub(crate) fn map_runtime_platform_theme_back( value: crate::module_bindings::RuntimePlatformTheme, ) -> DomainRuntimePlatformTheme { match value { crate::module_bindings::RuntimePlatformTheme::Light => DomainRuntimePlatformTheme::Light, crate::module_bindings::RuntimePlatformTheme::Dark => DomainRuntimePlatformTheme::Dark, } } pub(crate) fn map_runtime_item_reward_item_rarity_back( value: RuntimeItemRewardItemRarity, ) -> DomainRuntimeItemRewardItemRarity { match value { RuntimeItemRewardItemRarity::Common => DomainRuntimeItemRewardItemRarity::Common, RuntimeItemRewardItemRarity::Uncommon => DomainRuntimeItemRewardItemRarity::Uncommon, RuntimeItemRewardItemRarity::Rare => DomainRuntimeItemRewardItemRarity::Rare, RuntimeItemRewardItemRarity::Epic => DomainRuntimeItemRewardItemRarity::Epic, RuntimeItemRewardItemRarity::Legendary => DomainRuntimeItemRewardItemRarity::Legendary, } } pub(crate) fn map_runtime_item_equipment_slot_back( value: RuntimeItemEquipmentSlot, ) -> DomainRuntimeItemEquipmentSlot { match value { RuntimeItemEquipmentSlot::Weapon => DomainRuntimeItemEquipmentSlot::Weapon, RuntimeItemEquipmentSlot::Armor => DomainRuntimeItemEquipmentSlot::Armor, RuntimeItemEquipmentSlot::Relic => DomainRuntimeItemEquipmentSlot::Relic, } } pub(crate) fn map_custom_world_theme_mode_back( value: CustomWorldThemeMode, ) -> DomainCustomWorldThemeMode { match value { CustomWorldThemeMode::Martial => DomainCustomWorldThemeMode::Martial, CustomWorldThemeMode::Arcane => DomainCustomWorldThemeMode::Arcane, CustomWorldThemeMode::Machina => DomainCustomWorldThemeMode::Machina, CustomWorldThemeMode::Tide => DomainCustomWorldThemeMode::Tide, CustomWorldThemeMode::Rift => DomainCustomWorldThemeMode::Rift, CustomWorldThemeMode::Mythic => DomainCustomWorldThemeMode::Mythic, } } pub(crate) fn map_custom_world_publication_status( value: CustomWorldPublicationStatus, ) -> &'static str { match value { CustomWorldPublicationStatus::Draft => "draft", CustomWorldPublicationStatus::Published => "published", } } pub(crate) fn map_rpg_agent_stage(value: crate::module_bindings::RpgAgentStage) -> String { match value { crate::module_bindings::RpgAgentStage::CollectingIntent => "collecting_intent", crate::module_bindings::RpgAgentStage::Clarifying => "clarifying", crate::module_bindings::RpgAgentStage::FoundationReview => "foundation_review", crate::module_bindings::RpgAgentStage::ObjectRefining => "object_refining", crate::module_bindings::RpgAgentStage::VisualRefining => "visual_refining", crate::module_bindings::RpgAgentStage::LongTailReview => "long_tail_review", crate::module_bindings::RpgAgentStage::ReadyToPublish => "ready_to_publish", crate::module_bindings::RpgAgentStage::Published => "published", crate::module_bindings::RpgAgentStage::Error => "error", } .to_string() } pub(crate) fn parse_puzzle_agent_stage_record( value: &str, ) -> Result { match value.trim() { "collecting_anchors" => Ok(crate::module_bindings::PuzzleAgentStage::CollectingAnchors), "draft_ready" => Ok(crate::module_bindings::PuzzleAgentStage::DraftReady), "image_refining" => Ok(crate::module_bindings::PuzzleAgentStage::ImageRefining), "ready_to_publish" => Ok(crate::module_bindings::PuzzleAgentStage::ReadyToPublish), "published" => Ok(crate::module_bindings::PuzzleAgentStage::Published), other => Err(SpacetimeClientError::Runtime(format!( "未知 puzzle agent stage: {other}" ))), } } pub(crate) fn parse_rpg_agent_stage_record( value: &str, ) -> Result { match value.trim() { "collecting_intent" => Ok(crate::module_bindings::RpgAgentStage::CollectingIntent), "clarifying" => Ok(crate::module_bindings::RpgAgentStage::Clarifying), "foundation_review" => Ok(crate::module_bindings::RpgAgentStage::FoundationReview), "object_refining" => Ok(crate::module_bindings::RpgAgentStage::ObjectRefining), "visual_refining" => Ok(crate::module_bindings::RpgAgentStage::VisualRefining), "long_tail_review" => Ok(crate::module_bindings::RpgAgentStage::LongTailReview), "ready_to_publish" => Ok(crate::module_bindings::RpgAgentStage::ReadyToPublish), "published" => Ok(crate::module_bindings::RpgAgentStage::Published), "error" => Ok(crate::module_bindings::RpgAgentStage::Error), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent stage: {other}" ))), } } pub(crate) fn format_rpg_agent_message_role( value: crate::module_bindings::RpgAgentMessageRole, ) -> &'static str { match value { crate::module_bindings::RpgAgentMessageRole::User => "user", crate::module_bindings::RpgAgentMessageRole::Assistant => "assistant", crate::module_bindings::RpgAgentMessageRole::System => "system", } } pub(crate) fn format_rpg_agent_message_kind( value: crate::module_bindings::RpgAgentMessageKind, ) -> &'static str { match value { crate::module_bindings::RpgAgentMessageKind::Chat => "chat", crate::module_bindings::RpgAgentMessageKind::Clarification => "clarification", crate::module_bindings::RpgAgentMessageKind::Summary => "summary", crate::module_bindings::RpgAgentMessageKind::Checkpoint => "checkpoint", crate::module_bindings::RpgAgentMessageKind::Warning => "warning", crate::module_bindings::RpgAgentMessageKind::ActionResult => "action_result", } } pub(crate) fn format_rpg_agent_operation_type( value: crate::module_bindings::RpgAgentOperationType, ) -> &'static str { match value { crate::module_bindings::RpgAgentOperationType::ProcessMessage => "process_message", crate::module_bindings::RpgAgentOperationType::DraftFoundation => "draft_foundation", crate::module_bindings::RpgAgentOperationType::UpdateDraftCard => "update_draft_card", crate::module_bindings::RpgAgentOperationType::SyncResultProfile => "sync_result_profile", crate::module_bindings::RpgAgentOperationType::GenerateCharacters => "generate_characters", crate::module_bindings::RpgAgentOperationType::GenerateLandmarks => "generate_landmarks", crate::module_bindings::RpgAgentOperationType::GenerateRoleAssets => "generate_role_assets", crate::module_bindings::RpgAgentOperationType::SyncRoleAssets => "sync_role_assets", crate::module_bindings::RpgAgentOperationType::GenerateSceneAssets => { "generate_scene_assets" } crate::module_bindings::RpgAgentOperationType::SyncSceneAssets => "sync_scene_assets", crate::module_bindings::RpgAgentOperationType::ExpandLongTail => "expand_long_tail", crate::module_bindings::RpgAgentOperationType::PublishWorld => "publish_world", crate::module_bindings::RpgAgentOperationType::RevertCheckpoint => "revert_checkpoint", crate::module_bindings::RpgAgentOperationType::DeleteCharacters => "delete_characters", crate::module_bindings::RpgAgentOperationType::DeleteLandmarks => "delete_landmarks", } } pub(crate) fn parse_rpg_agent_operation_type_record( value: &str, ) -> Result { match value.trim() { "process_message" => Ok(crate::module_bindings::RpgAgentOperationType::ProcessMessage), "draft_foundation" => Ok(crate::module_bindings::RpgAgentOperationType::DraftFoundation), "update_draft_card" => Ok(crate::module_bindings::RpgAgentOperationType::UpdateDraftCard), "sync_result_profile" => { Ok(crate::module_bindings::RpgAgentOperationType::SyncResultProfile) } "generate_characters" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateCharacters) } "generate_landmarks" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateLandmarks) } "generate_role_assets" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateRoleAssets) } "sync_role_assets" => Ok(crate::module_bindings::RpgAgentOperationType::SyncRoleAssets), "generate_scene_assets" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateSceneAssets) } "sync_scene_assets" => Ok(crate::module_bindings::RpgAgentOperationType::SyncSceneAssets), "expand_long_tail" => Ok(crate::module_bindings::RpgAgentOperationType::ExpandLongTail), "publish_world" => Ok(crate::module_bindings::RpgAgentOperationType::PublishWorld), "revert_checkpoint" => Ok(crate::module_bindings::RpgAgentOperationType::RevertCheckpoint), "delete_characters" => Ok(crate::module_bindings::RpgAgentOperationType::DeleteCharacters), "delete_landmarks" => Ok(crate::module_bindings::RpgAgentOperationType::DeleteLandmarks), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent operation type: {other}" ))), } } pub(crate) fn format_rpg_agent_operation_status( value: crate::module_bindings::RpgAgentOperationStatus, ) -> &'static str { match value { crate::module_bindings::RpgAgentOperationStatus::Queued => "queued", crate::module_bindings::RpgAgentOperationStatus::Running => "running", crate::module_bindings::RpgAgentOperationStatus::Completed => "completed", crate::module_bindings::RpgAgentOperationStatus::Failed => "failed", } } pub(crate) fn parse_rpg_agent_operation_status_record( value: &str, ) -> Result { match value.trim() { "queued" => Ok(crate::module_bindings::RpgAgentOperationStatus::Queued), "running" => Ok(crate::module_bindings::RpgAgentOperationStatus::Running), "completed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Completed), "failed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Failed), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent operation status: {other}" ))), } } pub(crate) fn format_rpg_agent_draft_card_kind( value: crate::module_bindings::RpgAgentDraftCardKind, ) -> &'static str { match value { crate::module_bindings::RpgAgentDraftCardKind::World => "world", crate::module_bindings::RpgAgentDraftCardKind::Camp => "camp", crate::module_bindings::RpgAgentDraftCardKind::Faction => "faction", crate::module_bindings::RpgAgentDraftCardKind::Character => "character", crate::module_bindings::RpgAgentDraftCardKind::Landmark => "landmark", crate::module_bindings::RpgAgentDraftCardKind::Thread => "thread", crate::module_bindings::RpgAgentDraftCardKind::Chapter => "chapter", crate::module_bindings::RpgAgentDraftCardKind::SceneChapter => "scene_chapter", crate::module_bindings::RpgAgentDraftCardKind::Carrier => "carrier", crate::module_bindings::RpgAgentDraftCardKind::SidequestSeed => "sidequest_seed", } } pub(crate) fn format_rpg_agent_draft_card_status( value: crate::module_bindings::RpgAgentDraftCardStatus, ) -> &'static str { match value { crate::module_bindings::RpgAgentDraftCardStatus::Suggested => "suggested", crate::module_bindings::RpgAgentDraftCardStatus::Confirmed => "confirmed", crate::module_bindings::RpgAgentDraftCardStatus::Locked => "locked", crate::module_bindings::RpgAgentDraftCardStatus::Warning => "warning", } } pub(crate) fn format_custom_world_role_asset_status_back( value: crate::module_bindings::CustomWorldRoleAssetStatus, ) -> String { match value { crate::module_bindings::CustomWorldRoleAssetStatus::Missing => "missing", crate::module_bindings::CustomWorldRoleAssetStatus::VisualReady => "visual_ready", crate::module_bindings::CustomWorldRoleAssetStatus::AnimationsReady => "animations_ready", crate::module_bindings::CustomWorldRoleAssetStatus::Complete => "complete", } .to_string() } impl TryFrom<&str> for BigFishAssetKind { type Error = SpacetimeClientError; fn try_from(value: &str) -> Result { match value.trim() { "level_main_image" => Ok(Self::LevelMainImage), "level_motion" => Ok(Self::LevelMotion), "stage_background" => Ok(Self::StageBackground), other => Err(SpacetimeClientError::Runtime(format!( "big fish asset kind `{other}` 当前尚未支持" ))), } } } pub(crate) fn parse_big_fish_creation_stage( value: &str, ) -> Result { match value.trim() { "collecting_anchors" => Ok(BigFishCreationStage::CollectingAnchors), "draft_ready" => Ok(BigFishCreationStage::DraftReady), "asset_refining" => Ok(BigFishCreationStage::AssetRefining), "ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish), "published" => Ok(BigFishCreationStage::Published), other => Err(SpacetimeClientError::Runtime(format!( "big fish creation stage `{other}` ??????" ))), } } pub(crate) fn format_big_fish_creation_stage(value: BigFishCreationStage) -> &'static str { match value { BigFishCreationStage::CollectingAnchors => "collecting_anchors", BigFishCreationStage::DraftReady => "draft_ready", BigFishCreationStage::AssetRefining => "asset_refining", BigFishCreationStage::ReadyToPublish => "ready_to_publish", BigFishCreationStage::Published => "published", } } pub(crate) fn format_big_fish_anchor_status(value: BigFishAnchorStatus) -> &'static str { match value { BigFishAnchorStatus::Confirmed => "confirmed", BigFishAnchorStatus::Inferred => "inferred", BigFishAnchorStatus::Missing => "missing", BigFishAnchorStatus::Locked => "locked", } } pub(crate) fn format_big_fish_agent_message_role(value: BigFishAgentMessageRole) -> &'static str { match value { BigFishAgentMessageRole::User => "user", BigFishAgentMessageRole::Assistant => "assistant", BigFishAgentMessageRole::System => "system", } } pub(crate) fn format_big_fish_agent_message_kind(value: BigFishAgentMessageKind) -> &'static str { match value { BigFishAgentMessageKind::Chat => "chat", BigFishAgentMessageKind::Summary => "summary", BigFishAgentMessageKind::ActionResult => "action_result", BigFishAgentMessageKind::Warning => "warning", } } pub(crate) fn format_big_fish_asset_kind(value: BigFishAssetKind) -> &'static str { match value { BigFishAssetKind::LevelMainImage => "level_main_image", BigFishAssetKind::LevelMotion => "level_motion", BigFishAssetKind::StageBackground => "stage_background", } } pub(crate) fn format_big_fish_asset_status(value: BigFishAssetStatus) -> &'static str { match value { BigFishAssetStatus::Missing => "missing", BigFishAssetStatus::Ready => "ready", } } pub(crate) fn format_custom_world_theme_mode(value: DomainCustomWorldThemeMode) -> &'static str { match value { DomainCustomWorldThemeMode::Martial => "martial", DomainCustomWorldThemeMode::Arcane => "arcane", DomainCustomWorldThemeMode::Machina => "machina", DomainCustomWorldThemeMode::Tide => "tide", DomainCustomWorldThemeMode::Rift => "rift", DomainCustomWorldThemeMode::Mythic => "mythic", } } pub(crate) fn map_battle_mode_back(value: BattleMode) -> DomainBattleMode { match value { BattleMode::Fight => DomainBattleMode::Fight, BattleMode::Spar => DomainBattleMode::Spar, } } pub(crate) fn map_runtime_browse_history_theme_mode_back( value: crate::module_bindings::RuntimeBrowseHistoryThemeMode, ) -> module_runtime::RuntimeBrowseHistoryThemeMode { match value { crate::module_bindings::RuntimeBrowseHistoryThemeMode::Martial => { module_runtime::RuntimeBrowseHistoryThemeMode::Martial } crate::module_bindings::RuntimeBrowseHistoryThemeMode::Arcane => { module_runtime::RuntimeBrowseHistoryThemeMode::Arcane } crate::module_bindings::RuntimeBrowseHistoryThemeMode::Machina => { module_runtime::RuntimeBrowseHistoryThemeMode::Machina } crate::module_bindings::RuntimeBrowseHistoryThemeMode::Tide => { module_runtime::RuntimeBrowseHistoryThemeMode::Tide } crate::module_bindings::RuntimeBrowseHistoryThemeMode::Rift => { module_runtime::RuntimeBrowseHistoryThemeMode::Rift } crate::module_bindings::RuntimeBrowseHistoryThemeMode::Mythic => { module_runtime::RuntimeBrowseHistoryThemeMode::Mythic } } } pub(crate) fn map_runtime_profile_wallet_ledger_source_type_back( value: crate::module_bindings::RuntimeProfileWalletLedgerSourceType, ) -> module_runtime::RuntimeProfileWalletLedgerSourceType { match value { crate::module_bindings::RuntimeProfileWalletLedgerSourceType::SnapshotSync => { module_runtime::RuntimeProfileWalletLedgerSourceType::SnapshotSync } crate::module_bindings::RuntimeProfileWalletLedgerSourceType::InviteInviterReward => { module_runtime::RuntimeProfileWalletLedgerSourceType::InviteInviterReward } crate::module_bindings::RuntimeProfileWalletLedgerSourceType::InviteInviteeReward => { module_runtime::RuntimeProfileWalletLedgerSourceType::InviteInviteeReward } crate::module_bindings::RuntimeProfileWalletLedgerSourceType::PointsRecharge => { module_runtime::RuntimeProfileWalletLedgerSourceType::PointsRecharge } crate::module_bindings::RuntimeProfileWalletLedgerSourceType::AssetGenerationConsume => { module_runtime::RuntimeProfileWalletLedgerSourceType::AssetGenerationConsume } crate::module_bindings::RuntimeProfileWalletLedgerSourceType::AssetGenerationRefund => { module_runtime::RuntimeProfileWalletLedgerSourceType::AssetGenerationRefund } } } pub(crate) fn map_runtime_profile_recharge_product_kind_back( value: crate::module_bindings::RuntimeProfileRechargeProductKind, ) -> module_runtime::RuntimeProfileRechargeProductKind { match value { crate::module_bindings::RuntimeProfileRechargeProductKind::Points => { module_runtime::RuntimeProfileRechargeProductKind::Points } crate::module_bindings::RuntimeProfileRechargeProductKind::Membership => { module_runtime::RuntimeProfileRechargeProductKind::Membership } } } pub(crate) fn map_runtime_profile_membership_status_back( value: crate::module_bindings::RuntimeProfileMembershipStatus, ) -> module_runtime::RuntimeProfileMembershipStatus { match value { crate::module_bindings::RuntimeProfileMembershipStatus::Normal => { module_runtime::RuntimeProfileMembershipStatus::Normal } crate::module_bindings::RuntimeProfileMembershipStatus::Active => { module_runtime::RuntimeProfileMembershipStatus::Active } } } pub(crate) fn map_runtime_profile_membership_tier_back( value: crate::module_bindings::RuntimeProfileMembershipTier, ) -> module_runtime::RuntimeProfileMembershipTier { match value { crate::module_bindings::RuntimeProfileMembershipTier::Normal => { module_runtime::RuntimeProfileMembershipTier::Normal } crate::module_bindings::RuntimeProfileMembershipTier::Month => { module_runtime::RuntimeProfileMembershipTier::Month } crate::module_bindings::RuntimeProfileMembershipTier::Season => { module_runtime::RuntimeProfileMembershipTier::Season } crate::module_bindings::RuntimeProfileMembershipTier::Year => { module_runtime::RuntimeProfileMembershipTier::Year } } } pub(crate) fn map_runtime_profile_recharge_order_status_back( value: crate::module_bindings::RuntimeProfileRechargeOrderStatus, ) -> module_runtime::RuntimeProfileRechargeOrderStatus { match value { crate::module_bindings::RuntimeProfileRechargeOrderStatus::Paid => { module_runtime::RuntimeProfileRechargeOrderStatus::Paid } } } pub(crate) fn map_story_session_status(value: StorySessionStatus) -> DomainStorySessionStatus { match value { StorySessionStatus::Active => DomainStorySessionStatus::Active, StorySessionStatus::Completed => DomainStorySessionStatus::Completed, StorySessionStatus::Archived => DomainStorySessionStatus::Archived, } } pub(crate) fn map_battle_status(value: BattleStatus) -> DomainBattleStatus { match value { BattleStatus::Ongoing => DomainBattleStatus::Ongoing, BattleStatus::Resolved => DomainBattleStatus::Resolved, BattleStatus::Aborted => DomainBattleStatus::Aborted, } } pub(crate) fn map_story_event_kind(value: StoryEventKind) -> DomainStoryEventKind { match value { StoryEventKind::SessionStarted => DomainStoryEventKind::SessionStarted, StoryEventKind::StoryContinued => DomainStoryEventKind::StoryContinued, } } pub(crate) fn map_ai_task_kind(value: DomainAiTaskKind) -> AiTaskKind { match value { DomainAiTaskKind::StoryGeneration => AiTaskKind::StoryGeneration, DomainAiTaskKind::CharacterChat => AiTaskKind::CharacterChat, DomainAiTaskKind::NpcChat => AiTaskKind::NpcChat, DomainAiTaskKind::CustomWorldGeneration => AiTaskKind::CustomWorldGeneration, DomainAiTaskKind::QuestIntent => AiTaskKind::QuestIntent, DomainAiTaskKind::RuntimeItemIntent => AiTaskKind::RuntimeItemIntent, } } pub(crate) fn map_ai_task_stage_kind(value: DomainAiTaskStageKind) -> AiTaskStageKind { match value { DomainAiTaskStageKind::PreparePrompt => AiTaskStageKind::PreparePrompt, DomainAiTaskStageKind::RequestModel => AiTaskStageKind::RequestModel, DomainAiTaskStageKind::RepairResponse => AiTaskStageKind::RepairResponse, DomainAiTaskStageKind::NormalizeResult => AiTaskStageKind::NormalizeResult, DomainAiTaskStageKind::PersistResult => AiTaskStageKind::PersistResult, } } pub(crate) fn map_ai_result_reference_kind( value: DomainAiResultReferenceKind, ) -> AiResultReferenceKind { match value { DomainAiResultReferenceKind::StorySession => AiResultReferenceKind::StorySession, DomainAiResultReferenceKind::StoryEvent => AiResultReferenceKind::StoryEvent, DomainAiResultReferenceKind::CustomWorldProfile => { AiResultReferenceKind::CustomWorldProfile } DomainAiResultReferenceKind::QuestRecord => AiResultReferenceKind::QuestRecord, DomainAiResultReferenceKind::RuntimeItemRecord => AiResultReferenceKind::RuntimeItemRecord, DomainAiResultReferenceKind::AssetObject => AiResultReferenceKind::AssetObject, } } pub(crate) fn format_ai_task_kind(value: AiTaskKind) -> &'static str { match value { AiTaskKind::StoryGeneration => "story_generation", AiTaskKind::CharacterChat => "character_chat", AiTaskKind::NpcChat => "npc_chat", AiTaskKind::CustomWorldGeneration => "custom_world_generation", AiTaskKind::QuestIntent => "quest_intent", AiTaskKind::RuntimeItemIntent => "runtime_item_intent", } } pub(crate) fn format_ai_task_status(value: AiTaskStatus) -> &'static str { match value { AiTaskStatus::Pending => "pending", AiTaskStatus::Running => "running", AiTaskStatus::Completed => "completed", AiTaskStatus::Failed => "failed", AiTaskStatus::Cancelled => "cancelled", } } pub(crate) fn format_ai_task_stage_kind(value: AiTaskStageKind) -> &'static str { match value { AiTaskStageKind::PreparePrompt => "prepare_prompt", AiTaskStageKind::RequestModel => "request_model", AiTaskStageKind::RepairResponse => "repair_response", AiTaskStageKind::NormalizeResult => "normalize_result", AiTaskStageKind::PersistResult => "persist_result", } } pub(crate) fn format_ai_task_stage_status(value: AiTaskStageStatus) -> &'static str { match value { AiTaskStageStatus::Pending => "pending", AiTaskStageStatus::Running => "running", AiTaskStageStatus::Completed => "completed", AiTaskStageStatus::Skipped => "skipped", } } pub(crate) fn format_ai_result_reference_kind(value: AiResultReferenceKind) -> &'static str { match value { AiResultReferenceKind::StorySession => "story_session", AiResultReferenceKind::StoryEvent => "story_event", AiResultReferenceKind::CustomWorldProfile => "custom_world_profile", AiResultReferenceKind::QuestRecord => "quest_record", AiResultReferenceKind::RuntimeItemRecord => "runtime_item_record", AiResultReferenceKind::AssetObject => "asset_object", } } pub(crate) fn map_combat_outcome(value: CombatOutcome) -> DomainCombatOutcome { match value { CombatOutcome::Ongoing => DomainCombatOutcome::Ongoing, CombatOutcome::Victory => DomainCombatOutcome::Victory, CombatOutcome::SparComplete => DomainCombatOutcome::SparComplete, CombatOutcome::Escaped => DomainCombatOutcome::Escaped, } } pub(crate) fn map_runtime_item_reward_item_snapshot( snapshot: DomainRuntimeItemRewardItemSnapshot, ) -> RuntimeItemRewardItemSnapshot { RuntimeItemRewardItemSnapshot { item_id: snapshot.item_id, category: snapshot.category, item_name: snapshot.item_name, description: snapshot.description, quantity: snapshot.quantity, rarity: map_runtime_item_reward_item_rarity(snapshot.rarity), tags: snapshot.tags, stackable: snapshot.stackable, stack_key: snapshot.stack_key, equipment_slot_id: snapshot .equipment_slot_id .map(map_runtime_item_equipment_slot), } } pub(crate) fn map_runtime_item_reward_item_snapshot_back( snapshot: RuntimeItemRewardItemSnapshot, ) -> DomainRuntimeItemRewardItemSnapshot { DomainRuntimeItemRewardItemSnapshot { item_id: snapshot.item_id, category: snapshot.category, item_name: snapshot.item_name, description: snapshot.description, quantity: snapshot.quantity, rarity: map_runtime_item_reward_item_rarity_back(snapshot.rarity), tags: snapshot.tags, stackable: snapshot.stackable, stack_key: snapshot.stack_key, equipment_slot_id: snapshot .equipment_slot_id .map(map_runtime_item_equipment_slot_back), } } pub(crate) fn parse_json_value( value: &str, label: &str, ) -> Result { serde_json::from_str::(value) .map_err(|error| SpacetimeClientError::Runtime(format!("{label} 非法: {error}"))) } pub(crate) fn parse_optional_json_value( value: Option<&str>, fallback: serde_json::Value, label: &str, ) -> Result { match value.map(str::trim).filter(|value| !value.is_empty()) { Some(value) => parse_json_value(value, label), None => Ok(fallback), } } pub(crate) fn parse_json_array( value: &str, label: &str, ) -> Result, SpacetimeClientError> { match parse_json_value(value, label)? { serde_json::Value::Array(entries) => Ok(entries), _ => Err(SpacetimeClientError::Runtime(format!( "{label} 必须是 JSON array" ))), } } pub(crate) fn parse_json_string_array( value: &str, label: &str, ) -> Result, SpacetimeClientError> { parse_json_array(value, label)? .into_iter() .map(|entry| match entry { serde_json::Value::String(value) => Ok(value), _ => Err(SpacetimeClientError::Runtime(format!( "{label} 必须是 string array" ))), }) .collect() } pub(crate) fn map_custom_world_checkpoint_record( value: serde_json::Value, ) -> Result { let object = value.as_object().ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint 必须是 JSON object".to_string()) })?; let checkpoint_id = object .get("checkpointId") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.checkpointId 缺失".to_string()) })?; let created_at = object .get("createdAt") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.createdAt 缺失".to_string()) })?; let label = object .get("label") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.label 缺失".to_string()) })?; Ok(CustomWorldCheckpointRecord { checkpoint_id: checkpoint_id.to_string(), created_at: created_at.to_string(), label: label.to_string(), }) } pub(crate) fn parse_supported_actions_json( value: &str, ) -> Result, SpacetimeClientError> { parse_json_array(value, "custom world agent supported_actions_json")? .into_iter() .map(|entry| { let object = entry.as_object().ok_or_else(|| { SpacetimeClientError::Runtime( "custom world supported action 必须是 JSON object".to_string(), ) })?; let action = object .get("action") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world supported action.action 缺失".to_string(), ) })?; let enabled = object .get("enabled") .and_then(serde_json::Value::as_bool) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world supported action.enabled 缺失".to_string(), ) })?; Ok(CustomWorldSupportedActionRecord { action: action.to_string(), enabled, reason: object .get("reason") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .map(ToOwned::to_owned), }) }) .collect() } pub(crate) fn parse_custom_world_publish_gate_record( value: &str, ) -> Result { let object = parse_json_value(value, "custom world publish_gate_json")? .as_object() .cloned() .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish_gate_json 必须是 JSON object".to_string(), ) })?; let profile_id = object .get("profileId") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.profileId 缺失".to_string()) })?; let blockers = object .get("blockers") .and_then(serde_json::Value::as_array) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.blockers 缺失".to_string()) })? .iter() .cloned() .map(|entry| { let object = entry.as_object().ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker 必须是 JSON object".to_string(), ) })?; let id = object .get("id") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.id 缺失".to_string(), ) })?; let code = object .get("code") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.code 缺失".to_string(), ) })?; let message = object .get("message") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.message 缺失".to_string(), ) })?; Ok(CustomWorldResultPreviewBlockerRecord { id: id.to_string(), code: code.to_string(), message: message.to_string(), }) }) .collect::, _>>()?; let blocker_count = object .get("blockerCount") .and_then(serde_json::Value::as_u64) .and_then(|value| u32::try_from(value).ok()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.blockerCount 缺失".to_string()) })?; let publish_ready = object .get("publishReady") .and_then(serde_json::Value::as_bool) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.publishReady 缺失".to_string()) })?; let can_enter_world = object .get("canEnterWorld") .and_then(serde_json::Value::as_bool) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish_gate.canEnterWorld 缺失".to_string(), ) })?; Ok(CustomWorldPublishGateRecord { profile_id: profile_id.to_string(), blockers, blocker_count, publish_ready, can_enter_world, }) } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BattleStateRecord { pub battle_state_id: String, pub story_session_id: String, pub runtime_session_id: String, pub actor_user_id: String, pub chapter_id: Option, pub target_npc_id: String, pub target_name: String, pub battle_mode: String, pub status: String, pub player_hp: i32, pub player_max_hp: i32, pub player_mana: i32, pub player_max_mana: i32, pub target_hp: i32, pub target_max_hp: i32, pub experience_reward: u32, pub reward_items: Vec, pub turn_index: u32, pub last_action_function_id: Option, pub last_action_text: Option, pub last_result_text: Option, pub last_damage_dealt: i32, pub last_damage_taken: i32, pub last_outcome: String, pub version: u32, pub created_at: String, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct ResolveCombatActionRecord { pub battle_state: BattleStateRecord, pub damage_dealt: i32, pub damage_taken: i32, pub outcome: String, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldLibraryEntryRecord { pub owner_user_id: String, pub profile_id: String, pub public_work_code: Option, pub author_public_user_code: Option, pub profile: serde_json::Value, pub visibility: String, pub published_at: Option, 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, pub theme_mode: String, pub playable_npc_count: u32, pub landmark_count: u32, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldGalleryEntryRecord { pub owner_user_id: String, pub profile_id: String, pub public_work_code: String, pub author_public_user_code: String, pub visibility: String, pub published_at: Option, 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, pub theme_mode: String, pub playable_npc_count: u32, pub landmark_count: u32, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldLibraryMutationRecord { pub entry: CustomWorldLibraryEntryRecord, pub gallery_entry: Option, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldPublishedProfileCompileRecord { pub profile_id: String, pub owner_user_id: String, pub world_name: String, pub subtitle: String, pub summary_text: String, pub theme_mode: String, pub cover_image_src: Option, pub playable_npc_count: u32, pub landmark_count: u32, pub author_display_name: String, pub compiled_profile: serde_json::Value, pub updated_at: String, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldPublishWorldRecord { pub compiled_record: CustomWorldPublishedProfileCompileRecord, pub entry: CustomWorldLibraryEntryRecord, pub gallery_entry: Option, pub session_stage: String, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldAgentMessageRecord { pub message_id: String, pub role: String, pub kind: String, pub text: String, pub created_at: String, pub related_operation_id: Option, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldAgentOperationRecord { pub operation_id: String, pub operation_type: String, pub status: String, pub phase_label: String, pub phase_detail: String, pub progress: u32, pub error_message: Option, pub started_at_micros: i64, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldAgentOperationProgressRecordInput { pub session_id: String, pub owner_user_id: String, pub operation_id: String, // SpacetimeDB 模块侧使用枚举存储操作类型,这里保留字符串给 API 层做轻量传参。 pub operation_type: String, pub operation_status: String, pub phase_label: String, pub phase_detail: String, pub operation_progress: u32, pub error_message: Option, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldDraftCardRecord { pub card_id: String, pub kind: String, pub title: String, pub subtitle: String, pub summary: String, pub status: String, pub linked_ids: Vec, pub warning_count: u32, pub asset_status: Option, pub asset_status_label: Option, pub detail_payload: Option, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldSupportedActionRecord { pub action: String, pub enabled: bool, pub reason: Option, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldCheckpointRecord { pub checkpoint_id: String, pub created_at: String, pub label: String, } // 兼容并行 custom world facade 中仍在使用的旧命名,避免本轮 module-npc 收口被无关改动阻塞。 pub type CustomWorldAgentCheckpointRecord = CustomWorldCheckpointRecord; #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldResultPreviewBlockerRecord { pub id: String, pub code: String, pub message: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldPublishGateRecord { pub profile_id: String, pub blockers: Vec, pub blocker_count: u32, pub publish_ready: bool, pub can_enter_world: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldWorkSummaryRecord { 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, pub cover_render_mode: Option, pub cover_character_image_srcs: Vec, pub updated_at: String, pub published_at: Option, pub stage: Option, pub stage_label: Option, pub playable_npc_count: u32, pub landmark_count: u32, pub role_visual_ready_count: Option, pub role_animation_ready_count: Option, pub role_asset_summary_label: Option, pub session_id: Option, pub profile_id: Option, pub can_resume: bool, pub can_enter_world: bool, pub blocker_count: u32, pub publish_ready: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldDraftCardDetailSectionRecord { pub section_id: String, pub label: String, pub value: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldDraftCardDetailRecord { pub card_id: String, pub kind: String, pub title: String, pub sections: Vec, pub linked_ids: Vec, pub locked: bool, pub editable: bool, pub editable_section_ids: Vec, pub warning_messages: Vec, pub asset_status: Option, pub asset_status_label: Option, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldAgentSessionRecord { pub session_id: String, pub seed_text: String, pub current_turn: u32, pub anchor_content: serde_json::Value, pub progress_percent: u32, pub last_assistant_reply: Option, pub stage: String, pub focus_card_id: Option, 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, pub draft_cards: Vec, pub pending_clarifications: Vec, pub suggested_actions: Vec, pub recommended_replies: Vec, pub quality_findings: Vec, pub asset_coverage: serde_json::Value, pub checkpoints: Vec, pub supported_actions: Vec, pub publish_gate: Option, pub result_preview: Option, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldProfileUpsertRecordInput { pub profile_id: String, pub owner_user_id: String, pub public_work_code: Option, pub author_public_user_code: Option, pub source_agent_session_id: Option, pub world_name: String, pub subtitle: String, pub summary_text: String, pub theme_mode: DomainCustomWorldThemeMode, pub cover_image_src: Option, pub profile_payload_json: String, pub playable_npc_count: u32, pub landmark_count: u32, pub author_display_name: String, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldPublishWorldRecordInput { pub session_id: String, pub profile_id: String, pub owner_user_id: String, pub public_work_code: Option, pub author_public_user_code: String, pub draft_profile_json: String, pub legacy_result_profile_json: Option, pub setting_text: String, pub author_display_name: String, pub published_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldAgentSessionCreateRecordInput { pub session_id: String, pub owner_user_id: String, pub seed_text: String, pub welcome_message_id: String, pub welcome_message_text: String, pub anchor_content_json: String, pub creator_intent_json: Option, pub creator_intent_readiness_json: String, pub anchor_pack_json: Option, pub lock_state_json: Option, pub draft_profile_json: Option, pub pending_clarifications_json: String, pub suggested_actions_json: String, pub recommended_replies_json: String, pub quality_findings_json: String, pub asset_coverage_json: String, pub checkpoints_json: String, pub created_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldAgentMessageSubmitRecordInput { pub session_id: String, pub owner_user_id: String, pub user_message_id: String, pub user_message_text: String, pub operation_id: String, pub submitted_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldAgentMessageFinalizeRecordInput { pub session_id: String, pub owner_user_id: String, pub operation_id: String, pub assistant_message_id: Option, pub assistant_reply_text: Option, pub phase_label: String, pub phase_detail: String, pub operation_status: String, pub operation_progress: u32, pub stage: String, pub progress_percent: u32, pub focus_card_id: Option, pub anchor_content_json: String, pub creator_intent_json: Option, pub creator_intent_readiness_json: String, pub anchor_pack_json: Option, pub draft_profile_json: Option, pub pending_clarifications_json: String, pub suggested_actions_json: String, pub recommended_replies_json: String, pub quality_findings_json: String, pub asset_coverage_json: String, pub error_message: Option, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CustomWorldAgentActionExecuteRecordInput { pub session_id: String, pub owner_user_id: String, pub operation_id: String, pub action: String, pub payload_json: Option, pub submitted_at_micros: i64, } #[derive(Clone, Debug, PartialEq)] pub struct CustomWorldAgentActionExecuteRecord { pub operation: CustomWorldAgentOperationRecord, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentSessionCreateRecordInput { pub session_id: String, pub owner_user_id: String, pub seed_text: String, pub welcome_message_id: String, pub welcome_message_text: String, pub created_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentMessageSubmitRecordInput { pub session_id: String, pub owner_user_id: String, pub user_message_id: String, pub user_message_text: String, pub submitted_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentMessageFinalizeRecordInput { pub session_id: String, pub owner_user_id: String, pub assistant_message_id: Option, pub assistant_reply_text: Option, pub stage: String, pub progress_percent: u32, pub anchor_pack_json: String, pub error_message: Option, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleGeneratedImagesSaveRecordInput { pub session_id: String, pub owner_user_id: String, pub candidates_json: String, pub saved_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleSelectCoverImageRecordInput { pub session_id: String, pub owner_user_id: String, pub candidate_id: String, pub selected_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzlePublishRecordInput { pub session_id: String, pub owner_user_id: String, pub work_id: String, pub profile_id: String, pub author_display_name: String, pub level_name: Option, pub summary: Option, pub theme_tags: Option>, pub published_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleWorkUpsertRecordInput { pub profile_id: String, pub owner_user_id: String, pub level_name: String, pub summary: String, pub theme_tags: Vec, pub cover_image_src: Option, pub cover_asset_id: Option, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRunStartRecordInput { pub run_id: String, pub owner_user_id: String, pub profile_id: String, pub started_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRunSwapRecordInput { pub run_id: String, pub owner_user_id: String, pub first_piece_id: String, pub second_piece_id: String, pub swapped_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRunDragRecordInput { pub run_id: String, pub owner_user_id: String, pub piece_id: String, pub target_row: u32, pub target_col: u32, pub dragged_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRunNextLevelRecordInput { pub run_id: String, pub owner_user_id: String, pub advanced_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAnchorItemRecord { pub key: String, pub label: String, pub value: String, pub status: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAnchorPackRecord { pub theme_promise: PuzzleAnchorItemRecord, pub visual_subject: PuzzleAnchorItemRecord, pub visual_mood: PuzzleAnchorItemRecord, pub composition_hooks: PuzzleAnchorItemRecord, pub tags_and_forbidden: PuzzleAnchorItemRecord, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleCreatorIntentRecord { pub source_mode: String, pub raw_messages_summary: String, pub theme_promise: String, pub visual_subject: String, pub visual_mood: Vec, pub composition_hooks: Vec, pub theme_tags: Vec, pub forbidden_directives: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleGeneratedImageCandidateRecord { pub candidate_id: String, pub image_src: String, pub asset_id: String, pub prompt: String, pub actual_prompt: Option, pub source_type: String, pub selected: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleResultDraftRecord { pub level_name: String, pub summary: String, pub theme_tags: Vec, pub forbidden_directives: Vec, pub creator_intent: Option, pub anchor_pack: PuzzleAnchorPackRecord, pub candidates: Vec, pub selected_candidate_id: Option, pub cover_image_src: Option, pub cover_asset_id: Option, pub generation_status: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentMessageRecord { pub message_id: String, pub role: String, pub kind: String, pub text: String, pub created_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentSuggestedActionRecord { pub action_id: String, pub action_type: String, pub label: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleResultPreviewBlockerRecord { pub blocker_id: String, pub code: String, pub message: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleResultPreviewFindingRecord { pub finding_id: String, pub severity: String, pub code: String, pub message: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleResultPreviewRecord { pub draft: PuzzleResultDraftRecord, pub blockers: Vec, pub quality_findings: Vec, pub publish_ready: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleAgentSessionRecord { pub session_id: String, pub current_turn: u32, pub progress_percent: u32, pub stage: String, pub anchor_pack: PuzzleAnchorPackRecord, pub draft: Option, pub messages: Vec, pub last_assistant_reply: Option, pub published_profile_id: Option, pub suggested_actions: Vec, pub result_preview: Option, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleWorkProfileRecord { pub work_id: String, pub profile_id: String, pub owner_user_id: String, pub source_session_id: Option, pub author_display_name: String, pub level_name: String, pub summary: String, pub theme_tags: Vec, pub cover_image_src: Option, pub cover_asset_id: Option, pub publication_status: String, pub updated_at: String, pub published_at: Option, pub play_count: u32, pub publish_ready: bool, pub anchor_pack: PuzzleAnchorPackRecord, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleCellPositionRecord { pub row: u32, pub col: u32, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzlePieceStateRecord { pub piece_id: String, pub correct_row: u32, pub correct_col: u32, pub current_row: u32, pub current_col: u32, pub merged_group_id: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleMergedGroupRecord { pub group_id: String, pub piece_ids: Vec, pub occupied_cells: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleLeaderboardEntryRecord { pub rank: u32, pub nickname: String, pub elapsed_ms: u64, pub is_current_player: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleBoardRecord { pub rows: u32, pub cols: u32, pub pieces: Vec, pub merged_groups: Vec, pub selected_piece_id: Option, pub all_tiles_resolved: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRuntimeLevelRecord { pub run_id: String, pub level_index: u32, pub grid_size: u32, pub profile_id: String, pub level_name: String, pub author_display_name: String, pub theme_tags: Vec, pub cover_image_src: Option, pub board: PuzzleBoardRecord, pub status: String, pub started_at_ms: u64, pub cleared_at_ms: Option, pub elapsed_ms: Option, pub leaderboard_entries: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleRunRecord { 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, pub previous_level_tags: Vec, pub current_level: Option, pub recommended_next_profile_id: Option, pub leaderboard_entries: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct PuzzleLeaderboardSubmitRecordInput { pub run_id: String, pub owner_user_id: String, pub profile_id: String, pub grid_size: u32, pub elapsed_ms: u64, pub nickname: String, pub submitted_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishSessionCreateRecordInput { pub session_id: String, pub owner_user_id: String, pub seed_text: String, pub welcome_message_id: String, pub welcome_message_text: String, pub created_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishMessageSubmitRecordInput { pub session_id: String, pub owner_user_id: String, pub user_message_id: String, pub user_message_text: String, pub assistant_message_id: String, pub submitted_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishMessageFinalizeRecordInput { pub session_id: String, pub owner_user_id: String, pub assistant_message_id: Option, pub assistant_reply_text: Option, pub stage: String, pub progress_percent: u32, pub anchor_pack_json: String, pub error_message: Option, pub updated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAssetGenerateRecordInput { pub session_id: String, pub owner_user_id: String, pub asset_kind: String, pub level: Option, pub motion_key: Option, pub asset_url: Option, pub generated_at_micros: i64, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAnchorItemRecord { pub key: String, pub label: String, pub value: String, pub status: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAnchorPackRecord { pub gameplay_promise: BigFishAnchorItemRecord, pub ecology_visual_theme: BigFishAnchorItemRecord, pub growth_ladder: BigFishAnchorItemRecord, pub risk_tempo: BigFishAnchorItemRecord, } #[derive(Clone, Debug, PartialEq)] pub struct BigFishLevelBlueprintRecord { pub level: u32, pub name: String, pub one_line_fantasy: String, pub silhouette_direction: String, pub size_ratio: f32, pub visual_prompt_seed: String, pub motion_prompt_seed: String, pub merge_source_level: Option, pub prey_window: Vec, pub threat_window: Vec, pub is_final_level: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishBackgroundBlueprintRecord { 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, PartialEq)] pub struct BigFishRuntimeParamsRecord { 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, pub threat_spawn_delta_levels: Vec, pub win_level: u32, } #[derive(Clone, Debug, PartialEq)] pub struct BigFishGameDraftRecord { pub title: String, pub subtitle: String, pub core_fun: String, pub ecology_theme: String, pub levels: Vec, pub background: BigFishBackgroundBlueprintRecord, pub runtime_params: BigFishRuntimeParamsRecord, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAgentMessageRecord { pub message_id: String, pub role: String, pub kind: String, pub text: String, pub created_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAssetSlotRecord { pub slot_id: String, pub asset_kind: String, pub level: Option, pub motion_key: Option, pub status: String, pub asset_url: Option, pub prompt_snapshot: String, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAssetCoverageRecord { 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, } #[derive(Clone, Debug, PartialEq)] pub struct BigFishSessionRecord { pub session_id: String, pub current_turn: u32, pub progress_percent: u32, pub stage: String, pub anchor_pack: BigFishAnchorPackRecord, pub draft: Option, pub asset_slots: Vec, pub asset_coverage: BigFishAssetCoverageRecord, pub messages: Vec, pub last_assistant_reply: Option, pub publish_ready: bool, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct BigFishWorkSummaryRecord { pub work_id: String, pub source_session_id: String, pub owner_user_id: String, pub title: String, pub subtitle: String, pub summary: String, pub cover_image_src: Option, pub status: String, pub updated_at_micros: i64, pub publish_ready: bool, pub level_count: u32, pub level_main_image_ready_count: u32, pub level_motion_ready_count: u32, pub background_ready: bool, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct ResolveNpcBattleInteractionInput { pub npc_interaction: DomainResolveNpcInteractionInput, pub story_session_id: String, pub actor_user_id: String, pub battle_state_id: Option, pub player_hp: i32, pub player_max_hp: i32, pub player_mana: i32, pub player_max_mana: i32, pub target_hp: i32, pub target_max_hp: i32, pub experience_reward: u32, pub reward_items: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct AiTaskStageRecord { pub stage_kind: String, pub label: String, pub detail: String, pub order: u32, pub status: String, pub text_output: Option, pub structured_payload_json: Option, pub warning_messages: Vec, pub started_at: Option, pub completed_at: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct AiResultReferenceRecord { pub result_ref_id: String, pub task_id: String, pub reference_kind: String, pub reference_id: String, pub label: Option, pub created_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct AiTextChunkRecord { pub chunk_id: String, pub task_id: String, pub stage_kind: String, pub sequence: u32, pub delta_text: String, pub created_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct AiTaskRecord { pub task_id: String, pub task_kind: String, pub owner_user_id: String, pub request_label: String, pub source_module: String, pub source_entity_id: Option, pub request_payload_json: Option, pub status: String, pub failure_message: Option, pub stages: Vec, pub result_references: Vec, pub latest_text_output: Option, pub latest_structured_payload_json: Option, pub version: u32, pub created_at: String, pub started_at: Option, pub completed_at: Option, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct AiTaskMutationRecord { pub task: AiTaskRecord, pub text_chunk: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct NpcStateRecord { pub npc_state_id: String, pub runtime_session_id: String, pub npc_id: String, pub npc_name: String, pub affinity: i32, pub relation_stance: String, pub help_used: bool, pub chatted_count: u32, pub gifts_given: u32, pub recruited: bool, pub trade_stock_signature: Option, pub revealed_facts: Vec, pub known_attribute_rumors: Vec, pub first_meaningful_contact_resolved: bool, pub seen_backstory_chapter_ids: Vec, pub trust: u8, pub warmth: u8, pub ideological_fit: u8, pub fear_or_guard: u8, pub loyalty: u8, pub current_conflict_tag: Option, pub recent_approvals: Vec, pub recent_disapprovals: Vec, pub created_at: String, pub updated_at: String, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct NpcInteractionRecord { pub npc_state: NpcStateRecord, pub interaction_status: String, pub action_text: String, pub result_text: String, pub story_text: Option, pub battle_mode: Option, pub encounter_closed: bool, pub affinity_changed: bool, pub previous_affinity: i32, pub next_affinity: i32, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct NpcBattleInteractionRecord { pub npc_interaction: NpcInteractionRecord, pub battle_state: BattleStateRecord, } #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct NpcBattleInteractionSnapshot { interaction: DomainNpcInteractionResult, battle_state: DomainBattleStateSnapshot, } pub(crate) fn build_battle_state_record(snapshot: DomainBattleStateSnapshot) -> BattleStateRecord { BattleStateRecord { battle_state_id: snapshot.battle_state_id, story_session_id: snapshot.story_session_id, runtime_session_id: snapshot.runtime_session_id, actor_user_id: snapshot.actor_user_id, chapter_id: snapshot.chapter_id, target_npc_id: snapshot.target_npc_id, target_name: snapshot.target_name, battle_mode: snapshot.battle_mode.as_str().to_string(), status: snapshot.status.as_str().to_string(), player_hp: snapshot.player_hp, player_max_hp: snapshot.player_max_hp, player_mana: snapshot.player_mana, player_max_mana: snapshot.player_max_mana, target_hp: snapshot.target_hp, target_max_hp: snapshot.target_max_hp, experience_reward: snapshot.experience_reward, reward_items: snapshot.reward_items, turn_index: snapshot.turn_index, last_action_function_id: snapshot.last_action_function_id, last_action_text: snapshot.last_action_text, last_result_text: snapshot.last_result_text, last_damage_dealt: snapshot.last_damage_dealt, last_damage_taken: snapshot.last_damage_taken, last_outcome: snapshot.last_outcome.as_str().to_string(), version: snapshot.version, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn build_resolve_combat_action_record( result: DomainResolveCombatActionResult, ) -> ResolveCombatActionRecord { ResolveCombatActionRecord { battle_state: build_battle_state_record(result.snapshot), damage_dealt: result.damage_dealt, damage_taken: result.damage_taken, outcome: result.outcome.as_str().to_string(), } } impl From for crate::module_bindings::ResolveNpcBattleInteractionInput { fn from(input: ResolveNpcBattleInteractionInput) -> Self { Self { npc_interaction: crate::module_bindings::ResolveNpcInteractionInput { runtime_session_id: input.npc_interaction.runtime_session_id, npc_id: input.npc_interaction.npc_id, npc_name: input.npc_interaction.npc_name, interaction_function_id: input.npc_interaction.interaction_function_id, release_npc_id: input.npc_interaction.release_npc_id, updated_at_micros: input.npc_interaction.updated_at_micros, }, story_session_id: input.story_session_id, actor_user_id: input.actor_user_id, battle_state_id: input.battle_state_id, player_hp: input.player_hp, player_max_hp: input.player_max_hp, player_mana: input.player_mana, player_max_mana: input.player_max_mana, target_hp: input.target_hp, target_max_hp: input.target_max_hp, experience_reward: input.experience_reward, reward_items: input .reward_items .into_iter() .map(map_runtime_item_reward_item_snapshot) .collect(), } } } pub(crate) fn validate_npc_battle_interaction_input( input: &ResolveNpcBattleInteractionInput, ) -> Result<(), SpacetimeClientError> { let battle_state_input = DomainBattleStateInput { battle_state_id: input .battle_state_id .clone() .unwrap_or_else(|| "battle_preview".to_string()), story_session_id: input.story_session_id.clone(), runtime_session_id: input.npc_interaction.runtime_session_id.clone(), actor_user_id: input.actor_user_id.clone(), chapter_id: None, target_npc_id: input.npc_interaction.npc_id.clone(), target_name: input.npc_interaction.npc_name.clone(), battle_mode: DomainBattleMode::Fight, player_hp: input.player_hp, player_max_hp: input.player_max_hp, player_mana: input.player_mana, player_max_mana: input.player_max_mana, target_hp: input.target_hp, target_max_hp: input.target_max_hp, experience_reward: input.experience_reward, reward_items: input.reward_items.clone(), created_at_micros: input.npc_interaction.updated_at_micros, }; validate_battle_state_input(&battle_state_input) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; for reward_item in input.reward_items.iter().cloned() { normalize_reward_item_snapshot(reward_item) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; } Ok(()) } pub(crate) fn build_npc_state_record(snapshot: DomainNpcStateSnapshot) -> NpcStateRecord { NpcStateRecord { npc_state_id: snapshot.npc_state_id, runtime_session_id: snapshot.runtime_session_id, npc_id: snapshot.npc_id, npc_name: snapshot.npc_name, affinity: snapshot.affinity, relation_stance: format_npc_relation_stance(snapshot.relation_state.stance).to_string(), help_used: snapshot.help_used, chatted_count: snapshot.chatted_count, gifts_given: snapshot.gifts_given, recruited: snapshot.recruited, trade_stock_signature: snapshot.trade_stock_signature, revealed_facts: snapshot.revealed_facts, known_attribute_rumors: snapshot.known_attribute_rumors, first_meaningful_contact_resolved: snapshot.first_meaningful_contact_resolved, seen_backstory_chapter_ids: snapshot.seen_backstory_chapter_ids, trust: snapshot.stance_profile.trust, warmth: snapshot.stance_profile.warmth, ideological_fit: snapshot.stance_profile.ideological_fit, fear_or_guard: snapshot.stance_profile.fear_or_guard, loyalty: snapshot.stance_profile.loyalty, current_conflict_tag: snapshot.stance_profile.current_conflict_tag, recent_approvals: snapshot.stance_profile.recent_approvals, recent_disapprovals: snapshot.stance_profile.recent_disapprovals, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } pub(crate) fn build_npc_interaction_record( result: DomainNpcInteractionResult, ) -> NpcInteractionRecord { NpcInteractionRecord { npc_state: build_npc_state_record(result.npc_state), interaction_status: format_npc_interaction_status(result.interaction_status).to_string(), action_text: result.action_text, result_text: result.result_text, story_text: result.story_text, battle_mode: result .battle_mode .map(|mode| format_npc_interaction_battle_mode(mode).to_string()), encounter_closed: result.encounter_closed, affinity_changed: result.affinity_changed, previous_affinity: result.previous_affinity, next_affinity: result.next_affinity, } } pub(crate) fn build_npc_battle_interaction_record( result: NpcBattleInteractionSnapshot, ) -> NpcBattleInteractionRecord { NpcBattleInteractionRecord { npc_interaction: build_npc_interaction_record(result.interaction), battle_state: build_battle_state_record(result.battle_state), } } pub(crate) fn format_npc_relation_stance(value: DomainNpcRelationStance) -> &'static str { match value { DomainNpcRelationStance::Hostile => "hostile", DomainNpcRelationStance::Guarded => "guarded", DomainNpcRelationStance::Neutral => "neutral", DomainNpcRelationStance::Cooperative => "cooperative", DomainNpcRelationStance::Bonded => "bonded", } } pub(crate) fn format_npc_interaction_status(value: DomainNpcInteractionStatus) -> &'static str { match value { DomainNpcInteractionStatus::Previewed => "previewed", DomainNpcInteractionStatus::Dialogue => "dialogue", DomainNpcInteractionStatus::Resolved => "resolved", DomainNpcInteractionStatus::Recruited => "recruited", DomainNpcInteractionStatus::BattlePending => "battle_pending", DomainNpcInteractionStatus::Left => "left", } } pub(crate) fn format_npc_interaction_battle_mode( value: DomainNpcInteractionBattleMode, ) -> &'static str { match value { DomainNpcInteractionBattleMode::Fight => "fight", DomainNpcInteractionBattleMode::Spar => "spar", } } pub(crate) fn map_inventory_container_kind( value: InventoryContainerKind, ) -> module_inventory::InventoryContainerKind { match value { InventoryContainerKind::Backpack => module_inventory::InventoryContainerKind::Backpack, InventoryContainerKind::Equipment => module_inventory::InventoryContainerKind::Equipment, } } pub(crate) fn map_inventory_item_rarity( value: InventoryItemRarity, ) -> module_inventory::InventoryItemRarity { match value { InventoryItemRarity::Common => module_inventory::InventoryItemRarity::Common, InventoryItemRarity::Uncommon => module_inventory::InventoryItemRarity::Uncommon, InventoryItemRarity::Rare => module_inventory::InventoryItemRarity::Rare, InventoryItemRarity::Epic => module_inventory::InventoryItemRarity::Epic, InventoryItemRarity::Legendary => module_inventory::InventoryItemRarity::Legendary, } } pub(crate) fn map_inventory_equipment_slot( value: InventoryEquipmentSlot, ) -> module_inventory::InventoryEquipmentSlot { match value { InventoryEquipmentSlot::Weapon => module_inventory::InventoryEquipmentSlot::Weapon, InventoryEquipmentSlot::Armor => module_inventory::InventoryEquipmentSlot::Armor, InventoryEquipmentSlot::Relic => module_inventory::InventoryEquipmentSlot::Relic, } } pub(crate) fn map_inventory_item_source_kind( value: InventoryItemSourceKind, ) -> module_inventory::InventoryItemSourceKind { match value { InventoryItemSourceKind::StoryReward => { module_inventory::InventoryItemSourceKind::StoryReward } InventoryItemSourceKind::QuestReward => { module_inventory::InventoryItemSourceKind::QuestReward } InventoryItemSourceKind::TreasureReward => { module_inventory::InventoryItemSourceKind::TreasureReward } InventoryItemSourceKind::NpcGift => module_inventory::InventoryItemSourceKind::NpcGift, InventoryItemSourceKind::NpcTrade => module_inventory::InventoryItemSourceKind::NpcTrade, InventoryItemSourceKind::CombatDrop => { module_inventory::InventoryItemSourceKind::CombatDrop } InventoryItemSourceKind::ForgeCraft => { module_inventory::InventoryItemSourceKind::ForgeCraft } InventoryItemSourceKind::ForgeReforge => { module_inventory::InventoryItemSourceKind::ForgeReforge } InventoryItemSourceKind::ManualPatch => { module_inventory::InventoryItemSourceKind::ManualPatch } } }