Integrate unfinished server-rs refactor worklists
This commit is contained in:
@@ -1169,6 +1169,7 @@ pub(crate) fn map_big_fish_works_procedure_result(
|
||||
result: BigFishWorksProcedureResult,
|
||||
fallback_owner_user_id: Option<&str>,
|
||||
) -> Result<Vec<BigFishWorkSummaryRecord>, SpacetimeClientError> {
|
||||
let _ = fallback_owner_user_id;
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
@@ -1176,15 +1177,26 @@ pub(crate) fn map_big_fish_works_procedure_result(
|
||||
let items_json = result
|
||||
.items_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("big fish works 快照"))?;
|
||||
let items = serde_json::from_str::<Vec<CompatibleBigFishWorkSummaryRecord>>(&items_json)
|
||||
.map_err(|error| {
|
||||
SpacetimeClientError::Runtime(format!("big fish works items_json 非法: {error}"))
|
||||
})?;
|
||||
serde_json::from_str::<Vec<BigFishWorkSummaryRecord>>(&items_json).map_err(|error| {
|
||||
SpacetimeClientError::Runtime(format!("big fish works items_json 非法: {error}"))
|
||||
})
|
||||
}
|
||||
|
||||
Ok(items
|
||||
.into_iter()
|
||||
.map(|item| item.into_record(fallback_owner_user_id))
|
||||
.collect())
|
||||
pub(crate) fn map_big_fish_run_procedure_result(
|
||||
result: BigFishRunProcedureResult,
|
||||
) -> Result<BigFishRuntimeRunRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let run_json = result
|
||||
.run_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("big fish run 快照"))?;
|
||||
let run: module_big_fish::BigFishRuntimeSnapshot =
|
||||
serde_json::from_str(&run_json).map_err(|error| {
|
||||
SpacetimeClientError::Runtime(format!("big fish run run_json 非法: {error}"))
|
||||
})?;
|
||||
Ok(map_big_fish_runtime_snapshot(run))
|
||||
}
|
||||
|
||||
pub(crate) fn map_story_session_procedure_result(
|
||||
@@ -2396,6 +2408,53 @@ pub(crate) fn map_big_fish_agent_message_snapshot(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_big_fish_runtime_snapshot(
|
||||
snapshot: module_big_fish::BigFishRuntimeSnapshot,
|
||||
) -> BigFishRuntimeRunRecord {
|
||||
BigFishRuntimeRunRecord {
|
||||
run_id: snapshot.run_id,
|
||||
session_id: snapshot.session_id,
|
||||
status: snapshot.status.as_str().to_string(),
|
||||
tick: snapshot.tick,
|
||||
player_level: snapshot.player_level,
|
||||
win_level: snapshot.win_level,
|
||||
leader_entity_id: snapshot.leader_entity_id,
|
||||
owned_entities: snapshot
|
||||
.owned_entities
|
||||
.into_iter()
|
||||
.map(map_big_fish_runtime_entity_snapshot)
|
||||
.collect(),
|
||||
wild_entities: snapshot
|
||||
.wild_entities
|
||||
.into_iter()
|
||||
.map(map_big_fish_runtime_entity_snapshot)
|
||||
.collect(),
|
||||
camera_center: map_big_fish_vector2(snapshot.camera_center),
|
||||
last_input: map_big_fish_vector2(snapshot.last_input),
|
||||
event_log: snapshot.event_log,
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_big_fish_runtime_entity_snapshot(
|
||||
snapshot: module_big_fish::BigFishRuntimeEntitySnapshot,
|
||||
) -> BigFishRuntimeEntityRecord {
|
||||
BigFishRuntimeEntityRecord {
|
||||
entity_id: snapshot.entity_id,
|
||||
level: snapshot.level,
|
||||
position: map_big_fish_vector2(snapshot.position),
|
||||
radius: snapshot.radius,
|
||||
offscreen_seconds: snapshot.offscreen_seconds,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_big_fish_vector2(snapshot: module_big_fish::BigFishVector2) -> BigFishVector2Record {
|
||||
BigFishVector2Record {
|
||||
x: snapshot.x,
|
||||
y: snapshot.y,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_story_session_snapshot(snapshot: StorySessionSnapshot) -> StorySessionRecord {
|
||||
StorySessionRecord {
|
||||
story_session_id: snapshot.story_session_id,
|
||||
@@ -4143,6 +4202,23 @@ pub struct BigFishPlayReportRecordInput {
|
||||
pub reported_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct BigFishRunStartRecordInput {
|
||||
pub run_id: String,
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub started_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BigFishInputSubmitRecordInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub submitted_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PuzzleAnchorItemRecord {
|
||||
pub key: String,
|
||||
@@ -4527,6 +4603,38 @@ pub struct BigFishSessionRecord {
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BigFishVector2Record {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct BigFishWorkSummaryRecord {
|
||||
pub work_id: String,
|
||||
@@ -4546,123 +4654,6 @@ pub struct BigFishWorkSummaryRecord {
|
||||
pub play_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
struct CompatibleBigFishWorkSummaryRecord {
|
||||
work_id: String,
|
||||
source_session_id: String,
|
||||
#[serde(default)]
|
||||
owner_user_id: Option<String>,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
summary: String,
|
||||
cover_image_src: Option<String>,
|
||||
status: String,
|
||||
updated_at_micros: i64,
|
||||
publish_ready: bool,
|
||||
level_count: u32,
|
||||
level_main_image_ready_count: u32,
|
||||
level_motion_ready_count: u32,
|
||||
background_ready: bool,
|
||||
#[serde(default)]
|
||||
play_count: u32,
|
||||
}
|
||||
|
||||
impl CompatibleBigFishWorkSummaryRecord {
|
||||
fn into_record(self, fallback_owner_user_id: Option<&str>) -> BigFishWorkSummaryRecord {
|
||||
BigFishWorkSummaryRecord {
|
||||
work_id: self.work_id,
|
||||
source_session_id: self.source_session_id,
|
||||
// 中文注释:兼容旧 works JSON 没有 owner_user_id 的历史数据,避免一次字段升级把整个作品列表打崩。
|
||||
owner_user_id: self.owner_user_id.unwrap_or_else(|| {
|
||||
fallback_owner_user_id
|
||||
.map(str::to_string)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
title: self.title,
|
||||
subtitle: self.subtitle,
|
||||
summary: self.summary,
|
||||
cover_image_src: self.cover_image_src,
|
||||
status: self.status,
|
||||
updated_at_micros: self.updated_at_micros,
|
||||
publish_ready: self.publish_ready,
|
||||
level_count: self.level_count,
|
||||
level_main_image_ready_count: self.level_main_image_ready_count,
|
||||
level_motion_ready_count: self.level_motion_ready_count,
|
||||
background_ready: self.background_ready,
|
||||
play_count: self.play_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn big_fish_works_mapper_backfills_missing_owner_user_id_for_private_lists() {
|
||||
let result = BigFishWorksProcedureResult {
|
||||
ok: true,
|
||||
items_json: Some(
|
||||
r#"[{
|
||||
"work_id":"big-fish-work-session-1",
|
||||
"source_session_id":"session-1",
|
||||
"title":"深海草稿",
|
||||
"subtitle":"副标题",
|
||||
"summary":"摘要",
|
||||
"cover_image_src":null,
|
||||
"status":"draft",
|
||||
"updated_at_micros":123,
|
||||
"publish_ready":false,
|
||||
"level_count":8,
|
||||
"level_main_image_ready_count":0,
|
||||
"level_motion_ready_count":0,
|
||||
"background_ready":false
|
||||
}]"#
|
||||
.to_string(),
|
||||
),
|
||||
error_message: None,
|
||||
};
|
||||
|
||||
let items = map_big_fish_works_procedure_result(result, Some("user-1"))
|
||||
.expect("旧 works JSON 应能被兼容解析");
|
||||
|
||||
assert_eq!(items.len(), 1);
|
||||
assert_eq!(items[0].owner_user_id, "user-1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_fish_works_mapper_keeps_empty_owner_when_gallery_legacy_json_lacks_field() {
|
||||
let result = BigFishWorksProcedureResult {
|
||||
ok: true,
|
||||
items_json: Some(
|
||||
r#"[{
|
||||
"work_id":"big-fish-work-session-2",
|
||||
"source_session_id":"session-2",
|
||||
"title":"公开作品",
|
||||
"subtitle":"副标题",
|
||||
"summary":"摘要",
|
||||
"cover_image_src":null,
|
||||
"status":"published",
|
||||
"updated_at_micros":456,
|
||||
"publish_ready":true,
|
||||
"level_count":8,
|
||||
"level_main_image_ready_count":8,
|
||||
"level_motion_ready_count":16,
|
||||
"background_ready":true
|
||||
}]"#
|
||||
.to_string(),
|
||||
),
|
||||
error_message: None,
|
||||
};
|
||||
|
||||
let items = map_big_fish_works_procedure_result(result, None)
|
||||
.expect("公开 works 旧 JSON 也不应因缺字段报错");
|
||||
|
||||
assert_eq!(items.len(), 1);
|
||||
assert!(items[0].owner_user_id.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ResolveNpcBattleInteractionInput {
|
||||
pub npc_interaction: DomainResolveNpcInteractionInput,
|
||||
|
||||
Reference in New Issue
Block a user