|
|
|
|
@@ -1,4 +1,7 @@
|
|
|
|
|
use crate::big_fish::tables::{big_fish_agent_message, big_fish_creation_session};
|
|
|
|
|
use crate::runtime::{
|
|
|
|
|
ProfilePlayedWorkUpsertInput, add_profile_observed_play_time, upsert_profile_played_work,
|
|
|
|
|
};
|
|
|
|
|
use crate::*;
|
|
|
|
|
|
|
|
|
|
const INITIAL_BIG_FISH_CREATION_PROGRESS_PERCENT: u32 = 0;
|
|
|
|
|
@@ -93,6 +96,32 @@ pub fn delete_big_fish_work(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[spacetimedb::procedure]
|
|
|
|
|
pub fn record_big_fish_play(
|
|
|
|
|
ctx: &mut ProcedureContext,
|
|
|
|
|
input: BigFishPlayRecordInput,
|
|
|
|
|
) -> BigFishWorksProcedureResult {
|
|
|
|
|
match ctx.try_with_tx(|tx| record_big_fish_play_tx(tx, input.clone())) {
|
|
|
|
|
Ok(items) => match serde_json::to_string(&items) {
|
|
|
|
|
Ok(items_json) => BigFishWorksProcedureResult {
|
|
|
|
|
ok: true,
|
|
|
|
|
items_json: Some(items_json),
|
|
|
|
|
error_message: None,
|
|
|
|
|
},
|
|
|
|
|
Err(error) => BigFishWorksProcedureResult {
|
|
|
|
|
ok: false,
|
|
|
|
|
items_json: None,
|
|
|
|
|
error_message: Some(error.to_string()),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Err(message) => BigFishWorksProcedureResult {
|
|
|
|
|
ok: false,
|
|
|
|
|
items_json: None,
|
|
|
|
|
error_message: Some(message),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[spacetimedb::procedure]
|
|
|
|
|
pub fn submit_big_fish_message(
|
|
|
|
|
ctx: &mut ProcedureContext,
|
|
|
|
|
@@ -194,6 +223,7 @@ pub(crate) fn create_big_fish_session_tx(
|
|
|
|
|
.map_err(|error| error.to_string())?,
|
|
|
|
|
last_assistant_reply: Some(input.welcome_message_text.clone()),
|
|
|
|
|
publish_ready: false,
|
|
|
|
|
play_count: 0,
|
|
|
|
|
created_at,
|
|
|
|
|
updated_at: created_at,
|
|
|
|
|
});
|
|
|
|
|
@@ -383,6 +413,7 @@ pub(crate) fn submit_big_fish_message_tx(
|
|
|
|
|
asset_coverage_json: session.asset_coverage_json.clone(),
|
|
|
|
|
last_assistant_reply: session.last_assistant_reply.clone(),
|
|
|
|
|
publish_ready: session.publish_ready,
|
|
|
|
|
play_count: session.play_count,
|
|
|
|
|
created_at: session.created_at,
|
|
|
|
|
updated_at: submitted_at,
|
|
|
|
|
};
|
|
|
|
|
@@ -429,6 +460,7 @@ pub(crate) fn finalize_big_fish_agent_message_turn_tx(
|
|
|
|
|
asset_coverage_json: session.asset_coverage_json.clone(),
|
|
|
|
|
last_assistant_reply: session.last_assistant_reply.clone(),
|
|
|
|
|
publish_ready: session.publish_ready,
|
|
|
|
|
play_count: session.play_count,
|
|
|
|
|
created_at: session.created_at,
|
|
|
|
|
updated_at,
|
|
|
|
|
};
|
|
|
|
|
@@ -483,6 +515,7 @@ pub(crate) fn finalize_big_fish_agent_message_turn_tx(
|
|
|
|
|
asset_coverage_json: session.asset_coverage_json.clone(),
|
|
|
|
|
last_assistant_reply: Some(assistant_reply_text),
|
|
|
|
|
publish_ready: session.publish_ready,
|
|
|
|
|
play_count: session.play_count,
|
|
|
|
|
created_at: session.created_at,
|
|
|
|
|
updated_at,
|
|
|
|
|
};
|
|
|
|
|
@@ -536,6 +569,7 @@ pub(crate) fn compile_big_fish_draft_tx(
|
|
|
|
|
.map_err(|error| error.to_string())?,
|
|
|
|
|
last_assistant_reply: Some(reply.clone()),
|
|
|
|
|
publish_ready: coverage.publish_ready,
|
|
|
|
|
play_count: session.play_count,
|
|
|
|
|
created_at: session.created_at,
|
|
|
|
|
updated_at: compiled_at,
|
|
|
|
|
};
|
|
|
|
|
@@ -550,6 +584,92 @@ pub(crate) fn compile_big_fish_draft_tx(
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn record_big_fish_play_tx(
|
|
|
|
|
ctx: &ReducerContext,
|
|
|
|
|
input: BigFishPlayRecordInput,
|
|
|
|
|
) -> Result<Vec<BigFishWorkSummarySnapshot>, String> {
|
|
|
|
|
validate_play_record_input(&input).map_err(|error| error.to_string())?;
|
|
|
|
|
let session = ctx
|
|
|
|
|
.db
|
|
|
|
|
.big_fish_creation_session()
|
|
|
|
|
.session_id()
|
|
|
|
|
.find(&input.session_id)
|
|
|
|
|
.filter(|row| row.stage == BigFishCreationStage::Published)
|
|
|
|
|
.ok_or_else(|| "big_fish 已发布作品不存在".to_string())?;
|
|
|
|
|
let played_at = Timestamp::from_micros_since_unix_epoch(input.played_at_micros);
|
|
|
|
|
let draft = session
|
|
|
|
|
.draft_json
|
|
|
|
|
.as_deref()
|
|
|
|
|
.map(deserialize_draft)
|
|
|
|
|
.transpose()
|
|
|
|
|
.map_err(|error| format!("big_fish.draft_json 非法: {error}"))?;
|
|
|
|
|
let title = draft
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|value| value.title.trim().to_string())
|
|
|
|
|
.filter(|value| !value.is_empty())
|
|
|
|
|
.unwrap_or_else(|| "大鱼吃小鱼".to_string());
|
|
|
|
|
let subtitle = draft
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|value| {
|
|
|
|
|
let subtitle = value.subtitle.trim();
|
|
|
|
|
if subtitle.is_empty() {
|
|
|
|
|
let core_fun = value.core_fun.trim();
|
|
|
|
|
(!core_fun.is_empty()).then(|| core_fun.to_string())
|
|
|
|
|
} else {
|
|
|
|
|
Some(subtitle.to_string())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
let world_key = format!("big-fish:{}", session.session_id);
|
|
|
|
|
|
|
|
|
|
upsert_profile_played_work(
|
|
|
|
|
ctx,
|
|
|
|
|
ProfilePlayedWorkUpsertInput {
|
|
|
|
|
user_id: input.user_id.clone(),
|
|
|
|
|
world_key: world_key.clone(),
|
|
|
|
|
owner_user_id: Some(session.owner_user_id.clone()),
|
|
|
|
|
profile_id: Some(session.session_id.clone()),
|
|
|
|
|
world_type: Some("BIG_FISH".to_string()),
|
|
|
|
|
world_title: title,
|
|
|
|
|
world_subtitle: subtitle,
|
|
|
|
|
played_at_micros: input.played_at_micros,
|
|
|
|
|
},
|
|
|
|
|
)?;
|
|
|
|
|
add_profile_observed_play_time(
|
|
|
|
|
ctx,
|
|
|
|
|
&input.user_id,
|
|
|
|
|
&world_key,
|
|
|
|
|
input.elapsed_ms,
|
|
|
|
|
input.played_at_micros,
|
|
|
|
|
)?;
|
|
|
|
|
let next_session = BigFishCreationSession {
|
|
|
|
|
session_id: session.session_id.clone(),
|
|
|
|
|
owner_user_id: session.owner_user_id.clone(),
|
|
|
|
|
seed_text: session.seed_text.clone(),
|
|
|
|
|
current_turn: session.current_turn,
|
|
|
|
|
progress_percent: session.progress_percent,
|
|
|
|
|
stage: session.stage,
|
|
|
|
|
anchor_pack_json: session.anchor_pack_json.clone(),
|
|
|
|
|
draft_json: session.draft_json.clone(),
|
|
|
|
|
asset_coverage_json: session.asset_coverage_json.clone(),
|
|
|
|
|
last_assistant_reply: session.last_assistant_reply.clone(),
|
|
|
|
|
publish_ready: session.publish_ready,
|
|
|
|
|
// 中文注释:正式进入已发布作品时同时累加作品播放数,用户侧去重由 profile_played_world 保证。
|
|
|
|
|
play_count: session.play_count.saturating_add(1),
|
|
|
|
|
created_at: session.created_at,
|
|
|
|
|
updated_at: played_at,
|
|
|
|
|
};
|
|
|
|
|
replace_big_fish_session(ctx, &session, next_session);
|
|
|
|
|
|
|
|
|
|
list_big_fish_works_tx(
|
|
|
|
|
ctx,
|
|
|
|
|
BigFishWorksListInput {
|
|
|
|
|
owner_user_id: String::new(),
|
|
|
|
|
published_only: true,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn build_big_fish_session_snapshot(
|
|
|
|
|
ctx: &ReducerContext,
|
|
|
|
|
row: &BigFishCreationSession,
|
|
|
|
|
@@ -663,6 +783,7 @@ pub(crate) fn build_big_fish_work_summary(
|
|
|
|
|
level_main_image_ready_count: coverage.level_main_image_ready_count,
|
|
|
|
|
level_motion_ready_count: coverage.level_motion_ready_count,
|
|
|
|
|
background_ready: coverage.background_ready,
|
|
|
|
|
play_count: row.play_count,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -699,6 +820,7 @@ mod tests {
|
|
|
|
|
asset_coverage_json: "{}".to_string(),
|
|
|
|
|
last_assistant_reply: Some("欢迎来到大鱼吃小鱼共创。".to_string()),
|
|
|
|
|
publish_ready: false,
|
|
|
|
|
play_count: 0,
|
|
|
|
|
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
|
|
|
|
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
|
|
|
|
}
|
|
|
|
|
|