Files
Genarrative/server-rs/crates/spacetime-client/src/mapper/custom_world.rs

958 lines
38 KiB
Rust

use super::*;
impl From<CustomWorldProfileUpsertRecordInput> 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,
}
}
}
pub(crate) fn map_custom_world_profile_list_result(
result: CustomWorldProfileListResult,
) -> Result<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
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<Vec<CustomWorldGalleryEntryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result
.entries
.into_iter()
.map(map_custom_world_gallery_entry_snapshot)
.collect::<Result<Vec<_>, _>>()?)
}
pub(crate) fn map_custom_world_library_mutation_result(
result: CustomWorldLibraryMutationResult,
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let entry = result
.entry
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
.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<CustomWorldPublishWorldRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let compiled_record = result
.compiled_record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("published profile compile 快照"))
.and_then(map_custom_world_published_profile_compile_snapshot)?;
let entry = result
.entry
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry"))
.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::missing_snapshot("session stage"))
.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<CustomWorldAgentSessionRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let session = result
.session
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world agent session 快照"))?;
map_custom_world_agent_session_snapshot(session)
}
pub(crate) fn map_custom_world_agent_operation_procedure_result(
result: CustomWorldAgentOperationProcedureResult,
) -> Result<CustomWorldAgentOperationRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let operation = result.operation.ok_or_else(|| {
SpacetimeClientError::missing_snapshot("custom world agent operation 快照")
})?;
Ok(map_custom_world_agent_operation_snapshot(operation))
}
pub(crate) fn map_custom_world_works_list_result(
result: CustomWorldWorksListResult,
) -> Result<Vec<CustomWorldWorkSummaryRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
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<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let card = result
.card
.ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world card detail 快照"))?;
map_custom_world_draft_card_detail_snapshot(card)
}
pub(crate) fn map_custom_world_agent_action_execute_result(
result: CustomWorldAgentActionExecuteResult,
) -> Result<CustomWorldAgentActionExecuteRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let operation = result.operation.ok_or_else(|| {
SpacetimeClientError::missing_snapshot("custom world action operation 快照")
})?;
Ok(CustomWorldAgentActionExecuteRecord {
operation: map_custom_world_agent_operation_snapshot(operation),
})
}
pub(crate) fn map_custom_world_library_entry_from_profile_snapshot(
snapshot: CustomWorldProfileSnapshot,
) -> Result<CustomWorldLibraryEntryRecord, SpacetimeClientError> {
let profile = serde_json::from_str::<serde_json::Value>(&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,
play_count: snapshot.play_count,
remix_count: snapshot.remix_count,
like_count: snapshot.like_count,
recent_play_count_7d: 0,
})
}
pub(crate) fn map_custom_world_gallery_entry_snapshot(
snapshot: CustomWorldGalleryEntrySnapshot,
) -> Result<CustomWorldGalleryEntryRecord, SpacetimeClientError> {
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,
play_count: snapshot.play_count,
remix_count: snapshot.remix_count,
like_count: snapshot.like_count,
recent_play_count_7d: snapshot.recent_play_count_7_d,
})
}
pub(crate) fn map_custom_world_gallery_entry_row(
row: CustomWorldGalleryEntry,
recent_play_count_7d: u32,
) -> CustomWorldGalleryEntryRecord {
CustomWorldGalleryEntryRecord {
owner_user_id: row.owner_user_id,
profile_id: row.profile_id,
public_work_code: row.public_work_code,
author_public_user_code: row.author_public_user_code,
visibility: "published".to_string(),
published_at: Some(format_timestamp_micros(
row.published_at.to_micros_since_unix_epoch(),
)),
updated_at: format_timestamp_micros(row.updated_at.to_micros_since_unix_epoch()),
author_display_name: row.author_display_name,
world_name: row.world_name,
subtitle: row.subtitle,
summary_text: row.summary_text,
cover_image_src: row.cover_image_src,
theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back(
row.theme_mode,
))
.to_string(),
playable_npc_count: row.playable_npc_count,
landmark_count: row.landmark_count,
play_count: row.play_count,
remix_count: row.remix_count,
like_count: row.like_count,
recent_play_count_7d,
}
}
pub(crate) fn map_custom_world_published_profile_compile_snapshot(
snapshot: CustomWorldPublishedProfileCompileSnapshot,
) -> Result<CustomWorldPublishedProfileCompileRecord, SpacetimeClientError> {
let compiled_profile =
serde_json::from_str::<serde_json::Value>(&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<CustomWorldWorkSummaryRecord, SpacetimeClientError> {
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<CustomWorldAgentSessionRecord, SpacetimeClientError> {
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::<Result<Vec<_>, _>>()?;
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::<Result<Vec<_>, _>>()?,
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<CustomWorldDraftCardRecord, SpacetimeClientError> {
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<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
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_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_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_rpg_agent_stage_record(
value: &str,
) -> Result<crate::module_bindings::RpgAgentStage, SpacetimeClientError> {
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<crate::module_bindings::RpgAgentOperationType, SpacetimeClientError> {
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<crate::module_bindings::RpgAgentOperationStatus, SpacetimeClientError> {
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()
}
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 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_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_custom_world_checkpoint_record(
value: serde_json::Value,
) -> Result<CustomWorldCheckpointRecord, SpacetimeClientError> {
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_custom_world_publish_gate_record(
value: &str,
) -> Result<CustomWorldPublishGateRecord, SpacetimeClientError> {
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::<Result<Vec<_>, _>>()?;
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,
})
}