Files
Genarrative/server-rs/crates/spacetime-client/src/mapper/runtime.rs
2026-05-19 10:52:21 +08:00

468 lines
16 KiB
Rust

use super::*;
impl From<module_runtime::CreationEntryTypeAdminUpsertInput> for CreationEntryTypeAdminUpsertInput {
fn from(input: module_runtime::CreationEntryTypeAdminUpsertInput) -> Self {
Self {
id: input.id,
title: input.title,
subtitle: input.subtitle,
badge: input.badge,
image_src: input.image_src,
visible: input.visible,
open: input.open,
sort_order: input.sort_order,
}
}
}
impl From<module_runtime::RuntimeSettingGetInput> for RuntimeSettingGetInput {
fn from(input: module_runtime::RuntimeSettingGetInput) -> Self {
Self {
user_id: input.user_id,
}
}
}
impl From<module_runtime::RuntimeSettingUpsertInput> 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<module_runtime::RuntimeBrowseHistoryListInput> for RuntimeBrowseHistoryListInput {
fn from(input: module_runtime::RuntimeBrowseHistoryListInput) -> Self {
Self {
user_id: input.user_id,
}
}
}
impl From<module_runtime::RuntimeBrowseHistoryClearInput> for RuntimeBrowseHistoryClearInput {
fn from(input: module_runtime::RuntimeBrowseHistoryClearInput) -> Self {
Self {
user_id: input.user_id,
}
}
}
impl From<module_runtime::RuntimeBrowseHistorySyncInput> 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<module_runtime::RuntimeBrowseHistoryWriteInput> 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<module_runtime::RuntimeSnapshotGetInput> for RuntimeSnapshotGetInput {
fn from(input: module_runtime::RuntimeSnapshotGetInput) -> Self {
Self {
user_id: input.user_id,
}
}
}
impl From<module_runtime::RuntimeSnapshotDeleteInput> for RuntimeSnapshotDeleteInput {
fn from(input: module_runtime::RuntimeSnapshotDeleteInput) -> Self {
Self {
user_id: input.user_id,
}
}
}
impl From<module_runtime::RuntimeTrackingEventInput> for RuntimeTrackingEventInput {
fn from(input: module_runtime::RuntimeTrackingEventInput) -> Self {
Self {
event_id: input.event_id,
event_key: input.event_key,
scope_kind: map_runtime_tracking_scope_kind(input.scope_kind),
scope_id: input.scope_id,
user_id: input.user_id,
owner_user_id: input.owner_user_id,
profile_id: input.profile_id,
module_key: input.module_key,
metadata_json: input.metadata_json,
occurred_at_micros: input.occurred_at_micros,
}
}
}
pub type CreationEntryConfigRecord =
shared_contracts::creation_entry_config::CreationEntryConfigResponse;
pub(crate) fn map_creation_entry_config_procedure_result(
result: CreationEntryConfigProcedureResult,
) -> Result<CreationEntryConfigRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("创作入口配置快照"))?;
Ok(module_runtime::build_creation_entry_config_response(
map_creation_entry_config_snapshot(snapshot),
))
}
pub(crate) fn build_creation_entry_config_record_from_rows(
header: CreationEntryConfig,
mut creation_types: Vec<CreationEntryTypeConfig>,
) -> CreationEntryConfigRecord {
creation_types.sort_by(|left, right| {
left.sort_order
.cmp(&right.sort_order)
.then_with(|| left.id.cmp(&right.id))
});
module_runtime::build_creation_entry_config_response(
module_runtime::CreationEntryConfigSnapshot {
config_id: header.config_id,
start_card: module_runtime::CreationEntryStartCardSnapshot {
title: header.start_title,
description: header.start_description,
idle_badge: header.start_idle_badge,
busy_badge: header.start_busy_badge,
},
type_modal: module_runtime::CreationEntryTypeModalSnapshot {
title: header.modal_title,
description: header.modal_description,
},
creation_types: creation_types
.into_iter()
.map(|item| module_runtime::CreationEntryTypeSnapshot {
id: item.id,
title: item.title,
subtitle: item.subtitle,
badge: item.badge,
image_src: item.image_src,
visible: item.visible,
open: item.open,
sort_order: item.sort_order,
updated_at_micros: item.updated_at.to_micros_since_unix_epoch(),
})
.collect(),
updated_at_micros: header.updated_at.to_micros_since_unix_epoch(),
},
)
}
fn map_creation_entry_config_snapshot(
snapshot: CreationEntryConfigSnapshot,
) -> module_runtime::CreationEntryConfigSnapshot {
module_runtime::CreationEntryConfigSnapshot {
config_id: snapshot.config_id,
start_card: module_runtime::CreationEntryStartCardSnapshot {
title: snapshot.start_card.title,
description: snapshot.start_card.description,
idle_badge: snapshot.start_card.idle_badge,
busy_badge: snapshot.start_card.busy_badge,
},
type_modal: module_runtime::CreationEntryTypeModalSnapshot {
title: snapshot.type_modal.title,
description: snapshot.type_modal.description,
},
creation_types: snapshot
.creation_types
.into_iter()
.map(|item| module_runtime::CreationEntryTypeSnapshot {
id: item.id,
title: item.title,
subtitle: item.subtitle,
badge: item.badge,
image_src: item.image_src,
visible: item.visible,
open: item.open,
sort_order: item.sort_order,
updated_at_micros: item.updated_at_micros,
})
.collect(),
updated_at_micros: snapshot.updated_at_micros,
}
}
pub(crate) fn map_runtime_setting_procedure_result(
result: RuntimeSettingProcedureResult,
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let snapshot = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime settings 快照"))?;
Ok(build_runtime_setting_record(map_runtime_setting_snapshot(
snapshot,
)))
}
pub(crate) fn map_runtime_tracking_event_procedure_result(
result: RuntimeTrackingEventProcedureResult,
) -> Result<(), SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(())
}
pub(crate) fn map_runtime_tracking_event_batch_procedure_result(
result: RuntimeTrackingEventBatchProcedureResult,
) -> Result<u32, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
Ok(result.accepted_count)
}
pub(crate) fn map_runtime_snapshot_procedure_result(
result: RuntimeSnapshotProcedureResult,
) -> Result<Option<RuntimeSnapshotRecord>, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
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<RuntimeSnapshotRecord, SpacetimeClientError> {
map_runtime_snapshot_procedure_result(result)?
.ok_or_else(|| SpacetimeClientError::missing_snapshot("runtime snapshot 快照"))
}
pub(crate) fn map_runtime_snapshot_delete_procedure_result(
result: RuntimeSnapshotProcedureResult,
) -> Result<bool, SpacetimeClientError> {
map_runtime_snapshot_procedure_result(result).map(|record| record.is_some())
}
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_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_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_tracking_scope_kind(
value: DomainRuntimeTrackingScopeKind,
) -> crate::module_bindings::RuntimeTrackingScopeKind {
match value {
DomainRuntimeTrackingScopeKind::Site => {
crate::module_bindings::RuntimeTrackingScopeKind::Site
}
DomainRuntimeTrackingScopeKind::Work => {
crate::module_bindings::RuntimeTrackingScopeKind::Work
}
DomainRuntimeTrackingScopeKind::Module => {
crate::module_bindings::RuntimeTrackingScopeKind::Module
}
DomainRuntimeTrackingScopeKind::User => {
crate::module_bindings::RuntimeTrackingScopeKind::User
}
}
}
pub(crate) fn map_runtime_tracking_scope_kind_back(
value: crate::module_bindings::RuntimeTrackingScopeKind,
) -> DomainRuntimeTrackingScopeKind {
match value {
crate::module_bindings::RuntimeTrackingScopeKind::Site => {
DomainRuntimeTrackingScopeKind::Site
}
crate::module_bindings::RuntimeTrackingScopeKind::Work => {
DomainRuntimeTrackingScopeKind::Work
}
crate::module_bindings::RuntimeTrackingScopeKind::Module => {
DomainRuntimeTrackingScopeKind::Module
}
crate::module_bindings::RuntimeTrackingScopeKind::User => {
DomainRuntimeTrackingScopeKind::User
}
}
}
pub(crate) fn parse_json_value(
value: &str,
label: &str,
) -> Result<serde_json::Value, SpacetimeClientError> {
serde_json::from_str::<serde_json::Value>(value)
.map_err(|error| SpacetimeClientError::Runtime(format!("{label} 非法: {error}")))
}
pub(crate) fn parse_json_array(
value: &str,
label: &str,
) -> Result<Vec<serde_json::Value>, 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<Vec<String>, 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 parse_supported_actions_json(
value: &str,
) -> Result<Vec<CustomWorldSupportedActionRecord>, 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()
}
#[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<u32>,
pub threat_spawn_delta_levels: Vec<u32>,
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<BigFishLevelBlueprintRecord>,
pub background: BigFishBackgroundBlueprintRecord,
pub runtime_params: BigFishRuntimeParamsRecord,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BigFishRuntimeEntityRecord {
pub entity_id: String,
pub level: u32,
pub position: BigFishVector2Record,
pub radius: f32,
pub offscreen_seconds: f32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct BigFishRuntimeRunRecord {
pub run_id: String,
pub session_id: String,
pub status: String,
pub tick: u64,
pub player_level: u32,
pub win_level: u32,
pub leader_entity_id: Option<String>,
pub owned_entities: Vec<BigFishRuntimeEntityRecord>,
pub wild_entities: Vec<BigFishRuntimeEntityRecord>,
pub camera_center: BigFishVector2Record,
pub last_input: BigFishVector2Record,
pub event_log: Vec<String>,
pub updated_at: String,
}