Integrate unfinished server-rs refactor worklists

This commit is contained in:
2026-04-30 13:39:06 +08:00
parent 62934b0809
commit 7ab0933f6d
676 changed files with 24487 additions and 21531 deletions

View File

@@ -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,